xref: /onnv-gate/usr/src/cmd/lp/cmd/lpsched/exec.c (revision 320:7e1ecf3ab9be)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
230Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
27*320Sceastha /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28*320Sceastha /*	  All Rights Reserved  	*/
29*320Sceastha 
300Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
310Sstevel@tonic-gate 
320Sstevel@tonic-gate #include <dial.h>
330Sstevel@tonic-gate 
340Sstevel@tonic-gate #include <stdlib.h>
350Sstevel@tonic-gate #include "limits.h"
360Sstevel@tonic-gate #include "stdarg.h"
370Sstevel@tonic-gate #include "wait.h"
380Sstevel@tonic-gate #include "dial.h"
390Sstevel@tonic-gate #include "lpsched.h"
400Sstevel@tonic-gate #include <syslog.h>
410Sstevel@tonic-gate #include <pwd.h>
420Sstevel@tonic-gate 
430Sstevel@tonic-gate #define Done(EC,ERRNO)	done(((EC) << 8),ERRNO)
440Sstevel@tonic-gate 
450Sstevel@tonic-gate #define	STRLCAT(dst, src, size) \
460Sstevel@tonic-gate 	if (strlcat((dst), (src), (size)) >= (size)) { \
470Sstevel@tonic-gate 		errno = EINVAL; \
480Sstevel@tonic-gate 		return (-1); \
490Sstevel@tonic-gate 	}
500Sstevel@tonic-gate 
510Sstevel@tonic-gate static MESG *		ChildMd;
520Sstevel@tonic-gate 
530Sstevel@tonic-gate static int		ChildPid;
540Sstevel@tonic-gate static int		WaitedChildPid;
550Sstevel@tonic-gate static int		slot;
560Sstevel@tonic-gate static int		do_undial;
570Sstevel@tonic-gate 
580Sstevel@tonic-gate static char		argbuf[ARG_MAX];
590Sstevel@tonic-gate 
600Sstevel@tonic-gate static long		key;
610Sstevel@tonic-gate 
620Sstevel@tonic-gate static void		sigtrap ( int );
630Sstevel@tonic-gate static void		done ( int , int );
640Sstevel@tonic-gate static void		cool_heels ( void );
650Sstevel@tonic-gate static void		addenv (char ***envp, char * , char * );
660Sstevel@tonic-gate static void		trap_fault_signals ( void );
670Sstevel@tonic-gate static void		ignore_fault_signals ( void );
680Sstevel@tonic-gate static void		child_mallocfail ( void );
690Sstevel@tonic-gate static void		Fork2 ( void );
700Sstevel@tonic-gate 
710Sstevel@tonic-gate static int		Fork1 ( EXEC * );
720Sstevel@tonic-gate 
730Sstevel@tonic-gate static void
740Sstevel@tonic-gate relock(void)
750Sstevel@tonic-gate {
760Sstevel@tonic-gate 	struct flock		l;
770Sstevel@tonic-gate 
780Sstevel@tonic-gate 	l.l_type = F_WRLCK;
790Sstevel@tonic-gate 	l.l_whence = 1;
800Sstevel@tonic-gate 	l.l_start = 0;
810Sstevel@tonic-gate 	l.l_len = 0;
820Sstevel@tonic-gate 	(void)Fcntl (lock_fd, F_SETLK, &l);
830Sstevel@tonic-gate 	return;
840Sstevel@tonic-gate }
850Sstevel@tonic-gate 
860Sstevel@tonic-gate static char *_exec_name(int type)
870Sstevel@tonic-gate {
880Sstevel@tonic-gate 	static char *_names[] = {
890Sstevel@tonic-gate 	"", "EX_INTERF", "EX_SLOWF", "EX_ALERT", "EX_FALERT", "EX_PALERT",
900Sstevel@tonic-gate 	"EX_NOTIFY", "EX_FAULT_MESSAGE", "EX_FORM_MESSAGE", NULL };
910Sstevel@tonic-gate 
920Sstevel@tonic-gate 	if ((type < 0) || (type > EX_FORM_MESSAGE))
930Sstevel@tonic-gate 		return ("BAD_EXEC_TYPE");
940Sstevel@tonic-gate 	else
950Sstevel@tonic-gate 		return (_names[type]);
960Sstevel@tonic-gate }
970Sstevel@tonic-gate 
980Sstevel@tonic-gate /*
990Sstevel@tonic-gate  * This function replaces characters in a string that might be used
1000Sstevel@tonic-gate  * to exploit a security hole.  Replace command seperators (`, &, ;, |, ^),
1010Sstevel@tonic-gate  * output redirection (>, |), variable expansion ($), and character
1020Sstevel@tonic-gate  * escape (\).
1030Sstevel@tonic-gate  *
1040Sstevel@tonic-gate  * Bugid 4141687
1050Sstevel@tonic-gate  * Add ( ) < * ? [
1060Sstevel@tonic-gate  * Bugid 4139071
1070Sstevel@tonic-gate  * Remove \
1080Sstevel@tonic-gate  */
1090Sstevel@tonic-gate void clean_string(char *ptr)
1100Sstevel@tonic-gate {
1110Sstevel@tonic-gate 	char *cp;
1120Sstevel@tonic-gate 	wchar_t wc;
1130Sstevel@tonic-gate 	size_t len;
1140Sstevel@tonic-gate 
1150Sstevel@tonic-gate 	for (cp = ptr; *cp != NULL; ) {
1160Sstevel@tonic-gate 		if ((len = mbtowc(&wc, cp, MB_CUR_MAX)) == -1) {
1170Sstevel@tonic-gate 			cp++;
1180Sstevel@tonic-gate 			continue;
1190Sstevel@tonic-gate 		}
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate 		if (len == 1 &&
1220Sstevel@tonic-gate 		    ((wc == L'`') || (wc == L'&') || (wc == L';') ||
1230Sstevel@tonic-gate 		    (wc == L'|') || (wc == L'>') || (wc == L'^') ||
1240Sstevel@tonic-gate 		    (wc == L'$') || (wc == L'(') || (wc == L')') ||
1250Sstevel@tonic-gate 		    (wc == L'<') || (wc == L'*') || (wc == L'?') ||
1260Sstevel@tonic-gate 		    (wc == L'[')))
1270Sstevel@tonic-gate 			*cp = '_';
1280Sstevel@tonic-gate 		cp += len;
1290Sstevel@tonic-gate 	}
1300Sstevel@tonic-gate }
1310Sstevel@tonic-gate 
1320Sstevel@tonic-gate enum trust {TRUSTED, UNTRUSTED};
1330Sstevel@tonic-gate static char *
1340Sstevel@tonic-gate arg_string(enum trust type, char *fmt, ...)
1350Sstevel@tonic-gate {
1360Sstevel@tonic-gate 	char buf[BUFSIZ];
1370Sstevel@tonic-gate 	va_list	args;
1380Sstevel@tonic-gate 
1390Sstevel@tonic-gate 	va_start(args, fmt);
1400Sstevel@tonic-gate 	(void) vsnprintf(buf, sizeof(buf), fmt, args);
1410Sstevel@tonic-gate 	va_end(args);
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate 	/*
1440Sstevel@tonic-gate 	 * If the string contains data from an untrusted origin (user supplied),
1450Sstevel@tonic-gate 	 * clean it up in case one of our progeny is a shell script and isn't
1460Sstevel@tonic-gate 	 * careful about checking its input.
1470Sstevel@tonic-gate 	 */
1480Sstevel@tonic-gate 	if (type == UNTRUSTED)
1490Sstevel@tonic-gate 		clean_string(buf);
1500Sstevel@tonic-gate 
1510Sstevel@tonic-gate 	return (strdup(buf));
1520Sstevel@tonic-gate }
1530Sstevel@tonic-gate 
1540Sstevel@tonic-gate /* stolen from libc/gen/port/gen/execvp.c */
1550Sstevel@tonic-gate static const char *
1560Sstevel@tonic-gate execat(const char *s1, const char *s2, char *si)
1570Sstevel@tonic-gate {
1580Sstevel@tonic-gate         char    *s;
1590Sstevel@tonic-gate         int cnt = PATH_MAX + 1; /* number of characters in s2 */
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate         s = si;
1620Sstevel@tonic-gate         while (*s1 && *s1 != ':') {
1630Sstevel@tonic-gate                 if (cnt > 0) {
1640Sstevel@tonic-gate                         *s++ = *s1++;
1650Sstevel@tonic-gate                         cnt--;
1660Sstevel@tonic-gate                 } else
1670Sstevel@tonic-gate                         s1++;
1680Sstevel@tonic-gate         }
1690Sstevel@tonic-gate         if (si != s && cnt > 0) {
1700Sstevel@tonic-gate                 *s++ = '/';
1710Sstevel@tonic-gate                 cnt--;
1720Sstevel@tonic-gate         }
1730Sstevel@tonic-gate         while (*s2 && cnt > 0) {
1740Sstevel@tonic-gate                 *s++ = *s2++;
1750Sstevel@tonic-gate                 cnt--;
1760Sstevel@tonic-gate         }
1770Sstevel@tonic-gate         *s = '\0';
1780Sstevel@tonic-gate         return (*s1 ? ++s1: 0);
1790Sstevel@tonic-gate }
1800Sstevel@tonic-gate 
1810Sstevel@tonic-gate /*
1820Sstevel@tonic-gate  * Similiar to execvp(), execpt you can supply an environment and we always
1830Sstevel@tonic-gate  * use /bin/sh for shell scripts.  The PATH searched is the PATH in the
1840Sstevel@tonic-gate  * current environment, not the environment in the argument list.
1850Sstevel@tonic-gate  * This was pretty much stolen from libc/gen/port/execvp.c
1860Sstevel@tonic-gate  */
1870Sstevel@tonic-gate static int
1880Sstevel@tonic-gate execvpe(char *name, char *const argv[], char *const envp[])
1890Sstevel@tonic-gate {
1900Sstevel@tonic-gate 	char *path;
1910Sstevel@tonic-gate 	char fname[PATH_MAX+2];
1920Sstevel@tonic-gate 	char *newargs[256];
1930Sstevel@tonic-gate 	int i;
1940Sstevel@tonic-gate 	const char *cp;
1950Sstevel@tonic-gate 	unsigned etxtbsy = 1;
1960Sstevel@tonic-gate         int eacces = 0;
1970Sstevel@tonic-gate 
1980Sstevel@tonic-gate 	if (*name == '\0') {
1990Sstevel@tonic-gate 		errno = ENOENT;
2000Sstevel@tonic-gate 		return (-1);
2010Sstevel@tonic-gate 	}
2020Sstevel@tonic-gate 
2030Sstevel@tonic-gate 	if ((path = getenv("PATH")) == NULL)
2040Sstevel@tonic-gate 		path = "/usr/bin:/bin";
2050Sstevel@tonic-gate 
2060Sstevel@tonic-gate         cp = strchr(name, '/')? (const char *)"": path;
2070Sstevel@tonic-gate 
2080Sstevel@tonic-gate         do {
2090Sstevel@tonic-gate                 cp = execat(cp, name, fname);
2100Sstevel@tonic-gate         retry:
2110Sstevel@tonic-gate                 /*
2120Sstevel@tonic-gate                  * 4025035 and 4038378
2130Sstevel@tonic-gate                  * if a filename begins with a "-" prepend "./" so that
2140Sstevel@tonic-gate                  * the shell can't interpret it as an option
2150Sstevel@tonic-gate                  */
2160Sstevel@tonic-gate                 if (*fname == '-') {
2170Sstevel@tonic-gate                         size_t size = strlen(fname) + 1;
2180Sstevel@tonic-gate                         if ((size + 2) > sizeof (fname)) {
2190Sstevel@tonic-gate                                 errno = E2BIG;
2200Sstevel@tonic-gate                                 return (-1);
2210Sstevel@tonic-gate                         }
2220Sstevel@tonic-gate                         (void) memmove(fname + 2, fname, size);
2230Sstevel@tonic-gate                         fname[0] = '.';
2240Sstevel@tonic-gate                         fname[1] = '/';
2250Sstevel@tonic-gate                 }
2260Sstevel@tonic-gate                 (void) execve(fname, argv, envp);
2270Sstevel@tonic-gate                 switch (errno) {
2280Sstevel@tonic-gate                 case ENOEXEC:
2290Sstevel@tonic-gate                         newargs[0] = "sh";
2300Sstevel@tonic-gate                         newargs[1] = fname;
2310Sstevel@tonic-gate                         for (i = 1; (newargs[i + 1] = argv[i]) != NULL; ++i) {
2320Sstevel@tonic-gate                                 if (i >= 254) {
2330Sstevel@tonic-gate                                         errno = E2BIG;
2340Sstevel@tonic-gate                                         return (-1);
2350Sstevel@tonic-gate                                 }
2360Sstevel@tonic-gate                         }
2370Sstevel@tonic-gate                         (void) execve("/bin/sh", newargs, envp);
2380Sstevel@tonic-gate                         return (-1);
2390Sstevel@tonic-gate                 case ETXTBSY:
2400Sstevel@tonic-gate                         if (++etxtbsy > 5)
2410Sstevel@tonic-gate                                 return (-1);
2420Sstevel@tonic-gate                         (void) sleep(etxtbsy);
2430Sstevel@tonic-gate                         goto retry;
2440Sstevel@tonic-gate                 case EACCES:
2450Sstevel@tonic-gate                         ++eacces;
2460Sstevel@tonic-gate                         break;
2470Sstevel@tonic-gate                 case ENOMEM:
2480Sstevel@tonic-gate                 case E2BIG:
2490Sstevel@tonic-gate                 case EFAULT:
2500Sstevel@tonic-gate                         return (-1);
2510Sstevel@tonic-gate                 }
2520Sstevel@tonic-gate         } while (cp);
2530Sstevel@tonic-gate         if (eacces)
2540Sstevel@tonic-gate                 errno = EACCES;
2550Sstevel@tonic-gate         return (-1);
2560Sstevel@tonic-gate }
2570Sstevel@tonic-gate 
2580Sstevel@tonic-gate static char time_buf[50];
2590Sstevel@tonic-gate /**
2600Sstevel@tonic-gate  ** exec() - FORK AND EXEC CHILD PROCESS
2610Sstevel@tonic-gate  **/
2620Sstevel@tonic-gate 
2630Sstevel@tonic-gate /*VARARGS1*/
2640Sstevel@tonic-gate int
2650Sstevel@tonic-gate exec(int type, ...)
2660Sstevel@tonic-gate {
2670Sstevel@tonic-gate 	va_list			args;
2680Sstevel@tonic-gate 
2690Sstevel@tonic-gate 	int			i;
2700Sstevel@tonic-gate 	int			procuid;
2710Sstevel@tonic-gate 	int			procgid;
2720Sstevel@tonic-gate 	int			ret;
2730Sstevel@tonic-gate 	int			fr_flg;
2740Sstevel@tonic-gate 
2750Sstevel@tonic-gate 	char			*cp;
2760Sstevel@tonic-gate 	char			*infile;
2770Sstevel@tonic-gate 	char			*outfile;
2780Sstevel@tonic-gate 	char			*errfile;
2790Sstevel@tonic-gate 	char			*sep;
2800Sstevel@tonic-gate 
2810Sstevel@tonic-gate 	char			**listp;
2820Sstevel@tonic-gate 	char			**file_list;
2830Sstevel@tonic-gate 	char			*printerName;
2840Sstevel@tonic-gate 	char			*printerNameToShow;
2850Sstevel@tonic-gate 	static char		nameBuf[100];
2860Sstevel@tonic-gate 	char			*clean_title;
2870Sstevel@tonic-gate 
2880Sstevel@tonic-gate 	PSTATUS			*printer;
2890Sstevel@tonic-gate 
2900Sstevel@tonic-gate 	RSTATUS			*request;
2910Sstevel@tonic-gate 
2920Sstevel@tonic-gate 	FSTATUS			*form;
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate 	EXEC			*ep;
2950Sstevel@tonic-gate 
2960Sstevel@tonic-gate 	PWSTATUS		*pwheel;
2970Sstevel@tonic-gate 	time_t			now;
2980Sstevel@tonic-gate 	struct passwd		*pwp;
2990Sstevel@tonic-gate #ifdef LP_USE_PAPI_ATTR
3000Sstevel@tonic-gate 	struct stat		tmpBuf;
3010Sstevel@tonic-gate 	char 			tmpName[BUFSIZ];
3020Sstevel@tonic-gate 	char			*path = NULL;
3030Sstevel@tonic-gate #endif
3040Sstevel@tonic-gate 	char *av[ARG_MAX];
3050Sstevel@tonic-gate 	char **envp = NULL;
3060Sstevel@tonic-gate 	int ac = 0;
3070Sstevel@tonic-gate 
3080Sstevel@tonic-gate 	syslog(LOG_DEBUG, "exec(%s)", _exec_name(type));
3090Sstevel@tonic-gate 
3100Sstevel@tonic-gate 	memset(av, 0, sizeof (*av));
3110Sstevel@tonic-gate 
3120Sstevel@tonic-gate 	va_start (args, type);
3130Sstevel@tonic-gate 
3140Sstevel@tonic-gate 	switch (type) {
3150Sstevel@tonic-gate 
3160Sstevel@tonic-gate 	case EX_INTERF:
3170Sstevel@tonic-gate 		printer = va_arg(args, PSTATUS *);
3180Sstevel@tonic-gate 		if (printer->status & PS_REMOTE) {
3190Sstevel@tonic-gate 			errno = EINVAL;
3200Sstevel@tonic-gate 			return (-1);
3210Sstevel@tonic-gate 		}
3220Sstevel@tonic-gate 		request = printer->request;
3230Sstevel@tonic-gate 		ep = printer->exec;
3240Sstevel@tonic-gate 		break;
3250Sstevel@tonic-gate 
3260Sstevel@tonic-gate 	case EX_FAULT_MESSAGE:
3270Sstevel@tonic-gate 		printer = va_arg(args, PSTATUS *);
3280Sstevel@tonic-gate 		request = va_arg(args, RSTATUS *);
3290Sstevel@tonic-gate 		if (! ( printer->status & (PS_FORM_FAULT | PS_SHOW_FAULT))) {
3300Sstevel@tonic-gate 			return(0);
3310Sstevel@tonic-gate 		}
3320Sstevel@tonic-gate 		ep = printer->fault_exec;
3330Sstevel@tonic-gate 		printerName = (printer->printer && printer->printer->name
3340Sstevel@tonic-gate 				  ? printer->printer->name : "??");
3350Sstevel@tonic-gate 			snprintf(nameBuf, sizeof (nameBuf),
3360Sstevel@tonic-gate 				"%s (on %s)\n", printerName, Local_System);
3370Sstevel@tonic-gate 
3380Sstevel@tonic-gate 		printerNameToShow = nameBuf;
3390Sstevel@tonic-gate 
3400Sstevel@tonic-gate 		(void) time(&now);
3410Sstevel@tonic-gate 		(void) strftime(time_buf, sizeof (time_buf),
3420Sstevel@tonic-gate 			NULL, localtime(&now));
3430Sstevel@tonic-gate 		break;
3440Sstevel@tonic-gate 
3450Sstevel@tonic-gate 	case EX_SLOWF:
3460Sstevel@tonic-gate 		request = va_arg(args, RSTATUS *);
3470Sstevel@tonic-gate 		ep = request->exec;
3480Sstevel@tonic-gate 		break;
3490Sstevel@tonic-gate 
3500Sstevel@tonic-gate 	case EX_NOTIFY:
3510Sstevel@tonic-gate 		request = va_arg(args, RSTATUS *);
3520Sstevel@tonic-gate 		if (request->request->actions & ACT_NOTIFY) {
3530Sstevel@tonic-gate 			errno = EINVAL;
3540Sstevel@tonic-gate 			return (-1);
3550Sstevel@tonic-gate 		}
3560Sstevel@tonic-gate 		ep = request->exec;
3570Sstevel@tonic-gate 		break;
3580Sstevel@tonic-gate 
3590Sstevel@tonic-gate 	case EX_ALERT:
3600Sstevel@tonic-gate 		printer = va_arg(args, PSTATUS *);
3610Sstevel@tonic-gate 		if (!(printer->printer->fault_alert.shcmd)) {
3620Sstevel@tonic-gate 			errno = EINVAL;
3630Sstevel@tonic-gate 			return(-1);
3640Sstevel@tonic-gate 		}
3650Sstevel@tonic-gate 		ep = printer->alert->exec;
3660Sstevel@tonic-gate 		break;
3670Sstevel@tonic-gate 
3680Sstevel@tonic-gate 	case EX_PALERT:
3690Sstevel@tonic-gate 		pwheel = va_arg(args, PWSTATUS *);
3700Sstevel@tonic-gate 		ep = pwheel->alert->exec;
3710Sstevel@tonic-gate 		break;
3720Sstevel@tonic-gate 
3730Sstevel@tonic-gate 	case EX_FORM_MESSAGE:
3740Sstevel@tonic-gate 		(void) time(&now);
3750Sstevel@tonic-gate 		(void) strftime(time_buf, sizeof (time_buf),
3760Sstevel@tonic-gate 			NULL, localtime(&now));
3770Sstevel@tonic-gate 
3780Sstevel@tonic-gate 		/*FALLTHRU*/
3790Sstevel@tonic-gate 	case EX_FALERT:
3800Sstevel@tonic-gate 		form = va_arg(args, FSTATUS *);
3810Sstevel@tonic-gate 		ep = form->alert->exec;
3820Sstevel@tonic-gate 		break;
3830Sstevel@tonic-gate 
3840Sstevel@tonic-gate 	default:
3850Sstevel@tonic-gate 		errno = EINVAL;
3860Sstevel@tonic-gate 		return(-1);
3870Sstevel@tonic-gate 
3880Sstevel@tonic-gate 	}
3890Sstevel@tonic-gate 	va_end (args);
3900Sstevel@tonic-gate 
3910Sstevel@tonic-gate 	if (!ep || (ep->pid > 0)) {
3920Sstevel@tonic-gate 		errno = EBUSY;
3930Sstevel@tonic-gate 		return(-1);
3940Sstevel@tonic-gate 	}
3950Sstevel@tonic-gate 
3960Sstevel@tonic-gate 	ep->flags = 0;
3970Sstevel@tonic-gate 
3980Sstevel@tonic-gate 	key = ep->key = getkey();
3990Sstevel@tonic-gate 	slot = ep - Exec_Table;
4000Sstevel@tonic-gate 
4010Sstevel@tonic-gate 	switch ((ep->pid = Fork1(ep))) {
4020Sstevel@tonic-gate 
4030Sstevel@tonic-gate 	case -1:
4040Sstevel@tonic-gate 		relock ();
4050Sstevel@tonic-gate 		return(-1);
4060Sstevel@tonic-gate 
4070Sstevel@tonic-gate 	case 0:
4080Sstevel@tonic-gate 		/*
4090Sstevel@tonic-gate 		 * We want to be able to tell our parent how we died.
4100Sstevel@tonic-gate 		 */
4110Sstevel@tonic-gate 		lp_alloc_fail_handler = child_mallocfail;
4120Sstevel@tonic-gate 		break;
4130Sstevel@tonic-gate 
4140Sstevel@tonic-gate 	default:
4150Sstevel@tonic-gate 		switch(type) {
4160Sstevel@tonic-gate 
4170Sstevel@tonic-gate 		case EX_INTERF:
4180Sstevel@tonic-gate 			request->request->outcome |= RS_PRINTING;
4190Sstevel@tonic-gate 			break;
4200Sstevel@tonic-gate 
4210Sstevel@tonic-gate 		case EX_NOTIFY:
4220Sstevel@tonic-gate 			request->request->outcome |= RS_NOTIFYING;
4230Sstevel@tonic-gate 			break;
4240Sstevel@tonic-gate 
4250Sstevel@tonic-gate 		case EX_SLOWF:
4260Sstevel@tonic-gate 			request->request->outcome |= RS_FILTERING;
4270Sstevel@tonic-gate 			request->request->outcome &= ~RS_REFILTER;
4280Sstevel@tonic-gate 			break;
4290Sstevel@tonic-gate 
4300Sstevel@tonic-gate 		}
4310Sstevel@tonic-gate 		return(0);
4320Sstevel@tonic-gate 
4330Sstevel@tonic-gate 	}
4340Sstevel@tonic-gate 
4350Sstevel@tonic-gate 	for (i = 0; i < NSIG; i++)
4360Sstevel@tonic-gate 		(void)signal (i, SIG_DFL);
4370Sstevel@tonic-gate 	(void)signal (SIGALRM, SIG_IGN);
4380Sstevel@tonic-gate 	(void)signal (SIGTERM, sigtrap);
4390Sstevel@tonic-gate 
4400Sstevel@tonic-gate 	for (i = 0; i < OpenMax; i++)
4410Sstevel@tonic-gate 		if (i != ChildMd->writefd)
4420Sstevel@tonic-gate 			Close (i);
4430Sstevel@tonic-gate 
4440Sstevel@tonic-gate 	setpgrp();
4450Sstevel@tonic-gate 
4460Sstevel@tonic-gate 	/* Set a default path */
4470Sstevel@tonic-gate 	addenv (&envp, "PATH", "/usr/lib/lp/bin:/usr/bin:/bin:/usr/sbin:/sbin");
4480Sstevel@tonic-gate 	/* copy locale related variables */
4490Sstevel@tonic-gate 	addenv (&envp, "TZ", getenv("TZ"));
4500Sstevel@tonic-gate 	addenv (&envp, "LANG", getenv("LANG"));
4510Sstevel@tonic-gate 	addenv (&envp, "LC_ALL", getenv("LC_ALL"));
4520Sstevel@tonic-gate 	addenv (&envp, "LC_COLLATE", getenv("LC_COLLATE"));
4530Sstevel@tonic-gate 	addenv (&envp, "LC_CTYPE", getenv("LC_CTYPE"));
4540Sstevel@tonic-gate 	addenv (&envp, "LC_MESSAGES", getenv("LC_MESSAGES"));
4550Sstevel@tonic-gate 	addenv (&envp, "LC_MONETARY", getenv("LC_MONETARY"));
4560Sstevel@tonic-gate 	addenv (&envp, "LC_NUMERIC", getenv("LC_NUMERIC"));
4570Sstevel@tonic-gate 	addenv (&envp, "LC_TIME", getenv("LC_TIME"));
4580Sstevel@tonic-gate 
4590Sstevel@tonic-gate 	sprintf ((cp = BIGGEST_NUMBER_S), "%ld", key);
4600Sstevel@tonic-gate 	addenv (&envp, "SPOOLER_KEY", cp);
4610Sstevel@tonic-gate 
4620Sstevel@tonic-gate #if	defined(DEBUG)
4630Sstevel@tonic-gate 	addenv (&envp, "LPDEBUG", (debug? "1" : "0"));
4640Sstevel@tonic-gate #endif
4650Sstevel@tonic-gate 
4660Sstevel@tonic-gate 	/*
4670Sstevel@tonic-gate 	 * Open the standard input, standard output, and standard error.
4680Sstevel@tonic-gate 	 */
4690Sstevel@tonic-gate 	switch (type) {
4700Sstevel@tonic-gate 
4710Sstevel@tonic-gate 	case EX_SLOWF:
4720Sstevel@tonic-gate 	case EX_INTERF:
4730Sstevel@tonic-gate 		/*
4740Sstevel@tonic-gate 		 * stdin:  /dev/null
4750Sstevel@tonic-gate 		 * stdout: /dev/null (EX_SLOWF), printer port (EX_INTERF)
4760Sstevel@tonic-gate 		 * stderr: req#
4770Sstevel@tonic-gate 		 */
4780Sstevel@tonic-gate 		infile = 0;
4790Sstevel@tonic-gate 		outfile = 0;
4800Sstevel@tonic-gate 		errfile = makereqerr(request);
4810Sstevel@tonic-gate 		break;
4820Sstevel@tonic-gate 
4830Sstevel@tonic-gate 	case EX_NOTIFY:
4840Sstevel@tonic-gate 		/*
4850Sstevel@tonic-gate 		 * stdin:  req#
4860Sstevel@tonic-gate 		 * stdout: /dev/null
4870Sstevel@tonic-gate 		 * stderr: /dev/null
4880Sstevel@tonic-gate 		 */
4890Sstevel@tonic-gate 		infile = makereqerr(request);
4900Sstevel@tonic-gate 		outfile = 0;
4910Sstevel@tonic-gate 		errfile = 0;
4920Sstevel@tonic-gate 
4930Sstevel@tonic-gate 		break;
4940Sstevel@tonic-gate 
4950Sstevel@tonic-gate 	case EX_ALERT:
4960Sstevel@tonic-gate 	case EX_FALERT:
4970Sstevel@tonic-gate 	case EX_PALERT:
4980Sstevel@tonic-gate 	case EX_FAULT_MESSAGE:
4990Sstevel@tonic-gate 	case EX_FORM_MESSAGE:
5000Sstevel@tonic-gate 		/*
5010Sstevel@tonic-gate 		 * stdin:  /dev/null
5020Sstevel@tonic-gate 		 * stdout: /dev/null
5030Sstevel@tonic-gate 		 * stderr: /dev/null
5040Sstevel@tonic-gate 		 */
5050Sstevel@tonic-gate 		infile = 0;
5060Sstevel@tonic-gate 		outfile = 0;
5070Sstevel@tonic-gate 		errfile = 0;
5080Sstevel@tonic-gate 		break;
5090Sstevel@tonic-gate 
5100Sstevel@tonic-gate 	}
5110Sstevel@tonic-gate 
5120Sstevel@tonic-gate 	if (infile) {
5130Sstevel@tonic-gate 		if (Open(infile, O_RDONLY) == -1)
5140Sstevel@tonic-gate 			Done (EXEC_EXIT_NOPEN, errno);
5150Sstevel@tonic-gate 	} else {
5160Sstevel@tonic-gate 		if (Open("/dev/null", O_RDONLY) == -1)
5170Sstevel@tonic-gate 			Done (EXEC_EXIT_NOPEN, errno);
5180Sstevel@tonic-gate 	}
5190Sstevel@tonic-gate 
5200Sstevel@tonic-gate 	if (outfile) {
5210Sstevel@tonic-gate 		if (Open(outfile, O_CREAT|O_TRUNC|O_WRONLY, 0600) == -1)
5220Sstevel@tonic-gate 			Done (EXEC_EXIT_NOPEN, errno);
5230Sstevel@tonic-gate 	} else {
5240Sstevel@tonic-gate 		/*
5250Sstevel@tonic-gate 		 * If EX_INTERF, this is still needed to cause the
5260Sstevel@tonic-gate 		 * standard error channel to be #2.
5270Sstevel@tonic-gate 		 */
5280Sstevel@tonic-gate 		if (Open("/dev/null", O_WRONLY) == -1)
5290Sstevel@tonic-gate 			Done (EXEC_EXIT_NOPEN, errno);
5300Sstevel@tonic-gate 	}
5310Sstevel@tonic-gate 
5320Sstevel@tonic-gate 	if (errfile) {
5330Sstevel@tonic-gate 		if (Open(errfile, O_CREAT|O_TRUNC|O_WRONLY, 0600) == -1)
5340Sstevel@tonic-gate 			Done (EXEC_EXIT_NOPEN, errno);
5350Sstevel@tonic-gate 	} else {
5360Sstevel@tonic-gate 		if (Open("/dev/null", O_WRONLY) == -1)
5370Sstevel@tonic-gate 			Done (EXEC_EXIT_NOPEN, errno);
5380Sstevel@tonic-gate 	}
5390Sstevel@tonic-gate 
5400Sstevel@tonic-gate 	switch (type) {
5410Sstevel@tonic-gate 
5420Sstevel@tonic-gate 	case EX_INTERF:
5430Sstevel@tonic-gate 		/*
5440Sstevel@tonic-gate 		 * Opening a ``port'' can be dangerous to our health:
5450Sstevel@tonic-gate 		 *
5460Sstevel@tonic-gate 		 *	- Hangups can occur if the line is dropped.
5470Sstevel@tonic-gate 		 *	- The printer may send an interrupt.
5480Sstevel@tonic-gate 		 *	- A FIFO may be closed, generating SIGPIPE.
5490Sstevel@tonic-gate 		 *
5500Sstevel@tonic-gate 		 * We catch these so we can complain nicely.
5510Sstevel@tonic-gate 		 */
5520Sstevel@tonic-gate 		trap_fault_signals ();
5530Sstevel@tonic-gate 
5540Sstevel@tonic-gate 		(void)Close (1);
5550Sstevel@tonic-gate 
5560Sstevel@tonic-gate 		if (strchr (request->secure->user, '!'))
5570Sstevel@tonic-gate 		{
5580Sstevel@tonic-gate 			procuid = Lp_Uid;
5590Sstevel@tonic-gate 			procgid = Lp_Gid;
5600Sstevel@tonic-gate 		}
5610Sstevel@tonic-gate 		else
5620Sstevel@tonic-gate 		{
5630Sstevel@tonic-gate 			procuid = request->secure->uid;
5640Sstevel@tonic-gate 			procgid = request->secure->gid;
5650Sstevel@tonic-gate 		}
5660Sstevel@tonic-gate 		if (printer->printer->dial_info)
5670Sstevel@tonic-gate 		{
5680Sstevel@tonic-gate 			ret = open_dialup(request->printer_type,
5690Sstevel@tonic-gate 				printer->printer);
5700Sstevel@tonic-gate 			if (ret == 0)
5710Sstevel@tonic-gate 				do_undial = 1;
5720Sstevel@tonic-gate 		}
5730Sstevel@tonic-gate 		else
5740Sstevel@tonic-gate 		{
5750Sstevel@tonic-gate 			ret = open_direct(request->printer_type,
5760Sstevel@tonic-gate 				printer->printer);
5770Sstevel@tonic-gate 			do_undial = 0;
5780Sstevel@tonic-gate 			/* this is a URI */
5790Sstevel@tonic-gate 			if (is_printer_uri(printer->printer->device) == 0)
5800Sstevel@tonic-gate 				addenv(&envp, "DEVICE_URI",
5810Sstevel@tonic-gate 					 printer->printer->device);
5820Sstevel@tonic-gate 		}
5830Sstevel@tonic-gate 				addenv(&envp, "DEVICE_URI",
5840Sstevel@tonic-gate 					 printer->printer->device);
5850Sstevel@tonic-gate 		if (ret != 0)
5860Sstevel@tonic-gate 			Done (ret, errno);
5870Sstevel@tonic-gate 
5880Sstevel@tonic-gate 		if (!(request->request->outcome & RS_FILTERED))
5890Sstevel@tonic-gate 			file_list = request->request->file_list;
5900Sstevel@tonic-gate 
5910Sstevel@tonic-gate 		else {
5920Sstevel@tonic-gate 			register int		count	= 0;
5930Sstevel@tonic-gate 			register char *		num	= BIGGEST_REQID_S;
5940Sstevel@tonic-gate 			register char *		prefix;
5950Sstevel@tonic-gate 
5960Sstevel@tonic-gate 			prefix = makestr(
5970Sstevel@tonic-gate 				Lp_Tmp,
5980Sstevel@tonic-gate 				"/",
5990Sstevel@tonic-gate 				(request->secure && request->secure->system ?
6000Sstevel@tonic-gate 					request->secure->system : Local_System),
6010Sstevel@tonic-gate 				"/F",
6020Sstevel@tonic-gate 				getreqno(request->secure->req_id),
6030Sstevel@tonic-gate 				"-",
6040Sstevel@tonic-gate 				(char *)0
6050Sstevel@tonic-gate 			);
6060Sstevel@tonic-gate 
6070Sstevel@tonic-gate 			file_list = (char **)Malloc(
6080Sstevel@tonic-gate 				(lenlist(request->request->file_list) + 1)
6090Sstevel@tonic-gate 			      * sizeof(char *)
6100Sstevel@tonic-gate 			);
6110Sstevel@tonic-gate 
6120Sstevel@tonic-gate 			for (
6130Sstevel@tonic-gate 				listp = request->request->file_list;
6140Sstevel@tonic-gate 				*listp;
6150Sstevel@tonic-gate 				listp++
6160Sstevel@tonic-gate 			) {
6170Sstevel@tonic-gate 				sprintf (num, "%d", count + 1);
6180Sstevel@tonic-gate 				file_list[count] = makestr(
6190Sstevel@tonic-gate 					prefix,
6200Sstevel@tonic-gate 					num,
6210Sstevel@tonic-gate 					(char *)0
6220Sstevel@tonic-gate 				);
6230Sstevel@tonic-gate 				count++;
6240Sstevel@tonic-gate 			}
6250Sstevel@tonic-gate 			file_list[count] = 0;
6260Sstevel@tonic-gate 		}
6270Sstevel@tonic-gate 
6280Sstevel@tonic-gate #ifdef LP_USE_PAPI_ATTR
6290Sstevel@tonic-gate 		/*
6300Sstevel@tonic-gate 		 * Check if the PAPI job attribute file exists, if it does
6310Sstevel@tonic-gate 		 * pass the file's pathname to the printer interface script
6320Sstevel@tonic-gate 		 * in an environment variable. This file is created when
6330Sstevel@tonic-gate 		 * print jobs are submitted via the PAPI interface.
6340Sstevel@tonic-gate 		 */
6350Sstevel@tonic-gate 		snprintf(tmpName, sizeof (tmpName), "%s-%s",
6360Sstevel@tonic-gate 			getreqno(request->secure->req_id), LP_PAPIATTRNAME);
6370Sstevel@tonic-gate 		path = makepath(SPOOLDIR, "temp", tmpName, (char *)0);
6380Sstevel@tonic-gate 		if ((path != NULL) && (stat(path, &tmpBuf) == 0))
6390Sstevel@tonic-gate 		{
6400Sstevel@tonic-gate 			/*
6410Sstevel@tonic-gate 			 * IPP job attribute file exists for this job so
6420Sstevel@tonic-gate 			 * set the environment variable
6430Sstevel@tonic-gate 			 */
6440Sstevel@tonic-gate 			syslog(LOG_DEBUG, "exec(): ATTRPATH='%s'", path);
6450Sstevel@tonic-gate 			addenv(&envp, "ATTRPATH", path);
6460Sstevel@tonic-gate 		}
6470Sstevel@tonic-gate 		Free(path);
6480Sstevel@tonic-gate 
6490Sstevel@tonic-gate 		/*
6500Sstevel@tonic-gate 		 * now set environment variable for the printer's PostScript
6510Sstevel@tonic-gate 		 * Printer Description (PPD) file, this is used by the filter
6520Sstevel@tonic-gate 		 * when forming the print data for this printer.
6530Sstevel@tonic-gate 		 */
6540Sstevel@tonic-gate 		if ((request->printer != NULL) &&
6550Sstevel@tonic-gate 		    (request->printer->printer != NULL) &&
6560Sstevel@tonic-gate 		    (request->printer->printer->name != NULL))
6570Sstevel@tonic-gate 		{
6580Sstevel@tonic-gate 			snprintf(tmpName, sizeof (tmpName), "%s.ppd",
6590Sstevel@tonic-gate 				request->printer->printer->name);
6600Sstevel@tonic-gate 			path = makepath(ETCDIR, "ppd", tmpName, (char *)0);
6610Sstevel@tonic-gate 			if ((path != NULL) && (stat(path, &tmpBuf) == 0))
6620Sstevel@tonic-gate 			{
6630Sstevel@tonic-gate 				syslog(LOG_DEBUG,
6640Sstevel@tonic-gate 					"exec(): Printer PPD='%s'", path);
6650Sstevel@tonic-gate 				addenv(&envp, "PPD", path);
6660Sstevel@tonic-gate 			}
6670Sstevel@tonic-gate 			Free(path);
6680Sstevel@tonic-gate 		}
6690Sstevel@tonic-gate #endif
6700Sstevel@tonic-gate 
6710Sstevel@tonic-gate 		if (request->printer_type)
6720Sstevel@tonic-gate 			addenv(&envp, "TERM", request->printer_type);
6730Sstevel@tonic-gate 
6740Sstevel@tonic-gate 		if (!(printer->printer->daisy)) {
6750Sstevel@tonic-gate 			register char *	chset = 0;
6760Sstevel@tonic-gate 			register char *	csp;
6770Sstevel@tonic-gate 
6780Sstevel@tonic-gate 			if (
6790Sstevel@tonic-gate 				request->form
6800Sstevel@tonic-gate 			     && request->form->form->chset
6810Sstevel@tonic-gate 			     && request->form->form->mandatory
6820Sstevel@tonic-gate 			     && !STREQU(NAME_ANY, request->form->form->chset)
6830Sstevel@tonic-gate 			)
6840Sstevel@tonic-gate 				chset = request->form->form->chset;
6850Sstevel@tonic-gate 
6860Sstevel@tonic-gate 			else if (
6870Sstevel@tonic-gate 				request->request->charset
6880Sstevel@tonic-gate 			     && !STREQU(NAME_ANY, request->request->charset)
6890Sstevel@tonic-gate 			)
6900Sstevel@tonic-gate 				chset = request->request->charset;
6910Sstevel@tonic-gate 
6920Sstevel@tonic-gate 			if (chset) {
6930Sstevel@tonic-gate 				csp = search_cslist(
6940Sstevel@tonic-gate 					chset,
6950Sstevel@tonic-gate 					printer->printer->char_sets
6960Sstevel@tonic-gate 				);
6970Sstevel@tonic-gate 
6980Sstevel@tonic-gate 				/*
6990Sstevel@tonic-gate 				 * The "strtok()" below wrecks the string
7000Sstevel@tonic-gate 				 * for future use, but this is a child
7010Sstevel@tonic-gate 				 * process where it won't be needed again.
7020Sstevel@tonic-gate 				 */
7030Sstevel@tonic-gate 				addenv (&envp, "CHARSET",
7040Sstevel@tonic-gate 					(csp? strtok(csp, "=") : chset)
7050Sstevel@tonic-gate 				);
7060Sstevel@tonic-gate 			}
7070Sstevel@tonic-gate 		}
7080Sstevel@tonic-gate 
7090Sstevel@tonic-gate 		if (request->fast)
7100Sstevel@tonic-gate 			addenv(&envp, "FILTER", request->fast);
7110Sstevel@tonic-gate 
7120Sstevel@tonic-gate 		/*
7130Sstevel@tonic-gate 		*/
7140Sstevel@tonic-gate 		if (strcmp (request->secure->user, request->request->user))
7150Sstevel@tonic-gate 		{
7160Sstevel@tonic-gate 			addenv (&envp, "ALIAS_USERNAME",
7170Sstevel@tonic-gate 				request->request->user);
7180Sstevel@tonic-gate 		}
7190Sstevel@tonic-gate 		/*
7200Sstevel@tonic-gate 		 * Add the system name to the user name (ala system!user)
7210Sstevel@tonic-gate 		 * unless it is already there. RFS users may have trouble
7220Sstevel@tonic-gate 		 * here, sorry!
7230Sstevel@tonic-gate 		 */
7240Sstevel@tonic-gate 		cp = strchr(request->secure->user, '@');
7250Sstevel@tonic-gate 
7260Sstevel@tonic-gate 		allTraysWithForm(printer, request->form);
7270Sstevel@tonic-gate 
7280Sstevel@tonic-gate 		/*
7290Sstevel@tonic-gate 		 * Fix for 4137389
7300Sstevel@tonic-gate 		 * Remove double quotes from title string.
7310Sstevel@tonic-gate 		 */
7320Sstevel@tonic-gate 		fr_flg = 1;
7330Sstevel@tonic-gate 		clean_title = strdup(NB(request->request->title));
7340Sstevel@tonic-gate 		if (clean_title == NULL) {
7350Sstevel@tonic-gate 			/*
7360Sstevel@tonic-gate 			 * strdup failed. We're probably hosed
7370Sstevel@tonic-gate 			 * but try setting clean_title
7380Sstevel@tonic-gate 			 * to original title and continuing.
7390Sstevel@tonic-gate 			 */
7400Sstevel@tonic-gate 			clean_title = NB(request->request->title);
7410Sstevel@tonic-gate 			fr_flg = 0;
7420Sstevel@tonic-gate 		} else if (strcmp(clean_title, "") != 0) {
7430Sstevel@tonic-gate 			char *ct_p;
7440Sstevel@tonic-gate 
7450Sstevel@tonic-gate 			for (ct_p = clean_title; *ct_p != NULL; ct_p++) {
7460Sstevel@tonic-gate 				if (*ct_p == '"')
7470Sstevel@tonic-gate 					*ct_p = ' ';
7480Sstevel@tonic-gate 			}
7490Sstevel@tonic-gate 		}
7500Sstevel@tonic-gate 
7510Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s/%s", Lp_A_Interfaces,
7520Sstevel@tonic-gate 					printer->printer->name);
7530Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s", request->secure->req_id);
7540Sstevel@tonic-gate 		av[ac++] = arg_string(UNTRUSTED, "%s%s%s",
7550Sstevel@tonic-gate 					request->secure->user,
7560Sstevel@tonic-gate 					(cp? "" : "@"),
7570Sstevel@tonic-gate 					(cp? "" : request->secure->system));
7580Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s", clean_title);
7590Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%d", request->copies);
7600Sstevel@tonic-gate 
7610Sstevel@tonic-gate 		if (fr_flg)
7620Sstevel@tonic-gate 			free (clean_title);
7630Sstevel@tonic-gate 
7640Sstevel@tonic-gate 		sep = "";
7650Sstevel@tonic-gate 
7660Sstevel@tonic-gate 		/*
7670Sstevel@tonic-gate 		 * Do the administrator defined key=value pair options
7680Sstevel@tonic-gate 		 */
7690Sstevel@tonic-gate 
7700Sstevel@tonic-gate 		argbuf[0] = '\0';
7710Sstevel@tonic-gate 
7720Sstevel@tonic-gate 		if (printer->printer->options) {
7730Sstevel@tonic-gate 			char **tmp = printer->printer->options;
7740Sstevel@tonic-gate 			while(*tmp != NULL) {
7750Sstevel@tonic-gate 				STRLCAT(argbuf, sep, sizeof (argbuf));
7760Sstevel@tonic-gate 				sep = " ";
7770Sstevel@tonic-gate 				STRLCAT(argbuf, *tmp++, sizeof (argbuf));
7780Sstevel@tonic-gate 			}
7790Sstevel@tonic-gate 		}
7800Sstevel@tonic-gate 
7810Sstevel@tonic-gate 		/*
7820Sstevel@tonic-gate 		 * Do the administrator defined ``stty'' stuff before
7830Sstevel@tonic-gate 		 * the user's -o options, to allow the user to override.
7840Sstevel@tonic-gate 		 */
7850Sstevel@tonic-gate 		if (printer->printer->stty) {
7860Sstevel@tonic-gate 			STRLCAT (argbuf, sep, sizeof (argbuf));
7870Sstevel@tonic-gate 			sep = " ";
7880Sstevel@tonic-gate 			STRLCAT (argbuf, "stty='", sizeof (argbuf));
7890Sstevel@tonic-gate 			STRLCAT (argbuf, printer->printer->stty,
7900Sstevel@tonic-gate 			    sizeof (argbuf));
7910Sstevel@tonic-gate 			STRLCAT (argbuf, "'", sizeof (argbuf));
7920Sstevel@tonic-gate 		}
7930Sstevel@tonic-gate 
7940Sstevel@tonic-gate 		/*
7950Sstevel@tonic-gate 		 * Do all of the user's options except the cpi/lpi/etc.
7960Sstevel@tonic-gate 		 * stuff, which is done separately.
7970Sstevel@tonic-gate 		 */
7980Sstevel@tonic-gate 		if (request->request->options) {
7990Sstevel@tonic-gate 			listp = dashos(request->request->options);
8000Sstevel@tonic-gate 			while (*listp) {
8010Sstevel@tonic-gate 				if (
8020Sstevel@tonic-gate 					!STRNEQU(*listp, "cpi=", 4)
8030Sstevel@tonic-gate 				     && !STRNEQU(*listp, "lpi=", 4)
8040Sstevel@tonic-gate 				     && !STRNEQU(*listp, "width=", 6)
8050Sstevel@tonic-gate 				     && !STRNEQU(*listp, "length=", 7)
8060Sstevel@tonic-gate 				) {
8070Sstevel@tonic-gate 					STRLCAT (argbuf, sep, sizeof (argbuf));
8080Sstevel@tonic-gate 					sep = " ";
8090Sstevel@tonic-gate 					STRLCAT (argbuf, *listp,
8100Sstevel@tonic-gate 					    sizeof (argbuf));
8110Sstevel@tonic-gate 				}
8120Sstevel@tonic-gate 				listp++;
8130Sstevel@tonic-gate 			}
8140Sstevel@tonic-gate 		}
8150Sstevel@tonic-gate 
8160Sstevel@tonic-gate 		/*
8170Sstevel@tonic-gate 		 * The "pickfilter()" routine (from "validate()")
8180Sstevel@tonic-gate 		 * stored the cpi/lpi/etc. stuff that should be
8190Sstevel@tonic-gate 		 * used for this request. It chose form over user,
8200Sstevel@tonic-gate 		 * and user over printer.
8210Sstevel@tonic-gate 		 */
8220Sstevel@tonic-gate 		if (request->cpi) {
8230Sstevel@tonic-gate 			STRLCAT (argbuf, sep, sizeof (argbuf));
8240Sstevel@tonic-gate 			sep = " ";
8250Sstevel@tonic-gate 			STRLCAT (argbuf, "cpi=", sizeof (argbuf));
8260Sstevel@tonic-gate 			STRLCAT (argbuf, request->cpi, sizeof (argbuf));
8270Sstevel@tonic-gate 		}
8280Sstevel@tonic-gate 		if (request->lpi) {
8290Sstevel@tonic-gate 			STRLCAT (argbuf, sep, sizeof (argbuf));
8300Sstevel@tonic-gate 			sep = " ";
8310Sstevel@tonic-gate 			STRLCAT (argbuf, "lpi=", sizeof (argbuf));
8320Sstevel@tonic-gate 			STRLCAT (argbuf, request->lpi, sizeof (argbuf));
8330Sstevel@tonic-gate 		}
8340Sstevel@tonic-gate 		if (request->pwid) {
8350Sstevel@tonic-gate 			STRLCAT (argbuf, sep, sizeof (argbuf));
8360Sstevel@tonic-gate 			sep = " ";
8370Sstevel@tonic-gate 			STRLCAT (argbuf, "width=", sizeof (argbuf));
8380Sstevel@tonic-gate 			STRLCAT (argbuf, request->pwid, sizeof (argbuf));
8390Sstevel@tonic-gate 		}
8400Sstevel@tonic-gate 		if (request->plen) {
8410Sstevel@tonic-gate 			STRLCAT (argbuf, sep, sizeof (argbuf));
8420Sstevel@tonic-gate 			sep = " ";
8430Sstevel@tonic-gate 			STRLCAT (argbuf, "length=", sizeof (argbuf));
8440Sstevel@tonic-gate 			STRLCAT (argbuf, request->plen, sizeof (argbuf));
8450Sstevel@tonic-gate 		}
8460Sstevel@tonic-gate 
8470Sstevel@tonic-gate 		/*
8480Sstevel@tonic-gate 		 * Do the ``raw'' bit last, to ensure it gets
8490Sstevel@tonic-gate 		 * done. If the user doesn't want this, then he or
8500Sstevel@tonic-gate 		 * she can do the correct thing using -o stty=
8510Sstevel@tonic-gate 		 * and leaving out the -r option.
8520Sstevel@tonic-gate 		 */
8530Sstevel@tonic-gate 		if (request->request->actions & ACT_RAW) {
8540Sstevel@tonic-gate 			STRLCAT (argbuf, sep, sizeof (argbuf));
8550Sstevel@tonic-gate 			sep = " ";
8560Sstevel@tonic-gate 			STRLCAT (argbuf, "stty=-opost", sizeof (argbuf));
8570Sstevel@tonic-gate 		}
8580Sstevel@tonic-gate 
8590Sstevel@tonic-gate 
8600Sstevel@tonic-gate 		/* the "options" */
8610Sstevel@tonic-gate 		av[ac++] = arg_string(UNTRUSTED, "%s", argbuf);
8620Sstevel@tonic-gate 
8630Sstevel@tonic-gate 		for (listp = file_list; *listp; listp++)
8640Sstevel@tonic-gate 			av[ac++] = arg_string(TRUSTED, "%s", *listp);
8650Sstevel@tonic-gate 
8660Sstevel@tonic-gate 		(void)chfiles (file_list, procuid, procgid);
8670Sstevel@tonic-gate 
8680Sstevel@tonic-gate 		break;
8690Sstevel@tonic-gate 
8700Sstevel@tonic-gate 
8710Sstevel@tonic-gate 	case EX_SLOWF:
8720Sstevel@tonic-gate 		if (request->slow)
8730Sstevel@tonic-gate 			addenv(&envp, "FILTER", request->slow);
8740Sstevel@tonic-gate 
8750Sstevel@tonic-gate 		if (strchr (request->secure->user, '!'))
8760Sstevel@tonic-gate 		{
8770Sstevel@tonic-gate 			procuid = Lp_Uid;
8780Sstevel@tonic-gate 			procgid = Lp_Gid;
8790Sstevel@tonic-gate 		}
8800Sstevel@tonic-gate 		else
8810Sstevel@tonic-gate 		{
8820Sstevel@tonic-gate 			procuid = request->secure->uid;
8830Sstevel@tonic-gate 			procgid = request->secure->gid;
8840Sstevel@tonic-gate 		}
8850Sstevel@tonic-gate 		cp = _alloc_files(
8860Sstevel@tonic-gate 			lenlist(request->request->file_list),
8870Sstevel@tonic-gate 			getreqno(request->secure->req_id),
8880Sstevel@tonic-gate 			procuid,
8890Sstevel@tonic-gate 			procgid,
8900Sstevel@tonic-gate 			(request->secure && request->secure->system ?
8910Sstevel@tonic-gate 				request->secure->system : NULL )
8920Sstevel@tonic-gate 		);
8930Sstevel@tonic-gate 
8940Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s", Lp_Slow_Filter);
8950Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s/%s/%s", Lp_Tmp,
8960Sstevel@tonic-gate 				(request->secure && request->secure->system ?
8970Sstevel@tonic-gate 					request->secure->system : Local_System),
8980Sstevel@tonic-gate 				cp);
8990Sstevel@tonic-gate 		for (listp = request->request->file_list; *listp; listp++)
9000Sstevel@tonic-gate 			av[ac++] = arg_string(TRUSTED, "%s", *listp);
9010Sstevel@tonic-gate 
9020Sstevel@tonic-gate 		(void)chfiles (request->request->file_list, procuid, procgid);
9030Sstevel@tonic-gate 
9040Sstevel@tonic-gate #ifdef LP_USE_PAPI_ATTR
9050Sstevel@tonic-gate 		/*
9060Sstevel@tonic-gate 		 * Check if the PAPI job attribute file exists, if it does
9070Sstevel@tonic-gate 		 * pass the file's pathname to the slow-filters in an
9080Sstevel@tonic-gate 		 * environment variable. Note: this file is created when
9090Sstevel@tonic-gate 		 * print jobs are submitted via the PAPI interface.
9100Sstevel@tonic-gate 		 */
9110Sstevel@tonic-gate 		snprintf(tmpName, sizeof (tmpName), "%s-%s",
9120Sstevel@tonic-gate 			getreqno(request->secure->req_id), LP_PAPIATTRNAME);
9130Sstevel@tonic-gate 		path = makepath(SPOOLDIR, "temp", tmpName, (char *)0);
9140Sstevel@tonic-gate 		if ((path != NULL) && (stat(path, &tmpBuf) == 0))
9150Sstevel@tonic-gate 		{
9160Sstevel@tonic-gate 			/*
9170Sstevel@tonic-gate 			 * IPP job attribute file exists for this job so
9180Sstevel@tonic-gate 			 * set the environment variable
9190Sstevel@tonic-gate 			 */
9200Sstevel@tonic-gate 			syslog(LOG_DEBUG, "exec(): ATTRPATH='%s'", path);
9210Sstevel@tonic-gate 			addenv(&envp, "ATTRPATH", path);
9220Sstevel@tonic-gate 		}
9230Sstevel@tonic-gate 		Free(path);
9240Sstevel@tonic-gate 
9250Sstevel@tonic-gate 
9260Sstevel@tonic-gate 		/*
9270Sstevel@tonic-gate 		 * now set environment variable for the printer's PostScript
9280Sstevel@tonic-gate 		 * Printer Description (PPD) file, this is used by the filter
9290Sstevel@tonic-gate 		 * when forming the print data for this printer.
9300Sstevel@tonic-gate 		 */
9310Sstevel@tonic-gate 		if ((request->printer != NULL) &&
9320Sstevel@tonic-gate 		    (request->printer->printer != NULL) &&
9330Sstevel@tonic-gate 		    (request->printer->printer->name != NULL))
9340Sstevel@tonic-gate 		{
9350Sstevel@tonic-gate 			snprintf(tmpName, sizeof (tmpName), "%s.ppd",
9360Sstevel@tonic-gate 				request->printer->printer->name);
9370Sstevel@tonic-gate 			path = makepath(ETCDIR, "ppd", tmpName, (char *)0);
9380Sstevel@tonic-gate 			if ((path != NULL) && (stat(path, &tmpBuf) == 0))
9390Sstevel@tonic-gate 			{
9400Sstevel@tonic-gate 				syslog(LOG_DEBUG,
9410Sstevel@tonic-gate 					"exec(): Printer PPD='%s'", path);
9420Sstevel@tonic-gate 				addenv(&envp, "PPD", path);
9430Sstevel@tonic-gate 			}
9440Sstevel@tonic-gate 			Free(path);
9450Sstevel@tonic-gate 		}
9460Sstevel@tonic-gate #endif
9470Sstevel@tonic-gate 		break;
9480Sstevel@tonic-gate 
9490Sstevel@tonic-gate 	case EX_ALERT:
9500Sstevel@tonic-gate 		procuid = Lp_Uid;
9510Sstevel@tonic-gate 		procgid = Lp_Gid;
9520Sstevel@tonic-gate 		(void)Chown (printer->alert->msgfile, procuid, procgid);
9530Sstevel@tonic-gate 
9540Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s/%s/%s", Lp_A_Printers,
9550Sstevel@tonic-gate 				printer->printer->name, ALERTSHFILE);
9560Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s", printer->alert->msgfile);
9570Sstevel@tonic-gate 
9580Sstevel@tonic-gate 		break;
9590Sstevel@tonic-gate 
9600Sstevel@tonic-gate 	case EX_PALERT:
9610Sstevel@tonic-gate 		procuid = Lp_Uid;
9620Sstevel@tonic-gate 		procgid = Lp_Gid;
9630Sstevel@tonic-gate 		(void)Chown (pwheel->alert->msgfile, procuid, procgid);
9640Sstevel@tonic-gate 
9650Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s/%s/%s", Lp_A_PrintWheels,
9660Sstevel@tonic-gate 				pwheel->pwheel->name, ALERTSHFILE);
9670Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s", printer->alert->msgfile);
9680Sstevel@tonic-gate 
9690Sstevel@tonic-gate 		break;
9700Sstevel@tonic-gate 
9710Sstevel@tonic-gate 	case EX_FALERT:
9720Sstevel@tonic-gate 		procuid = Lp_Uid;
9730Sstevel@tonic-gate 		procgid = Lp_Gid;
9740Sstevel@tonic-gate 		(void)Chown (form->alert->msgfile, procuid, procgid);
9750Sstevel@tonic-gate 
9760Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s/%s/%s", Lp_A_Forms,
9770Sstevel@tonic-gate 				form->form->name, ALERTSHFILE);
9780Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s", printer->alert->msgfile);
9790Sstevel@tonic-gate 
9800Sstevel@tonic-gate 		break;
9810Sstevel@tonic-gate 
9820Sstevel@tonic-gate 	case EX_FORM_MESSAGE:
9830Sstevel@tonic-gate 		procuid = Lp_Uid;
9840Sstevel@tonic-gate 		procgid = Lp_Gid;
9850Sstevel@tonic-gate 
9860Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s/form", Lp_A_Faults);
9870Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s", form->form->name);
9880Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s", time_buf);
9890Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s/%s/%s", Lp_A_Forms,
9900Sstevel@tonic-gate 				form->form->name, FORMMESSAGEFILE);
9910Sstevel@tonic-gate 
9920Sstevel@tonic-gate 		break;
9930Sstevel@tonic-gate 
9940Sstevel@tonic-gate 	case EX_FAULT_MESSAGE:
9950Sstevel@tonic-gate 		procuid = Lp_Uid;
9960Sstevel@tonic-gate 		procgid = Lp_Gid;
9970Sstevel@tonic-gate 
9980Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s/printer", Lp_A_Faults);
9990Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s", printerNameToShow);
10000Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s", time_buf);
10010Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s/%s/%s", Lp_A_Printers,
10020Sstevel@tonic-gate 				printerName, FAULTMESSAGEFILE);
10030Sstevel@tonic-gate 
10040Sstevel@tonic-gate 		break;
10050Sstevel@tonic-gate 
10060Sstevel@tonic-gate 	case EX_NOTIFY:
10070Sstevel@tonic-gate 		if (request->request->alert) {
10080Sstevel@tonic-gate 			if (strchr(request->secure->user, '!')) {
10090Sstevel@tonic-gate 				procuid = Lp_Uid;
10100Sstevel@tonic-gate 				procgid = Lp_Gid;
10110Sstevel@tonic-gate 			} else {
10120Sstevel@tonic-gate 				procuid = request->secure->uid;
10130Sstevel@tonic-gate 				procgid = request->secure->gid;
10140Sstevel@tonic-gate 			}
10150Sstevel@tonic-gate 			av[ac++] = arg_string(TRUSTED, "%s",
10160Sstevel@tonic-gate 					request->request->alert);
10170Sstevel@tonic-gate 		} else {
10180Sstevel@tonic-gate 			char *user = strdup(request->secure->user);
10190Sstevel@tonic-gate 			procuid = Lp_Uid;
10200Sstevel@tonic-gate 			procgid = Lp_Gid;
10210Sstevel@tonic-gate 			clean_string(user);
10220Sstevel@tonic-gate 
10230Sstevel@tonic-gate 			if ((request->request->actions & ACT_WRITE) &&
10240Sstevel@tonic-gate 			    (!request->secure->system ||
10250Sstevel@tonic-gate 			    STREQU(request->secure->system, Local_System))) {
10260Sstevel@tonic-gate 				av[ac++] = arg_string(TRUSTED, "%s", BINWRITE);
10270Sstevel@tonic-gate 				snprintf(argbuf, sizeof (argbuf),
10280Sstevel@tonic-gate 					"%s %s || %s %s",
10290Sstevel@tonic-gate 					BINWRITE, user,
10300Sstevel@tonic-gate 					BINMAIL, user
10310Sstevel@tonic-gate 				);
10320Sstevel@tonic-gate 				av[ac++] = arg_string(TRUSTED, "/bin/sh");
10330Sstevel@tonic-gate 				av[ac++] = arg_string(TRUSTED, "-c");
10340Sstevel@tonic-gate 				av[ac++] = arg_string(TRUSTED, "%s", argbuf);
10350Sstevel@tonic-gate 			} else {
10360Sstevel@tonic-gate 				av[ac++] = arg_string(TRUSTED, "%s", BINMAIL);
10370Sstevel@tonic-gate 				av[ac++] = arg_string(UNTRUSTED, "%s", user);
10380Sstevel@tonic-gate 			}
10390Sstevel@tonic-gate 
10400Sstevel@tonic-gate 			free(user);
10410Sstevel@tonic-gate 		}
10420Sstevel@tonic-gate 		break;
10430Sstevel@tonic-gate 	}
10440Sstevel@tonic-gate 
10450Sstevel@tonic-gate 	av[ac++] = NULL;
10460Sstevel@tonic-gate 
10470Sstevel@tonic-gate 	Fork2 ();
10480Sstevel@tonic-gate 	/* only the child returns */
10490Sstevel@tonic-gate 
10500Sstevel@tonic-gate 	/*
10510Sstevel@tonic-gate 	 * Correctly set up the supplemental group list
10520Sstevel@tonic-gate 	 * for proper file access (before execl the interface program)
10530Sstevel@tonic-gate 	 */
10540Sstevel@tonic-gate 
10550Sstevel@tonic-gate 	pwp = getpwuid(procuid);
10560Sstevel@tonic-gate 	if (pwp == NULL) {
10570Sstevel@tonic-gate 		note("getpwuid(%d) call failed\n", procuid);
10580Sstevel@tonic-gate 	} else if (initgroups(pwp->pw_name, procgid) < 0) {
10590Sstevel@tonic-gate 		note("initgroups() call failed %d\n", errno);
10600Sstevel@tonic-gate 	}
10610Sstevel@tonic-gate 
10620Sstevel@tonic-gate 	setgid (procgid);
10630Sstevel@tonic-gate 	setuid (procuid);
10640Sstevel@tonic-gate 
10650Sstevel@tonic-gate 	/*
10660Sstevel@tonic-gate 	 * The shell doesn't allow the "trap" builtin to set a trap
10670Sstevel@tonic-gate 	 * for a signal ignored when the shell is started. Thus, don't
10680Sstevel@tonic-gate 	 * turn off signals in the last child!
10690Sstevel@tonic-gate 	 */
10700Sstevel@tonic-gate 
10710Sstevel@tonic-gate 	for (i = 0; av[i] != NULL; i++)
10720Sstevel@tonic-gate 		syslog(LOG_DEBUG, "exec: av[%d] = %s", i, av[i]);
10730Sstevel@tonic-gate 	for (i = 0; av[i] != NULL; i++)
10740Sstevel@tonic-gate 		syslog(LOG_DEBUG, "exec: envp[%d] = %s", i, envp[i]);
10750Sstevel@tonic-gate 
10760Sstevel@tonic-gate 	execvpe(av[0], av, envp);
10770Sstevel@tonic-gate 	Done (EXEC_EXIT_NEXEC, errno);
10780Sstevel@tonic-gate 	/*NOTREACHED*/
1079*320Sceastha 	return (0);
10800Sstevel@tonic-gate }
10810Sstevel@tonic-gate 
10820Sstevel@tonic-gate /**
10830Sstevel@tonic-gate  ** addenv() - ADD A VARIABLE TO THE ENVIRONMENT
10840Sstevel@tonic-gate  **/
10850Sstevel@tonic-gate 
10860Sstevel@tonic-gate static void
10870Sstevel@tonic-gate addenv(char ***envp, char *name, char *value)
10880Sstevel@tonic-gate {
10890Sstevel@tonic-gate 	register char *		cp;
10900Sstevel@tonic-gate 
10910Sstevel@tonic-gate 	if ((name == NULL) || (value == NULL))
10920Sstevel@tonic-gate 		return;
10930Sstevel@tonic-gate 
10940Sstevel@tonic-gate 	if ((cp = makestr(name, "=", value, (char *)0)))
10950Sstevel@tonic-gate 		addlist(envp, cp);
10960Sstevel@tonic-gate 	return;
10970Sstevel@tonic-gate }
10980Sstevel@tonic-gate 
10990Sstevel@tonic-gate /**
11000Sstevel@tonic-gate  ** Fork1() - FORK FIRST CHILD, SET UP CONNECTION TO IT
11010Sstevel@tonic-gate  **/
11020Sstevel@tonic-gate 
11030Sstevel@tonic-gate static int
11040Sstevel@tonic-gate Fork1(EXEC *ep)
11050Sstevel@tonic-gate {
11060Sstevel@tonic-gate 	int			pid;
11070Sstevel@tonic-gate 	int			fds[2];
11080Sstevel@tonic-gate 
11090Sstevel@tonic-gate 	if (pipe(fds) == -1) {
11100Sstevel@tonic-gate 		note("Failed to create pipe for child process (%s).\n", PERROR);
11110Sstevel@tonic-gate 		errno = EAGAIN ;
11120Sstevel@tonic-gate 		return(-1);
11130Sstevel@tonic-gate 	}
11140Sstevel@tonic-gate 
11150Sstevel@tonic-gate 	ep->md = mconnect((char *)0, fds[0], fds[1]);
11160Sstevel@tonic-gate 
11170Sstevel@tonic-gate 	switch (pid = fork()) {
11180Sstevel@tonic-gate 
11190Sstevel@tonic-gate 	case -1:
11200Sstevel@tonic-gate 		mdisconnect(ep->md);
11210Sstevel@tonic-gate 		close(fds[0]);
11220Sstevel@tonic-gate 		close(fds[1]);
11230Sstevel@tonic-gate 		ep->md = 0;
11240Sstevel@tonic-gate 		return (-1);
11250Sstevel@tonic-gate 
11260Sstevel@tonic-gate 	case 0:
11270Sstevel@tonic-gate 		ChildMd = mconnect(NULL, fds[1], fds[1]);
11280Sstevel@tonic-gate 		return (0);
11290Sstevel@tonic-gate 
11300Sstevel@tonic-gate 	default:
11310Sstevel@tonic-gate 		mlistenadd(ep->md, POLLIN);
11320Sstevel@tonic-gate 		return (pid);
11330Sstevel@tonic-gate 	}
11340Sstevel@tonic-gate }
11350Sstevel@tonic-gate 
11360Sstevel@tonic-gate /**
11370Sstevel@tonic-gate  ** Fork2() - FORK SECOND CHILD AND WAIT FOR IT
11380Sstevel@tonic-gate  **/
11390Sstevel@tonic-gate 
11400Sstevel@tonic-gate static void
11410Sstevel@tonic-gate Fork2(void)
11420Sstevel@tonic-gate {
11430Sstevel@tonic-gate 	switch ((ChildPid = fork())) {
11440Sstevel@tonic-gate 
11450Sstevel@tonic-gate 	case -1:
11460Sstevel@tonic-gate 		Done (EXEC_EXIT_NFORK, errno);
11470Sstevel@tonic-gate 		/*NOTREACHED*/
11480Sstevel@tonic-gate 
11490Sstevel@tonic-gate 	case 0:
11500Sstevel@tonic-gate 		return;
11510Sstevel@tonic-gate 
11520Sstevel@tonic-gate 	default:
11530Sstevel@tonic-gate 		/*
11540Sstevel@tonic-gate 		 * Delay calling "ignore_fault_signals()" as long
11550Sstevel@tonic-gate 		 * as possible, to give the child a chance to exec
11560Sstevel@tonic-gate 		 * the interface program and turn on traps.
11570Sstevel@tonic-gate 		 */
11580Sstevel@tonic-gate 
11590Sstevel@tonic-gate 		cool_heels ();
11600Sstevel@tonic-gate 		/*NOTREACHED*/
11610Sstevel@tonic-gate 
11620Sstevel@tonic-gate 	}
11630Sstevel@tonic-gate }
11640Sstevel@tonic-gate 
11650Sstevel@tonic-gate 
11660Sstevel@tonic-gate /**
11670Sstevel@tonic-gate  ** cool_heels() - WAIT FOR CHILD TO "DIE"
11680Sstevel@tonic-gate  **/
11690Sstevel@tonic-gate 
11700Sstevel@tonic-gate static void
11710Sstevel@tonic-gate cool_heels(void)
11720Sstevel@tonic-gate {
11730Sstevel@tonic-gate 	int			status;
11740Sstevel@tonic-gate 
11750Sstevel@tonic-gate 	/*
11760Sstevel@tonic-gate 	 * At this point our only job is to wait for the child process.
11770Sstevel@tonic-gate 	 * If we hang out for a bit longer, that's okay.
11780Sstevel@tonic-gate 	 * By delaying before turning off the fault signals,
11790Sstevel@tonic-gate 	 * we increase the chance that the child process has completed
11800Sstevel@tonic-gate 	 * its exec and has turned on the fault traps. Nonetheless,
11810Sstevel@tonic-gate 	 * we can't guarantee a zero chance of missing a fault.
11820Sstevel@tonic-gate 	 * (We don't want to keep trapping the signals because the
11830Sstevel@tonic-gate 	 * interface program is likely to have a better way to handle
11840Sstevel@tonic-gate 	 * them; this process provides only rudimentary handling.)
11850Sstevel@tonic-gate 	 *
11860Sstevel@tonic-gate 	 * Note that on a very busy system, or with a very fast interface
11870Sstevel@tonic-gate 	 * program, the tables could be turned: Our sleep below (coupled
11880Sstevel@tonic-gate 	 * with a delay in the kernel scheduling us) may cause us to
11890Sstevel@tonic-gate 	 * detect the fault instead of the interface program.
11900Sstevel@tonic-gate 	 *
11910Sstevel@tonic-gate 	 * What we need is a way to synchronize with the child process.
11920Sstevel@tonic-gate 	 */
11930Sstevel@tonic-gate 	sleep (1);
11940Sstevel@tonic-gate 	ignore_fault_signals ();
11950Sstevel@tonic-gate 
11960Sstevel@tonic-gate 	WaitedChildPid = 0;
11970Sstevel@tonic-gate 	while ((WaitedChildPid = wait(&status)) != ChildPid)
11980Sstevel@tonic-gate 		;
11990Sstevel@tonic-gate 
12000Sstevel@tonic-gate 	if (
12010Sstevel@tonic-gate 		EXITED(status) > EXEC_EXIT_USER
12020Sstevel@tonic-gate 	     && EXITED(status) != EXEC_EXIT_FAULT
12030Sstevel@tonic-gate 	)
12040Sstevel@tonic-gate 		Done (EXEC_EXIT_EXIT, EXITED(status));
12050Sstevel@tonic-gate 
12060Sstevel@tonic-gate 	done (status, 0);	/* Don't use Done() */
12070Sstevel@tonic-gate 	/*NOTREACHED*/
12080Sstevel@tonic-gate }
12090Sstevel@tonic-gate 
12100Sstevel@tonic-gate 
12110Sstevel@tonic-gate /**
12120Sstevel@tonic-gate  ** trap_fault_signals() - TRAP SIGNALS THAT CAN OCCUR ON PRINTER FAULT
12130Sstevel@tonic-gate  ** ignore_fault_signals() - IGNORE SAME
12140Sstevel@tonic-gate  **/
12150Sstevel@tonic-gate 
12160Sstevel@tonic-gate static void
12170Sstevel@tonic-gate trap_fault_signals(void)
12180Sstevel@tonic-gate {
12190Sstevel@tonic-gate 	signal (SIGHUP, sigtrap);
12200Sstevel@tonic-gate 	signal (SIGINT, sigtrap);
12210Sstevel@tonic-gate 	signal (SIGQUIT, sigtrap);
12220Sstevel@tonic-gate 	signal (SIGPIPE, sigtrap);
12230Sstevel@tonic-gate 	return;
12240Sstevel@tonic-gate }
12250Sstevel@tonic-gate 
12260Sstevel@tonic-gate static void
12270Sstevel@tonic-gate ignore_fault_signals(void)
12280Sstevel@tonic-gate {
12290Sstevel@tonic-gate 	signal (SIGHUP, SIG_IGN);
12300Sstevel@tonic-gate 	signal (SIGINT, SIG_IGN);
12310Sstevel@tonic-gate 	signal (SIGQUIT, SIG_IGN);
12320Sstevel@tonic-gate 	signal (SIGPIPE, SIG_IGN);
12330Sstevel@tonic-gate 	return;
12340Sstevel@tonic-gate }
12350Sstevel@tonic-gate 
12360Sstevel@tonic-gate /**
12370Sstevel@tonic-gate  ** sigtrap() - TRAP VARIOUS SIGNALS
12380Sstevel@tonic-gate  **/
12390Sstevel@tonic-gate 
12400Sstevel@tonic-gate static void
12410Sstevel@tonic-gate sigtrap(int sig)
12420Sstevel@tonic-gate {
12430Sstevel@tonic-gate 	signal (sig, SIG_IGN);
12440Sstevel@tonic-gate 	switch (sig) {
12450Sstevel@tonic-gate 
12460Sstevel@tonic-gate 	case SIGHUP:
12470Sstevel@tonic-gate 		Done (EXEC_EXIT_HUP, 0);
12480Sstevel@tonic-gate 		/*NOTREACHED*/
12490Sstevel@tonic-gate 
12500Sstevel@tonic-gate 	case SIGQUIT:
12510Sstevel@tonic-gate 	case SIGINT:
12520Sstevel@tonic-gate 		Done (EXEC_EXIT_INTR, 0);
12530Sstevel@tonic-gate 		/*NOTREACHED*/
12540Sstevel@tonic-gate 
12550Sstevel@tonic-gate 	case SIGPIPE:
12560Sstevel@tonic-gate 		Done (EXEC_EXIT_PIPE, 0);
12570Sstevel@tonic-gate 		/*NOTREACHED*/
12580Sstevel@tonic-gate 
12590Sstevel@tonic-gate 	case SIGTERM:
12600Sstevel@tonic-gate 		/*
12610Sstevel@tonic-gate 		 * If we were killed with SIGTERM, it should have been
12620Sstevel@tonic-gate 		 * via the Spooler who should have killed the entire
12630Sstevel@tonic-gate 		 * process group. We have to wait for the children,
12640Sstevel@tonic-gate 		 * since we're their parent, but WE MAY HAVE WAITED
12650Sstevel@tonic-gate 		 * FOR THEM ALREADY (in cool_heels()).
12660Sstevel@tonic-gate 		 */
12670Sstevel@tonic-gate 		if (ChildPid != WaitedChildPid) {
12680Sstevel@tonic-gate 			register int		cpid;
12690Sstevel@tonic-gate 
12700Sstevel@tonic-gate 			while (
12710Sstevel@tonic-gate 				(cpid = wait((int *)0)) != ChildPid
12720Sstevel@tonic-gate 			     && (cpid != -1 || errno != ECHILD)
12730Sstevel@tonic-gate 			)
12740Sstevel@tonic-gate 				;
12750Sstevel@tonic-gate 		}
12760Sstevel@tonic-gate 
12770Sstevel@tonic-gate 		/*
12780Sstevel@tonic-gate 		 * We can't rely on getting SIGTERM back in the wait()
12790Sstevel@tonic-gate 		 * above, because, for instance, some shells trap SIGTERM
12800Sstevel@tonic-gate 		 * and exit instead. Thus we force it.
12810Sstevel@tonic-gate 		 */
12820Sstevel@tonic-gate 		done (SIGTERM, 0);	/* Don't use Done() */
12830Sstevel@tonic-gate 		/*NOTREACHED*/
12840Sstevel@tonic-gate 	}
12850Sstevel@tonic-gate }
12860Sstevel@tonic-gate 
12870Sstevel@tonic-gate /**
12880Sstevel@tonic-gate  ** done() - TELL SPOOLER THIS CHILD IS DONE
12890Sstevel@tonic-gate  **/
12900Sstevel@tonic-gate 
12910Sstevel@tonic-gate static void
12920Sstevel@tonic-gate done(int status, int err)
12930Sstevel@tonic-gate {
12940Sstevel@tonic-gate 	if (do_undial)
12950Sstevel@tonic-gate 		undial (1);
12960Sstevel@tonic-gate 
12970Sstevel@tonic-gate 	mputm (ChildMd, S_CHILD_DONE, key, slot, status, err);
12980Sstevel@tonic-gate 	mdisconnect (ChildMd);
12990Sstevel@tonic-gate 
13000Sstevel@tonic-gate 	exit (0);
13010Sstevel@tonic-gate 	/*NOTREACHED*/
13020Sstevel@tonic-gate }
13030Sstevel@tonic-gate 
13040Sstevel@tonic-gate /**
13050Sstevel@tonic-gate  ** child_mallocfail()
13060Sstevel@tonic-gate  **/
13070Sstevel@tonic-gate 
13080Sstevel@tonic-gate static void
13090Sstevel@tonic-gate child_mallocfail(void)
13100Sstevel@tonic-gate {
13110Sstevel@tonic-gate 	Done (EXEC_EXIT_NOMEM, ENOMEM);
13120Sstevel@tonic-gate }
1313