xref: /onnv-gate/usr/src/cmd/lp/cmd/lpsched/exec.c (revision 3125:084bca4d4623)
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  */
21*3125Sjacobs 
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};
1370Sstevel@tonic-gate static char *
1380Sstevel@tonic-gate arg_string(enum trust type, char *fmt, ...)
1390Sstevel@tonic-gate {
1400Sstevel@tonic-gate 	char buf[BUFSIZ];
1410Sstevel@tonic-gate 	va_list	args;
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate 	va_start(args, fmt);
1440Sstevel@tonic-gate 	(void) vsnprintf(buf, sizeof(buf), fmt, args);
1450Sstevel@tonic-gate 	va_end(args);
1460Sstevel@tonic-gate 
1470Sstevel@tonic-gate 	/*
1480Sstevel@tonic-gate 	 * If the string contains data from an untrusted origin (user supplied),
1490Sstevel@tonic-gate 	 * clean it up in case one of our progeny is a shell script and isn't
1500Sstevel@tonic-gate 	 * careful about checking its input.
1510Sstevel@tonic-gate 	 */
1520Sstevel@tonic-gate 	if (type == UNTRUSTED)
1530Sstevel@tonic-gate 		clean_string(buf);
1540Sstevel@tonic-gate 
1550Sstevel@tonic-gate 	return (strdup(buf));
1560Sstevel@tonic-gate }
1570Sstevel@tonic-gate 
1580Sstevel@tonic-gate /* stolen from libc/gen/port/gen/execvp.c */
1590Sstevel@tonic-gate static const char *
1600Sstevel@tonic-gate execat(const char *s1, const char *s2, char *si)
1610Sstevel@tonic-gate {
1620Sstevel@tonic-gate         char    *s;
1630Sstevel@tonic-gate         int cnt = PATH_MAX + 1; /* number of characters in s2 */
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate         s = si;
1660Sstevel@tonic-gate         while (*s1 && *s1 != ':') {
1670Sstevel@tonic-gate                 if (cnt > 0) {
1680Sstevel@tonic-gate                         *s++ = *s1++;
1690Sstevel@tonic-gate                         cnt--;
1700Sstevel@tonic-gate                 } else
1710Sstevel@tonic-gate                         s1++;
1720Sstevel@tonic-gate         }
1730Sstevel@tonic-gate         if (si != s && cnt > 0) {
1740Sstevel@tonic-gate                 *s++ = '/';
1750Sstevel@tonic-gate                 cnt--;
1760Sstevel@tonic-gate         }
1770Sstevel@tonic-gate         while (*s2 && cnt > 0) {
1780Sstevel@tonic-gate                 *s++ = *s2++;
1790Sstevel@tonic-gate                 cnt--;
1800Sstevel@tonic-gate         }
1810Sstevel@tonic-gate         *s = '\0';
1820Sstevel@tonic-gate         return (*s1 ? ++s1: 0);
1830Sstevel@tonic-gate }
1840Sstevel@tonic-gate 
1850Sstevel@tonic-gate /*
1860Sstevel@tonic-gate  * Similiar to execvp(), execpt you can supply an environment and we always
1870Sstevel@tonic-gate  * use /bin/sh for shell scripts.  The PATH searched is the PATH in the
1880Sstevel@tonic-gate  * current environment, not the environment in the argument list.
1890Sstevel@tonic-gate  * This was pretty much stolen from libc/gen/port/execvp.c
1900Sstevel@tonic-gate  */
1910Sstevel@tonic-gate static int
1920Sstevel@tonic-gate execvpe(char *name, char *const argv[], char *const envp[])
1930Sstevel@tonic-gate {
1940Sstevel@tonic-gate 	char *path;
1950Sstevel@tonic-gate 	char fname[PATH_MAX+2];
1960Sstevel@tonic-gate 	char *newargs[256];
1970Sstevel@tonic-gate 	int i;
1980Sstevel@tonic-gate 	const char *cp;
1990Sstevel@tonic-gate 	unsigned etxtbsy = 1;
2000Sstevel@tonic-gate         int eacces = 0;
2010Sstevel@tonic-gate 
2020Sstevel@tonic-gate 	if (*name == '\0') {
2030Sstevel@tonic-gate 		errno = ENOENT;
2040Sstevel@tonic-gate 		return (-1);
2050Sstevel@tonic-gate 	}
2060Sstevel@tonic-gate 
2070Sstevel@tonic-gate 	if ((path = getenv("PATH")) == NULL)
2080Sstevel@tonic-gate 		path = "/usr/bin:/bin";
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate         cp = strchr(name, '/')? (const char *)"": path;
2110Sstevel@tonic-gate 
2120Sstevel@tonic-gate         do {
2130Sstevel@tonic-gate                 cp = execat(cp, name, fname);
2140Sstevel@tonic-gate         retry:
2150Sstevel@tonic-gate                 /*
2160Sstevel@tonic-gate                  * 4025035 and 4038378
2170Sstevel@tonic-gate                  * if a filename begins with a "-" prepend "./" so that
2180Sstevel@tonic-gate                  * the shell can't interpret it as an option
2190Sstevel@tonic-gate                  */
2200Sstevel@tonic-gate                 if (*fname == '-') {
2210Sstevel@tonic-gate                         size_t size = strlen(fname) + 1;
2220Sstevel@tonic-gate                         if ((size + 2) > sizeof (fname)) {
2230Sstevel@tonic-gate                                 errno = E2BIG;
2240Sstevel@tonic-gate                                 return (-1);
2250Sstevel@tonic-gate                         }
2260Sstevel@tonic-gate                         (void) memmove(fname + 2, fname, size);
2270Sstevel@tonic-gate                         fname[0] = '.';
2280Sstevel@tonic-gate                         fname[1] = '/';
2290Sstevel@tonic-gate                 }
2300Sstevel@tonic-gate                 (void) execve(fname, argv, envp);
2310Sstevel@tonic-gate                 switch (errno) {
2320Sstevel@tonic-gate                 case ENOEXEC:
2330Sstevel@tonic-gate                         newargs[0] = "sh";
2340Sstevel@tonic-gate                         newargs[1] = fname;
2350Sstevel@tonic-gate                         for (i = 1; (newargs[i + 1] = argv[i]) != NULL; ++i) {
2360Sstevel@tonic-gate                                 if (i >= 254) {
2370Sstevel@tonic-gate                                         errno = E2BIG;
2380Sstevel@tonic-gate                                         return (-1);
2390Sstevel@tonic-gate                                 }
2400Sstevel@tonic-gate                         }
2410Sstevel@tonic-gate                         (void) execve("/bin/sh", newargs, envp);
2420Sstevel@tonic-gate                         return (-1);
2430Sstevel@tonic-gate                 case ETXTBSY:
2440Sstevel@tonic-gate                         if (++etxtbsy > 5)
2450Sstevel@tonic-gate                                 return (-1);
2460Sstevel@tonic-gate                         (void) sleep(etxtbsy);
2470Sstevel@tonic-gate                         goto retry;
2480Sstevel@tonic-gate                 case EACCES:
2490Sstevel@tonic-gate                         ++eacces;
2500Sstevel@tonic-gate                         break;
2510Sstevel@tonic-gate                 case ENOMEM:
2520Sstevel@tonic-gate                 case E2BIG:
2530Sstevel@tonic-gate                 case EFAULT:
2540Sstevel@tonic-gate                         return (-1);
2550Sstevel@tonic-gate                 }
2560Sstevel@tonic-gate         } while (cp);
2570Sstevel@tonic-gate         if (eacces)
2580Sstevel@tonic-gate                 errno = EACCES;
2590Sstevel@tonic-gate         return (-1);
2600Sstevel@tonic-gate }
2610Sstevel@tonic-gate 
2620Sstevel@tonic-gate static char time_buf[50];
2631676Sjpk 
2640Sstevel@tonic-gate /**
2650Sstevel@tonic-gate  ** exec() - FORK AND EXEC CHILD PROCESS
2660Sstevel@tonic-gate  **/
2670Sstevel@tonic-gate 
2680Sstevel@tonic-gate /*VARARGS1*/
2690Sstevel@tonic-gate int
2700Sstevel@tonic-gate exec(int type, ...)
2710Sstevel@tonic-gate {
2720Sstevel@tonic-gate 	va_list			args;
2730Sstevel@tonic-gate 
2740Sstevel@tonic-gate 	int			i;
2750Sstevel@tonic-gate 	int			procuid;
2760Sstevel@tonic-gate 	int			procgid;
2770Sstevel@tonic-gate 	int			ret;
2780Sstevel@tonic-gate 	int			fr_flg;
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate 	char			*cp;
2810Sstevel@tonic-gate 	char			*infile;
2820Sstevel@tonic-gate 	char			*outfile;
2830Sstevel@tonic-gate 	char			*errfile;
2840Sstevel@tonic-gate 	char			*sep;
2850Sstevel@tonic-gate 
2860Sstevel@tonic-gate 	char			**listp;
2870Sstevel@tonic-gate 	char			**file_list;
2880Sstevel@tonic-gate 	char			*printerName;
2890Sstevel@tonic-gate 	char			*printerNameToShow;
2900Sstevel@tonic-gate 	static char		nameBuf[100];
2910Sstevel@tonic-gate 	char			*clean_title;
2920Sstevel@tonic-gate 
2930Sstevel@tonic-gate 	PSTATUS			*printer;
2940Sstevel@tonic-gate 
2950Sstevel@tonic-gate 	RSTATUS			*request;
2960Sstevel@tonic-gate 
2970Sstevel@tonic-gate 	FSTATUS			*form;
2980Sstevel@tonic-gate 
2990Sstevel@tonic-gate 	EXEC			*ep;
3000Sstevel@tonic-gate 
3010Sstevel@tonic-gate 	PWSTATUS		*pwheel;
3020Sstevel@tonic-gate 	time_t			now;
3030Sstevel@tonic-gate 	struct passwd		*pwp;
3040Sstevel@tonic-gate #ifdef LP_USE_PAPI_ATTR
3050Sstevel@tonic-gate 	struct stat		tmpBuf;
3060Sstevel@tonic-gate 	char 			tmpName[BUFSIZ];
3070Sstevel@tonic-gate 	char			*path = NULL;
3080Sstevel@tonic-gate #endif
3090Sstevel@tonic-gate 	char *av[ARG_MAX];
3100Sstevel@tonic-gate 	char **envp = NULL;
3110Sstevel@tonic-gate 	int ac = 0;
3121676Sjpk 	char	*mail_zonename = NULL;
3131676Sjpk 	char	*slabel = NULL;
3140Sstevel@tonic-gate 
3150Sstevel@tonic-gate 	syslog(LOG_DEBUG, "exec(%s)", _exec_name(type));
3160Sstevel@tonic-gate 
3170Sstevel@tonic-gate 	memset(av, 0, sizeof (*av));
3180Sstevel@tonic-gate 
3190Sstevel@tonic-gate 	va_start (args, type);
3200Sstevel@tonic-gate 
3210Sstevel@tonic-gate 	switch (type) {
3220Sstevel@tonic-gate 
3230Sstevel@tonic-gate 	case EX_INTERF:
3240Sstevel@tonic-gate 		printer = va_arg(args, PSTATUS *);
3250Sstevel@tonic-gate 		request = printer->request;
3260Sstevel@tonic-gate 		ep = printer->exec;
3270Sstevel@tonic-gate 		break;
3280Sstevel@tonic-gate 
3290Sstevel@tonic-gate 	case EX_FAULT_MESSAGE:
3300Sstevel@tonic-gate 		printer = va_arg(args, PSTATUS *);
3310Sstevel@tonic-gate 		request = va_arg(args, RSTATUS *);
3320Sstevel@tonic-gate 		if (! ( printer->status & (PS_FORM_FAULT | PS_SHOW_FAULT))) {
3330Sstevel@tonic-gate 			return(0);
3340Sstevel@tonic-gate 		}
3350Sstevel@tonic-gate 		ep = printer->fault_exec;
3360Sstevel@tonic-gate 		printerName = (printer->printer && printer->printer->name
3370Sstevel@tonic-gate 				  ? printer->printer->name : "??");
3380Sstevel@tonic-gate 			snprintf(nameBuf, sizeof (nameBuf),
3390Sstevel@tonic-gate 				"%s (on %s)\n", printerName, Local_System);
3400Sstevel@tonic-gate 
3410Sstevel@tonic-gate 		printerNameToShow = nameBuf;
3420Sstevel@tonic-gate 
3430Sstevel@tonic-gate 		(void) time(&now);
3440Sstevel@tonic-gate 		(void) strftime(time_buf, sizeof (time_buf),
3450Sstevel@tonic-gate 			NULL, localtime(&now));
3460Sstevel@tonic-gate 		break;
3470Sstevel@tonic-gate 
3480Sstevel@tonic-gate 	case EX_SLOWF:
3490Sstevel@tonic-gate 		request = va_arg(args, RSTATUS *);
3500Sstevel@tonic-gate 		ep = request->exec;
3510Sstevel@tonic-gate 		break;
3520Sstevel@tonic-gate 
3530Sstevel@tonic-gate 	case EX_NOTIFY:
3540Sstevel@tonic-gate 		request = va_arg(args, RSTATUS *);
3550Sstevel@tonic-gate 		if (request->request->actions & ACT_NOTIFY) {
3560Sstevel@tonic-gate 			errno = EINVAL;
3570Sstevel@tonic-gate 			return (-1);
3580Sstevel@tonic-gate 		}
3590Sstevel@tonic-gate 		ep = request->exec;
3600Sstevel@tonic-gate 		break;
3610Sstevel@tonic-gate 
3620Sstevel@tonic-gate 	case EX_ALERT:
3630Sstevel@tonic-gate 		printer = va_arg(args, PSTATUS *);
3640Sstevel@tonic-gate 		if (!(printer->printer->fault_alert.shcmd)) {
3650Sstevel@tonic-gate 			errno = EINVAL;
3660Sstevel@tonic-gate 			return(-1);
3670Sstevel@tonic-gate 		}
3680Sstevel@tonic-gate 		ep = printer->alert->exec;
3690Sstevel@tonic-gate 		break;
3700Sstevel@tonic-gate 
3710Sstevel@tonic-gate 	case EX_PALERT:
3720Sstevel@tonic-gate 		pwheel = va_arg(args, PWSTATUS *);
3730Sstevel@tonic-gate 		ep = pwheel->alert->exec;
3740Sstevel@tonic-gate 		break;
3750Sstevel@tonic-gate 
3760Sstevel@tonic-gate 	case EX_FORM_MESSAGE:
3770Sstevel@tonic-gate 		(void) time(&now);
3780Sstevel@tonic-gate 		(void) strftime(time_buf, sizeof (time_buf),
3790Sstevel@tonic-gate 			NULL, localtime(&now));
3800Sstevel@tonic-gate 
3810Sstevel@tonic-gate 		/*FALLTHRU*/
3820Sstevel@tonic-gate 	case EX_FALERT:
3830Sstevel@tonic-gate 		form = va_arg(args, FSTATUS *);
3840Sstevel@tonic-gate 		ep = form->alert->exec;
3850Sstevel@tonic-gate 		break;
3860Sstevel@tonic-gate 
3870Sstevel@tonic-gate 	default:
3880Sstevel@tonic-gate 		errno = EINVAL;
3890Sstevel@tonic-gate 		return(-1);
3900Sstevel@tonic-gate 
3910Sstevel@tonic-gate 	}
3920Sstevel@tonic-gate 	va_end (args);
3930Sstevel@tonic-gate 
3940Sstevel@tonic-gate 	if (!ep || (ep->pid > 0)) {
3950Sstevel@tonic-gate 		errno = EBUSY;
3960Sstevel@tonic-gate 		return(-1);
3970Sstevel@tonic-gate 	}
3980Sstevel@tonic-gate 
3990Sstevel@tonic-gate 	ep->flags = 0;
4000Sstevel@tonic-gate 
4010Sstevel@tonic-gate 	key = ep->key = getkey();
4020Sstevel@tonic-gate 
4030Sstevel@tonic-gate 	switch ((ep->pid = Fork1(ep))) {
4040Sstevel@tonic-gate 
4050Sstevel@tonic-gate 	case -1:
4060Sstevel@tonic-gate 		relock ();
4070Sstevel@tonic-gate 		return(-1);
4080Sstevel@tonic-gate 
4090Sstevel@tonic-gate 	case 0:
4100Sstevel@tonic-gate 		/*
4110Sstevel@tonic-gate 		 * We want to be able to tell our parent how we died.
4120Sstevel@tonic-gate 		 */
4130Sstevel@tonic-gate 		lp_alloc_fail_handler = child_mallocfail;
4140Sstevel@tonic-gate 		break;
4150Sstevel@tonic-gate 
4160Sstevel@tonic-gate 	default:
4170Sstevel@tonic-gate 		switch(type) {
4180Sstevel@tonic-gate 
4190Sstevel@tonic-gate 		case EX_INTERF:
4200Sstevel@tonic-gate 			request->request->outcome |= RS_PRINTING;
4210Sstevel@tonic-gate 			break;
4220Sstevel@tonic-gate 
4230Sstevel@tonic-gate 		case EX_NOTIFY:
4240Sstevel@tonic-gate 			request->request->outcome |= RS_NOTIFYING;
4250Sstevel@tonic-gate 			break;
4260Sstevel@tonic-gate 
4270Sstevel@tonic-gate 		case EX_SLOWF:
4280Sstevel@tonic-gate 			request->request->outcome |= RS_FILTERING;
4290Sstevel@tonic-gate 			request->request->outcome &= ~RS_REFILTER;
4300Sstevel@tonic-gate 			break;
4310Sstevel@tonic-gate 
4320Sstevel@tonic-gate 		}
4330Sstevel@tonic-gate 		return(0);
4340Sstevel@tonic-gate 
4350Sstevel@tonic-gate 	}
4360Sstevel@tonic-gate 
4370Sstevel@tonic-gate 	for (i = 0; i < NSIG; i++)
4380Sstevel@tonic-gate 		(void)signal (i, SIG_DFL);
4390Sstevel@tonic-gate 	(void)signal (SIGALRM, SIG_IGN);
4400Sstevel@tonic-gate 	(void)signal (SIGTERM, sigtrap);
441*3125Sjacobs 
442*3125Sjacobs 	closelog();
4430Sstevel@tonic-gate 	for (i = 0; i < OpenMax; i++)
4440Sstevel@tonic-gate 		if (i != ChildMd->writefd)
4450Sstevel@tonic-gate 			Close (i);
446*3125Sjacobs 	openlog("lpsched", LOG_PID|LOG_NDELAY|LOG_NOWAIT, LOG_LPR);
447*3125Sjacobs 
4480Sstevel@tonic-gate 	setpgrp();
4490Sstevel@tonic-gate 
4500Sstevel@tonic-gate 	/* Set a default path */
4510Sstevel@tonic-gate 	addenv (&envp, "PATH", "/usr/lib/lp/bin:/usr/bin:/bin:/usr/sbin:/sbin");
4520Sstevel@tonic-gate 	/* copy locale related variables */
4530Sstevel@tonic-gate 	addenv (&envp, "TZ", getenv("TZ"));
4540Sstevel@tonic-gate 	addenv (&envp, "LANG", getenv("LANG"));
4550Sstevel@tonic-gate 	addenv (&envp, "LC_ALL", getenv("LC_ALL"));
4560Sstevel@tonic-gate 	addenv (&envp, "LC_COLLATE", getenv("LC_COLLATE"));
4570Sstevel@tonic-gate 	addenv (&envp, "LC_CTYPE", getenv("LC_CTYPE"));
4580Sstevel@tonic-gate 	addenv (&envp, "LC_MESSAGES", getenv("LC_MESSAGES"));
4590Sstevel@tonic-gate 	addenv (&envp, "LC_MONETARY", getenv("LC_MONETARY"));
4600Sstevel@tonic-gate 	addenv (&envp, "LC_NUMERIC", getenv("LC_NUMERIC"));
4610Sstevel@tonic-gate 	addenv (&envp, "LC_TIME", getenv("LC_TIME"));
4620Sstevel@tonic-gate 
4630Sstevel@tonic-gate 	sprintf ((cp = BIGGEST_NUMBER_S), "%ld", key);
4640Sstevel@tonic-gate 	addenv (&envp, "SPOOLER_KEY", cp);
4650Sstevel@tonic-gate 
4660Sstevel@tonic-gate #if	defined(DEBUG)
4670Sstevel@tonic-gate 	addenv (&envp, "LPDEBUG", (debug? "1" : "0"));
4680Sstevel@tonic-gate #endif
4690Sstevel@tonic-gate 
4700Sstevel@tonic-gate 	/*
4710Sstevel@tonic-gate 	 * Open the standard input, standard output, and standard error.
4720Sstevel@tonic-gate 	 */
4730Sstevel@tonic-gate 	switch (type) {
4740Sstevel@tonic-gate 
4750Sstevel@tonic-gate 	case EX_SLOWF:
4760Sstevel@tonic-gate 	case EX_INTERF:
4770Sstevel@tonic-gate 		/*
4780Sstevel@tonic-gate 		 * stdin:  /dev/null
4790Sstevel@tonic-gate 		 * stdout: /dev/null (EX_SLOWF), printer port (EX_INTERF)
4800Sstevel@tonic-gate 		 * stderr: req#
4810Sstevel@tonic-gate 		 */
4820Sstevel@tonic-gate 		infile = 0;
4830Sstevel@tonic-gate 		outfile = 0;
4840Sstevel@tonic-gate 		errfile = makereqerr(request);
4850Sstevel@tonic-gate 		break;
4860Sstevel@tonic-gate 
4870Sstevel@tonic-gate 	case EX_NOTIFY:
4880Sstevel@tonic-gate 		/*
4890Sstevel@tonic-gate 		 * stdin:  req#
4900Sstevel@tonic-gate 		 * stdout: /dev/null
4910Sstevel@tonic-gate 		 * stderr: /dev/null
4920Sstevel@tonic-gate 		 */
4930Sstevel@tonic-gate 		infile = makereqerr(request);
4940Sstevel@tonic-gate 		outfile = 0;
4950Sstevel@tonic-gate 		errfile = 0;
4960Sstevel@tonic-gate 
4970Sstevel@tonic-gate 		break;
4980Sstevel@tonic-gate 
4990Sstevel@tonic-gate 	case EX_ALERT:
5000Sstevel@tonic-gate 	case EX_FALERT:
5010Sstevel@tonic-gate 	case EX_PALERT:
5020Sstevel@tonic-gate 	case EX_FAULT_MESSAGE:
5030Sstevel@tonic-gate 	case EX_FORM_MESSAGE:
5040Sstevel@tonic-gate 		/*
5050Sstevel@tonic-gate 		 * stdin:  /dev/null
5060Sstevel@tonic-gate 		 * stdout: /dev/null
5070Sstevel@tonic-gate 		 * stderr: /dev/null
5080Sstevel@tonic-gate 		 */
5090Sstevel@tonic-gate 		infile = 0;
5100Sstevel@tonic-gate 		outfile = 0;
5110Sstevel@tonic-gate 		errfile = 0;
5120Sstevel@tonic-gate 		break;
5130Sstevel@tonic-gate 
5140Sstevel@tonic-gate 	}
5150Sstevel@tonic-gate 
5160Sstevel@tonic-gate 	if (infile) {
5170Sstevel@tonic-gate 		if (Open(infile, O_RDONLY) == -1)
5180Sstevel@tonic-gate 			Done (EXEC_EXIT_NOPEN, errno);
5190Sstevel@tonic-gate 	} else {
5200Sstevel@tonic-gate 		if (Open("/dev/null", O_RDONLY) == -1)
5210Sstevel@tonic-gate 			Done (EXEC_EXIT_NOPEN, errno);
5220Sstevel@tonic-gate 	}
5230Sstevel@tonic-gate 
5240Sstevel@tonic-gate 	if (outfile) {
5250Sstevel@tonic-gate 		if (Open(outfile, O_CREAT|O_TRUNC|O_WRONLY, 0600) == -1)
5260Sstevel@tonic-gate 			Done (EXEC_EXIT_NOPEN, errno);
5270Sstevel@tonic-gate 	} else {
5280Sstevel@tonic-gate 		/*
5290Sstevel@tonic-gate 		 * If EX_INTERF, this is still needed to cause the
5300Sstevel@tonic-gate 		 * standard error channel to be #2.
5310Sstevel@tonic-gate 		 */
5320Sstevel@tonic-gate 		if (Open("/dev/null", O_WRONLY) == -1)
5330Sstevel@tonic-gate 			Done (EXEC_EXIT_NOPEN, errno);
5340Sstevel@tonic-gate 	}
5350Sstevel@tonic-gate 
5360Sstevel@tonic-gate 	if (errfile) {
5370Sstevel@tonic-gate 		if (Open(errfile, O_CREAT|O_TRUNC|O_WRONLY, 0600) == -1)
5380Sstevel@tonic-gate 			Done (EXEC_EXIT_NOPEN, errno);
5390Sstevel@tonic-gate 	} else {
5400Sstevel@tonic-gate 		if (Open("/dev/null", O_WRONLY) == -1)
5410Sstevel@tonic-gate 			Done (EXEC_EXIT_NOPEN, errno);
5420Sstevel@tonic-gate 	}
5430Sstevel@tonic-gate 
5440Sstevel@tonic-gate 	switch (type) {
5450Sstevel@tonic-gate 
5460Sstevel@tonic-gate 	case EX_INTERF:
5470Sstevel@tonic-gate 		/*
5480Sstevel@tonic-gate 		 * Opening a ``port'' can be dangerous to our health:
5490Sstevel@tonic-gate 		 *
5500Sstevel@tonic-gate 		 *	- Hangups can occur if the line is dropped.
5510Sstevel@tonic-gate 		 *	- The printer may send an interrupt.
5520Sstevel@tonic-gate 		 *	- A FIFO may be closed, generating SIGPIPE.
5530Sstevel@tonic-gate 		 *
5540Sstevel@tonic-gate 		 * We catch these so we can complain nicely.
5550Sstevel@tonic-gate 		 */
5560Sstevel@tonic-gate 		trap_fault_signals ();
5570Sstevel@tonic-gate 
5580Sstevel@tonic-gate 		(void)Close (1);
5590Sstevel@tonic-gate 
560*3125Sjacobs 		if (strchr (request->request->user, '@'))
5610Sstevel@tonic-gate 		{
5620Sstevel@tonic-gate 			procuid = Lp_Uid;
5630Sstevel@tonic-gate 			procgid = Lp_Gid;
5640Sstevel@tonic-gate 		}
5650Sstevel@tonic-gate 		else
5660Sstevel@tonic-gate 		{
5670Sstevel@tonic-gate 			procuid = request->secure->uid;
5680Sstevel@tonic-gate 			procgid = request->secure->gid;
5690Sstevel@tonic-gate 		}
5700Sstevel@tonic-gate 		if (printer->printer->dial_info)
5710Sstevel@tonic-gate 		{
5720Sstevel@tonic-gate 			ret = open_dialup(request->printer_type,
5730Sstevel@tonic-gate 				printer->printer);
5740Sstevel@tonic-gate 			if (ret == 0)
5750Sstevel@tonic-gate 				do_undial = 1;
5760Sstevel@tonic-gate 		}
5770Sstevel@tonic-gate 		else
5780Sstevel@tonic-gate 		{
5790Sstevel@tonic-gate 			ret = open_direct(request->printer_type,
5800Sstevel@tonic-gate 				printer->printer);
5810Sstevel@tonic-gate 			do_undial = 0;
5820Sstevel@tonic-gate 			/* this is a URI */
5830Sstevel@tonic-gate 			if (is_printer_uri(printer->printer->device) == 0)
5840Sstevel@tonic-gate 				addenv(&envp, "DEVICE_URI",
5850Sstevel@tonic-gate 					 printer->printer->device);
5860Sstevel@tonic-gate 		}
5870Sstevel@tonic-gate 				addenv(&envp, "DEVICE_URI",
5880Sstevel@tonic-gate 					 printer->printer->device);
5890Sstevel@tonic-gate 		if (ret != 0)
5900Sstevel@tonic-gate 			Done (ret, errno);
5910Sstevel@tonic-gate 
5920Sstevel@tonic-gate 		if (!(request->request->outcome & RS_FILTERED))
5930Sstevel@tonic-gate 			file_list = request->request->file_list;
5940Sstevel@tonic-gate 
5950Sstevel@tonic-gate 		else {
5960Sstevel@tonic-gate 			register int		count	= 0;
5970Sstevel@tonic-gate 			register char *		num	= BIGGEST_REQID_S;
5980Sstevel@tonic-gate 			register char *		prefix;
5990Sstevel@tonic-gate 
6000Sstevel@tonic-gate 			prefix = makestr(
601*3125Sjacobs 				Lp_Temp,
6020Sstevel@tonic-gate 				"/F",
6030Sstevel@tonic-gate 				getreqno(request->secure->req_id),
6040Sstevel@tonic-gate 				"-",
6050Sstevel@tonic-gate 				(char *)0
6060Sstevel@tonic-gate 			);
6070Sstevel@tonic-gate 
6080Sstevel@tonic-gate 			file_list = (char **)Malloc(
6090Sstevel@tonic-gate 				(lenlist(request->request->file_list) + 1)
6100Sstevel@tonic-gate 			      * sizeof(char *)
6110Sstevel@tonic-gate 			);
6120Sstevel@tonic-gate 
6130Sstevel@tonic-gate 			for (
6140Sstevel@tonic-gate 				listp = request->request->file_list;
6150Sstevel@tonic-gate 				*listp;
6160Sstevel@tonic-gate 				listp++
6170Sstevel@tonic-gate 			) {
6180Sstevel@tonic-gate 				sprintf (num, "%d", count + 1);
6190Sstevel@tonic-gate 				file_list[count] = makestr(
6200Sstevel@tonic-gate 					prefix,
6210Sstevel@tonic-gate 					num,
6220Sstevel@tonic-gate 					(char *)0
6230Sstevel@tonic-gate 				);
6240Sstevel@tonic-gate 				count++;
6250Sstevel@tonic-gate 			}
6260Sstevel@tonic-gate 			file_list[count] = 0;
6270Sstevel@tonic-gate 		}
6280Sstevel@tonic-gate 
6290Sstevel@tonic-gate #ifdef LP_USE_PAPI_ATTR
6300Sstevel@tonic-gate 		/*
6310Sstevel@tonic-gate 		 * Check if the PAPI job attribute file exists, if it does
6320Sstevel@tonic-gate 		 * pass the file's pathname to the printer interface script
6330Sstevel@tonic-gate 		 * in an environment variable. This file is created when
6340Sstevel@tonic-gate 		 * print jobs are submitted via the PAPI interface.
6350Sstevel@tonic-gate 		 */
6360Sstevel@tonic-gate 		snprintf(tmpName, sizeof (tmpName), "%s-%s",
6370Sstevel@tonic-gate 			getreqno(request->secure->req_id), LP_PAPIATTRNAME);
638*3125Sjacobs 		path = makepath(Lp_Temp, tmpName, (char *)0);
6390Sstevel@tonic-gate 		if ((path != NULL) && (stat(path, &tmpBuf) == 0))
6400Sstevel@tonic-gate 		{
6410Sstevel@tonic-gate 			/*
6420Sstevel@tonic-gate 			 * IPP job attribute file exists for this job so
6430Sstevel@tonic-gate 			 * set the environment variable
6440Sstevel@tonic-gate 			 */
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 				addenv(&envp, "PPD", path);
6640Sstevel@tonic-gate 			}
6650Sstevel@tonic-gate 			Free(path);
6660Sstevel@tonic-gate 		}
6670Sstevel@tonic-gate #endif
6680Sstevel@tonic-gate 
6690Sstevel@tonic-gate 		if (request->printer_type)
6700Sstevel@tonic-gate 			addenv(&envp, "TERM", request->printer_type);
6710Sstevel@tonic-gate 
6720Sstevel@tonic-gate 		if (!(printer->printer->daisy)) {
6730Sstevel@tonic-gate 			register char *	chset = 0;
6740Sstevel@tonic-gate 			register char *	csp;
6750Sstevel@tonic-gate 
6760Sstevel@tonic-gate 			if (
6770Sstevel@tonic-gate 				request->form
6780Sstevel@tonic-gate 			     && request->form->form->chset
6790Sstevel@tonic-gate 			     && request->form->form->mandatory
6800Sstevel@tonic-gate 			     && !STREQU(NAME_ANY, request->form->form->chset)
6810Sstevel@tonic-gate 			)
6820Sstevel@tonic-gate 				chset = request->form->form->chset;
6830Sstevel@tonic-gate 
6840Sstevel@tonic-gate 			else if (
6850Sstevel@tonic-gate 				request->request->charset
6860Sstevel@tonic-gate 			     && !STREQU(NAME_ANY, request->request->charset)
6870Sstevel@tonic-gate 			)
6880Sstevel@tonic-gate 				chset = request->request->charset;
6890Sstevel@tonic-gate 
6900Sstevel@tonic-gate 			if (chset) {
6910Sstevel@tonic-gate 				csp = search_cslist(
6920Sstevel@tonic-gate 					chset,
6930Sstevel@tonic-gate 					printer->printer->char_sets
6940Sstevel@tonic-gate 				);
6950Sstevel@tonic-gate 
6960Sstevel@tonic-gate 				/*
6970Sstevel@tonic-gate 				 * The "strtok()" below wrecks the string
6980Sstevel@tonic-gate 				 * for future use, but this is a child
6990Sstevel@tonic-gate 				 * process where it won't be needed again.
7000Sstevel@tonic-gate 				 */
7010Sstevel@tonic-gate 				addenv (&envp, "CHARSET",
7020Sstevel@tonic-gate 					(csp? strtok(csp, "=") : chset)
7030Sstevel@tonic-gate 				);
7040Sstevel@tonic-gate 			}
7050Sstevel@tonic-gate 		}
7060Sstevel@tonic-gate 
7070Sstevel@tonic-gate 		if (request->fast)
7080Sstevel@tonic-gate 			addenv(&envp, "FILTER", request->fast);
7090Sstevel@tonic-gate 
7100Sstevel@tonic-gate 		/*
7111676Sjpk 		 * Add the sensitivity label to the environment for
7121676Sjpk 		 * banner page and header/footer processing
7131676Sjpk 		 */
7141676Sjpk 
7151676Sjpk 		if (is_system_labeled() && request->secure->slabel != NULL)
7161676Sjpk 			addenv(&envp, "SLABEL", request->secure->slabel);
7171676Sjpk 
7181676Sjpk 		/*
7190Sstevel@tonic-gate 		 * Add the system name to the user name (ala system!user)
7200Sstevel@tonic-gate 		 * unless it is already there. RFS users may have trouble
7210Sstevel@tonic-gate 		 * here, sorry!
7220Sstevel@tonic-gate 		 */
7230Sstevel@tonic-gate 		cp = strchr(request->secure->user, '@');
7240Sstevel@tonic-gate 
7250Sstevel@tonic-gate 		allTraysWithForm(printer, request->form);
7260Sstevel@tonic-gate 
7270Sstevel@tonic-gate 		/*
7280Sstevel@tonic-gate 		 * Fix for 4137389
7290Sstevel@tonic-gate 		 * Remove double quotes from title string.
7300Sstevel@tonic-gate 		 */
7310Sstevel@tonic-gate 		fr_flg = 1;
7320Sstevel@tonic-gate 		clean_title = strdup(NB(request->request->title));
7330Sstevel@tonic-gate 		if (clean_title == NULL) {
7340Sstevel@tonic-gate 			/*
7350Sstevel@tonic-gate 			 * strdup failed. We're probably hosed
7360Sstevel@tonic-gate 			 * but try setting clean_title
7370Sstevel@tonic-gate 			 * to original title and continuing.
7380Sstevel@tonic-gate 			 */
7390Sstevel@tonic-gate 			clean_title = NB(request->request->title);
7400Sstevel@tonic-gate 			fr_flg = 0;
7410Sstevel@tonic-gate 		} else if (strcmp(clean_title, "") != 0) {
7420Sstevel@tonic-gate 			char *ct_p;
7430Sstevel@tonic-gate 
7440Sstevel@tonic-gate 			for (ct_p = clean_title; *ct_p != NULL; ct_p++) {
7450Sstevel@tonic-gate 				if (*ct_p == '"')
7460Sstevel@tonic-gate 					*ct_p = ' ';
7470Sstevel@tonic-gate 			}
7480Sstevel@tonic-gate 		}
7490Sstevel@tonic-gate 
7500Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s/%s", Lp_A_Interfaces,
7510Sstevel@tonic-gate 					printer->printer->name);
7520Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s", request->secure->req_id);
753*3125Sjacobs 		av[ac++] = arg_string(UNTRUSTED, "%s", request->request->user);
7540Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s", clean_title);
7550Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%d", request->copies);
7560Sstevel@tonic-gate 
7570Sstevel@tonic-gate 		if (fr_flg)
7580Sstevel@tonic-gate 			free (clean_title);
7590Sstevel@tonic-gate 
7600Sstevel@tonic-gate 		sep = "";
7610Sstevel@tonic-gate 
7620Sstevel@tonic-gate 		/*
7630Sstevel@tonic-gate 		 * Do the administrator defined key=value pair options
7640Sstevel@tonic-gate 		 */
7650Sstevel@tonic-gate 
7660Sstevel@tonic-gate 		argbuf[0] = '\0';
7670Sstevel@tonic-gate 
7680Sstevel@tonic-gate 		if (printer->printer->options) {
7690Sstevel@tonic-gate 			char **tmp = printer->printer->options;
7700Sstevel@tonic-gate 			while(*tmp != NULL) {
7710Sstevel@tonic-gate 				STRLCAT(argbuf, sep, sizeof (argbuf));
7720Sstevel@tonic-gate 				sep = " ";
7730Sstevel@tonic-gate 				STRLCAT(argbuf, *tmp++, sizeof (argbuf));
7740Sstevel@tonic-gate 			}
7750Sstevel@tonic-gate 		}
7760Sstevel@tonic-gate 
7770Sstevel@tonic-gate 		/*
7780Sstevel@tonic-gate 		 * Do the administrator defined ``stty'' stuff before
7790Sstevel@tonic-gate 		 * the user's -o options, to allow the user to override.
7800Sstevel@tonic-gate 		 */
7810Sstevel@tonic-gate 		if (printer->printer->stty) {
7820Sstevel@tonic-gate 			STRLCAT (argbuf, sep, sizeof (argbuf));
7830Sstevel@tonic-gate 			sep = " ";
7840Sstevel@tonic-gate 			STRLCAT (argbuf, "stty='", sizeof (argbuf));
7850Sstevel@tonic-gate 			STRLCAT (argbuf, printer->printer->stty,
7860Sstevel@tonic-gate 			    sizeof (argbuf));
7870Sstevel@tonic-gate 			STRLCAT (argbuf, "'", sizeof (argbuf));
7880Sstevel@tonic-gate 		}
7890Sstevel@tonic-gate 
7900Sstevel@tonic-gate 		/*
7910Sstevel@tonic-gate 		 * Do all of the user's options except the cpi/lpi/etc.
7920Sstevel@tonic-gate 		 * stuff, which is done separately.
7930Sstevel@tonic-gate 		 */
7940Sstevel@tonic-gate 		if (request->request->options) {
7950Sstevel@tonic-gate 			listp = dashos(request->request->options);
7960Sstevel@tonic-gate 			while (*listp) {
7970Sstevel@tonic-gate 				if (
7980Sstevel@tonic-gate 					!STRNEQU(*listp, "cpi=", 4)
7990Sstevel@tonic-gate 				     && !STRNEQU(*listp, "lpi=", 4)
8000Sstevel@tonic-gate 				     && !STRNEQU(*listp, "width=", 6)
8010Sstevel@tonic-gate 				     && !STRNEQU(*listp, "length=", 7)
8020Sstevel@tonic-gate 				) {
8030Sstevel@tonic-gate 					STRLCAT (argbuf, sep, sizeof (argbuf));
8040Sstevel@tonic-gate 					sep = " ";
8050Sstevel@tonic-gate 					STRLCAT (argbuf, *listp,
8060Sstevel@tonic-gate 					    sizeof (argbuf));
8070Sstevel@tonic-gate 				}
8080Sstevel@tonic-gate 				listp++;
8090Sstevel@tonic-gate 			}
8100Sstevel@tonic-gate 		}
8110Sstevel@tonic-gate 
8120Sstevel@tonic-gate 		/*
8130Sstevel@tonic-gate 		 * The "pickfilter()" routine (from "validate()")
8140Sstevel@tonic-gate 		 * stored the cpi/lpi/etc. stuff that should be
8150Sstevel@tonic-gate 		 * used for this request. It chose form over user,
8160Sstevel@tonic-gate 		 * and user over printer.
8170Sstevel@tonic-gate 		 */
8180Sstevel@tonic-gate 		if (request->cpi) {
8190Sstevel@tonic-gate 			STRLCAT (argbuf, sep, sizeof (argbuf));
8200Sstevel@tonic-gate 			sep = " ";
8210Sstevel@tonic-gate 			STRLCAT (argbuf, "cpi=", sizeof (argbuf));
8220Sstevel@tonic-gate 			STRLCAT (argbuf, request->cpi, sizeof (argbuf));
8230Sstevel@tonic-gate 		}
8240Sstevel@tonic-gate 		if (request->lpi) {
8250Sstevel@tonic-gate 			STRLCAT (argbuf, sep, sizeof (argbuf));
8260Sstevel@tonic-gate 			sep = " ";
8270Sstevel@tonic-gate 			STRLCAT (argbuf, "lpi=", sizeof (argbuf));
8280Sstevel@tonic-gate 			STRLCAT (argbuf, request->lpi, sizeof (argbuf));
8290Sstevel@tonic-gate 		}
8300Sstevel@tonic-gate 		if (request->pwid) {
8310Sstevel@tonic-gate 			STRLCAT (argbuf, sep, sizeof (argbuf));
8320Sstevel@tonic-gate 			sep = " ";
8330Sstevel@tonic-gate 			STRLCAT (argbuf, "width=", sizeof (argbuf));
8340Sstevel@tonic-gate 			STRLCAT (argbuf, request->pwid, sizeof (argbuf));
8350Sstevel@tonic-gate 		}
8360Sstevel@tonic-gate 		if (request->plen) {
8370Sstevel@tonic-gate 			STRLCAT (argbuf, sep, sizeof (argbuf));
8380Sstevel@tonic-gate 			sep = " ";
8390Sstevel@tonic-gate 			STRLCAT (argbuf, "length=", sizeof (argbuf));
8400Sstevel@tonic-gate 			STRLCAT (argbuf, request->plen, sizeof (argbuf));
8410Sstevel@tonic-gate 		}
8420Sstevel@tonic-gate 
8430Sstevel@tonic-gate 		/*
8440Sstevel@tonic-gate 		 * Do the ``raw'' bit last, to ensure it gets
8450Sstevel@tonic-gate 		 * done. If the user doesn't want this, then he or
8460Sstevel@tonic-gate 		 * she can do the correct thing using -o stty=
8470Sstevel@tonic-gate 		 * and leaving out the -r option.
8480Sstevel@tonic-gate 		 */
8490Sstevel@tonic-gate 		if (request->request->actions & ACT_RAW) {
8500Sstevel@tonic-gate 			STRLCAT (argbuf, sep, sizeof (argbuf));
8510Sstevel@tonic-gate 			sep = " ";
8520Sstevel@tonic-gate 			STRLCAT (argbuf, "stty=-opost", sizeof (argbuf));
8530Sstevel@tonic-gate 		}
8540Sstevel@tonic-gate 
8550Sstevel@tonic-gate 
8560Sstevel@tonic-gate 		/* the "options" */
8570Sstevel@tonic-gate 		av[ac++] = arg_string(UNTRUSTED, "%s", argbuf);
8580Sstevel@tonic-gate 
8590Sstevel@tonic-gate 		for (listp = file_list; *listp; listp++)
8600Sstevel@tonic-gate 			av[ac++] = arg_string(TRUSTED, "%s", *listp);
8610Sstevel@tonic-gate 
8620Sstevel@tonic-gate 		(void)chfiles (file_list, procuid, procgid);
8630Sstevel@tonic-gate 
8640Sstevel@tonic-gate 		break;
8650Sstevel@tonic-gate 
8660Sstevel@tonic-gate 
8670Sstevel@tonic-gate 	case EX_SLOWF:
8680Sstevel@tonic-gate 		if (request->slow)
8690Sstevel@tonic-gate 			addenv(&envp, "FILTER", request->slow);
8700Sstevel@tonic-gate 
871*3125Sjacobs 		if (strchr (request->request->user, '@'))
8720Sstevel@tonic-gate 		{
8730Sstevel@tonic-gate 			procuid = Lp_Uid;
8740Sstevel@tonic-gate 			procgid = Lp_Gid;
8750Sstevel@tonic-gate 		}
8760Sstevel@tonic-gate 		else
8770Sstevel@tonic-gate 		{
8780Sstevel@tonic-gate 			procuid = request->secure->uid;
8790Sstevel@tonic-gate 			procgid = request->secure->gid;
8800Sstevel@tonic-gate 		}
8810Sstevel@tonic-gate 		cp = _alloc_files(
8820Sstevel@tonic-gate 			lenlist(request->request->file_list),
8830Sstevel@tonic-gate 			getreqno(request->secure->req_id),
884*3125Sjacobs 			procuid, procgid);
8850Sstevel@tonic-gate 
8860Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s", Lp_Slow_Filter);
887*3125Sjacobs 		av[ac++] = arg_string(TRUSTED, "%s/%s/%s", Lp_Temp, cp);
8880Sstevel@tonic-gate 		for (listp = request->request->file_list; *listp; listp++)
8890Sstevel@tonic-gate 			av[ac++] = arg_string(TRUSTED, "%s", *listp);
8900Sstevel@tonic-gate 
8910Sstevel@tonic-gate 		(void)chfiles (request->request->file_list, procuid, procgid);
8920Sstevel@tonic-gate 
8930Sstevel@tonic-gate #ifdef LP_USE_PAPI_ATTR
8940Sstevel@tonic-gate 		/*
8950Sstevel@tonic-gate 		 * Check if the PAPI job attribute file exists, if it does
8960Sstevel@tonic-gate 		 * pass the file's pathname to the slow-filters in an
8970Sstevel@tonic-gate 		 * environment variable. Note: this file is created when
8980Sstevel@tonic-gate 		 * print jobs are submitted via the PAPI interface.
8990Sstevel@tonic-gate 		 */
9000Sstevel@tonic-gate 		snprintf(tmpName, sizeof (tmpName), "%s-%s",
9010Sstevel@tonic-gate 			getreqno(request->secure->req_id), LP_PAPIATTRNAME);
902*3125Sjacobs 		path = makepath(Lp_Temp, tmpName, (char *)0);
9030Sstevel@tonic-gate 		if ((path != NULL) && (stat(path, &tmpBuf) == 0))
9040Sstevel@tonic-gate 		{
9050Sstevel@tonic-gate 			/*
9060Sstevel@tonic-gate 			 * IPP job attribute file exists for this job so
9070Sstevel@tonic-gate 			 * set the environment variable
9080Sstevel@tonic-gate 			 */
9090Sstevel@tonic-gate 			addenv(&envp, "ATTRPATH", path);
9100Sstevel@tonic-gate 		}
9110Sstevel@tonic-gate 		Free(path);
9120Sstevel@tonic-gate 
9130Sstevel@tonic-gate 
9140Sstevel@tonic-gate 		/*
9150Sstevel@tonic-gate 		 * now set environment variable for the printer's PostScript
9160Sstevel@tonic-gate 		 * Printer Description (PPD) file, this is used by the filter
9170Sstevel@tonic-gate 		 * when forming the print data for this printer.
9180Sstevel@tonic-gate 		 */
9190Sstevel@tonic-gate 		if ((request->printer != NULL) &&
9200Sstevel@tonic-gate 		    (request->printer->printer != NULL) &&
9210Sstevel@tonic-gate 		    (request->printer->printer->name != NULL))
9220Sstevel@tonic-gate 		{
9230Sstevel@tonic-gate 			snprintf(tmpName, sizeof (tmpName), "%s.ppd",
9240Sstevel@tonic-gate 				request->printer->printer->name);
9250Sstevel@tonic-gate 			path = makepath(ETCDIR, "ppd", tmpName, (char *)0);
9260Sstevel@tonic-gate 			if ((path != NULL) && (stat(path, &tmpBuf) == 0))
9270Sstevel@tonic-gate 			{
9280Sstevel@tonic-gate 				addenv(&envp, "PPD", path);
9290Sstevel@tonic-gate 			}
9300Sstevel@tonic-gate 			Free(path);
9310Sstevel@tonic-gate 		}
9320Sstevel@tonic-gate #endif
9330Sstevel@tonic-gate 		break;
9340Sstevel@tonic-gate 
9350Sstevel@tonic-gate 	case EX_ALERT:
9360Sstevel@tonic-gate 		procuid = Lp_Uid;
9370Sstevel@tonic-gate 		procgid = Lp_Gid;
9380Sstevel@tonic-gate 		(void)Chown (printer->alert->msgfile, procuid, procgid);
9390Sstevel@tonic-gate 
9400Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s/%s/%s", Lp_A_Printers,
9410Sstevel@tonic-gate 				printer->printer->name, ALERTSHFILE);
9420Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s", printer->alert->msgfile);
9430Sstevel@tonic-gate 
9440Sstevel@tonic-gate 		break;
9450Sstevel@tonic-gate 
9460Sstevel@tonic-gate 	case EX_PALERT:
9470Sstevel@tonic-gate 		procuid = Lp_Uid;
9480Sstevel@tonic-gate 		procgid = Lp_Gid;
9490Sstevel@tonic-gate 		(void)Chown (pwheel->alert->msgfile, procuid, procgid);
9500Sstevel@tonic-gate 
9510Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s/%s/%s", Lp_A_PrintWheels,
9520Sstevel@tonic-gate 				pwheel->pwheel->name, ALERTSHFILE);
9530Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s", printer->alert->msgfile);
9540Sstevel@tonic-gate 
9550Sstevel@tonic-gate 		break;
9560Sstevel@tonic-gate 
9570Sstevel@tonic-gate 	case EX_FALERT:
9580Sstevel@tonic-gate 		procuid = Lp_Uid;
9590Sstevel@tonic-gate 		procgid = Lp_Gid;
9600Sstevel@tonic-gate 		(void)Chown (form->alert->msgfile, procuid, procgid);
9610Sstevel@tonic-gate 
9620Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s/%s/%s", Lp_A_Forms,
9630Sstevel@tonic-gate 				form->form->name, ALERTSHFILE);
9640Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s", printer->alert->msgfile);
9650Sstevel@tonic-gate 
9660Sstevel@tonic-gate 		break;
9670Sstevel@tonic-gate 
9680Sstevel@tonic-gate 	case EX_FORM_MESSAGE:
9690Sstevel@tonic-gate 		procuid = Lp_Uid;
9700Sstevel@tonic-gate 		procgid = Lp_Gid;
9710Sstevel@tonic-gate 
9720Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s/form", Lp_A_Faults);
9730Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s", form->form->name);
9740Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s", time_buf);
9750Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s/%s/%s", Lp_A_Forms,
9760Sstevel@tonic-gate 				form->form->name, FORMMESSAGEFILE);
9770Sstevel@tonic-gate 
9780Sstevel@tonic-gate 		break;
9790Sstevel@tonic-gate 
9800Sstevel@tonic-gate 	case EX_FAULT_MESSAGE:
9810Sstevel@tonic-gate 		procuid = Lp_Uid;
9820Sstevel@tonic-gate 		procgid = Lp_Gid;
9830Sstevel@tonic-gate 
9840Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s/printer", Lp_A_Faults);
9850Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s", printerNameToShow);
9860Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s", time_buf);
9870Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s/%s/%s", Lp_A_Printers,
9880Sstevel@tonic-gate 				printerName, FAULTMESSAGEFILE);
9890Sstevel@tonic-gate 
9900Sstevel@tonic-gate 		break;
9910Sstevel@tonic-gate 
9920Sstevel@tonic-gate 	case EX_NOTIFY:
9930Sstevel@tonic-gate 		if (request->request->alert) {
994*3125Sjacobs 			if (strchr(request->request->user, '@')) {
9950Sstevel@tonic-gate 				procuid = Lp_Uid;
9960Sstevel@tonic-gate 				procgid = Lp_Gid;
9970Sstevel@tonic-gate 			} else {
9980Sstevel@tonic-gate 				procuid = request->secure->uid;
9990Sstevel@tonic-gate 				procgid = request->secure->gid;
10000Sstevel@tonic-gate 			}
10010Sstevel@tonic-gate 			av[ac++] = arg_string(TRUSTED, "%s",
10020Sstevel@tonic-gate 					request->request->alert);
10030Sstevel@tonic-gate 		} else {
1004*3125Sjacobs 			char *user = strdup(request->request->user);
10050Sstevel@tonic-gate 			clean_string(user);
10061676Sjpk 			slabel = request->secure->slabel;
10070Sstevel@tonic-gate 
1008*3125Sjacobs 			if (request->request->actions & ACT_WRITE) {
10090Sstevel@tonic-gate 				av[ac++] = arg_string(TRUSTED, "%s", BINWRITE);
10100Sstevel@tonic-gate 				snprintf(argbuf, sizeof (argbuf),
10110Sstevel@tonic-gate 					"%s %s || %s %s",
10120Sstevel@tonic-gate 					BINWRITE, user,
10130Sstevel@tonic-gate 					BINMAIL, user
10140Sstevel@tonic-gate 				);
10150Sstevel@tonic-gate 				av[ac++] = arg_string(TRUSTED, "/bin/sh");
10160Sstevel@tonic-gate 				av[ac++] = arg_string(TRUSTED, "-c");
10170Sstevel@tonic-gate 				av[ac++] = arg_string(TRUSTED, "%s", argbuf);
10181676Sjpk 			} else if ((getzoneid() == GLOBAL_ZONEID) &&
10191676Sjpk 				   is_system_labeled() && (slabel != NULL)) {
10201676Sjpk 				/*
10211676Sjpk 				 * If in the global zone and the system is
10221676Sjpk 				 * labeled, mail is handled via a local
10231676Sjpk 				 * labeled zone that is the same label as
10241676Sjpk 				 * the request.
10251676Sjpk 				 */
10261676Sjpk 				if ((mail_zonename =
10271676Sjpk 				    get_labeled_zonename(slabel)) ==
10281676Sjpk 				    (char *)-1) {
10291676Sjpk 					/*
10301676Sjpk 					 * Cannot find labeled zone, just
10311676Sjpk 					 * return 0.
10321676Sjpk 					 */
10331676Sjpk 					return(0);
10341676Sjpk 				}
10351676Sjpk 			}
10361676Sjpk 			if (mail_zonename == NULL) {
10371676Sjpk 				procuid = Lp_Uid;
10381676Sjpk 				procgid = Lp_Gid;
10390Sstevel@tonic-gate 				av[ac++] = arg_string(TRUSTED, "%s", BINMAIL);
10400Sstevel@tonic-gate 				av[ac++] = arg_string(UNTRUSTED, "%s", user);
10411676Sjpk 			} else {
10421676Sjpk 				procuid = getuid();
10431676Sjpk 				procgid = getgid();
10441676Sjpk 				av[ac++] = arg_string(TRUSTED, "%s",
10451676Sjpk 				    "/usr/sbin/zlogin");
10461676Sjpk 				av[ac++] = arg_string(TRUSTED, "%s",
10471676Sjpk 				    mail_zonename);
10481676Sjpk 				av[ac++] = arg_string(TRUSTED, "%s",
10491676Sjpk 				    BINMAIL);
10501676Sjpk 				av[ac++] = arg_string(UNTRUSTED, "%s",
10511676Sjpk 				    user);
10521676Sjpk 				Free(mail_zonename);
10530Sstevel@tonic-gate 			}
10540Sstevel@tonic-gate 
10550Sstevel@tonic-gate 			free(user);
10560Sstevel@tonic-gate 		}
10570Sstevel@tonic-gate 		break;
10580Sstevel@tonic-gate 	}
10590Sstevel@tonic-gate 
10600Sstevel@tonic-gate 	av[ac++] = NULL;
10610Sstevel@tonic-gate 
10620Sstevel@tonic-gate 	Fork2 ();
10630Sstevel@tonic-gate 	/* only the child returns */
10640Sstevel@tonic-gate 
10650Sstevel@tonic-gate 	/*
10660Sstevel@tonic-gate 	 * Correctly set up the supplemental group list
10670Sstevel@tonic-gate 	 * for proper file access (before execl the interface program)
10680Sstevel@tonic-gate 	 */
10690Sstevel@tonic-gate 
10700Sstevel@tonic-gate 	pwp = getpwuid(procuid);
10710Sstevel@tonic-gate 	if (pwp == NULL) {
10720Sstevel@tonic-gate 		note("getpwuid(%d) call failed\n", procuid);
10730Sstevel@tonic-gate 	} else if (initgroups(pwp->pw_name, procgid) < 0) {
10740Sstevel@tonic-gate 		note("initgroups() call failed %d\n", errno);
10750Sstevel@tonic-gate 	}
10760Sstevel@tonic-gate 
10770Sstevel@tonic-gate 	setgid (procgid);
10780Sstevel@tonic-gate 	setuid (procuid);
10790Sstevel@tonic-gate 
10800Sstevel@tonic-gate 	/*
10810Sstevel@tonic-gate 	 * The shell doesn't allow the "trap" builtin to set a trap
10820Sstevel@tonic-gate 	 * for a signal ignored when the shell is started. Thus, don't
10830Sstevel@tonic-gate 	 * turn off signals in the last child!
10840Sstevel@tonic-gate 	 */
10850Sstevel@tonic-gate 
1086*3125Sjacobs #ifdef DEBUG
10870Sstevel@tonic-gate 	for (i = 0; av[i] != NULL; i++)
1088*3125Sjacobs 		note("exec(%s): av[%d] = %s", _exec_name(type), i, av[i]);
10891676Sjpk 	for (i = 0; envp[i] != NULL; i++)
1090*3125Sjacobs 		note("exec(%s): envp[%d] = %s", _exec_name(type), i, envp[i]);
1091*3125Sjacobs #endif
10920Sstevel@tonic-gate 
10930Sstevel@tonic-gate 	execvpe(av[0], av, envp);
10940Sstevel@tonic-gate 	Done (EXEC_EXIT_NEXEC, errno);
10950Sstevel@tonic-gate 	/*NOTREACHED*/
1096320Sceastha 	return (0);
10970Sstevel@tonic-gate }
10980Sstevel@tonic-gate 
10990Sstevel@tonic-gate /**
11000Sstevel@tonic-gate  ** addenv() - ADD A VARIABLE TO THE ENVIRONMENT
11010Sstevel@tonic-gate  **/
11020Sstevel@tonic-gate 
11030Sstevel@tonic-gate static void
11040Sstevel@tonic-gate addenv(char ***envp, char *name, char *value)
11050Sstevel@tonic-gate {
11060Sstevel@tonic-gate 	register char *		cp;
11070Sstevel@tonic-gate 
11080Sstevel@tonic-gate 	if ((name == NULL) || (value == NULL))
11090Sstevel@tonic-gate 		return;
11100Sstevel@tonic-gate 
11110Sstevel@tonic-gate 	if ((cp = makestr(name, "=", value, (char *)0)))
11120Sstevel@tonic-gate 		addlist(envp, cp);
11130Sstevel@tonic-gate 	return;
11140Sstevel@tonic-gate }
11150Sstevel@tonic-gate 
11160Sstevel@tonic-gate /**
11170Sstevel@tonic-gate  ** Fork1() - FORK FIRST CHILD, SET UP CONNECTION TO IT
11180Sstevel@tonic-gate  **/
11190Sstevel@tonic-gate 
11200Sstevel@tonic-gate static int
11210Sstevel@tonic-gate Fork1(EXEC *ep)
11220Sstevel@tonic-gate {
11230Sstevel@tonic-gate 	int			pid;
11240Sstevel@tonic-gate 	int			fds[2];
11250Sstevel@tonic-gate 
11260Sstevel@tonic-gate 	if (pipe(fds) == -1) {
11270Sstevel@tonic-gate 		note("Failed to create pipe for child process (%s).\n", PERROR);
11280Sstevel@tonic-gate 		errno = EAGAIN ;
11290Sstevel@tonic-gate 		return(-1);
11300Sstevel@tonic-gate 	}
11310Sstevel@tonic-gate 
11320Sstevel@tonic-gate 	ep->md = mconnect((char *)0, fds[0], fds[1]);
11330Sstevel@tonic-gate 
11340Sstevel@tonic-gate 	switch (pid = fork()) {
11350Sstevel@tonic-gate 
11360Sstevel@tonic-gate 	case -1:
11370Sstevel@tonic-gate 		mdisconnect(ep->md);
11380Sstevel@tonic-gate 		close(fds[0]);
11390Sstevel@tonic-gate 		close(fds[1]);
11400Sstevel@tonic-gate 		ep->md = 0;
11410Sstevel@tonic-gate 		return (-1);
11420Sstevel@tonic-gate 
11430Sstevel@tonic-gate 	case 0:
11440Sstevel@tonic-gate 		ChildMd = mconnect(NULL, fds[1], fds[1]);
11450Sstevel@tonic-gate 		return (0);
11460Sstevel@tonic-gate 
11470Sstevel@tonic-gate 	default:
11480Sstevel@tonic-gate 		mlistenadd(ep->md, POLLIN);
11490Sstevel@tonic-gate 		return (pid);
11500Sstevel@tonic-gate 	}
11510Sstevel@tonic-gate }
11520Sstevel@tonic-gate 
11530Sstevel@tonic-gate /**
11540Sstevel@tonic-gate  ** Fork2() - FORK SECOND CHILD AND WAIT FOR IT
11550Sstevel@tonic-gate  **/
11560Sstevel@tonic-gate 
11570Sstevel@tonic-gate static void
11580Sstevel@tonic-gate Fork2(void)
11590Sstevel@tonic-gate {
11600Sstevel@tonic-gate 	switch ((ChildPid = fork())) {
11610Sstevel@tonic-gate 
11620Sstevel@tonic-gate 	case -1:
11630Sstevel@tonic-gate 		Done (EXEC_EXIT_NFORK, errno);
11640Sstevel@tonic-gate 		/*NOTREACHED*/
11650Sstevel@tonic-gate 
11660Sstevel@tonic-gate 	case 0:
11670Sstevel@tonic-gate 		return;
11680Sstevel@tonic-gate 
11690Sstevel@tonic-gate 	default:
11700Sstevel@tonic-gate 		/*
11710Sstevel@tonic-gate 		 * Delay calling "ignore_fault_signals()" as long
11720Sstevel@tonic-gate 		 * as possible, to give the child a chance to exec
11730Sstevel@tonic-gate 		 * the interface program and turn on traps.
11740Sstevel@tonic-gate 		 */
11750Sstevel@tonic-gate 
11760Sstevel@tonic-gate 		cool_heels ();
11770Sstevel@tonic-gate 		/*NOTREACHED*/
11780Sstevel@tonic-gate 
11790Sstevel@tonic-gate 	}
11800Sstevel@tonic-gate }
11810Sstevel@tonic-gate 
11820Sstevel@tonic-gate 
11830Sstevel@tonic-gate /**
11840Sstevel@tonic-gate  ** cool_heels() - WAIT FOR CHILD TO "DIE"
11850Sstevel@tonic-gate  **/
11860Sstevel@tonic-gate 
11870Sstevel@tonic-gate static void
11880Sstevel@tonic-gate cool_heels(void)
11890Sstevel@tonic-gate {
11900Sstevel@tonic-gate 	int			status;
11910Sstevel@tonic-gate 
11920Sstevel@tonic-gate 	/*
11930Sstevel@tonic-gate 	 * At this point our only job is to wait for the child process.
11940Sstevel@tonic-gate 	 * If we hang out for a bit longer, that's okay.
11950Sstevel@tonic-gate 	 * By delaying before turning off the fault signals,
11960Sstevel@tonic-gate 	 * we increase the chance that the child process has completed
11970Sstevel@tonic-gate 	 * its exec and has turned on the fault traps. Nonetheless,
11980Sstevel@tonic-gate 	 * we can't guarantee a zero chance of missing a fault.
11990Sstevel@tonic-gate 	 * (We don't want to keep trapping the signals because the
12000Sstevel@tonic-gate 	 * interface program is likely to have a better way to handle
12010Sstevel@tonic-gate 	 * them; this process provides only rudimentary handling.)
12020Sstevel@tonic-gate 	 *
12030Sstevel@tonic-gate 	 * Note that on a very busy system, or with a very fast interface
12040Sstevel@tonic-gate 	 * program, the tables could be turned: Our sleep below (coupled
12050Sstevel@tonic-gate 	 * with a delay in the kernel scheduling us) may cause us to
12060Sstevel@tonic-gate 	 * detect the fault instead of the interface program.
12070Sstevel@tonic-gate 	 *
12080Sstevel@tonic-gate 	 * What we need is a way to synchronize with the child process.
12090Sstevel@tonic-gate 	 */
12100Sstevel@tonic-gate 	sleep (1);
12110Sstevel@tonic-gate 	ignore_fault_signals ();
12120Sstevel@tonic-gate 
12130Sstevel@tonic-gate 	WaitedChildPid = 0;
12140Sstevel@tonic-gate 	while ((WaitedChildPid = wait(&status)) != ChildPid)
12150Sstevel@tonic-gate 		;
12160Sstevel@tonic-gate 
12170Sstevel@tonic-gate 	if (
12180Sstevel@tonic-gate 		EXITED(status) > EXEC_EXIT_USER
12190Sstevel@tonic-gate 	     && EXITED(status) != EXEC_EXIT_FAULT
12200Sstevel@tonic-gate 	)
12210Sstevel@tonic-gate 		Done (EXEC_EXIT_EXIT, EXITED(status));
12220Sstevel@tonic-gate 
12230Sstevel@tonic-gate 	done (status, 0);	/* Don't use Done() */
12240Sstevel@tonic-gate 	/*NOTREACHED*/
12250Sstevel@tonic-gate }
12260Sstevel@tonic-gate 
12270Sstevel@tonic-gate 
12280Sstevel@tonic-gate /**
12290Sstevel@tonic-gate  ** trap_fault_signals() - TRAP SIGNALS THAT CAN OCCUR ON PRINTER FAULT
12300Sstevel@tonic-gate  ** ignore_fault_signals() - IGNORE SAME
12310Sstevel@tonic-gate  **/
12320Sstevel@tonic-gate 
12330Sstevel@tonic-gate static void
12340Sstevel@tonic-gate trap_fault_signals(void)
12350Sstevel@tonic-gate {
12360Sstevel@tonic-gate 	signal (SIGHUP, sigtrap);
12370Sstevel@tonic-gate 	signal (SIGINT, sigtrap);
12380Sstevel@tonic-gate 	signal (SIGQUIT, sigtrap);
12390Sstevel@tonic-gate 	signal (SIGPIPE, sigtrap);
12400Sstevel@tonic-gate 	return;
12410Sstevel@tonic-gate }
12420Sstevel@tonic-gate 
12430Sstevel@tonic-gate static void
12440Sstevel@tonic-gate ignore_fault_signals(void)
12450Sstevel@tonic-gate {
12460Sstevel@tonic-gate 	signal (SIGHUP, SIG_IGN);
12470Sstevel@tonic-gate 	signal (SIGINT, SIG_IGN);
12480Sstevel@tonic-gate 	signal (SIGQUIT, SIG_IGN);
12490Sstevel@tonic-gate 	signal (SIGPIPE, SIG_IGN);
12500Sstevel@tonic-gate 	return;
12510Sstevel@tonic-gate }
12520Sstevel@tonic-gate 
12530Sstevel@tonic-gate /**
12540Sstevel@tonic-gate  ** sigtrap() - TRAP VARIOUS SIGNALS
12550Sstevel@tonic-gate  **/
12560Sstevel@tonic-gate 
12570Sstevel@tonic-gate static void
12580Sstevel@tonic-gate sigtrap(int sig)
12590Sstevel@tonic-gate {
12600Sstevel@tonic-gate 	signal (sig, SIG_IGN);
12610Sstevel@tonic-gate 	switch (sig) {
12620Sstevel@tonic-gate 
12630Sstevel@tonic-gate 	case SIGHUP:
12640Sstevel@tonic-gate 		Done (EXEC_EXIT_HUP, 0);
12650Sstevel@tonic-gate 		/*NOTREACHED*/
12660Sstevel@tonic-gate 
12670Sstevel@tonic-gate 	case SIGQUIT:
12680Sstevel@tonic-gate 	case SIGINT:
12690Sstevel@tonic-gate 		Done (EXEC_EXIT_INTR, 0);
12700Sstevel@tonic-gate 		/*NOTREACHED*/
12710Sstevel@tonic-gate 
12720Sstevel@tonic-gate 	case SIGPIPE:
12730Sstevel@tonic-gate 		Done (EXEC_EXIT_PIPE, 0);
12740Sstevel@tonic-gate 		/*NOTREACHED*/
12750Sstevel@tonic-gate 
12760Sstevel@tonic-gate 	case SIGTERM:
12770Sstevel@tonic-gate 		/*
12780Sstevel@tonic-gate 		 * If we were killed with SIGTERM, it should have been
12790Sstevel@tonic-gate 		 * via the Spooler who should have killed the entire
12800Sstevel@tonic-gate 		 * process group. We have to wait for the children,
12810Sstevel@tonic-gate 		 * since we're their parent, but WE MAY HAVE WAITED
12820Sstevel@tonic-gate 		 * FOR THEM ALREADY (in cool_heels()).
12830Sstevel@tonic-gate 		 */
12840Sstevel@tonic-gate 		if (ChildPid != WaitedChildPid) {
12850Sstevel@tonic-gate 			register int		cpid;
12860Sstevel@tonic-gate 
12870Sstevel@tonic-gate 			while (
12880Sstevel@tonic-gate 				(cpid = wait((int *)0)) != ChildPid
12890Sstevel@tonic-gate 			     && (cpid != -1 || errno != ECHILD)
12900Sstevel@tonic-gate 			)
12910Sstevel@tonic-gate 				;
12920Sstevel@tonic-gate 		}
12930Sstevel@tonic-gate 
12940Sstevel@tonic-gate 		/*
12950Sstevel@tonic-gate 		 * We can't rely on getting SIGTERM back in the wait()
12960Sstevel@tonic-gate 		 * above, because, for instance, some shells trap SIGTERM
12970Sstevel@tonic-gate 		 * and exit instead. Thus we force it.
12980Sstevel@tonic-gate 		 */
12990Sstevel@tonic-gate 		done (SIGTERM, 0);	/* Don't use Done() */
13000Sstevel@tonic-gate 		/*NOTREACHED*/
13010Sstevel@tonic-gate 	}
13020Sstevel@tonic-gate }
13030Sstevel@tonic-gate 
13040Sstevel@tonic-gate /**
13050Sstevel@tonic-gate  ** done() - TELL SPOOLER THIS CHILD IS DONE
13060Sstevel@tonic-gate  **/
13070Sstevel@tonic-gate 
13080Sstevel@tonic-gate static void
13090Sstevel@tonic-gate done(int status, int err)
13100Sstevel@tonic-gate {
13110Sstevel@tonic-gate 	if (do_undial)
13120Sstevel@tonic-gate 		undial (1);
13130Sstevel@tonic-gate 
1314*3125Sjacobs 	mputm (ChildMd, S_CHILD_DONE, key, status, err);
13150Sstevel@tonic-gate 	mdisconnect (ChildMd);
13160Sstevel@tonic-gate 
13170Sstevel@tonic-gate 	exit (0);
13180Sstevel@tonic-gate 	/*NOTREACHED*/
13190Sstevel@tonic-gate }
13200Sstevel@tonic-gate 
13210Sstevel@tonic-gate /**
13220Sstevel@tonic-gate  ** child_mallocfail()
13230Sstevel@tonic-gate  **/
13240Sstevel@tonic-gate 
13250Sstevel@tonic-gate static void
13260Sstevel@tonic-gate child_mallocfail(void)
13270Sstevel@tonic-gate {
13280Sstevel@tonic-gate 	Done (EXEC_EXIT_NOMEM, ENOMEM);
13290Sstevel@tonic-gate }
1330