/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
#pragma ident "%Z%%M% %I% %E% SMI"
#include "stdarg.h"
#include "lpsched.h"
#include <syslog.h>
extern int isStartingForms;
typedef struct later {
int event,
union arg {
} arg;
} LATER;
static void ev_message(PSTATUS *);
static void ev_form_message(FSTATUS *);
{
static char *_names[] = {
"", "EV_SLOWF", "EV_INTERF", "EV_NOTIFY", "EV_LATER", "EV_ALARM",
return ("BAD_EVENT");
else
}
/*
* schedule() - SCHEDULE BY EVENT
*/
/*VARARGS1*/
void
{
int i;
/*
* If we're in the process of shutting down, don't
* schedule anything.
*/
if (Shutdown)
return;
/*
* If we're still in the process of starting up, don't start
* anything! Schedule it for one tick later. While we're starting
* ticks aren't counted, so the events won't be started.
* HOWEVER, with a count of 1, a single EV_ALARM after we're
* finished starting will be enough to clear all things scheduled
* for later.
*/
if (Starting) {
switch (event) {
case EV_INTERF:
case EV_ENABLE:
goto Return;
case EV_SLOWF:
case EV_NOTIFY:
goto Return;
case EV_MESSAGE:
goto Return;
case EV_FORM_MESSAGE:
goto Return;
case EV_LATER:
/*
* This is okay--in fact it may be us!
*/
break;
case EV_ALARM:
/*
* The alarm will go off again, hold off for now.
*/
goto Return;
}
}
/*
* Schedule something:
*/
switch (event) {
case EV_INTERF:
else
break;
/*
* The EV_ENABLE event is used to get a printer going again
* after waiting for a fault to be cleared. We used to use
* just the EV_INTERF event, but this wasn't enough: For
* requests that can go on several different printers (e.g.
* queued for class, queued for ``any''), a printer is
* arbitrarily assigned. The EV_INTERF event just checks
* assignments, not possibilities, so a printer with no
* assigned requests but still eligible to handle one or
* more requests would never automatically start up again after
* a fault. The EV_ENABLE event calls "enable()" which eventually
* gets around to invoking the EV_INTERF event. However, it first
* calls "queue_attract()" to get an eligible request assigned
* so that things proceed. This also makes sense from the
* following standpoint: The documented method of getting a
* printer going, while it is waiting for auto-retry, is to
* manually issue the enable command!
*
* Note: "enable()" will destroy the current record of the fault,
* so if the fault is still with us any new alert will not include
* the history of each repeated fault. This is a plus and a minus,
* usually a minus: While a repeated fault may occasionally show
* a varied record, usually the same reason is given each time;
* before switching to EV_ENABLE we typically saw a boring, long
* list of identical reasons.
*/
case EV_ENABLE:
else
break;
case EV_SLOWF:
else
break;
case EV_NOTIFY:
else
break;
case EV_MESSAGE:
break;
case EV_FORM_MESSAGE:
break;
case EV_LATER:
alarm (CLOCK_TICK);
case EV_MESSAGE:
case EV_INTERF:
case EV_ENABLE:
break;
case EV_FORM_MESSAGE:
break;
case EV_SLOWF:
case EV_NOTIFY:
break;
}
break;
case EV_ALARM:
Sig_Alrm = 0;
/*
* The act of scheduling some of the ``laters'' may
* cause new ``laters'' to be added to the list.
* To ease the handling of the linked list, we first
* run through the list and move all events ready to
* be scheduled to another list. Then we schedule the
* events off the new list. This leaves the main ``later''
* list ready for new events.
*/
else {
}
}
case EV_MESSAGE:
case EV_INTERF:
case EV_ENABLE:
break;
case EV_FORM_MESSAGE:
break;
case EV_SLOWF:
case EV_NOTIFY:
break;
}
}
alarm (CLOCK_TICK);
break;
}
return;
}
/*
* maybe_schedule() - MAYBE SCHEDULE SOMETHING FOR A REQUEST
*/
void
{
/*
* Use this routine if a request has been changed by some
* means so that it is ready for filtering or printing,
* but a previous filtering or printing process for this
* request MAY NOT have finished yet. If a process is still
* running, then the cleanup of that process will cause
* "schedule()" to be called. Calling "schedule()" regardless
* might make another request slip ahead of this request.
*/
/*
* "schedule()" will refuse if this request is filtering.
* It will also refuse if the request ``was'' filtering
* but the filter was terminated in "validate_request()",
* because we can not have heard from the filter process
* yet. Also, when called with a particular request,
* "schedule()" won't slip another request ahead.
*/
if (NEEDS_FILTERING(prs))
return;
}
static void
{
char toSelf;
toSelf = 0;
if (!toSelf) {
toSelf = 1;
}
}
}
static void
{
sysList);
if (!*toSelf) {
*toSelf = 1;
}
}
static void
{
char **sysList;
char toSelf;
toSelf = 0;
}
/*
* ev_interf() - CHECK AND EXEC INTERFACE PROGRAM
*/
/*
* Macro to check if the request needs a print wheel or character set (S)
* and the printer (P) has it mounted or can select it. Since the request
* has already been approved for the printer, we don't have to check the
* character set, just the mount. If the printer has selectable character
* sets, there's nothing to check so the request is ready to print.
*/
!(PRS)->pwheel_name || \
((PPS)->pwheel_name && \
static void
{
/*
* If the printer isn't tied up doing something
* else, and isn't disabled, see if there is a request
* waiting to print on it. Note: We don't include
* PS_FAULTED here, because simply having a printer
* fault (without also being disabled) isn't sufficient
* to keep us from trying again. (In fact, we HAVE TO
* try again, to see if the fault has gone away.)
*
* NOTE: If the printer is faulted but the filter controlling
* the printer is waiting for the fault to clear, a
* request will still be attached to the printer, as
* evidenced by "pps->request", so we won't try to
* schedule another request!
*/
return;
/*
* Just because the printer isn't busy and the
* request is assigned to this printer, don't get the
* idea that the request can't be printing (RS_ACTIVE),
* because another printer may still have the request
* attached but we've not yet heard from the child
* process controlling that printer.
*
* We have the waiting request, we have
* the ready (local) printer. If the exec fails
* because the fork failed, schedule a
* try later and claim we succeeded. The
* later attempt will sort things out,
* e.g. will re-schedule if the fork fails
* again.
*/
return;
}
return;
}
}
}
return;
}
/*
* ev_slowf() - CHECK AND EXEC SLOW FILTER
*/
static int
{
/*
* Return -1 if no more can be executed (no more exec slots)
* or if it's unwise to execute any more (fork failed).
*/
return (-1);
}
NEEDS_FILTERING(prs)) {
return (-1);
}
}
}
return (0);
}
/*
* ev_notify() - CHECK AND EXEC NOTIFICATION
*/
static int
{
/*
* Return -1 if no more can be executed (no more exec slots)
* or if it's unwise to execute any more (fork failed, already
* sent one to remote side).
*/
/*
* If the job came from a remote machine, we forward the
* outcome of the request to the network manager for sending
* to the remote side.
*/
return (0); /* but try another request */
}
/*
* If the job didn't come from a remote system,
* we'll try to start a process to send the notification
* to the user. But we only allow so many notifications
* to run at the same time, so we may not be able to
* do it.
*/
return (-1);
return (-1);
}
}
}
return (0);
}
/*
* find_exec_slot() - FIND AVAILABLE EXEC SLOT
*/
static EXEC *
{
int i;
for (i = 0; exec_table[i] != NULL; i++)
if (exec_table[i]->pid == 0)
return (exec_table[i]);
exec_table, i);
return (0);
}