Path: utzoo!news-server.csri.toronto.edu!cs.utexas.edu!uunet!mcsun!hp4nl!star.cs.vu.nl!nat.vu.nl!maart From: maart@nat.vu.nl (Maarten Litmaath) Newsgroups: comp.unix.programmer Subject: Re: Detecting exec(2) failing after performing fork(2)? Keywords: pipe, close-on-exec Message-ID: <1991Mar4.231540.17644@nat.vu.nl> Date: 4 Mar 91 22:15:40 GMT References: <1991Mar1.205944.13198@crc.skl.dnd.ca> Organization: Dept. of Physics, Vrije University Amsterdam Lines: 119 In article <1991Mar1.205944.13198@crc.skl.dnd.ca>, rosenqui@crc.skl.dnd.ca (Eric Rosenquist) writes: >In article shj@login.dkuug.dk (Stig Jacobsen) writes: >>When my application desires to spawn off a background process, >>I use something roughly like this: >> >>int spawn(char *path, ...) >>{ >> >> if (fork() == 0) >> execlp(path, NULL); >> >>} >> >>This is fine if the exec..() call goes well. However, if the exec() >>call fails, the error is not reported back to the parent. I get >>a SIGCLD of course, but what I'd really like is that my spawn() >>function just returns an error, if the exec() call fails. ... >> ... > >It's too late once the fork() has completed. [...] Wrong. The following example shows how it can be done. (I used execvp() instead of execlp().) ------------------------------------------------------------ /* * Compile with `-DNO_FCNTL' if your UNIX variant doesn't have fcntl(2). * Compile with `-DNO_STRERROR' if it doesn't have strerror(3). */ #include #ifdef NO_FCNTL #include #else #include #endif /* NO_FCNTL */ main(argc, argv) int argc; char **argv; { int err, spawn(); char *strerror(); if (argc == 1) { fprintf(stderr, "Usage: %s command args\n", argv[0]); exit(1); } err = spawn(&argv[1]); switch (err) { case -1: perror("pipe"); break; case -2: perror("fork"); break; default: printf("The execvp() in the child %s.\n", err == 0 ? "succeeded" : "failed"); if (err != 0) printf("The reason was: %s.\n", strerror(err)); } } int spawn(argv) char **argv; { extern int errno; int pp[2], n, err; if (pipe(pp) < 0) return -1; switch (fork()) { case -1: return -2; case 0: close(pp[0]); /* set close-on-exec flag */ #ifdef NO_FCNTL ioctl(pp[1], FIOCLEX, (int *) 0); #else fcntl(pp[1], F_SETFD, 1); #endif /* NO_FCNTL */ execvp(*argv, argv); /* send a message indicating the failure */ write(pp[1], (char *) &errno, sizeof errno); _exit(1); } close(pp[1]); n = read(pp[0], (char *) &err, sizeof err); close(pp[0]); return n == 0 ? 0 : err; } #ifdef NO_STRERROR char *strerror(n) int n; { extern int errno, sys_nerr; extern char *sys_errlist[]; static char buf[32]; if ((unsigned) n < sys_nerr) return sys_errlist[n]; sprintf(buf, "Unknown error %d", n); return buf; } #endif /* NO_STRERROR */