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