#include "lpsched.h"
#include "ctype.h"
#include "sys/stat.h"
#include <syslog.h>
#define SHOULD_NOTIFY(PRS) \
( \
(PRS)->request->actions & (ACT_MAIL|ACT_WRITE|ACT_NOTIFY)\
|| (PRS)->request->alert \
)
static char * geterrbuf ( RSTATUS * );
void
dowait (void)
{
int exited,
killed,
canned,
i;
EXEC *ep;
char *errbuf = NULL;
register RSTATUS *prs;
register PSTATUS *pps;
register ALERT *pas;
syslog(LOG_DEBUG, "dowait(%d)", DoneChildren);
while (DoneChildren > 0) {
DoneChildren--;
for (i = 0; (ep = Exec_Table[i]) != NULL; i++)
if (ep->pid == -99)
break;
syslog(LOG_DEBUG, "dowait(): 0x%8.8x", ep);
if (Exec_Table[i] == NULL)
continue;
syslog(LOG_DEBUG, "dowait(): cleaning up 0x%8.8x", ep);
ep->pid = 0;
ep->key = 0;
if (ep->md)
DROP_MD(ep->md);
killed = KILLED(ep->status);
exited = EXITED(ep->status);
syslog(LOG_DEBUG, "dowait(): type %d, killed %d, exited %d",
ep->type, killed, exited);
switch (ep->type) {
case EX_INTERF:
pps = ep->ex.printer;
prs = pps->request;
pps->request = 0;
pps->status &= ~PS_BUSY;
if (0 <= exited && exited < EXEC_EXIT_USER) {
pps->status &= ~PS_FAULTED;
if (pps->alert->active)
cancel_alert (A_PRINTER, pps);
}
canned = 0;
if (killed == SIGTERM) {
if (prs->request->outcome & RS_CANCELLED)
canned = 1;
if (
canned
|| pps->status & (PS_DISABLED|PS_FAULTED)
|| prs->request->outcome & RS_STOPPED
|| Shutdown
)
killed = 0;
}
errbuf = geterrbuf(prs);
if (
errbuf
|| (0 < exited && exited <= EXEC_EXIT_USER)
|| killed
) {
if (exited != EXIT_RETRY) {
prs->request->outcome |= RS_FAILED;
}
prs->request->outcome |= RS_NOTIFY;
notify (prs, errbuf, killed, exited, 0);
if (errbuf)
Free (errbuf);
} else if (canned) {
if (SHOULD_NOTIFY(prs))
prs->request->outcome |= RS_NOTIFY;
notify (prs, (char *)0, 0, 0, 0);
} else if (exited == 0) {
prs->request->outcome |= RS_PRINTED;
if (SHOULD_NOTIFY(prs))
prs->request->outcome |= RS_NOTIFY;
notify (prs, (char *)0, 0, 0, 0);
}
switch (exited) {
case EXEC_EXIT_FAULT:
printer_fault (pps, prs, 0, 0);
break;
case EXEC_EXIT_HUP:
printer_fault (pps, prs, HANGUP_FAULT, 0);
break;
case EXEC_EXIT_INTR:
printer_fault (pps, prs, INTERRUPT_FAULT, 0);
break;
case EXEC_EXIT_PIPE:
printer_fault (pps, prs, PIPE_FAULT, 0);
break;
case EXEC_EXIT_EXIT:
note (
"Bad exit from interface program for printer %s: %d\n",
pps->printer->name,
ep->Errno
);
printer_fault (pps, prs, EXIT_FAULT, 0);
break;
case EXEC_EXIT_NPORT:
printer_fault (pps, prs, OPEN_FAULT, ep->Errno);
break;
case EXEC_EXIT_TMOUT:
printer_fault (pps, prs, TIMEOUT_FAULT, 0);
break;
case EXEC_EXIT_NOPEN:
errno = ep->Errno;
note (
"Failed to open a print service file (%s).\n",
PERROR
);
break;
case EXEC_EXIT_NEXEC:
errno = ep->Errno;
note (
"Failed to exec child process (%s).\n",
PERROR
);
break;
case EXEC_EXIT_NOMEM:
mallocfail ();
break;
case EXEC_EXIT_NFORK:
errno = ep->Errno;
note (
"Failed to fork child process (%s).\n",
PERROR
);
break;
case EXEC_EXIT_NPUSH:
printer_fault (pps, prs, PUSH_FAULT, ep->Errno);
break;
default:
if ((exited & EXEC_EXIT_NMASK) == EXEC_EXIT_NDIAL)
dial_problem (
pps,
prs,
exited & ~EXEC_EXIT_NMASK
);
else if (
exited < -1
|| exited > EXEC_EXIT_USER
)
note (
"Bad exit from exec() for printer %s: %d\n",
pps->printer->name,
exited
);
break;
}
if (
(pps->status & PS_FAULTED)
&& !STREQU(pps->printer->fault_rec, NAME_WAIT)
&& !(pps->status & (PS_LATER|PS_DISABLED))
) {
load_str (&pps->dis_reason, CUZ_STOPPED);
schedule (EV_LATER, WHEN_PRINTER, EV_ENABLE, pps);
}
prs->request->outcome &= ~(RS_PRINTING|RS_STOPPED);
if (prs->printer->status & (PS_FAULTED|PS_DISABLED|PS_LATER))
(void)queue_repel (prs->printer, 0, (qchk_fnc_type)0);
if (
prs->printer != pps
)
schedule (EV_INTERF, prs->printer);
check_request (prs);
if (!(pps->status & (PS_FAULTED|PS_DISABLED|PS_LATER)))
queue_attract (pps, qchk_waiting, 1);
break;
case EX_SLOWF:
prs = ep->ex.request;
ep->ex.request = 0;
prs->exec = 0;
prs->request->outcome &= ~RS_FILTERING;
canned = 0;
if (killed == SIGTERM){
if (prs->request->outcome & RS_CANCELLED)
canned = 1;
if (
canned
|| prs->request->outcome & RS_STOPPED
|| Shutdown
)
killed = 0;
}
errbuf = geterrbuf(prs);
if (prs->request->outcome
& (RS_REFILTER | RS_STOPPED)) {
if (errbuf) {
Free(errbuf);
errbuf = NULL;
}
}
if (
errbuf
|| 0 < exited && exited <= EXEC_EXIT_USER
|| killed
) {
prs->request->outcome |= RS_FAILED;
prs->request->outcome |= RS_NOTIFY;
notify (prs, errbuf, killed, exited, 1);
if (errbuf)
Free (errbuf);
} else if (canned) {
if (SHOULD_NOTIFY(prs))
prs->request->outcome |= RS_NOTIFY;
notify (prs, (char *)0, 0, 0, 1);
} else if (exited == 0) {
prs->request->outcome |= RS_FILTERED;
} else if (exited == -1) {
;
} else if (exited == EXEC_EXIT_NOPEN) {
errno = ep->Errno;
note (
"Failed to open a print service file (%s).\n",
PERROR
);
} else if (exited == EXEC_EXIT_NEXEC) {
errno = ep->Errno;
note (
"Failed to exec child process (%s).\n",
PERROR
);
} else if (exited == EXEC_EXIT_NOMEM) {
mallocfail ();
}
prs->request->outcome &= ~RS_STOPPED;
schedule (EV_INTERF, prs->printer);
if (
prs->request->outcome & RS_REFILTER
)
schedule (EV_SLOWF, prs);
else
schedule (EV_SLOWF, (RSTATUS *)0);
check_request (prs);
break;
case EX_NOTIFY:
prs = ep->ex.request;
ep->ex.request = 0;
prs->exec = 0;
prs->request->outcome &= ~RS_NOTIFYING;
if (!Shutdown || !killed)
prs->request->outcome &= ~RS_NOTIFY;
schedule (EV_NOTIFY, (RSTATUS *)0);
check_request (prs);
break;
case EX_ALERT:
pas = ep->ex.printer->alert;
goto CleanUpAlert;
case EX_FALERT:
pas = ep->ex.form->alert;
goto CleanUpAlert;
case EX_PALERT:
pas = ep->ex.pwheel->alert;
CleanUpAlert:
if (Shutdown)
break;
if (ep->flags & EXF_RESTART) {
ep->flags &= ~(EXF_RESTART);
if (exec(ep->type, ep->ex.form) == 0) {
pas->active = 1;
break;
}
}
(void)Unlink (pas->msgfile);
break;
}
}
return;
}
static char *
geterrbuf(RSTATUS *prs)
{
register char *cp;
int fd,
n;
char *buf = 0,
*file;
struct stat statbuf;
if (!prs) return(NULL);
file = makereqerr(prs);
if (
Stat(file, &statbuf) == 0
&& statbuf.st_size
&& (fd = Open(file, O_RDONLY)) != -1
) {
lp_alloc_fail_handler = 0;
if ((buf = Malloc(statbuf.st_size + 1)))
if ((n = Read(fd, buf, statbuf.st_size)) > 0) {
buf[n] = 0;
for (cp = buf; *cp && isspace(*cp); cp++)
;
if (!*cp) {
Free (buf);
buf = 0;
}
} else {
Free (buf);
buf = 0;
}
lp_alloc_fail_handler = mallocfail;
Close(fd);
}
if (file)
Free (file);
return (buf);
}
void
check_request(RSTATUS *prs)
{
if (prs->request->outcome & RS_DONE) {
unqueue_form (prs);
unqueue_pwheel (prs);
putrequest (prs->req_file, prs->request);
if (!(prs->request->outcome & (RS_ACTIVE | RS_NOTIFY))) {
rmfiles (prs, 1);
free_rstatus (prs);
}
}
return;
}
void
check_children(void)
{
register int i;
for (i = 0; Exec_Table[i] != NULL; i++)
if (Exec_Table[i]->pid > 0)
break;
if (Exec_Table[i] == NULL)
Shutdown = 2;
}