Home | History | Annotate | Download | only in lpsched
      1     0  stevel /*
      2     0  stevel  * CDDL HEADER START
      3     0  stevel  *
      4     0  stevel  * The contents of this file are subject to the terms of the
      5  3125  jacobs  * Common Development and Distribution License (the "License").
      6  3125  jacobs  * You may not use this file except in compliance with the License.
      7     0  stevel  *
      8     0  stevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9     0  stevel  * or http://www.opensolaris.org/os/licensing.
     10     0  stevel  * See the License for the specific language governing permissions
     11     0  stevel  * and limitations under the License.
     12     0  stevel  *
     13     0  stevel  * When distributing Covered Code, include this CDDL HEADER in each
     14     0  stevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15     0  stevel  * If applicable, add the following below this CDDL HEADER, with the
     16     0  stevel  * fields enclosed by brackets "[]" replaced with your own identifying
     17     0  stevel  * information: Portions Copyright [yyyy] [name of copyright owner]
     18     0  stevel  *
     19     0  stevel  * CDDL HEADER END
     20     0  stevel  */
     21  3125  jacobs 
     22     0  stevel /*
     23  3125  jacobs  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
     24     0  stevel  * Use is subject to license terms.
     25     0  stevel  */
     26     0  stevel 
     27     0  stevel /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
     28     0  stevel /*	  All Rights Reserved  	*/
     29     0  stevel 
     30     0  stevel 
     31  3125  jacobs #pragma ident	"%Z%%M%	%I%	%E% SMI"
     32     0  stevel 
     33     0  stevel #include "stdarg.h"
     34     0  stevel #include "lpsched.h"
     35     0  stevel #include <syslog.h>
     36     0  stevel 
     37     0  stevel extern int isStartingForms;
     38     0  stevel 
     39     0  stevel typedef struct later {
     40     0  stevel 	struct later *		next;
     41     0  stevel 	int			event,
     42     0  stevel 				ticks;
     43     0  stevel 	union arg {
     44     0  stevel 		PSTATUS *		printer;
     45     0  stevel 		RSTATUS *		request;
     46     0  stevel 		FSTATUS *		form;
     47     0  stevel 	}			arg;
     48     0  stevel }			LATER;
     49     0  stevel 
     50     0  stevel static LATER		LaterHead	= { 0 },
     51     0  stevel 			TempHead;
     52     0  stevel 
     53     0  stevel static void		ev_interf(PSTATUS *);
     54     0  stevel static void		ev_message(PSTATUS *);
     55     0  stevel static void		ev_form_message(FSTATUS *);
     56     0  stevel static int		ev_slowf(RSTATUS *);
     57     0  stevel static int		ev_notify(RSTATUS *);
     58     0  stevel 
     59  3125  jacobs static EXEC		*find_exec_slot(EXEC **);
     60     0  stevel 
     61     0  stevel static char *_event_name(int event)
     62     0  stevel {
     63     0  stevel 	static char *_names[] = {
     64     0  stevel 	"", "EV_SLOWF", "EV_INTERF", "EV_NOTIFY", "EV_LATER", "EV_ALARM",
     65  3125  jacobs 	"EV_MESSAGE", "EV_ENABLE", "EV_FORM_MESSAGE", NULL };
     66     0  stevel 
     67  3125  jacobs 	if ((event < 0) || (event > EV_FORM_MESSAGE))
     68     0  stevel 		return ("BAD_EVENT");
     69     0  stevel 	else
     70     0  stevel 		return (_names[event]);
     71     0  stevel }
     72     0  stevel 
     73     0  stevel /*
     74     0  stevel  * schedule() - SCHEDULE BY EVENT
     75     0  stevel  */
     76     0  stevel 
     77     0  stevel /*VARARGS1*/
     78     0  stevel void
     79     0  stevel schedule(int event, ...)
     80     0  stevel {
     81     0  stevel 	va_list			ap;
     82     0  stevel 
     83     0  stevel 	LATER *			plprev;
     84     0  stevel 	LATER *			pl;
     85     0  stevel 	LATER *			plnext	= 0;
     86     0  stevel 
     87     0  stevel 	register PSTATUS *	pps;
     88     0  stevel 	register RSTATUS *	prs;
     89     0  stevel 	register FSTATUS *	pfs;
     90     0  stevel 
     91  3125  jacobs 	int i;
     92     0  stevel 	/*
     93     0  stevel 	 * If we're in the process of shutting down, don't
     94     0  stevel 	 * schedule anything.
     95     0  stevel 	 */
     96     0  stevel 	syslog(LOG_DEBUG, "schedule(%s)", _event_name(event));
     97     0  stevel 
     98     0  stevel 	if (Shutdown)
     99     0  stevel 		return;
    100     0  stevel 
    101     0  stevel 	va_start (ap, event);
    102     0  stevel 
    103     0  stevel 	/*
    104     0  stevel 	 * If we're still in the process of starting up, don't start
    105     0  stevel 	 * anything! Schedule it for one tick later. While we're starting
    106     0  stevel 	 * ticks aren't counted, so the events won't be started.
    107     0  stevel 	 * HOWEVER, with a count of 1, a single EV_ALARM after we're
    108     0  stevel 	 * finished starting will be enough to clear all things scheduled
    109     0  stevel 	 * for later.
    110     0  stevel 	 */
    111     0  stevel 	if (Starting) {
    112     0  stevel 		switch (event) {
    113     0  stevel 
    114     0  stevel 		case EV_INTERF:
    115     0  stevel 		case EV_ENABLE:
    116     0  stevel 			pps = va_arg(ap, PSTATUS *);
    117     0  stevel 			schedule (EV_LATER, 1, event, pps);
    118     0  stevel 			goto Return;
    119     0  stevel 
    120     0  stevel 		case EV_SLOWF:
    121     0  stevel 		case EV_NOTIFY:
    122     0  stevel 			prs = va_arg(ap, RSTATUS *);
    123     0  stevel 			schedule (EV_LATER, 1, event, prs);
    124     0  stevel 			goto Return;
    125     0  stevel 
    126     0  stevel 		case EV_MESSAGE:
    127     0  stevel 			pps = va_arg(ap, PSTATUS *);
    128     0  stevel 			schedule (EV_LATER, 1, event, pps);
    129     0  stevel 			goto Return;
    130     0  stevel 
    131     0  stevel 		case EV_FORM_MESSAGE:
    132     0  stevel 			pfs = va_arg(ap, FSTATUS *);
    133     0  stevel 			schedule (EV_LATER, 1, event, pfs);
    134     0  stevel 			goto Return;
    135     0  stevel 
    136     0  stevel 		case EV_LATER:
    137     0  stevel 			/*
    138     0  stevel 			 * This is okay--in fact it may be us!
    139     0  stevel 			 */
    140     0  stevel 			break;
    141     0  stevel 
    142     0  stevel 		case EV_ALARM:
    143     0  stevel 			/*
    144     0  stevel 			 * The alarm will go off again, hold off for now.
    145     0  stevel 			 */
    146     0  stevel 			goto Return;
    147     0  stevel 
    148     0  stevel 		}
    149     0  stevel 	}
    150     0  stevel 
    151     0  stevel 	/*
    152     0  stevel 	 * Schedule something:
    153     0  stevel 	 */
    154     0  stevel 	switch (event) {
    155     0  stevel 
    156     0  stevel 	case EV_INTERF:
    157     0  stevel 		if ((pps = va_arg(ap, PSTATUS *)) != NULL)
    158     0  stevel 			ev_interf (pps);
    159     0  stevel 
    160     0  stevel 		else
    161  3125  jacobs 			for (i = 0; PStatus != NULL && PStatus[i] != NULL; i++)
    162  3125  jacobs 				ev_interf (PStatus[i]);
    163     0  stevel 
    164     0  stevel 		break;
    165     0  stevel 
    166     0  stevel 	/*
    167     0  stevel 	 * The EV_ENABLE event is used to get a printer going again
    168     0  stevel 	 * after waiting for a fault to be cleared. We used to use
    169     0  stevel 	 * just the EV_INTERF event, but this wasn't enough: For
    170     0  stevel 	 * requests that can go on several different printers (e.g.
    171     0  stevel 	 * queued for class, queued for ``any''), a printer is
    172     0  stevel 	 * arbitrarily assigned. The EV_INTERF event just checks
    173     0  stevel 	 * assignments, not possibilities, so a printer with no
    174     0  stevel 	 * assigned requests but still eligible to handle one or
    175     0  stevel 	 * more requests would never automatically start up again after
    176     0  stevel 	 * a fault. The EV_ENABLE event calls "enable()" which eventually
    177     0  stevel 	 * gets around to invoking the EV_INTERF event. However, it first
    178     0  stevel 	 * calls "queue_attract()" to get an eligible request assigned
    179     0  stevel 	 * so that things proceed. This also makes sense from the
    180     0  stevel 	 * following standpoint: The documented method of getting a
    181     0  stevel 	 * printer going, while it is waiting for auto-retry, is to
    182     0  stevel 	 * manually issue the enable command!
    183     0  stevel 	 *
    184     0  stevel 	 * Note: "enable()" will destroy the current record of the fault,
    185     0  stevel 	 * so if the fault is still with us any new alert will not include
    186     0  stevel 	 * the history of each repeated fault. This is a plus and a minus,
    187     0  stevel 	 * usually a minus: While a repeated fault may occasionally show
    188     0  stevel 	 * a varied record, usually the same reason is given each time;
    189     0  stevel 	 * before switching to EV_ENABLE we typically saw a boring, long
    190     0  stevel 	 * list of identical reasons.
    191     0  stevel 	 */
    192     0  stevel 	case EV_ENABLE:
    193     0  stevel 		if ((pps = va_arg(ap, PSTATUS *)) != NULL)
    194     0  stevel 			enable (pps);
    195     0  stevel 		else
    196  3125  jacobs 			for (i = 0; PStatus != NULL && PStatus[i] != NULL; i++)
    197  3125  jacobs 				enable (PStatus[i]);
    198     0  stevel 		break;
    199     0  stevel 
    200     0  stevel 	case EV_SLOWF:
    201     0  stevel 		if ((prs = va_arg(ap, RSTATUS *)) != NULL)
    202     0  stevel 			(void) ev_slowf (prs);
    203     0  stevel 		else
    204     0  stevel 			for (prs = Request_List; prs && ev_slowf(prs) != -1;
    205     0  stevel 				prs = prs->next);
    206     0  stevel 		break;
    207     0  stevel 
    208     0  stevel 	case EV_NOTIFY:
    209     0  stevel 		if ((prs = va_arg(ap, RSTATUS *)) != NULL)
    210     0  stevel 			(void) ev_notify (prs);
    211     0  stevel 		else
    212     0  stevel 			for (prs = Request_List; prs && ev_notify(prs) != -1;
    213     0  stevel 				prs = prs->next);
    214     0  stevel 		break;
    215     0  stevel 
    216     0  stevel 	case EV_MESSAGE:
    217     0  stevel 		pps = va_arg(ap, PSTATUS *);
    218     0  stevel 		ev_message(pps);
    219     0  stevel 		break;
    220     0  stevel 
    221     0  stevel 	case EV_FORM_MESSAGE:
    222     0  stevel 		pfs = va_arg(ap, FSTATUS *);
    223     0  stevel 		ev_form_message(pfs);
    224     0  stevel 		break;
    225     0  stevel 
    226     0  stevel 	case EV_LATER:
    227     0  stevel 		pl = (LATER *)Malloc(sizeof (LATER));
    228     0  stevel 
    229     0  stevel 		if (!LaterHead.next)
    230     0  stevel 			alarm (CLOCK_TICK);
    231     0  stevel 
    232     0  stevel 		pl->next = LaterHead.next;
    233     0  stevel 		LaterHead.next = pl;
    234     0  stevel 
    235     0  stevel 		pl->ticks = va_arg(ap, int);
    236     0  stevel 		pl->event = va_arg(ap, int);
    237     0  stevel 		switch (pl->event) {
    238     0  stevel 
    239     0  stevel 		case EV_MESSAGE:
    240     0  stevel 		case EV_INTERF:
    241     0  stevel 		case EV_ENABLE:
    242     0  stevel 			pl->arg.printer = va_arg(ap, PSTATUS *);
    243     0  stevel 			if (pl->arg.printer)
    244     0  stevel 				pl->arg.printer->status |= PS_LATER;
    245     0  stevel 			break;
    246     0  stevel 
    247     0  stevel 		case EV_FORM_MESSAGE:
    248     0  stevel 			pl->arg.form = va_arg(ap, FSTATUS *);
    249     0  stevel 			break;
    250     0  stevel 
    251     0  stevel 		case EV_SLOWF:
    252     0  stevel 		case EV_NOTIFY:
    253     0  stevel 			pl->arg.request = va_arg(ap, RSTATUS *);
    254     0  stevel 			break;
    255     0  stevel 
    256     0  stevel 		}
    257     0  stevel 		break;
    258     0  stevel 
    259     0  stevel 	case EV_ALARM:
    260     0  stevel 		Sig_Alrm = 0;
    261     0  stevel 
    262     0  stevel 		/*
    263     0  stevel 		 * The act of scheduling some of the ``laters'' may
    264     0  stevel 		 * cause new ``laters'' to be added to the list.
    265     0  stevel 		 * To ease the handling of the linked list, we first
    266     0  stevel 		 * run through the list and move all events ready to
    267     0  stevel 		 * be scheduled to another list. Then we schedule the
    268     0  stevel 		 * events off the new list. This leaves the main ``later''
    269     0  stevel 		 * list ready for new events.
    270     0  stevel 		 */
    271     0  stevel 		TempHead.next = 0;
    272     0  stevel 		for (pl = (plprev = &LaterHead)->next; pl; pl = plnext) {
    273     0  stevel 			plnext = pl->next;
    274     0  stevel 			if (--pl->ticks)
    275     0  stevel 				plprev = pl;
    276     0  stevel 			else {
    277     0  stevel 				plprev->next = plnext;
    278     0  stevel 
    279     0  stevel 				pl->next = TempHead.next;
    280     0  stevel 				TempHead.next = pl;
    281     0  stevel 			}
    282     0  stevel 		}
    283     0  stevel 
    284     0  stevel 		for (pl = TempHead.next; pl; pl = plnext) {
    285     0  stevel 			plnext = pl->next;
    286     0  stevel 			switch (pl->event) {
    287     0  stevel 
    288     0  stevel 			case EV_MESSAGE:
    289     0  stevel 			case EV_INTERF:
    290     0  stevel 			case EV_ENABLE:
    291     0  stevel 				pl->arg.printer->status &= ~PS_LATER;
    292     0  stevel 				schedule (pl->event, pl->arg.printer);
    293     0  stevel 				break;
    294     0  stevel 
    295     0  stevel 			case EV_FORM_MESSAGE:
    296     0  stevel 				schedule (pl->event, pl->arg.form);
    297     0  stevel 				break;
    298     0  stevel 
    299     0  stevel 			case EV_SLOWF:
    300     0  stevel 			case EV_NOTIFY:
    301     0  stevel 				schedule (pl->event, pl->arg.request);
    302     0  stevel 				break;
    303     0  stevel 
    304     0  stevel 			}
    305     0  stevel 			Free ((char *)pl);
    306     0  stevel 		}
    307     0  stevel 
    308     0  stevel 		if (LaterHead.next)
    309     0  stevel 			alarm (CLOCK_TICK);
    310     0  stevel 		break;
    311     0  stevel 
    312     0  stevel 	}
    313     0  stevel 
    314     0  stevel Return:	va_end (ap);
    315     0  stevel 
    316     0  stevel 	return;
    317     0  stevel }
    318     0  stevel 
    319     0  stevel /*
    320     0  stevel  * maybe_schedule() - MAYBE SCHEDULE SOMETHING FOR A REQUEST
    321     0  stevel  */
    322     0  stevel 
    323     0  stevel void
    324     0  stevel maybe_schedule(RSTATUS *prs)
    325     0  stevel {
    326     0  stevel 	/*
    327     0  stevel 	 * Use this routine if a request has been changed by some
    328     0  stevel 	 * means so that it is ready for filtering or printing,
    329     0  stevel 	 * but a previous filtering or printing process for this
    330     0  stevel 	 * request MAY NOT have finished yet. If a process is still
    331     0  stevel 	 * running, then the cleanup of that process will cause
    332     0  stevel 	 * "schedule()" to be called. Calling "schedule()" regardless
    333     0  stevel 	 * might make another request slip ahead of this request.
    334     0  stevel 	 */
    335     0  stevel 
    336     0  stevel 	/*
    337     0  stevel 	 * "schedule()" will refuse if this request is filtering.
    338     0  stevel 	 * It will also refuse if the request ``was'' filtering
    339     0  stevel 	 * but the filter was terminated in "validate_request()",
    340     0  stevel 	 * because we can not have heard from the filter process
    341     0  stevel 	 * yet. Also, when called with a particular request,
    342     0  stevel 	 * "schedule()" won't slip another request ahead.
    343     0  stevel 	 */
    344     0  stevel 	if (NEEDS_FILTERING(prs))
    345     0  stevel 		schedule (EV_SLOWF, prs);
    346     0  stevel 
    347     0  stevel 	else if (!(prs->request->outcome & RS_STOPPED))
    348     0  stevel 		schedule (EV_INTERF, prs->printer);
    349     0  stevel 
    350     0  stevel 	return;
    351     0  stevel }
    352     0  stevel 
    353     0  stevel static void
    354     0  stevel ev_message(PSTATUS *pps)
    355     0  stevel {
    356     0  stevel 	register RSTATUS	*prs;
    357     0  stevel 	char			toSelf;
    358     0  stevel 
    359     0  stevel 	syslog(LOG_DEBUG, "ev_message(%s)",
    360     0  stevel 	       (pps && pps->request && pps->request->req_file ?
    361     0  stevel 		pps->request->req_file : "NULL"));
    362     0  stevel 
    363     0  stevel 	toSelf = 0;
    364  3125  jacobs 	for (prs = Request_List; prs != NULL; prs = prs->next)
    365  3125  jacobs 		if (prs->printer == pps) {
    366  3125  jacobs 			note("prs (%d) pps (%d)\n", prs, pps);
    367     0  stevel 			if (!toSelf) {
    368     0  stevel 				toSelf = 1;
    369     0  stevel 				exec(EX_FAULT_MESSAGE, pps, prs);
    370     0  stevel 			}
    371  3125  jacobs 		}
    372     0  stevel }
    373     0  stevel 
    374     0  stevel static void
    375     0  stevel ev_form_message_body(FSTATUS *pfs, RSTATUS *prs, char *toSelf, char ***sysList)
    376     0  stevel {
    377  3125  jacobs 	syslog(LOG_DEBUG, "ev_form_message_body(%s, %d, 0x%x)",
    378     0  stevel 	      (pfs && pfs->form && pfs->form->name ? pfs->form->name : "NULL"),
    379  3125  jacobs 	      (toSelf ? *toSelf : 0),
    380     0  stevel 		sysList);
    381     0  stevel 
    382  3125  jacobs 	if (!*toSelf) {
    383  3125  jacobs 		*toSelf = 1;
    384  3125  jacobs 		exec(EX_FORM_MESSAGE, pfs);
    385  3125  jacobs 	}
    386     0  stevel }
    387     0  stevel 
    388     0  stevel static void
    389     0  stevel ev_form_message(FSTATUS *pfs)
    390     0  stevel {
    391     0  stevel 	register RSTATUS	*prs;
    392     0  stevel 	char **sysList;
    393     0  stevel 	char toSelf;
    394     0  stevel 
    395     0  stevel 	syslog(LOG_DEBUG, "ev_form_message(%s)",
    396     0  stevel 	       (pfs && pfs->form && pfs->form->name ?
    397     0  stevel 		pfs->form->name : "NULL"));
    398     0  stevel 
    399     0  stevel 	toSelf = 0;
    400     0  stevel 	sysList = NULL;
    401  3125  jacobs 
    402  3125  jacobs 	for (prs = Request_List; prs != NULL; prs = prs->next)
    403  3125  jacobs 		if (prs->form == pfs)
    404  3125  jacobs 			ev_form_message_body(pfs, prs, &toSelf, &sysList);
    405  3125  jacobs 
    406     0  stevel 	if (NewRequest && (NewRequest->form == pfs))
    407     0  stevel 		ev_form_message_body(pfs, NewRequest, &toSelf, &sysList);
    408     0  stevel 
    409     0  stevel 	freelist(sysList);
    410     0  stevel }
    411     0  stevel 
    412     0  stevel /*
    413     0  stevel  * ev_interf() - CHECK AND EXEC INTERFACE PROGRAM
    414     0  stevel  */
    415     0  stevel 
    416     0  stevel /*
    417     0  stevel  * Macro to check if the request needs a print wheel or character set (S)
    418     0  stevel  * and the printer (P) has it mounted or can select it. Since the request
    419     0  stevel  * has already been approved for the printer, we don't have to check the
    420     0  stevel  * character set, just the mount. If the printer has selectable character
    421     0  stevel  * sets, there's nothing to check so the request is ready to print.
    422     0  stevel  */
    423     0  stevel #define	MATCH(PRS, PPS) (\
    424     0  stevel 		!(PPS)->printer->daisy || \
    425     0  stevel 		!(PRS)->pwheel_name || \
    426     0  stevel 		!((PRS)->status & RSS_PWMAND) || \
    427     0  stevel 		STREQU((PRS)->pwheel_name, NAME_ANY) || \
    428     0  stevel 		((PPS)->pwheel_name && \
    429     0  stevel 		STREQU((PPS)->pwheel_name, (PRS)->pwheel_name)))
    430     0  stevel 
    431     0  stevel 
    432     0  stevel static void
    433     0  stevel ev_interf(PSTATUS *pps)
    434     0  stevel {
    435     0  stevel 	register RSTATUS	*prs;
    436     0  stevel 
    437     0  stevel 	syslog(LOG_DEBUG, "ev_interf(%s)",
    438     0  stevel 	       (pps && pps->request && pps->request->req_file ?
    439     0  stevel 		pps->request->req_file : "NULL"));
    440     0  stevel 
    441     0  stevel 
    442     0  stevel 	/*
    443     0  stevel 	 * If the printer isn't tied up doing something
    444     0  stevel 	 * else, and isn't disabled, see if there is a request
    445     0  stevel 	 * waiting to print on it. Note: We don't include
    446     0  stevel 	 * PS_FAULTED here, because simply having a printer
    447     0  stevel 	 * fault (without also being disabled) isn't sufficient
    448     0  stevel 	 * to keep us from trying again. (In fact, we HAVE TO
    449     0  stevel 	 * try again, to see if the fault has gone away.)
    450     0  stevel 	 *
    451     0  stevel 	 * NOTE: If the printer is faulted but the filter controlling
    452     0  stevel 	 * the printer is waiting for the fault to clear, a
    453     0  stevel 	 * request will still be attached to the printer, as
    454     0  stevel 	 * evidenced by "pps->request", so we won't try to
    455     0  stevel 	 * schedule another request!
    456     0  stevel 	 */
    457     0  stevel 	if (pps->request || pps->status & (PS_DISABLED|PS_LATER|PS_BUSY))
    458     0  stevel 		return;
    459     0  stevel 
    460  3125  jacobs 	for (prs = Request_List; prs != NULL; prs = prs->next) {
    461  3125  jacobs 		if ((prs->printer == pps) && (qchk_waiting(prs)) &&
    462  3125  jacobs 		    isFormUsableOnPrinter(pps, prs->form) && MATCH(prs, pps)) {
    463  3125  jacobs 		/*
    464  3125  jacobs 		 * Just because the printer isn't busy and the
    465  3125  jacobs 		 * request is assigned to this printer, don't get the
    466  3125  jacobs 		 * idea that the request can't be printing (RS_ACTIVE),
    467  3125  jacobs 		 * because another printer may still have the request
    468  3125  jacobs 		 * attached but we've not yet heard from the child
    469  3125  jacobs 		 * process controlling that printer.
    470  3125  jacobs 		 *
    471  3125  jacobs 		 * We have the waiting request, we have
    472  3125  jacobs 		 * the ready (local) printer. If the exec fails
    473  3125  jacobs 		 * because the fork failed, schedule a
    474  3125  jacobs 		 * try later and claim we succeeded. The
    475  3125  jacobs 		 * later attempt will sort things out,
    476  3125  jacobs 		 * e.g. will re-schedule if the fork fails
    477  3125  jacobs 		 * again.
    478  3125  jacobs 		 */
    479     0  stevel 			pps->request = prs;
    480     0  stevel 			if (exec(EX_INTERF, pps) == 0) {
    481     0  stevel 				pps->status |= PS_BUSY;
    482     0  stevel 				return;
    483     0  stevel 			}
    484     0  stevel 			pps->request = 0;
    485     0  stevel 			if (errno == EAGAIN) {
    486     0  stevel 				load_str (&pps->dis_reason, CUZ_NOFORK);
    487     0  stevel 				schedule (EV_LATER, WHEN_FORK, EV_ENABLE, pps);
    488     0  stevel 				return;
    489     0  stevel 			}
    490     0  stevel 		}
    491  3125  jacobs 	}
    492     0  stevel 
    493     0  stevel 	return;
    494     0  stevel }
    495     0  stevel 
    496     0  stevel /*
    497     0  stevel  * ev_slowf() - CHECK AND EXEC SLOW FILTER
    498     0  stevel  */
    499     0  stevel 
    500     0  stevel static int
    501     0  stevel ev_slowf(RSTATUS *prs)
    502     0  stevel {
    503     0  stevel 	register EXEC		*ep;
    504     0  stevel 
    505     0  stevel 	syslog(LOG_DEBUG, "ev_slowf(%s)",
    506     0  stevel 	       (prs && prs->req_file ? prs->req_file : "NULL"));
    507     0  stevel 
    508     0  stevel 	/*
    509     0  stevel 	 * Return -1 if no more can be executed (no more exec slots)
    510     0  stevel 	 * or if it's unwise to execute any more (fork failed).
    511     0  stevel 	 */
    512     0  stevel 
    513  3125  jacobs 	if (!(ep = find_exec_slot(Exec_Slow))) {
    514  3125  jacobs 		syslog(LOG_DEBUG, "ev_slowf(%s): no slot",
    515  3125  jacobs 	       		(prs && prs->req_file ? prs->req_file : "NULL"));
    516     0  stevel 		return (-1);
    517  3125  jacobs 	}
    518     0  stevel 
    519     0  stevel 	if (!(prs->request->outcome & (RS_DONE|RS_HELD|RS_ACTIVE)) &&
    520     0  stevel 	    NEEDS_FILTERING(prs)) {
    521     0  stevel 		(prs->exec = ep)->ex.request = prs;
    522     0  stevel 		if (exec(EX_SLOWF, prs) != 0) {
    523     0  stevel 			ep->ex.request = 0;
    524     0  stevel 			prs->exec = 0;
    525     0  stevel 			if (errno == EAGAIN) {
    526     0  stevel 				schedule (EV_LATER, WHEN_FORK, EV_SLOWF, prs);
    527     0  stevel 				return (-1);
    528     0  stevel 			}
    529     0  stevel 		}
    530     0  stevel 	}
    531     0  stevel 	return (0);
    532     0  stevel }
    533     0  stevel 
    534     0  stevel /*
    535     0  stevel  * ev_notify() - CHECK AND EXEC NOTIFICATION
    536     0  stevel  */
    537     0  stevel 
    538     0  stevel static int
    539     0  stevel ev_notify(RSTATUS *prs)
    540     0  stevel {
    541     0  stevel 	register EXEC		*ep;
    542     0  stevel 
    543     0  stevel 	syslog(LOG_DEBUG, "ev_notify(%s)",
    544     0  stevel 	       (prs && prs->req_file ? prs->req_file : "NULL"));
    545     0  stevel 
    546     0  stevel 	/*
    547     0  stevel 	 * Return -1 if no more can be executed (no more exec slots)
    548     0  stevel 	 * or if it's unwise to execute any more (fork failed, already
    549     0  stevel 	 * sent one to remote side).
    550     0  stevel 	 */
    551     0  stevel 
    552     0  stevel 	/*
    553     0  stevel 	 * If the job came from a remote machine, we forward the
    554     0  stevel 	 * outcome of the request to the network manager for sending
    555     0  stevel 	 * to the remote side.
    556     0  stevel 	 */
    557     0  stevel 	if (prs->request->actions & ACT_NOTIFY) {
    558     0  stevel 		if (prs->request->outcome & RS_NOTIFY) {
    559     0  stevel 			prs->request->actions &= ~ACT_NOTIFY;
    560     0  stevel 			return (0);  /* but try another request */
    561     0  stevel 		}
    562     0  stevel 	/*
    563     0  stevel 	 * If the job didn't come from a remote system,
    564     0  stevel 	 * we'll try to start a process to send the notification
    565     0  stevel 	 * to the user. But we only allow so many notifications
    566     0  stevel 	 * to run at the same time, so we may not be able to
    567     0  stevel 	 * do it.
    568     0  stevel 	 */
    569  3125  jacobs 	} else if (!(ep = find_exec_slot(Exec_Notify)))
    570     0  stevel 		return (-1);
    571     0  stevel 
    572     0  stevel 	else if (prs->request->outcome & RS_NOTIFY &&
    573     0  stevel 		!(prs->request->outcome & RS_NOTIFYING)) {
    574     0  stevel 
    575     0  stevel 		(prs->exec = ep)->ex.request = prs;
    576     0  stevel 		if (exec(EX_NOTIFY, prs) != 0) {
    577     0  stevel 			ep->ex.request = 0;
    578     0  stevel 			prs->exec = 0;
    579     0  stevel 			if (errno == EAGAIN) {
    580     0  stevel 				schedule (EV_LATER, WHEN_FORK, EV_NOTIFY, prs);
    581     0  stevel 				return (-1);
    582     0  stevel 			}
    583     0  stevel 		}
    584     0  stevel 	}
    585     0  stevel 	return (0);
    586     0  stevel }
    587     0  stevel 
    588     0  stevel 
    589     0  stevel /*
    590     0  stevel  * find_exec_slot() - FIND AVAILABLE EXEC SLOT
    591     0  stevel  */
    592     0  stevel 
    593     0  stevel static EXEC *
    594  3125  jacobs find_exec_slot(EXEC **exec_table)
    595     0  stevel {
    596  3125  jacobs 	int i;
    597     0  stevel 
    598  3125  jacobs 	for (i = 0; exec_table[i] != NULL; i++)
    599  3125  jacobs 		if (exec_table[i]->pid == 0)
    600  3125  jacobs 			return (exec_table[i]);
    601     0  stevel 
    602  3125  jacobs 	syslog(LOG_DEBUG, "find_exec_slot(0x%8.8x): after %d, no slots",
    603  3125  jacobs 			exec_table, i);
    604     0  stevel 	return (0);
    605     0  stevel }
    606