|
|
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( ¤t); ! 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.