Date: Wed, 22 Mar 2000 01:03:46 -0500 (EST) From: Brian Fundakowski Feldman <green@FreeBSD.org> To: Brian Somers <brian@FreeBSD.org> Cc: cvs-committers@FreeBSD.org, cvs-all@FreeBSD.org Subject: Ultimate Re: cvs commit: src/usr.sbin/ppp exec.c Message-ID: <Pine.BSF.4.21.0003220101370.22960-100000@green.dyndns.org> In-Reply-To: <Pine.BSF.4.21.0003220010290.20622-100000@green.dyndns.org>
index | next in thread | previous in thread | raw e-mail
> > On Tue, 21 Mar 2000, Brian Somers wrote:
> >
> > > FWIW:
> > > I tried to implement this by doing a pipe(), setting the
> > > write desciptors close-on-exec flag in the child and writing
> > > errno to the descriptor if the exec() fails. The parent can
> > > then ``if (read()) got errno else exec worked''.
> > >
> > > This didn't work though - the child could write() to fd[1] on
> > > exec failure, but the parent got 0 trying to read() from fd[0] !
> > > Is this a bug in execve() ?
Finally! I have what I think is exactly what you want. Here's the
test output:
{"/home/green"}$ cc -DCASEONE -O -o bar bar.c
{"/home/green"}$ ./bar
Hey, dad! Lemme exec something impossible.
Wait completed for pid 22969.
Child exec failed (13).
{"/home/green"}$ cc -UCASEONE -O -o bar bar.c
{"/home/green"}$ ./bar
Okay, I'll exec something good now.
Wait completed for pid 22976.
Child exec succeeded, exited with status 42.
#include <sys/types.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
int
main() {
int pipes[2];
int error, i;
fd_set readset;
struct timeval tv = { 0, 0 };
int status;
char data[sizeof(int)];
char *const impossible[] = { "/", NULL };
char *const test[] = { "sh", "-c", "exit 42", NULL };
error = pipe(pipes);
if (error != 0)
err(1, "pipe");
if (fcntl(pipes[0], F_SETFD, 1) != 0 ||
fcntl(pipes[1], F_SETFD, 1) != 0)
err(1, "fcntl");
switch (fork()) {
default:
error = wait(&status);
if (error == -1)
err(1, "wait");
printf("Wait completed for pid %d.\n", error);
FD_ZERO(&readset);
FD_SET(pipes[0], &readset);
error = select(pipes[0] + 1, &readset, NULL, NULL, &tv);
switch (error) {
case -1:
err(1, "select");
case 0:
printf("Child exec succeeded, ");
if (WIFEXITED(status))
printf("exited with status %d.\n",
WEXITSTATUS(status));
else if (WIFSIGNALED(status))
printf("exited on signal %d.\n",
WTERMSIG(status));
else
printf("stoped on signal %d.\n",
WSTOPSIG(status));
break;
case 1:
if (read(pipes[0], data, sizeof(data)) !=
sizeof(data))
err(1, "parent read");
printf("Child exec failed (%d).\n",
*(int *)data);
}
exit(0);
case -1:
err(1, "fork");
case 0:
#ifdef CASEONE
printf("Hey, dad! Lemme exec something impossible.\n");
(void)execve(*impossible, impossible, NULL);
*(int *)data = errno;
if (write(pipes[1], data, sizeof(data)) != sizeof(data))
err(1, "child write");
#else
printf("Okay, I'll exec something good now.\n");
if (execve("/bin/sh", test, NULL) != 0)
err(1, "execve");
#endif
exit(0);
}
}
--
Brian Fundakowski Feldman \ FreeBSD: The Power to Serve! /
green@FreeBSD.org `------------------------------'
To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe cvs-all" in the body of the message
help
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?Pine.BSF.4.21.0003220101370.22960-100000>
