summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbrian <brian@FreeBSD.org>2000-03-22 03:01:53 +0000
committerbrian <brian@FreeBSD.org>2000-03-22 03:01:53 +0000
commit5bda7f13ae4f6baf62ee2b747c0dd16d990a5017 (patch)
treef9f933999acae31349cdb83976e8e52c2473719c
parentb47896e80062927cee8f935e430194387da38913 (diff)
downloadFreeBSD-src-5bda7f13ae4f6baf62ee2b747c0dd16d990a5017.zip
FreeBSD-src-5bda7f13ae4f6baf62ee2b747c0dd16d990a5017.tar.gz
Do some vfork() trickery so that the parent can determine
if the childs exec() has succeeded or failed by taking advantage of the fact that both processes share the same memory. 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() ?
-rw-r--r--usr.sbin/ppp/exec.c44
1 files changed, 37 insertions, 7 deletions
diff --git a/usr.sbin/ppp/exec.c b/usr.sbin/ppp/exec.c
index 5336dd3..e9baa9c 100644
--- a/usr.sbin/ppp/exec.c
+++ b/usr.sbin/ppp/exec.c
@@ -108,7 +108,8 @@ exec_Create(struct physical *p)
log_Printf(LogPHASE, "Unable to create pipe for line exec: %s\n",
strerror(errno));
else {
- int stat, argc, i;
+ static int child_status;
+ int stat, argc, i, ret, wret;
pid_t pid, realpid;
char *argv[MAXARGS];
@@ -122,6 +123,7 @@ exec_Create(struct physical *p)
case -1:
log_Printf(LogPHASE, "Unable to create pipe for line exec: %s\n",
strerror(errno));
+ close(fids[1]);
break;
case 0:
@@ -129,15 +131,20 @@ exec_Create(struct physical *p)
timer_TermService();
setuid(ID0realuid());
- switch (fork()) {
+ child_status = 0;
+ switch (vfork()) {
case 0:
break;
case -1:
+ ret = errno;
log_Printf(LogPHASE, "Unable to fork to drop parent: %s\n",
strerror(errno));
+ _exit(ret);
+ break;
+
default:
- _exit(127);
+ _exit(child_status); /* The error from exec() ! */
}
log_Printf(LogDEBUG, "Exec'ing ``%s''\n", p->name.base);
@@ -145,7 +152,7 @@ exec_Create(struct physical *p)
if ((argc = MakeArgs(p->name.base, argv, VECSIZE(argv),
PARSE_REDUCE|PARSE_NOHASH)) < 0) {
log_Printf(LogWARN, "Syntax error in exec command\n");
- _exit(127);
+ _exit(ESRCH);
}
command_Expand(argv, argc, (char const *const *)argv,
@@ -158,20 +165,43 @@ exec_Create(struct physical *p)
fcntl(i, F_SETFD, 1);
execvp(*argv, argv);
- printf("execvp failed: %s: %s\r\n", *argv, strerror(errno));
- _exit(127);
+ child_status = errno; /* Only works for vfork() */
+ printf("execvp failed: %s: %s\r\n", *argv, strerror(child_status));
+ _exit(child_status);
break;
default:
close(fids[1]);
+ while ((wret = waitpid(pid, &stat, 0)) == -1 && errno == EINTR)
+ ;
+ if (wret == -1) {
+ log_Printf(LogWARN, "Waiting for child process: %s\n",
+ strerror(errno));
+ close(fids[0]);
+ break;
+ } else if (WIFSIGNALED(stat)) {
+ log_Printf(LogWARN, "Child process received sig %d !\n",
+ WTERMSIG(stat));
+ close(fids[0]);
+ break;
+ } else if (WIFSTOPPED(stat)) {
+ log_Printf(LogWARN, "Child process received stop sig %d !\n",
+ WSTOPSIG(stat));
+ /* I guess that's ok.... */
+ } else if ((ret = WEXITSTATUS(stat))) {
+ log_Printf(LogWARN, "Cannot exec \"%s\": %s\n", p->name.base,
+ strerror(ret));
+ close(fids[0]);
+ break;
+ }
p->fd = fids[0];
- waitpid(pid, &stat, 0);
log_Printf(LogDEBUG, "Using descriptor %d for child\n", p->fd);
physical_SetupStack(p, execdevice.name, PHYSICAL_FORCE_ASYNC);
if (p->cfg.cd.necessity != CD_DEFAULT)
log_Printf(LogWARN, "Carrier settings ignored\n");
return &execdevice;
}
+ close(fids[0]);
}
}
OpenPOWER on IntegriCloud