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

1.1       root        1: /******************************************************************************
                      2:    Various routines used by the MLP spooler system.
                      3: ******************************************************************************/
                      4: 
                      5: #include "header.h"
                      6: 
                      7: char progname[16];
                      8: 
                      9: static char  caparea[WORKSTR];
                     10: static char *PS, *PN;
                     11: 
                     12: char curr_printer[WORKSTR];
                     13: char curr_device[WORKSTR];
                     14: char curr_backend[WORKSTR];
                     15: char curr_desc[WORKSTR];
                     16: char curr_user[20];
                     17: char curr_name[20];
                     18: char curr_longevity[2];
                     19: int  curr_mailme;
                     20: int  curr_writeme;
                     21: int  curr_copies;
                     22: int  curr_copy;
                     23: int  curr_formlen;
                     24: int  abort_write = FALSE;
                     25: int  kill_request = FALSE;
                     26: 
                     27: 
                     28: /******************************************************************************
                     29:    Scatf works like sprintf except the target string has the newly formated
                     30:    string appended to the end of it.  Be sure the target is big enough to 
                     31:    hold the new string as well as its current contents.  Returns a pointer
                     32:    to the target string.
                     33: ******************************************************************************/
                     34: 
                     35: char *scatf( va_alist)
                     36: va_dcl
                     37: {
                     38:     va_list  args;
                     39:     char    *dest, *tmp;
                     40: 
                     41:     tmp = malloc(512);
                     42:     va_start( args);
                     43: 
                     44:     dest = va_arg( args, char *);
                     45: 
                     46:     sprintf( tmp, "%r", args);
                     47: 
                     48:     strcat( dest, tmp);
                     49: 
                     50:     va_end( args);
                     51:     free( tmp);
                     52: 
                     53:     return( dest);
                     54: }
                     55: 
                     56: 
                     57: 
                     58: /******************************************************************************
                     59:    fatal.  Handles fatal errors with "astonishing" grace.  It sends a formated
                     60:    messages to root's mailbox and terminates the program.  Warning sends a 
                     61:    formated message to the user's mailbox and returns to caller.
                     62: ******************************************************************************/
                     63: 
                     64: void warning( va_alist)
                     65: va_dcl
                     66: {
                     67:    va_list  args;
                     68:    char    *i, *j, user[20];
                     69: 
                     70:    strcpy( user, "root");  if ( i = (char *) getlogin())  strcpy( user, i);
                     71: 
                     72:    i = calloc(1024,1);  j = calloc(1024,1);
                     73: 
                     74:    strcpy(  i, "/bin/echo \"\n`date`\n\"");
                     75:    strcat(  i, "'\n*** Message From The MLP Spooler ***\n\n");
                     76: 
                     77:    va_start( args);  
                     78:    sprintf( j, "%r", args);
                     79:    va_end( args);
                     80: 
                     81:    strcat( i, j); 
                     82: 
                     83:    if (getenv("MLPLMAIL"))
                     84:       strcat( i, "\n\n' | lmail ");
                     85:    else
                     86:       strcat( i, "\n\n' | mail ");
                     87: 
                     88:    strcat( i, user);
                     89: 
                     90:    log( "%s", j);  system( i);
                     91: 
                     92:    free( i);  free( j);
                     93: }
                     94: 
                     95: void warning_user( va_alist)
                     96: va_dcl
                     97: {
                     98:    va_list  args;
                     99:    char    *i, *j, *user;
                    100: 
                    101:    i = calloc(1024,1);  j = calloc(1024,1);
                    102: 
                    103:    strcpy(  i, "/bin/echo \"\n`date`\n\"");
                    104:    strcat(  i, "'\n*** Message From The MLP Spooler ***\n\n");
                    105: 
                    106:    va_start( args);  
                    107:    user = va_arg( args, char *);  sprintf( j, "%r", args);
                    108:    va_end( args);
                    109: 
                    110:    strcat( i, j); 
                    111: 
                    112:    if (getenv("MLPLMAIL"))
                    113:       strcat( i, "\n\n' | lmail ");
                    114:    else
                    115:       strcat( i, "\n\n' | mail ");
                    116: 
                    117:    strcat( i, user);
                    118: 
                    119:    log( "%s", j);  system( i);
                    120: 
                    121:    free( i);  free( j);
                    122: }
                    123: 
                    124: 
                    125: 
                    126: void fatal( va_alist)
                    127: va_dcl
                    128: {
                    129:    va_list  args;
                    130:    char    *i, *j;
                    131: 
                    132:    i = calloc(1024,1);  j = calloc(1024,1);
                    133: 
                    134:    strcpy(  i, "/bin/echo \"\n`date`\n\"");
                    135:    strcat(  i, "'\n*** Message From The MLP Spooler ***\n\n");
                    136: 
                    137:    va_start( args);  
                    138:    sprintf( j, "%r", args);
                    139:    va_end( args);
                    140: 
                    141:    strcat( i, j); 
                    142: 
                    143:    if (getenv("MLPLMAIL"))
                    144:       strcat( i, "\n\n' | lmail root");
                    145:    else
                    146:       strcat( i, "\n\n' | mail root");
                    147: 
                    148:    log( "%s", j);  system( i);
                    149: 
                    150:    free( i);  free( j);
                    151:    exit(0);
                    152: }
                    153: 
                    154: 
                    155: /******************************************************************************
                    156:    Removes the leading and trailing spaces from the given string.  First
                    157:    scan to the end of the string. Then eat the right hand spaces.  Then
                    158:    eat the left hand spaces.  Then copy the unpadded string back into its
                    159:    original place.
                    160: ******************************************************************************/
                    161: 
                    162: char *unpadd( str)
                    163: char *str;
                    164: {
                    165:    int   len = 0;
                    166:    char *t, *u;
                    167: 
                    168:    for (t = str; *t; t++) len++;    t--;
                    169: 
                    170:    while ( t != str && *t == ' ') { *t = 0; t--; len--;} 
                    171: 
                    172:    for (t = str; *t && *t == ' '; t++) len--;
                    173: 
                    174:    u = calloc((len+1), 1); strncpy( u, t, len); strcpy( str, u); free( u);
                    175: 
                    176:    return( str);
                    177: }
                    178: 
                    179: 
                    180: /******************************************************************************
                    181:    Rename a file.
                    182: ******************************************************************************/
                    183: 
                    184: int rename( old, new)
                    185: char *old;
                    186: char *new;
                    187: {
                    188:    unlink( new);
                    189: 
                    190:    if ( link( old, new) == BAD) return(2);
                    191: 
                    192:    if ( unlink( old) == BAD)    return(3);
                    193: 
                    194:    return(0);
                    195: }
                    196: 
                    197: 
                    198: 
                    199: 
                    200: 
                    201: /*****************************************************************************
                    202:    Put a request in the inactive queue
                    203: *****************************************************************************/
                    204: 
                    205: void make_inactive( name)
                    206: char *name;
                    207: {
                    208:    char newname[20], path[WORKSTR], newpath[WORKSTR];
                    209: 
                    210:    if (*name == 'r') return;  /* already inactive */
                    211: 
                    212:    strcpy( newname, name); newname[0] = 'r';
                    213: 
                    214:    sprintf( path,    "%s/%s", QUEUE_PATH, name);
                    215:    sprintf( newpath, "%s/%s", QUEUE_PATH, newname);     
                    216: 
                    217:    rename( path, newpath);
                    218: } 
                    219: 
                    220: 
                    221: 
                    222: 
                    223: 
                    224: /******************************************************************************
                    225:    Get/Set header information
                    226: ******************************************************************************/
                    227: 
                    228: char *headerval( header, opt, value)
                    229: char *header;
                    230: int   opt;
                    231: char *value;
                    232: {
                    233:    static char s[HEADER_SIZE];
                    234:    int         offset, length, n;
                    235: 
                    236:    switch (opt) {
                    237:       case H_USER:      offset =  0; length =  14; break;
                    238:       case H_PRINTER:   offset = 14; length =  14; break;
                    239:       case H_TYPE:      offset = 28; length =  10; break;
                    240:       case H_FORMLEN:   offset = 38; length =   3; break;
                    241:       case H_PAGES:     offset = 41; length =   4; break;
                    242:       case H_COPIES:    offset = 45; length =   2; break;
                    243:       case H_LONGEVITY: offset = 47; length =   1; break;
                    244:       case H_MAILME:    offset = 48; length =   1; break;
                    245:       case H_WRITEME:   offset = 49; length =   1; break;
                    246:       case H_DBASE:     offset = 50; length =  14; break;
                    247:       case H_FORMAT:    offset = 64; length =  14; break;
                    248:       case H_DSTAMP:    offset = 78; length =  10; break;
                    249:       case H_DESC:      offset = 88; length =  60; break;
                    250: 
                    251:       case H_ENTIRE:    offset =  0; length = HEADER_SIZE-2; 
                    252:                         header[HEADER_SIZE-1] = '\n';
                    253:                         header[HEADER_SIZE] = 0;
                    254:                         break;
                    255:    }
                    256: 
                    257:    if (value[0]) {
                    258:       for (n = 0; n < length; n++) header[offset+n] = ' ';
                    259:       for (n = 0; value[n] && n < length; n++) header[offset+n] = value[n]; 
                    260:    }
                    261: 
                    262:    strncpy( s, &header[offset], length); s[length] = 0;
                    263: 
                    264:    return( s);
                    265: }
                    266: 
                    267: 
                    268: 
                    269: 
                    270: /******************************************************************************
                    271:    Log text messages into the log file.
                    272: ******************************************************************************/
                    273: 
                    274: log( va_alist)
                    275: va_dcl
                    276: {
                    277:    va_list    args;
                    278:    FILE      *fp;
                    279:    long       clock;
                    280:    struct tm *tt;
                    281:    char       message[1200];
                    282: 
                    283: 
                    284:    va_start( args);  sprintf( message, "%r", args);  va_end( args); 
                    285: 
                    286:    MLP_lock( L_LOG);
                    287: 
                    288:    time( &clock); tt = localtime( &clock);
                    289: 
                    290:    if ( fp = fopen( LOG_PATH, "a+")) {
                    291:       fprintf( fp, "%02d/%02d/%02d ", (tt->tm_mon+1), tt->tm_mday, tt->tm_year);
                    292:       fprintf( fp, "%02d:%02d - ", (tt->tm_hour), tt->tm_min);
                    293:       fprintf( fp, "%s\n", message);
                    294:       fflush( fp);
                    295:       close( fp);
                    296:    }
                    297: 
                    298:    MLP_unlock( L_LOG);
                    299: }
                    300: 
                    301: 
                    302: 
                    303: /******************************************************************************
                    304:    Get Termcap Information.  If we've already filled PS then don't bother again.
                    305: ******************************************************************************/
                    306: 
                    307: void get_termcap()
                    308: {
                    309:    extern char *tgetstr();
                    310:    extern int   tgetent();
                    311:    char *buff, *term, *ptr;
                    312: 
                    313:    if ( PS) return;
                    314: 
                    315:    ptr = buff = calloc( 1024, 1);
                    316: 
                    317:    if ( buff == NULL) fatal("Not enough memory to local print");
                    318: 
                    319:    if ( (term = getenv("TERM")) == NULL)
                    320:       fatal("Trying to local print.  TERM must be defined.");
                    321: 
                    322:    if ( tgetent( buff, term) == BAD)
                    323:       fatal("Trying to local print.  Cannot find %s in /etc/termcap", term);
                    324: 
                    325:    ptr = caparea;
                    326: 
                    327:    PS = tgetstr( "PS", &ptr);
                    328:    PN = tgetstr( "PN", &ptr);
                    329: 
                    330:    if ( PS == NULL || PN == NULL)
                    331:       fatal("Trying to local print.\n\nBoth PS and PN need to be defined for terminal %s in /etc/termcap", term);
                    332: }
                    333: 
                    334: 
                    335: 
                    336: 
                    337: 
                    338: 
                    339: 
                    340: /******************************************************************************
                    341:    Return a datestamp string (actually it is the long-int in text form)
                    342: ******************************************************************************/
                    343: 
                    344: char *datestamp()
                    345: {
                    346:    static char stamp[11];
                    347:    time_t      t;
                    348: 
                    349:    time( &t);  sprintf( stamp, "%010lu", t);
                    350: 
                    351:    return( stamp);
                    352: }
                    353: 
                    354: 
                    355: 
                    356: /******************************************************************************
                    357:    Given a string, convert it to uppercase.
                    358: ******************************************************************************/
                    359: 
                    360: char *uppercase( str)
                    361: char *str;
                    362: {
                    363:    char *c = str;
                    364: 
                    365:    while (*c) {
                    366:       if (islower(*c)) *c = toupper(*c);
                    367:       c++;
                    368:    }
                    369: 
                    370:    return( str);
                    371: }
                    372: 
                    373: 
                    374: 
                    375: /******************************************************************************
                    376:   Given the name of a control-file parameter, return its value.  Lock the
                    377:   file so we can read/write it without it changing on us.  If the value of the
                    378:   string "newval", is non-null then assign the parameter this new new value.
                    379: ******************************************************************************/
                    380: 
                    381: char *parameters( param, newval, pathname, locktype)
                    382: char *param;
                    383: char *newval;
                    384: char *pathname;
                    385: int  locktype;
                    386: {
                    387:    static  char value[ WORKSTR];
                    388:    FILE   *fp, *ofp;
                    389:    char    tmp[WORKSTR], tmp1[WORKSTR], parameter[30], *c, tmppath[WORKSTR];
                    390: 
                    391:    sprintf( tmppath, "%s.tmp", pathname);
                    392: 
                    393:    strncpy( parameter, param, sizeof( parameter));  uppercase( parameter);
                    394: 
                    395:    strcpy( value, "");
                    396: 
                    397:    MLP_lock( locktype); 
                    398:  
                    399:    if ( (fp = fopen( pathname, "r"))) {
                    400: 
                    401:       if (!strcmp( newval, "")) {
                    402: 
                    403:          while (!feof( fp)) {
                    404:             fgets( tmp, sizeof( tmp), fp);
                    405: 
                    406:             for (c = tmp; *c && *c != '#'; c++); /* look for comment */
                    407: 
                    408:             if ( *tmp && !*c) {
                    409:                c = strtok( tmp, SEP);  uppercase( c);
                    410: 
                    411:              
                    412:                if ( !strcmp( c, parameter)) {
                    413:                   c = strtok( NULL, "\n");
                    414:                   while (*c && (*c == ' ' || *c == '\t' || *c == '=')) c++;
                    415:                   strcpy( value, c);
                    416:                   break;
                    417:                }
                    418:             }
                    419:          }
                    420:          fclose( fp);
                    421:       }
                    422:       else { 
                    423:          if ( (ofp = fopen( tmppath, "w"))) {
                    424: 
                    425:             while (!feof( fp)) {
                    426:                fgets( tmp, sizeof( tmp), fp);  strcpy( tmp1, tmp);
                    427: 
                    428:                if ( *tmp && *tmp != '#') {
                    429:                   c = strtok( tmp, SEP);  uppercase( c);
                    430: 
                    431:                   if ( strcmp( c, parameter)) 
                    432:                      fprintf( ofp, "%s", tmp1);
                    433:                }
                    434:                else
                    435:                   fprintf( ofp, "%s", tmp1);
                    436:             }
                    437: 
                    438:             fprintf( ofp, "%s = %s\n", param, newval);
                    439: 
                    440:             fclose( ofp);  fclose( fp);
                    441: 
                    442:             rename( tmppath, pathname);
                    443:          }
                    444:          else {
                    445:             fclose( fp);
                    446:             fatal("Cannot create %s", tmppath);
                    447:          }
                    448:       }
                    449:    }
                    450:    else
                    451:    if ( errno == EACCES) 
                    452:          fatal("Permission Problem with \"%s\".  It should have the suid bit set.", progname);
                    453:    else
                    454:    if ( rename( tmppath, pathname) == 0) {
                    455:       MLP_unlock( locktype);
                    456:       return( parameters( param, newval, pathname, locktype));
                    457:    }
                    458:    else {
                    459:       if ( (fp = fopen( pathname, "w"))) {
                    460:          fclose( fp);
                    461:          MLP_unlock( locktype);
                    462:          return( parameters( param, newval, pathname, locktype));
                    463:       }
                    464:       else
                    465:          fatal("Cannot create control file: %s", pathname);
                    466:    }
                    467:    
                    468: 
                    469:    MLP_unlock( locktype);
                    470: 
                    471:    return( value);
                    472: }
                    473: 
                    474: 
                    475: 
                    476: 
                    477: /******************************************************************************
                    478:   Given the name of a printer-setup parameter, return its value. 
                    479:   If the value of the string "newval", is non-null then assign the parameter
                    480:   this new new value.
                    481: ******************************************************************************/
                    482: 
                    483: char *controls( param, newval)
                    484: char *param;
                    485: char *newval;
                    486: {
                    487:    return( parameters( param, newval, CONTROL_PATH, L_CONTROL));
                    488: }
                    489: 
                    490: 
                    491: /******************************************************************************
                    492:   Given the name of a printer-status parameter, return its value.  
                    493:   If the value of the string "newval", is non-null then assign the parameter
                    494:   this new new value.
                    495: ******************************************************************************/
                    496: 
                    497: char *status( param, newval)
                    498: char *param;
                    499: char *newval;
                    500: {
                    501:    return( parameters( param, newval, STATUS_PATH, L_STATUS));
                    502: }
                    503: 
                    504: 
                    505: 
                    506: 
                    507: /*****************************************************************************
                    508:    Given the name of a printer, return the name of its device.  The controls
                    509:    line for a printer looks like this:
                    510: 
                    511:    printer = name, device, backend
                    512: *****************************************************************************/
                    513: 
                    514: char *printer_device( newprinter)
                    515: char *newprinter;
                    516: {
                    517:    char  line[WORKSTR], tmp[40], *c, tmppath[WORKSTR], printer[WORKSTR];
                    518:    FILE *fp;
                    519: 
                    520:    strcpy( printer, newprinter);
                    521: 
                    522:    sprintf( tmppath, "%s.tmp", CONTROL_PATH);
                    523: 
                    524:    MLP_lock( L_CONTROL);
                    525: 
                    526:    if ( (fp = fopen( CONTROL_PATH, "r"))) {
                    527: 
                    528:       while ( fgets( line, sizeof( line), fp)) {
                    529: 
                    530:          *tmp = *curr_device = *curr_backend = 0;   
                    531: 
                    532:          c = strtok( line, SEP);  if (c) strncpy( tmp, c, sizeof(tmp));
                    533: 
                    534:          if (!strcmp( "PRINTER", uppercase( tmp))) {
                    535:             c = strtok( NULL, SEP);
                    536: 
                    537:             if (!strcmp( printer, c)) {
                    538:                c = strtok( NULL, SEP); if (c) strncpy( curr_device,  c, WORKSTR);
                    539:                c = strtok( NULL, SEP); if (c) strncpy( curr_backend, c, WORKSTR);
                    540:                break;
                    541:             }
                    542:          }
                    543:       }
                    544: 
                    545:       fclose( fp);
                    546:    }
                    547:    else
                    548:    if ( errno == EACCES) {
                    549:          /* fprintf(stderr,"permission problem (%s)\n", progname); fflush(stderr); */
                    550:          fatal("Permission Problem with \"%s\".  It should have the suid bit set.", progname);
                    551:    }
                    552:    else
                    553:    if ( rename( tmppath, CONTROL_PATH) == 0) {
                    554:       MLP_unlock( L_CONTROL);
                    555:       return( printer_device( newprinter));
                    556:    }
                    557:    else
                    558:       fatal( "Missing control file: %s", CONTROL_PATH);
                    559: 
                    560:    MLP_unlock( L_CONTROL);
                    561: 
                    562:    return( curr_device);   
                    563: }
                    564: 
                    565: 
                    566: 
                    567: 
                    568: 
                    569: /******************************************************************************
                    570:    Given a user name, return the name of the printer to which they are cur-
                    571:    rently routed.
                    572: ******************************************************************************/
                    573: 
                    574: char *route_request( user)
                    575: char *user;
                    576: {
                    577:    static  char printer[15];
                    578:    FILE   *fp;
                    579:    char         path[WORKSTR], *c;
                    580: 
                    581:    sprintf( path, "%s/%s", ROUTE_PATH, user);
                    582: 
                    583: 
                    584:    strcpy( printer, "");
                    585: 
                    586:    if ( (fp = fopen( path, "r"))) {
                    587:       fgets( printer, sizeof( printer), fp);
                    588:       fclose( fp);
                    589:    }
                    590:    else {
                    591:       strcpy( printer, controls( DEFAULT,""));
                    592: 
                    593:       if (!strcmp( printer, ""))
                    594:          fatal( "Controls file (%s) needs a default printer entry", CONTROL_PATH);
                    595:    }
                    596: 
                    597:    if ( c = strchr( printer, '\n')) *c = 0;
                    598: 
                    599:    return( printer);
                    600: }
                    601: 
                    602: 
                    603: 
                    604: 
                    605: 
                    606: /******************************************************************************
                    607:    Return a new report sequence number.
                    608: ******************************************************************************/
                    609: 
                    610: int get_seq_num()
                    611: {
                    612:    char *v, newnum[10];
                    613:    int   n;
                    614: 
                    615:    v = status("seqnum","");          if ( v[0] == 0)  v = "00001";
                    616:    
                    617:    sscanf( v, "%d", &n);               if ( n >= 32001) n = 1;
                    618: 
                    619:    sprintf( newnum, "%05u", (n+1));    status( SEQNUM, newnum);
                    620: 
                    621:    return(n);
                    622: }
                    623: 
                    624: 
                    625: 
                    626: 
                    627: /******************************************************************************
                    628:    Local print.  Send the contents of the spool file (less the header)
                    629:    to the printer connected to the user's terminal.  We assume that we are
                    630:    positioned past the header.
                    631: ******************************************************************************/
                    632: 
                    633: void local_print( fd, start, end)
                    634: int fd;
                    635: int start;
                    636: int end;
                    637: {
                    638:    char *c, k;
                    639:    long here;
                    640: 
                    641: 
                    642:    here = lseek( fd, 0L, 1);
                    643: 
                    644:    get_termcap();
                    645: 
                    646:    write( 1, PN, strlen( PN));
                    647: 
                    648:    writeOut( fd, 1, start, end, curr_formlen, FALSE);
                    649: 
                    650:    c = controls( LOCALFEED, "");
                    651: 
                    652:    if (!strcmp( c, "ON") || !strcmp( c, "on")) { k = '\f'; write( 1, &k, 1); }
                    653: 
                    654:    write( 1, PS, strlen( PS));
                    655: 
                    656:    lseek( fd, here, 0);
                    657: }
                    658: 
                    659: 
                    660: 
                    661: /*****************************************************************************
                    662:    Return a sorted list of the spool queue.  The data structure returned is
                    663:    a two dimensional array ( entries x MAXNAMLEN).
                    664: *****************************************************************************/
                    665: 
                    666: char *dirlist( dirname, descend)
                    667: char *dirname;
                    668: int   descend;
                    669: {
                    670:    extern char *realloc();
                    671:    DIR *dr;
                    672:    struct dirent *dp;
                    673:    char *t, tmp[MAXNAMLEN];
                    674:    int   size, top, swapit, i, j, gap, comp;
                    675: 
                    676:    dr = opendir( dirname);  t = calloc( MAXNAMLEN, 1);  size = 0;
                    677: 
                    678:    while ( ( dp = readdir( dr)) != NULL)
                    679:       if (!strcmp( ".", dp->d_name) || !strcmp( "..", dp->d_name))
                    680:          continue;
                    681:       else {
                    682:          strncpy( (t+(size * MAXNAMLEN)), dp->d_name, MAXNAMLEN);
                    683:          size++;
                    684:          t = realloc( t, ((size+1) * MAXNAMLEN));
                    685:       }
                    686: 
                    687:    closedir( dr);
                    688: 
                    689:    strcpy( (t+(size * MAXNAMLEN)), "");
                    690: 
                    691: 
                    692:    /* Use a COMBsort to sort the items in this directory */
                    693:    /* This sort is like a bubble sort only MUCH faster */
                    694: 
                    695:    gap = size;
                    696: 
                    697:    do {
                    698:       gap = gap * 10 / 13;    if (gap == 0) gap = 1;
                    699: 
                    700:       top = size - gap;       swapit = 0;
                    701: 
                    702:       for ( i = 0; i < top; i++) {
                    703:          j = i + gap;
                    704:         
                    705:          comp = strcmp( (t+(i * MAXNAMLEN)), (t+(j * MAXNAMLEN)));
                    706: 
                    707:          if (descend) {      /* Reverse the sort order */
                    708:             if ( comp > 0)
                    709:                comp = 0;
                    710:             else
                    711:                comp = 1;
                    712:          }
                    713:        
                    714:          if ( comp > 0) {
                    715:             strcpy( tmp, (t+(i * MAXNAMLEN)));
                    716:             strcpy( (t+(i * MAXNAMLEN)), (t+(j * MAXNAMLEN)));
                    717:             strcpy( (t+(j * MAXNAMLEN)), tmp);
                    718: 
                    719:             swapit++;
                    720:          } 
                    721:       }
                    722:    } while ( swapit || gap > 1);
                    723:    return( t);
                    724: }
                    725: 
                    726: 
                    727: 
                    728: /******************************************************************************
                    729:    Wakeup The Despooler by sending it an alarm signal.  The despooler's PID
                    730:    will be found in the controls database.
                    731: ******************************************************************************/
                    732: 
                    733: void wakeup_despooler()
                    734: {
                    735:    char  *v;
                    736:    int    pid = 0;
                    737: 
                    738:    v = status( DESPOOLER,"");
                    739: 
                    740:    sscanf( v, "%d", &pid);
                    741: 
                    742:    if ( pid > 0) kill( pid, SIGALRM);
                    743: }
                    744: 
                    745: 
                    746: 
                    747: 
                    748: 
                    749: /******************************************************************************
                    750:    Basename.  Strip the leading path information from a pathname.
                    751: ******************************************************************************/
                    752: 
                    753: char *basename( path)
                    754: char *path;
                    755: {
                    756:    char *c;
                    757: 
                    758:    if (path == NULL) return("");
                    759: 
                    760:    for (c = path; *c; c++); c--;           /* go to the end of the string */
                    761: 
                    762:    while (c != path && *(c-1) != '/') c--; /* step back til we see a slash */
                    763: 
                    764:    return( c);
                    765: }
                    766: 
                    767: 
                    768: 
                    769: 
                    770: /******************************************************************************
                    771:    Return TRUE if the scheduler is running, FALSE if not.
                    772: ******************************************************************************/
                    773: 
                    774: int scheduler_status()
                    775: {
                    776:    char *t;
                    777:    int   pid;
                    778: 
                    779:    t = status( DESPOOLER, "");  sscanf( t, "%d", &pid);
                    780:    
                    781:    if ( pid > 1 && !kill( pid, 0))
                    782:       return( TRUE);
                    783:    else
                    784:       return( FALSE);
                    785: }
                    786: 
                    787: 
                    788: 
                    789: 
                    790: /******************************************************************************
                    791:    This routine does all the actual I/O to the device.  The tricky part is
                    792:    counting the pages and (optionally printing only the desired range of pages).
                    793:    It is used in several places.  Source and Sink are the input and output
                    794:    file descriptors.  The source's file pointer is expected to be at the
                    795:    start of the user's data; that is, seek past the header, if there is one.
                    796:    Start and end are the starting and ending page numbers for the reqeuest.
                    797:    If both of these are zero then we will send all of the source data to the
                    798:    sink, otherwise we send source to sink only when we are within the page
                    799:    range.  Counting pages depends heavily on the form length (curr_formlen)
                    800:    and the nature of the source data.  If you are sending bitmaps to a laser
                    801:    printer though this routine, the page numbers will probably be wildly
                    802:    skewed!  At this point, I know of no convienent way around this.  You'd
                    803:    have to parse the input for ALL known laser printers. Then the next new
                    804:    one could possibly make your effort moot.  Maybe this could be done for
                    805:    HPCL and Postscript?  If the flag "report" is TRUE then the routine's
                    806:    progress will be reported in the status file.  This routine returns the
                    807:    number of pages that it has processed.
                    808: ******************************************************************************/
                    809: 
                    810: #define IOBUFF 1024
                    811: 
                    812: int writeOut( source, sink, start, end, formlen, report)
                    813: int source;
                    814: int sink;
                    815: int start;
                    816: int end;
                    817: int formlen;
                    818: int report;
                    819: {
                    820:    int   result, lines, progress;
                    821:    int   pages;
                    822:    long  rsize, oldpos;
                    823:    char  tmp[WORKSTR];
                    824:    char *i, *ibuff, *imax;  /* input buffer pointers */
                    825:    char *o, *obuff, *omax;  /* output buffer pointers */
                    826: 
                    827:    /* how big is the source file? */
                    828:  
                    829:    oldpos = lseek( source, 0L, 1);
                    830:    rsize  = lseek( source, 0L, 2);  lseek( source, oldpos, 0);
                    831: 
                    832:    
                    833:    ibuff = malloc( IOBUFF);  obuff = malloc( IOBUFF);
                    834: 
                    835:    o = obuff;  omax = obuff + IOBUFF;
                    836: 
                    837:    lines = 0;  pages = 1;
                    838:  
                    839:    while ( result = read( source, ibuff, IOBUFF)) {
                    840:       if (abort_write) {
                    841:          o = obuff;
                    842:          pages = -1;
                    843:          break;
                    844:       }
                    845: 
                    846:       if ( start == 0 && end == 0)
                    847:          write( sink, ibuff, result);   /* print entire request */
                    848:       else {
                    849: 
                    850:          /* print from start to end page of request */
                    851: 
                    852:          for ( i = ibuff, imax = ibuff + result; i < imax; i++) {
                    853: 
                    854:             if ( *i == '\n') {
                    855:                lines++;
                    856: 
                    857:                if ( lines > formlen) {
                    858:                   lines = 0;
                    859:                   /* lines -= formlen; */
                    860:                   pages++;
                    861:                }
                    862:             }
                    863:             else
                    864:             if ( *i == '\f') {
                    865:                pages++;
                    866:                lines = 0;
                    867:             }
                    868: 
                    869:             if ( pages >= start && pages <= end) {
                    870: 
                    871:                *o++ = *i;
                    872: 
                    873:                if ( o >= omax) {
                    874: 
                    875:                   write( sink, obuff, IOBUFF);
                    876:                   o = obuff;
                    877:                }
                    878:             }
                    879:          }
                    880:       }
                    881: 
                    882: 
                    883:       /* Report Progress to the status file */
                    884: 
                    885:       if (report) {
                    886:          progress = (int) (lseek( source, 0L, 1) * 100L / rsize);
                    887: 
                    888:          sprintf( tmp, "%d, %s, %s, %d, %d of %d", getpid(), curr_name, 
                    889:             curr_printer, progress, curr_copy, curr_copies);
                    890: 
                    891:          status( curr_device, tmp);
                    892:       }
                    893:    }
                    894: 
                    895:    /* write anything leftover in the output buffer */
                    896: 
                    897:    if ( o != obuff) write( sink, obuff, (int) (o - obuff)); 
                    898: 
                    899: 
                    900:    free( ibuff);  free( obuff);
                    901: 
                    902:    return( pages);
                    903: }
                    904: 
                    905: 
                    906: 
                    907: /******************************************************************************
                    908:    Given the sequence number of a request, return the full file name of
                    909:    the request.
                    910: ******************************************************************************/
                    911: 
                    912: char *request_name( seqnum)
                    913: char *seqnum;
                    914: {
                    915:    DIR *dr;
                    916:    struct dirent *dp;
                    917:    int val;
                    918:    char tvalue[15];
                    919:    static char value[15];
                    920: 
                    921: 
                    922:    val = 0;  sscanf( seqnum, "%d", &val);   sprintf( tvalue, "%05u", val);
                    923: 
                    924:    dr = opendir( QUEUE_PATH);  value[0] = 0;
                    925: 
                    926: 
                    927:    while ( ( dp = readdir( dr)) != NULL)
                    928:       if (!strcmp( ".", dp->d_name) || !strcmp( "..", dp->d_name))
                    929:          continue;
                    930:       else {
                    931:          if (!strncmp( tvalue, &dp->d_name[2], 5)) {
                    932:             sprintf( value, "%s", dp->d_name);
                    933:             break;
                    934:          }
                    935:       }
                    936: 
                    937:    closedir( dr);
                    938: 
                    939:    return( value);
                    940: }
                    941: 
                    942: 
                    943: 
                    944: 
                    945: /****************************************************************************
                    946:    Given the report sequence number, return the owner's name
                    947: ****************************************************************************/
                    948: 
                    949: char *request_owner( seqnum)
                    950: char *seqnum;
                    951: {
                    952:    static char owner[20];
                    953:    char path[WORKSTR], head[HEADER_SIZE];
                    954:    int  fd;
                    955: 
                    956:    strcpy( owner, request_name( seqnum));
                    957: 
                    958:    if (*owner) {
                    959:       sprintf( path, "%s/%s", QUEUE_PATH, owner);
                    960: 
                    961:       if ( (fd = open( path, O_RDONLY)) != BAD) {
                    962:          read( fd, head, HEADER_SIZE);
                    963:          close( fd);
                    964: 
                    965:          strcpy( owner, headerval( head, H_USER, ""));
                    966:          unpadd( owner);
                    967:       }
                    968:    }
                    969:    else
                    970:       *owner = 0;
                    971: 
                    972:    return( owner);
                    973: }
                    974: 
                    975: 
                    976: 
                    977: 
                    978: /****************************************************************************
                    979:   Return 1 if I (the program's user) own the request, 0 otherwise. If I'm
                    980:   superuser, then I own it all.
                    981: ****************************************************************************/
                    982: 
                    983: int do_i_own_it( seqnum)
                    984: char *seqnum;
                    985: {
                    986:    struct passwd *p;
                    987:    
                    988:    p = getpwuid( getuid());
                    989: 
                    990:    if ((p && !strcmp( p->pw_name, request_owner( seqnum))) ||
                    991:       (getuid() == 0))
                    992:       return(1);
                    993:    else
                    994:       return(0);
                    995: }
                    996: 
                    997: 
                    998: 
                    999: 
                   1000: 
                   1001: /******************************************************************************
                   1002:    Report the status of all the printers defined in the control file.
                   1003: ******************************************************************************/
                   1004: 
                   1005: char *each_printer( command)
                   1006: int command;
                   1007: {
                   1008:    static FILE *fp;
                   1009:    static char  line[WORKSTR];
                   1010:    char         tmp[WORKSTR], *t;
                   1011: 
                   1012:    *line = 0;
                   1013: 
                   1014:    switch (command) {
                   1015:       case E_START: MLP_lock( L_CONTROL);
                   1016: 
                   1017:                     if ( (fp = fopen( CONTROL_PATH, "r+")) == NULL) {
                   1018:                        sprintf( tmp, "%s.tmp", CONTROL_PATH);
                   1019: 
                   1020:                        if ( errno == EACCES)
                   1021:                           fatal("Permission Problem with \"%s\".  It should have the suid bit set.", progname);
                   1022:                        else
                   1023:                        if ( rename( tmp, CONTROL_PATH) == 0) {
                   1024:                           MLP_unlock( L_CONTROL);
                   1025:                           return( each_printer( command));
                   1026:                        }
                   1027:                        else
                   1028:                           fatal( "Missing control file: %s", CONTROL_PATH);
                   1029:                     }
                   1030:                     break;
                   1031: 
                   1032:       case E_NEXT:  while (fgets( tmp, sizeof(tmp), fp)) {
                   1033: 
                   1034:                        t = strtok( tmp, SEP); uppercase( t);
                   1035:                        if (!strcmp( "PRINTER", t)) {
                   1036:                           for (t = tmp; *t; t++); t++;
                   1037:                           while (strchr(SEP, *t)) t++;
                   1038:                           strcpy( line, t);
                   1039:                           break;
                   1040:                        }
                   1041:                     }
                   1042:                     break;
                   1043: 
                   1044:       case E_REWIND: fseek( fp, 0L, SEEK_SET); break;
                   1045: 
                   1046:       case E_END:    fclose( fp);
                   1047:       case E_UNLOCK: MLP_unlock( L_CONTROL); break;
                   1048: 
                   1049:       case E_FILE:   return( (char *) fp);
                   1050:    }
                   1051: 
                   1052:    return( line);
                   1053: }
                   1054: 
                   1055: 
                   1056: 
                   1057: 
                   1058: char *report_printer_status( display_type)
                   1059: {
                   1060:    static char request_list[WORKSTR];
                   1061:    int    pid, req;
                   1062:    char   tmp[40], *t, *c, *d, *header, rpath[WORKSTR];
                   1063:    char   request[20], user[20], timestr[40];
                   1064:    long   rtime;
                   1065: 
                   1066:    request_list[0] = 0;  /* will contain a list of all the request that are
                   1067:                             currently printing.  This is so we can skip these
                   1068:                             when we go over the list of all pending requests.*/
                   1069: 
                   1070: 
                   1071:    each_printer( E_START);
                   1072: 
                   1073:    while ( *(t = each_printer( E_NEXT))) {
                   1074: 
                   1075:          *tmp = *curr_printer = *curr_device = *curr_backend = 0;   
                   1076: 
                   1077:          c = strtok( t   , SEP); if (c) strncpy( curr_printer, c, WORKSTR);
                   1078:          c = strtok( NULL, SEP); if (c) strncpy( curr_device,  c, WORKSTR);
                   1079:          c = strtok( NULL, SEP); if (c) strncpy( curr_backend, c, WORKSTR);
                   1080: 
                   1081: 
                   1082:          /*** Now look at this printer from the status database ***/
                   1083: 
                   1084:          strcpy( tmp, status( curr_device, ""));
                   1085: 
                   1086: 
                   1087:          c = strtok( tmp, SEP);  pid = 0; sscanf( c, "%d", &pid);
                   1088: 
                   1089:          if (pid > 0 && kill( pid, 0)) c = NULL;
                   1090: 
                   1091:          switch (display_type) {
                   1092:          case PID_DISPLAY:
                   1093:             if (c != NULL) {
                   1094:                c = strtok( NULL, SEP);
                   1095:                if (c) sprintf( timestr, "%d|%s ", pid, (c+2));
                   1096: 
                   1097:                if ((strlen( request_list)+strlen( timestr))
                   1098:                      < sizeof( request_list))
                   1099:                   strcat( request_list, timestr);
                   1100:             }
                   1101:          break;
                   1102: 
                   1103:          case DEVICE_DISPLAY:
                   1104:             printf("device for %s: %s\n", curr_printer, curr_device);
                   1105:          break;
                   1106: 
                   1107:          case PRINTER_DISPLAY:
                   1108:             *request = 0; if ( d = strtok( NULL, SEP)) strcpy( request, d);
                   1109: 
                   1110:             d = strtok( NULL, SEP);
                   1111: 
                   1112:             if ( c == NULL || d == NULL || strcmp(d, curr_printer))
                   1113:                printf("printer %s is idle\n", curr_printer);
                   1114:             else {
                   1115:                printf("printer %s is printing request #", curr_printer);
                   1116:                printf("%s, ", &request[2]);
                   1117: 
                   1118:                if ( c = strtok( NULL, SEP))
                   1119:                   printf("%s%% sent to device", c);
                   1120: 
                   1121:                if ( c = strtok( NULL, ","))
                   1122:                   printf(", copy %s", c);
                   1123:    
                   1124:                printf("\n");
                   1125:             }
                   1126:          break;
                   1127: 
                   1128:          case REQUEST_DISPLAY:
                   1129:             if ( c != NULL) {
                   1130:                strcpy( request, strtok( NULL, SEP));
                   1131:                sprintf( rpath, "%s/%s", QUEUE_PATH, request);
                   1132: 
                   1133:                if ((c = strtok( NULL, SEP)) && !strcpy( c, curr_printer)) {   
                   1134:               
                   1135:                   if ( (req = open( rpath, O_RDONLY)) != BAD) {
                   1136:                      header = calloc( HEADER_SIZE, 1);
                   1137:                      read( req, header, HEADER_SIZE);
                   1138:                      close( req);
                   1139: 
                   1140:                      strcpy( user, headerval( header, H_USER, ""));
                   1141:                      unpadd( user);
                   1142: 
                   1143:                      strcpy( timestr, headerval( header, H_DSTAMP, ""));
                   1144:                      rtime = 0L; sscanf( timestr, "%ld", &rtime);
                   1145:                      strcpy( timestr, ctime(&rtime));
                   1146:                      timestr[strlen(timestr)-1] = 0;
                   1147: 
                   1148:                      free( header);
                   1149: 
                   1150:                      printf( "%s-%s\t\t%c\t%s", user,
                   1151:                         (request+2), *(request+1), timestr);
                   1152: 
                   1153:                      printf( "\ton %s\n", curr_printer);
                   1154: 
                   1155: 
                   1156:                      sprintf( timestr, "%s|", request);
                   1157:                      if ((strlen( request_list)+strlen( timestr))
                   1158:                           < sizeof( request_list))
                   1159:                         strcat( request_list, timestr);
                   1160:                   }
                   1161:                }                  
                   1162:             }
                   1163: 
                   1164:          break;
                   1165:          }
                   1166:    }
                   1167: 
                   1168:    each_printer( E_END);
                   1169: 
                   1170:    return( request_list);
                   1171: }
                   1172: 
                   1173: 
                   1174: 
                   1175: /******************************************************************************
                   1176:    Cancel currently printing requests (not pending ones!).  Kill only the ones
                   1177:    I own.  If I'm superuser, then I own it all.
                   1178: ******************************************************************************/
                   1179: 
                   1180: int kill_printing_request( seqnum, sig, flag)
                   1181: int  seqnum;
                   1182: int  sig;
                   1183: int  flag;
                   1184: {
                   1185:    int   pid, seq, sucessfull = FALSE;
                   1186:    char *list, *t;
                   1187: 
                   1188:    list = report_printer_status( PID_DISPLAY);
                   1189: 
                   1190:    t = strtok( list, " ");
                   1191: 
                   1192:    do {
                   1193:       if (t) {
                   1194:          sscanf( t, "%d|%d", &pid, &seq);
                   1195: 
                   1196:          if ( flag || (seq == seqnum)) 
                   1197:             if (do_i_own_it( seqnum)) {
                   1198:                kill( pid, sig);
                   1199:                sucessfull = TRUE;
                   1200:             }
                   1201: 
                   1202:          t = strtok( NULL, " ");
                   1203:       }
                   1204:    } while (t);
                   1205: 
                   1206:    if (flag) log("Abort Currently Printing Requests");
                   1207: 
                   1208:    return( sucessfull);
                   1209: }
                   1210: 
                   1211: 
                   1212: 
                   1213: 
                   1214: /*****************************************************************************
                   1215:    This routine scans the spool queue looking for request that need to be
                   1216:    removed.  That is, they need to die of old age!  There are four classes
                   1217:    of longevity: (R) reprint, (T) temporary, (S) shortterm, and (L) longterm.
                   1218:    R requests are really just headers and they are deleted as soon as they
                   1219:    have despooled.  This routine handles the other three classes.
                   1220: *****************************************************************************/
                   1221: 
                   1222: #define THOURS 0.5
                   1223: #define SHOURS 24.0
                   1224: #define LHOURS (7.0 * 24.0)
                   1225: 
                   1226: void grim_reaper()
                   1227: {
                   1228:    long   temporary, shortterm, longterm, current, dstamp, elapst;
                   1229:    float  thours, shours, lhours;
                   1230:    char  *entries, *name, header[HEADER_SIZE], path[WORKSTR], life[2];
                   1231:    char   desc[WORKSTR];
                   1232:    int    n, fd, die;
                   1233: 
                   1234:    thours = THOURS; sscanf( controls( TLIFE, ""), "%f", &thours);
                   1235:    shours = SHOURS; sscanf( controls( SLIFE, ""), "%f", &shours);
                   1236:    lhours = LHOURS; sscanf( controls( LLIFE, ""), "%f", &lhours);
                   1237: 
                   1238:    temporary = (long) 3600.0 * thours;
                   1239:    shortterm = (long) 3600.0 * shours;
                   1240:    longterm  = (long) 3600.0 * lhours;
                   1241: 
                   1242:    time( &current);
                   1243: 
                   1244:    entries  = dirlist( QUEUE_PATH, FALSE);  /* return sorted spool queue list */
                   1245:                                             /* This list is a two dimensional */
                   1246:                                             /* array (entries x MAXNAMLEN) */
                   1247:                                             /* Ascending order */
                   1248: 
                   1249:    for ( n = 0; *(name = (entries+(n * MAXNAMLEN))); n++) {
                   1250:       if ( *name == 'R') continue;
                   1251: 
                   1252:       sprintf( path, "%s/%s", QUEUE_PATH, name);
                   1253: 
                   1254:       if ( fd = open( path, O_RDONLY)) {
                   1255:          read( fd, header, HEADER_SIZE);
                   1256:          dstamp = 0L; 
                   1257:          sscanf( headerval( header, H_DSTAMP,    ""), "%ld", &dstamp);
                   1258:          sscanf( headerval( header, H_LONGEVITY, ""), "%1s", life);
                   1259:          strcpy( desc, headerval( header, H_DESC, ""));
                   1260:          unpadd( desc);
                   1261:          close( fd);
                   1262: 
                   1263:          elapst = current - dstamp;    die = FALSE;
                   1264: 
                   1265:          switch (*life) {
                   1266:             case 'T': if (elapst > temporary) die = TRUE; break;
                   1267:             case 'S': if (elapst > shortterm) die = TRUE; break;
                   1268:             case 'L': if (elapst > longterm)  die = TRUE; break;
                   1269:          }
                   1270: 
                   1271:          if (die) { 
                   1272:             log( "Request #%s \"%s\" expired.", &name[2], desc);
                   1273:             unlink( path);
                   1274:             /* printf("unlink %s\n", path); */
                   1275:          }
                   1276:       }
                   1277:    }
                   1278: 
                   1279:    free( entries);
                   1280: }
                   1281: 
                   1282: 
                   1283: 
                   1284: /******************************************************************************
                   1285:   ftok() implements Unix's function of the same name.  Given a valid pathname
                   1286:   and a project identifier, return a "unique" handle.  This handle is used by
                   1287:   the Unix IPC.  If the path is not found, a -1 is returned.  For some reason,
                   1288:   Coherent does not implement this function.
                   1289: ******************************************************************************/
                   1290: 
                   1291: key_t ftok( path, proj)
                   1292: char *path;
                   1293: char  proj;
                   1294: {
                   1295:    struct stat s;
                   1296: 
                   1297:    if (stat( path, &s) == BAD) return( (key_t) -1L);
                   1298: 
                   1299:    return( (key_t) (s.st_ino | (proj << 16) | (s.st_dev << 24)));
                   1300: }
                   1301: 
                   1302: 
                   1303: /******************************************************************************
                   1304:    MLP_Lock.  This routine can lock several critical sections involving MLP
                   1305:    process.  These are: Cancel, Controls and Status.  The controls and status
                   1306:    files need to be locked while they are modified.  The Cancel lock keeps
                   1307:    processes that cancel requests out of the hair of the despooler and vice-
                   1308:    versa.
                   1309: 
                   1310:    ***NOTE***
                   1311:    Because Mark Williams has not implemented SEM_UNDO, we will fall back to
                   1312:    lockfiles for safety reasons.
                   1313: ******************************************************************************/
                   1314: 
                   1315: int locks[IPC_SEMS];    /* contains lockfile fd's */
                   1316: 
                   1317: void MLP_lock( which)
                   1318: int which;
                   1319: {
                   1320:    char path[WORKSTR];
                   1321: 
                   1322:    sprintf( path, "%s/LCK..%d", QUEUE_PATH, which);
                   1323: 
                   1324:    locks[which] = open( path, O_RDWR); lockf( locks[which], F_LOCK, 0L);
                   1325: 
                   1326: /* SEM_UNDO is not yet implemented...
                   1327: 
                   1328:    static struct sembuf lcancel[2]  = { 0,0,0,  0,1,SEM_UNDO };
                   1329:    static struct sembuf lcontrol[2] = { 1,0,0,  1,1,SEM_UNDO };
                   1330:    static struct sembuf lstatus[2]  = { 2,0,0,  2,1,SEM_UNDO };
                   1331:    static struct sembuf llog[2]     = { 3,0,0,  3,1,SEM_UNDO };
                   1332: 
                   1333:    struct sembuf *s;
                   1334:    key_t k;
                   1335:    int   sID;
                   1336: 
                   1337:    k = ftok( IPC_NAME, 1);
                   1338: 
                   1339:    if ((sID = semget( k, IPC_SEMS, IPC_PERMS|IPC_CREAT|IPC_EXCL)) == BAD) {
                   1340:       if ((sID = semget( k, IPC_SEMS, 0)) == BAD) {
                   1341:          return;
                   1342:       }
                   1343:    }
                   1344: 
                   1345:    switch (which) {
                   1346:       case L_CANCEL:  semop( sID, lcancel,  2); break;
                   1347:       case L_CONTROL: semop( sID, lcontrol, 2); break;
                   1348:       case L_STATUS:  semop( sID, lstatus,  2); break;
                   1349:       case L_LOG:     semop( sID, llog,     2); break;
                   1350:    }
                   1351: */
                   1352: }
                   1353: 
                   1354: 
                   1355: 
                   1356: void MLP_unlock( which)
                   1357: int which;
                   1358: {
                   1359:    char path[WORKSTR];
                   1360: 
                   1361:    sprintf( path, "%s/LCK..%d", QUEUE_PATH, which);
                   1362: 
                   1363:    lockf( locks[which], F_ULOCK, 0L); close( locks[which]); unlink( path);
                   1364: 
                   1365: /* SEM_UNDO is not yet implemented...
                   1366: 
                   1367:    static struct sembuf lcancel[1]  = { 0,-1, IPC_NOWAIT|SEM_UNDO };
                   1368:    static struct sembuf lcontrol[1] = { 1,-1, IPC_NOWAIT|SEM_UNDO };
                   1369:    static struct sembuf lstatus[1]  = { 2,-1, IPC_NOWAIT|SEM_UNDO };
                   1370:    static struct sembuf llog[1]  =    { 3,-1, IPC_NOWAIT|SEM_UNDO };
                   1371: 
                   1372:    key_t k;
                   1373:    int   sID;
                   1374: 
                   1375:    k = ftok( IPC_NAME, 1);
                   1376: 
                   1377:    if ((sID = semget( k, IPC_SEMS, IPC_PERMS|IPC_CREAT|IPC_EXCL)) == BAD) {
                   1378:       if ((sID = semget( k, IPC_SEMS, 0)) == BAD) {
                   1379:          return;
                   1380:       }
                   1381:    }
                   1382: 
                   1383:    switch (which) {
                   1384:       case L_CANCEL:  semop( sID, lcancel,  1); break;
                   1385:       case L_CONTROL: semop( sID, lcontrol, 1); break;
                   1386:       case L_STATUS:  semop( sID, lstatus,  1); break;
                   1387:       case L_LOG:     semop( sID, llog,     1); break;
                   1388:    }
                   1389: */
                   1390: }

unix.superglobalmegacorp.com

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