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