xref: /titanic_41/usr/src/cmd/lp/cmd/lpsched/schedule.c (revision 0a44ef6d9afbfe052a7e975f55ea0d2954b62a82)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0a44ef6dSjacobs  * Common Development and Distribution License (the "License").
6*0a44ef6dSjacobs  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
21*0a44ef6dSjacobs 
227c478bd9Sstevel@tonic-gate /*
23*0a44ef6dSjacobs  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
287c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate 
31*0a44ef6dSjacobs #pragma ident	"%Z%%M%	%I%	%E% SMI"
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate #include "stdarg.h"
347c478bd9Sstevel@tonic-gate #include "lpsched.h"
357c478bd9Sstevel@tonic-gate #include <syslog.h>
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate extern int isStartingForms;
387c478bd9Sstevel@tonic-gate 
397c478bd9Sstevel@tonic-gate typedef struct later {
407c478bd9Sstevel@tonic-gate 	struct later *		next;
417c478bd9Sstevel@tonic-gate 	int			event,
427c478bd9Sstevel@tonic-gate 				ticks;
437c478bd9Sstevel@tonic-gate 	union arg {
447c478bd9Sstevel@tonic-gate 		PSTATUS *		printer;
457c478bd9Sstevel@tonic-gate 		RSTATUS *		request;
467c478bd9Sstevel@tonic-gate 		FSTATUS *		form;
477c478bd9Sstevel@tonic-gate 	}			arg;
487c478bd9Sstevel@tonic-gate }			LATER;
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate static LATER		LaterHead	= { 0 },
517c478bd9Sstevel@tonic-gate 			TempHead;
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate static void		ev_interf(PSTATUS *);
547c478bd9Sstevel@tonic-gate static void		ev_message(PSTATUS *);
557c478bd9Sstevel@tonic-gate static void		ev_form_message(FSTATUS *);
567c478bd9Sstevel@tonic-gate static int		ev_slowf(RSTATUS *);
577c478bd9Sstevel@tonic-gate static int		ev_notify(RSTATUS *);
587c478bd9Sstevel@tonic-gate 
59*0a44ef6dSjacobs static EXEC		*find_exec_slot(EXEC **);
607c478bd9Sstevel@tonic-gate 
_event_name(int event)617c478bd9Sstevel@tonic-gate static char *_event_name(int event)
627c478bd9Sstevel@tonic-gate {
637c478bd9Sstevel@tonic-gate 	static char *_names[] = {
647c478bd9Sstevel@tonic-gate 	"", "EV_SLOWF", "EV_INTERF", "EV_NOTIFY", "EV_LATER", "EV_ALARM",
65*0a44ef6dSjacobs 	"EV_MESSAGE", "EV_ENABLE", "EV_FORM_MESSAGE", NULL };
667c478bd9Sstevel@tonic-gate 
67*0a44ef6dSjacobs 	if ((event < 0) || (event > EV_FORM_MESSAGE))
687c478bd9Sstevel@tonic-gate 		return ("BAD_EVENT");
697c478bd9Sstevel@tonic-gate 	else
707c478bd9Sstevel@tonic-gate 		return (_names[event]);
717c478bd9Sstevel@tonic-gate }
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate /*
747c478bd9Sstevel@tonic-gate  * schedule() - SCHEDULE BY EVENT
757c478bd9Sstevel@tonic-gate  */
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate /*VARARGS1*/
787c478bd9Sstevel@tonic-gate void
schedule(int event,...)797c478bd9Sstevel@tonic-gate schedule(int event, ...)
807c478bd9Sstevel@tonic-gate {
817c478bd9Sstevel@tonic-gate 	va_list			ap;
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate 	LATER *			plprev;
847c478bd9Sstevel@tonic-gate 	LATER *			pl;
857c478bd9Sstevel@tonic-gate 	LATER *			plnext	= 0;
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate 	register PSTATUS *	pps;
887c478bd9Sstevel@tonic-gate 	register RSTATUS *	prs;
897c478bd9Sstevel@tonic-gate 	register FSTATUS *	pfs;
907c478bd9Sstevel@tonic-gate 
91*0a44ef6dSjacobs 	int i;
927c478bd9Sstevel@tonic-gate 	/*
937c478bd9Sstevel@tonic-gate 	 * If we're in the process of shutting down, don't
947c478bd9Sstevel@tonic-gate 	 * schedule anything.
957c478bd9Sstevel@tonic-gate 	 */
967c478bd9Sstevel@tonic-gate 	syslog(LOG_DEBUG, "schedule(%s)", _event_name(event));
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate 	if (Shutdown)
997c478bd9Sstevel@tonic-gate 		return;
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate 	va_start (ap, event);
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate 	/*
1047c478bd9Sstevel@tonic-gate 	 * If we're still in the process of starting up, don't start
1057c478bd9Sstevel@tonic-gate 	 * anything! Schedule it for one tick later. While we're starting
1067c478bd9Sstevel@tonic-gate 	 * ticks aren't counted, so the events won't be started.
1077c478bd9Sstevel@tonic-gate 	 * HOWEVER, with a count of 1, a single EV_ALARM after we're
1087c478bd9Sstevel@tonic-gate 	 * finished starting will be enough to clear all things scheduled
1097c478bd9Sstevel@tonic-gate 	 * for later.
1107c478bd9Sstevel@tonic-gate 	 */
1117c478bd9Sstevel@tonic-gate 	if (Starting) {
1127c478bd9Sstevel@tonic-gate 		switch (event) {
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate 		case EV_INTERF:
1157c478bd9Sstevel@tonic-gate 		case EV_ENABLE:
1167c478bd9Sstevel@tonic-gate 			pps = va_arg(ap, PSTATUS *);
1177c478bd9Sstevel@tonic-gate 			schedule (EV_LATER, 1, event, pps);
1187c478bd9Sstevel@tonic-gate 			goto Return;
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate 		case EV_SLOWF:
1217c478bd9Sstevel@tonic-gate 		case EV_NOTIFY:
1227c478bd9Sstevel@tonic-gate 			prs = va_arg(ap, RSTATUS *);
1237c478bd9Sstevel@tonic-gate 			schedule (EV_LATER, 1, event, prs);
1247c478bd9Sstevel@tonic-gate 			goto Return;
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate 		case EV_MESSAGE:
1277c478bd9Sstevel@tonic-gate 			pps = va_arg(ap, PSTATUS *);
1287c478bd9Sstevel@tonic-gate 			schedule (EV_LATER, 1, event, pps);
1297c478bd9Sstevel@tonic-gate 			goto Return;
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate 		case EV_FORM_MESSAGE:
1327c478bd9Sstevel@tonic-gate 			pfs = va_arg(ap, FSTATUS *);
1337c478bd9Sstevel@tonic-gate 			schedule (EV_LATER, 1, event, pfs);
1347c478bd9Sstevel@tonic-gate 			goto Return;
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate 		case EV_LATER:
1377c478bd9Sstevel@tonic-gate 			/*
1387c478bd9Sstevel@tonic-gate 			 * This is okay--in fact it may be us!
1397c478bd9Sstevel@tonic-gate 			 */
1407c478bd9Sstevel@tonic-gate 			break;
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate 		case EV_ALARM:
1437c478bd9Sstevel@tonic-gate 			/*
1447c478bd9Sstevel@tonic-gate 			 * The alarm will go off again, hold off for now.
1457c478bd9Sstevel@tonic-gate 			 */
1467c478bd9Sstevel@tonic-gate 			goto Return;
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate 		}
1497c478bd9Sstevel@tonic-gate 	}
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate 	/*
1527c478bd9Sstevel@tonic-gate 	 * Schedule something:
1537c478bd9Sstevel@tonic-gate 	 */
1547c478bd9Sstevel@tonic-gate 	switch (event) {
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate 	case EV_INTERF:
1577c478bd9Sstevel@tonic-gate 		if ((pps = va_arg(ap, PSTATUS *)) != NULL)
1587c478bd9Sstevel@tonic-gate 			ev_interf (pps);
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate 		else
161*0a44ef6dSjacobs 			for (i = 0; PStatus != NULL && PStatus[i] != NULL; i++)
162*0a44ef6dSjacobs 				ev_interf (PStatus[i]);
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate 		break;
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate 	/*
1677c478bd9Sstevel@tonic-gate 	 * The EV_ENABLE event is used to get a printer going again
1687c478bd9Sstevel@tonic-gate 	 * after waiting for a fault to be cleared. We used to use
1697c478bd9Sstevel@tonic-gate 	 * just the EV_INTERF event, but this wasn't enough: For
1707c478bd9Sstevel@tonic-gate 	 * requests that can go on several different printers (e.g.
1717c478bd9Sstevel@tonic-gate 	 * queued for class, queued for ``any''), a printer is
1727c478bd9Sstevel@tonic-gate 	 * arbitrarily assigned. The EV_INTERF event just checks
1737c478bd9Sstevel@tonic-gate 	 * assignments, not possibilities, so a printer with no
1747c478bd9Sstevel@tonic-gate 	 * assigned requests but still eligible to handle one or
1757c478bd9Sstevel@tonic-gate 	 * more requests would never automatically start up again after
1767c478bd9Sstevel@tonic-gate 	 * a fault. The EV_ENABLE event calls "enable()" which eventually
1777c478bd9Sstevel@tonic-gate 	 * gets around to invoking the EV_INTERF event. However, it first
1787c478bd9Sstevel@tonic-gate 	 * calls "queue_attract()" to get an eligible request assigned
1797c478bd9Sstevel@tonic-gate 	 * so that things proceed. This also makes sense from the
1807c478bd9Sstevel@tonic-gate 	 * following standpoint: The documented method of getting a
1817c478bd9Sstevel@tonic-gate 	 * printer going, while it is waiting for auto-retry, is to
1827c478bd9Sstevel@tonic-gate 	 * manually issue the enable command!
1837c478bd9Sstevel@tonic-gate 	 *
1847c478bd9Sstevel@tonic-gate 	 * Note: "enable()" will destroy the current record of the fault,
1857c478bd9Sstevel@tonic-gate 	 * so if the fault is still with us any new alert will not include
1867c478bd9Sstevel@tonic-gate 	 * the history of each repeated fault. This is a plus and a minus,
1877c478bd9Sstevel@tonic-gate 	 * usually a minus: While a repeated fault may occasionally show
1887c478bd9Sstevel@tonic-gate 	 * a varied record, usually the same reason is given each time;
1897c478bd9Sstevel@tonic-gate 	 * before switching to EV_ENABLE we typically saw a boring, long
1907c478bd9Sstevel@tonic-gate 	 * list of identical reasons.
1917c478bd9Sstevel@tonic-gate 	 */
1927c478bd9Sstevel@tonic-gate 	case EV_ENABLE:
1937c478bd9Sstevel@tonic-gate 		if ((pps = va_arg(ap, PSTATUS *)) != NULL)
1947c478bd9Sstevel@tonic-gate 			enable (pps);
1957c478bd9Sstevel@tonic-gate 		else
196*0a44ef6dSjacobs 			for (i = 0; PStatus != NULL && PStatus[i] != NULL; i++)
197*0a44ef6dSjacobs 				enable (PStatus[i]);
1987c478bd9Sstevel@tonic-gate 		break;
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate 	case EV_SLOWF:
2017c478bd9Sstevel@tonic-gate 		if ((prs = va_arg(ap, RSTATUS *)) != NULL)
2027c478bd9Sstevel@tonic-gate 			(void) ev_slowf (prs);
2037c478bd9Sstevel@tonic-gate 		else
2047c478bd9Sstevel@tonic-gate 			for (prs = Request_List; prs && ev_slowf(prs) != -1;
2057c478bd9Sstevel@tonic-gate 				prs = prs->next);
2067c478bd9Sstevel@tonic-gate 		break;
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate 	case EV_NOTIFY:
2097c478bd9Sstevel@tonic-gate 		if ((prs = va_arg(ap, RSTATUS *)) != NULL)
2107c478bd9Sstevel@tonic-gate 			(void) ev_notify (prs);
2117c478bd9Sstevel@tonic-gate 		else
2127c478bd9Sstevel@tonic-gate 			for (prs = Request_List; prs && ev_notify(prs) != -1;
2137c478bd9Sstevel@tonic-gate 				prs = prs->next);
2147c478bd9Sstevel@tonic-gate 		break;
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate 	case EV_MESSAGE:
2177c478bd9Sstevel@tonic-gate 		pps = va_arg(ap, PSTATUS *);
2187c478bd9Sstevel@tonic-gate 		ev_message(pps);
2197c478bd9Sstevel@tonic-gate 		break;
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate 	case EV_FORM_MESSAGE:
2227c478bd9Sstevel@tonic-gate 		pfs = va_arg(ap, FSTATUS *);
2237c478bd9Sstevel@tonic-gate 		ev_form_message(pfs);
2247c478bd9Sstevel@tonic-gate 		break;
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate 	case EV_LATER:
2277c478bd9Sstevel@tonic-gate 		pl = (LATER *)Malloc(sizeof (LATER));
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate 		if (!LaterHead.next)
2307c478bd9Sstevel@tonic-gate 			alarm (CLOCK_TICK);
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate 		pl->next = LaterHead.next;
2337c478bd9Sstevel@tonic-gate 		LaterHead.next = pl;
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate 		pl->ticks = va_arg(ap, int);
2367c478bd9Sstevel@tonic-gate 		pl->event = va_arg(ap, int);
2377c478bd9Sstevel@tonic-gate 		switch (pl->event) {
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate 		case EV_MESSAGE:
2407c478bd9Sstevel@tonic-gate 		case EV_INTERF:
2417c478bd9Sstevel@tonic-gate 		case EV_ENABLE:
2427c478bd9Sstevel@tonic-gate 			pl->arg.printer = va_arg(ap, PSTATUS *);
2437c478bd9Sstevel@tonic-gate 			if (pl->arg.printer)
2447c478bd9Sstevel@tonic-gate 				pl->arg.printer->status |= PS_LATER;
2457c478bd9Sstevel@tonic-gate 			break;
2467c478bd9Sstevel@tonic-gate 
2477c478bd9Sstevel@tonic-gate 		case EV_FORM_MESSAGE:
2487c478bd9Sstevel@tonic-gate 			pl->arg.form = va_arg(ap, FSTATUS *);
2497c478bd9Sstevel@tonic-gate 			break;
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate 		case EV_SLOWF:
2527c478bd9Sstevel@tonic-gate 		case EV_NOTIFY:
2537c478bd9Sstevel@tonic-gate 			pl->arg.request = va_arg(ap, RSTATUS *);
2547c478bd9Sstevel@tonic-gate 			break;
2557c478bd9Sstevel@tonic-gate 
2567c478bd9Sstevel@tonic-gate 		}
2577c478bd9Sstevel@tonic-gate 		break;
2587c478bd9Sstevel@tonic-gate 
2597c478bd9Sstevel@tonic-gate 	case EV_ALARM:
2607c478bd9Sstevel@tonic-gate 		Sig_Alrm = 0;
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate 		/*
2637c478bd9Sstevel@tonic-gate 		 * The act of scheduling some of the ``laters'' may
2647c478bd9Sstevel@tonic-gate 		 * cause new ``laters'' to be added to the list.
2657c478bd9Sstevel@tonic-gate 		 * To ease the handling of the linked list, we first
2667c478bd9Sstevel@tonic-gate 		 * run through the list and move all events ready to
2677c478bd9Sstevel@tonic-gate 		 * be scheduled to another list. Then we schedule the
2687c478bd9Sstevel@tonic-gate 		 * events off the new list. This leaves the main ``later''
2697c478bd9Sstevel@tonic-gate 		 * list ready for new events.
2707c478bd9Sstevel@tonic-gate 		 */
2717c478bd9Sstevel@tonic-gate 		TempHead.next = 0;
2727c478bd9Sstevel@tonic-gate 		for (pl = (plprev = &LaterHead)->next; pl; pl = plnext) {
2737c478bd9Sstevel@tonic-gate 			plnext = pl->next;
2747c478bd9Sstevel@tonic-gate 			if (--pl->ticks)
2757c478bd9Sstevel@tonic-gate 				plprev = pl;
2767c478bd9Sstevel@tonic-gate 			else {
2777c478bd9Sstevel@tonic-gate 				plprev->next = plnext;
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate 				pl->next = TempHead.next;
2807c478bd9Sstevel@tonic-gate 				TempHead.next = pl;
2817c478bd9Sstevel@tonic-gate 			}
2827c478bd9Sstevel@tonic-gate 		}
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate 		for (pl = TempHead.next; pl; pl = plnext) {
2857c478bd9Sstevel@tonic-gate 			plnext = pl->next;
2867c478bd9Sstevel@tonic-gate 			switch (pl->event) {
2877c478bd9Sstevel@tonic-gate 
2887c478bd9Sstevel@tonic-gate 			case EV_MESSAGE:
2897c478bd9Sstevel@tonic-gate 			case EV_INTERF:
2907c478bd9Sstevel@tonic-gate 			case EV_ENABLE:
2917c478bd9Sstevel@tonic-gate 				pl->arg.printer->status &= ~PS_LATER;
2927c478bd9Sstevel@tonic-gate 				schedule (pl->event, pl->arg.printer);
2937c478bd9Sstevel@tonic-gate 				break;
2947c478bd9Sstevel@tonic-gate 
2957c478bd9Sstevel@tonic-gate 			case EV_FORM_MESSAGE:
2967c478bd9Sstevel@tonic-gate 				schedule (pl->event, pl->arg.form);
2977c478bd9Sstevel@tonic-gate 				break;
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate 			case EV_SLOWF:
3007c478bd9Sstevel@tonic-gate 			case EV_NOTIFY:
3017c478bd9Sstevel@tonic-gate 				schedule (pl->event, pl->arg.request);
3027c478bd9Sstevel@tonic-gate 				break;
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate 			}
3057c478bd9Sstevel@tonic-gate 			Free ((char *)pl);
3067c478bd9Sstevel@tonic-gate 		}
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate 		if (LaterHead.next)
3097c478bd9Sstevel@tonic-gate 			alarm (CLOCK_TICK);
3107c478bd9Sstevel@tonic-gate 		break;
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate 	}
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate Return:	va_end (ap);
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate 	return;
3177c478bd9Sstevel@tonic-gate }
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate /*
3207c478bd9Sstevel@tonic-gate  * maybe_schedule() - MAYBE SCHEDULE SOMETHING FOR A REQUEST
3217c478bd9Sstevel@tonic-gate  */
3227c478bd9Sstevel@tonic-gate 
3237c478bd9Sstevel@tonic-gate void
maybe_schedule(RSTATUS * prs)3247c478bd9Sstevel@tonic-gate maybe_schedule(RSTATUS *prs)
3257c478bd9Sstevel@tonic-gate {
3267c478bd9Sstevel@tonic-gate 	/*
3277c478bd9Sstevel@tonic-gate 	 * Use this routine if a request has been changed by some
3287c478bd9Sstevel@tonic-gate 	 * means so that it is ready for filtering or printing,
3297c478bd9Sstevel@tonic-gate 	 * but a previous filtering or printing process for this
3307c478bd9Sstevel@tonic-gate 	 * request MAY NOT have finished yet. If a process is still
3317c478bd9Sstevel@tonic-gate 	 * running, then the cleanup of that process will cause
3327c478bd9Sstevel@tonic-gate 	 * "schedule()" to be called. Calling "schedule()" regardless
3337c478bd9Sstevel@tonic-gate 	 * might make another request slip ahead of this request.
3347c478bd9Sstevel@tonic-gate 	 */
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate 	/*
3377c478bd9Sstevel@tonic-gate 	 * "schedule()" will refuse if this request is filtering.
3387c478bd9Sstevel@tonic-gate 	 * It will also refuse if the request ``was'' filtering
3397c478bd9Sstevel@tonic-gate 	 * but the filter was terminated in "validate_request()",
3407c478bd9Sstevel@tonic-gate 	 * because we can not have heard from the filter process
3417c478bd9Sstevel@tonic-gate 	 * yet. Also, when called with a particular request,
3427c478bd9Sstevel@tonic-gate 	 * "schedule()" won't slip another request ahead.
3437c478bd9Sstevel@tonic-gate 	 */
3447c478bd9Sstevel@tonic-gate 	if (NEEDS_FILTERING(prs))
3457c478bd9Sstevel@tonic-gate 		schedule (EV_SLOWF, prs);
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate 	else if (!(prs->request->outcome & RS_STOPPED))
3487c478bd9Sstevel@tonic-gate 		schedule (EV_INTERF, prs->printer);
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate 	return;
3517c478bd9Sstevel@tonic-gate }
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate static void
ev_message(PSTATUS * pps)3547c478bd9Sstevel@tonic-gate ev_message(PSTATUS *pps)
3557c478bd9Sstevel@tonic-gate {
3567c478bd9Sstevel@tonic-gate 	register RSTATUS	*prs;
3577c478bd9Sstevel@tonic-gate 	char			toSelf;
3587c478bd9Sstevel@tonic-gate 
3597c478bd9Sstevel@tonic-gate 	syslog(LOG_DEBUG, "ev_message(%s)",
3607c478bd9Sstevel@tonic-gate 	       (pps && pps->request && pps->request->req_file ?
3617c478bd9Sstevel@tonic-gate 		pps->request->req_file : "NULL"));
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate 	toSelf = 0;
364*0a44ef6dSjacobs 	for (prs = Request_List; prs != NULL; prs = prs->next)
365*0a44ef6dSjacobs 		if (prs->printer == pps) {
3667c478bd9Sstevel@tonic-gate 			note("prs (%d) pps (%d)\n", prs, pps);
3677c478bd9Sstevel@tonic-gate 			if (!toSelf) {
3687c478bd9Sstevel@tonic-gate 				toSelf = 1;
3697c478bd9Sstevel@tonic-gate 				exec(EX_FAULT_MESSAGE, pps, prs);
3707c478bd9Sstevel@tonic-gate 			}
371*0a44ef6dSjacobs 		}
3727c478bd9Sstevel@tonic-gate }
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate static void
ev_form_message_body(FSTATUS * pfs,RSTATUS * prs,char * toSelf,char *** sysList)3757c478bd9Sstevel@tonic-gate ev_form_message_body(FSTATUS *pfs, RSTATUS *prs, char *toSelf, char ***sysList)
3767c478bd9Sstevel@tonic-gate {
377*0a44ef6dSjacobs 	syslog(LOG_DEBUG, "ev_form_message_body(%s, %d, 0x%x)",
3787c478bd9Sstevel@tonic-gate 	      (pfs && pfs->form && pfs->form->name ? pfs->form->name : "NULL"),
379*0a44ef6dSjacobs 	      (toSelf ? *toSelf : 0),
3807c478bd9Sstevel@tonic-gate 		sysList);
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate 	if (!*toSelf) {
3837c478bd9Sstevel@tonic-gate 		*toSelf = 1;
3847c478bd9Sstevel@tonic-gate 		exec(EX_FORM_MESSAGE, pfs);
3857c478bd9Sstevel@tonic-gate 	}
3867c478bd9Sstevel@tonic-gate }
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate static void
ev_form_message(FSTATUS * pfs)3897c478bd9Sstevel@tonic-gate ev_form_message(FSTATUS *pfs)
3907c478bd9Sstevel@tonic-gate {
3917c478bd9Sstevel@tonic-gate 	register RSTATUS	*prs;
3927c478bd9Sstevel@tonic-gate 	char **sysList;
3937c478bd9Sstevel@tonic-gate 	char toSelf;
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate 	syslog(LOG_DEBUG, "ev_form_message(%s)",
3967c478bd9Sstevel@tonic-gate 	       (pfs && pfs->form && pfs->form->name ?
3977c478bd9Sstevel@tonic-gate 		pfs->form->name : "NULL"));
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate 	toSelf = 0;
4007c478bd9Sstevel@tonic-gate 	sysList = NULL;
401*0a44ef6dSjacobs 
402*0a44ef6dSjacobs 	for (prs = Request_List; prs != NULL; prs = prs->next)
403*0a44ef6dSjacobs 		if (prs->form == pfs)
4047c478bd9Sstevel@tonic-gate 			ev_form_message_body(pfs, prs, &toSelf, &sysList);
405*0a44ef6dSjacobs 
4067c478bd9Sstevel@tonic-gate 	if (NewRequest && (NewRequest->form == pfs))
4077c478bd9Sstevel@tonic-gate 		ev_form_message_body(pfs, NewRequest, &toSelf, &sysList);
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate 	freelist(sysList);
4107c478bd9Sstevel@tonic-gate }
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate /*
4137c478bd9Sstevel@tonic-gate  * ev_interf() - CHECK AND EXEC INTERFACE PROGRAM
4147c478bd9Sstevel@tonic-gate  */
4157c478bd9Sstevel@tonic-gate 
4167c478bd9Sstevel@tonic-gate /*
4177c478bd9Sstevel@tonic-gate  * Macro to check if the request needs a print wheel or character set (S)
4187c478bd9Sstevel@tonic-gate  * and the printer (P) has it mounted or can select it. Since the request
4197c478bd9Sstevel@tonic-gate  * has already been approved for the printer, we don't have to check the
4207c478bd9Sstevel@tonic-gate  * character set, just the mount. If the printer has selectable character
4217c478bd9Sstevel@tonic-gate  * sets, there's nothing to check so the request is ready to print.
4227c478bd9Sstevel@tonic-gate  */
4237c478bd9Sstevel@tonic-gate #define	MATCH(PRS, PPS) (\
4247c478bd9Sstevel@tonic-gate 		!(PPS)->printer->daisy || \
4257c478bd9Sstevel@tonic-gate 		!(PRS)->pwheel_name || \
4267c478bd9Sstevel@tonic-gate 		!((PRS)->status & RSS_PWMAND) || \
4277c478bd9Sstevel@tonic-gate 		STREQU((PRS)->pwheel_name, NAME_ANY) || \
4287c478bd9Sstevel@tonic-gate 		((PPS)->pwheel_name && \
4297c478bd9Sstevel@tonic-gate 		STREQU((PPS)->pwheel_name, (PRS)->pwheel_name)))
4307c478bd9Sstevel@tonic-gate 
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate static void
ev_interf(PSTATUS * pps)4337c478bd9Sstevel@tonic-gate ev_interf(PSTATUS *pps)
4347c478bd9Sstevel@tonic-gate {
4357c478bd9Sstevel@tonic-gate 	register RSTATUS	*prs;
4367c478bd9Sstevel@tonic-gate 
4377c478bd9Sstevel@tonic-gate 	syslog(LOG_DEBUG, "ev_interf(%s)",
4387c478bd9Sstevel@tonic-gate 	       (pps && pps->request && pps->request->req_file ?
4397c478bd9Sstevel@tonic-gate 		pps->request->req_file : "NULL"));
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate 
4427c478bd9Sstevel@tonic-gate 	/*
4437c478bd9Sstevel@tonic-gate 	 * If the printer isn't tied up doing something
4447c478bd9Sstevel@tonic-gate 	 * else, and isn't disabled, see if there is a request
4457c478bd9Sstevel@tonic-gate 	 * waiting to print on it. Note: We don't include
4467c478bd9Sstevel@tonic-gate 	 * PS_FAULTED here, because simply having a printer
4477c478bd9Sstevel@tonic-gate 	 * fault (without also being disabled) isn't sufficient
4487c478bd9Sstevel@tonic-gate 	 * to keep us from trying again. (In fact, we HAVE TO
4497c478bd9Sstevel@tonic-gate 	 * try again, to see if the fault has gone away.)
4507c478bd9Sstevel@tonic-gate 	 *
4517c478bd9Sstevel@tonic-gate 	 * NOTE: If the printer is faulted but the filter controlling
4527c478bd9Sstevel@tonic-gate 	 * the printer is waiting for the fault to clear, a
4537c478bd9Sstevel@tonic-gate 	 * request will still be attached to the printer, as
4547c478bd9Sstevel@tonic-gate 	 * evidenced by "pps->request", so we won't try to
4557c478bd9Sstevel@tonic-gate 	 * schedule another request!
4567c478bd9Sstevel@tonic-gate 	 */
4577c478bd9Sstevel@tonic-gate 	if (pps->request || pps->status & (PS_DISABLED|PS_LATER|PS_BUSY))
4587c478bd9Sstevel@tonic-gate 		return;
4597c478bd9Sstevel@tonic-gate 
460*0a44ef6dSjacobs 	for (prs = Request_List; prs != NULL; prs = prs->next) {
461*0a44ef6dSjacobs 		if ((prs->printer == pps) && (qchk_waiting(prs)) &&
462*0a44ef6dSjacobs 		    isFormUsableOnPrinter(pps, prs->form) && MATCH(prs, pps)) {
4637c478bd9Sstevel@tonic-gate 		/*
4647c478bd9Sstevel@tonic-gate 		 * Just because the printer isn't busy and the
4657c478bd9Sstevel@tonic-gate 		 * request is assigned to this printer, don't get the
4667c478bd9Sstevel@tonic-gate 		 * idea that the request can't be printing (RS_ACTIVE),
4677c478bd9Sstevel@tonic-gate 		 * because another printer may still have the request
4687c478bd9Sstevel@tonic-gate 		 * attached but we've not yet heard from the child
4697c478bd9Sstevel@tonic-gate 		 * process controlling that printer.
470*0a44ef6dSjacobs 		 *
4717c478bd9Sstevel@tonic-gate 		 * We have the waiting request, we have
4727c478bd9Sstevel@tonic-gate 		 * the ready (local) printer. If the exec fails
4737c478bd9Sstevel@tonic-gate 		 * because the fork failed, schedule a
4747c478bd9Sstevel@tonic-gate 		 * try later and claim we succeeded. The
4757c478bd9Sstevel@tonic-gate 		 * later attempt will sort things out,
4767c478bd9Sstevel@tonic-gate 		 * e.g. will re-schedule if the fork fails
4777c478bd9Sstevel@tonic-gate 		 * again.
4787c478bd9Sstevel@tonic-gate 		 */
4797c478bd9Sstevel@tonic-gate 			pps->request = prs;
4807c478bd9Sstevel@tonic-gate 			if (exec(EX_INTERF, pps) == 0) {
4817c478bd9Sstevel@tonic-gate 				pps->status |= PS_BUSY;
4827c478bd9Sstevel@tonic-gate 				return;
4837c478bd9Sstevel@tonic-gate 			}
4847c478bd9Sstevel@tonic-gate 			pps->request = 0;
4857c478bd9Sstevel@tonic-gate 			if (errno == EAGAIN) {
4867c478bd9Sstevel@tonic-gate 				load_str (&pps->dis_reason, CUZ_NOFORK);
4877c478bd9Sstevel@tonic-gate 				schedule (EV_LATER, WHEN_FORK, EV_ENABLE, pps);
4887c478bd9Sstevel@tonic-gate 				return;
4897c478bd9Sstevel@tonic-gate 			}
4907c478bd9Sstevel@tonic-gate 		}
491*0a44ef6dSjacobs 	}
4927c478bd9Sstevel@tonic-gate 
4937c478bd9Sstevel@tonic-gate 	return;
4947c478bd9Sstevel@tonic-gate }
4957c478bd9Sstevel@tonic-gate 
4967c478bd9Sstevel@tonic-gate /*
4977c478bd9Sstevel@tonic-gate  * ev_slowf() - CHECK AND EXEC SLOW FILTER
4987c478bd9Sstevel@tonic-gate  */
4997c478bd9Sstevel@tonic-gate 
5007c478bd9Sstevel@tonic-gate static int
ev_slowf(RSTATUS * prs)5017c478bd9Sstevel@tonic-gate ev_slowf(RSTATUS *prs)
5027c478bd9Sstevel@tonic-gate {
5037c478bd9Sstevel@tonic-gate 	register EXEC		*ep;
5047c478bd9Sstevel@tonic-gate 
5057c478bd9Sstevel@tonic-gate 	syslog(LOG_DEBUG, "ev_slowf(%s)",
5067c478bd9Sstevel@tonic-gate 	       (prs && prs->req_file ? prs->req_file : "NULL"));
5077c478bd9Sstevel@tonic-gate 
5087c478bd9Sstevel@tonic-gate 	/*
5097c478bd9Sstevel@tonic-gate 	 * Return -1 if no more can be executed (no more exec slots)
5107c478bd9Sstevel@tonic-gate 	 * or if it's unwise to execute any more (fork failed).
5117c478bd9Sstevel@tonic-gate 	 */
5127c478bd9Sstevel@tonic-gate 
513*0a44ef6dSjacobs 	if (!(ep = find_exec_slot(Exec_Slow))) {
514*0a44ef6dSjacobs 		syslog(LOG_DEBUG, "ev_slowf(%s): no slot",
515*0a44ef6dSjacobs 	       		(prs && prs->req_file ? prs->req_file : "NULL"));
5167c478bd9Sstevel@tonic-gate 		return (-1);
517*0a44ef6dSjacobs 	}
5187c478bd9Sstevel@tonic-gate 
5197c478bd9Sstevel@tonic-gate 	if (!(prs->request->outcome & (RS_DONE|RS_HELD|RS_ACTIVE)) &&
5207c478bd9Sstevel@tonic-gate 	    NEEDS_FILTERING(prs)) {
5217c478bd9Sstevel@tonic-gate 		(prs->exec = ep)->ex.request = prs;
5227c478bd9Sstevel@tonic-gate 		if (exec(EX_SLOWF, prs) != 0) {
5237c478bd9Sstevel@tonic-gate 			ep->ex.request = 0;
5247c478bd9Sstevel@tonic-gate 			prs->exec = 0;
5257c478bd9Sstevel@tonic-gate 			if (errno == EAGAIN) {
5267c478bd9Sstevel@tonic-gate 				schedule (EV_LATER, WHEN_FORK, EV_SLOWF, prs);
5277c478bd9Sstevel@tonic-gate 				return (-1);
5287c478bd9Sstevel@tonic-gate 			}
5297c478bd9Sstevel@tonic-gate 		}
5307c478bd9Sstevel@tonic-gate 	}
5317c478bd9Sstevel@tonic-gate 	return (0);
5327c478bd9Sstevel@tonic-gate }
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate /*
5357c478bd9Sstevel@tonic-gate  * ev_notify() - CHECK AND EXEC NOTIFICATION
5367c478bd9Sstevel@tonic-gate  */
5377c478bd9Sstevel@tonic-gate 
5387c478bd9Sstevel@tonic-gate static int
ev_notify(RSTATUS * prs)5397c478bd9Sstevel@tonic-gate ev_notify(RSTATUS *prs)
5407c478bd9Sstevel@tonic-gate {
5417c478bd9Sstevel@tonic-gate 	register EXEC		*ep;
5427c478bd9Sstevel@tonic-gate 
5437c478bd9Sstevel@tonic-gate 	syslog(LOG_DEBUG, "ev_notify(%s)",
5447c478bd9Sstevel@tonic-gate 	       (prs && prs->req_file ? prs->req_file : "NULL"));
5457c478bd9Sstevel@tonic-gate 
5467c478bd9Sstevel@tonic-gate 	/*
5477c478bd9Sstevel@tonic-gate 	 * Return -1 if no more can be executed (no more exec slots)
5487c478bd9Sstevel@tonic-gate 	 * or if it's unwise to execute any more (fork failed, already
5497c478bd9Sstevel@tonic-gate 	 * sent one to remote side).
5507c478bd9Sstevel@tonic-gate 	 */
5517c478bd9Sstevel@tonic-gate 
5527c478bd9Sstevel@tonic-gate 	/*
5537c478bd9Sstevel@tonic-gate 	 * If the job came from a remote machine, we forward the
5547c478bd9Sstevel@tonic-gate 	 * outcome of the request to the network manager for sending
5557c478bd9Sstevel@tonic-gate 	 * to the remote side.
5567c478bd9Sstevel@tonic-gate 	 */
5577c478bd9Sstevel@tonic-gate 	if (prs->request->actions & ACT_NOTIFY) {
5587c478bd9Sstevel@tonic-gate 		if (prs->request->outcome & RS_NOTIFY) {
5597c478bd9Sstevel@tonic-gate 			prs->request->actions &= ~ACT_NOTIFY;
5607c478bd9Sstevel@tonic-gate 			return (0);  /* but try another request */
5617c478bd9Sstevel@tonic-gate 		}
5627c478bd9Sstevel@tonic-gate 	/*
5637c478bd9Sstevel@tonic-gate 	 * If the job didn't come from a remote system,
5647c478bd9Sstevel@tonic-gate 	 * we'll try to start a process to send the notification
5657c478bd9Sstevel@tonic-gate 	 * to the user. But we only allow so many notifications
5667c478bd9Sstevel@tonic-gate 	 * to run at the same time, so we may not be able to
5677c478bd9Sstevel@tonic-gate 	 * do it.
5687c478bd9Sstevel@tonic-gate 	 */
569*0a44ef6dSjacobs 	} else if (!(ep = find_exec_slot(Exec_Notify)))
5707c478bd9Sstevel@tonic-gate 		return (-1);
5717c478bd9Sstevel@tonic-gate 
5727c478bd9Sstevel@tonic-gate 	else if (prs->request->outcome & RS_NOTIFY &&
5737c478bd9Sstevel@tonic-gate 		!(prs->request->outcome & RS_NOTIFYING)) {
5747c478bd9Sstevel@tonic-gate 
5757c478bd9Sstevel@tonic-gate 		(prs->exec = ep)->ex.request = prs;
5767c478bd9Sstevel@tonic-gate 		if (exec(EX_NOTIFY, prs) != 0) {
5777c478bd9Sstevel@tonic-gate 			ep->ex.request = 0;
5787c478bd9Sstevel@tonic-gate 			prs->exec = 0;
5797c478bd9Sstevel@tonic-gate 			if (errno == EAGAIN) {
5807c478bd9Sstevel@tonic-gate 				schedule (EV_LATER, WHEN_FORK, EV_NOTIFY, prs);
5817c478bd9Sstevel@tonic-gate 				return (-1);
5827c478bd9Sstevel@tonic-gate 			}
5837c478bd9Sstevel@tonic-gate 		}
5847c478bd9Sstevel@tonic-gate 	}
5857c478bd9Sstevel@tonic-gate 	return (0);
5867c478bd9Sstevel@tonic-gate }
5877c478bd9Sstevel@tonic-gate 
5887c478bd9Sstevel@tonic-gate 
5897c478bd9Sstevel@tonic-gate /*
5907c478bd9Sstevel@tonic-gate  * find_exec_slot() - FIND AVAILABLE EXEC SLOT
5917c478bd9Sstevel@tonic-gate  */
5927c478bd9Sstevel@tonic-gate 
5937c478bd9Sstevel@tonic-gate static EXEC *
find_exec_slot(EXEC ** exec_table)594*0a44ef6dSjacobs find_exec_slot(EXEC **exec_table)
5957c478bd9Sstevel@tonic-gate {
596*0a44ef6dSjacobs 	int i;
5977c478bd9Sstevel@tonic-gate 
598*0a44ef6dSjacobs 	for (i = 0; exec_table[i] != NULL; i++)
599*0a44ef6dSjacobs 		if (exec_table[i]->pid == 0)
600*0a44ef6dSjacobs 			return (exec_table[i]);
6017c478bd9Sstevel@tonic-gate 
602*0a44ef6dSjacobs 	syslog(LOG_DEBUG, "find_exec_slot(0x%8.8x): after %d, no slots",
603*0a44ef6dSjacobs 			exec_table, i);
6047c478bd9Sstevel@tonic-gate 	return (0);
6057c478bd9Sstevel@tonic-gate }
606