From owner-cvs-all Wed Mar 22 2:14:37 2000 Delivered-To: cvs-all@freebsd.org Received: from storm.FreeBSD.org.uk (storm.freebsd.org.uk [194.242.139.170]) by hub.freebsd.org (Postfix) with ESMTP id 06DD737BC70; Wed, 22 Mar 2000 02:14:13 -0800 (PST) (envelope-from brian@Awfulhak.org) Received: from hak.lan.Awfulhak.org (tun.AwfulHak.org [194.242.139.173]) by storm.FreeBSD.org.uk (8.9.3/8.9.3) with ESMTP id KAA28936; Wed, 22 Mar 2000 10:14:00 GMT (envelope-from brian@Awfulhak.org) Received: from hak.lan.Awfulhak.org (localhost [127.0.0.1]) by hak.lan.Awfulhak.org (8.9.3/8.9.3) with ESMTP id KAA01119; Wed, 22 Mar 2000 10:13:56 GMT (envelope-from brian@hak.lan.Awfulhak.org) Message-Id: <200003221013.KAA01119@hak.lan.Awfulhak.org> X-Mailer: exmh version 2.1.1 10/15/1999 To: Brian Fundakowski Feldman Cc: Brian Somers , cvs-committers@FreeBSD.org, cvs-all@FreeBSD.org Subject: Re: Ultimate Re: cvs commit: src/usr.sbin/ppp exec.c In-Reply-To: Message from Brian Fundakowski Feldman of "Wed, 22 Mar 2000 01:03:46 EST." MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-ID: <1111.953720035.1@hak.lan.Awfulhak.org> Date: Wed, 22 Mar 2000 10:13:56 +0000 From: Brian Somers Sender: owner-cvs-all@FreeBSD.ORG Precedence: bulk X-Loop: FreeBSD.ORG > > > 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: [.....] Not quite, but now that you've got me thinking (you're program is pretty close to what I was trying to do). This doesn't make sense ! This works - try ./foo true ./foo alskjd ./foo sleep 100 #include #include #include #include #include #include #include #include int main(int argc, char **argv) { int pipes[2], error, status, ret; pid_t pid; if (argc <= 1) errx(1, "Tell me what to exec"); switch ((pid = fork())) { default: while ((error = wait(&status)) == -1 && errno == EINTR) ; if (error == -1) err(1, "parent wait"); else { fputs("Parent: ", stdout); if (WIFEXITED(status)) printf("child exited with status %d.\n", WEXITSTATUS(status)); else if (WIFSIGNALED(status)) printf("child exited on signal %d.\n", WTERMSIG(status)); else printf("child stoped on signal %d.\n", WSTOPSIG(status)); } exit(0); case -1: err(1, "fork"); case 0: error = pipe(pipes); if (error != 0) err(1, "intermediate pipe"); switch (fork()) { /* Don't want defunct processes */ case 0: close(pipes[0]); break; case -1: ret = errno; close(pipes[0]); close(pipes[1]); _exit(ret); default: /* * Intermediate - find out what the child can * do and report to parent */ close(pipes[1]); error = read(pipes[0], &ret, sizeof ret); switch (error) { case -1: ret = errno; break; case 0: printf("Intermediate: 0 from read (good!)\n"); ret = 0; break; case sizeof ret: break; default: ret = EIO; break; } _exit(ret); } /* * Child. Exec the process, reporting to the parent via * pipes[1] */ if (fcntl(pipes[1], F_SETFD, 1) != 0) err(1, "Child: fcntl"); printf("Child: execing %s\n", argv[1]); execvp(argv[1], argv + 1); ret = errno; if (write(pipes[1], &ret, sizeof ret) != sizeof ret) err(1, "Child write"); printf("Child: sent status %d after failure\n", ret); _exit(ret); } } *BUT*, now try the attached patches to ppp. You want to have an empty default: section and then this in ppp.conf: exec: set ifaddr 127.0.0.2 127.0.0.3 set device "!/bin/pwx" "!/bin/pwy" set redial 2 2 Then run ``ppp -b exec''. With the current code, it correctly fails to execute pwx and tries pwy and gets things right. With the patched code (which *should* work) it craps out at the first hurdle 'cos it things the exec succeeded - see the diagnostics ! So go figure :*P > -- > Brian Fundakowski Feldman \ FreeBSD: The Power to Serve! / > green@FreeBSD.org `------------------------------' Index: exec.c =================================================================== RCS file: /home/ncvs/src/usr.sbin/ppp/exec.c,v retrieving revision 1.21 diff -u -r1.21 exec.c --- exec.c 2000/03/22 03:01:53 1.21 +++ exec.c 2000/03/22 09:07:43 @@ -109,7 +109,7 @@ strerror(errno)); else { static int child_status; - int stat, argc, i, ret, wret; + int stat, argc, i, ret, wret, fd[2]; pid_t pid, realpid; char *argv[MAXARGS]; @@ -131,19 +131,42 @@ timer_TermService(); setuid(ID0realuid()); - child_status = 0; - switch (vfork()) { + if (pipe(fd) == -1) + _exit(errno); + + switch (fork()) { case 0: + close(fd[0]); break; case -1: ret = errno; + close(fd[0]); + close(fd[1]); log_Printf(LogPHASE, "Unable to fork to drop parent: %s\n", strerror(errno)); _exit(ret); break; default: + close(fd[1]); + switch ((ret = read(fd[0], &child_status, sizeof child_status))) { + case -1: + child_status = errno; + break; + + case 0: + log_Printf(LogPHASE, "Cool ! Got zero from read !\n"); + child_status = 0; + break; + + case sizeof wret: + break; + + default: + child_status = EIO; + break; + } _exit(child_status); /* The error from exec() ! */ } @@ -163,10 +186,17 @@ dup2(fids[1], STDERR_FILENO); for (i = getdtablesize(); i > STDERR_FILENO; i--) fcntl(i, F_SETFD, 1); + fcntl(fd[1], F_SETFD, 1); execvp(*argv, argv); - child_status = errno; /* Only works for vfork() */ + child_status = errno; printf("execvp failed: %s: %s\r\n", *argv, strerror(child_status)); + wret = write(fd[1], &child_status, sizeof child_status); + if (wret == sizeof child_status) + log_Printf(LogPHASE, "Reported exec failure %d\n", child_status); + else + log_Printf(LogPHASE, "Didn't report exec failure %d !\n", + child_status); _exit(child_status); break; -- Brian Don't _EVER_ lose your sense of humour ! To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe cvs-all" in the body of the message