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