Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 22 Mar 2000 00:17:03 -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:   Re: cvs commit: src/usr.sbin/ppp exec.c
Message-ID:  <Pine.BSF.4.21.0003220010290.20622-100000@green.dyndns.org>
In-Reply-To: <Pine.BSF.4.21.0003212327250.11563-100000@green.dyndns.org>

next in thread | previous in thread | raw e-mail | index | archive | help
On Tue, 21 Mar 2000, Brian Fundakowski Feldman wrote:

> 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() ?

I don't get that problem, exactly, since the parent gets the right
read for me, not 0.  It's not an easy problem you're trying to
solve, and I wish I could think of a better way than this.  Why do
you really care the difference between exec failing and the program
which was execed failing?

Here's a much better example of how it's possible to do what you want:

{"/home/green"}$ ./bar
Hey, dad!  Lemme exec something impossible.
Child exec failed (4186).
Okay, I'll exec something good now.
hello
Child exec succeeded.

#include <sys/types.h>
#include <sys/time.h>

#include <err.h>
#include <stdio.h>
#include <unistd.h>

int
main() {
        fd_set readset;
        struct timeval tv;
        int pipes[2];
        int error, i;
        char data[sizeof(int)];
        char *const impossible[] = { "/", NULL };
        char *const echo[] = { "echo", "hello", NULL };

        error = pipe(pipes);
        if (error != 0)
                err(1, "pipe");
        switch (fork()) {
        default:
                for (i = 0; i < 2; i++) {
                        FD_ZERO(&readset);
                        FD_SET(pipes[0], &readset);
                        tv.tv_sec = 0;
                        tv.tv_usec = 100000;
                        error = select(pipes[0] + 1, &readset, NULL, NULL, &tv);
                        switch (error) {
                        case -1:
                                err(1, "select");
                        case 0:
                                printf("Child exec succeeded.\n");
                                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:
                setsid();
                printf("Hey, dad!  Lemme exec something impossible.\n");
                (void)execve(*impossible, impossible, NULL);
                *(int *)data = 4186;
                if (write(pipes[1], data, sizeof(data)) != sizeof(data))
                        err(1, "child write");
                printf("Okay, I'll exec something good now.\n");   
                if (execve("/bin/echo", echo, NULL) != 0)
                        err(1, "execve");
                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.0003220010290.20622-100000>