Short answer here is to use system()
or popen()
rather than execl()
. Seeing as Jason has already posted a good answer about using popen()
, I'll skip that and explain how to use execl()
just in case you actually care. Most likely, this is all unnecessary technical mumbo jumbo--but dammit, I had most of this typed out already as a long prelude before discussing popen()
and I'm not throwing it away now!
Firstly...
When calling execl()
all of the command-line arguments need to be passed separately. Also, the first argument must be repeated as argv[0]
in any program's main()
is traditionally the name of the program. So the fixed call should look like:
execl("/usr/bin/php", "/usr/bin/php", "-q",
"/var/www/html/phpinfo.php", (char *) NULL);
(I added the cast to (char *)
to ensure that a null pointer is passed as the final argument rather than the integer 0, if NULL
happens to be defined as 0
and not (void *) 0
, which is legal.)
However...
This gets the execl()
call right, but there's a bigger problem. The exec
family of functions are almost always used in combination with fork()
and some complicated pipe()
juggling. This is because the exec
functions do not actually run the program in a separate process; they actually replace the current process! So once you call execl()
, your code is done. Finished. execl()
never returns. If you just call it like you've done you'll never get to see what happens as your program will magically transform into a /usr/bin/php
process.
OK, so what's this about fork()
and pipe()
? At a high level, what you've got to do is split your process into two processes. The parent process will continue to be "your" process, while the child process will immediately call execl()
and transform itself into /usr/bin/php
. Then if you've wired the parent and child processes together correctly they'll be able to communicate with each other.
To make a long story short, if you're still here and haven't nodded off you should consult the wise oracle Google for way more details about all of this. There are plenty of web sites out there giving even more (!) in-depth details about how to do the fork
/exec
dance.
I won't leave you hanging though. Here's a function I use for my own programs that does exactly what I've outlined. It is very similar to popen()
in fact, the only difference being that the caller can access the child's stderr
stream in addition to stdin
and stdout
.
Code...
#include <errno.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
pid_t execute(const char *command, FILE **in, FILE **out, FILE **err)
{
pid_t pid;
int fd[6];
pipe(&fd[0]);
pipe(&fd[2]);
pipe(&fd[4]);
switch (pid = fork()) {
case -1:
perror("unable to fork()");
exit(1);
case 0:
close(fd[1]); // Close write end of stdin.
close(fd[2]); // Close read end of stdout.
close(fd[4]); // Close read end of stderr.
dup2(fd[0], STDIN_FILENO); // Have stdin read from the first pipe.
dup2(fd[3], STDOUT_FILENO); // Have stdout write to the second pipe.
dup2(fd[5], STDERR_FILENO); // Have stderr write to the third pipe.
execlp("/bin/sh", "/bin/sh", "-c", command, (char *) NULL);
perror("execlp() failed");
_exit(1);
default:
close(fd[0]); // Close read end of stdin.
close(fd[3]); // Close write end of stdout.
close(fd[5]); // Close write end of stderr.
if (in) *in = fdopen(fd[1], "wb"); else close(fd[1]);
if (out) *out = fdopen(fd[2], "rb"); else close(fd[2]);
if (err) *err = fdopen(fd[4], "rb"); else close(fd[4]);
return pid;
}
}