Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP hanging while exec() bash script

I have some lines of code that look like this...

exec($this->path.' start > /dev/null 2>&1 &');
return ['status' => 'Command executed'];

$this->path is a shell script, start is an argument to the shell script and I believe the rest of the line is suppose to dump any response so the php script can continue running. It is not working like it should, php is successfully launching the shell script (which launches a game server) however php just hangs until I shut the server down using the shell. When I shut the server down with the shell it finishes executing and I receive the 'command executed' response. I've also disabled enforcement of SELinux to make sure it isn't interfering.

Running Linux - Fedora 21 and the built in PHP development server.

like image 871
slick1537 Avatar asked Oct 20 '22 19:10

slick1537


1 Answers

I believe the rest of the line is suppose to dump any response so the php script can continue running

If you don't understand it, here is the explanation. If you have:

exec($this->path.' start > /dev/null 2>&1 &');

The > /dev/null part means to redirect stdout (i.e. the regular output produced by the command) to /dev/null (which is the null device). Therefore any output produced by the command itself will be suppressed.

The 2>&1 part means redirect stderror (i.e. any errors produced by the execution of the command) to stdout. However since stdout is being redirected to /dev/null, any errors will also be redirected there. Therefore with these two, it suppresses any messages that will ever be produced by the command.

Finally the & (ampersand) at the end forks the command to a new process. From the Bash man page:

If a command is terminated by the control operator &, the shell executes the command in the background in a subshell. The shell does not wait for the command to finish, and the return status is 0 (true).

However, according to this question, what you are doing should be working. There must be something else going on to prevent the process from successfully forking. Just to rule out PHP from being the problem, I would first try to execute the command by the command line instead of through PHP's exec. If it still doesn't work, I would guess it's because there is a problem with your Job Control. Either it is somehow disabled. I haven't tried this in PHP, but you might be able to enable it with the set -m command (which enables job control). Note, to disable job control instead of set -m you do set +m. Here is how you could do this in PHP:

exec('set -m && ' . $this->path.' start > /dev/null 2>&1 &');

Another thing you could do is while the PHP script is executing, log in to the command line and type the command jobs and look at its output. If it is blank, PHP is not forking the jobs correctly. You should see something like:

[1]+  Stopped                 your_command.sh

Notice how here it says stopped. This should probably not be stopped if the process is still running.

Another thing you could do is see if checkjobs is enabled or disabled. Log in to the server and execute the following to get the builtin shell optional behavior:

shopt -p | grep checkjobs

If the output is shopt -u checkjobs, this is not the problem. If it instead says shopt -s checkjobs, this could cause the behavior you are seeing because killing a shell with background jobs will result in an error saying that there are jobs running and you actually have to kill the shell twice to get out of it. Maybe this is something PHP devs did not consider. In that case, prepend shopt -u checkjobs && before your command in PHP.

exec('shopt -u checkjobs && ' . $this->path.' start > /dev/null 2>&1 &');
like image 124
Mike Avatar answered Oct 22 '22 11:10

Mike