|
|
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.