|
|
1.1 ! root 1: /***************************************************************************** ! 2: MLP-Spool. Search the print queue (/usr/spool/mlp/queue) for reports ! 3: to ! 4: print. When necesarry, spawn processes to print these reports on the ! 5: proper printers observing the needs of concurent printing processes. ! 6: ! 7: Author: B.Blatchley (c) 1992 Magnetic Data Operation ! 8: *****************************************************************************/ ! 9: ! 10: #include "header.h" ! 11: #include <sys/param.h> ! 12: #include <sys/stat.h> ! 13: ! 14: #define SLEEPY 30 ! 15: ! 16: extern char curr_printer[WORKSTR]; ! 17: extern char curr_device[WORKSTR]; ! 18: extern char curr_backend[WORKSTR]; ! 19: extern char curr_desc[WORKSTR]; ! 20: extern char curr_user[20]; ! 21: extern char curr_name[20]; ! 22: extern char curr_longevity[2]; ! 23: extern int curr_writeme; ! 24: extern int curr_mailme; ! 25: extern int curr_copies; ! 26: extern int curr_copy; ! 27: extern int curr_formlen; ! 28: extern int abort_write; ! 29: extern int kill_request; ! 30: ! 31: int our_child; ! 32: int pip[2]; /* backend pipe, global so cancel can close it */ ! 33: ! 34: ! 35: /***************************************************************************** ! 36: There are times when this program will sleep, while waiting for new things ! 37: to do. This process is called when the program receives a "wakeup" signal ! 38: from another process (or from its internal alarm-clock). ! 39: *****************************************************************************/ ! 40: ! 41: void wakeup() ! 42: { ! 43: signal( SIGALRM, wakeup); ! 44: } ! 45: ! 46: ! 47: ! 48: ! 49: /***************************************************************************** ! 50: Kill the backend process without placing the request on hold ! 51: *****************************************************************************/ ! 52: ! 53: void request_kill() ! 54: { ! 55: abort_write = TRUE; ! 56: kill_request = TRUE; ! 57: signal( R_KILL, request_kill); ! 58: } ! 59: ! 60: ! 61: ! 62: /***************************************************************************** ! 63: Kill the backend process but keep the request current (will reprint when ! 64: the despooler scans the the queue). ! 65: *****************************************************************************/ ! 66: ! 67: void request_cancel() ! 68: { ! 69: abort_write = TRUE; ! 70: kill_request = FALSE; ! 71: signal( R_CANCEL, request_cancel); ! 72: } ! 73: ! 74: ! 75: ! 76: ! 77: /***************************************************************************** ! 78: Extract Header Values ! 79: *****************************************************************************/ ! 80: ! 81: int extract_header( name) ! 82: char *name; ! 83: { ! 84: int fd; ! 85: char path[WORKSTR], header[HEADER_SIZE], *t; ! 86: ! 87: sprintf( path, "%s/%s", QUEUE_PATH, name); ! 88: ! 89: if ( (fd = open( path, O_RDONLY)) != BAD) { ! 90: ! 91: read( fd, header, HEADER_SIZE); close( fd); ! 92: ! 93: strcpy( curr_name, name); ! 94: ! 95: t = headerval( header, H_USER, ""); ! 96: strcpy( curr_user, unpadd( t)); ! 97: ! 98: t = headerval( header, H_PRINTER, ""); ! 99: strcpy( curr_printer, unpadd( t)); ! 100: ! 101: t = headerval( header, H_DESC, ""); ! 102: strcpy( curr_desc, unpadd( t)); ! 103: ! 104: t = headerval( header, H_LONGEVITY, ""); ! 105: strncpy( curr_longevity, unpadd( t), 1); ! 106: ! 107: curr_mailme = FALSE; ! 108: if ( *(headerval( header, H_MAILME, "")) != ' ') ! 109: curr_mailme = TRUE; ! 110: ! 111: curr_writeme = FALSE; ! 112: if ( *(headerval( header, H_WRITEME, "")) != ' ') ! 113: curr_writeme = TRUE; ! 114: ! 115: sscanf( headerval( header, H_COPIES, ""), "%d", &curr_copies); ! 116: ! 117: sscanf( headerval( header, H_FORMLEN, ""), "%d", &curr_formlen); ! 118: ! 119: return(1); ! 120: } ! 121: else ! 122: return(0); ! 123: } ! 124: ! 125: ! 126: ! 127: /***************************************************************************** ! 128: Return TRUE if the device specified in this request is available ! 129: *****************************************************************************/ ! 130: ! 131: int device_available( name) ! 132: char *name; ! 133: { ! 134: int id; ! 135: char *t, *c; ! 136: ! 137: if ( extract_header()) { ! 138: printer_device( curr_printer); ! 139: ! 140: if (!strcmp( curr_device, "")) { /* No device? */ ! 141: t = calloc(1000,1); ! 142: ! 143: scatf( t, "Printer \"%s\" has no device associated ", curr_printer); ! 144: scatf( t, "with it.\n\nRequest #%s has been suspended. ", &name[2]); ! 145: scatf( t, "One way to resolve the problem\nwould be to define the "); ! 146: scatf( t, "printer in %s. Another\nwould be to move ", CONTROL_PATH); ! 147: scatf( t, "the request to a different printer.\n\n"); ! 148: scatf( t, "You may need to ask MLP to reprint the request."); ! 149: ! 150: warning( curr_user, t); ! 151: free( t); ! 152: ! 153: /* Put the request into the inactive queue */ ! 154: ! 155: make_inactive( name); ! 156: ! 157: return(0); ! 158: } ! 159: ! 160: /* find out if the device is being used */ ! 161: ! 162: if (*(t = status( curr_device, ""))) { ! 163: /* Who is using the device? */ ! 164: ! 165: c = strtok( t, SEP); sscanf( c, "%d", &id); ! 166: ! 167: if (!kill( id, 0)) return(0); /* process is still active */ ! 168: } ! 169: ! 170: return(1); ! 171: } ! 172: ! 173: return(0); ! 174: } ! 175: ! 176: ! 177: ! 178: ! 179: /***************************************************************************** ! 180: Write Request. Setup a pipeline and spawn a backend process to handle ! 181: the writing of the request. We do this so that we can monitor to progress ! 182: of the request. ! 183: *****************************************************************************/ ! 184: ! 185: write_request( name, backend, start, end) ! 186: char *name; ! 187: char *backend; ! 188: int start; ! 189: int end; ! 190: { ! 191: int source, sink, feed = FALSE, copy, docopies, tmpv; ! 192: char path[WORKSTR], tmp[WORKSTR], copies[10], *t, *u; ! 193: ! 194: signal( R_KILL, request_kill); ! 195: signal( R_CANCEL, request_cancel); ! 196: ! 197: /* Open the print request and the device (data source & sink) */ ! 198: ! 199: sprintf( path, "%s/%s", QUEUE_PATH, name); ! 200: ! 201: if ( ( source = open( path, O_RDONLY)) == BAD) { ! 202: warning_user(curr_user, "Cannot open request file: %s for request %s", path, &name[2]); ! 203: make_inactive( name); ! 204: return; ! 205: } ! 206: ! 207: if ( ( sink = open( curr_device, O_WRONLY|O_CREAT|O_TRUNC|O_SYNC, 0644)) == BAD) { ! 208: warning_user(curr_user, "Cannot open device %s for request %s", curr_device, &name[2]); ! 209: make_inactive( name); ! 210: return; ! 211: } ! 212: ! 213: if( pipe( pip) == BAD) { ! 214: warning_user(curr_user, "Cannot create pipe to despool #%s", &name[2]); ! 215: make_inactive( name); ! 216: return; ! 217: } ! 218: ! 219: switch (fork()) { ! 220: case BAD: warning_user(curr_user, "Cannot fork to despool #%s", &name[2]); ! 221: close( source); close( sink); close( pip[0]); close( pip[1]); ! 222: make_inactive( name); ! 223: return; ! 224: ! 225: case 0: exit(0); ! 226: ! 227: default: setpgrp(); /* cut us loose from any control terminals! */ ! 228: ! 229: /* The parent feeds the child, will noting the progress of the feeding ! 230: in the status file -- Inquiring Minds want to know! */ ! 231: ! 232: switch ( our_child = fork()) { ! 233: case BAD: warning_user(curr_user, "Cannot fork to despool #%s", &name[2]); ! 234: close( source); close( sink); close( pip[0]); close( pip[1]); ! 235: return; ! 236: ! 237: case 0: close( source); close( pip[1]); dup2( pip[0], 0); dup2( sink, 1); ! 238: ! 239: signal( SIGTERM, SIG_IGN); ! 240: signal( SIGINT, SIG_IGN); ! 241: ! 242: ! 243: sprintf( copies, "%d", curr_copies); ! 244: ! 245: if (!strcmp( backend, DBACKEND)) ! 246: execl( backend, backend, NULL); ! 247: else ! 248: execl( "/bin/sh", "/bin/sh", backend, &name[2], curr_user, ! 249: copies, NULL); ! 250: } ! 251: ! 252: ! 253: /* Parent feeds the child... */ ! 254: ! 255: close( pip[0]); signal( SIGCLD, SIG_IGN); ! 256: ! 257: ! 258: t = controls( FEED, ""); ! 259: if (!strcmp( t, "ON") || !strcmp( t, "on")) feed = TRUE; ! 260: ! 261: docopies = 1; ! 262: t = controls( DOCOPIES, ""); ! 263: if (!strcmp( t, "ON") || !strcmp( t, "on")) docopies = curr_copies; ! 264: ! 265: ! 266: for ( copy = 0; copy < docopies; copy++) { ! 267: curr_copy = copy + 1; ! 268: ! 269: lseek( source, (long) HEADER_SIZE, 0); ! 270: ! 271: if (writeOut( source, pip[1], start, end, curr_formlen, TRUE) == BAD) { ! 272: ! 273: sscanf( &name[2], "%d", &tmpv); ! 274: ! 275: if ( kill_request) { ! 276: sprintf( tmp, "\n\n*** Request #%d Terminated ***\n\f", tmpv); ! 277: warning_user(curr_user, "The despooling of request #%d has been aborted.", tmpv); ! 278: } ! 279: else { ! 280: sprintf( tmp, "\n\n*** Request #%d Canceled ***\n\f", tmpv); ! 281: warning_user(curr_user, "Request #%d has been canceled.", tmpv); ! 282: } ! 283: ! 284: write( pip[1], tmp, strlen(tmp)); ! 285: break; ! 286: } ! 287: ! 288: if ( feed) { *tmp = '\f'; write( pip[1], tmp, 1); } ! 289: } ! 290: ! 291: ! 292: close( source); close( pip[1]); close( sink); ! 293: ! 294: ! 295: /* If the request was aborted, keep it in the active ! 296: part of the queue. Otherwise, retire it to the ! 297: inactive queue. If the request is a reprint ! 298: then remove it from the queue. */ ! 299: ! 300: if (!kill_request) ! 301: make_inactive( name); ! 302: ! 303: wait(); ! 304: ! 305: ! 306: /* Send Messages if necessary */ ! 307: ! 308: if (curr_writeme || curr_mailme) { ! 309: t = calloc(512,1); ! 310: u = calloc(512,1); ! 311: ! 312: strcpy( t, "echo \"\n`date`\n\"'\n*** MLP Spooler Reports"); ! 313: strcat( t, " ***\n\nYour request, \""); ! 314: strcat( t, curr_desc); ! 315: strcat( t, ",\" "); ! 316: ! 317: if (strlen( curr_desc) > 15) ! 318: strcat( t, "\n"); ! 319: ! 320: sprintf( tmp, "has been despooled on printer: %s", curr_printer); ! 321: strcat( t, tmp); ! 322: ! 323: if (curr_writeme) { ! 324: sprintf( u, "%s\n\n'| write %s >/dev/null", t, curr_user); ! 325: system( u); ! 326: } ! 327: ! 328: if ( curr_mailme) { ! 329: if (getenv("MLPLMAIL")) ! 330: sprintf( u, "%s\n\n'| lmail %s 2>/dev/null", t, curr_user); ! 331: else ! 332: sprintf( u, "%s\n\n'| mail %s 2>/dev/null", t, curr_user); ! 333: ! 334: system( u); ! 335: } ! 336: ! 337: free( t); free( u); ! 338: } ! 339: } ! 340: ! 341: close( pip[0]); close( pip[1]); ! 342: } ! 343: ! 344: ! 345: ! 346: ! 347: /***************************************************************************** ! 348: De-spool a given file. ! 349: *****************************************************************************/ ! 350: ! 351: despool_file( name, start, end) ! 352: char *name; ! 353: int start; ! 354: int end; ! 355: { ! 356: char path[WORKSTR], tmp[512], newname[20]; ! 357: int backend, r_copies; ! 358: ! 359: if ( *curr_longevity == 'R') { /* Is this a reprint? */ ! 360: ! 361: /* sample description: "Reprint #00000 from page 0000 to page 0000" ! 362: 10-| 26-| 34-| */ ! 363: ! 364: sscanf( &curr_desc[9], "%5s", tmp); ! 365: strcpy( newname, request_name( tmp)); ! 366: ! 367: sscanf( &curr_desc[26], "%d", &start); ! 368: sscanf( &curr_desc[34], "%d", &end); ! 369: ! 370: sprintf( tmp, "%s/%s", QUEUE_PATH, name); ! 371: unlink( tmp); ! 372: ! 373: r_copies = curr_copies; strcpy( tmp, curr_printer); ! 374: extract_header( newname); ! 375: curr_copies = r_copies; strcpy( curr_printer, tmp); ! 376: } ! 377: else ! 378: strcpy( newname, name); ! 379: ! 380: ! 381: if (*curr_backend == 0) strcpy( curr_backend, DEFAULT); ! 382: ! 383: sprintf( path, "%s/%s", BACKEND_PATH, curr_backend); ! 384: ! 385: if ( (backend = open( path, O_RDONLY)) == BAD) { ! 386: sprintf( tmp, "Cannot find backend script (%s) for ", curr_backend); ! 387: scatf( tmp, "the %s printer\nwhile trying to ", curr_printer); ! 388: scatf( tmp, "despool request #%s\n\n", &newname[2]); ! 389: scatf( tmp, "Despooling done with %s.\n", DBACKEND); ! 390: warning( tmp); ! 391: write_request( newname, DBACKEND, start, end); ! 392: } ! 393: else ! 394: write_request( newname, path, start, end); ! 395: ! 396: ! 397: log( "Despooled Request #%s", &name[2]); ! 398: } ! 399: ! 400: ! 401: ! 402: /***************************************************************************** ! 403: De-spool. Check the queue for work, then process it. ! 404: *****************************************************************************/ ! 405: ! 406: void despool() ! 407: { ! 408: char *name, *t, *plist, tmp[WORKSTR]; ! 409: int n = 0, parent; ! 410: ! 411: ! 412: parent = getpid(); ! 413: ! 414: plist = calloc(1024,1); /* contains a list of printer in use during ! 415: this pass over the spool queue */ ! 416: ! 417: t = dirlist( QUEUE_PATH, FALSE); /* return sorted spool queue list */ ! 418: /* This list is a two dimensional array */ ! 419: /* (entries x MAXNAMLEN) */ ! 420: /* Ascending order */ ! 421: ! 422: while ( *(name = (t+(n * MAXNAMLEN)))) { ! 423: ! 424: if ( name[0] == 'R') { /* despool the "ready" entries */ ! 425: if ( device_available( name)) { ! 426: sprintf( tmp, "%s|", curr_device); ! 427: ! 428: if (!strstr( plist, tmp)) { ! 429: strcat( plist, tmp); ! 430: ! 431: switch (fork()) { ! 432: ! 433: case -1: warning("Cannot fork backend process for reqest #%s", &name[2]); ! 434: break; ! 435: ! 436: case 0: /* claim the device */ ! 437: ! 438: sprintf( tmp, "%d, %s", getpid(), name); ! 439: status( curr_device, tmp); ! 440: ! 441: despool_file( name, 0, 0); ! 442: ! 443: /* wakeup parent to rescan for work for this device */ ! 444: kill( parent, SIGALRM); ! 445: ! 446: exit(0); ! 447: } ! 448: ! 449: signal( SIGCLD, SIG_IGN); ! 450: } ! 451: } ! 452: } ! 453: ! 454: n++; ! 455: } ! 456: ! 457: free( plist); free( t); ! 458: } ! 459: ! 460: ! 461: ! 462: ! 463: ! 464: /****************************************************************************** ! 465: Roll the log over after a given time so that it does not grow ! 466: without bounds. ! 467: ******************************************************************************/ ! 468: ! 469: #define RHOURS (7.0 * 24.0) ! 470: ! 471: roll_log() ! 472: { ! 473: long rollover, current; ! 474: struct stat *s; ! 475: float rhours; ! 476: char tmp[WORKSTR]; ! 477: ! 478: rhours = RHOURS; sscanf( controls( TLIFE, ""), "%f", &rhours); ! 479: ! 480: rollover = (long) 3600.0 * rhours; time( ¤t); ! 481: ! 482: stat( LOG_PATH, s); ! 483: ! 484: if ((s->st_ctime + rollover) < current) { ! 485: sprintf( tmp, "%s.o", LOG_PATH); ! 486: ! 487: unlink( tmp); rename( LOG_PATH, tmp); ! 488: ! 489: warning("Logfile moved to log.o, starting new log.", "root"); ! 490: } ! 491: } ! 492: ! 493: ! 494: ! 495: ! 496: /***************************************************************************** ! 497: Main Driver. Tell the spooler how to find us. Then process the queue ! 498: and sleep until something exciting happens ;) First check to see if ! 499: the despooler is already running. ! 500: *****************************************************************************/ ! 501: ! 502: void main() ! 503: { ! 504: char tmp[10]; ! 505: int child, cycles; ! 506: ! 507: umask(FPERMS); ! 508: ! 509: if ( scheduler_status()) { ! 510: printf("MLP Scheduler already started.\n"); ! 511: exit(0); ! 512: } ! 513: ! 514: switch (child = fork()) { ! 515: case -1: fatal("Scheduler becoming a daemon. Cannot fork()"); ! 516: ! 517: case 0: /* I am in the background now, and will despool requests */ ! 518: ! 519: chdir("/"); /* so we can dismount any mounted filesystems */ ! 520: ! 521: /* for (fd = 0; fd < NOFILE; fd++) close(fd); */ ! 522: ! 523: umask(0); ! 524: ! 525: setpgrp(); /* detatch me from my parent process */ ! 526: ! 527: signal( SIGCLD, SIG_IGN); ! 528: signal( SIGALRM, wakeup); ! 529: ! 530: sprintf( tmp, "%d", getpid()); status( DESPOOLER, tmp); ! 531: ! 532: cycles = 0; ! 533: ! 534: while ( *(status( DESPOOLER, ""))) { ! 535: MLP_lock( L_CANCEL); ! 536: ! 537: despool(); ! 538: ! 539: if (cycles++ > 10) { ! 540: grim_reaper(); /* purge the inactive queue */ ! 541: cycles = 0; ! 542: } ! 543: ! 544: MLP_unlock( L_CANCEL); ! 545: ! 546: sleep( SLEEPY); ! 547: } ! 548: ! 549: fatal("Scheduler daemon expired gracefully"); ! 550: break; ! 551: ! 552: default: printf("MLP Scheduler Started, PID: %d\n", child); ! 553: log("MLP Scheduler Started, PID: %d", child); ! 554: break; ! 555: } ! 556: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.