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