Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

exec always returns -1 (or 127)

Tags:

linux

php

exec

I'm using php 5.2.9 on a production server, and it seems that the exec() function behaves "non-standard".

If i run exec("ls", $output, $return_var) then $output will contain the list of files in the current folder as expected, but $return_var will be set to -1 instead of 0, as expected. I'm using the $return_var to determine wherever the command finished successfully, and on every other server tested this works as expected:)

Anyone ever hit a situation like this?


edit:

<?php
$command = "asd";

$t1 = time();

$output = Array();
$result = -5;
$r = exec($command, $output, $result);
$t2 = time();

echo "<pre>";
var_export(Array(
    'command'=>$command,
    'result'=>$result,
    'output'=>implode("\n", $output),
    'r'=>$r,
    't2-t1'=>$t2-$t1,
));
echo "</pre>";

Whatever command i put in $command, $result will always be -1, even for nonexistent commands...this is very weird

like image 495
Quamis Avatar asked Aug 11 '10 14:08

Quamis


1 Answers

Assuming the system returning $result == -1 is Unix-like based (I don't know how would behave Windows with the same code)

The PHP (5.2.9) exec() function does not call the C exec() primitive (which returns -1 if it could not replace/execute the process, which is not the case here). Instead it calls popen() that creates a pipe, performs a fork() and execute a shell with your command. The return_value, -1, is not the direct result from a C primitive, but rather is built by PHP internally, depending on the way your command was processed. In other terms, the "ls" command may have been well executed, while for instance PHP could not close properly the pipe.

Looking at the C code, in ext/standard/exec.c, there could be two reasons why the return code is -1, triggered by an error ; the 2nd one happens after the popen() call

  fp = VCWD_POPEN(cmd_p, "r");

  if (!fp) {
       php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to fork [%s]", cmd);
       goto err;
  }
  // ...
  err:

  pclose_return = -1;
  goto done;

However in this case, you wouldn't see the result, and the log would show an error.

Later, the return_value is set via the line

  pclose_return = php_stream_close(stream);

Looking at _php_stream_free() (php_stream_close() is a macro replaced with _php_stream_free()), the most likely candidate that could return -1 is

  ret = stream->ops->close(stream, preserve_handle ? 0 : 1 TSRMLS_CC);

Which in turn calls indirectly the C primitive pclose(). According to the manual

The pclose() function returns -1 if wait4(2) returns an error, or some other error is detected.

There seem to be an error detected during the closing of the pipe, that does not prevent the resulting data to be set. To find the reason rigorously, one need to check the operating system setup and logs, the PHP configuration and compilation parameters.

I would recommend

  • to apply patches for your OS, and maybe update to a more recent version (if applicable),
  • to update PHP to 5.3.3 (latest as of now) since the PHP exec() code changed significantly.

Be aware that there were changes related to the PHP suhosin module in the version 5.3 that enhance by default the security when running PHP files.

like image 134
Déjà vu Avatar answered Oct 09 '22 07:10

Déjà vu