Axe
Axe

Reputation: 65

C++ app hangs on exit when I envoke a script and leave the script running

I have a C++/Qt program running on Ubuntu 10.04. I am running a remote application using x-windows (ssh -X) with RSA key to prevent the password dialog. The C++/Qt program allows the user to invoke a shell script. The C++/Qt program must run as 'gksudo -k'.

The problem that I am having is that when I invoke the shell script from my program it causes a thread in the local C++/Qt program to hang on exit if I leave the remote application running. (I want to be able to leave the ssh session running, and not effect restarting the C++/Qt program)

From the C++ code:

try
{
    system(script.c_str());
}
catch (exception& e)
{
    throw;
}
catch ( ... )
{
    ThrowException("Controller::LaunchScript()");
}

The shell script is in /usr/local/bin, and looks like this:

#!/bin/sh
ip_address='192.168.0.1'
remote_usr='xxusrxx'
remote_cmd='/usr/local/bin/remote_application'

cmd="ssh -X "$remote_usr"@"$ip_address" \""$remote_cmd"\""
eval $cmd &

Any thoughts or suggestions?

Update 1:

When I look at the processes running using 'ps -ef', the C++/Qt program nor the launcher script show up, but the 'ssh -X' does. When I restart my C++/Qt program it throws an error "address already in use" like when I have tried to start the application in the past while having another instance already running.

Update 2:

I could be getting further down the rabbit hole, but I am now looking at the sudo+xauth issues and solutions. Current failed attempt is adding:

export XAUTHORITY=/home/xxusrxx/.Xauthority
sudo -E -u xxusrxx

Also, it appears the the C++/Qt process that is hanging is defunct. One possibility is to track the have the application "clean-up" defunct processes on startup.

Upvotes: 1

Views: 982

Answers (2)

Ivan Kovacevic
Ivan Kovacevic

Reputation: 1332

Try redirecting all file descriptors(stdin, stdout, stderr) to /dev/null.

In your shell script, change to this:

eval $cmd >/dev/null 2>&1 &

Actually I do not know why would you need eval, just call ssh directly:

ssh -X "$remote_usr"@"$ip_address" "$remote_cmd" >/dev/null 2>&1 &

>/dev/null - This, obviously, redirects the stdout.
2>&1 - This redirects standard error(fd 2) to standard output(fd 1) which we previously redirected to /dev/null, so now they are both redirected to /dev/null
& - forking to background will automatically redirect stdin to /dev/null

Equivalently, directly in C++/Qt, you can just add another string with that at the end of the QStringList as Kuba Ober showed you

<< remote_cmd << ">/dev/null 2>&1")

RESPONSE TO YOUR UPDATE:

You say in your update that "When I look at the processes running using 'ps -ef', the C++/Qt program nor the launcher script show up, but the 'ssh -X' does. "

Does that mean that you no longer have a stuck thread/process?

Further you say "When I restart my C++/Qt program it throws an error "address already in use""
I suppose that is so because when you launch ssh again when the previous ssh client is still running(and forwarding X11), it connects again on the remote and there it tells the sshd server to open a port to listen for X server connections, and then it complains that that port(or interface_address:port combination) is already in use. The simple solution, if you don't need multiple ssh connections is to kill the existing ssh connection before launching your app. Otherwise you must investigate how to force sshd to bind on another port or something like that. Maybe logging in as a different user resolves the issue automatically.

But a big note here: I really don't have much experience with X11 forwarding so I'm writing this greatly by just assuming how it works. I might be wrong.

Upvotes: 1

Since you use Qt, there is no reason to use the system call, and there's no reason to use the helper script. Finally, wrapping a system call in a try-catch block is pointless since it doesn't trow exceptions. It's a C function that returns a result.

You can use QProcess::startDetached and your code will not wait for anything:

QString ip_address="192.168.0.1"
QString remote_usr="xxusrxx"
QString remote_cmd="/usr/local/bin/remote_application"

if (!QProcess::startDetached("ssh", QStringList()
  << "-X" << QString("%1@%2").arg(remote_usr).arg(ip_address)
  << remote_cmd)
  ThrowException("Controller::LaunchScript()");

You can similarly start the script, but there's really no point to the script.

Upvotes: 1

Related Questions