popen.c revision 45369
12311Sjkh/*
22311Sjkh * Copyright (c) 1988 The Regents of the University of California.
32311Sjkh * All rights reserved.
42311Sjkh *
52311Sjkh * This code is derived from software written by Ken Arnold and
62311Sjkh * published in UNIX Review, Vol. 6, No. 8.
72311Sjkh *
82311Sjkh * Redistribution and use in source and binary forms are permitted
92311Sjkh * provided that the above copyright notice and this paragraph are
102311Sjkh * duplicated in all such forms and that any documentation,
112311Sjkh * advertising materials, and other materials related to such
122311Sjkh * distribution and use acknowledge that the software was developed
132311Sjkh * by the University of California, Berkeley.  The name of the
142311Sjkh * University may not be used to endorse or promote products derived
152311Sjkh * from this software without specific prior written permission.
162311Sjkh * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
172311Sjkh * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
182311Sjkh * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
192311Sjkh *
202311Sjkh */
212311Sjkh
222311Sjkh/* this came out of the ftpd sources; it's been modified to avoid the
232311Sjkh * globbing stuff since we don't need it.  also execvp instead of execv.
242311Sjkh */
252311Sjkh
262311Sjkh#ifndef lint
2729452Scharnier#if 0
282311Sjkhstatic char sccsid[] = "@(#)popen.c	5.7 (Berkeley) 2/14/89";
2929452Scharnier#endif
3029452Scharnierstatic const char rcsid[] =
3145369Speter	"$Id: popen.c,v 1.5 1997/09/15 06:39:07 charnier Exp $";
322311Sjkh#endif /* not lint */
332311Sjkh
342311Sjkh#include "cron.h"
352311Sjkh#include <sys/signal.h>
3645369Speter#include <fcntl.h>
372311Sjkh
382311Sjkh
3920573Spst#define MAX_ARGS 100
402311Sjkh#define WANT_GLOBBING 0
412311Sjkh
422311Sjkh/*
432311Sjkh * Special version of popen which avoids call to shell.  This insures noone
442311Sjkh * may create a pipe to a hidden program as a side effect of a list or dir
452311Sjkh * command.
462311Sjkh */
472311Sjkhstatic PID_T *pids;
482311Sjkhstatic int fds;
492311Sjkh
502311SjkhFILE *
512311Sjkhcron_popen(program, type)
522311Sjkh	char *program, *type;
532311Sjkh{
542311Sjkh	register char *cp;
552311Sjkh	FILE *iop;
562311Sjkh	int argc, pdes[2];
572311Sjkh	PID_T pid;
5820573Spst	char *argv[MAX_ARGS + 1];
592311Sjkh#if WANT_GLOBBING
602311Sjkh	char **pop, *vv[2];
612311Sjkh	int gargc;
622311Sjkh	char *gargv[1000];
632311Sjkh	extern char **glob(), **copyblk();
642311Sjkh#endif
652311Sjkh
6629452Scharnier	if ((*type != 'r' && *type != 'w') || type[1])
672311Sjkh		return(NULL);
682311Sjkh
692311Sjkh	if (!pids) {
702311Sjkh		if ((fds = getdtablesize()) <= 0)
712311Sjkh			return(NULL);
722311Sjkh		if (!(pids = (PID_T *)malloc((u_int)(fds * sizeof(PID_T)))))
732311Sjkh			return(NULL);
742311Sjkh		bzero((char *)pids, fds * sizeof(PID_T));
752311Sjkh	}
762311Sjkh	if (pipe(pdes) < 0)
772311Sjkh		return(NULL);
782311Sjkh
792311Sjkh	/* break up string into pieces */
8020573Spst	for (argc = 0, cp = program; argc < MAX_ARGS; cp = NULL)
812311Sjkh		if (!(argv[argc++] = strtok(cp, " \t\n")))
822311Sjkh			break;
832311Sjkh
842311Sjkh#if WANT_GLOBBING
852311Sjkh	/* glob each piece */
862311Sjkh	gargv[0] = argv[0];
872311Sjkh	for (gargc = argc = 1; argv[argc]; argc++) {
882311Sjkh		if (!(pop = glob(argv[argc]))) {	/* globbing failed */
892311Sjkh			vv[0] = argv[argc];
902311Sjkh			vv[1] = NULL;
912311Sjkh			pop = copyblk(vv);
922311Sjkh		}
932311Sjkh		argv[argc] = (char *)pop;		/* save to free later */
942311Sjkh		while (*pop && gargc < 1000)
952311Sjkh			gargv[gargc++] = *pop++;
962311Sjkh	}
972311Sjkh	gargv[gargc] = NULL;
982311Sjkh#endif
992311Sjkh
1002311Sjkh	iop = NULL;
1012311Sjkh	switch(pid = vfork()) {
1022311Sjkh	case -1:			/* error */
1032311Sjkh		(void)close(pdes[0]);
1042311Sjkh		(void)close(pdes[1]);
1052311Sjkh		goto pfree;
1062311Sjkh		/* NOTREACHED */
1072311Sjkh	case 0:				/* child */
1082311Sjkh		if (*type == 'r') {
10945369Speter			/* Do not share our parent's stdin */
11045369Speter			(void)close(0);
11145369Speter			(void)open("/dev/null", O_RDWR);
1122311Sjkh			if (pdes[1] != 1) {
1132311Sjkh				dup2(pdes[1], 1);
1142311Sjkh				dup2(pdes[1], 2);	/* stderr, too! */
1152311Sjkh				(void)close(pdes[1]);
1162311Sjkh			}
1172311Sjkh			(void)close(pdes[0]);
1182311Sjkh		} else {
1192311Sjkh			if (pdes[0] != 0) {
1202311Sjkh				dup2(pdes[0], 0);
1212311Sjkh				(void)close(pdes[0]);
1222311Sjkh			}
12345369Speter			/* Hack: stdout gets revoked */
12445369Speter			(void)close(1);
12545369Speter			(void)open("/dev/null", O_RDWR);
12645369Speter			(void)close(2);
12745369Speter			(void)open("/dev/null", O_RDWR);
1282311Sjkh			(void)close(pdes[1]);
1292311Sjkh		}
1302311Sjkh#if WANT_GLOBBING
1312311Sjkh		execvp(gargv[0], gargv);
1322311Sjkh#else
1332311Sjkh		execvp(argv[0], argv);
1342311Sjkh#endif
1352311Sjkh		_exit(1);
1362311Sjkh	}
1372311Sjkh	/* parent; assume fdopen can't fail...  */
1382311Sjkh	if (*type == 'r') {
1392311Sjkh		iop = fdopen(pdes[0], type);
1402311Sjkh		(void)close(pdes[1]);
1412311Sjkh	} else {
1422311Sjkh		iop = fdopen(pdes[1], type);
1432311Sjkh		(void)close(pdes[0]);
1442311Sjkh	}
1452311Sjkh	pids[fileno(iop)] = pid;
1462311Sjkh
1472311Sjkhpfree:
1482311Sjkh#if WANT_GLOBBING
1492311Sjkh	for (argc = 1; argv[argc] != NULL; argc++) {
1502311Sjkh/*		blkfree((char **)argv[argc]);	*/
1512311Sjkh		free((char *)argv[argc]);
1522311Sjkh	}
1532311Sjkh#endif
1542311Sjkh	return(iop);
1552311Sjkh}
1562311Sjkh
1572311Sjkhint
1582311Sjkhcron_pclose(iop)
1592311Sjkh	FILE *iop;
1602311Sjkh{
1612311Sjkh	register int fdes;
1622311Sjkh	int omask;
1632311Sjkh	WAIT_T stat_loc;
1642311Sjkh	PID_T pid;
1652311Sjkh
1662311Sjkh	/*
1672311Sjkh	 * pclose returns -1 if stream is not associated with a
1682311Sjkh	 * `popened' command, or, if already `pclosed'.
1692311Sjkh	 */
1702311Sjkh	if (pids == 0 || pids[fdes = fileno(iop)] == 0)
1712311Sjkh		return(-1);
1722311Sjkh	(void)fclose(iop);
1732311Sjkh	omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
1742311Sjkh	while ((pid = wait(&stat_loc)) != pids[fdes] && pid != -1)
1752311Sjkh		;
1762311Sjkh	(void)sigsetmask(omask);
1772311Sjkh	pids[fdes] = 0;
1782311Sjkh	return (pid == -1 ? -1 : WEXITSTATUS(stat_loc));
1792311Sjkh}
180