QProcess: setStandardOutputFile produces empty files
-
I'm trying to run mysqldump as a QProcess. I'm requiring the user to provide the MySQL root password because I can't count on regular user accounts having lock tables and any other permissions required to do a dump.
Since mysqldump likes to write to stdout, I'm using QProcess::setStandardOutputFile to save the output to a file. However, the output file is always empty/0 bytes in size after the process is finished and I’m not sure why. If I had to guess, I would say the process is not working at all for some reason. Since I know the executable path is good (I'm using regular mysqldump stored at /usr/bin/mysqldump), something must be wrong with the args that get passed to the process.
Right now, I'm trying to get this working on Linux first before I worry about Windows implementation.
Here's my code: (filename and mysqldump_path are QStrings that contain form data)
@
QFile output(filename);
QFile mysqldump(mysqldump_path);// Stop the dump process if the mysqldump executable does not exist (usually at /usr/bin/mysqldump on Unix/Linux) if(!mysqldump.exists()){ QMessageBox m; m.critical(this,"RoboJournal","RoboJournal could not find the <i>mysqldump</i> executable at the expected location (<b>" + mysqldump_path + "</b>)."); cout << "OUTPUT: Aborting! mysqldump does not exist at " << mysqldump_path.toStdString() << endl; return false; } // Ask before overwrite if a dump file with the same path+name already exists. if(output.exists()){ QMessageBox b; int choice=b.question(this,"RoboJournal","<b>" + filename + "</b> already exists. Do you want to replace it?", QMessageBox::Yes | QMessageBox::No, QMessageBox::No); if(choice==QMessageBox::No) return false; } QString root_pass; QString database=Buffer::database_name; bool clickedOk=false; while(root_pass.isEmpty()){ root_pass=QInputDialog::getText(this,"RoboJournal","Enter the MySQL root password for <b>" + Buffer::host + "</b>:",QLineEdit::Password,"",&clickedOk); if(!clickedOk) return false; } //escape any parentheses/braces/special characters in the password. root_pass=root_pass.replace(")","\\)"); root_pass=root_pass.replace("(","\\("); root_pass=root_pass.replace("]","\\]"); root_pass=root_pass.replace("[","\\["); root_pass=root_pass.replace("}","\\}"); root_pass=root_pass.replace("{","\\{"); root_pass=root_pass.replace("\'","\\'"); root_pass=root_pass.replace("\"","\\"); // complete the dump QProcess* dump=new QProcess(); dump->setStandardOutputFile(filename,QIODevice::ReadWrite); QStringList args; args << " -u root "; args << "-p" + root_pass; args << " " + database; cout << "cmd: " << args.join("").toStdString() << endl; dump->start(mysqldump_path, args, QIODevice::ReadWrite); QMessageBox n; n.information(this,"RoboJournal","The current contents of <b>" + database + "</b> have been backed up to <b>" + filename + "</b>."); return true;@
The things I'm not sure about are
-
Whether QProcess cares about extra spacing in the arguments (I added extra spacing so I could cut and paste the cout output into bash to test it (I'm going to take that out after I finish debugging). Without extra spacing, everything ends up bunched together.
-
Whether QProcess requires escaping on argument values. My root password contains a ")" character and it wouldn't work in bash until I escaped it with ")". I tried adding code to escape the password value in case the user has a similar password but it didn't fix this problem.
-
-
I doubt if the process is running. Can you check after joining the program and arguments. In your case:
@mysqldump_path = mysqldump_path +" "+args.join("");@Regarding escaping, QProcess needs a string. If that string is provided correctly, and proper escape sequences are provided to characters like " , \ etc, and you can print the command correctly, work on qprocess side is done. How the command is interpreted by the process started and how it interprets special sequences and spaces etc, is something which will be documented in the process.
So, refer the process, mysqldump on how it wants its commandline, create such a commandline in qt and use qprocess. No special handling is required. -
I just tried
@
mysqldump_path = mysqldump_path +" "+args.join("");
cout << mysqldump_path.toStdString() << endl;dump->start(mysqldump_path, QIODevice::ReadWrite);@
I got the following as output from cout (password obscured):
bq. /usr/bin/mysqldump -u root -pblahblahblah) test_db
I copy+pasted the mysqldump_path string into bash and it worked fine there. It looks like the Qprocess never starts for some reason; In my latest test, I kept a system monitor open while I tried to do a dump and no mysqldump process ever appeared in the process list.