How to execute complex linux commands in Qt? [dupl

2019-03-13 15:18发布

This question already has an answer here:

I want to restart the computer by running a command in linux using QProcess. I have hard-coded my root password in my application.

When i run the following in a terminal it works perfect:

echo myPass | sudo -S shutdown -r now 

When i put the command in a shell script and call it via QProcess it is also successful :

QProcess process;
process.startDetached("/bin/sh", QStringList()<< "myScript.sh");

But i can not run it by directly passing to QProcess:

process.startDetached("echo myPass | sudo -S shutdown -r now ");

It will just print myPass | sudo -S shutdown -r now

How is it possible to run such relatively complex commands directly using QProcess. (Not putting in a shell script).

3条回答
倾城 Initia
2楼-- · 2019-03-13 15:28

First, you could configure sudo to avoid asking you the password. For instance by being member of the sudo group and having the line

 %sudo  ALL=NOPASSWD:  ALL

in your /etc/sudoers file. Of course not asking the password lowers the security of your system.

To answer your question about Qt, remember that bash(1), like all Posix shells, hence /bin/sh, accept the -c argument with a string (actually system(3) is forking a /bin/sh -c). So just execute

 process.startDetached("/bin/sh", QStringList()<< "-c" 
                       << "echo myPass | sudo -S shutdown -r now");

As AntiClimacus answered, puting your root password inside an executable is a bad idea.

查看更多
Rolldiameter
3楼-- · 2019-03-13 15:29

You must put your command in a shell script and execute sh or bash with QProcess with your shell script as argument, because your command contains |, which must be interpreted by sh or bash.

However, it's just my opinion, but: I don't think it is a good solution to do what you are doing, i.e. include your root password in an executable.

查看更多
Animai°情兽
4楼-- · 2019-03-13 15:33

The key methods that exist for this purpose established in QProcess:

void QProcess::setProcessChannelMode(ProcessChannelMode mode)

and

void QProcess::setStandardOutputProcess(QProcess * destination)

Therefore, the following code snippet would be the equivalence of command1 | command2 without limiting yourself to one interpreter or another:

QProcess process1
QProcess process2;

process1.setStandardOutputProcess(&process2);

process1.start("echo myPass");
process2.start("sudo -S shutdown -r now");
process2.setProcessChannelMode(QProcess::ForwardedChannels);

// Wait for it to start
if(!process1.waitForStarted())
    return 0;

bool retval = false;
QByteArray buffer;
// To be fair: you only need to wait here for a bit with shutdown,
// but I will still leave the rest here for a generic solution
while ((retval = process2.waitForFinished()));
    buffer.append(process2.readAll());

if (!retval) {
    qDebug() << "Process 2 error:" << process2.errorString();
    return 1;
}

You could drop the sudo -S part because you could run this small program as root, as well as setting up the rights. You could even set setuid or setcap for the shutdown program.

What we usually do when building commercial Linux systems is to have a minimal application that can get setuid or setcap for the activity it is trying to do, and then we call that explicitly with system(3) or QProcess on Linux. Basically,

I would write that small application to avoid giving full root access to the whole application, so to restrict the access right against malicious use as follows:

sudo chmod u+s /path/to/my/application
查看更多
登录 后发表回答