Quamis
Quamis

Reputation: 11087

exec always returns -1 (or 127)

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

Upvotes: 12

Views: 6907

Answers (5)

Quamis
Quamis

Reputation: 11087

Seems like the problem got fixed by the server admin. I have no idea what he did, but it now works. The thing is that the server admin is pretty "strict" and maybe he got a little to restrictive with some system config. From the SSH shell for example i could not see where the php binaries were installed. I'm pretty sure that the SSH shell was chrooted, and also the webserver (either that or they were totally different servers, but i don't know how was that possible without using any kind of mount)...

Upvotes: 0

paulsm4
paulsm4

Reputation: 121689

I tried it out on two different Linux PC's (PHP 5.03 and PHP 5.2.10) - both worked just fine.

PHP 5.2.10 example:

array (
  'command' => 'ls',
  'result' => 0,
  'output' => 'atmail
...
vhosts',
  'r' => 'vhosts',
  't2-t1' => 0,
)

I'd double-check for any security-related directives in your php.ini file, check file permissions in the directory you're trying to search, and see if you have SELinux and/or AppArmor running.

You might also consider an altenrative, like opendir()/readdir ().

IMHO .. PSM

Upvotes: 0

Rob Paisley
Rob Paisley

Reputation: 457

Can we get the output of strace'ing the PHP process? That will likely contain the answer we're looking for.

Also 5.2.14 is the newest of the 5.2 series. Any chance you could try it there? If you're on a shared hosting provider, you can still likely get it to run locally to see if the behavior changes.

Upvotes: 0

D&#233;j&#224; vu
D&#233;j&#224; vu

Reputation: 28840

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.

Upvotes: 1

user229044
user229044

Reputation: 239302

Make sure you're not running in safe mode and that exec isn't listed in disable_functions in php.ini.

Either of these situations would cause exec() to fail, though I think a notice would be raised.

Upvotes: 0

Related Questions