Deleted Added
full compact
1/*
2 * Copyright (c) 1983, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by the University of
17 * California, Berkeley and its contributors.
18 * 4. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35#ifndef lint
36static const char copyright[] =
37"@(#) Copyright (c) 1983, 1993\n\
38 The Regents of the University of California. All rights reserved.\n";
39#endif /* not lint */
40
41#ifndef lint
42/*
43static char sccsid[] = "@(#)printjob.c 8.7 (Berkeley) 5/10/95";
44*/
45static const char rcsid[] =
46 "$FreeBSD: head/usr.sbin/lpr/lpd/printjob.c 79739 2001-07-15 00:09:46Z gad $";
46 "$FreeBSD: head/usr.sbin/lpr/lpd/printjob.c 80133 2001-07-22 07:25:27Z gad $";
47#endif /* not lint */
48
49
50/*
51 * printjob -- print jobs in the queue.
52 *
53 * NOTE: the lock file is used to pass information to lpq and lprm.
54 * it does not need to be removed because file locks are dynamic.
55 */
56
57#include <sys/param.h>
58#include <sys/wait.h>
59#include <sys/stat.h>
60#include <sys/types.h>
61
62#include <pwd.h>
63#include <unistd.h>
64#include <signal.h>
65#include <syslog.h>
66#include <fcntl.h>
67#include <dirent.h>
68#include <errno.h>
69#include <stdio.h>
70#include <string.h>
71#include <stdlib.h>
72#include <sys/ioctl.h>
73#include <termios.h>
74#include <time.h>
75#include "lp.h"
76#include "lp.local.h"
77#include "pathnames.h"
78#include "extern.h"
79
80#define DORETURN 0 /* absorb fork error */
81#define DOABORT 1 /* abort if dofork fails */
82
83/*
84 * Error tokens
85 */
86#define REPRINT -2
87#define ERROR -1
88#define OK 0
89#define FATALERR 1
90#define NOACCT 2
91#define FILTERERR 3
92#define ACCESS 4
93
94static dev_t fdev; /* device of file pointed to by symlink */
95static ino_t fino; /* inode of file pointed to by symlink */
96static FILE *cfp; /* control file */
97static int child; /* id of any filters */
98static int job_dfcnt; /* count of datafiles in current user job */
99static int lfd; /* lock file descriptor */
100static int ofd; /* output filter file descriptor */
101static int ofilter; /* id of output filter, if any */
102static int tfd = -1; /* output filter temp file output */
103static int pfd; /* prstatic inter file descriptor */
104static int pid; /* pid of lpd process */
105static int prchild; /* id of pr process */
106static char title[80]; /* ``pr'' title */
107static char locale[80]; /* ``pr'' locale */
108
109static char class[32]; /* classification field */
110static char origin_host[MAXHOSTNAMELEN]; /* user's host machine */
111 /* indentation size in static characters */
112static char indent[10] = "-i0";
113static char jobname[100]; /* job or file name */
114static char length[10] = "-l"; /* page length in lines */
115static char logname[32]; /* user's login name */
116static char pxlength[10] = "-y"; /* page length in pixels */
117static char pxwidth[10] = "-x"; /* page width in pixels */
118/* tempstderr is the filename used to catch stderr from exec-ing filters */
119static char tempstderr[] = "errs.XXXXXXX";
120static char width[10] = "-w"; /* page width in static characters */
121#define TFILENAME "fltXXXXXX"
122static char tfile[] = TFILENAME; /* file name for filter output */
123
124static void abortpr(int _signo);
125static void alarmhandler(int _signo);
126static void banner(struct printer *_pp, char *_name1, char *_name2);
127static int dofork(const struct printer *_pp, int _action);
128static int dropit(int _c);
129static void init(struct printer *_pp);
130static void openpr(const struct printer *_pp);
131static void opennet(const struct printer *_pp);
132static void opentty(const struct printer *_pp);
133static void openrem(const struct printer *pp);
134static int print(struct printer *_pp, int _format, char *_file);
135static int printit(struct printer *_pp, char *_file);
136static void pstatus(const struct printer *_pp, const char *_msg, ...)
137 __printflike(2, 3);
138static char response(const struct printer *_pp);
139static void scan_out(struct printer *_pp, int _scfd, char *_scsp,
140 int _dlm);
141static char *scnline(int _key, char *_p, int _c);
142static int sendfile(struct printer *_pp, int _type, char *_file,
143 char _format);
144static int sendit(struct printer *_pp, char *_file);
145static void sendmail(struct printer *_pp, char *_user, int _bombed);
146static void setty(const struct printer *_pp);
147
148void
149printjob(struct printer *pp)
150{
151 struct stat stb;
152 register struct jobqueue *q, **qp;
153 struct jobqueue **queue;
154 register int i, nitems;
155 off_t pidoff;
156 int errcnt, jobcount, tempfd;
157
158 jobcount = 0;
159 init(pp); /* set up capabilities */
160 (void) write(1, "", 1); /* ack that daemon is started */
161 (void) close(2); /* set up log file */
162 if (open(pp->log_file, O_WRONLY|O_APPEND, LOG_FILE_MODE) < 0) {
163 syslog(LOG_ERR, "%s: %m", pp->log_file);
164 (void) open(_PATH_DEVNULL, O_WRONLY);
165 }
166 setgid(getegid());
167 pid = getpid(); /* for use with lprm */
168 setpgrp(0, pid);
169
170 /*
171 * At initial lpd startup, printjob may be called with various
172 * signal handlers in effect. After that initial startup, any
173 * calls to printjob will have a *different* set of signal-handlers
174 * in effect. Make sure all handlers are the ones we want.
175 */
176 signal(SIGCHLD, SIG_DFL);
177 signal(SIGHUP, abortpr);
178 signal(SIGINT, abortpr);
179 signal(SIGQUIT, abortpr);
180 signal(SIGTERM, abortpr);
181
182 /*
183 * uses short form file names
184 */
185 if (chdir(pp->spool_dir) < 0) {
186 syslog(LOG_ERR, "%s: %m", pp->spool_dir);
187 exit(1);
188 }
189 if (stat(pp->lock_file, &stb) == 0 && (stb.st_mode & LFM_PRINT_DIS))
190 exit(0); /* printing disabled */
191 lfd = open(pp->lock_file, O_WRONLY|O_CREAT|O_EXLOCK|O_NONBLOCK,
192 LOCK_FILE_MODE);
193 if (lfd < 0) {
194 if (errno == EWOULDBLOCK) /* active daemon present */
195 exit(0);
196 syslog(LOG_ERR, "%s: %s: %m", pp->printer, pp->lock_file);
197 exit(1);
198 }
199 /* turn off non-blocking mode (was turned on for lock effects only) */
200 if (fcntl(lfd, F_SETFL, 0) < 0) {
201 syslog(LOG_ERR, "%s: %s: %m", pp->printer, pp->lock_file);
202 exit(1);
203 }
204 ftruncate(lfd, 0);
205 /*
206 * write process id for others to know
207 */
208 sprintf(line, "%u\n", pid);
209 pidoff = i = strlen(line);
210 if (write(lfd, line, i) != i) {
211 syslog(LOG_ERR, "%s: %s: %m", pp->printer, pp->lock_file);
212 exit(1);
213 }
214 /*
215 * search the spool directory for work and sort by queue order.
216 */
217 if ((nitems = getq(pp, &queue)) < 0) {
218 syslog(LOG_ERR, "%s: can't scan %s", pp->printer,
219 pp->spool_dir);
220 exit(1);
221 }
222 if (nitems == 0) /* no work to do */
223 exit(0);
224 if (stb.st_mode & LFM_RESET_QUE) { /* reset queue flag */
225 if (fchmod(lfd, stb.st_mode & ~LFM_RESET_QUE) < 0)
226 syslog(LOG_ERR, "%s: %s: %m", pp->printer,
227 pp->lock_file);
228 }
229
230 /* create a file which will be used to hold stderr from filters */
231 if ((tempfd = mkstemp(tempstderr)) == -1) {
232 syslog(LOG_ERR, "%s: mkstemp(%s): %m", pp->printer,
233 tempstderr);
234 exit(1);
235 }
236 if ((i = fchmod(tempfd, 0664)) == -1) {
237 syslog(LOG_ERR, "%s: fchmod(%s): %m", pp->printer,
238 tempstderr);
239 exit(1);
240 }
241 /* lpd doesn't need it to be open, it just needs it to exist */
242 close(tempfd);
243
244 openpr(pp); /* open printer or remote */
245again:
246 /*
247 * we found something to do now do it --
248 * write the name of the current control file into the lock file
249 * so the spool queue program can tell what we're working on
250 */
251 for (qp = queue; nitems--; free((char *) q)) {
252 q = *qp++;
253 if (stat(q->job_cfname, &stb) < 0)
254 continue;
255 errcnt = 0;
256 restart:
257 (void) lseek(lfd, pidoff, 0);
258 (void) snprintf(line, sizeof(line), "%s\n", q->job_cfname);
259 i = strlen(line);
260 if (write(lfd, line, i) != i)
261 syslog(LOG_ERR, "%s: %s: %m", pp->printer,
262 pp->lock_file);
263 if (!pp->remote)
264 i = printit(pp, q->job_cfname);
265 else
266 i = sendit(pp, q->job_cfname);
267 /*
268 * Check to see if we are supposed to stop printing or
269 * if we are to rebuild the queue.
270 */
271 if (fstat(lfd, &stb) == 0) {
272 /* stop printing before starting next job? */
273 if (stb.st_mode & LFM_PRINT_DIS)
274 goto done;
275 /* rebuild queue (after lpc topq) */
276 if (stb.st_mode & LFM_RESET_QUE) {
277 for (free(q); nitems--; free(q))
278 q = *qp++;
279 if (fchmod(lfd, stb.st_mode & ~LFM_RESET_QUE)
280 < 0)
281 syslog(LOG_WARNING, "%s: %s: %m",
282 pp->printer, pp->lock_file);
283 break;
284 }
285 }
286 if (i == OK) /* all files of this job printed */
287 jobcount++;
288 else if (i == REPRINT && ++errcnt < 5) {
289 /* try reprinting the job */
290 syslog(LOG_INFO, "restarting %s", pp->printer);
291 if (ofilter > 0) {
292 kill(ofilter, SIGCONT); /* to be sure */
293 (void) close(ofd);
294 while ((i = wait(NULL)) > 0 && i != ofilter)
295 ;
296 if (i < 0)
297 syslog(LOG_WARNING, "%s: after kill(of=%d), wait() returned: %m",
298 pp->printer, ofilter);
299 ofilter = 0;
300 }
301 (void) close(pfd); /* close printer */
302 if (ftruncate(lfd, pidoff) < 0)
303 syslog(LOG_WARNING, "%s: %s: %m",
304 pp->printer, pp->lock_file);
305 openpr(pp); /* try to reopen printer */
306 goto restart;
307 } else {
308 syslog(LOG_WARNING, "%s: job could not be %s (%s)",
309 pp->printer,
310 pp->remote ? "sent to remote host" : "printed",
311 q->job_cfname);
312 if (i == REPRINT) {
313 /* ensure we don't attempt this job again */
314 (void) unlink(q->job_cfname);
315 q->job_cfname[0] = 'd';
316 (void) unlink(q->job_cfname);
317 if (logname[0])
318 sendmail(pp, logname, FATALERR);
319 }
320 }
321 }
322 free(queue);
323 /*
324 * search the spool directory for more work.
325 */
326 if ((nitems = getq(pp, &queue)) < 0) {
327 syslog(LOG_ERR, "%s: can't scan %s", pp->printer,
328 pp->spool_dir);
329 exit(1);
330 }
331 if (nitems == 0) { /* no more work to do */
332 done:
333 if (jobcount > 0) { /* jobs actually printed */
334 if (!pp->no_formfeed && !pp->tof)
335 (void) write(ofd, pp->form_feed,
336 strlen(pp->form_feed));
337 if (pp->trailer != NULL) /* output trailer */
338 (void) write(ofd, pp->trailer,
339 strlen(pp->trailer));
340 }
341 (void) close(ofd);
342 (void) wait(NULL);
343 (void) unlink(tempstderr);
344 exit(0);
345 }
346 goto again;
347}
348
349char fonts[4][50]; /* fonts for troff */
350
351char ifonts[4][40] = {
352 _PATH_VFONTR,
353 _PATH_VFONTI,
354 _PATH_VFONTB,
355 _PATH_VFONTS,
356};
357
358/*
359 * The remaining part is the reading of the control file (cf)
360 * and performing the various actions.
361 */
362static int
363printit(struct printer *pp, char *file)
364{
365 register int i;
366 char *cp;
367 int bombed, didignorehdr;
368
369 bombed = OK;
370 didignorehdr = 0;
371 /*
372 * open control file; ignore if no longer there.
373 */
374 if ((cfp = fopen(file, "r")) == NULL) {
375 syslog(LOG_INFO, "%s: %s: %m", pp->printer, file);
376 return(OK);
377 }
378 /*
379 * Reset troff fonts.
380 */
381 for (i = 0; i < 4; i++)
382 strcpy(fonts[i], ifonts[i]);
383 sprintf(&width[2], "%ld", pp->page_width);
384 strcpy(indent+2, "0");
385
386 /* initialize job-specific count of datafiles processed */
387 job_dfcnt = 0;
388
389 /*
390 * read the control file for work to do
391 *
392 * file format -- first character in the line is a command
393 * rest of the line is the argument.
394 * valid commands are:
395 *
396 * S -- "stat info" for symbolic link protection
397 * J -- "job name" on banner page
398 * C -- "class name" on banner page
399 * L -- "literal" user's name to print on banner
400 * T -- "title" for pr
401 * H -- "host name" of machine where lpr was done
402 * P -- "person" user's login name
403 * I -- "indent" amount to indent output
404 * R -- laser dpi "resolution"
405 * f -- "file name" name of text file to print
406 * l -- "file name" text file with control chars
407 * p -- "file name" text file to print with pr(1)
408 * t -- "file name" troff(1) file to print
409 * n -- "file name" ditroff(1) file to print
410 * d -- "file name" dvi file to print
411 * g -- "file name" plot(1G) file to print
412 * v -- "file name" plain raster file to print
413 * c -- "file name" cifplot file to print
414 * 1 -- "R font file" for troff
415 * 2 -- "I font file" for troff
416 * 3 -- "B font file" for troff
417 * 4 -- "S font file" for troff
418 * N -- "name" of file (used by lpq)
419 * U -- "unlink" name of file to remove
420 * (after we print it. (Pass 2 only)).
421 * M -- "mail" to user when done printing
422 * Z -- "locale" for pr
423 *
424 * getline reads a line and expands tabs to blanks
425 */
426
427 /* pass 1 */
428
429 while (getline(cfp))
430 switch (line[0]) {
431 case 'H':
432 strlcpy(origin_host, line + 1, sizeof(origin_host));
433 if (class[0] == '\0') {
434 strncpy(class, line+1, sizeof(class) - 1);
435 class[sizeof(class) - 1] = '\0';
434 strlcpy(class, line+1, sizeof(class));
435 }
436 continue;
437
438 case 'P':
440 strncpy(logname, line+1, sizeof(logname) - 1);
441 logname[sizeof(logname) - 1] = '\0';
439 strlcpy(logname, line + 1, sizeof(logname));
440 if (pp->restricted) { /* restricted */
441 if (getpwnam(logname) == NULL) {
442 bombed = NOACCT;
443 sendmail(pp, line+1, bombed);
444 goto pass2;
445 }
446 }
447 continue;
448
449 case 'S':
450 cp = line+1;
451 i = 0;
452 while (*cp >= '0' && *cp <= '9')
453 i = i * 10 + (*cp++ - '0');
454 fdev = i;
455 cp++;
456 i = 0;
457 while (*cp >= '0' && *cp <= '9')
458 i = i * 10 + (*cp++ - '0');
459 fino = i;
460 continue;
461
462 case 'J':
463 if (line[1] != '\0') {
466 strncpy(jobname, line+1, sizeof(jobname) - 1);
467 jobname[sizeof(jobname) - 1] = '\0';
464 strlcpy(jobname, line + 1, sizeof(jobname));
465 } else
466 strcpy(jobname, " ");
467 continue;
468
469 case 'C':
470 if (line[1] != '\0')
474 strncpy(class, line+1, sizeof(class) - 1);
475 else if (class[0] == '\0')
471 strlcpy(class, line + 1, sizeof(class));
472 else if (class[0] == '\0') {
473 /* XXX - why call gethostname instead of
474 * just strlcpy'ing local_host? */
475 gethostname(class, sizeof(class));
477 class[sizeof(class) - 1] = '\0';
476 class[sizeof(class) - 1] = '\0';
477 }
478 continue;
479
480 case 'T': /* header title for pr */
481 strncpy(title, line+1, sizeof(title) - 1);
482 title[sizeof(title) - 1] = '\0';
481 strlcpy(title, line + 1, sizeof(title));
482 continue;
483
484 case 'L': /* identification line */
485 if (!pp->no_header && !pp->header_last)
486 banner(pp, line+1, jobname);
487 continue;
488
489 case '1': /* troff fonts */
490 case '2':
491 case '3':
492 case '4':
493 if (line[1] != '\0') {
495 strncpy(fonts[line[0]-'1'], line+1,
496 50-1);
497 fonts[line[0]-'1'][50-1] = '\0';
494 strlcpy(fonts[line[0]-'1'], line + 1,
495 (size_t)50);
496 }
497 continue;
498
499 case 'W': /* page width */
502 strncpy(width+2, line+1, sizeof(width) - 3);
503 width[2+sizeof(width) - 3] = '\0';
500 strlcpy(width+2, line + 1, sizeof(width) - 2);
501 continue;
502
503 case 'I': /* indent amount */
507 strncpy(indent+2, line+1, sizeof(indent) - 3);
508 indent[2+sizeof(indent) - 3] = '\0';
504 strlcpy(indent+2, line + 1, sizeof(indent) - 2);
505 continue;
506
507 case 'Z': /* locale for pr */
512 strncpy(locale, line+1, sizeof(locale) - 1);
508 strlcpy(locale, line + 1, sizeof(locale));
509 locale[sizeof(locale) - 1] = '\0';
510 continue;
511
512 default: /* some file to print */
513 /* only lowercase cmd-codes include a file-to-print */
514 if ((line[0] < 'a') || (line[0] > 'z')) {
515 /* ignore any other lines */
516 if (lflag <= 1)
517 continue;
518 if (!didignorehdr) {
519 syslog(LOG_INFO, "%s: in %s :",
520 pp->printer, file);
521 didignorehdr = 1;
522 }
523 syslog(LOG_INFO, "%s: ignoring line: '%c' %s",
524 pp->printer, line[0], &line[1]);
525 continue;
526 }
527 i = print(pp, line[0], line+1);
528 switch (i) {
529 case ERROR:
530 if (bombed == OK)
531 bombed = FATALERR;
532 break;
533 case REPRINT:
534 (void) fclose(cfp);
535 return(REPRINT);
536 case FILTERERR:
537 case ACCESS:
538 bombed = i;
539 sendmail(pp, logname, bombed);
540 }
541 title[0] = '\0';
542 continue;
543
544 case 'N':
545 case 'U':
546 case 'M':
547 case 'R':
548 continue;
549 }
550
551 /* pass 2 */
552
553pass2:
554 fseek(cfp, 0L, 0);
555 while (getline(cfp))
556 switch (line[0]) {
557 case 'L': /* identification line */
558 if (!pp->no_header && pp->header_last)
559 banner(pp, line+1, jobname);
560 continue;
561
562 case 'M':
563 if (bombed < NOACCT) /* already sent if >= NOACCT */
564 sendmail(pp, line+1, bombed);
565 continue;
566
567 case 'U':
568 if (strchr(line+1, '/'))
569 continue;
570 (void) unlink(line+1);
571 }
572 /*
573 * clean-up in case another control file exists
574 */
575 (void) fclose(cfp);
576 (void) unlink(file);
577 return(bombed == OK ? OK : ERROR);
578}
579
580/*
581 * Print a file.
582 * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}.
583 * Return -1 if a non-recoverable error occured,
584 * 2 if the filter detected some errors (but printed the job anyway),
585 * 1 if we should try to reprint this job and
586 * 0 if all is well.
587 * Note: all filters take stdin as the file, stdout as the printer,
588 * stderr as the log file, and must not ignore SIGINT.
589 */
590static int
591print(struct printer *pp, int format, char *file)
592{
593 register int n, i;
594 register char *prog;
595 int fi, fo;
596 FILE *fp;
597 char *av[15], buf[BUFSIZ];
598 int pid, p[2], stopped;
599 union wait status;
600 struct stat stb;
601
602 if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0) {
603 syslog(LOG_INFO, "%s: unable to open %s ('%c' line)",
604 pp->printer, file, format);
605 return(ERROR);
606 }
607 /*
608 * Check to see if data file is a symbolic link. If so, it should
609 * still point to the same file or someone is trying to print
610 * something he shouldn't.
611 */
612 if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 &&
613 (stb.st_dev != fdev || stb.st_ino != fino))
614 return(ACCESS);
615
616 job_dfcnt++; /* increment datafile counter for this job */
617 stopped = 0; /* output filter is not stopped */
618
619 /* everything seems OK, start it up */
620 if (!pp->no_formfeed && !pp->tof) { /* start on a fresh page */
621 (void) write(ofd, pp->form_feed, strlen(pp->form_feed));
622 pp->tof = 1;
623 }
624 if (pp->filters[LPF_INPUT] == NULL
625 && (format == 'f' || format == 'l')) {
626 pp->tof = 0;
627 while ((n = read(fi, buf, BUFSIZ)) > 0)
628 if (write(ofd, buf, n) != n) {
629 (void) close(fi);
630 return(REPRINT);
631 }
632 (void) close(fi);
633 return(OK);
634 }
635 switch (format) {
636 case 'p': /* print file using 'pr' */
637 if (pp->filters[LPF_INPUT] == NULL) { /* use output filter */
638 prog = _PATH_PR;
639 i = 0;
640 av[i++] = "pr";
641 av[i++] = width;
642 av[i++] = length;
643 av[i++] = "-h";
644 av[i++] = *title ? title : " ";
645 av[i++] = "-L";
646 av[i++] = *locale ? locale : "C";
647 av[i++] = "-F";
648 av[i] = 0;
649 fo = ofd;
650 goto start;
651 }
652 pipe(p);
653 if ((prchild = dofork(pp, DORETURN)) == 0) { /* child */
654 dup2(fi, 0); /* file is stdin */
655 dup2(p[1], 1); /* pipe is stdout */
656 closelog();
657 closeallfds(3);
658 execl(_PATH_PR, "pr", width, length,
659 "-h", *title ? title : " ",
660 "-L", *locale ? locale : "C",
661 "-F", (char *)0);
662 syslog(LOG_ERR, "cannot execl %s", _PATH_PR);
663 exit(2);
664 }
665 (void) close(p[1]); /* close output side */
666 (void) close(fi);
667 if (prchild < 0) {
668 prchild = 0;
669 (void) close(p[0]);
670 return(ERROR);
671 }
672 fi = p[0]; /* use pipe for input */
673 case 'f': /* print plain text file */
674 prog = pp->filters[LPF_INPUT];
675 av[1] = width;
676 av[2] = length;
677 av[3] = indent;
678 n = 4;
679 break;
680 case 'l': /* like 'f' but pass control characters */
681 prog = pp->filters[LPF_INPUT];
682 av[1] = "-c";
683 av[2] = width;
684 av[3] = length;
685 av[4] = indent;
686 n = 5;
687 break;
688 case 'r': /* print a fortran text file */
689 prog = pp->filters[LPF_FORTRAN];
690 av[1] = width;
691 av[2] = length;
692 n = 3;
693 break;
694 case 't': /* print troff output */
695 case 'n': /* print ditroff output */
696 case 'd': /* print tex output */
697 (void) unlink(".railmag");
698 if ((fo = creat(".railmag", FILMOD)) < 0) {
699 syslog(LOG_ERR, "%s: cannot create .railmag",
700 pp->printer);
701 (void) unlink(".railmag");
702 } else {
703 for (n = 0; n < 4; n++) {
704 if (fonts[n][0] != '/')
705 (void) write(fo, _PATH_VFONT,
706 sizeof(_PATH_VFONT) - 1);
707 (void) write(fo, fonts[n], strlen(fonts[n]));
708 (void) write(fo, "\n", 1);
709 }
710 (void) close(fo);
711 }
712 prog = (format == 't') ? pp->filters[LPF_TROFF]
713 : ((format == 'n') ? pp->filters[LPF_DITROFF]
714 : pp->filters[LPF_DVI]);
715 av[1] = pxwidth;
716 av[2] = pxlength;
717 n = 3;
718 break;
719 case 'c': /* print cifplot output */
720 prog = pp->filters[LPF_CIFPLOT];
721 av[1] = pxwidth;
722 av[2] = pxlength;
723 n = 3;
724 break;
725 case 'g': /* print plot(1G) output */
726 prog = pp->filters[LPF_GRAPH];
727 av[1] = pxwidth;
728 av[2] = pxlength;
729 n = 3;
730 break;
731 case 'v': /* print raster output */
732 prog = pp->filters[LPF_RASTER];
733 av[1] = pxwidth;
734 av[2] = pxlength;
735 n = 3;
736 break;
737 default:
738 (void) close(fi);
739 syslog(LOG_ERR, "%s: illegal format character '%c'",
740 pp->printer, format);
741 return(ERROR);
742 }
743 if (prog == NULL) {
744 (void) close(fi);
745 syslog(LOG_ERR,
746 "%s: no filter found in printcap for format character '%c'",
747 pp->printer, format);
748 return(ERROR);
749 }
750 if ((av[0] = strrchr(prog, '/')) != NULL)
751 av[0]++;
752 else
753 av[0] = prog;
754 av[n++] = "-n";
755 av[n++] = logname;
756 av[n++] = "-h";
757 av[n++] = origin_host;
758 av[n++] = pp->acct_file;
759 av[n] = 0;
760 fo = pfd;
761 if (ofilter > 0) { /* stop output filter */
762 write(ofd, "\031\1", 2);
763 while ((pid =
764 wait3((int *)&status, WUNTRACED, 0)) > 0 && pid != ofilter)
765 ;
766 if (pid < 0)
767 syslog(LOG_WARNING, "%s: after stopping 'of', wait3() returned: %m",
768 pp->printer);
769 else if (status.w_stopval != WSTOPPED) {
770 (void) close(fi);
771 syslog(LOG_WARNING,
772 "%s: output filter died "
773 "(pid=%d retcode=%d termsig=%d)",
774 pp->printer, ofilter, status.w_retcode,
775 status.w_termsig);
776 return(REPRINT);
777 }
778 stopped++;
779 }
780start:
781 if ((child = dofork(pp, DORETURN)) == 0) { /* child */
782 dup2(fi, 0);
783 dup2(fo, 1);
784 /* setup stderr for the filter (child process)
785 * so it goes to our temporary errors file */
786 n = open(tempstderr, O_WRONLY|O_TRUNC, 0664);
787 if (n >= 0)
788 dup2(n, 2);
789 closelog();
790 closeallfds(3);
791 execv(prog, av);
792 syslog(LOG_ERR, "cannot execv %s", prog);
793 exit(2);
794 }
795 (void) close(fi);
796 if (child < 0)
797 status.w_retcode = 100;
798 else {
799 while ((pid = wait((int *)&status)) > 0 && pid != child)
800 ;
801 if (pid < 0) {
802 status.w_retcode = 100;
803 syslog(LOG_WARNING, "%s: after execv(%s), wait() returned: %m",
804 pp->printer, prog);
805 }
806 }
807 child = 0;
808 prchild = 0;
809 if (stopped) { /* restart output filter */
810 if (kill(ofilter, SIGCONT) < 0) {
811 syslog(LOG_ERR, "cannot restart output filter");
812 exit(1);
813 }
814 }
815 pp->tof = 0;
816
817 /* Copy the filter's output to "lf" logfile */
818 if ((fp = fopen(tempstderr, "r"))) {
819 while (fgets(buf, sizeof(buf), fp))
820 fputs(buf, stderr);
821 fclose(fp);
822 }
823
824 if (!WIFEXITED(status)) {
825 syslog(LOG_WARNING, "%s: filter '%c' terminated (termsig=%d)",
826 pp->printer, format, status.w_termsig);
827 return(ERROR);
828 }
829 switch (status.w_retcode) {
830 case 0:
831 pp->tof = 1;
832 return(OK);
833 case 1:
834 return(REPRINT);
835 case 2:
836 return(ERROR);
837 default:
838 syslog(LOG_WARNING, "%s: filter '%c' exited (retcode=%d)",
839 pp->printer, format, status.w_retcode);
840 return(FILTERERR);
841 }
842}
843
844/*
845 * Send the daemon control file (cf) and any data files.
846 * Return -1 if a non-recoverable error occured, 1 if a recoverable error and
847 * 0 if all is well.
848 */
849static int
850sendit(struct printer *pp, char *file)
851{
852 register int i, err = OK;
853 char *cp, last[BUFSIZ];
854
855 /*
856 * open control file
857 */
858 if ((cfp = fopen(file, "r")) == NULL)
859 return(OK);
860
861 /* initialize job-specific count of datafiles processed */
862 job_dfcnt = 0;
863
864 /*
865 * read the control file for work to do
866 *
867 * file format -- first character in the line is a command
868 * rest of the line is the argument.
869 * commands of interest are:
870 *
871 * a-z -- "file name" name of file to print
872 * U -- "unlink" name of file to remove
873 * (after we print it. (Pass 2 only)).
874 */
875
876 /*
877 * pass 1
878 */
879 while (getline(cfp)) {
880 again:
881 if (line[0] == 'S') {
882 cp = line+1;
883 i = 0;
884 while (*cp >= '0' && *cp <= '9')
885 i = i * 10 + (*cp++ - '0');
886 fdev = i;
887 cp++;
888 i = 0;
889 while (*cp >= '0' && *cp <= '9')
890 i = i * 10 + (*cp++ - '0');
891 fino = i;
892 } else if (line[0] == 'H') {
893 strlcpy(origin_host, line + 1, sizeof(origin_host));
894 if (class[0] == '\0') {
899 strncpy(class, line+1, sizeof(class) - 1);
900 class[sizeof(class) - 1] = '\0';
895 strlcpy(class, line + 1, sizeof(class));
896 }
897 } else if (line[0] == 'P') {
903 strncpy(logname, line+1, sizeof(logname) - 1);
904 logname[sizeof(logname) - 1] = '\0';
898 strlcpy(logname, line + 1, sizeof(logname));
899 if (pp->restricted) { /* restricted */
900 if (getpwnam(logname) == NULL) {
901 sendmail(pp, line+1, NOACCT);
902 err = ERROR;
903 break;
904 }
905 }
906 } else if (line[0] == 'I') {
913 strncpy(indent+2, line+1, sizeof(indent) - 3);
914 indent[2 + sizeof(indent) - 3] = '\0';
907 strlcpy(indent+2, line + 1, sizeof(indent) - 2);
908 } else if (line[0] >= 'a' && line[0] <= 'z') {
909 strcpy(last, line);
910 while ((i = getline(cfp)) != 0)
911 if (strcmp(last, line))
912 break;
913 switch (sendfile(pp, '\3', last+1, *last)) {
914 case OK:
915 if (i)
916 goto again;
917 break;
918 case REPRINT:
919 (void) fclose(cfp);
920 return(REPRINT);
921 case ACCESS:
922 sendmail(pp, logname, ACCESS);
923 case ERROR:
924 err = ERROR;
925 }
926 break;
927 }
928 }
929 if (err == OK && sendfile(pp, '\2', file, '\0') > 0) {
930 (void) fclose(cfp);
931 return(REPRINT);
932 }
933 /*
934 * pass 2
935 */
936 fseek(cfp, 0L, 0);
937 while (getline(cfp))
938 if (line[0] == 'U' && !strchr(line+1, '/'))
939 (void) unlink(line+1);
940 /*
941 * clean-up in case another control file exists
942 */
943 (void) fclose(cfp);
944 (void) unlink(file);
945 return(err);
946}
947
948/*
949 * Send a data file to the remote machine and spool it.
950 * Return positive if we should try resending.
951 */
952static int
953sendfile(struct printer *pp, int type, char *file, char format)
954{
955 register int f, i, amt;
956 struct stat stb;
957 FILE *fp;
958 char buf[BUFSIZ];
959 int closedpr, resp, sizerr, statrc;
960
961 statrc = lstat(file, &stb);
962 if (statrc < 0) {
963 syslog(LOG_ERR, "%s: error from lstat(%s): %m",
964 pp->printer, file);
965 return(ERROR);
966 }
967 f = open(file, O_RDONLY);
968 if (f < 0) {
969 syslog(LOG_ERR, "%s: error from open(%s,O_RDONLY): %m",
970 pp->printer, file);
971 return(ERROR);
972 }
973 /*
974 * Check to see if data file is a symbolic link. If so, it should
975 * still point to the same file or someone is trying to print something
976 * he shouldn't.
977 */
978 if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 &&
979 (stb.st_dev != fdev || stb.st_ino != fino))
980 return(ACCESS);
981
982 job_dfcnt++; /* increment datafile counter for this job */
983
984 /* everything seems OK, start it up */
985 sizerr = 0;
986 closedpr = 0;
987 if (type == '\3') {
988 if (pp->filters[LPF_INPUT]) {
989 /*
990 * We're sending something with an ifilter. We have to
991 * run the ifilter and store the output as a temporary
992 * spool file (tfile...), because the protocol requires
993 * us to send the file size before we start sending any
994 * of the data.
995 */
996 char *av[15];
997 int n;
998 int ifilter;
999 union wait status; /* XXX */
1000
1001 strcpy(tfile,TFILENAME);
1002 if ((tfd = mkstemp(tfile)) == -1) {
1003 syslog(LOG_ERR, "mkstemp: %m");
1004 return(ERROR);
1005 }
1006 if ((av[0] = strrchr(pp->filters[LPF_INPUT], '/')) == NULL)
1007 av[0] = pp->filters[LPF_INPUT];
1008 else
1009 av[0]++;
1010 if (format == 'l')
1011 av[n=1] = "-c";
1012 else
1013 n = 0;
1014 av[++n] = width;
1015 av[++n] = length;
1016 av[++n] = indent;
1017 av[++n] = "-n";
1018 av[++n] = logname;
1019 av[++n] = "-h";
1020 av[++n] = origin_host;
1021 av[++n] = pp->acct_file;
1022 av[++n] = 0;
1023 if ((ifilter = dofork(pp, DORETURN)) == 0) { /* child */
1024 dup2(f, 0);
1025 dup2(tfd, 1);
1026 /* setup stderr for the filter (child process)
1027 * so it goes to our temporary errors file */
1028 n = open(tempstderr, O_WRONLY|O_TRUNC, 0664);
1029 if (n >= 0)
1030 dup2(n, 2);
1031 closelog();
1032 closeallfds(3);
1033 execv(pp->filters[LPF_INPUT], av);
1034 syslog(LOG_ERR, "cannot execv %s",
1035 pp->filters[LPF_INPUT]);
1036 exit(2);
1037 }
1038 (void) close(f);
1039 if (ifilter < 0)
1040 status.w_retcode = 100;
1041 else {
1042 while ((pid = wait((int *)&status)) > 0 &&
1043 pid != ifilter)
1044 ;
1045 if (pid < 0) {
1046 status.w_retcode = 100;
1047 syslog(LOG_WARNING, "%s: after execv(%s), wait() returned: %m",
1048 pp->printer, pp->filters[LPF_INPUT]);
1049 }
1050 }
1051 /* Copy the filter's output to "lf" logfile */
1052 if ((fp = fopen(tempstderr, "r"))) {
1053 while (fgets(buf, sizeof(buf), fp))
1054 fputs(buf, stderr);
1055 fclose(fp);
1056 }
1057 /* process the return-code from the filter */
1058 switch (status.w_retcode) {
1059 case 0:
1060 break;
1061 case 1:
1062 unlink(tfile);
1063 return(REPRINT);
1064 case 2:
1065 unlink(tfile);
1066 return(ERROR);
1067 default:
1068 syslog(LOG_WARNING, "%s: filter '%c' exited"
1069 " (retcode=%d)",
1070 pp->printer, format, status.w_retcode);
1071 unlink(tfile);
1072 return(FILTERERR);
1073 }
1074 statrc = fstat(tfd, &stb); /* to find size of tfile */
1075 if (statrc < 0) {
1076 syslog(LOG_ERR, "%s: error processing 'if', fstat(%s): %m",
1077 pp->printer, tfile);
1078 return(ERROR);
1079 }
1080 f = tfd;
1081 lseek(f,0,SEEK_SET);
1082 } else if (ofilter) {
1083 /*
1084 * We're sending something with an ofilter, we have to
1085 * store the output as a temporary file (tfile)... the
1086 * protocol requires us to send the file size
1087 */
1088 int i;
1089 for (i = 0; i < stb.st_size; i += BUFSIZ) {
1090 amt = BUFSIZ;
1091 if (i + amt > stb.st_size)
1092 amt = stb.st_size - i;
1093 if (sizerr == 0 && read(f, buf, amt) != amt) {
1094 sizerr = 1;
1095 break;
1096 }
1097 if (write(ofd, buf, amt) != amt) {
1098 (void) close(f);
1099 return(REPRINT);
1100 }
1101 }
1102 close(ofd);
1103 close(f);
1104 while ((i = wait(NULL)) > 0 && i != ofilter)
1105 ;
1106 if (i < 0)
1107 syslog(LOG_WARNING, "%s: after closing 'of', wait() returned: %m",
1108 pp->printer);
1109 ofilter = 0;
1110 statrc = fstat(tfd, &stb); /* to find size of tfile */
1111 if (statrc < 0) {
1112 syslog(LOG_ERR, "%s: error processing 'of', fstat(%s): %m",
1113 pp->printer, tfile);
1114 openpr(pp);
1115 return(ERROR);
1116 }
1117 f = tfd;
1118 lseek(f,0,SEEK_SET);
1119 closedpr = 1;
1120 }
1121 }
1122
1123 (void) sprintf(buf, "%c%qd %s\n", type, stb.st_size, file);
1124 amt = strlen(buf);
1125 for (i = 0; ; i++) {
1126 if (write(pfd, buf, amt) != amt ||
1127 (resp = response(pp)) < 0 || resp == '\1') {
1128 (void) close(f);
1129 if (tfd != -1 && type == '\3') {
1130 tfd = -1;
1131 unlink(tfile);
1132 if (closedpr)
1133 openpr(pp);
1134 }
1135 return(REPRINT);
1136 } else if (resp == '\0')
1137 break;
1138 if (i == 0)
1139 pstatus(pp,
1140 "no space on remote; waiting for queue to drain");
1141 if (i == 10)
1142 syslog(LOG_ALERT, "%s: can't send to %s; queue full",
1143 pp->printer, pp->remote_host);
1144 sleep(5 * 60);
1145 }
1146 if (i)
1147 pstatus(pp, "sending to %s", pp->remote_host);
1148 if (type == '\3')
1149 trstat_init(pp, file, job_dfcnt);
1150 for (i = 0; i < stb.st_size; i += BUFSIZ) {
1151 amt = BUFSIZ;
1152 if (i + amt > stb.st_size)
1153 amt = stb.st_size - i;
1154 if (sizerr == 0 && read(f, buf, amt) != amt)
1155 sizerr = 1;
1156 if (write(pfd, buf, amt) != amt) {
1157 (void) close(f);
1158 if (tfd != -1 && type == '\3') {
1159 tfd = -1;
1160 unlink(tfile);
1161 if (closedpr)
1162 openpr(pp);
1163 }
1164 return(REPRINT);
1165 }
1166 }
1167
1168 (void) close(f);
1169 if (tfd != -1 && type == '\3') {
1170 tfd = -1;
1171 unlink(tfile);
1172 }
1173 if (sizerr) {
1174 syslog(LOG_INFO, "%s: %s: changed size", pp->printer, file);
1175 /* tell recvjob to ignore this file */
1176 (void) write(pfd, "\1", 1);
1177 if (closedpr)
1178 openpr(pp);
1179 return(ERROR);
1180 }
1181 if (write(pfd, "", 1) != 1 || response(pp)) {
1182 if (closedpr)
1183 openpr(pp);
1184 return(REPRINT);
1185 }
1186 if (closedpr)
1187 openpr(pp);
1188 if (type == '\3')
1189 trstat_write(pp, TR_SENDING, stb.st_size, logname,
1190 pp->remote_host, origin_host);
1191 return(OK);
1192}
1193
1194/*
1195 * Check to make sure there have been no errors and that both programs
1196 * are in sync with eachother.
1197 * Return non-zero if the connection was lost.
1198 */
1199static char
1200response(const struct printer *pp)
1201{
1202 char resp;
1203
1204 if (read(pfd, &resp, 1) != 1) {
1205 syslog(LOG_INFO, "%s: lost connection", pp->printer);
1206 return(-1);
1207 }
1208 return(resp);
1209}
1210
1211/*
1212 * Banner printing stuff
1213 */
1214static void
1215banner(struct printer *pp, char *name1, char *name2)
1216{
1217 time_t tvec;
1218
1219 time(&tvec);
1220 if (!pp->no_formfeed && !pp->tof)
1221 (void) write(ofd, pp->form_feed, strlen(pp->form_feed));
1222 if (pp->short_banner) { /* short banner only */
1223 if (class[0]) {
1224 (void) write(ofd, class, strlen(class));
1225 (void) write(ofd, ":", 1);
1226 }
1227 (void) write(ofd, name1, strlen(name1));
1228 (void) write(ofd, " Job: ", 7);
1229 (void) write(ofd, name2, strlen(name2));
1230 (void) write(ofd, " Date: ", 8);
1231 (void) write(ofd, ctime(&tvec), 24);
1232 (void) write(ofd, "\n", 1);
1233 } else { /* normal banner */
1234 (void) write(ofd, "\n\n\n", 3);
1235 scan_out(pp, ofd, name1, '\0');
1236 (void) write(ofd, "\n\n", 2);
1237 scan_out(pp, ofd, name2, '\0');
1238 if (class[0]) {
1239 (void) write(ofd,"\n\n\n",3);
1240 scan_out(pp, ofd, class, '\0');
1241 }
1242 (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15);
1243 (void) write(ofd, name2, strlen(name2));
1244 (void) write(ofd, "\n\t\t\t\t\tDate: ", 12);
1245 (void) write(ofd, ctime(&tvec), 24);
1246 (void) write(ofd, "\n", 1);
1247 }
1248 if (!pp->no_formfeed)
1249 (void) write(ofd, pp->form_feed, strlen(pp->form_feed));
1250 pp->tof = 1;
1251}
1252
1253static char *
1254scnline(int key, char *p, int c)
1255{
1256 register int scnwidth;
1257
1258 for (scnwidth = WIDTH; --scnwidth;) {
1259 key <<= 1;
1260 *p++ = key & 0200 ? c : BACKGND;
1261 }
1262 return (p);
1263}
1264
1265#define TRC(q) (((q)-' ')&0177)
1266
1267static void
1268scan_out(struct printer *pp, int scfd, char *scsp, int dlm)
1269{
1270 register char *strp;
1271 register int nchrs, j;
1272 char outbuf[LINELEN+1], *sp, c, cc;
1273 int d, scnhgt;
1274
1275 for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) {
1276 strp = &outbuf[0];
1277 sp = scsp;
1278 for (nchrs = 0; ; ) {
1279 d = dropit(c = TRC(cc = *sp++));
1280 if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d))
1281 for (j = WIDTH; --j;)
1282 *strp++ = BACKGND;
1283 else
1284 strp = scnline(scnkey[(int)c][scnhgt-1-d], strp, cc);
1285 if (*sp == dlm || *sp == '\0' ||
1286 nchrs++ >= pp->page_width/(WIDTH+1)-1)
1287 break;
1288 *strp++ = BACKGND;
1289 *strp++ = BACKGND;
1290 }
1291 while (*--strp == BACKGND && strp >= outbuf)
1292 ;
1293 strp++;
1294 *strp++ = '\n';
1295 (void) write(scfd, outbuf, strp-outbuf);
1296 }
1297}
1298
1299static int
1300dropit(int c)
1301{
1302 switch(c) {
1303
1304 case TRC('_'):
1305 case TRC(';'):
1306 case TRC(','):
1307 case TRC('g'):
1308 case TRC('j'):
1309 case TRC('p'):
1310 case TRC('q'):
1311 case TRC('y'):
1312 return (DROP);
1313
1314 default:
1315 return (0);
1316 }
1317}
1318
1319/*
1320 * sendmail ---
1321 * tell people about job completion
1322 */
1323static void
1324sendmail(struct printer *pp, char *user, int bombed)
1325{
1326 register int i;
1327 int p[2], s;
1328 register const char *cp;
1329 struct stat stb;
1330 FILE *fp;
1331
1332 pipe(p);
1333 if ((s = dofork(pp, DORETURN)) == 0) { /* child */
1334 dup2(p[0], 0);
1335 closelog();
1336 closeallfds(3);
1337 if ((cp = strrchr(_PATH_SENDMAIL, '/')) != NULL)
1338 cp++;
1339 else
1340 cp = _PATH_SENDMAIL;
1341 execl(_PATH_SENDMAIL, cp, "-t", (char *)0);
1342 _exit(0);
1343 } else if (s > 0) { /* parent */
1344 dup2(p[1], 1);
1345 printf("To: %s@%s\n", user, origin_host);
1346 printf("Subject: %s printer job \"%s\"\n", pp->printer,
1347 *jobname ? jobname : "<unknown>");
1348 printf("Reply-To: root@%s\n\n", local_host);
1349 printf("Your printer job ");
1350 if (*jobname)
1351 printf("(%s) ", jobname);
1352
1353 cp = "XXX compiler confusion"; /* XXX shut GCC up */
1354 switch (bombed) {
1355 case OK:
1356 printf("\ncompleted successfully\n");
1357 cp = "OK";
1358 break;
1359 default:
1360 case FATALERR:
1361 printf("\ncould not be printed\n");
1362 cp = "FATALERR";
1363 break;
1364 case NOACCT:
1365 printf("\ncould not be printed without an account on %s\n",
1366 local_host);
1367 cp = "NOACCT";
1368 break;
1369 case FILTERERR:
1370 if (stat(tempstderr, &stb) < 0 || stb.st_size == 0
1371 || (fp = fopen(tempstderr, "r")) == NULL) {
1372 printf("\nhad some errors and may not have printed\n");
1373 break;
1374 }
1375 printf("\nhad the following errors and may not have printed:\n");
1376 while ((i = getc(fp)) != EOF)
1377 putchar(i);
1378 (void) fclose(fp);
1379 cp = "FILTERERR";
1380 break;
1381 case ACCESS:
1382 printf("\nwas not printed because it was not linked to the original file\n");
1383 cp = "ACCESS";
1384 }
1385 fflush(stdout);
1386 (void) close(1);
1387 } else {
1388 syslog(LOG_WARNING, "unable to send mail to %s: %m", user);
1389 return;
1390 }
1391 (void) close(p[0]);
1392 (void) close(p[1]);
1393 wait(NULL);
1394 syslog(LOG_INFO, "mail sent to user %s about job %s on printer %s (%s)",
1395 user, *jobname ? jobname : "<unknown>", pp->printer, cp);
1396}
1397
1398/*
1399 * dofork - fork with retries on failure
1400 */
1401static int
1402dofork(const struct printer *pp, int action)
1403{
1404 register int i, forkpid;
1405 struct passwd *pwd;
1406
1407 for (i = 0; i < 20; i++) {
1408 if ((forkpid = fork()) < 0) {
1409 sleep((unsigned)(i*i));
1410 continue;
1411 }
1412 /*
1413 * Child should run as daemon instead of root
1414 */
1415 if (forkpid == 0) {
1416 if ((pwd = getpwuid(pp->daemon_user)) == NULL) {
1417 syslog(LOG_ERR, "Can't lookup default daemon uid (%ld) in password file",
1418 pp->daemon_user);
1419 break;
1420 }
1421 initgroups(pwd->pw_name, pwd->pw_gid);
1422 setgid(pwd->pw_gid);
1423 setuid(pp->daemon_user);
1424 }
1425 return(forkpid);
1426 }
1427 syslog(LOG_ERR, "can't fork");
1428
1429 switch (action) {
1430 case DORETURN:
1431 return (-1);
1432 default:
1433 syslog(LOG_ERR, "bad action (%d) to dofork", action);
1434 /*FALL THRU*/
1435 case DOABORT:
1436 exit(1);
1437 }
1438 /*NOTREACHED*/
1439}
1440
1441/*
1442 * Kill child processes to abort current job.
1443 */
1444static void
1445abortpr(int signo __unused)
1446{
1447
1448 (void) unlink(tempstderr);
1449 kill(0, SIGINT);
1450 if (ofilter > 0)
1451 kill(ofilter, SIGCONT);
1452 while (wait(NULL) > 0)
1453 ;
1454 if (ofilter > 0 && tfd != -1)
1455 unlink(tfile);
1456 exit(0);
1457}
1458
1459static void
1460init(struct printer *pp)
1461{
1462 char *s;
1463
1464 sprintf(&width[2], "%ld", pp->page_width);
1465 sprintf(&length[2], "%ld", pp->page_length);
1466 sprintf(&pxwidth[2], "%ld", pp->page_pwidth);
1467 sprintf(&pxlength[2], "%ld", pp->page_plength);
1468 if ((s = checkremote(pp)) != 0) {
1469 syslog(LOG_WARNING, "%s", s);
1470 free(s);
1471 }
1472}
1473
1474void
1475startprinting(const char *printer)
1476{
1477 struct printer myprinter, *pp = &myprinter;
1478 int status;
1479
1480 init_printer(pp);
1481 status = getprintcap(printer, pp);
1482 switch(status) {
1483 case PCAPERR_OSERR:
1484 syslog(LOG_ERR, "can't open printer description file: %m");
1485 exit(1);
1486 case PCAPERR_NOTFOUND:
1487 syslog(LOG_ERR, "unknown printer: %s", printer);
1488 exit(1);
1489 case PCAPERR_TCLOOP:
1490 fatal(pp, "potential reference loop detected in printcap file");
1491 default:
1492 break;
1493 }
1494 printjob(pp);
1495}
1496
1497/*
1498 * Acquire line printer or remote connection.
1499 */
1500static void
1501openpr(const struct printer *pp)
1502{
1503 int p[2];
1504 char *cp;
1505
1506 if (pp->remote) {
1507 openrem(pp);
1508 } else if (*pp->lp) {
1509 if ((cp = strchr(pp->lp, '@')) != NULL)
1510 opennet(pp);
1511 else
1512 opentty(pp);
1513 } else {
1514 syslog(LOG_ERR, "%s: no line printer device or host name",
1515 pp->printer);
1516 exit(1);
1517 }
1518
1519 /*
1520 * Start up an output filter, if needed.
1521 */
1522 if (pp->filters[LPF_OUTPUT] && !pp->filters[LPF_INPUT] && !ofilter) {
1523 pipe(p);
1524 if (pp->remote) {
1525 strcpy(tfile, TFILENAME);
1526 tfd = mkstemp(tfile);
1527 }
1528 if ((ofilter = dofork(pp, DOABORT)) == 0) { /* child */
1529 dup2(p[0], 0); /* pipe is std in */
1530 /* tfile/printer is stdout */
1531 dup2(pp->remote ? tfd : pfd, 1);
1532 closelog();
1533 closeallfds(3);
1534 if ((cp = strrchr(pp->filters[LPF_OUTPUT], '/')) == NULL)
1535 cp = pp->filters[LPF_OUTPUT];
1536 else
1537 cp++;
1538 execl(pp->filters[LPF_OUTPUT], cp, width, length,
1539 (char *)0);
1540 syslog(LOG_ERR, "%s: %s: %m", pp->printer,
1541 pp->filters[LPF_OUTPUT]);
1542 exit(1);
1543 }
1544 (void) close(p[0]); /* close input side */
1545 ofd = p[1]; /* use pipe for output */
1546 } else {
1547 ofd = pfd;
1548 ofilter = 0;
1549 }
1550}
1551
1552/*
1553 * Printer connected directly to the network
1554 * or to a terminal server on the net
1555 */
1556static void
1557opennet(const struct printer *pp)
1558{
1559 register int i;
1560 int resp;
1561 u_long port;
1562 char *ep;
1563 void (*savealrm)(int);
1564
1565 port = strtoul(pp->lp, &ep, 0);
1566 if (*ep != '@' || port > 65535) {
1567 syslog(LOG_ERR, "%s: bad port number: %s", pp->printer,
1568 pp->lp);
1569 exit(1);
1570 }
1571 ep++;
1572
1573 for (i = 1; ; i = i < 256 ? i << 1 : i) {
1574 resp = -1;
1575 savealrm = signal(SIGALRM, alarmhandler);
1576 alarm(pp->conn_timeout);
1577 pfd = getport(pp, ep, port);
1578 alarm(0);
1579 (void)signal(SIGALRM, savealrm);
1580 if (pfd < 0 && errno == ECONNREFUSED)
1581 resp = 1;
1582 else if (pfd >= 0) {
1583 /*
1584 * need to delay a bit for rs232 lines
1585 * to stabilize in case printer is
1586 * connected via a terminal server
1587 */
1588 delay(500);
1589 break;
1590 }
1591 if (i == 1) {
1592 if (resp < 0)
1593 pstatus(pp, "waiting for %s to come up",
1594 pp->lp);
1595 else
1596 pstatus(pp,
1597 "waiting for access to printer on %s",
1598 pp->lp);
1599 }
1600 sleep(i);
1601 }
1602 pstatus(pp, "sending to %s port %lu", ep, port);
1603}
1604
1605/*
1606 * Printer is connected to an RS232 port on this host
1607 */
1608static void
1609opentty(const struct printer *pp)
1610{
1611 register int i;
1612
1613 for (i = 1; ; i = i < 32 ? i << 1 : i) {
1614 pfd = open(pp->lp, pp->rw ? O_RDWR : O_WRONLY);
1615 if (pfd >= 0) {
1616 delay(500);
1617 break;
1618 }
1619 if (errno == ENOENT) {
1620 syslog(LOG_ERR, "%s: %m", pp->lp);
1621 exit(1);
1622 }
1623 if (i == 1)
1624 pstatus(pp,
1625 "waiting for %s to become ready (offline?)",
1626 pp->printer);
1627 sleep(i);
1628 }
1629 if (isatty(pfd))
1630 setty(pp);
1631 pstatus(pp, "%s is ready and printing", pp->printer);
1632}
1633
1634/*
1635 * Printer is on a remote host
1636 */
1637static void
1638openrem(const struct printer *pp)
1639{
1640 register int i;
1641 int resp;
1642 void (*savealrm)(int);
1643
1644 for (i = 1; ; i = i < 256 ? i << 1 : i) {
1645 resp = -1;
1646 savealrm = signal(SIGALRM, alarmhandler);
1647 alarm(pp->conn_timeout);
1648 pfd = getport(pp, pp->remote_host, 0);
1649 alarm(0);
1650 (void)signal(SIGALRM, savealrm);
1651 if (pfd >= 0) {
1652 if ((writel(pfd, "\2", pp->remote_queue, "\n",
1653 (char *)0)
1654 == 2 + strlen(pp->remote_queue))
1655 && (resp = response(pp)) == 0)
1656 break;
1657 (void) close(pfd);
1658 }
1659 if (i == 1) {
1660 if (resp < 0)
1661 pstatus(pp, "waiting for %s to come up",
1662 pp->remote_host);
1663 else {
1664 pstatus(pp,
1665 "waiting for queue to be enabled on %s",
1666 pp->remote_host);
1667 i = 256;
1668 }
1669 }
1670 sleep(i);
1671 }
1672 pstatus(pp, "sending to %s", pp->remote_host);
1673}
1674
1675/*
1676 * setup tty lines.
1677 */
1678static void
1679setty(const struct printer *pp)
1680{
1681 struct termios ttybuf;
1682
1683 if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) {
1684 syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", pp->printer);
1685 exit(1);
1686 }
1687 if (tcgetattr(pfd, &ttybuf) < 0) {
1688 syslog(LOG_ERR, "%s: tcgetattr: %m", pp->printer);
1689 exit(1);
1690 }
1691 if (pp->baud_rate > 0)
1692 cfsetspeed(&ttybuf, pp->baud_rate);
1693 if (pp->mode_set) {
1694 char *s = strdup(pp->mode_set), *tmp;
1695
1696 while ((tmp = strsep(&s, ",")) != NULL) {
1697 (void) msearch(tmp, &ttybuf);
1698 }
1699 }
1700 if (pp->mode_set != 0 || pp->baud_rate > 0) {
1701 if (tcsetattr(pfd, TCSAFLUSH, &ttybuf) == -1) {
1702 syslog(LOG_ERR, "%s: tcsetattr: %m", pp->printer);
1703 }
1704 }
1705}
1706
1707#ifdef __STDC__
1708#include <stdarg.h>
1709#else
1710#include <varargs.h>
1711#endif
1712
1713static void
1714#ifdef __STDC__
1715pstatus(const struct printer *pp, const char *msg, ...)
1716#else
1717pstatus(pp, msg, va_alist)
1718 const struct printer *pp;
1719 char *msg;
1720 va_dcl
1721#endif
1722{
1723 int fd;
1724 char *buf;
1725 va_list ap;
1726#ifdef __STDC__
1727 va_start(ap, msg);
1728#else
1729 va_start(ap);
1730#endif
1731
1732 umask(0);
1733 fd = open(pp->status_file, O_WRONLY|O_CREAT|O_EXLOCK, STAT_FILE_MODE);
1734 if (fd < 0) {
1735 syslog(LOG_ERR, "%s: %s: %m", pp->printer, pp->status_file);
1736 exit(1);
1737 }
1738 ftruncate(fd, 0);
1739 vasprintf(&buf, msg, ap);
1740 va_end(ap);
1741 writel(fd, buf, "\n", (char *)0);
1742 close(fd);
1743 free(buf);
1744}
1745
1746void
1747alarmhandler(int signo __unused)
1748{
1749 /* the signal is ignored */
1750 /* (the '__unused' is just to avoid a compile-time warning) */
1751}