Annotation of coherent/g/usr/bin/mlp/lpsched.c, revision 1.1.1.1

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( &current);
                    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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.