Detecting exec(2) failing after performing fork(2)?

Maarten Litmaath maart at nat.vu.nl
Tue Mar 5 08:15:40 AEST 1991


In article <1991Mar1.205944.13198 at crc.skl.dnd.ca>,
	rosenqui at crc.skl.dnd.ca (Eric Rosenquist) writes:
>In article <shj.667793966 at dkuugin> shj at 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	<stdio.h>
#ifdef	NO_FCNTL
#include	<sys/ioctl.h>
#else
#include	<fcntl.h>
#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 */



More information about the Comp.unix.programmer mailing list