Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Using execl to execute a daemon

23 views
Skip to first unread message

chsa...@gmail.com

unread,
Apr 28, 2009, 10:53:43 PM4/28/09
to
I'm writing a program in C on Linux which includes a module that
allows a shell command to be executed on a remote machine. The
easiest way to actually execute the command would of course be to
simply use the system() function, or use popen and then grab the
output. However, I chose to use a more low-level approach due to
other design requirements which are not relevant to the current
problem.

So basically, I set up a pipe and fork, and then call execl. This all
works perfectly, except for one annoying exception. It doesn't work
properly if the shell command to be executed is a daemon. In that
case, it just hangs. I can't figure out why. My understanding is
that when a daemon starts, it typically forks and then kills its
parent. Since my application has an open pipe to the parent, the call
to read() should fail when the daemon kills its parent. But instead
the application just hangs.

Here is some bare bones code that reproduces the problem:

int main(int argc, char** argv)
{
if (argc < 2) {
printf("Please specify a shell command\n");
return 0;
}

// Create a pipe and fork
//
int fd[2];
int p = pipe(fd);
pid_t pid = fork();

if (pid > 0)
{
// Read from the pipe and output the result
//
close(fd[1]);
char buf[1024] = { 0 };
read(fd[0], buf, sizeof(buf));
printf("%s\n", buf);

// Wait for child to terminate
int status;
wait(&status);
}
else if (pid == 0)
{
// Redirect stdout and stderr to the pipe and execute
the shell
// command
//
dup2(fd[1], STDOUT_FILENO);
dup2(fd[1], STDERR_FILENO);
close(fd[0]);
execl("/bin/sh", "sh", "-c", argv[1], 0);
}
}

The code works fine if you use it with a normal shell command. But if
you try to run a daemon, it just hangs instead of returning to the
prompt as it should.

David Schwartz

unread,
Apr 28, 2009, 11:24:20 PM4/28/09
to
On Apr 28, 7:53 pm, chsal...@gmail.com wrote:

>         if (pid > 0)
>         {
>                 // Read from the pipe and output the result
>                 //
>                 close(fd[1]);
>                 char buf[1024] = { 0 };
>                 read(fd[0], buf, sizeof(buf));
>                 printf("%s\n", buf);
>
>                 // Wait for child to terminate
>                 int status;
>                 wait(&status);
>         }

This can deadlock. The child may be waiting for you to read from its
output before it terminates and you are waiting for it to terminate.

>         else if (pid == 0)
>         {
>                 // Redirect stdout and stderr to the pipe and execute
> the shell
>                 // command
>                 //
>                 dup2(fd[1], STDOUT_FILENO);
>                 dup2(fd[1], STDERR_FILENO);
>                 close(fd[0]);
>                 execl("/bin/sh", "sh", "-c", argv[1], 0);
>         }

Why don't you close fd(1)?

DS

Gordon Burditt

unread,
Apr 28, 2009, 11:44:11 PM4/28/09
to
>I'm writing a program in C on Linux which includes a module that
>allows a shell command to be executed on a remote machine. The
>easiest way to actually execute the command would of course be to
>simply use the system() function, or use popen and then grab the
>output. However, I chose to use a more low-level approach due to
>other design requirements which are not relevant to the current
>problem.
>
>So basically, I set up a pipe and fork, and then call execl. This all
>works perfectly, except for one annoying exception. It doesn't work
>properly if the shell command to be executed is a daemon. In that
>case, it just hangs. I can't figure out why. My understanding is
>that when a daemon starts, it typically forks and then kills its
>parent.

No, typically it forks and the parent *exits*. Unless it's trying
to write data down a pipe that the application isn't reading.

>Since my application has an open pipe to the parent, the call
>to read() should fail when the daemon kills its parent. But instead
>the application just hangs.

A read() on a pipe will return with end-of-file when *all* of the
write ends of the pipe have been closed. The parent may pass on
the pipe to its child. If it's a daemon, it will typically close
stdin, stdout, and stderr and re-open them as /dev/null, but if the
pipe got passed as fd 3 or higher, it might still be hanging.

Another possible problem is that the application reading the pipe
has failed to close its write end, which would cause the deadlock
you are seeing.

You really need to close fd[1] here.

Alex Fraser

unread,
Apr 29, 2009, 3:34:02 AM4/29/09
to
chsa...@gmail.com wrote:
[snip]

> execl("/bin/sh", "sh", "-c", argv[1], 0);

Not related to the problem, which David and Gordon have pointed out, but
you should cast the last argument so that it is passed as a pointer to
char, as expected by execl, and not an int:
execl("/bin/sh", "sh", "-c", argv[1], (char *)0);

(Because execl takes variable arguments, there is no way to tell the
compiler what the types should be; the rules are such that a bare "0"
will be passed as an int.)

If you don't cast, bad things may happen on a system with a different
size and/or representation for the integer 0 and a null pointer to char.

Alex

Nate Eldredge

unread,
Apr 30, 2009, 12:42:13 AM4/30/09
to
Alex Fraser <m...@privacy.net> writes:

Good call. I have spent a substantial amount of time and energy fixing
this bug in various programs. It causes them to break on my amd64
machine.

By the way, if you use gcc and your system headers are properly
instrumented, -Wformat (enabled by -Wall) will warn about this.

0 new messages