xref: /onnv-gate/usr/src/cmd/lp/cmd/lpsched/exec.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
23*0Sstevel@tonic-gate /*	  All Rights Reserved  	*/
24*0Sstevel@tonic-gate 
25*0Sstevel@tonic-gate 
26*0Sstevel@tonic-gate /*
27*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
28*0Sstevel@tonic-gate  * Use is subject to license terms.
29*0Sstevel@tonic-gate  */
30*0Sstevel@tonic-gate 
31*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
32*0Sstevel@tonic-gate 
33*0Sstevel@tonic-gate #include <dial.h>
34*0Sstevel@tonic-gate 
35*0Sstevel@tonic-gate #include <stdlib.h>
36*0Sstevel@tonic-gate #include "limits.h"
37*0Sstevel@tonic-gate #include "stdarg.h"
38*0Sstevel@tonic-gate #include "wait.h"
39*0Sstevel@tonic-gate #include "dial.h"
40*0Sstevel@tonic-gate #include "lpsched.h"
41*0Sstevel@tonic-gate #include <syslog.h>
42*0Sstevel@tonic-gate #include <pwd.h>
43*0Sstevel@tonic-gate 
44*0Sstevel@tonic-gate #define Done(EC,ERRNO)	done(((EC) << 8),ERRNO)
45*0Sstevel@tonic-gate 
46*0Sstevel@tonic-gate #define	STRLCAT(dst, src, size) \
47*0Sstevel@tonic-gate 	if (strlcat((dst), (src), (size)) >= (size)) { \
48*0Sstevel@tonic-gate 		errno = EINVAL; \
49*0Sstevel@tonic-gate 		return (-1); \
50*0Sstevel@tonic-gate 	}
51*0Sstevel@tonic-gate 
52*0Sstevel@tonic-gate static MESG *		ChildMd;
53*0Sstevel@tonic-gate 
54*0Sstevel@tonic-gate static int		ChildPid;
55*0Sstevel@tonic-gate static int		WaitedChildPid;
56*0Sstevel@tonic-gate static int		slot;
57*0Sstevel@tonic-gate static int		do_undial;
58*0Sstevel@tonic-gate 
59*0Sstevel@tonic-gate static char		argbuf[ARG_MAX];
60*0Sstevel@tonic-gate 
61*0Sstevel@tonic-gate static long		key;
62*0Sstevel@tonic-gate 
63*0Sstevel@tonic-gate static void		sigtrap ( int );
64*0Sstevel@tonic-gate static void		done ( int , int );
65*0Sstevel@tonic-gate static void		cool_heels ( void );
66*0Sstevel@tonic-gate static void		addenv (char ***envp, char * , char * );
67*0Sstevel@tonic-gate static void		trap_fault_signals ( void );
68*0Sstevel@tonic-gate static void		ignore_fault_signals ( void );
69*0Sstevel@tonic-gate static void		child_mallocfail ( void );
70*0Sstevel@tonic-gate static void		Fork2 ( void );
71*0Sstevel@tonic-gate 
72*0Sstevel@tonic-gate static int		Fork1 ( EXEC * );
73*0Sstevel@tonic-gate 
74*0Sstevel@tonic-gate static void
75*0Sstevel@tonic-gate relock(void)
76*0Sstevel@tonic-gate {
77*0Sstevel@tonic-gate 	struct flock		l;
78*0Sstevel@tonic-gate 
79*0Sstevel@tonic-gate 	l.l_type = F_WRLCK;
80*0Sstevel@tonic-gate 	l.l_whence = 1;
81*0Sstevel@tonic-gate 	l.l_start = 0;
82*0Sstevel@tonic-gate 	l.l_len = 0;
83*0Sstevel@tonic-gate 	(void)Fcntl (lock_fd, F_SETLK, &l);
84*0Sstevel@tonic-gate 	return;
85*0Sstevel@tonic-gate }
86*0Sstevel@tonic-gate 
87*0Sstevel@tonic-gate static char *_exec_name(int type)
88*0Sstevel@tonic-gate {
89*0Sstevel@tonic-gate 	static char *_names[] = {
90*0Sstevel@tonic-gate 	"", "EX_INTERF", "EX_SLOWF", "EX_ALERT", "EX_FALERT", "EX_PALERT",
91*0Sstevel@tonic-gate 	"EX_NOTIFY", "EX_FAULT_MESSAGE", "EX_FORM_MESSAGE", NULL };
92*0Sstevel@tonic-gate 
93*0Sstevel@tonic-gate 	if ((type < 0) || (type > EX_FORM_MESSAGE))
94*0Sstevel@tonic-gate 		return ("BAD_EXEC_TYPE");
95*0Sstevel@tonic-gate 	else
96*0Sstevel@tonic-gate 		return (_names[type]);
97*0Sstevel@tonic-gate }
98*0Sstevel@tonic-gate 
99*0Sstevel@tonic-gate /*
100*0Sstevel@tonic-gate  * This function replaces characters in a string that might be used
101*0Sstevel@tonic-gate  * to exploit a security hole.  Replace command seperators (`, &, ;, |, ^),
102*0Sstevel@tonic-gate  * output redirection (>, |), variable expansion ($), and character
103*0Sstevel@tonic-gate  * escape (\).
104*0Sstevel@tonic-gate  *
105*0Sstevel@tonic-gate  * Bugid 4141687
106*0Sstevel@tonic-gate  * Add ( ) < * ? [
107*0Sstevel@tonic-gate  * Bugid 4139071
108*0Sstevel@tonic-gate  * Remove \
109*0Sstevel@tonic-gate  */
110*0Sstevel@tonic-gate void clean_string(char *ptr)
111*0Sstevel@tonic-gate {
112*0Sstevel@tonic-gate 	char *cp;
113*0Sstevel@tonic-gate 	wchar_t wc;
114*0Sstevel@tonic-gate 	size_t len;
115*0Sstevel@tonic-gate 
116*0Sstevel@tonic-gate 	for (cp = ptr; *cp != NULL; ) {
117*0Sstevel@tonic-gate 		if ((len = mbtowc(&wc, cp, MB_CUR_MAX)) == -1) {
118*0Sstevel@tonic-gate 			cp++;
119*0Sstevel@tonic-gate 			continue;
120*0Sstevel@tonic-gate 		}
121*0Sstevel@tonic-gate 
122*0Sstevel@tonic-gate 		if (len == 1 &&
123*0Sstevel@tonic-gate 		    ((wc == L'`') || (wc == L'&') || (wc == L';') ||
124*0Sstevel@tonic-gate 		    (wc == L'|') || (wc == L'>') || (wc == L'^') ||
125*0Sstevel@tonic-gate 		    (wc == L'$') || (wc == L'(') || (wc == L')') ||
126*0Sstevel@tonic-gate 		    (wc == L'<') || (wc == L'*') || (wc == L'?') ||
127*0Sstevel@tonic-gate 		    (wc == L'[')))
128*0Sstevel@tonic-gate 			*cp = '_';
129*0Sstevel@tonic-gate 		cp += len;
130*0Sstevel@tonic-gate 	}
131*0Sstevel@tonic-gate }
132*0Sstevel@tonic-gate 
133*0Sstevel@tonic-gate enum trust {TRUSTED, UNTRUSTED};
134*0Sstevel@tonic-gate static char *
135*0Sstevel@tonic-gate arg_string(enum trust type, char *fmt, ...)
136*0Sstevel@tonic-gate {
137*0Sstevel@tonic-gate 	char buf[BUFSIZ];
138*0Sstevel@tonic-gate 	va_list	args;
139*0Sstevel@tonic-gate 
140*0Sstevel@tonic-gate 	va_start(args, fmt);
141*0Sstevel@tonic-gate 	(void) vsnprintf(buf, sizeof(buf), fmt, args);
142*0Sstevel@tonic-gate 	va_end(args);
143*0Sstevel@tonic-gate 
144*0Sstevel@tonic-gate 	/*
145*0Sstevel@tonic-gate 	 * If the string contains data from an untrusted origin (user supplied),
146*0Sstevel@tonic-gate 	 * clean it up in case one of our progeny is a shell script and isn't
147*0Sstevel@tonic-gate 	 * careful about checking its input.
148*0Sstevel@tonic-gate 	 */
149*0Sstevel@tonic-gate 	if (type == UNTRUSTED)
150*0Sstevel@tonic-gate 		clean_string(buf);
151*0Sstevel@tonic-gate 
152*0Sstevel@tonic-gate 	return (strdup(buf));
153*0Sstevel@tonic-gate }
154*0Sstevel@tonic-gate 
155*0Sstevel@tonic-gate /* stolen from libc/gen/port/gen/execvp.c */
156*0Sstevel@tonic-gate static const char *
157*0Sstevel@tonic-gate execat(const char *s1, const char *s2, char *si)
158*0Sstevel@tonic-gate {
159*0Sstevel@tonic-gate         char    *s;
160*0Sstevel@tonic-gate         int cnt = PATH_MAX + 1; /* number of characters in s2 */
161*0Sstevel@tonic-gate 
162*0Sstevel@tonic-gate         s = si;
163*0Sstevel@tonic-gate         while (*s1 && *s1 != ':') {
164*0Sstevel@tonic-gate                 if (cnt > 0) {
165*0Sstevel@tonic-gate                         *s++ = *s1++;
166*0Sstevel@tonic-gate                         cnt--;
167*0Sstevel@tonic-gate                 } else
168*0Sstevel@tonic-gate                         s1++;
169*0Sstevel@tonic-gate         }
170*0Sstevel@tonic-gate         if (si != s && cnt > 0) {
171*0Sstevel@tonic-gate                 *s++ = '/';
172*0Sstevel@tonic-gate                 cnt--;
173*0Sstevel@tonic-gate         }
174*0Sstevel@tonic-gate         while (*s2 && cnt > 0) {
175*0Sstevel@tonic-gate                 *s++ = *s2++;
176*0Sstevel@tonic-gate                 cnt--;
177*0Sstevel@tonic-gate         }
178*0Sstevel@tonic-gate         *s = '\0';
179*0Sstevel@tonic-gate         return (*s1 ? ++s1: 0);
180*0Sstevel@tonic-gate }
181*0Sstevel@tonic-gate 
182*0Sstevel@tonic-gate /*
183*0Sstevel@tonic-gate  * Similiar to execvp(), execpt you can supply an environment and we always
184*0Sstevel@tonic-gate  * use /bin/sh for shell scripts.  The PATH searched is the PATH in the
185*0Sstevel@tonic-gate  * current environment, not the environment in the argument list.
186*0Sstevel@tonic-gate  * This was pretty much stolen from libc/gen/port/execvp.c
187*0Sstevel@tonic-gate  */
188*0Sstevel@tonic-gate static int
189*0Sstevel@tonic-gate execvpe(char *name, char *const argv[], char *const envp[])
190*0Sstevel@tonic-gate {
191*0Sstevel@tonic-gate 	char *path;
192*0Sstevel@tonic-gate 	char fname[PATH_MAX+2];
193*0Sstevel@tonic-gate 	char *newargs[256];
194*0Sstevel@tonic-gate 	int i;
195*0Sstevel@tonic-gate 	const char *cp;
196*0Sstevel@tonic-gate 	unsigned etxtbsy = 1;
197*0Sstevel@tonic-gate         int eacces = 0;
198*0Sstevel@tonic-gate 
199*0Sstevel@tonic-gate 	if (*name == '\0') {
200*0Sstevel@tonic-gate 		errno = ENOENT;
201*0Sstevel@tonic-gate 		return (-1);
202*0Sstevel@tonic-gate 	}
203*0Sstevel@tonic-gate 
204*0Sstevel@tonic-gate 	if ((path = getenv("PATH")) == NULL)
205*0Sstevel@tonic-gate 		path = "/usr/bin:/bin";
206*0Sstevel@tonic-gate 
207*0Sstevel@tonic-gate         cp = strchr(name, '/')? (const char *)"": path;
208*0Sstevel@tonic-gate 
209*0Sstevel@tonic-gate         do {
210*0Sstevel@tonic-gate                 cp = execat(cp, name, fname);
211*0Sstevel@tonic-gate         retry:
212*0Sstevel@tonic-gate                 /*
213*0Sstevel@tonic-gate                  * 4025035 and 4038378
214*0Sstevel@tonic-gate                  * if a filename begins with a "-" prepend "./" so that
215*0Sstevel@tonic-gate                  * the shell can't interpret it as an option
216*0Sstevel@tonic-gate                  */
217*0Sstevel@tonic-gate                 if (*fname == '-') {
218*0Sstevel@tonic-gate                         size_t size = strlen(fname) + 1;
219*0Sstevel@tonic-gate                         if ((size + 2) > sizeof (fname)) {
220*0Sstevel@tonic-gate                                 errno = E2BIG;
221*0Sstevel@tonic-gate                                 return (-1);
222*0Sstevel@tonic-gate                         }
223*0Sstevel@tonic-gate                         (void) memmove(fname + 2, fname, size);
224*0Sstevel@tonic-gate                         fname[0] = '.';
225*0Sstevel@tonic-gate                         fname[1] = '/';
226*0Sstevel@tonic-gate                 }
227*0Sstevel@tonic-gate                 (void) execve(fname, argv, envp);
228*0Sstevel@tonic-gate                 switch (errno) {
229*0Sstevel@tonic-gate                 case ENOEXEC:
230*0Sstevel@tonic-gate                         newargs[0] = "sh";
231*0Sstevel@tonic-gate                         newargs[1] = fname;
232*0Sstevel@tonic-gate                         for (i = 1; (newargs[i + 1] = argv[i]) != NULL; ++i) {
233*0Sstevel@tonic-gate                                 if (i >= 254) {
234*0Sstevel@tonic-gate                                         errno = E2BIG;
235*0Sstevel@tonic-gate                                         return (-1);
236*0Sstevel@tonic-gate                                 }
237*0Sstevel@tonic-gate                         }
238*0Sstevel@tonic-gate                         (void) execve("/bin/sh", newargs, envp);
239*0Sstevel@tonic-gate                         return (-1);
240*0Sstevel@tonic-gate                 case ETXTBSY:
241*0Sstevel@tonic-gate                         if (++etxtbsy > 5)
242*0Sstevel@tonic-gate                                 return (-1);
243*0Sstevel@tonic-gate                         (void) sleep(etxtbsy);
244*0Sstevel@tonic-gate                         goto retry;
245*0Sstevel@tonic-gate                 case EACCES:
246*0Sstevel@tonic-gate                         ++eacces;
247*0Sstevel@tonic-gate                         break;
248*0Sstevel@tonic-gate                 case ENOMEM:
249*0Sstevel@tonic-gate                 case E2BIG:
250*0Sstevel@tonic-gate                 case EFAULT:
251*0Sstevel@tonic-gate                         return (-1);
252*0Sstevel@tonic-gate                 }
253*0Sstevel@tonic-gate         } while (cp);
254*0Sstevel@tonic-gate         if (eacces)
255*0Sstevel@tonic-gate                 errno = EACCES;
256*0Sstevel@tonic-gate         return (-1);
257*0Sstevel@tonic-gate }
258*0Sstevel@tonic-gate 
259*0Sstevel@tonic-gate static char time_buf[50];
260*0Sstevel@tonic-gate /**
261*0Sstevel@tonic-gate  ** exec() - FORK AND EXEC CHILD PROCESS
262*0Sstevel@tonic-gate  **/
263*0Sstevel@tonic-gate 
264*0Sstevel@tonic-gate /*VARARGS1*/
265*0Sstevel@tonic-gate int
266*0Sstevel@tonic-gate exec(int type, ...)
267*0Sstevel@tonic-gate {
268*0Sstevel@tonic-gate 	va_list			args;
269*0Sstevel@tonic-gate 
270*0Sstevel@tonic-gate 	int			i;
271*0Sstevel@tonic-gate 	int			procuid;
272*0Sstevel@tonic-gate 	int			procgid;
273*0Sstevel@tonic-gate 	int			ret;
274*0Sstevel@tonic-gate 	int			fr_flg;
275*0Sstevel@tonic-gate 
276*0Sstevel@tonic-gate 	char			*cp;
277*0Sstevel@tonic-gate 	char			*infile;
278*0Sstevel@tonic-gate 	char			*outfile;
279*0Sstevel@tonic-gate 	char			*errfile;
280*0Sstevel@tonic-gate 	char			*sep;
281*0Sstevel@tonic-gate 
282*0Sstevel@tonic-gate 	char			**listp;
283*0Sstevel@tonic-gate 	char			**file_list;
284*0Sstevel@tonic-gate 	char			*printerName;
285*0Sstevel@tonic-gate 	char			*printerNameToShow;
286*0Sstevel@tonic-gate 	static char		nameBuf[100];
287*0Sstevel@tonic-gate 	char			*clean_title;
288*0Sstevel@tonic-gate 
289*0Sstevel@tonic-gate 	PSTATUS			*printer;
290*0Sstevel@tonic-gate 
291*0Sstevel@tonic-gate 	RSTATUS			*request;
292*0Sstevel@tonic-gate 
293*0Sstevel@tonic-gate 	FSTATUS			*form;
294*0Sstevel@tonic-gate 
295*0Sstevel@tonic-gate 	EXEC			*ep;
296*0Sstevel@tonic-gate 
297*0Sstevel@tonic-gate 	PWSTATUS		*pwheel;
298*0Sstevel@tonic-gate 	time_t			now;
299*0Sstevel@tonic-gate 	struct passwd		*pwp;
300*0Sstevel@tonic-gate #ifdef LP_USE_PAPI_ATTR
301*0Sstevel@tonic-gate 	struct stat		tmpBuf;
302*0Sstevel@tonic-gate 	char 			tmpName[BUFSIZ];
303*0Sstevel@tonic-gate 	char			*path = NULL;
304*0Sstevel@tonic-gate #endif
305*0Sstevel@tonic-gate 	char *av[ARG_MAX];
306*0Sstevel@tonic-gate 	char **envp = NULL;
307*0Sstevel@tonic-gate 	int ac = 0;
308*0Sstevel@tonic-gate 
309*0Sstevel@tonic-gate 	syslog(LOG_DEBUG, "exec(%s)", _exec_name(type));
310*0Sstevel@tonic-gate 
311*0Sstevel@tonic-gate 	memset(av, 0, sizeof (*av));
312*0Sstevel@tonic-gate 
313*0Sstevel@tonic-gate 	va_start (args, type);
314*0Sstevel@tonic-gate 
315*0Sstevel@tonic-gate 	switch (type) {
316*0Sstevel@tonic-gate 
317*0Sstevel@tonic-gate 	case EX_INTERF:
318*0Sstevel@tonic-gate 		printer = va_arg(args, PSTATUS *);
319*0Sstevel@tonic-gate 		if (printer->status & PS_REMOTE) {
320*0Sstevel@tonic-gate 			errno = EINVAL;
321*0Sstevel@tonic-gate 			return (-1);
322*0Sstevel@tonic-gate 		}
323*0Sstevel@tonic-gate 		request = printer->request;
324*0Sstevel@tonic-gate 		ep = printer->exec;
325*0Sstevel@tonic-gate 		break;
326*0Sstevel@tonic-gate 
327*0Sstevel@tonic-gate 	case EX_FAULT_MESSAGE:
328*0Sstevel@tonic-gate 		printer = va_arg(args, PSTATUS *);
329*0Sstevel@tonic-gate 		request = va_arg(args, RSTATUS *);
330*0Sstevel@tonic-gate 		if (! ( printer->status & (PS_FORM_FAULT | PS_SHOW_FAULT))) {
331*0Sstevel@tonic-gate 			return(0);
332*0Sstevel@tonic-gate 		}
333*0Sstevel@tonic-gate 		ep = printer->fault_exec;
334*0Sstevel@tonic-gate 		printerName = (printer->printer && printer->printer->name
335*0Sstevel@tonic-gate 				  ? printer->printer->name : "??");
336*0Sstevel@tonic-gate 			snprintf(nameBuf, sizeof (nameBuf),
337*0Sstevel@tonic-gate 				"%s (on %s)\n", printerName, Local_System);
338*0Sstevel@tonic-gate 
339*0Sstevel@tonic-gate 		printerNameToShow = nameBuf;
340*0Sstevel@tonic-gate 
341*0Sstevel@tonic-gate 		(void) time(&now);
342*0Sstevel@tonic-gate 		(void) strftime(time_buf, sizeof (time_buf),
343*0Sstevel@tonic-gate 			NULL, localtime(&now));
344*0Sstevel@tonic-gate 		break;
345*0Sstevel@tonic-gate 
346*0Sstevel@tonic-gate 	case EX_SLOWF:
347*0Sstevel@tonic-gate 		request = va_arg(args, RSTATUS *);
348*0Sstevel@tonic-gate 		ep = request->exec;
349*0Sstevel@tonic-gate 		break;
350*0Sstevel@tonic-gate 
351*0Sstevel@tonic-gate 	case EX_NOTIFY:
352*0Sstevel@tonic-gate 		request = va_arg(args, RSTATUS *);
353*0Sstevel@tonic-gate 		if (request->request->actions & ACT_NOTIFY) {
354*0Sstevel@tonic-gate 			errno = EINVAL;
355*0Sstevel@tonic-gate 			return (-1);
356*0Sstevel@tonic-gate 		}
357*0Sstevel@tonic-gate 		ep = request->exec;
358*0Sstevel@tonic-gate 		break;
359*0Sstevel@tonic-gate 
360*0Sstevel@tonic-gate 	case EX_ALERT:
361*0Sstevel@tonic-gate 		printer = va_arg(args, PSTATUS *);
362*0Sstevel@tonic-gate 		if (!(printer->printer->fault_alert.shcmd)) {
363*0Sstevel@tonic-gate 			errno = EINVAL;
364*0Sstevel@tonic-gate 			return(-1);
365*0Sstevel@tonic-gate 		}
366*0Sstevel@tonic-gate 		ep = printer->alert->exec;
367*0Sstevel@tonic-gate 		break;
368*0Sstevel@tonic-gate 
369*0Sstevel@tonic-gate 	case EX_PALERT:
370*0Sstevel@tonic-gate 		pwheel = va_arg(args, PWSTATUS *);
371*0Sstevel@tonic-gate 		ep = pwheel->alert->exec;
372*0Sstevel@tonic-gate 		break;
373*0Sstevel@tonic-gate 
374*0Sstevel@tonic-gate 	case EX_FORM_MESSAGE:
375*0Sstevel@tonic-gate 		(void) time(&now);
376*0Sstevel@tonic-gate 		(void) strftime(time_buf, sizeof (time_buf),
377*0Sstevel@tonic-gate 			NULL, localtime(&now));
378*0Sstevel@tonic-gate 
379*0Sstevel@tonic-gate 		/*FALLTHRU*/
380*0Sstevel@tonic-gate 	case EX_FALERT:
381*0Sstevel@tonic-gate 		form = va_arg(args, FSTATUS *);
382*0Sstevel@tonic-gate 		ep = form->alert->exec;
383*0Sstevel@tonic-gate 		break;
384*0Sstevel@tonic-gate 
385*0Sstevel@tonic-gate 	default:
386*0Sstevel@tonic-gate 		errno = EINVAL;
387*0Sstevel@tonic-gate 		return(-1);
388*0Sstevel@tonic-gate 
389*0Sstevel@tonic-gate 	}
390*0Sstevel@tonic-gate 	va_end (args);
391*0Sstevel@tonic-gate 
392*0Sstevel@tonic-gate 	if (!ep || (ep->pid > 0)) {
393*0Sstevel@tonic-gate 		errno = EBUSY;
394*0Sstevel@tonic-gate 		return(-1);
395*0Sstevel@tonic-gate 	}
396*0Sstevel@tonic-gate 
397*0Sstevel@tonic-gate 	ep->flags = 0;
398*0Sstevel@tonic-gate 
399*0Sstevel@tonic-gate 	key = ep->key = getkey();
400*0Sstevel@tonic-gate 	slot = ep - Exec_Table;
401*0Sstevel@tonic-gate 
402*0Sstevel@tonic-gate 	switch ((ep->pid = Fork1(ep))) {
403*0Sstevel@tonic-gate 
404*0Sstevel@tonic-gate 	case -1:
405*0Sstevel@tonic-gate 		relock ();
406*0Sstevel@tonic-gate 		return(-1);
407*0Sstevel@tonic-gate 
408*0Sstevel@tonic-gate 	case 0:
409*0Sstevel@tonic-gate 		/*
410*0Sstevel@tonic-gate 		 * We want to be able to tell our parent how we died.
411*0Sstevel@tonic-gate 		 */
412*0Sstevel@tonic-gate 		lp_alloc_fail_handler = child_mallocfail;
413*0Sstevel@tonic-gate 		break;
414*0Sstevel@tonic-gate 
415*0Sstevel@tonic-gate 	default:
416*0Sstevel@tonic-gate 		switch(type) {
417*0Sstevel@tonic-gate 
418*0Sstevel@tonic-gate 		case EX_INTERF:
419*0Sstevel@tonic-gate 			request->request->outcome |= RS_PRINTING;
420*0Sstevel@tonic-gate 			break;
421*0Sstevel@tonic-gate 
422*0Sstevel@tonic-gate 		case EX_NOTIFY:
423*0Sstevel@tonic-gate 			request->request->outcome |= RS_NOTIFYING;
424*0Sstevel@tonic-gate 			break;
425*0Sstevel@tonic-gate 
426*0Sstevel@tonic-gate 		case EX_SLOWF:
427*0Sstevel@tonic-gate 			request->request->outcome |= RS_FILTERING;
428*0Sstevel@tonic-gate 			request->request->outcome &= ~RS_REFILTER;
429*0Sstevel@tonic-gate 			break;
430*0Sstevel@tonic-gate 
431*0Sstevel@tonic-gate 		}
432*0Sstevel@tonic-gate 		return(0);
433*0Sstevel@tonic-gate 
434*0Sstevel@tonic-gate 	}
435*0Sstevel@tonic-gate 
436*0Sstevel@tonic-gate 	for (i = 0; i < NSIG; i++)
437*0Sstevel@tonic-gate 		(void)signal (i, SIG_DFL);
438*0Sstevel@tonic-gate 	(void)signal (SIGALRM, SIG_IGN);
439*0Sstevel@tonic-gate 	(void)signal (SIGTERM, sigtrap);
440*0Sstevel@tonic-gate 
441*0Sstevel@tonic-gate 	for (i = 0; i < OpenMax; i++)
442*0Sstevel@tonic-gate 		if (i != ChildMd->writefd)
443*0Sstevel@tonic-gate 			Close (i);
444*0Sstevel@tonic-gate 
445*0Sstevel@tonic-gate 	setpgrp();
446*0Sstevel@tonic-gate 
447*0Sstevel@tonic-gate 	/* Set a default path */
448*0Sstevel@tonic-gate 	addenv (&envp, "PATH", "/usr/lib/lp/bin:/usr/bin:/bin:/usr/sbin:/sbin");
449*0Sstevel@tonic-gate 	/* copy locale related variables */
450*0Sstevel@tonic-gate 	addenv (&envp, "TZ", getenv("TZ"));
451*0Sstevel@tonic-gate 	addenv (&envp, "LANG", getenv("LANG"));
452*0Sstevel@tonic-gate 	addenv (&envp, "LC_ALL", getenv("LC_ALL"));
453*0Sstevel@tonic-gate 	addenv (&envp, "LC_COLLATE", getenv("LC_COLLATE"));
454*0Sstevel@tonic-gate 	addenv (&envp, "LC_CTYPE", getenv("LC_CTYPE"));
455*0Sstevel@tonic-gate 	addenv (&envp, "LC_MESSAGES", getenv("LC_MESSAGES"));
456*0Sstevel@tonic-gate 	addenv (&envp, "LC_MONETARY", getenv("LC_MONETARY"));
457*0Sstevel@tonic-gate 	addenv (&envp, "LC_NUMERIC", getenv("LC_NUMERIC"));
458*0Sstevel@tonic-gate 	addenv (&envp, "LC_TIME", getenv("LC_TIME"));
459*0Sstevel@tonic-gate 
460*0Sstevel@tonic-gate 	sprintf ((cp = BIGGEST_NUMBER_S), "%ld", key);
461*0Sstevel@tonic-gate 	addenv (&envp, "SPOOLER_KEY", cp);
462*0Sstevel@tonic-gate 
463*0Sstevel@tonic-gate #if	defined(DEBUG)
464*0Sstevel@tonic-gate 	addenv (&envp, "LPDEBUG", (debug? "1" : "0"));
465*0Sstevel@tonic-gate #endif
466*0Sstevel@tonic-gate 
467*0Sstevel@tonic-gate 	/*
468*0Sstevel@tonic-gate 	 * Open the standard input, standard output, and standard error.
469*0Sstevel@tonic-gate 	 */
470*0Sstevel@tonic-gate 	switch (type) {
471*0Sstevel@tonic-gate 
472*0Sstevel@tonic-gate 	case EX_SLOWF:
473*0Sstevel@tonic-gate 	case EX_INTERF:
474*0Sstevel@tonic-gate 		/*
475*0Sstevel@tonic-gate 		 * stdin:  /dev/null
476*0Sstevel@tonic-gate 		 * stdout: /dev/null (EX_SLOWF), printer port (EX_INTERF)
477*0Sstevel@tonic-gate 		 * stderr: req#
478*0Sstevel@tonic-gate 		 */
479*0Sstevel@tonic-gate 		infile = 0;
480*0Sstevel@tonic-gate 		outfile = 0;
481*0Sstevel@tonic-gate 		errfile = makereqerr(request);
482*0Sstevel@tonic-gate 		break;
483*0Sstevel@tonic-gate 
484*0Sstevel@tonic-gate 	case EX_NOTIFY:
485*0Sstevel@tonic-gate 		/*
486*0Sstevel@tonic-gate 		 * stdin:  req#
487*0Sstevel@tonic-gate 		 * stdout: /dev/null
488*0Sstevel@tonic-gate 		 * stderr: /dev/null
489*0Sstevel@tonic-gate 		 */
490*0Sstevel@tonic-gate 		infile = makereqerr(request);
491*0Sstevel@tonic-gate 		outfile = 0;
492*0Sstevel@tonic-gate 		errfile = 0;
493*0Sstevel@tonic-gate 
494*0Sstevel@tonic-gate 		break;
495*0Sstevel@tonic-gate 
496*0Sstevel@tonic-gate 	case EX_ALERT:
497*0Sstevel@tonic-gate 	case EX_FALERT:
498*0Sstevel@tonic-gate 	case EX_PALERT:
499*0Sstevel@tonic-gate 	case EX_FAULT_MESSAGE:
500*0Sstevel@tonic-gate 	case EX_FORM_MESSAGE:
501*0Sstevel@tonic-gate 		/*
502*0Sstevel@tonic-gate 		 * stdin:  /dev/null
503*0Sstevel@tonic-gate 		 * stdout: /dev/null
504*0Sstevel@tonic-gate 		 * stderr: /dev/null
505*0Sstevel@tonic-gate 		 */
506*0Sstevel@tonic-gate 		infile = 0;
507*0Sstevel@tonic-gate 		outfile = 0;
508*0Sstevel@tonic-gate 		errfile = 0;
509*0Sstevel@tonic-gate 		break;
510*0Sstevel@tonic-gate 
511*0Sstevel@tonic-gate 	}
512*0Sstevel@tonic-gate 
513*0Sstevel@tonic-gate 	if (infile) {
514*0Sstevel@tonic-gate 		if (Open(infile, O_RDONLY) == -1)
515*0Sstevel@tonic-gate 			Done (EXEC_EXIT_NOPEN, errno);
516*0Sstevel@tonic-gate 	} else {
517*0Sstevel@tonic-gate 		if (Open("/dev/null", O_RDONLY) == -1)
518*0Sstevel@tonic-gate 			Done (EXEC_EXIT_NOPEN, errno);
519*0Sstevel@tonic-gate 	}
520*0Sstevel@tonic-gate 
521*0Sstevel@tonic-gate 	if (outfile) {
522*0Sstevel@tonic-gate 		if (Open(outfile, O_CREAT|O_TRUNC|O_WRONLY, 0600) == -1)
523*0Sstevel@tonic-gate 			Done (EXEC_EXIT_NOPEN, errno);
524*0Sstevel@tonic-gate 	} else {
525*0Sstevel@tonic-gate 		/*
526*0Sstevel@tonic-gate 		 * If EX_INTERF, this is still needed to cause the
527*0Sstevel@tonic-gate 		 * standard error channel to be #2.
528*0Sstevel@tonic-gate 		 */
529*0Sstevel@tonic-gate 		if (Open("/dev/null", O_WRONLY) == -1)
530*0Sstevel@tonic-gate 			Done (EXEC_EXIT_NOPEN, errno);
531*0Sstevel@tonic-gate 	}
532*0Sstevel@tonic-gate 
533*0Sstevel@tonic-gate 	if (errfile) {
534*0Sstevel@tonic-gate 		if (Open(errfile, O_CREAT|O_TRUNC|O_WRONLY, 0600) == -1)
535*0Sstevel@tonic-gate 			Done (EXEC_EXIT_NOPEN, errno);
536*0Sstevel@tonic-gate 	} else {
537*0Sstevel@tonic-gate 		if (Open("/dev/null", O_WRONLY) == -1)
538*0Sstevel@tonic-gate 			Done (EXEC_EXIT_NOPEN, errno);
539*0Sstevel@tonic-gate 	}
540*0Sstevel@tonic-gate 
541*0Sstevel@tonic-gate 	switch (type) {
542*0Sstevel@tonic-gate 
543*0Sstevel@tonic-gate 	case EX_INTERF:
544*0Sstevel@tonic-gate 		/*
545*0Sstevel@tonic-gate 		 * Opening a ``port'' can be dangerous to our health:
546*0Sstevel@tonic-gate 		 *
547*0Sstevel@tonic-gate 		 *	- Hangups can occur if the line is dropped.
548*0Sstevel@tonic-gate 		 *	- The printer may send an interrupt.
549*0Sstevel@tonic-gate 		 *	- A FIFO may be closed, generating SIGPIPE.
550*0Sstevel@tonic-gate 		 *
551*0Sstevel@tonic-gate 		 * We catch these so we can complain nicely.
552*0Sstevel@tonic-gate 		 */
553*0Sstevel@tonic-gate 		trap_fault_signals ();
554*0Sstevel@tonic-gate 
555*0Sstevel@tonic-gate 		(void)Close (1);
556*0Sstevel@tonic-gate 
557*0Sstevel@tonic-gate 		if (strchr (request->secure->user, '!'))
558*0Sstevel@tonic-gate 		{
559*0Sstevel@tonic-gate 			procuid = Lp_Uid;
560*0Sstevel@tonic-gate 			procgid = Lp_Gid;
561*0Sstevel@tonic-gate 		}
562*0Sstevel@tonic-gate 		else
563*0Sstevel@tonic-gate 		{
564*0Sstevel@tonic-gate 			procuid = request->secure->uid;
565*0Sstevel@tonic-gate 			procgid = request->secure->gid;
566*0Sstevel@tonic-gate 		}
567*0Sstevel@tonic-gate 		if (printer->printer->dial_info)
568*0Sstevel@tonic-gate 		{
569*0Sstevel@tonic-gate 			ret = open_dialup(request->printer_type,
570*0Sstevel@tonic-gate 				printer->printer);
571*0Sstevel@tonic-gate 			if (ret == 0)
572*0Sstevel@tonic-gate 				do_undial = 1;
573*0Sstevel@tonic-gate 		}
574*0Sstevel@tonic-gate 		else
575*0Sstevel@tonic-gate 		{
576*0Sstevel@tonic-gate 			ret = open_direct(request->printer_type,
577*0Sstevel@tonic-gate 				printer->printer);
578*0Sstevel@tonic-gate 			do_undial = 0;
579*0Sstevel@tonic-gate 			/* this is a URI */
580*0Sstevel@tonic-gate 			if (is_printer_uri(printer->printer->device) == 0)
581*0Sstevel@tonic-gate 				addenv(&envp, "DEVICE_URI",
582*0Sstevel@tonic-gate 					 printer->printer->device);
583*0Sstevel@tonic-gate 		}
584*0Sstevel@tonic-gate 				addenv(&envp, "DEVICE_URI",
585*0Sstevel@tonic-gate 					 printer->printer->device);
586*0Sstevel@tonic-gate 		if (ret != 0)
587*0Sstevel@tonic-gate 			Done (ret, errno);
588*0Sstevel@tonic-gate 
589*0Sstevel@tonic-gate 		if (!(request->request->outcome & RS_FILTERED))
590*0Sstevel@tonic-gate 			file_list = request->request->file_list;
591*0Sstevel@tonic-gate 
592*0Sstevel@tonic-gate 		else {
593*0Sstevel@tonic-gate 			register int		count	= 0;
594*0Sstevel@tonic-gate 			register char *		num	= BIGGEST_REQID_S;
595*0Sstevel@tonic-gate 			register char *		prefix;
596*0Sstevel@tonic-gate 
597*0Sstevel@tonic-gate 			prefix = makestr(
598*0Sstevel@tonic-gate 				Lp_Tmp,
599*0Sstevel@tonic-gate 				"/",
600*0Sstevel@tonic-gate 				(request->secure && request->secure->system ?
601*0Sstevel@tonic-gate 					request->secure->system : Local_System),
602*0Sstevel@tonic-gate 				"/F",
603*0Sstevel@tonic-gate 				getreqno(request->secure->req_id),
604*0Sstevel@tonic-gate 				"-",
605*0Sstevel@tonic-gate 				(char *)0
606*0Sstevel@tonic-gate 			);
607*0Sstevel@tonic-gate 
608*0Sstevel@tonic-gate 			file_list = (char **)Malloc(
609*0Sstevel@tonic-gate 				(lenlist(request->request->file_list) + 1)
610*0Sstevel@tonic-gate 			      * sizeof(char *)
611*0Sstevel@tonic-gate 			);
612*0Sstevel@tonic-gate 
613*0Sstevel@tonic-gate 			for (
614*0Sstevel@tonic-gate 				listp = request->request->file_list;
615*0Sstevel@tonic-gate 				*listp;
616*0Sstevel@tonic-gate 				listp++
617*0Sstevel@tonic-gate 			) {
618*0Sstevel@tonic-gate 				sprintf (num, "%d", count + 1);
619*0Sstevel@tonic-gate 				file_list[count] = makestr(
620*0Sstevel@tonic-gate 					prefix,
621*0Sstevel@tonic-gate 					num,
622*0Sstevel@tonic-gate 					(char *)0
623*0Sstevel@tonic-gate 				);
624*0Sstevel@tonic-gate 				count++;
625*0Sstevel@tonic-gate 			}
626*0Sstevel@tonic-gate 			file_list[count] = 0;
627*0Sstevel@tonic-gate 		}
628*0Sstevel@tonic-gate 
629*0Sstevel@tonic-gate #ifdef LP_USE_PAPI_ATTR
630*0Sstevel@tonic-gate 		/*
631*0Sstevel@tonic-gate 		 * Check if the PAPI job attribute file exists, if it does
632*0Sstevel@tonic-gate 		 * pass the file's pathname to the printer interface script
633*0Sstevel@tonic-gate 		 * in an environment variable. This file is created when
634*0Sstevel@tonic-gate 		 * print jobs are submitted via the PAPI interface.
635*0Sstevel@tonic-gate 		 */
636*0Sstevel@tonic-gate 		snprintf(tmpName, sizeof (tmpName), "%s-%s",
637*0Sstevel@tonic-gate 			getreqno(request->secure->req_id), LP_PAPIATTRNAME);
638*0Sstevel@tonic-gate 		path = makepath(SPOOLDIR, "temp", tmpName, (char *)0);
639*0Sstevel@tonic-gate 		if ((path != NULL) && (stat(path, &tmpBuf) == 0))
640*0Sstevel@tonic-gate 		{
641*0Sstevel@tonic-gate 			/*
642*0Sstevel@tonic-gate 			 * IPP job attribute file exists for this job so
643*0Sstevel@tonic-gate 			 * set the environment variable
644*0Sstevel@tonic-gate 			 */
645*0Sstevel@tonic-gate 			syslog(LOG_DEBUG, "exec(): ATTRPATH='%s'", path);
646*0Sstevel@tonic-gate 			addenv(&envp, "ATTRPATH", path);
647*0Sstevel@tonic-gate 		}
648*0Sstevel@tonic-gate 		Free(path);
649*0Sstevel@tonic-gate 
650*0Sstevel@tonic-gate 		/*
651*0Sstevel@tonic-gate 		 * now set environment variable for the printer's PostScript
652*0Sstevel@tonic-gate 		 * Printer Description (PPD) file, this is used by the filter
653*0Sstevel@tonic-gate 		 * when forming the print data for this printer.
654*0Sstevel@tonic-gate 		 */
655*0Sstevel@tonic-gate 		if ((request->printer != NULL) &&
656*0Sstevel@tonic-gate 		    (request->printer->printer != NULL) &&
657*0Sstevel@tonic-gate 		    (request->printer->printer->name != NULL))
658*0Sstevel@tonic-gate 		{
659*0Sstevel@tonic-gate 			snprintf(tmpName, sizeof (tmpName), "%s.ppd",
660*0Sstevel@tonic-gate 				request->printer->printer->name);
661*0Sstevel@tonic-gate 			path = makepath(ETCDIR, "ppd", tmpName, (char *)0);
662*0Sstevel@tonic-gate 			if ((path != NULL) && (stat(path, &tmpBuf) == 0))
663*0Sstevel@tonic-gate 			{
664*0Sstevel@tonic-gate 				syslog(LOG_DEBUG,
665*0Sstevel@tonic-gate 					"exec(): Printer PPD='%s'", path);
666*0Sstevel@tonic-gate 				addenv(&envp, "PPD", path);
667*0Sstevel@tonic-gate 			}
668*0Sstevel@tonic-gate 			Free(path);
669*0Sstevel@tonic-gate 		}
670*0Sstevel@tonic-gate #endif
671*0Sstevel@tonic-gate 
672*0Sstevel@tonic-gate 		if (request->printer_type)
673*0Sstevel@tonic-gate 			addenv(&envp, "TERM", request->printer_type);
674*0Sstevel@tonic-gate 
675*0Sstevel@tonic-gate 		if (!(printer->printer->daisy)) {
676*0Sstevel@tonic-gate 			register char *	chset = 0;
677*0Sstevel@tonic-gate 			register char *	csp;
678*0Sstevel@tonic-gate 
679*0Sstevel@tonic-gate 			if (
680*0Sstevel@tonic-gate 				request->form
681*0Sstevel@tonic-gate 			     && request->form->form->chset
682*0Sstevel@tonic-gate 			     && request->form->form->mandatory
683*0Sstevel@tonic-gate 			     && !STREQU(NAME_ANY, request->form->form->chset)
684*0Sstevel@tonic-gate 			)
685*0Sstevel@tonic-gate 				chset = request->form->form->chset;
686*0Sstevel@tonic-gate 
687*0Sstevel@tonic-gate 			else if (
688*0Sstevel@tonic-gate 				request->request->charset
689*0Sstevel@tonic-gate 			     && !STREQU(NAME_ANY, request->request->charset)
690*0Sstevel@tonic-gate 			)
691*0Sstevel@tonic-gate 				chset = request->request->charset;
692*0Sstevel@tonic-gate 
693*0Sstevel@tonic-gate 			if (chset) {
694*0Sstevel@tonic-gate 				csp = search_cslist(
695*0Sstevel@tonic-gate 					chset,
696*0Sstevel@tonic-gate 					printer->printer->char_sets
697*0Sstevel@tonic-gate 				);
698*0Sstevel@tonic-gate 
699*0Sstevel@tonic-gate 				/*
700*0Sstevel@tonic-gate 				 * The "strtok()" below wrecks the string
701*0Sstevel@tonic-gate 				 * for future use, but this is a child
702*0Sstevel@tonic-gate 				 * process where it won't be needed again.
703*0Sstevel@tonic-gate 				 */
704*0Sstevel@tonic-gate 				addenv (&envp, "CHARSET",
705*0Sstevel@tonic-gate 					(csp? strtok(csp, "=") : chset)
706*0Sstevel@tonic-gate 				);
707*0Sstevel@tonic-gate 			}
708*0Sstevel@tonic-gate 		}
709*0Sstevel@tonic-gate 
710*0Sstevel@tonic-gate 		if (request->fast)
711*0Sstevel@tonic-gate 			addenv(&envp, "FILTER", request->fast);
712*0Sstevel@tonic-gate 
713*0Sstevel@tonic-gate 		/*
714*0Sstevel@tonic-gate 		*/
715*0Sstevel@tonic-gate 		if (strcmp (request->secure->user, request->request->user))
716*0Sstevel@tonic-gate 		{
717*0Sstevel@tonic-gate 			addenv (&envp, "ALIAS_USERNAME",
718*0Sstevel@tonic-gate 				request->request->user);
719*0Sstevel@tonic-gate 		}
720*0Sstevel@tonic-gate 		/*
721*0Sstevel@tonic-gate 		 * Add the system name to the user name (ala system!user)
722*0Sstevel@tonic-gate 		 * unless it is already there. RFS users may have trouble
723*0Sstevel@tonic-gate 		 * here, sorry!
724*0Sstevel@tonic-gate 		 */
725*0Sstevel@tonic-gate 		cp = strchr(request->secure->user, '@');
726*0Sstevel@tonic-gate 
727*0Sstevel@tonic-gate 		allTraysWithForm(printer, request->form);
728*0Sstevel@tonic-gate 
729*0Sstevel@tonic-gate 		/*
730*0Sstevel@tonic-gate 		 * Fix for 4137389
731*0Sstevel@tonic-gate 		 * Remove double quotes from title string.
732*0Sstevel@tonic-gate 		 */
733*0Sstevel@tonic-gate 		fr_flg = 1;
734*0Sstevel@tonic-gate 		clean_title = strdup(NB(request->request->title));
735*0Sstevel@tonic-gate 		if (clean_title == NULL) {
736*0Sstevel@tonic-gate 			/*
737*0Sstevel@tonic-gate 			 * strdup failed. We're probably hosed
738*0Sstevel@tonic-gate 			 * but try setting clean_title
739*0Sstevel@tonic-gate 			 * to original title and continuing.
740*0Sstevel@tonic-gate 			 */
741*0Sstevel@tonic-gate 			clean_title = NB(request->request->title);
742*0Sstevel@tonic-gate 			fr_flg = 0;
743*0Sstevel@tonic-gate 		} else if (strcmp(clean_title, "") != 0) {
744*0Sstevel@tonic-gate 			char *ct_p;
745*0Sstevel@tonic-gate 
746*0Sstevel@tonic-gate 			for (ct_p = clean_title; *ct_p != NULL; ct_p++) {
747*0Sstevel@tonic-gate 				if (*ct_p == '"')
748*0Sstevel@tonic-gate 					*ct_p = ' ';
749*0Sstevel@tonic-gate 			}
750*0Sstevel@tonic-gate 		}
751*0Sstevel@tonic-gate 
752*0Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s/%s", Lp_A_Interfaces,
753*0Sstevel@tonic-gate 					printer->printer->name);
754*0Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s", request->secure->req_id);
755*0Sstevel@tonic-gate 		av[ac++] = arg_string(UNTRUSTED, "%s%s%s",
756*0Sstevel@tonic-gate 					request->secure->user,
757*0Sstevel@tonic-gate 					(cp? "" : "@"),
758*0Sstevel@tonic-gate 					(cp? "" : request->secure->system));
759*0Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s", clean_title);
760*0Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%d", request->copies);
761*0Sstevel@tonic-gate 
762*0Sstevel@tonic-gate 		if (fr_flg)
763*0Sstevel@tonic-gate 			free (clean_title);
764*0Sstevel@tonic-gate 
765*0Sstevel@tonic-gate 		sep = "";
766*0Sstevel@tonic-gate 
767*0Sstevel@tonic-gate 		/*
768*0Sstevel@tonic-gate 		 * Do the administrator defined key=value pair options
769*0Sstevel@tonic-gate 		 */
770*0Sstevel@tonic-gate 
771*0Sstevel@tonic-gate 		argbuf[0] = '\0';
772*0Sstevel@tonic-gate 
773*0Sstevel@tonic-gate 		if (printer->printer->options) {
774*0Sstevel@tonic-gate 			char **tmp = printer->printer->options;
775*0Sstevel@tonic-gate 			while(*tmp != NULL) {
776*0Sstevel@tonic-gate 				STRLCAT(argbuf, sep, sizeof (argbuf));
777*0Sstevel@tonic-gate 				sep = " ";
778*0Sstevel@tonic-gate 				STRLCAT(argbuf, *tmp++, sizeof (argbuf));
779*0Sstevel@tonic-gate 			}
780*0Sstevel@tonic-gate 		}
781*0Sstevel@tonic-gate 
782*0Sstevel@tonic-gate 		/*
783*0Sstevel@tonic-gate 		 * Do the administrator defined ``stty'' stuff before
784*0Sstevel@tonic-gate 		 * the user's -o options, to allow the user to override.
785*0Sstevel@tonic-gate 		 */
786*0Sstevel@tonic-gate 		if (printer->printer->stty) {
787*0Sstevel@tonic-gate 			STRLCAT (argbuf, sep, sizeof (argbuf));
788*0Sstevel@tonic-gate 			sep = " ";
789*0Sstevel@tonic-gate 			STRLCAT (argbuf, "stty='", sizeof (argbuf));
790*0Sstevel@tonic-gate 			STRLCAT (argbuf, printer->printer->stty,
791*0Sstevel@tonic-gate 			    sizeof (argbuf));
792*0Sstevel@tonic-gate 			STRLCAT (argbuf, "'", sizeof (argbuf));
793*0Sstevel@tonic-gate 		}
794*0Sstevel@tonic-gate 
795*0Sstevel@tonic-gate 		/*
796*0Sstevel@tonic-gate 		 * Do all of the user's options except the cpi/lpi/etc.
797*0Sstevel@tonic-gate 		 * stuff, which is done separately.
798*0Sstevel@tonic-gate 		 */
799*0Sstevel@tonic-gate 		if (request->request->options) {
800*0Sstevel@tonic-gate 			listp = dashos(request->request->options);
801*0Sstevel@tonic-gate 			while (*listp) {
802*0Sstevel@tonic-gate 				if (
803*0Sstevel@tonic-gate 					!STRNEQU(*listp, "cpi=", 4)
804*0Sstevel@tonic-gate 				     && !STRNEQU(*listp, "lpi=", 4)
805*0Sstevel@tonic-gate 				     && !STRNEQU(*listp, "width=", 6)
806*0Sstevel@tonic-gate 				     && !STRNEQU(*listp, "length=", 7)
807*0Sstevel@tonic-gate 				) {
808*0Sstevel@tonic-gate 					STRLCAT (argbuf, sep, sizeof (argbuf));
809*0Sstevel@tonic-gate 					sep = " ";
810*0Sstevel@tonic-gate 					STRLCAT (argbuf, *listp,
811*0Sstevel@tonic-gate 					    sizeof (argbuf));
812*0Sstevel@tonic-gate 				}
813*0Sstevel@tonic-gate 				listp++;
814*0Sstevel@tonic-gate 			}
815*0Sstevel@tonic-gate 		}
816*0Sstevel@tonic-gate 
817*0Sstevel@tonic-gate 		/*
818*0Sstevel@tonic-gate 		 * The "pickfilter()" routine (from "validate()")
819*0Sstevel@tonic-gate 		 * stored the cpi/lpi/etc. stuff that should be
820*0Sstevel@tonic-gate 		 * used for this request. It chose form over user,
821*0Sstevel@tonic-gate 		 * and user over printer.
822*0Sstevel@tonic-gate 		 */
823*0Sstevel@tonic-gate 		if (request->cpi) {
824*0Sstevel@tonic-gate 			STRLCAT (argbuf, sep, sizeof (argbuf));
825*0Sstevel@tonic-gate 			sep = " ";
826*0Sstevel@tonic-gate 			STRLCAT (argbuf, "cpi=", sizeof (argbuf));
827*0Sstevel@tonic-gate 			STRLCAT (argbuf, request->cpi, sizeof (argbuf));
828*0Sstevel@tonic-gate 		}
829*0Sstevel@tonic-gate 		if (request->lpi) {
830*0Sstevel@tonic-gate 			STRLCAT (argbuf, sep, sizeof (argbuf));
831*0Sstevel@tonic-gate 			sep = " ";
832*0Sstevel@tonic-gate 			STRLCAT (argbuf, "lpi=", sizeof (argbuf));
833*0Sstevel@tonic-gate 			STRLCAT (argbuf, request->lpi, sizeof (argbuf));
834*0Sstevel@tonic-gate 		}
835*0Sstevel@tonic-gate 		if (request->pwid) {
836*0Sstevel@tonic-gate 			STRLCAT (argbuf, sep, sizeof (argbuf));
837*0Sstevel@tonic-gate 			sep = " ";
838*0Sstevel@tonic-gate 			STRLCAT (argbuf, "width=", sizeof (argbuf));
839*0Sstevel@tonic-gate 			STRLCAT (argbuf, request->pwid, sizeof (argbuf));
840*0Sstevel@tonic-gate 		}
841*0Sstevel@tonic-gate 		if (request->plen) {
842*0Sstevel@tonic-gate 			STRLCAT (argbuf, sep, sizeof (argbuf));
843*0Sstevel@tonic-gate 			sep = " ";
844*0Sstevel@tonic-gate 			STRLCAT (argbuf, "length=", sizeof (argbuf));
845*0Sstevel@tonic-gate 			STRLCAT (argbuf, request->plen, sizeof (argbuf));
846*0Sstevel@tonic-gate 		}
847*0Sstevel@tonic-gate 
848*0Sstevel@tonic-gate 		/*
849*0Sstevel@tonic-gate 		 * Do the ``raw'' bit last, to ensure it gets
850*0Sstevel@tonic-gate 		 * done. If the user doesn't want this, then he or
851*0Sstevel@tonic-gate 		 * she can do the correct thing using -o stty=
852*0Sstevel@tonic-gate 		 * and leaving out the -r option.
853*0Sstevel@tonic-gate 		 */
854*0Sstevel@tonic-gate 		if (request->request->actions & ACT_RAW) {
855*0Sstevel@tonic-gate 			STRLCAT (argbuf, sep, sizeof (argbuf));
856*0Sstevel@tonic-gate 			sep = " ";
857*0Sstevel@tonic-gate 			STRLCAT (argbuf, "stty=-opost", sizeof (argbuf));
858*0Sstevel@tonic-gate 		}
859*0Sstevel@tonic-gate 
860*0Sstevel@tonic-gate 
861*0Sstevel@tonic-gate 		/* the "options" */
862*0Sstevel@tonic-gate 		av[ac++] = arg_string(UNTRUSTED, "%s", argbuf);
863*0Sstevel@tonic-gate 
864*0Sstevel@tonic-gate 		for (listp = file_list; *listp; listp++)
865*0Sstevel@tonic-gate 			av[ac++] = arg_string(TRUSTED, "%s", *listp);
866*0Sstevel@tonic-gate 
867*0Sstevel@tonic-gate 		(void)chfiles (file_list, procuid, procgid);
868*0Sstevel@tonic-gate 
869*0Sstevel@tonic-gate 		break;
870*0Sstevel@tonic-gate 
871*0Sstevel@tonic-gate 
872*0Sstevel@tonic-gate 	case EX_SLOWF:
873*0Sstevel@tonic-gate 		if (request->slow)
874*0Sstevel@tonic-gate 			addenv(&envp, "FILTER", request->slow);
875*0Sstevel@tonic-gate 
876*0Sstevel@tonic-gate 		if (strchr (request->secure->user, '!'))
877*0Sstevel@tonic-gate 		{
878*0Sstevel@tonic-gate 			procuid = Lp_Uid;
879*0Sstevel@tonic-gate 			procgid = Lp_Gid;
880*0Sstevel@tonic-gate 		}
881*0Sstevel@tonic-gate 		else
882*0Sstevel@tonic-gate 		{
883*0Sstevel@tonic-gate 			procuid = request->secure->uid;
884*0Sstevel@tonic-gate 			procgid = request->secure->gid;
885*0Sstevel@tonic-gate 		}
886*0Sstevel@tonic-gate 		cp = _alloc_files(
887*0Sstevel@tonic-gate 			lenlist(request->request->file_list),
888*0Sstevel@tonic-gate 			getreqno(request->secure->req_id),
889*0Sstevel@tonic-gate 			procuid,
890*0Sstevel@tonic-gate 			procgid,
891*0Sstevel@tonic-gate 			(request->secure && request->secure->system ?
892*0Sstevel@tonic-gate 				request->secure->system : NULL )
893*0Sstevel@tonic-gate 		);
894*0Sstevel@tonic-gate 
895*0Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s", Lp_Slow_Filter);
896*0Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s/%s/%s", Lp_Tmp,
897*0Sstevel@tonic-gate 				(request->secure && request->secure->system ?
898*0Sstevel@tonic-gate 					request->secure->system : Local_System),
899*0Sstevel@tonic-gate 				cp);
900*0Sstevel@tonic-gate 		for (listp = request->request->file_list; *listp; listp++)
901*0Sstevel@tonic-gate 			av[ac++] = arg_string(TRUSTED, "%s", *listp);
902*0Sstevel@tonic-gate 
903*0Sstevel@tonic-gate 		(void)chfiles (request->request->file_list, procuid, procgid);
904*0Sstevel@tonic-gate 
905*0Sstevel@tonic-gate #ifdef LP_USE_PAPI_ATTR
906*0Sstevel@tonic-gate 		/*
907*0Sstevel@tonic-gate 		 * Check if the PAPI job attribute file exists, if it does
908*0Sstevel@tonic-gate 		 * pass the file's pathname to the slow-filters in an
909*0Sstevel@tonic-gate 		 * environment variable. Note: this file is created when
910*0Sstevel@tonic-gate 		 * print jobs are submitted via the PAPI interface.
911*0Sstevel@tonic-gate 		 */
912*0Sstevel@tonic-gate 		snprintf(tmpName, sizeof (tmpName), "%s-%s",
913*0Sstevel@tonic-gate 			getreqno(request->secure->req_id), LP_PAPIATTRNAME);
914*0Sstevel@tonic-gate 		path = makepath(SPOOLDIR, "temp", tmpName, (char *)0);
915*0Sstevel@tonic-gate 		if ((path != NULL) && (stat(path, &tmpBuf) == 0))
916*0Sstevel@tonic-gate 		{
917*0Sstevel@tonic-gate 			/*
918*0Sstevel@tonic-gate 			 * IPP job attribute file exists for this job so
919*0Sstevel@tonic-gate 			 * set the environment variable
920*0Sstevel@tonic-gate 			 */
921*0Sstevel@tonic-gate 			syslog(LOG_DEBUG, "exec(): ATTRPATH='%s'", path);
922*0Sstevel@tonic-gate 			addenv(&envp, "ATTRPATH", path);
923*0Sstevel@tonic-gate 		}
924*0Sstevel@tonic-gate 		Free(path);
925*0Sstevel@tonic-gate 
926*0Sstevel@tonic-gate 
927*0Sstevel@tonic-gate 		/*
928*0Sstevel@tonic-gate 		 * now set environment variable for the printer's PostScript
929*0Sstevel@tonic-gate 		 * Printer Description (PPD) file, this is used by the filter
930*0Sstevel@tonic-gate 		 * when forming the print data for this printer.
931*0Sstevel@tonic-gate 		 */
932*0Sstevel@tonic-gate 		if ((request->printer != NULL) &&
933*0Sstevel@tonic-gate 		    (request->printer->printer != NULL) &&
934*0Sstevel@tonic-gate 		    (request->printer->printer->name != NULL))
935*0Sstevel@tonic-gate 		{
936*0Sstevel@tonic-gate 			snprintf(tmpName, sizeof (tmpName), "%s.ppd",
937*0Sstevel@tonic-gate 				request->printer->printer->name);
938*0Sstevel@tonic-gate 			path = makepath(ETCDIR, "ppd", tmpName, (char *)0);
939*0Sstevel@tonic-gate 			if ((path != NULL) && (stat(path, &tmpBuf) == 0))
940*0Sstevel@tonic-gate 			{
941*0Sstevel@tonic-gate 				syslog(LOG_DEBUG,
942*0Sstevel@tonic-gate 					"exec(): Printer PPD='%s'", path);
943*0Sstevel@tonic-gate 				addenv(&envp, "PPD", path);
944*0Sstevel@tonic-gate 			}
945*0Sstevel@tonic-gate 			Free(path);
946*0Sstevel@tonic-gate 		}
947*0Sstevel@tonic-gate #endif
948*0Sstevel@tonic-gate 		break;
949*0Sstevel@tonic-gate 
950*0Sstevel@tonic-gate 	case EX_ALERT:
951*0Sstevel@tonic-gate 		procuid = Lp_Uid;
952*0Sstevel@tonic-gate 		procgid = Lp_Gid;
953*0Sstevel@tonic-gate 		(void)Chown (printer->alert->msgfile, procuid, procgid);
954*0Sstevel@tonic-gate 
955*0Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s/%s/%s", Lp_A_Printers,
956*0Sstevel@tonic-gate 				printer->printer->name, ALERTSHFILE);
957*0Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s", printer->alert->msgfile);
958*0Sstevel@tonic-gate 
959*0Sstevel@tonic-gate 		break;
960*0Sstevel@tonic-gate 
961*0Sstevel@tonic-gate 	case EX_PALERT:
962*0Sstevel@tonic-gate 		procuid = Lp_Uid;
963*0Sstevel@tonic-gate 		procgid = Lp_Gid;
964*0Sstevel@tonic-gate 		(void)Chown (pwheel->alert->msgfile, procuid, procgid);
965*0Sstevel@tonic-gate 
966*0Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s/%s/%s", Lp_A_PrintWheels,
967*0Sstevel@tonic-gate 				pwheel->pwheel->name, ALERTSHFILE);
968*0Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s", printer->alert->msgfile);
969*0Sstevel@tonic-gate 
970*0Sstevel@tonic-gate 		break;
971*0Sstevel@tonic-gate 
972*0Sstevel@tonic-gate 	case EX_FALERT:
973*0Sstevel@tonic-gate 		procuid = Lp_Uid;
974*0Sstevel@tonic-gate 		procgid = Lp_Gid;
975*0Sstevel@tonic-gate 		(void)Chown (form->alert->msgfile, procuid, procgid);
976*0Sstevel@tonic-gate 
977*0Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s/%s/%s", Lp_A_Forms,
978*0Sstevel@tonic-gate 				form->form->name, ALERTSHFILE);
979*0Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s", printer->alert->msgfile);
980*0Sstevel@tonic-gate 
981*0Sstevel@tonic-gate 		break;
982*0Sstevel@tonic-gate 
983*0Sstevel@tonic-gate 	case EX_FORM_MESSAGE:
984*0Sstevel@tonic-gate 		procuid = Lp_Uid;
985*0Sstevel@tonic-gate 		procgid = Lp_Gid;
986*0Sstevel@tonic-gate 
987*0Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s/form", Lp_A_Faults);
988*0Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s", form->form->name);
989*0Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s", time_buf);
990*0Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s/%s/%s", Lp_A_Forms,
991*0Sstevel@tonic-gate 				form->form->name, FORMMESSAGEFILE);
992*0Sstevel@tonic-gate 
993*0Sstevel@tonic-gate 		break;
994*0Sstevel@tonic-gate 
995*0Sstevel@tonic-gate 	case EX_FAULT_MESSAGE:
996*0Sstevel@tonic-gate 		procuid = Lp_Uid;
997*0Sstevel@tonic-gate 		procgid = Lp_Gid;
998*0Sstevel@tonic-gate 
999*0Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s/printer", Lp_A_Faults);
1000*0Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s", printerNameToShow);
1001*0Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s", time_buf);
1002*0Sstevel@tonic-gate 		av[ac++] = arg_string(TRUSTED, "%s/%s/%s", Lp_A_Printers,
1003*0Sstevel@tonic-gate 				printerName, FAULTMESSAGEFILE);
1004*0Sstevel@tonic-gate 
1005*0Sstevel@tonic-gate 		break;
1006*0Sstevel@tonic-gate 
1007*0Sstevel@tonic-gate 	case EX_NOTIFY:
1008*0Sstevel@tonic-gate 		if (request->request->alert) {
1009*0Sstevel@tonic-gate 			if (strchr(request->secure->user, '!')) {
1010*0Sstevel@tonic-gate 				procuid = Lp_Uid;
1011*0Sstevel@tonic-gate 				procgid = Lp_Gid;
1012*0Sstevel@tonic-gate 			} else {
1013*0Sstevel@tonic-gate 				procuid = request->secure->uid;
1014*0Sstevel@tonic-gate 				procgid = request->secure->gid;
1015*0Sstevel@tonic-gate 			}
1016*0Sstevel@tonic-gate 			av[ac++] = arg_string(TRUSTED, "%s",
1017*0Sstevel@tonic-gate 					request->request->alert);
1018*0Sstevel@tonic-gate 		} else {
1019*0Sstevel@tonic-gate 			char *user = strdup(request->secure->user);
1020*0Sstevel@tonic-gate 			procuid = Lp_Uid;
1021*0Sstevel@tonic-gate 			procgid = Lp_Gid;
1022*0Sstevel@tonic-gate 			clean_string(user);
1023*0Sstevel@tonic-gate 
1024*0Sstevel@tonic-gate 			if ((request->request->actions & ACT_WRITE) &&
1025*0Sstevel@tonic-gate 			    (!request->secure->system ||
1026*0Sstevel@tonic-gate 			    STREQU(request->secure->system, Local_System))) {
1027*0Sstevel@tonic-gate 				av[ac++] = arg_string(TRUSTED, "%s", BINWRITE);
1028*0Sstevel@tonic-gate 				snprintf(argbuf, sizeof (argbuf),
1029*0Sstevel@tonic-gate 					"%s %s || %s %s",
1030*0Sstevel@tonic-gate 					BINWRITE, user,
1031*0Sstevel@tonic-gate 					BINMAIL, user
1032*0Sstevel@tonic-gate 				);
1033*0Sstevel@tonic-gate 				av[ac++] = arg_string(TRUSTED, "/bin/sh");
1034*0Sstevel@tonic-gate 				av[ac++] = arg_string(TRUSTED, "-c");
1035*0Sstevel@tonic-gate 				av[ac++] = arg_string(TRUSTED, "%s", argbuf);
1036*0Sstevel@tonic-gate 			} else {
1037*0Sstevel@tonic-gate 				av[ac++] = arg_string(TRUSTED, "%s", BINMAIL);
1038*0Sstevel@tonic-gate 				av[ac++] = arg_string(UNTRUSTED, "%s", user);
1039*0Sstevel@tonic-gate 			}
1040*0Sstevel@tonic-gate 
1041*0Sstevel@tonic-gate 			free(user);
1042*0Sstevel@tonic-gate 		}
1043*0Sstevel@tonic-gate 		break;
1044*0Sstevel@tonic-gate 	}
1045*0Sstevel@tonic-gate 
1046*0Sstevel@tonic-gate 	av[ac++] = NULL;
1047*0Sstevel@tonic-gate 
1048*0Sstevel@tonic-gate 	Fork2 ();
1049*0Sstevel@tonic-gate 	/* only the child returns */
1050*0Sstevel@tonic-gate 
1051*0Sstevel@tonic-gate 	/*
1052*0Sstevel@tonic-gate 	 * Correctly set up the supplemental group list
1053*0Sstevel@tonic-gate 	 * for proper file access (before execl the interface program)
1054*0Sstevel@tonic-gate 	 */
1055*0Sstevel@tonic-gate 
1056*0Sstevel@tonic-gate 	pwp = getpwuid(procuid);
1057*0Sstevel@tonic-gate 	if (pwp == NULL) {
1058*0Sstevel@tonic-gate 		note("getpwuid(%d) call failed\n", procuid);
1059*0Sstevel@tonic-gate 	} else if (initgroups(pwp->pw_name, procgid) < 0) {
1060*0Sstevel@tonic-gate 		note("initgroups() call failed %d\n", errno);
1061*0Sstevel@tonic-gate 	}
1062*0Sstevel@tonic-gate 
1063*0Sstevel@tonic-gate 	setgid (procgid);
1064*0Sstevel@tonic-gate 	setuid (procuid);
1065*0Sstevel@tonic-gate 
1066*0Sstevel@tonic-gate 	/*
1067*0Sstevel@tonic-gate 	 * The shell doesn't allow the "trap" builtin to set a trap
1068*0Sstevel@tonic-gate 	 * for a signal ignored when the shell is started. Thus, don't
1069*0Sstevel@tonic-gate 	 * turn off signals in the last child!
1070*0Sstevel@tonic-gate 	 */
1071*0Sstevel@tonic-gate 
1072*0Sstevel@tonic-gate 	for (i = 0; av[i] != NULL; i++)
1073*0Sstevel@tonic-gate 		syslog(LOG_DEBUG, "exec: av[%d] = %s", i, av[i]);
1074*0Sstevel@tonic-gate 	for (i = 0; av[i] != NULL; i++)
1075*0Sstevel@tonic-gate 		syslog(LOG_DEBUG, "exec: envp[%d] = %s", i, envp[i]);
1076*0Sstevel@tonic-gate 
1077*0Sstevel@tonic-gate 	execvpe(av[0], av, envp);
1078*0Sstevel@tonic-gate 	Done (EXEC_EXIT_NEXEC, errno);
1079*0Sstevel@tonic-gate 	/*NOTREACHED*/
1080*0Sstevel@tonic-gate }
1081*0Sstevel@tonic-gate 
1082*0Sstevel@tonic-gate /**
1083*0Sstevel@tonic-gate  ** addenv() - ADD A VARIABLE TO THE ENVIRONMENT
1084*0Sstevel@tonic-gate  **/
1085*0Sstevel@tonic-gate 
1086*0Sstevel@tonic-gate static void
1087*0Sstevel@tonic-gate addenv(char ***envp, char *name, char *value)
1088*0Sstevel@tonic-gate {
1089*0Sstevel@tonic-gate 	register char *		cp;
1090*0Sstevel@tonic-gate 
1091*0Sstevel@tonic-gate 	if ((name == NULL) || (value == NULL))
1092*0Sstevel@tonic-gate 		return;
1093*0Sstevel@tonic-gate 
1094*0Sstevel@tonic-gate 	if ((cp = makestr(name, "=", value, (char *)0)))
1095*0Sstevel@tonic-gate 		addlist(envp, cp);
1096*0Sstevel@tonic-gate 	return;
1097*0Sstevel@tonic-gate }
1098*0Sstevel@tonic-gate 
1099*0Sstevel@tonic-gate /**
1100*0Sstevel@tonic-gate  ** Fork1() - FORK FIRST CHILD, SET UP CONNECTION TO IT
1101*0Sstevel@tonic-gate  **/
1102*0Sstevel@tonic-gate 
1103*0Sstevel@tonic-gate static int
1104*0Sstevel@tonic-gate Fork1(EXEC *ep)
1105*0Sstevel@tonic-gate {
1106*0Sstevel@tonic-gate 	int			pid;
1107*0Sstevel@tonic-gate 	int			fds[2];
1108*0Sstevel@tonic-gate 
1109*0Sstevel@tonic-gate 	if (pipe(fds) == -1) {
1110*0Sstevel@tonic-gate 		note("Failed to create pipe for child process (%s).\n", PERROR);
1111*0Sstevel@tonic-gate 		errno = EAGAIN ;
1112*0Sstevel@tonic-gate 		return(-1);
1113*0Sstevel@tonic-gate 	}
1114*0Sstevel@tonic-gate 
1115*0Sstevel@tonic-gate 	ep->md = mconnect((char *)0, fds[0], fds[1]);
1116*0Sstevel@tonic-gate 
1117*0Sstevel@tonic-gate 	switch (pid = fork()) {
1118*0Sstevel@tonic-gate 
1119*0Sstevel@tonic-gate 	case -1:
1120*0Sstevel@tonic-gate 		mdisconnect(ep->md);
1121*0Sstevel@tonic-gate 		close(fds[0]);
1122*0Sstevel@tonic-gate 		close(fds[1]);
1123*0Sstevel@tonic-gate 		ep->md = 0;
1124*0Sstevel@tonic-gate 		return (-1);
1125*0Sstevel@tonic-gate 
1126*0Sstevel@tonic-gate 	case 0:
1127*0Sstevel@tonic-gate 		ChildMd = mconnect(NULL, fds[1], fds[1]);
1128*0Sstevel@tonic-gate 		return (0);
1129*0Sstevel@tonic-gate 
1130*0Sstevel@tonic-gate 	default:
1131*0Sstevel@tonic-gate 		mlistenadd(ep->md, POLLIN);
1132*0Sstevel@tonic-gate 		return (pid);
1133*0Sstevel@tonic-gate 	}
1134*0Sstevel@tonic-gate }
1135*0Sstevel@tonic-gate 
1136*0Sstevel@tonic-gate /**
1137*0Sstevel@tonic-gate  ** Fork2() - FORK SECOND CHILD AND WAIT FOR IT
1138*0Sstevel@tonic-gate  **/
1139*0Sstevel@tonic-gate 
1140*0Sstevel@tonic-gate static void
1141*0Sstevel@tonic-gate Fork2(void)
1142*0Sstevel@tonic-gate {
1143*0Sstevel@tonic-gate 	switch ((ChildPid = fork())) {
1144*0Sstevel@tonic-gate 
1145*0Sstevel@tonic-gate 	case -1:
1146*0Sstevel@tonic-gate 		Done (EXEC_EXIT_NFORK, errno);
1147*0Sstevel@tonic-gate 		/*NOTREACHED*/
1148*0Sstevel@tonic-gate 
1149*0Sstevel@tonic-gate 	case 0:
1150*0Sstevel@tonic-gate 		return;
1151*0Sstevel@tonic-gate 
1152*0Sstevel@tonic-gate 	default:
1153*0Sstevel@tonic-gate 		/*
1154*0Sstevel@tonic-gate 		 * Delay calling "ignore_fault_signals()" as long
1155*0Sstevel@tonic-gate 		 * as possible, to give the child a chance to exec
1156*0Sstevel@tonic-gate 		 * the interface program and turn on traps.
1157*0Sstevel@tonic-gate 		 */
1158*0Sstevel@tonic-gate 
1159*0Sstevel@tonic-gate 		cool_heels ();
1160*0Sstevel@tonic-gate 		/*NOTREACHED*/
1161*0Sstevel@tonic-gate 
1162*0Sstevel@tonic-gate 	}
1163*0Sstevel@tonic-gate }
1164*0Sstevel@tonic-gate 
1165*0Sstevel@tonic-gate 
1166*0Sstevel@tonic-gate /**
1167*0Sstevel@tonic-gate  ** cool_heels() - WAIT FOR CHILD TO "DIE"
1168*0Sstevel@tonic-gate  **/
1169*0Sstevel@tonic-gate 
1170*0Sstevel@tonic-gate static void
1171*0Sstevel@tonic-gate cool_heels(void)
1172*0Sstevel@tonic-gate {
1173*0Sstevel@tonic-gate 	int			status;
1174*0Sstevel@tonic-gate 
1175*0Sstevel@tonic-gate 	/*
1176*0Sstevel@tonic-gate 	 * At this point our only job is to wait for the child process.
1177*0Sstevel@tonic-gate 	 * If we hang out for a bit longer, that's okay.
1178*0Sstevel@tonic-gate 	 * By delaying before turning off the fault signals,
1179*0Sstevel@tonic-gate 	 * we increase the chance that the child process has completed
1180*0Sstevel@tonic-gate 	 * its exec and has turned on the fault traps. Nonetheless,
1181*0Sstevel@tonic-gate 	 * we can't guarantee a zero chance of missing a fault.
1182*0Sstevel@tonic-gate 	 * (We don't want to keep trapping the signals because the
1183*0Sstevel@tonic-gate 	 * interface program is likely to have a better way to handle
1184*0Sstevel@tonic-gate 	 * them; this process provides only rudimentary handling.)
1185*0Sstevel@tonic-gate 	 *
1186*0Sstevel@tonic-gate 	 * Note that on a very busy system, or with a very fast interface
1187*0Sstevel@tonic-gate 	 * program, the tables could be turned: Our sleep below (coupled
1188*0Sstevel@tonic-gate 	 * with a delay in the kernel scheduling us) may cause us to
1189*0Sstevel@tonic-gate 	 * detect the fault instead of the interface program.
1190*0Sstevel@tonic-gate 	 *
1191*0Sstevel@tonic-gate 	 * What we need is a way to synchronize with the child process.
1192*0Sstevel@tonic-gate 	 */
1193*0Sstevel@tonic-gate 	sleep (1);
1194*0Sstevel@tonic-gate 	ignore_fault_signals ();
1195*0Sstevel@tonic-gate 
1196*0Sstevel@tonic-gate 	WaitedChildPid = 0;
1197*0Sstevel@tonic-gate 	while ((WaitedChildPid = wait(&status)) != ChildPid)
1198*0Sstevel@tonic-gate 		;
1199*0Sstevel@tonic-gate 
1200*0Sstevel@tonic-gate 	if (
1201*0Sstevel@tonic-gate 		EXITED(status) > EXEC_EXIT_USER
1202*0Sstevel@tonic-gate 	     && EXITED(status) != EXEC_EXIT_FAULT
1203*0Sstevel@tonic-gate 	)
1204*0Sstevel@tonic-gate 		Done (EXEC_EXIT_EXIT, EXITED(status));
1205*0Sstevel@tonic-gate 
1206*0Sstevel@tonic-gate 	done (status, 0);	/* Don't use Done() */
1207*0Sstevel@tonic-gate 	/*NOTREACHED*/
1208*0Sstevel@tonic-gate }
1209*0Sstevel@tonic-gate 
1210*0Sstevel@tonic-gate 
1211*0Sstevel@tonic-gate /**
1212*0Sstevel@tonic-gate  ** trap_fault_signals() - TRAP SIGNALS THAT CAN OCCUR ON PRINTER FAULT
1213*0Sstevel@tonic-gate  ** ignore_fault_signals() - IGNORE SAME
1214*0Sstevel@tonic-gate  **/
1215*0Sstevel@tonic-gate 
1216*0Sstevel@tonic-gate static void
1217*0Sstevel@tonic-gate trap_fault_signals(void)
1218*0Sstevel@tonic-gate {
1219*0Sstevel@tonic-gate 	signal (SIGHUP, sigtrap);
1220*0Sstevel@tonic-gate 	signal (SIGINT, sigtrap);
1221*0Sstevel@tonic-gate 	signal (SIGQUIT, sigtrap);
1222*0Sstevel@tonic-gate 	signal (SIGPIPE, sigtrap);
1223*0Sstevel@tonic-gate 	return;
1224*0Sstevel@tonic-gate }
1225*0Sstevel@tonic-gate 
1226*0Sstevel@tonic-gate static void
1227*0Sstevel@tonic-gate ignore_fault_signals(void)
1228*0Sstevel@tonic-gate {
1229*0Sstevel@tonic-gate 	signal (SIGHUP, SIG_IGN);
1230*0Sstevel@tonic-gate 	signal (SIGINT, SIG_IGN);
1231*0Sstevel@tonic-gate 	signal (SIGQUIT, SIG_IGN);
1232*0Sstevel@tonic-gate 	signal (SIGPIPE, SIG_IGN);
1233*0Sstevel@tonic-gate 	return;
1234*0Sstevel@tonic-gate }
1235*0Sstevel@tonic-gate 
1236*0Sstevel@tonic-gate /**
1237*0Sstevel@tonic-gate  ** sigtrap() - TRAP VARIOUS SIGNALS
1238*0Sstevel@tonic-gate  **/
1239*0Sstevel@tonic-gate 
1240*0Sstevel@tonic-gate static void
1241*0Sstevel@tonic-gate sigtrap(int sig)
1242*0Sstevel@tonic-gate {
1243*0Sstevel@tonic-gate 	signal (sig, SIG_IGN);
1244*0Sstevel@tonic-gate 	switch (sig) {
1245*0Sstevel@tonic-gate 
1246*0Sstevel@tonic-gate 	case SIGHUP:
1247*0Sstevel@tonic-gate 		Done (EXEC_EXIT_HUP, 0);
1248*0Sstevel@tonic-gate 		/*NOTREACHED*/
1249*0Sstevel@tonic-gate 
1250*0Sstevel@tonic-gate 	case SIGQUIT:
1251*0Sstevel@tonic-gate 	case SIGINT:
1252*0Sstevel@tonic-gate 		Done (EXEC_EXIT_INTR, 0);
1253*0Sstevel@tonic-gate 		/*NOTREACHED*/
1254*0Sstevel@tonic-gate 
1255*0Sstevel@tonic-gate 	case SIGPIPE:
1256*0Sstevel@tonic-gate 		Done (EXEC_EXIT_PIPE, 0);
1257*0Sstevel@tonic-gate 		/*NOTREACHED*/
1258*0Sstevel@tonic-gate 
1259*0Sstevel@tonic-gate 	case SIGTERM:
1260*0Sstevel@tonic-gate 		/*
1261*0Sstevel@tonic-gate 		 * If we were killed with SIGTERM, it should have been
1262*0Sstevel@tonic-gate 		 * via the Spooler who should have killed the entire
1263*0Sstevel@tonic-gate 		 * process group. We have to wait for the children,
1264*0Sstevel@tonic-gate 		 * since we're their parent, but WE MAY HAVE WAITED
1265*0Sstevel@tonic-gate 		 * FOR THEM ALREADY (in cool_heels()).
1266*0Sstevel@tonic-gate 		 */
1267*0Sstevel@tonic-gate 		if (ChildPid != WaitedChildPid) {
1268*0Sstevel@tonic-gate 			register int		cpid;
1269*0Sstevel@tonic-gate 
1270*0Sstevel@tonic-gate 			while (
1271*0Sstevel@tonic-gate 				(cpid = wait((int *)0)) != ChildPid
1272*0Sstevel@tonic-gate 			     && (cpid != -1 || errno != ECHILD)
1273*0Sstevel@tonic-gate 			)
1274*0Sstevel@tonic-gate 				;
1275*0Sstevel@tonic-gate 		}
1276*0Sstevel@tonic-gate 
1277*0Sstevel@tonic-gate 		/*
1278*0Sstevel@tonic-gate 		 * We can't rely on getting SIGTERM back in the wait()
1279*0Sstevel@tonic-gate 		 * above, because, for instance, some shells trap SIGTERM
1280*0Sstevel@tonic-gate 		 * and exit instead. Thus we force it.
1281*0Sstevel@tonic-gate 		 */
1282*0Sstevel@tonic-gate 		done (SIGTERM, 0);	/* Don't use Done() */
1283*0Sstevel@tonic-gate 		/*NOTREACHED*/
1284*0Sstevel@tonic-gate 	}
1285*0Sstevel@tonic-gate }
1286*0Sstevel@tonic-gate 
1287*0Sstevel@tonic-gate /**
1288*0Sstevel@tonic-gate  ** done() - TELL SPOOLER THIS CHILD IS DONE
1289*0Sstevel@tonic-gate  **/
1290*0Sstevel@tonic-gate 
1291*0Sstevel@tonic-gate static void
1292*0Sstevel@tonic-gate done(int status, int err)
1293*0Sstevel@tonic-gate {
1294*0Sstevel@tonic-gate 	if (do_undial)
1295*0Sstevel@tonic-gate 		undial (1);
1296*0Sstevel@tonic-gate 
1297*0Sstevel@tonic-gate 	mputm (ChildMd, S_CHILD_DONE, key, slot, status, err);
1298*0Sstevel@tonic-gate 	mdisconnect (ChildMd);
1299*0Sstevel@tonic-gate 
1300*0Sstevel@tonic-gate 	exit (0);
1301*0Sstevel@tonic-gate 	/*NOTREACHED*/
1302*0Sstevel@tonic-gate }
1303*0Sstevel@tonic-gate 
1304*0Sstevel@tonic-gate /**
1305*0Sstevel@tonic-gate  ** child_mallocfail()
1306*0Sstevel@tonic-gate  **/
1307*0Sstevel@tonic-gate 
1308*0Sstevel@tonic-gate static void
1309*0Sstevel@tonic-gate child_mallocfail(void)
1310*0Sstevel@tonic-gate {
1311*0Sstevel@tonic-gate 	Done (EXEC_EXIT_NOMEM, ENOMEM);
1312*0Sstevel@tonic-gate }
1313