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 /* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */ 31 32 #include "lpsched.h" 33 #include "ctype.h" 34 #include "sys/stat.h" 35 #include <syslog.h> 36 37 /* 38 * Macro to test if we should notify the user. 39 */ 40 #define SHOULD_NOTIFY(PRS) \ 41 ( \ 42 (PRS)->request->actions & (ACT_MAIL|ACT_WRITE|ACT_NOTIFY)\ 43 || (PRS)->request->alert \ 44 ) 45 46 static char * geterrbuf ( RSTATUS * ); 47 48 /** 49 ** dowait() - CLEAN UP CHILD THAT HAS FINISHED, RESCHEDULE ANOTHER TASK 50 **/ 51 52 void 53 dowait (void) 54 { 55 int exited, 56 killed, 57 canned, 58 i; 59 EXEC *ep; 60 char *errbuf = NULL; 61 register RSTATUS *prs; 62 register PSTATUS *pps; 63 register ALERT *pas; 64 65 syslog(LOG_DEBUG, "dowait(%d)", DoneChildren); 66 while (DoneChildren > 0) { 67 DoneChildren--; 68 69 for (i = 0; (ep = Exec_Table[i]) != NULL; i++) 70 if (ep->pid == -99) 71 break; 72 73 syslog(LOG_DEBUG, "dowait(): 0x%8.8x", ep); 74 75 if (Exec_Table[i] == NULL) /* nothing to cleanup */ 76 continue; 77 78 syslog(LOG_DEBUG, "dowait(): cleaning up 0x%8.8x", ep); 79 80 ep->pid = 0; 81 ep->key = 0; /* avoid subsequent sneaks */ 82 if (ep->md) 83 DROP_MD(ep->md); 84 85 killed = KILLED(ep->status); 86 exited = EXITED(ep->status); 87 88 syslog(LOG_DEBUG, "dowait(): type %d, killed %d, exited %d", 89 ep->type, killed, exited); 90 91 switch (ep->type) { 92 93 case EX_INTERF: 94 /* 95 * WARNING: It could be that when we get here 96 * 97 * pps->request->printer != pps 98 * 99 * because the request has been assigned to 100 * another printer. 101 */ 102 pps = ep->ex.printer; 103 prs = pps->request; 104 pps->request = 0; 105 pps->status &= ~PS_BUSY; 106 107 /* 108 * If the interface program exited cleanly 109 * or with just a user error, the printer 110 * is assumed to be working. 111 */ 112 if (0 <= exited && exited < EXEC_EXIT_USER) { 113 pps->status &= ~PS_FAULTED; 114 if (pps->alert->active) 115 cancel_alert (A_PRINTER, pps); 116 } 117 118 /* 119 * If the interface program was killed with 120 * SIGTERM, it may have been because we canceled 121 * the request, disabled the printer, or for some 122 * other reason stopped the request. 123 * If so, clear the "killed" flag because that's 124 * not the condition of importance here. 125 */ 126 canned = 0; 127 if (killed == SIGTERM) { 128 if (prs->request->outcome & RS_CANCELLED) 129 canned = 1; 130 131 if ( 132 canned 133 || pps->status & (PS_DISABLED|PS_FAULTED) 134 || prs->request->outcome & RS_STOPPED 135 || Shutdown 136 ) 137 killed = 0; 138 } 139 140 /* 141 * If there was standard error output from the 142 * interface program, or if the interface program 143 * exited with a (user) exit code, or if it got 144 * a strange signal, the user should be notified. 145 */ 146 errbuf = geterrbuf(prs); 147 if ( 148 errbuf 149 || (0 < exited && exited <= EXEC_EXIT_USER) 150 || killed 151 ) { 152 if (exited != EXIT_RETRY) { 153 prs->request->outcome |= RS_FAILED; 154 } 155 prs->request->outcome |= RS_NOTIFY; 156 notify (prs, errbuf, killed, exited, 0); 157 if (errbuf) 158 Free (errbuf); 159 160 /* 161 * If the request was canceled, call "notify()" 162 * in case we're to notify the user. 163 */ 164 } else if (canned) { 165 if (SHOULD_NOTIFY(prs)) 166 prs->request->outcome |= RS_NOTIFY; 167 notify (prs, (char *)0, 0, 0, 0); 168 169 /* 170 * If the request finished successfully, call 171 * "notify()" in case we're to notify the user. 172 */ 173 } else if (exited == 0) { 174 prs->request->outcome |= RS_PRINTED; 175 176 if (SHOULD_NOTIFY(prs)) 177 prs->request->outcome |= RS_NOTIFY; 178 notify (prs, (char *)0, 0, 0, 0); 179 } 180 181 /* 182 * If the interface program exits with an 183 * exit code higher than EXEC_EXIT_USER, it's 184 * a special case. 185 */ 186 187 switch (exited) { 188 189 case EXEC_EXIT_FAULT: 190 printer_fault (pps, prs, 0, 0); 191 break; 192 193 case EXEC_EXIT_HUP: 194 printer_fault (pps, prs, HANGUP_FAULT, 0); 195 break; 196 197 case EXEC_EXIT_INTR: 198 printer_fault (pps, prs, INTERRUPT_FAULT, 0); 199 break; 200 201 case EXEC_EXIT_PIPE: 202 printer_fault (pps, prs, PIPE_FAULT, 0); 203 break; 204 205 case EXEC_EXIT_EXIT: 206 note ( 207 "Bad exit from interface program for printer %s: %d\n", 208 pps->printer->name, 209 ep->Errno 210 ); 211 printer_fault (pps, prs, EXIT_FAULT, 0); 212 break; 213 214 case EXEC_EXIT_NPORT: 215 printer_fault (pps, prs, OPEN_FAULT, ep->Errno); 216 break; 217 218 case EXEC_EXIT_TMOUT: 219 printer_fault (pps, prs, TIMEOUT_FAULT, 0); 220 break; 221 222 case EXEC_EXIT_NOPEN: 223 errno = ep->Errno; 224 note ( 225 "Failed to open a print service file (%s).\n", 226 PERROR 227 ); 228 break; 229 230 case EXEC_EXIT_NEXEC: 231 errno = ep->Errno; 232 note ( 233 "Failed to exec child process (%s).\n", 234 PERROR 235 ); 236 break; 237 238 case EXEC_EXIT_NOMEM: 239 mallocfail (); 240 break; 241 242 case EXEC_EXIT_NFORK: 243 errno = ep->Errno; 244 note ( 245 "Failed to fork child process (%s).\n", 246 PERROR 247 ); 248 break; 249 250 case EXEC_EXIT_NPUSH: 251 printer_fault (pps, prs, PUSH_FAULT, ep->Errno); 252 break; 253 254 default: 255 if ((exited & EXEC_EXIT_NMASK) == EXEC_EXIT_NDIAL) 256 dial_problem ( 257 pps, 258 prs, 259 exited & ~EXEC_EXIT_NMASK 260 ); 261 262 else if ( 263 exited < -1 264 || exited > EXEC_EXIT_USER 265 ) 266 note ( 267 "Bad exit from exec() for printer %s: %d\n", 268 pps->printer->name, 269 exited 270 ); 271 272 break; 273 } 274 275 /* 276 * Being in the "dowait()" routine means the 277 * interface (and fast filter!) have stopped. 278 * If we have a fault and we're expected to try 279 * again later, make sure we try again later. 280 */ 281 if ( 282 (pps->status & PS_FAULTED) 283 && !STREQU(pps->printer->fault_rec, NAME_WAIT) 284 && !(pps->status & (PS_LATER|PS_DISABLED)) 285 ) { 286 load_str (&pps->dis_reason, CUZ_STOPPED); 287 schedule (EV_LATER, WHEN_PRINTER, EV_ENABLE, pps); 288 } 289 290 prs->request->outcome &= ~(RS_PRINTING|RS_STOPPED); 291 292 /* 293 * If the printer to which this request was 294 * assigned is not able to handle requests now, 295 * push waiting requests off on to another 296 * printer. 297 */ 298 if (prs->printer->status & (PS_FAULTED|PS_DISABLED|PS_LATER)) 299 (void)queue_repel (prs->printer, 0, (qchk_fnc_type)0); 300 301 /* 302 * If the request is now assigned to a different 303 * printer, call "schedule()" to fire up an 304 * interface. If this request also happens to 305 * be dead, or in need of refiltering, it won't 306 * get scheduled. 307 */ 308 if ( 309 prs->printer != pps 310 ) 311 schedule (EV_INTERF, prs->printer); 312 313 check_request (prs); 314 315 /* 316 * Attract the FIRST request that is waiting to 317 * print to this printer, unless the printer isn't 318 * ready to print another request. We do this 319 * even though requests may already be assigned 320 * to this printer, because a request NOT assigned 321 * might be ahead of them in the queue. 322 */ 323 if (!(pps->status & (PS_FAULTED|PS_DISABLED|PS_LATER))) 324 queue_attract (pps, qchk_waiting, 1); 325 326 break; 327 328 case EX_SLOWF: 329 prs = ep->ex.request; 330 ep->ex.request = 0; 331 prs->exec = 0; 332 prs->request->outcome &= ~RS_FILTERING; 333 334 /* 335 * If the slow filter was killed with SIGTERM, 336 * it may have been because we canceled the 337 * request, stopped the filtering, or put a 338 * change hold on the request. If so, clear 339 * the "killed" flag because that's not the 340 * condition of importance. 341 */ 342 canned = 0; 343 if (killed == SIGTERM){ 344 if (prs->request->outcome & RS_CANCELLED) 345 canned = 1; 346 347 if ( 348 canned 349 || prs->request->outcome & RS_STOPPED 350 || Shutdown 351 ) 352 killed = 0; 353 } 354 355 /* 356 * If there was standard error output from the 357 * slow filter, or if the interface program exited 358 * with a non-zero exit code, the user should 359 * be notified. 360 */ 361 errbuf = geterrbuf(prs); 362 if (prs->request->outcome 363 & (RS_REFILTER | RS_STOPPED)) { 364 if (errbuf) { 365 Free(errbuf); 366 errbuf = NULL; 367 } 368 } 369 if ( 370 errbuf 371 || 0 < exited && exited <= EXEC_EXIT_USER 372 || killed 373 ) { 374 prs->request->outcome |= RS_FAILED; 375 prs->request->outcome |= RS_NOTIFY; 376 notify (prs, errbuf, killed, exited, 1); 377 if (errbuf) 378 Free (errbuf); 379 380 381 /* 382 * If the request was canceled, call "notify()" 383 * in case we're to notify the user. 384 */ 385 } else if (canned) { 386 if (SHOULD_NOTIFY(prs)) 387 prs->request->outcome |= RS_NOTIFY; 388 notify (prs, (char *)0, 0, 0, 1); 389 390 /* 391 * If the slow filter exited normally, mark 392 * the request as finished slow filtering. 393 */ 394 } else if (exited == 0) { 395 prs->request->outcome |= RS_FILTERED; 396 397 } else if (exited == -1) { 398 /*EMPTY*/; 399 400 } else if (exited == EXEC_EXIT_NOPEN) { 401 errno = ep->Errno; 402 note ( 403 "Failed to open a print service file (%s).\n", 404 PERROR 405 ); 406 407 } else if (exited == EXEC_EXIT_NEXEC) { 408 errno = ep->Errno; 409 note ( 410 "Failed to exec child process (%s).\n", 411 PERROR 412 ); 413 414 } else if (exited == EXEC_EXIT_NOMEM) { 415 mallocfail (); 416 417 } 418 419 prs->request->outcome &= ~RS_STOPPED; 420 421 schedule (EV_INTERF, prs->printer); 422 if ( 423 prs->request->outcome & RS_REFILTER 424 ) 425 schedule (EV_SLOWF, prs); 426 else 427 schedule (EV_SLOWF, (RSTATUS *)0); 428 429 check_request (prs); 430 break; 431 432 case EX_NOTIFY: 433 prs = ep->ex.request; 434 ep->ex.request = 0; 435 prs->exec = 0; 436 437 prs->request->outcome &= ~RS_NOTIFYING; 438 if (!Shutdown || !killed) 439 prs->request->outcome &= ~RS_NOTIFY; 440 441 /* 442 * Now that this notification process slot 443 * has opened up, schedule the next notification 444 * (if any). 445 */ 446 schedule (EV_NOTIFY, (RSTATUS *)0); 447 448 check_request (prs); 449 break; 450 451 case EX_ALERT: 452 pas = ep->ex.printer->alert; 453 goto CleanUpAlert; 454 455 case EX_FALERT: 456 pas = ep->ex.form->alert; 457 goto CleanUpAlert; 458 459 case EX_PALERT: 460 pas = ep->ex.pwheel->alert; 461 /* 462 * CAUTION: It may well be that we've removed 463 * the print wheel by the time we get here. 464 * Only the alert structure (and exec structure) 465 * can be considered okay. 466 */ 467 468 CleanUpAlert: 469 if (Shutdown) 470 break; 471 472 if (ep->flags & EXF_RESTART) { 473 ep->flags &= ~(EXF_RESTART); 474 if (exec(ep->type, ep->ex.form) == 0) { 475 pas->active = 1; 476 break; 477 } 478 } 479 (void)Unlink (pas->msgfile); 480 break; 481 482 } 483 } 484 485 return; 486 } 487 488 489 /** 490 ** geterrbuf() - READ NON-BLANK STANDARD ERROR OUTPUT 491 **/ 492 493 static char * 494 geterrbuf(RSTATUS *prs) 495 { 496 register char *cp; 497 int fd, 498 n; 499 char *buf = 0, 500 *file; 501 struct stat statbuf; 502 503 if (!prs) return(NULL); 504 505 file = makereqerr(prs); 506 if ( 507 Stat(file, &statbuf) == 0 508 && statbuf.st_size 509 && (fd = Open(file, O_RDONLY)) != -1 510 ) { 511 /* 512 * Don't die if we can't allocate space for this 513 * file--the file may be huge! 514 */ 515 lp_alloc_fail_handler = 0; 516 if ((buf = Malloc(statbuf.st_size + 1))) 517 if ((n = Read(fd, buf, statbuf.st_size)) > 0) { 518 buf[n] = 0; 519 520 /* 521 * NOTE: Ignore error output with no 522 * printable text. This hides problems we 523 * have with some shell scripts that 524 * occasionally cause spurious newlines 525 * when stopped via SIGTERM. Without this 526 * check for non-blank output, stopping 527 * a request sometimes causes a request 528 * failure. 529 */ 530 for (cp = buf; *cp && isspace(*cp); cp++) 531 ; 532 if (!*cp) { 533 Free (buf); 534 buf = 0; 535 } 536 } else { 537 Free (buf); 538 buf = 0; 539 } 540 lp_alloc_fail_handler = mallocfail; 541 Close(fd); 542 } 543 if (file) 544 Free (file); 545 546 return (buf); 547 } 548 549 /** 550 ** check_request() - CLEAN UP AFTER REQUEST 551 **/ 552 553 void 554 check_request(RSTATUS *prs) 555 { 556 /* 557 * If the request is done, decrement the count of requests 558 * needing the form or print wheel. Update the disk copy of 559 * the request. If we're finished with the request, get rid of it. 560 */ 561 if (prs->request->outcome & RS_DONE) { 562 unqueue_form (prs); 563 unqueue_pwheel (prs); 564 putrequest (prs->req_file, prs->request); 565 if (!(prs->request->outcome & (RS_ACTIVE | RS_NOTIFY))) { 566 rmfiles (prs, 1); 567 free_rstatus (prs); 568 } 569 } 570 return; 571 } 572 573 /** 574 ** check_children() 575 **/ 576 577 void 578 check_children(void) 579 { 580 register int i; 581 582 for (i = 0; Exec_Table[i] != NULL; i++) 583 if (Exec_Table[i]->pid > 0) 584 break; 585 586 if (Exec_Table[i] == NULL) 587 Shutdown = 2; 588 } 589