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