Skip site navigation (1)Skip section navigation (2)
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>

next in thread | previous in thread | raw e-mail | index | archive | help
> > 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




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?Pine.BSF.4.21.0003220101370.22960-100000>