Detecting exec(2) failing after performing fork(2)?
Maarten Litmaath
maart at nat.vu.nl
Tue Mar 12 08:20:53 AEST 1991
In article <shj.668447405 at dkuugin>,
shj at login.dkuug.dk (Stig Jacobsen) writes:
>[...]
>Since I didn't want to wait() for anything, I just performed
>another fork() in the spawn() function and then let the first
>child exit() imediately, so that the second child would get init
>(process 1) as parent. This way I avoid a zombie process.
>
>Rather wastefull, yes, but I couldn't find another way to
>disassociate my child process from the parent.
This is quite a normal (portable!) way to dispose of child processes.
Right, I've composed a general spawn() example, included below.
Note that the calling syntax and semantics have changed.
Enjoy!
--------------------cut here--------------------
/*
* spawn.c
*
* Usage:
*
* char *command, *argv[];
* int status, *pidp, *errp, (*preamble)();
*
* status = spawn(command, argv, pidp, errp, preamble);
*
* Spawn `command' with arguments `argv' (argv[0] is the name);
* the `argv' array ends with a NULL pointer.
*
* If `preamble' is not a NULL pointer, the addressed function will be
* called in the child (before the execvp(), of course) with arguments
* `command' and `argv'. This function may set some signals to be ignored,
* reset the process group, redirect input, etc. Only if it returns 0 the
* call to execvp() will be made; else spawn() will return -3 and if `errp'
* is not a NULL pointer the return value of `preamble' will be copied into
* `*errp'.
*
* The process ID of the child is copied into `*pidp', unless `pidp' is a
* NULL pointer.
*
* The return value of spawn() itself is 0 on success, -1 if it could not
* create the pipe that it needs, -2 if it could not fork(), -3 if `preamble'
* was nonnull and did not return 0, and -4 if the execvp() failed.
*
* In the last case the errno value indicating why the execvp() failed
* is copied into `*errp', unless `errp' is a NULL pointer.
*
* Compile with `-DNO_FCNTL' if your UNIX variant doesn't have fcntl(2).
* Compile with `-DNO_STRERROR' if it doesn't have strerror(3).
*
* Author: Maarten Litmaath @ Dept. of Physics, Vrije University Amsterdam
* Email: maart at nat.vu.nl
* Date: 11 Mar 91
*/
#include <stdio.h>
#ifdef NO_FCNTL
#include <sys/ioctl.h>
#else
#include <fcntl.h>
#endif /* NO_FCNTL */
main(argc, argv)
int argc;
char **argv;
{
int status, spawn(), pid, error, preamble();
char *strerror();
if (argc == 1) {
fprintf(stderr, "Usage: %s command args\n", argv[0]);
exit(1);
}
/* start background job */
status = spawn(argv[1], &argv[1], &pid, &error, preamble);
switch (status) {
case 0:
printf("The execvp() in the child succeeded.\n");
printf("The child has process ID %d.\n", pid);
break;
case -1:
perror("pipe");
break;
case -2:
perror("fork");
break;
case -3:
printf("The preamble function returned %d.\n", error);
break;
case -4:
printf("The execvp() in the child failed.\n");
printf("The reason was: %s.\n", strerror(error));
break;
default:
printf("Values of %d will give rise to dom!\n", status);
/* pseudo V6 */
break;
}
return status;
}
int spawn(cmd, argv, pidp, errp, preamble)
char *cmd, **argv;
int *pidp, *errp, (*preamble)();
{
extern int errno;
int pp[2], n, pid;
struct error {
int status, errno;
} err;
if (pipe(pp) < 0)
return -1;
switch (pid = fork()) {
case -1:
close(pp[0]);
close(pp[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 */
if (preamble && (err.errno = (*preamble)(cmd, argv)) != 0)
err.status = -3;
else {
execvp(cmd, argv);
err.errno = errno;
err.status = -4;
}
/* send a message indicating the failure */
write(pp[1], (char *) &err, sizeof err);
_exit(1);
}
if (pidp)
*pidp = pid;
close(pp[1]);
n = read(pp[0], (char *) &err, sizeof err);
close(pp[0]);
if (n != 0 && errp)
*errp = err.errno;
return n == 0 ? 0 : err.status;
}
#include <signal.h>
static int Signals[] = {
SIGHUP, /* ignore SIGHUP (on logout or hangup) */
SIGINT, /* ignore interrupts */
SIGQUIT, /* ignore quits */
#ifdef SIGTSTP
SIGTSTP, /* ignore keyboard stop signals */
#endif /* SIGTSTP */
0
};
/* ARGSUSED */
int preamble(cmd, argv)
char *cmd, **argv;
{
int *sigp;
for (sigp = Signals; *sigp; sigp++)
signal(*sigp, SIG_IGN);
return 0;
}
#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 */
More information about the Comp.unix.programmer
mailing list