1 | /* |
---|
2 | * $Id: printjob.25.c,v 1.2 1999-01-22 23:10:44 ghudson Exp $ |
---|
3 | */ |
---|
4 | |
---|
5 | /* |
---|
6 | * Copyright (c) 1983 Regents of the University of California. |
---|
7 | * All rights reserved. The Berkeley software License Agreement |
---|
8 | * specifies the terms and conditions for redistribution. |
---|
9 | */ |
---|
10 | |
---|
11 | #ifndef lint |
---|
12 | static char sccsid[] = "@(#)printjob.c 5.2 (Berkeley) 9/17/85"; |
---|
13 | static char *rcsid_printjob_c = "$Id: printjob.25.c,v 1.2 1999-01-22 23:10:44 ghudson Exp $"; |
---|
14 | #endif |
---|
15 | |
---|
16 | /* |
---|
17 | * printjob -- print jobs in the queue. |
---|
18 | * |
---|
19 | * NOTE: the lock file is used to pass information to lpq and lprm. |
---|
20 | * it does not need to be removed because file locks are dynamic. |
---|
21 | */ |
---|
22 | |
---|
23 | #include "lp.h" |
---|
24 | #ifdef _AUX_SOURCE |
---|
25 | #include <sys/termio.h> |
---|
26 | #endif |
---|
27 | |
---|
28 | #define DORETURN 0 /* absorb fork error */ |
---|
29 | #define DOABORT 1 /* abort if dofork fails */ |
---|
30 | /* |
---|
31 | * Error tokens |
---|
32 | */ |
---|
33 | #define DEFER -4 /* Defer printing file till later */ |
---|
34 | #define REPRINT -2 |
---|
35 | #define ERROR -1 |
---|
36 | #define OK 0 |
---|
37 | #define FATALERR 1 |
---|
38 | #define NOACCT 2 |
---|
39 | #define FILTERERR 3 |
---|
40 | #define ACCESS 4 |
---|
41 | |
---|
42 | static int network; /* true if network access to printer */ |
---|
43 | #ifdef ZEPHYR |
---|
44 | #undef STAT |
---|
45 | #include <zephyr/zephyr.h> |
---|
46 | |
---|
47 | #define ZCLASS "MESSAGE" |
---|
48 | #define ZINSTANCE "PERSONAL" |
---|
49 | #define ZSENDER "Printer Daemon" |
---|
50 | #define ZDEFAULTFORMAT "$message" |
---|
51 | |
---|
52 | ZNotice_t notice; |
---|
53 | char zrecipient[40+REALM_SZ]; |
---|
54 | char *zmessage[6]; |
---|
55 | char zmessagetext[BUFSIZ]; |
---|
56 | int zerrno; |
---|
57 | int zflag = 0; |
---|
58 | |
---|
59 | static char *zerrtext[]={"Document printing has been deferred", |
---|
60 | "This is impossible", |
---|
61 | "Attempting to reprint document", |
---|
62 | "Generic error", |
---|
63 | "Document has finished printing successfully", |
---|
64 | "Fatal error", |
---|
65 | "No local account, document not printed", |
---|
66 | "Error in document output filter", |
---|
67 | "Error accessing symlinked file"}; |
---|
68 | |
---|
69 | static char *zerrtoken[]={"DEFER","IMPOSSIBLE","REPRINT","ERROR","OK", |
---|
70 | "FATALERR","NOACCT","FILTERERR","ACCESS"}; |
---|
71 | |
---|
72 | #endif ZEPHYR |
---|
73 | |
---|
74 | |
---|
75 | char title[80]; /* ``pr'' title */ |
---|
76 | FILE *cfp = NULL; /* control file */ |
---|
77 | int pfd; /* printer file descriptor */ |
---|
78 | int ofd; /* output filter file descriptor */ |
---|
79 | int lfd = -1; /* lock file descriptor */ |
---|
80 | int pid; /* pid of lpd process */ |
---|
81 | int prchild; /* id of pr process */ |
---|
82 | int child; /* id of any filters */ |
---|
83 | int ofilter; /* id of output filter, if any */ |
---|
84 | int tof; /* true if at top of form */ |
---|
85 | int remote; /* true if sending files to remote */ |
---|
86 | dev_t fdev; /* device of file pointed to by symlink */ |
---|
87 | ino_t fino; /* inode of file pointed to by symlink */ |
---|
88 | |
---|
89 | char fromhost[32]; /* user's host machine */ |
---|
90 | #ifdef KERBEROS |
---|
91 | char logname[ANAME_SZ + INST_SZ + REALM_SZ + 3]; |
---|
92 | #else |
---|
93 | char logname[32]; /* user's login name */ |
---|
94 | #endif KERBEROS |
---|
95 | char jobname[100]; /* job or file name */ |
---|
96 | char queuename[100]; /* print queue name */ |
---|
97 | |
---|
98 | char class[32]; /* classification field */ |
---|
99 | char width[10] = "-w"; /* page width in characters */ |
---|
100 | char length[10] = "-l"; /* page length in lines */ |
---|
101 | char pxwidth[10] = "-x"; /* page width in pixels */ |
---|
102 | char pxlength[10] = "-y"; /* page length in pixels */ |
---|
103 | char indent[10] = "-i0"; /* indentation size in characters */ |
---|
104 | char cost[10] = "-m"; /* Cost/page option */ |
---|
105 | char qacct[128] = "-a"; |
---|
106 | char tpfile[] = "errsXXXXXX"; /* file name for filter output */ |
---|
107 | int lflag; /* Log info flag */ |
---|
108 | int account_flag = 0; |
---|
109 | |
---|
110 | printjob() |
---|
111 | { |
---|
112 | struct stat stb; |
---|
113 | |
---|
114 | register struct queue_ *q, **qp; |
---|
115 | struct queue_ **queue; |
---|
116 | register int i, nitems; |
---|
117 | long pidoff; |
---|
118 | int count = 0; |
---|
119 | extern int abortpr(); |
---|
120 | |
---|
121 | init(); /* set up capabilities */ |
---|
122 | (void) write(1, "", 1); /* ack that daemon is started */ |
---|
123 | setgid(getegid()); |
---|
124 | pid = getpid(); /* for use with lprm */ |
---|
125 | setpgrp(0, pid); |
---|
126 | signal(SIGHUP, abortpr); |
---|
127 | signal(SIGINT, abortpr); |
---|
128 | signal(SIGQUIT, abortpr); |
---|
129 | signal(SIGTERM, abortpr); |
---|
130 | |
---|
131 | (void) mktemp(tpfile); |
---|
132 | |
---|
133 | /* |
---|
134 | * uses short form file names |
---|
135 | */ |
---|
136 | if (chdir(SD) < 0) { |
---|
137 | syslog(LOG_ERR, "%s: %m", SD); |
---|
138 | exit(1); |
---|
139 | } |
---|
140 | if (stat(LO, &stb) == 0 && (stb.st_mode & 0100)) |
---|
141 | exit(0); /* printing disabled */ |
---|
142 | lfd = open(LO, O_WRONLY|O_CREAT, 0644); |
---|
143 | if (lfd < 0) { |
---|
144 | syslog(LOG_ERR, "%s: %s: %m", printer, LO); |
---|
145 | exit(1); |
---|
146 | } |
---|
147 | if (flock(lfd, LOCK_EX|LOCK_NB) < 0) { |
---|
148 | if (errno == EWOULDBLOCK) /* active daemon present */ |
---|
149 | exit(0); |
---|
150 | syslog(LOG_ERR, "%s: %s: %m", printer, LO); |
---|
151 | exit(1); |
---|
152 | } |
---|
153 | ftruncate(lfd, 0); |
---|
154 | /* |
---|
155 | * write process id for others to know |
---|
156 | */ |
---|
157 | sprintf(line, "%u\n", pid); |
---|
158 | pidoff = i = strlen(line); |
---|
159 | if (write(lfd, line, i) != i) { |
---|
160 | syslog(LOG_ERR, "%s: %s: %m", printer, LO); |
---|
161 | exit(1); |
---|
162 | } |
---|
163 | /* |
---|
164 | * search the spool directory for work and sort by queue order. |
---|
165 | */ |
---|
166 | if ((nitems = getq_(&queue)) < 0) { |
---|
167 | syslog(LOG_ERR, "%s: can't scan %s", printer, SD); |
---|
168 | exit(1); |
---|
169 | } |
---|
170 | if (nitems == 0) /* no work to do */ |
---|
171 | { |
---|
172 | if (lflag) syslog(LOG_INFO, "No work on %s.", printer); |
---|
173 | exit(0); |
---|
174 | } |
---|
175 | if (stb.st_mode & 01) { /* reset queue flag */ |
---|
176 | if (fchmod(lfd, stb.st_mode & 0776) < 0) |
---|
177 | syslog(LOG_ERR, "%s: %s: %m", printer, LO); |
---|
178 | } |
---|
179 | if(lflag) syslog("Opening printer on %s", printer); |
---|
180 | openpr(); /* open printer or remote */ |
---|
181 | again: |
---|
182 | /* |
---|
183 | * we found something to do now do it -- |
---|
184 | * write the name of the current control file into the lock file |
---|
185 | * so the spool queue program can tell what we're working on |
---|
186 | */ |
---|
187 | if (lflag)syslog(LOG_INFO,"Got something to print.."); |
---|
188 | for (qp = queue; nitems--; free((char *) q)) { |
---|
189 | q = *qp++; |
---|
190 | if (stat(q->q_name, &stb) < 0) { |
---|
191 | continue; |
---|
192 | } |
---|
193 | restart: |
---|
194 | (void) lseek(lfd, pidoff, 0); |
---|
195 | (void) sprintf(line, "%s\n", q->q_name); |
---|
196 | i = strlen(line); |
---|
197 | if (write(lfd, line, i) != i) |
---|
198 | syslog(LOG_ERR, "%s: %s: %m", printer, LO); |
---|
199 | if (!remote) |
---|
200 | i = printit(q->q_name); |
---|
201 | else |
---|
202 | i = sendit(q->q_name); |
---|
203 | /* |
---|
204 | * Check to see if we are supposed to stop printing or |
---|
205 | * if we are to rebuild the queue. |
---|
206 | */ |
---|
207 | if (fstat(lfd, &stb) == 0) { |
---|
208 | /* stop printing before starting next job? */ |
---|
209 | if (stb.st_mode & 0100) |
---|
210 | goto done; |
---|
211 | /* rebuild queue (after lpc topq) */ |
---|
212 | if (stb.st_mode & 01) { |
---|
213 | for (free((char *) q); nitems--; free((char *) q)) |
---|
214 | q = *qp++; |
---|
215 | if (fchmod(lfd, stb.st_mode & 0776) < 0) |
---|
216 | syslog(LOG_WARNING, "%s: %s: %m", |
---|
217 | printer, LO); |
---|
218 | break; |
---|
219 | } |
---|
220 | if (i == DEFER) { |
---|
221 | if (fchmod(lfd, stb.st_mode | 001) < 0) |
---|
222 | syslog(LOG_WARNING, "%s: %s: %m", |
---|
223 | printer, LO); |
---|
224 | continue; |
---|
225 | } |
---|
226 | } |
---|
227 | if (i == OK) /* file ok and printed */ |
---|
228 | count++; |
---|
229 | else if (i == REPRINT) { /* try reprinting the job */ |
---|
230 | if (lflag)syslog(LOG_INFO, "restarting %s", printer); |
---|
231 | if (ofilter > 0) { |
---|
232 | kill(ofilter, SIGCONT); /* to be sure */ |
---|
233 | (void) close(ofd); |
---|
234 | while ((i = wait(0)) > 0 && i != ofilter) |
---|
235 | ; |
---|
236 | ofilter = 0; |
---|
237 | } |
---|
238 | (void) close(pfd); /* close printer */ |
---|
239 | if (ftruncate(lfd, pidoff) < 0) |
---|
240 | syslog(LOG_WARNING, "%s: %s: %m", printer, LO); |
---|
241 | openpr(); /* try to reopen printer */ |
---|
242 | goto restart; |
---|
243 | } |
---|
244 | } |
---|
245 | free((char *) queue); |
---|
246 | /* |
---|
247 | * search the spool directory for more work. |
---|
248 | */ |
---|
249 | if ((nitems = getq_(&queue)) < 0) { |
---|
250 | syslog(LOG_ERR, "%s: can't scan %s", printer, SD); |
---|
251 | exit(1); |
---|
252 | } |
---|
253 | if (nitems == 0) { /* no more work to do */ |
---|
254 | done: |
---|
255 | if (count > 0) { /* Files actually printed */ |
---|
256 | if (!SF && !tof) |
---|
257 | (void) write(ofd, FF, strlen(FF)); |
---|
258 | if (TR != NULL) /* output trailer */ |
---|
259 | (void) write(ofd, TR, strlen(TR)); |
---|
260 | } |
---|
261 | (void) UNLINK(tpfile); |
---|
262 | exit(0); |
---|
263 | } |
---|
264 | goto again; |
---|
265 | } |
---|
266 | |
---|
267 | char fonts[4][50]; /* fonts for troff */ |
---|
268 | |
---|
269 | char ifonts[4][18] = { |
---|
270 | "/usr/lib/vfont/R", |
---|
271 | "/usr/lib/vfont/I", |
---|
272 | "/usr/lib/vfont/B", |
---|
273 | "/usr/lib/vfont/S" |
---|
274 | }; |
---|
275 | |
---|
276 | /* |
---|
277 | * The remaining part is the reading of the control file (cf) |
---|
278 | * and performing the various actions. |
---|
279 | */ |
---|
280 | printit(file) |
---|
281 | char *file; |
---|
282 | { |
---|
283 | register int i; |
---|
284 | char *cp; |
---|
285 | int bombed = OK; |
---|
286 | |
---|
287 | /* |
---|
288 | * open control file; ignore if no longer there. |
---|
289 | */ |
---|
290 | if ((cfp = fopen(file, "r")) == NULL) { |
---|
291 | syslog(LOG_INFO, "%s: %s: %m", printer, file); |
---|
292 | return(OK); |
---|
293 | } |
---|
294 | /* |
---|
295 | * Try to lock control file. If we fail, defer processing |
---|
296 | * this file till later |
---|
297 | */ |
---|
298 | if (!network && (flock(fileno(cfp), LOCK_EX|LOCK_NB) < 0)) { |
---|
299 | if (errno == EWOULDBLOCK) { |
---|
300 | /* |
---|
301 | * We couldn't get the lock. Probably lprm |
---|
302 | * has locked it, in preparation for blowing |
---|
303 | * it away. So we defer it till later; |
---|
304 | * usually it won't be there, but just in |
---|
305 | * case some other bozo locks the file.... |
---|
306 | */ |
---|
307 | fclose(cfp); |
---|
308 | cfp = NULL; |
---|
309 | return(DEFER); |
---|
310 | } |
---|
311 | syslog(LOG_ERR, "%s: %s: %m", printer, file); |
---|
312 | exit(1); |
---|
313 | } |
---|
314 | |
---|
315 | /* |
---|
316 | * Reset troff fonts. |
---|
317 | */ |
---|
318 | for (i = 0; i < 4; i++) |
---|
319 | strcpy(fonts[i], ifonts[i]); |
---|
320 | sprintf(&width[2], "%d", PW); |
---|
321 | strcpy(indent+2, "0"); |
---|
322 | qacct[2] = NULL; |
---|
323 | jobname[0] = '\0'; |
---|
324 | |
---|
325 | /* |
---|
326 | * read the control file for work to do |
---|
327 | * |
---|
328 | * file format -- first character in the line is a command |
---|
329 | * rest of the line is the argument. |
---|
330 | * valid commands are: |
---|
331 | * |
---|
332 | * S -- "stat info" for symbolic link protection |
---|
333 | * J -- "job name" on banner page |
---|
334 | * C -- "class name" on banner page |
---|
335 | * L -- "literal" user's name to print on banner |
---|
336 | * T -- "title" for pr |
---|
337 | * H -- "host name" of machine where lpr was done |
---|
338 | * P -- "person" user's login name |
---|
339 | * W -- "width" width of page |
---|
340 | * I -- "indent" amount to indent output |
---|
341 | * f -- "file name" name of text file to print |
---|
342 | * l -- "file name" text file with control chars |
---|
343 | * p -- "file name" text file to print with pr(1) |
---|
344 | * t -- "file name" troff(1) file to print |
---|
345 | * n -- "file name" ditroff(1) file to print |
---|
346 | * d -- "file name" dvi file to print |
---|
347 | * g -- "file name" plot(1G) file to print |
---|
348 | * v -- "file name" plain raster file to print |
---|
349 | * c -- "file name" cifplot file to print |
---|
350 | * 1 -- "R font file" for troff |
---|
351 | * 2 -- "I font file" for troff |
---|
352 | * 3 -- "B font file" for troff |
---|
353 | * 4 -- "S font file" for troff |
---|
354 | * N -- "name" of file (used by lpq) |
---|
355 | * U -- "unlink" name of file to remove |
---|
356 | * (after we print it. (Pass 2 only)). |
---|
357 | * M -- "mail" to user when done printing |
---|
358 | * |
---|
359 | * Additions: |
---|
360 | * Z -- send zephyr message to user |
---|
361 | * Q -- Account number for quota management |
---|
362 | * q -- printer queue name |
---|
363 | * getline reads a line and expands tabs to blanks |
---|
364 | */ |
---|
365 | |
---|
366 | /* pass 1 */ |
---|
367 | |
---|
368 | account_flag = 0; |
---|
369 | while (getline(cfp)) |
---|
370 | switch (line[0]) { |
---|
371 | case 'H': |
---|
372 | strcpy(fromhost, line+1); |
---|
373 | if (class[0] == '\0') |
---|
374 | strncpy(class, line+1, sizeof(class)-1); |
---|
375 | continue; |
---|
376 | |
---|
377 | case 'P': |
---|
378 | strncpy(logname, line+1, sizeof(logname)-1); |
---|
379 | if (RS) { /* restricted */ |
---|
380 | if (getpwnam(logname) == (struct passwd *)0) { |
---|
381 | bombed = NOACCT; |
---|
382 | #ifdef ZEPHYR |
---|
383 | sendzephyr(line+1, bombed); |
---|
384 | #else |
---|
385 | sendmail(line+1, bombed); |
---|
386 | #endif ZEPHYR |
---|
387 | goto pass2; |
---|
388 | } |
---|
389 | } |
---|
390 | continue; |
---|
391 | |
---|
392 | case 'A': /* For old client compatibility */ |
---|
393 | case 'Q': |
---|
394 | if (line[1] != '\0') { |
---|
395 | strcpy(&qacct[2], line+1); |
---|
396 | account_flag = 1; |
---|
397 | } |
---|
398 | continue; |
---|
399 | |
---|
400 | case 'S': |
---|
401 | cp = line+1; |
---|
402 | i = 0; |
---|
403 | while (*cp >= '0' && *cp <= '9') |
---|
404 | i = i * 10 + (*cp++ - '0'); |
---|
405 | fdev = i; |
---|
406 | cp++; |
---|
407 | i = 0; |
---|
408 | while (*cp >= '0' && *cp <= '9') |
---|
409 | i = i * 10 + (*cp++ - '0'); |
---|
410 | fino = i; |
---|
411 | continue; |
---|
412 | |
---|
413 | case 'J': |
---|
414 | if (line[1] != '\0') |
---|
415 | strncpy(jobname, line+1, sizeof(jobname)-1); |
---|
416 | else |
---|
417 | strcpy(jobname, " "); |
---|
418 | continue; |
---|
419 | |
---|
420 | case 'C': |
---|
421 | if (line[1] != '\0') |
---|
422 | strncpy(class, line+1, sizeof(class)-1); |
---|
423 | else if (class[0] == '\0') |
---|
424 | { |
---|
425 | struct hostent *hp; |
---|
426 | gethostname(class, sizeof(class)); |
---|
427 | hp = gethostbyname(class); |
---|
428 | if (hp) strcpy(class, hp -> h_name); |
---|
429 | } |
---|
430 | continue; |
---|
431 | |
---|
432 | case 'T': /* header title for pr */ |
---|
433 | strncpy(title, line+1, sizeof(title)-1); |
---|
434 | continue; |
---|
435 | |
---|
436 | case 'L': /* identification line */ |
---|
437 | if (!SH && !HL) |
---|
438 | banner(line+1, jobname); |
---|
439 | continue; |
---|
440 | |
---|
441 | case '1': /* troff fonts */ |
---|
442 | case '2': |
---|
443 | case '3': |
---|
444 | case '4': |
---|
445 | if (line[1] != '\0') |
---|
446 | strcpy(fonts[line[0]-'1'], line+1); |
---|
447 | continue; |
---|
448 | |
---|
449 | case 'W': /* page width */ |
---|
450 | strncpy(width+2, line+1, sizeof(width)-3); |
---|
451 | continue; |
---|
452 | |
---|
453 | case 'I': /* indent amount */ |
---|
454 | strncpy(indent+2, line+1, sizeof(indent)-3); |
---|
455 | continue; |
---|
456 | |
---|
457 | default: /* some file to print */ |
---|
458 | switch (i = print(line[0], line+1)) { |
---|
459 | case ERROR: |
---|
460 | if (bombed == OK) |
---|
461 | bombed = FATALERR; |
---|
462 | break; |
---|
463 | case REPRINT: |
---|
464 | (void) fclose(cfp); |
---|
465 | cfp = NULL; |
---|
466 | |
---|
467 | return(REPRINT); |
---|
468 | case FILTERERR: |
---|
469 | case ACCESS: |
---|
470 | bombed = i; |
---|
471 | #ifdef ZEPHYR |
---|
472 | sendzephyr(logname, bombed); |
---|
473 | #else |
---|
474 | sendmail(logname, bombed); |
---|
475 | #endif ZEPHYR |
---|
476 | } |
---|
477 | title[0] = '\0'; |
---|
478 | continue; |
---|
479 | |
---|
480 | case 'N': |
---|
481 | case 'U': |
---|
482 | case 'M': |
---|
483 | case 'Z': |
---|
484 | case 'E': /* From multics days */ |
---|
485 | continue; |
---|
486 | |
---|
487 | case 'q': |
---|
488 | if (line[1]) { |
---|
489 | strncpy(queuename, line+1, sizeof(queuename)-1); |
---|
490 | printer = queuename; |
---|
491 | } |
---|
492 | continue; |
---|
493 | } |
---|
494 | |
---|
495 | /* pass 2 */ |
---|
496 | |
---|
497 | pass2: |
---|
498 | fseek(cfp, 0L, 0); |
---|
499 | while (getline(cfp)) |
---|
500 | switch (line[0]) { |
---|
501 | case 'L': /* identification line */ |
---|
502 | if (!SH && HL) |
---|
503 | banner(line+1, jobname); |
---|
504 | continue; |
---|
505 | |
---|
506 | case 'M': |
---|
507 | if (bombed < NOACCT) /* already sent if >= NOACCT */ |
---|
508 | sendmail(line+1, bombed); |
---|
509 | continue; |
---|
510 | |
---|
511 | case 'U': |
---|
512 | (void) UNLINK(line+1); |
---|
513 | continue; |
---|
514 | #ifdef ZEPHYR |
---|
515 | case 'Z': |
---|
516 | if (bombed < NOACCT) /* already sent if >= NOACCT */ |
---|
517 | sendzephyr(line+1, bombed); |
---|
518 | continue; |
---|
519 | #endif ZEPHYR |
---|
520 | |
---|
521 | } |
---|
522 | /* |
---|
523 | * clean-up in case another control file exists |
---|
524 | */ |
---|
525 | (void) fclose(cfp); |
---|
526 | cfp = NULL; |
---|
527 | (void) UNLINK(file); |
---|
528 | return(bombed == OK ? OK : ERROR); |
---|
529 | } |
---|
530 | |
---|
531 | /* |
---|
532 | * Print a file. |
---|
533 | * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}. |
---|
534 | * Return -1 if a non-recoverable error occured, |
---|
535 | * 2 if the filter detected some errors (but printed the job anyway), |
---|
536 | * 1 if we should try to reprint this job and |
---|
537 | * 0 if all is well. |
---|
538 | * Note: all filters take stdin as the file, stdout as the printer, |
---|
539 | * stderr as the log file, and must not ignore SIGINT. |
---|
540 | */ |
---|
541 | print(format, file) |
---|
542 | int format; |
---|
543 | char *file; |
---|
544 | { |
---|
545 | register int n; |
---|
546 | register char *prog; |
---|
547 | int fi, fo; |
---|
548 | char *av[15], buf[BUFSIZ]; |
---|
549 | int pid, p[2], stopped = 0; |
---|
550 | #if defined(POSIX) |
---|
551 | int status; |
---|
552 | #else |
---|
553 | union wait status; |
---|
554 | #endif |
---|
555 | struct stat stb; |
---|
556 | |
---|
557 | if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0) |
---|
558 | return(ERROR); |
---|
559 | /* |
---|
560 | * Check to see if data file is a symbolic link. If so, it should |
---|
561 | * still point to the same file or someone is trying to print |
---|
562 | * something he shouldn't. |
---|
563 | */ |
---|
564 | if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 && |
---|
565 | (stb.st_dev != fdev || stb.st_ino != fino)) |
---|
566 | return(ACCESS); |
---|
567 | if (!SF && !tof) { /* start on a fresh page */ |
---|
568 | (void) write(ofd, FF, strlen(FF)); |
---|
569 | tof = 1; |
---|
570 | } |
---|
571 | if (IF == NULL && (format == 'f' || format == 'l')) { |
---|
572 | tof = 0; |
---|
573 | while ((n = read(fi, buf, BUFSIZ)) > 0) |
---|
574 | if (write(ofd, buf, n) != n) { |
---|
575 | (void) close(fi); |
---|
576 | return(REPRINT); |
---|
577 | } |
---|
578 | (void) close(fi); |
---|
579 | return(OK); |
---|
580 | } |
---|
581 | switch (format) { |
---|
582 | case 'p': /* print file using 'pr' */ |
---|
583 | if (IF == NULL) { /* use output filter */ |
---|
584 | prog = PR; |
---|
585 | av[0] = "pr"; |
---|
586 | av[1] = width; |
---|
587 | av[2] = length; |
---|
588 | av[3] = "-h"; |
---|
589 | av[4] = *title ? title : " "; |
---|
590 | av[5] = 0; |
---|
591 | fo = ofd; |
---|
592 | goto start; |
---|
593 | } |
---|
594 | pipe(p); |
---|
595 | if ((prchild = dofork(DORETURN)) == 0) { /* child */ |
---|
596 | dup2(fi, 0); /* file is stdin */ |
---|
597 | dup2(p[1], 1); /* pipe is stdout */ |
---|
598 | for (n = 3; n < NOFILE; n++) |
---|
599 | (void) close(n); |
---|
600 | execl(PR, "pr", width, length, "-h", *title ? title : " ", 0); |
---|
601 | syslog(LOG_ERR, "cannot execl %s", PR); |
---|
602 | exit(2); |
---|
603 | } |
---|
604 | (void) close(p[1]); /* close output side */ |
---|
605 | (void) close(fi); |
---|
606 | if (prchild < 0) { |
---|
607 | prchild = 0; |
---|
608 | (void) close(p[0]); |
---|
609 | return(ERROR); |
---|
610 | } |
---|
611 | fi = p[0]; /* use pipe for input */ |
---|
612 | case 'f': /* print plain text file */ |
---|
613 | prog = IF; |
---|
614 | av[1] = width; |
---|
615 | av[2] = length; |
---|
616 | av[3] = indent; |
---|
617 | n = 4; |
---|
618 | break; |
---|
619 | case 'l': /* like 'f' but pass control characters */ |
---|
620 | prog = IF; |
---|
621 | av[1] = "-c"; |
---|
622 | av[2] = width; |
---|
623 | av[3] = length; |
---|
624 | av[4] = indent; |
---|
625 | n = 5; |
---|
626 | break; |
---|
627 | case 'r': /* print a fortran text file */ |
---|
628 | prog = RF; |
---|
629 | av[1] = width; |
---|
630 | av[2] = length; |
---|
631 | n = 3; |
---|
632 | break; |
---|
633 | case 't': /* print troff output */ |
---|
634 | case 'n': /* print ditroff output */ |
---|
635 | case 'd': /* print tex output */ |
---|
636 | (void) UNLINK(".railmag"); |
---|
637 | if ((fo = creat(".railmag", FILMOD)) < 0) { |
---|
638 | syslog(LOG_ERR, "%s: cannot create .railmag", printer); |
---|
639 | (void) UNLINK(".railmag"); |
---|
640 | } else { |
---|
641 | for (n = 0; n < 4; n++) { |
---|
642 | if (fonts[n][0] != '/') |
---|
643 | (void) write(fo, "/usr/lib/vfont/", 15); |
---|
644 | (void) write(fo, fonts[n], strlen(fonts[n])); |
---|
645 | (void) write(fo, "\n", 1); |
---|
646 | } |
---|
647 | (void) close(fo); |
---|
648 | } |
---|
649 | prog = (format == 't') ? TF : (format == 'n') ? NF : DF; |
---|
650 | av[1] = pxwidth; |
---|
651 | av[2] = pxlength; |
---|
652 | n = 3; |
---|
653 | break; |
---|
654 | case 'c': /* print cifplot output */ |
---|
655 | prog = CF; |
---|
656 | av[1] = pxwidth; |
---|
657 | av[2] = pxlength; |
---|
658 | n = 3; |
---|
659 | break; |
---|
660 | case 'g': /* print plot(1G) output */ |
---|
661 | prog = GF; |
---|
662 | av[1] = pxwidth; |
---|
663 | av[2] = pxlength; |
---|
664 | n = 3; |
---|
665 | break; |
---|
666 | case 'v': /* print raster output */ |
---|
667 | prog = VF; |
---|
668 | av[1] = pxwidth; |
---|
669 | av[2] = pxlength; |
---|
670 | n = 3; |
---|
671 | break; |
---|
672 | default: |
---|
673 | (void) close(fi); |
---|
674 | syslog(LOG_ERR, "%s: illegal format character '%c'", |
---|
675 | printer, format); |
---|
676 | return(ERROR); |
---|
677 | } |
---|
678 | if ((av[0] = rindex(prog, '/')) != NULL) |
---|
679 | av[0]++; |
---|
680 | else |
---|
681 | av[0] = prog; |
---|
682 | av[n++] = "-P"; |
---|
683 | av[n++] = printer; |
---|
684 | av[n++] = "-n"; |
---|
685 | av[n++] = logname; |
---|
686 | av[n++] = "-h"; |
---|
687 | av[n++] = fromhost; |
---|
688 | av[n++] = cost; |
---|
689 | if (account_flag) |
---|
690 | av[n++] = qacct; |
---|
691 | av[n++] = AF; |
---|
692 | av[n] = 0; |
---|
693 | fo = pfd; |
---|
694 | if (ofilter > 0) { /* stop output filter */ |
---|
695 | write(ofd, "\031\1", 2); |
---|
696 | #if defined(POSIX) |
---|
697 | while ((pid = waitpid(-1,&status, WUNTRACED)) > 0 && pid != ofilter) |
---|
698 | #else |
---|
699 | while ((pid = wait3(&status, WUNTRACED, 0)) > 0 && pid != ofilter) |
---|
700 | #endif |
---|
701 | ; |
---|
702 | if (pid == -1 || !WIFSTOPPED(status)) { |
---|
703 | (void) close(fi); |
---|
704 | syslog(LOG_WARNING, "%s: output filter died (%d)", |
---|
705 | printer, status); |
---|
706 | return(REPRINT); |
---|
707 | } |
---|
708 | stopped++; |
---|
709 | } |
---|
710 | start: |
---|
711 | if ((child = dofork(DORETURN)) == 0) { /* child */ |
---|
712 | dup2(fi, 0); |
---|
713 | dup2(fo, 1); |
---|
714 | n = open(tpfile, O_WRONLY|O_CREAT|O_TRUNC, 0664); |
---|
715 | if (n >= 0) |
---|
716 | dup2(n, 2); |
---|
717 | for (n = 3; n < NOFILE; n++) |
---|
718 | (void) close(n); |
---|
719 | execv(prog, av); |
---|
720 | syslog(LOG_ERR, "cannot execv %s", prog); |
---|
721 | exit(2); |
---|
722 | } |
---|
723 | (void) close(fi); |
---|
724 | if (child < 0) |
---|
725 | #if defined(POSIX) |
---|
726 | status= 100; |
---|
727 | #else |
---|
728 | status.w_retcode = 100; |
---|
729 | #endif |
---|
730 | else |
---|
731 | while ((pid = wait(&status)) > 0 && pid != child) |
---|
732 | ; |
---|
733 | child = 0; |
---|
734 | prchild = 0; |
---|
735 | if (stopped) { /* restart output filter */ |
---|
736 | if (kill(ofilter, SIGCONT) < 0) { |
---|
737 | syslog(LOG_ERR, "cannot restart output filter"); |
---|
738 | exit(1); |
---|
739 | } |
---|
740 | } |
---|
741 | tof = 0; |
---|
742 | #ifdef _AUX_SOURCE |
---|
743 | /* WIFEXITED on the MAC with POSIX_SOURCE uses wrong macro */ |
---|
744 | if (!(((status).w_stopval != WSTOPPED && (status).w_termsig == 0))) { |
---|
745 | #else |
---|
746 | if (!WIFEXITED(status)) { |
---|
747 | #endif |
---|
748 | syslog(LOG_WARNING, "%s: Daemon filter '%c' terminated (%d)", |
---|
749 | printer, format, WTERMSIG(status)); |
---|
750 | return(ERROR); |
---|
751 | } |
---|
752 | switch (WEXITSTATUS(status)) { |
---|
753 | case 0: |
---|
754 | tof = 1; |
---|
755 | return(OK); |
---|
756 | case 1: |
---|
757 | return(REPRINT); |
---|
758 | default: |
---|
759 | syslog(LOG_WARNING, "%s: Daemon filter '%c' exited (%d)", |
---|
760 | printer, format, WEXITSTATUS(status)); |
---|
761 | case 2: |
---|
762 | return(ERROR); |
---|
763 | } |
---|
764 | } |
---|
765 | |
---|
766 | /* |
---|
767 | * Send the daemon control file (cf) and any data files. |
---|
768 | * Return -1 if a non-recoverable error occured, 1 if a recoverable error and |
---|
769 | * 0 if all is well. |
---|
770 | */ |
---|
771 | sendit(file) |
---|
772 | char *file; |
---|
773 | { |
---|
774 | register int i, err = OK; |
---|
775 | char *cp, last[BUFSIZ]; |
---|
776 | |
---|
777 | /* |
---|
778 | * open control file |
---|
779 | */ |
---|
780 | if ((cfp = fopen(file, "r")) == NULL) |
---|
781 | return(OK); |
---|
782 | /* |
---|
783 | * read the control file for work to do |
---|
784 | * |
---|
785 | * file format -- first character in the line is a command |
---|
786 | * rest of the line is the argument. |
---|
787 | * commands of interest are: |
---|
788 | * |
---|
789 | * a-z -- "file name" name of file to print |
---|
790 | * U -- "unlink" name of file to remove |
---|
791 | * (after we print it. (Pass 2 only)). |
---|
792 | */ |
---|
793 | |
---|
794 | /* |
---|
795 | * pass 1 |
---|
796 | */ |
---|
797 | while (getline(cfp)) { |
---|
798 | again: |
---|
799 | if (line[0] == 'S') { |
---|
800 | cp = line+1; |
---|
801 | i = 0; |
---|
802 | while (*cp >= '0' && *cp <= '9') |
---|
803 | i = i * 10 + (*cp++ - '0'); |
---|
804 | fdev = i; |
---|
805 | cp++; |
---|
806 | i = 0; |
---|
807 | while (*cp >= '0' && *cp <= '9') |
---|
808 | i = i * 10 + (*cp++ - '0'); |
---|
809 | fino = i; |
---|
810 | continue; |
---|
811 | } |
---|
812 | if (line[0] >= 'a' && line[0] <= 'z') { |
---|
813 | strcpy(last, line); |
---|
814 | while (i = getline(cfp)) |
---|
815 | if (strcmp(last, line)) |
---|
816 | break; |
---|
817 | switch (sendfile('\3', last+1)) { |
---|
818 | case OK: |
---|
819 | if (i) |
---|
820 | goto again; |
---|
821 | break; |
---|
822 | case REPRINT: |
---|
823 | (void) fclose(cfp); |
---|
824 | cfp = NULL; |
---|
825 | return(REPRINT); |
---|
826 | case ACCESS: |
---|
827 | #ifdef ZEPHYR |
---|
828 | sendmail(logname, ACCESS); |
---|
829 | #else |
---|
830 | sendzephyr(logname, ACCESS); |
---|
831 | #endif ZEPHYR |
---|
832 | case ERROR: |
---|
833 | err = ERROR; |
---|
834 | } |
---|
835 | break; |
---|
836 | } |
---|
837 | } |
---|
838 | if (err == OK && sendfile('\2', file) > 0) { |
---|
839 | (void) fclose(cfp); |
---|
840 | cfp = NULL; |
---|
841 | return(REPRINT); |
---|
842 | } |
---|
843 | /* |
---|
844 | * pass 2 |
---|
845 | */ |
---|
846 | fseek(cfp, 0L, 0); |
---|
847 | while (getline(cfp)) |
---|
848 | if (line[0] == 'U') |
---|
849 | (void) UNLINK(line+1); |
---|
850 | /* |
---|
851 | * clean-up in case another control file exists |
---|
852 | */ |
---|
853 | (void) fclose(cfp); |
---|
854 | cfp = NULL; |
---|
855 | (void) UNLINK(file); |
---|
856 | return(err); |
---|
857 | } |
---|
858 | |
---|
859 | /* |
---|
860 | * Send a data file to the remote machine and spool it. |
---|
861 | * Return positive if we should try resending. |
---|
862 | */ |
---|
863 | sendfile(type, file) |
---|
864 | char type, *file; |
---|
865 | { |
---|
866 | register int f, i, amt; |
---|
867 | struct stat stb; |
---|
868 | char buf[BUFSIZ]; |
---|
869 | int sizerr, resp; |
---|
870 | |
---|
871 | if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0) |
---|
872 | return(ERROR); |
---|
873 | /* |
---|
874 | * Check to see if data file is a symbolic link. If so, it should |
---|
875 | * still point to the same file or someone is trying to print something |
---|
876 | * he shouldn't. |
---|
877 | */ |
---|
878 | if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 && |
---|
879 | (stb.st_dev != fdev || stb.st_ino != fino)) |
---|
880 | return(ACCESS); |
---|
881 | (void) sprintf(buf, "%c%d %s\n", type, stb.st_size, file); |
---|
882 | amt = strlen(buf); |
---|
883 | for (i = 0; ; i++) { |
---|
884 | if (write(pfd, buf, amt) != amt || |
---|
885 | (resp = response()) < 0 || resp == '\1') { |
---|
886 | (void) close(f); |
---|
887 | return(REPRINT); |
---|
888 | } else if (resp == '\0') |
---|
889 | break; |
---|
890 | if (i == 0) |
---|
891 | status("no space on remote; waiting for queue to drain"); |
---|
892 | if (i == 10) |
---|
893 | syslog(LOG_ALERT, "%s: can't send to %s; queue full", |
---|
894 | printer, RM); |
---|
895 | sleep(5 * 60); |
---|
896 | } |
---|
897 | if (i) |
---|
898 | status("sending to %s", RM); |
---|
899 | sizerr = 0; |
---|
900 | for (i = 0; i < stb.st_size; i += BUFSIZ) { |
---|
901 | amt = BUFSIZ; |
---|
902 | if (i + amt > stb.st_size) |
---|
903 | amt = stb.st_size - i; |
---|
904 | if (sizerr == 0 && read(f, buf, amt) != amt) |
---|
905 | sizerr = 1; |
---|
906 | if (write(pfd, buf, amt) != amt) { |
---|
907 | (void) close(f); |
---|
908 | return(REPRINT); |
---|
909 | } |
---|
910 | } |
---|
911 | (void) close(f); |
---|
912 | if (sizerr) { |
---|
913 | syslog(LOG_INFO, "%s: %s: changed size", printer, file); |
---|
914 | /* tell recvjob to ignore this file */ |
---|
915 | (void) write(pfd, "\1", 1); |
---|
916 | return(ERROR); |
---|
917 | } |
---|
918 | if (write(pfd, "", 1) != 1 || response()) |
---|
919 | return(REPRINT); |
---|
920 | return(OK); |
---|
921 | } |
---|
922 | |
---|
923 | /* |
---|
924 | * Check to make sure there have been no errors and that both programs |
---|
925 | * are in sync with eachother. |
---|
926 | * Return non-zero if the connection was lost. |
---|
927 | */ |
---|
928 | response() |
---|
929 | { |
---|
930 | char resp; |
---|
931 | |
---|
932 | if (read(pfd, &resp, 1) != 1) { |
---|
933 | syslog(LOG_INFO, "%s: lost connection", printer); |
---|
934 | return(-1); |
---|
935 | } |
---|
936 | return(resp); |
---|
937 | } |
---|
938 | |
---|
939 | /* |
---|
940 | * Banner printing stuff |
---|
941 | */ |
---|
942 | banner(name1, name2) |
---|
943 | char *name1, *name2; |
---|
944 | { |
---|
945 | time_t tvec; |
---|
946 | extern char *ctime(); |
---|
947 | |
---|
948 | time(&tvec); |
---|
949 | if (!SF && !tof) |
---|
950 | (void) write(ofd, FF, strlen(FF)); |
---|
951 | if (SB) { /* short banner only */ |
---|
952 | if (class[0]) { |
---|
953 | (void) write(ofd, class, strlen(class)); |
---|
954 | (void) write(ofd, ":", 1); |
---|
955 | } |
---|
956 | (void) write(ofd, name1, strlen(name1)); |
---|
957 | (void) write(ofd, " Job: ", 7); |
---|
958 | (void) write(ofd, name2, strlen(name2)); |
---|
959 | (void) write(ofd, " Date: ", 8); |
---|
960 | (void) write(ofd, ctime(&tvec), 24); |
---|
961 | (void) write(ofd, "\n", 1); |
---|
962 | } else { /* normal banner */ |
---|
963 | (void) write(ofd, "\n\n\n", 3); |
---|
964 | scan_out(ofd, name1, '\0'); |
---|
965 | (void) write(ofd, "\n\n", 2); |
---|
966 | scan_out(ofd, name2, '\0'); |
---|
967 | if (class[0]) { |
---|
968 | register char *cp; |
---|
969 | (void) write(ofd,"\n\n\n",3); |
---|
970 | /* Take out domain names, if any */ |
---|
971 | if (cp = index(class, '.')) *cp = '\0'; |
---|
972 | scan_out(ofd, class, '\0'); |
---|
973 | } |
---|
974 | (void) write(ofd, "\n\n\n\n\t\t\t\tJob: ", 17); |
---|
975 | (void) write(ofd, name2, strlen(name2)); |
---|
976 | |
---|
977 | (void) write(ofd, "\n\t\t\t\tUser: ", 14); |
---|
978 | if (logname[0]) (void) write (ofd, logname, strlen(logname)); |
---|
979 | else (void) write(ofd, name1, strlen(name1)); |
---|
980 | |
---|
981 | if (class[0] || fromhost[0]) { |
---|
982 | (void) write (ofd, "@", 1); |
---|
983 | if (fromhost[0]) { |
---|
984 | (void) write (ofd, fromhost, strlen(fromhost)); |
---|
985 | } |
---|
986 | else { |
---|
987 | (void) write (ofd, class, strlen(class)); |
---|
988 | } |
---|
989 | } |
---|
990 | |
---|
991 | (void) write(ofd, "\n\t\t\t\tDate: ", 14); |
---|
992 | (void) write(ofd, ctime(&tvec), 24); |
---|
993 | |
---|
994 | if (printer != (char *) NULL && *printer != '\0') { |
---|
995 | (void) write (ofd, "\n\t\t\t\tPrinter: ", 14); |
---|
996 | (void) write (ofd, printer, strlen(printer)); |
---|
997 | if (host != (char *) NULL && *host != '\0') { |
---|
998 | (void) write (ofd, " (on ", 5); |
---|
999 | (void) write (ofd, host, strlen(host)); |
---|
1000 | (void) write (ofd, ")", 1); |
---|
1001 | } |
---|
1002 | } |
---|
1003 | |
---|
1004 | (void) write(ofd, "\n", 1); |
---|
1005 | } |
---|
1006 | if (!SF) |
---|
1007 | (void) write(ofd, FF, strlen(FF)); |
---|
1008 | tof = 1; |
---|
1009 | } |
---|
1010 | |
---|
1011 | char * |
---|
1012 | scnline(key, p, c) |
---|
1013 | register char key, *p; |
---|
1014 | char c; |
---|
1015 | { |
---|
1016 | register int scnwidth; |
---|
1017 | |
---|
1018 | for (scnwidth = WIDTH; --scnwidth;) { |
---|
1019 | key <<= 1; |
---|
1020 | *p++ = key & 0200 ? c : BACKGND; |
---|
1021 | } |
---|
1022 | return (p); |
---|
1023 | } |
---|
1024 | |
---|
1025 | #define TRC(q) (((q)-' ')&0177) |
---|
1026 | |
---|
1027 | scan_out(scfd, scsp, dlm) |
---|
1028 | int scfd; |
---|
1029 | char *scsp, dlm; |
---|
1030 | { |
---|
1031 | register char *strp; |
---|
1032 | register nchrs, j; |
---|
1033 | char outbuf[LINELEN+1], *sp, c, cc; |
---|
1034 | int d, scnhgt; |
---|
1035 | extern char scnkey[][HEIGHT]; /* in lpdchar.c */ |
---|
1036 | |
---|
1037 | for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) { |
---|
1038 | strp = &outbuf[0]; |
---|
1039 | sp = scsp; |
---|
1040 | for (nchrs = 0; ; ) { |
---|
1041 | d = dropit(c = TRC(cc = *sp++)); |
---|
1042 | if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d)) |
---|
1043 | for (j = WIDTH; --j;) |
---|
1044 | *strp++ = BACKGND; |
---|
1045 | else |
---|
1046 | strp = scnline(scnkey[c][scnhgt-1-d], strp, cc); |
---|
1047 | if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1) |
---|
1048 | break; |
---|
1049 | *strp++ = BACKGND; |
---|
1050 | *strp++ = BACKGND; |
---|
1051 | } |
---|
1052 | while (*--strp == BACKGND && strp >= outbuf) |
---|
1053 | ; |
---|
1054 | strp++; |
---|
1055 | *strp++ = '\n'; |
---|
1056 | (void) write(scfd, outbuf, strp-outbuf); |
---|
1057 | } |
---|
1058 | } |
---|
1059 | |
---|
1060 | dropit(c) |
---|
1061 | char c; |
---|
1062 | { |
---|
1063 | switch(c) { |
---|
1064 | |
---|
1065 | case TRC('_'): |
---|
1066 | case TRC(';'): |
---|
1067 | case TRC(','): |
---|
1068 | case TRC('g'): |
---|
1069 | case TRC('j'): |
---|
1070 | case TRC('p'): |
---|
1071 | case TRC('q'): |
---|
1072 | case TRC('y'): |
---|
1073 | return (DROP); |
---|
1074 | |
---|
1075 | default: |
---|
1076 | return (0); |
---|
1077 | } |
---|
1078 | } |
---|
1079 | |
---|
1080 | /* |
---|
1081 | * sendmail --- |
---|
1082 | * tell people about job completion |
---|
1083 | */ |
---|
1084 | sendmail(user, bombed) |
---|
1085 | char *user; |
---|
1086 | int bombed; |
---|
1087 | { |
---|
1088 | register int i; |
---|
1089 | int p[2], s; |
---|
1090 | register char *cp; |
---|
1091 | char buf[100]; |
---|
1092 | struct stat stb; |
---|
1093 | FILE *fp; |
---|
1094 | #ifdef ALLOW_MAIL |
---|
1095 | pipe(p); |
---|
1096 | if ((s = dofork(DORETURN)) == 0) { /* child */ |
---|
1097 | dup2(p[0], 0); |
---|
1098 | for (i = 3; i < NOFILE; i++) |
---|
1099 | (void) close(i); |
---|
1100 | if ((cp = rindex(MAIL, '/')) != NULL) |
---|
1101 | cp++; |
---|
1102 | else |
---|
1103 | cp = MAIL; |
---|
1104 | sprintf(buf, "%s@%s", user, fromhost); |
---|
1105 | execl(MAIL, cp, buf, 0); |
---|
1106 | exit(0); |
---|
1107 | } else if (s > 0) { /* parent */ |
---|
1108 | dup2(p[1], 1); |
---|
1109 | printf("To: %s@%s\n", user, fromhost); |
---|
1110 | printf("Subject: printer job\n\n"); |
---|
1111 | printf("Your printer job "); |
---|
1112 | if (*jobname) |
---|
1113 | printf("(%s) ", jobname); |
---|
1114 | switch (bombed) { |
---|
1115 | case OK: |
---|
1116 | printf("\ncompleted successfully\n"); |
---|
1117 | break; |
---|
1118 | default: |
---|
1119 | case FATALERR: |
---|
1120 | printf("\ncould not be printed\n"); |
---|
1121 | break; |
---|
1122 | case NOACCT: |
---|
1123 | printf("\ncould not be printed without an account on %s\n", host); |
---|
1124 | break; |
---|
1125 | case FILTERERR: |
---|
1126 | if (stat(tpfile, &stb) < 0 || stb.st_size == 0 || |
---|
1127 | (fp = fopen(tpfile, "r")) == NULL) { |
---|
1128 | printf("\nwas printed but had some errors\n"); |
---|
1129 | break; |
---|
1130 | } |
---|
1131 | printf("\nwas printed but had the following errors:\n"); |
---|
1132 | while ((i = getc(fp)) != EOF) |
---|
1133 | putchar(i); |
---|
1134 | (void) fclose(fp); |
---|
1135 | break; |
---|
1136 | case ACCESS: |
---|
1137 | printf("\nwas not printed because it was not linked to the original file\n"); |
---|
1138 | } |
---|
1139 | fflush(stdout); |
---|
1140 | (void) close(1); |
---|
1141 | } |
---|
1142 | (void) close(p[0]); |
---|
1143 | (void) close(p[1]); |
---|
1144 | wait(&s); |
---|
1145 | #endif |
---|
1146 | } |
---|
1147 | |
---|
1148 | #ifdef ZEPHYR |
---|
1149 | sendzephyr(user, bombed) |
---|
1150 | char *user; |
---|
1151 | int bombed; |
---|
1152 | { |
---|
1153 | notice.z_kind=UNACKED; |
---|
1154 | notice.z_port=0; |
---|
1155 | notice.z_class=ZCLASS; |
---|
1156 | notice.z_class_inst=ZINSTANCE; |
---|
1157 | notice.z_opcode=""; |
---|
1158 | notice.z_sender=ZSENDER; |
---|
1159 | strcpy(zrecipient,logname); |
---|
1160 | notice.z_recipient=zrecipient; |
---|
1161 | notice.z_default_format=ZDEFAULTFORMAT; |
---|
1162 | notice.z_num_other_fields=0; |
---|
1163 | |
---|
1164 | if(*jobname) |
---|
1165 | sprintf(zmessagetext,"Printer status for %s:\n\nJob name: %s\n%s", |
---|
1166 | printer,jobname,zerrtext[bombed+4]); |
---|
1167 | else |
---|
1168 | sprintf(zmessagetext,"Printer status for %s:\n\n%s", |
---|
1169 | printer,zerrtext[bombed+4]); |
---|
1170 | zmessage[0]="Printer Daemon"; |
---|
1171 | zmessage[1]=zmessagetext; |
---|
1172 | zmessage[2]=printer; |
---|
1173 | zmessage[3]=line+1; |
---|
1174 | zmessage[4]=zerrtext[bombed+4]; |
---|
1175 | zmessage[5]=zerrtoken[bombed+4]; |
---|
1176 | |
---|
1177 | if (zerrno=ZSendList(¬ice,zmessage,6,ZNOAUTH)) |
---|
1178 | syslog(LOG_ERR,"Error sending zephyr notification: zerrno=%d", |
---|
1179 | zerrno); |
---|
1180 | } |
---|
1181 | #endif ZEPHYR |
---|
1182 | |
---|
1183 | |
---|
1184 | /* |
---|
1185 | * dofork - fork with retries on failure |
---|
1186 | */ |
---|
1187 | dofork(action) |
---|
1188 | int action; |
---|
1189 | { |
---|
1190 | register int i, pid; |
---|
1191 | |
---|
1192 | for (i = 0; i < 20; i++) { |
---|
1193 | if ((pid = fork()) < 0) { |
---|
1194 | sleep((unsigned)(i*i)); |
---|
1195 | continue; |
---|
1196 | } |
---|
1197 | /* |
---|
1198 | * Child should run as daemon instead of root |
---|
1199 | */ |
---|
1200 | if (pid == 0) |
---|
1201 | setuid(DU); |
---|
1202 | return(pid); |
---|
1203 | } |
---|
1204 | syslog(LOG_ERR, "can't fork"); |
---|
1205 | |
---|
1206 | switch (action) { |
---|
1207 | case DORETURN: |
---|
1208 | return (-1); |
---|
1209 | default: |
---|
1210 | syslog(LOG_ERR, "bad action (%d) to dofork", action); |
---|
1211 | /*FALL THRU*/ |
---|
1212 | case DOABORT: |
---|
1213 | exit(1); |
---|
1214 | } |
---|
1215 | /*NOTREACHED*/ |
---|
1216 | } |
---|
1217 | |
---|
1218 | /* |
---|
1219 | * Kill child processes to abort current job. |
---|
1220 | */ |
---|
1221 | abortpr() |
---|
1222 | { |
---|
1223 | int hard_kill(); |
---|
1224 | |
---|
1225 | /* Drop the lock on the control file, if necessary */ |
---|
1226 | if (cfp) |
---|
1227 | (void) fclose(cfp); |
---|
1228 | /* Drop lock on lock file as well */ |
---|
1229 | if (lfd > 0) |
---|
1230 | (void) close(lfd); |
---|
1231 | (void) UNLINK(tpfile); |
---|
1232 | kill(0, SIGINT); |
---|
1233 | if (ofilter > 0) |
---|
1234 | kill(ofilter, SIGCONT); |
---|
1235 | signal(SIGALRM, hard_kill); |
---|
1236 | alarm(30); |
---|
1237 | while (wait(0) > 0) |
---|
1238 | ; |
---|
1239 | exit(0); |
---|
1240 | } |
---|
1241 | |
---|
1242 | hard_kill() |
---|
1243 | { |
---|
1244 | kill(0, SIGKILL); |
---|
1245 | } |
---|
1246 | |
---|
1247 | init() |
---|
1248 | { |
---|
1249 | int status; |
---|
1250 | |
---|
1251 | #ifdef HESIOD |
---|
1252 | if ((status = pgetent(line, printer)) <= 0) { |
---|
1253 | if (pralias(alibuf, printer)) |
---|
1254 | printer = alibuf; |
---|
1255 | if ((status = hpgetent(line, printer)) < 1) |
---|
1256 | fatal("unknown printer"); |
---|
1257 | } |
---|
1258 | #else |
---|
1259 | if ((status = pgetent(line, printer)) < 0) { |
---|
1260 | fatal("can't open printer description file"); |
---|
1261 | } else if (status == 0) |
---|
1262 | fatal("unknown printer"); |
---|
1263 | #endif HESIOD |
---|
1264 | if ((LP = pgetstr("lp", &bp)) == NULL) |
---|
1265 | LP = DEFDEVLP; |
---|
1266 | if ((RP = pgetstr("rp", &bp)) == NULL) |
---|
1267 | RP = DEFLP; |
---|
1268 | if ((LO = pgetstr("lo", &bp)) == NULL) |
---|
1269 | LO = DEFLOCK; |
---|
1270 | if ((ST = pgetstr("st", &bp)) == NULL) |
---|
1271 | ST = DEFSTAT; |
---|
1272 | if ((LF = pgetstr("lf", &bp)) == NULL) |
---|
1273 | LF = DEFLOGF; |
---|
1274 | if ((SD = pgetstr("sd", &bp)) == NULL) |
---|
1275 | SD = DEFSPOOL; |
---|
1276 | if ((DU = pgetnum("du")) < 0) |
---|
1277 | DU = DEFUID; |
---|
1278 | if ((FF = pgetstr("ff", &bp)) == NULL) |
---|
1279 | FF = DEFFF; |
---|
1280 | if ((PW = pgetnum("pw")) < 0) |
---|
1281 | PW = DEFWIDTH; |
---|
1282 | sprintf(&width[2], "%d", PW); |
---|
1283 | if ((PL = pgetnum("pl")) < 0) |
---|
1284 | PL = DEFLENGTH; |
---|
1285 | sprintf(&length[2], "%d", PL); |
---|
1286 | #ifdef PQUOTA |
---|
1287 | if ((CP = pgetnum("pc")) < 0) |
---|
1288 | CP = DEFPC; |
---|
1289 | sprintf(&cost[2], "%d", CP); |
---|
1290 | #endif |
---|
1291 | if ((PX = pgetnum("px")) < 0) |
---|
1292 | PX = 0; |
---|
1293 | sprintf(&pxwidth[2], "%d", PX); |
---|
1294 | if ((PY = pgetnum("py")) < 0) |
---|
1295 | PY = 0; |
---|
1296 | sprintf(&pxlength[2], "%d", PY); |
---|
1297 | RM = pgetstr("rm", &bp); |
---|
1298 | |
---|
1299 | |
---|
1300 | /* |
---|
1301 | * Figure out whether the local machine is the same as the remote |
---|
1302 | * machine entry (if it exists). If not, then ignore the local |
---|
1303 | * queue information. |
---|
1304 | */ |
---|
1305 | |
---|
1306 | if (RM != (char *) NULL) { |
---|
1307 | |
---|
1308 | char name[255]; |
---|
1309 | struct hostent *hp; |
---|
1310 | |
---|
1311 | /* get the name of the local host */ |
---|
1312 | gethostname (name, sizeof(name) - 1); |
---|
1313 | name[sizeof(name)-1] = '\0'; |
---|
1314 | |
---|
1315 | /* get the network standard name of the local host */ |
---|
1316 | hp = gethostbyname (name); |
---|
1317 | if (hp == (struct hostent *) NULL) { |
---|
1318 | printf ("unable to get hostname for local machine %s\n", |
---|
1319 | name); |
---|
1320 | } else { |
---|
1321 | strcpy (name, hp->h_name); |
---|
1322 | |
---|
1323 | /* get the network standard name of RM */ |
---|
1324 | hp = gethostbyname (RM); |
---|
1325 | if (hp == (struct hostent *) NULL) { |
---|
1326 | printf ("unable to get hostname for remote machine %s\n", |
---|
1327 | RM); |
---|
1328 | } |
---|
1329 | /* if printer is not on local machine, ignore LP */ |
---|
1330 | else if (strcasecmp(name, hp->h_name) != 0) *LP = '\0'; |
---|
1331 | } |
---|
1332 | |
---|
1333 | } |
---|
1334 | |
---|
1335 | localcheck_done: |
---|
1336 | |
---|
1337 | AF = pgetstr("af", &bp); |
---|
1338 | OF = pgetstr("of", &bp); |
---|
1339 | IF = pgetstr("if", &bp); |
---|
1340 | RF = pgetstr("rf", &bp); |
---|
1341 | TF = pgetstr("tf", &bp); |
---|
1342 | NF = pgetstr("nf", &bp); |
---|
1343 | DF = pgetstr("df", &bp); |
---|
1344 | GF = pgetstr("gf", &bp); |
---|
1345 | VF = pgetstr("vf", &bp); |
---|
1346 | CF = pgetstr("cf", &bp); |
---|
1347 | TR = pgetstr("tr", &bp); |
---|
1348 | RS = pgetflag("rs"); |
---|
1349 | SF = pgetflag("sf"); |
---|
1350 | SH = pgetflag("sh"); |
---|
1351 | SB = pgetflag("sb"); |
---|
1352 | HL = pgetflag("hl"); |
---|
1353 | RW = pgetflag("rw"); |
---|
1354 | BR = pgetnum("br"); |
---|
1355 | if ((FC = pgetnum("fc")) < 0) |
---|
1356 | FC = 0; |
---|
1357 | if ((FS = pgetnum("fs")) < 0) |
---|
1358 | FS = 0; |
---|
1359 | if ((XC = pgetnum("xc")) < 0) |
---|
1360 | XC = 0; |
---|
1361 | if ((XS = pgetnum("xs")) < 0) |
---|
1362 | XS = 0; |
---|
1363 | tof = !pgetflag("fo"); |
---|
1364 | } |
---|
1365 | |
---|
1366 | /* |
---|
1367 | * Acquire line printer or remote connection. |
---|
1368 | */ |
---|
1369 | openpr() |
---|
1370 | { |
---|
1371 | register int i, n; |
---|
1372 | int resp; |
---|
1373 | |
---|
1374 | if (lflag)syslog(LOG_INFO, "Opening printer (LP = \"%s\")", LP); |
---|
1375 | if (*LP) { |
---|
1376 | for (i = 1; ; i = i < 32 ? i << 1 : i) { |
---|
1377 | if (LP[0] == '@') { |
---|
1378 | pfd = tcp_conn(&LP[1]); |
---|
1379 | network = 1; |
---|
1380 | } else { |
---|
1381 | pfd = open(LP, RW ? O_RDWR : O_WRONLY); |
---|
1382 | network = 0; |
---|
1383 | } |
---|
1384 | if (lflag) syslog(LOG_INFO, "LP opened."); |
---|
1385 | if (pfd >= 0) |
---|
1386 | break; |
---|
1387 | if (errno == ENOENT) { |
---|
1388 | syslog(LOG_ERR, "%s: %m", LP); |
---|
1389 | exit(1); |
---|
1390 | } |
---|
1391 | else syslog(LOG_ERR, "%s: %m", LP); |
---|
1392 | if (i == 1) |
---|
1393 | status("waiting for %s (%s) to become ready (offline ?)", printer, LP); |
---|
1394 | sleep(i); |
---|
1395 | } |
---|
1396 | if (isatty(pfd)) |
---|
1397 | setty(); |
---|
1398 | status("%s is ready and printing", printer); |
---|
1399 | /* |
---|
1400 | * Start up an output filter, if needed. |
---|
1401 | */ |
---|
1402 | if (OF) { |
---|
1403 | int p[2]; |
---|
1404 | char *cp; |
---|
1405 | if (lflag) syslog(LOG_INFO, "Starting filter on %s", LP); |
---|
1406 | |
---|
1407 | pipe(p); |
---|
1408 | if ((ofilter = dofork(DOABORT)) == 0) { /* child */ |
---|
1409 | dup2(p[0], 0); /* pipe is std in */ |
---|
1410 | dup2(pfd, 1); /* printer is std out */ |
---|
1411 | for (i = 3; i < NOFILE; i++) |
---|
1412 | (void) close(i); |
---|
1413 | if ((cp = rindex(OF, '/')) == NULL) |
---|
1414 | cp = OF; |
---|
1415 | else |
---|
1416 | cp++; |
---|
1417 | execl(OF, cp, width, length, |
---|
1418 | "-P", printer, |
---|
1419 | 0); |
---|
1420 | syslog(LOG_ERR, "%s: %s: %m", printer, OF); |
---|
1421 | exit(1); |
---|
1422 | } |
---|
1423 | (void) close(p[0]); /* close input side */ |
---|
1424 | ofd = p[1]; /* use pipe for output */ |
---|
1425 | } else { |
---|
1426 | ofd = pfd; |
---|
1427 | ofilter = 0; |
---|
1428 | } |
---|
1429 | |
---|
1430 | } else if (RM != NULL) { |
---|
1431 | if (lflag) syslog(LOG_INFO, "Connecting to %s..", RM); |
---|
1432 | for (i = 1; ; i = i < 256 ? i << 1 : i) { |
---|
1433 | resp = -1; |
---|
1434 | pfd = getport(RM); |
---|
1435 | if (pfd >= 0) { |
---|
1436 | (void) sprintf(line, "\2%s\n", RP); |
---|
1437 | n = strlen(line); |
---|
1438 | if (write(pfd, line, n) == n && |
---|
1439 | (resp = response()) == '\0') |
---|
1440 | break; |
---|
1441 | (void) close(pfd); |
---|
1442 | } |
---|
1443 | if (i == 1) { |
---|
1444 | if (resp < 0) |
---|
1445 | status("waiting for %s to come up", RM); |
---|
1446 | else { |
---|
1447 | status("waiting for queue to be enabled on %s", RM); |
---|
1448 | i = 256; |
---|
1449 | } |
---|
1450 | } |
---|
1451 | sleep(i); |
---|
1452 | } |
---|
1453 | if (lflag) syslog(LOG_INFO, "Sending to %s..", RM); |
---|
1454 | status("sending to %s", RM); |
---|
1455 | remote = 1; |
---|
1456 | ofd = pfd; |
---|
1457 | ofilter = 0; |
---|
1458 | } else { |
---|
1459 | syslog(LOG_ERR, "%s: no line printer device or host name", |
---|
1460 | printer); |
---|
1461 | exit(1); |
---|
1462 | } |
---|
1463 | } |
---|
1464 | |
---|
1465 | struct bauds { |
---|
1466 | int baud; |
---|
1467 | int speed; |
---|
1468 | } bauds[] = { |
---|
1469 | 50, B50, |
---|
1470 | 75, B75, |
---|
1471 | 110, B110, |
---|
1472 | 134, B134, |
---|
1473 | 150, B150, |
---|
1474 | 200, B200, |
---|
1475 | 300, B300, |
---|
1476 | 600, B600, |
---|
1477 | 1200, B1200, |
---|
1478 | 1800, B1800, |
---|
1479 | 2400, B2400, |
---|
1480 | 4800, B4800, |
---|
1481 | 9600, B9600, |
---|
1482 | 19200, EXTA, |
---|
1483 | 38400, EXTB, |
---|
1484 | 0, 0 |
---|
1485 | }; |
---|
1486 | |
---|
1487 | /* |
---|
1488 | * setup tty lines. |
---|
1489 | */ |
---|
1490 | setty() |
---|
1491 | { |
---|
1492 | #ifndef POSIX |
---|
1493 | struct sgttyb ttybuf; |
---|
1494 | #else |
---|
1495 | struct termios ttybuf; |
---|
1496 | #endif |
---|
1497 | register struct bauds *bp; |
---|
1498 | |
---|
1499 | #ifndef POSIX |
---|
1500 | /* I cannot determine if under AUX you can open a line exclusively */ |
---|
1501 | if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) { |
---|
1502 | syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer); |
---|
1503 | exit(1); |
---|
1504 | } |
---|
1505 | #endif |
---|
1506 | #ifndef POSIX |
---|
1507 | if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) { |
---|
1508 | syslog(LOG_ERR, "%s: ioctl(TIOCGETP): %m", printer); |
---|
1509 | exit(1); |
---|
1510 | } |
---|
1511 | #else |
---|
1512 | if (tcgetattr(pfd, &ttybuf) < 0) { |
---|
1513 | syslog(LOG_ERR, "%s: tcgetattr: %m", printer); |
---|
1514 | exit(1); |
---|
1515 | } |
---|
1516 | #endif |
---|
1517 | if (BR > 0) { |
---|
1518 | for (bp = bauds; bp->baud; bp++) |
---|
1519 | if (BR == bp->baud) |
---|
1520 | break; |
---|
1521 | if (!bp->baud) { |
---|
1522 | syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR); |
---|
1523 | exit(1); |
---|
1524 | } |
---|
1525 | #ifndef POSIX |
---|
1526 | ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed; |
---|
1527 | #else |
---|
1528 | ttybuf.c_cflag &= ~CBAUD; |
---|
1529 | ttybuf.c_cflag |= bp->speed; |
---|
1530 | if (XC) ttybuf.c_lflag &= ~XC; |
---|
1531 | if (XS) ttybuf.c_lflag |= XS; |
---|
1532 | #endif |
---|
1533 | } |
---|
1534 | #ifndef POSIX |
---|
1535 | ttybuf.sg_flags &= ~FC; |
---|
1536 | ttybuf.sg_flags |= FS; |
---|
1537 | if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) { |
---|
1538 | syslog(LOG_INFO, "SETP failed.."); |
---|
1539 | syslog(LOG_ERR, "%s: ioctl(TIOCSETP): %m", printer); |
---|
1540 | exit(1); |
---|
1541 | } |
---|
1542 | #else |
---|
1543 | ttybuf.c_cflag &= ~FC; |
---|
1544 | ttybuf.c_cflag |= FS; |
---|
1545 | if (tcsetattr(pfd, TCSANOW,&ttybuf) < 0) { |
---|
1546 | syslog(LOG_INFO, "tcsetattr failed.."); |
---|
1547 | syslog(LOG_ERR, "%s: tcsetattr: %m", printer); |
---|
1548 | exit(1); |
---|
1549 | } |
---|
1550 | #endif /* POSIX */ |
---|
1551 | #ifndef POSIX |
---|
1552 | /* AUX does not appear to have old/new line disciplines that |
---|
1553 | do anything */ |
---|
1554 | if (XC || XS) { |
---|
1555 | int ldisc = NTTYDISC; |
---|
1556 | |
---|
1557 | if (ioctl(pfd, TIOCSETD, &ldisc) < 0) { |
---|
1558 | syslog(LOG_ERR, "%s: ioctl(TIOCSETD): %m", printer); |
---|
1559 | exit(1); |
---|
1560 | } |
---|
1561 | } |
---|
1562 | /* For AUX, XC and XS handled above */ |
---|
1563 | if (XC) { |
---|
1564 | if (ioctl(pfd, TIOCLBIC, &XC) < 0) { |
---|
1565 | syslog(LOG_ERR, "%s: ioctl(TIOCLBIC): %m", printer); |
---|
1566 | exit(1); |
---|
1567 | } |
---|
1568 | } |
---|
1569 | |
---|
1570 | if (XS) { |
---|
1571 | if (ioctl(pfd, TIOCLBIS, &XS) < 0) { |
---|
1572 | syslog(LOG_ERR, "%s: ioctl(TIOCLBIS): %m", printer); |
---|
1573 | exit(1); |
---|
1574 | } |
---|
1575 | } |
---|
1576 | #endif |
---|
1577 | } |
---|
1578 | |
---|
1579 | /*VARARGS1*/ |
---|
1580 | status(msg, a1, a2, a3) |
---|
1581 | char *msg; |
---|
1582 | { |
---|
1583 | register int fd; |
---|
1584 | char buf[BUFSIZ]; |
---|
1585 | |
---|
1586 | umask(0); |
---|
1587 | fd = open(ST, O_WRONLY|O_CREAT, 0664); |
---|
1588 | if (fd < 0 || flock(fd, LOCK_EX) < 0) { |
---|
1589 | syslog(LOG_ERR, "%s: %s: %m", printer, ST); |
---|
1590 | exit(1); |
---|
1591 | } |
---|
1592 | ftruncate(fd, 0); |
---|
1593 | sprintf(buf, msg, a1, a2, a3); |
---|
1594 | strcat(buf, "\n"); |
---|
1595 | (void) write(fd, buf, strlen(buf)); |
---|
1596 | (void) close(fd); |
---|
1597 | } |
---|