2 * Copyright (c) 1983, 1993
3 * The Regents of the University of California. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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
36 static const char copyright[] =
37 "@(#) Copyright (c) 1983, 1993\n\
38 The Regents of the University of California. All rights reserved.\n";
43 static char sccsid[] = "@(#)printjob.c 8.7 (Berkeley) 5/10/95";
45 static const char rcsid[] =
46 "$FreeBSD: src/usr.sbin/lpr/lpd/printjob.c,v 1.22.2.32 2002/06/19 23:58:16 gad Exp $";
51 * printjob -- print jobs in the queue.
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.
57 #include <sys/param.h>
60 #include <sys/types.h>
72 #include <sys/ioctl.h>
77 #include "pathnames.h"
80 #define DORETURN 0 /* dofork should return "can't fork" error */
81 #define DOABORT 1 /* dofork should just die if fork() fails */
94 static dev_t fdev; /* device of file pointed to by symlink */
95 static ino_t fino; /* inode of file pointed to by symlink */
96 static FILE *cfp; /* control file */
97 static pid_t of_pid; /* process id of output filter, if any */
98 static int child; /* id of any filters */
99 static int job_dfcnt; /* count of datafiles in current user job */
100 static int lfd; /* lock file descriptor */
101 static int ofd; /* output filter file descriptor */
102 static int tfd = -1; /* output filter temp file output */
103 static int pfd; /* prstatic inter file descriptor */
104 static int prchild; /* id of pr process */
105 static char title[80]; /* ``pr'' title */
106 static char locale[80]; /* ``pr'' locale */
108 /* these two are set from pp->daemon_user, but only if they are needed */
109 static char *daemon_uname; /* set from pwd->pw_name */
110 static int daemon_defgid;
112 static char class[32]; /* classification field */
113 static char origin_host[MAXHOSTNAMELEN]; /* user's host machine */
114 /* indentation size in static characters */
115 static char indent[10] = "-i0";
116 static char jobname[100]; /* job or file name */
117 static char length[10] = "-l"; /* page length in lines */
118 static char logname[32]; /* user's login name */
119 static char pxlength[10] = "-y"; /* page length in pixels */
120 static char pxwidth[10] = "-x"; /* page width in pixels */
121 /* tempstderr is the filename used to catch stderr from exec-ing filters */
122 static char tempstderr[] = "errs.XXXXXXX";
123 static char width[10] = "-w"; /* page width in static characters */
124 #define TFILENAME "fltXXXXXX"
125 static char tfile[] = TFILENAME; /* file name for filter output */
127 static void abortpr(int _signo);
128 static void alarmhandler(int _signo);
129 static void banner(struct printer *_pp, char *_name1, char *_name2);
130 static int dofork(const struct printer *_pp, int _action);
131 static int dropit(int _c);
132 static int execfilter(struct printer *_pp, char *_f_cmd, char **_f_av,
133 int _infd, int _outfd);
134 static void init(struct printer *_pp);
135 static void openpr(const struct printer *_pp);
136 static void opennet(const struct printer *_pp);
137 static void opentty(const struct printer *_pp);
138 static void openrem(const struct printer *pp);
139 static int print(struct printer *_pp, int _format, char *_file);
140 static int printit(struct printer *_pp, char *_file);
141 static void pstatus(const struct printer *_pp, const char *_msg, ...)
143 static char response(const struct printer *_pp);
144 static void scan_out(struct printer *_pp, int _scfd, char *_scsp,
146 static char *scnline(int _key, char *_p, int _c);
147 static int sendfile(struct printer *_pp, int _type, char *_file,
148 char _format, int _copyreq);
149 static int sendit(struct printer *_pp, char *_file);
150 static void sendmail(struct printer *_pp, char *_userid, int _bombed);
151 static void setty(const struct printer *_pp);
154 printjob(struct printer *pp)
157 register struct jobqueue *q, **qp;
158 struct jobqueue **queue;
159 register int i, nitems;
162 int errcnt, jobcount, tempfd;
165 init(pp); /* set up capabilities */
166 (void) write(1, "", 1); /* ack that daemon is started */
167 (void) close(2); /* set up log file */
168 if (open(pp->log_file, O_WRONLY|O_APPEND, LOG_FILE_MODE) < 0) {
169 syslog(LOG_ERR, "%s: open(%s): %m", pp->printer,
171 (void) open(_PATH_DEVNULL, O_WRONLY);
174 printpid = getpid(); /* for use with lprm */
175 setpgrp(0, printpid);
178 * At initial lpd startup, printjob may be called with various
179 * signal handlers in effect. After that initial startup, any
180 * calls to printjob will have a *different* set of signal-handlers
181 * in effect. Make sure all handlers are the ones we want.
183 signal(SIGCHLD, SIG_DFL);
184 signal(SIGHUP, abortpr);
185 signal(SIGINT, abortpr);
186 signal(SIGQUIT, abortpr);
187 signal(SIGTERM, abortpr);
190 * uses short form file names
192 if (chdir(pp->spool_dir) < 0) {
193 syslog(LOG_ERR, "%s: chdir(%s): %m", pp->printer,
197 if (stat(pp->lock_file, &stb) == 0 && (stb.st_mode & LFM_PRINT_DIS))
198 exit(0); /* printing disabled */
199 lfd = open(pp->lock_file, O_WRONLY|O_CREAT|O_EXLOCK|O_NONBLOCK,
202 if (errno == EWOULDBLOCK) /* active daemon present */
204 syslog(LOG_ERR, "%s: open(%s): %m", pp->printer,
208 /* turn off non-blocking mode (was turned on for lock effects only) */
209 if (fcntl(lfd, F_SETFL, 0) < 0) {
210 syslog(LOG_ERR, "%s: fcntl(%s): %m", pp->printer,
216 * write process id for others to know
218 sprintf(line, "%u\n", printpid);
219 pidoff = i = strlen(line);
220 if (write(lfd, line, i) != i) {
221 syslog(LOG_ERR, "%s: write(%s): %m", pp->printer,
226 * search the spool directory for work and sort by queue order.
228 if ((nitems = getq(pp, &queue)) < 0) {
229 syslog(LOG_ERR, "%s: can't scan %s", pp->printer,
233 if (nitems == 0) /* no work to do */
235 if (stb.st_mode & LFM_RESET_QUE) { /* reset queue flag */
236 if (fchmod(lfd, stb.st_mode & ~LFM_RESET_QUE) < 0)
237 syslog(LOG_ERR, "%s: fchmod(%s): %m", pp->printer,
241 /* create a file which will be used to hold stderr from filters */
242 if ((tempfd = mkstemp(tempstderr)) == -1) {
243 syslog(LOG_ERR, "%s: mkstemp(%s): %m", pp->printer,
247 if ((i = fchmod(tempfd, 0664)) == -1) {
248 syslog(LOG_ERR, "%s: fchmod(%s): %m", pp->printer,
252 /* lpd doesn't need it to be open, it just needs it to exist */
255 openpr(pp); /* open printer or remote */
258 * we found something to do now do it --
259 * write the name of the current control file into the lock file
260 * so the spool queue program can tell what we're working on
262 for (qp = queue; nitems--; free((char *) q)) {
264 if (stat(q->job_cfname, &stb) < 0)
268 (void) lseek(lfd, pidoff, 0);
269 (void) snprintf(line, sizeof(line), "%s\n", q->job_cfname);
271 if (write(lfd, line, i) != i)
272 syslog(LOG_ERR, "%s: write(%s): %m", pp->printer,
275 i = printit(pp, q->job_cfname);
277 i = sendit(pp, q->job_cfname);
279 * Check to see if we are supposed to stop printing or
280 * if we are to rebuild the queue.
282 if (fstat(lfd, &stb) == 0) {
283 /* stop printing before starting next job? */
284 if (stb.st_mode & LFM_PRINT_DIS)
286 /* rebuild queue (after lpc topq) */
287 if (stb.st_mode & LFM_RESET_QUE) {
288 for (free(q); nitems--; free(q))
290 if (fchmod(lfd, stb.st_mode & ~LFM_RESET_QUE)
293 "%s: fchmod(%s): %m",
294 pp->printer, pp->lock_file);
298 if (i == OK) /* all files of this job printed */
300 else if (i == REPRINT && ++errcnt < 5) {
301 /* try reprinting the job */
302 syslog(LOG_INFO, "restarting %s", pp->printer);
304 kill(of_pid, SIGCONT); /* to be sure */
306 while ((i = wait(NULL)) > 0 && i != of_pid)
309 syslog(LOG_WARNING, "%s: after kill(of=%d), wait() returned: %m",
310 pp->printer, of_pid);
313 (void) close(pfd); /* close printer */
314 if (ftruncate(lfd, pidoff) < 0)
315 syslog(LOG_WARNING, "%s: ftruncate(%s): %m",
316 pp->printer, pp->lock_file);
317 openpr(pp); /* try to reopen printer */
320 syslog(LOG_WARNING, "%s: job could not be %s (%s)",
322 pp->remote ? "sent to remote host" : "printed",
325 /* ensure we don't attempt this job again */
326 (void) unlink(q->job_cfname);
327 q->job_cfname[0] = 'd';
328 (void) unlink(q->job_cfname);
330 sendmail(pp, logname, FATALERR);
336 * search the spool directory for more work.
338 if ((nitems = getq(pp, &queue)) < 0) {
339 syslog(LOG_ERR, "%s: can't scan %s", pp->printer,
343 if (nitems == 0) { /* no more work to do */
345 if (jobcount > 0) { /* jobs actually printed */
346 if (!pp->no_formfeed && !pp->tof)
347 (void) write(ofd, pp->form_feed,
348 strlen(pp->form_feed));
349 if (pp->trailer != NULL) /* output trailer */
350 (void) write(ofd, pp->trailer,
351 strlen(pp->trailer));
355 (void) unlink(tempstderr);
361 char fonts[4][50]; /* fonts for troff */
363 char ifonts[4][40] = {
371 * The remaining part is the reading of the control file (cf)
372 * and performing the various actions.
375 printit(struct printer *pp, char *file)
379 int bombed, didignorehdr;
384 * open control file; ignore if no longer there.
386 if ((cfp = fopen(file, "r")) == NULL) {
387 syslog(LOG_INFO, "%s: fopen(%s): %m", pp->printer, file);
393 for (i = 0; i < 4; i++)
394 strcpy(fonts[i], ifonts[i]);
395 sprintf(&width[2], "%ld", pp->page_width);
396 strcpy(indent+2, "0");
398 /* initialize job-specific count of datafiles processed */
402 * read the control file for work to do
404 * file format -- first character in the line is a command
405 * rest of the line is the argument.
406 * valid commands are:
408 * S -- "stat info" for symbolic link protection
409 * J -- "job name" on banner page
410 * C -- "class name" on banner page
411 * L -- "literal" user's name to print on banner
412 * T -- "title" for pr
413 * H -- "host name" of machine where lpr was done
414 * P -- "person" user's login name
415 * I -- "indent" amount to indent output
416 * R -- laser dpi "resolution"
417 * f -- "file name" name of text file to print
418 * l -- "file name" text file with control chars
419 * o -- "file name" postscript file, according to
420 * the RFC. Here it is treated like an 'f'.
421 * p -- "file name" text file to print with pr(1)
422 * t -- "file name" troff(1) file to print
423 * n -- "file name" ditroff(1) file to print
424 * d -- "file name" dvi file to print
425 * g -- "file name" plot(1G) file to print
426 * v -- "file name" plain raster file to print
427 * c -- "file name" cifplot file to print
428 * 1 -- "R font file" for troff
429 * 2 -- "I font file" for troff
430 * 3 -- "B font file" for troff
431 * 4 -- "S font file" for troff
432 * N -- "name" of file (used by lpq)
433 * U -- "unlink" name of file to remove
434 * (after we print it. (Pass 2 only)).
435 * M -- "mail" to user when done printing
436 * Z -- "locale" for pr
438 * getline reads a line and expands tabs to blanks
446 strlcpy(origin_host, line + 1, sizeof(origin_host));
447 if (class[0] == '\0') {
448 strlcpy(class, line+1, sizeof(class));
453 strlcpy(logname, line + 1, sizeof(logname));
454 if (pp->restricted) { /* restricted */
455 if (getpwnam(logname) == NULL) {
457 sendmail(pp, line+1, bombed);
466 while (*cp >= '0' && *cp <= '9')
467 i = i * 10 + (*cp++ - '0');
471 while (*cp >= '0' && *cp <= '9')
472 i = i * 10 + (*cp++ - '0');
477 if (line[1] != '\0') {
478 strlcpy(jobname, line + 1, sizeof(jobname));
480 strcpy(jobname, " ");
485 strlcpy(class, line + 1, sizeof(class));
486 else if (class[0] == '\0') {
487 /* XXX - why call gethostname instead of
488 * just strlcpy'ing local_host? */
489 gethostname(class, sizeof(class));
490 class[sizeof(class) - 1] = '\0';
494 case 'T': /* header title for pr */
495 strlcpy(title, line + 1, sizeof(title));
498 case 'L': /* identification line */
499 if (!pp->no_header && !pp->header_last)
500 banner(pp, line+1, jobname);
503 case '1': /* troff fonts */
507 if (line[1] != '\0') {
508 strlcpy(fonts[line[0]-'1'], line + 1,
513 case 'W': /* page width */
514 strlcpy(width+2, line + 1, sizeof(width) - 2);
517 case 'I': /* indent amount */
518 strlcpy(indent+2, line + 1, sizeof(indent) - 2);
521 case 'Z': /* locale for pr */
522 strlcpy(locale, line + 1, sizeof(locale));
525 default: /* some file to print */
526 /* only lowercase cmd-codes include a file-to-print */
527 if ((line[0] < 'a') || (line[0] > 'z')) {
528 /* ignore any other lines */
532 syslog(LOG_INFO, "%s: in %s :",
536 syslog(LOG_INFO, "%s: ignoring line: '%c' %s",
537 pp->printer, line[0], &line[1]);
540 i = print(pp, line[0], line+1);
552 sendmail(pp, logname, bombed);
570 case 'L': /* identification line */
571 if (!pp->no_header && pp->header_last)
572 banner(pp, line+1, jobname);
576 if (bombed < NOACCT) /* already sent if >= NOACCT */
577 sendmail(pp, line+1, bombed);
581 if (strchr(line+1, '/'))
583 (void) unlink(line+1);
586 * clean-up in case another control file exists
590 return (bombed == OK ? OK : ERROR);
595 * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}.
596 * Return -1 if a non-recoverable error occured,
597 * 2 if the filter detected some errors (but printed the job anyway),
598 * 1 if we should try to reprint this job and
600 * Note: all filters take stdin as the file, stdout as the printer,
601 * stderr as the log file, and must not ignore SIGINT.
604 print(struct printer *pp, int format, char *file)
610 char *av[15], buf[BUFSIZ];
612 int p[2], retcode, stopped, wstatus, wstatus_set;
615 if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0) {
616 syslog(LOG_INFO, "%s: unable to open %s ('%c' line)",
617 pp->printer, file, format);
621 * Check to see if data file is a symbolic link. If so, it should
622 * still point to the same file or someone is trying to print
623 * something he shouldn't.
625 if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 &&
626 (stb.st_dev != fdev || stb.st_ino != fino))
629 job_dfcnt++; /* increment datafile counter for this job */
630 stopped = 0; /* output filter is not stopped */
632 /* everything seems OK, start it up */
633 if (!pp->no_formfeed && !pp->tof) { /* start on a fresh page */
634 (void) write(ofd, pp->form_feed, strlen(pp->form_feed));
637 if (pp->filters[LPF_INPUT] == NULL
638 && (format == 'f' || format == 'l' || format == 'o')) {
640 while ((n = read(fi, buf, BUFSIZ)) > 0)
641 if (write(ofd, buf, n) != n) {
649 case 'p': /* print file using 'pr' */
650 if (pp->filters[LPF_INPUT] == NULL) { /* use output filter */
657 av[i++] = *title ? title : " ";
659 av[i++] = *locale ? locale : "C";
666 if ((prchild = dofork(pp, DORETURN)) == 0) { /* child */
667 dup2(fi, 0); /* file is stdin */
668 dup2(p[1], 1); /* pipe is stdout */
671 execl(_PATH_PR, "pr", width, length,
672 "-h", *title ? title : " ",
673 "-L", *locale ? locale : "C",
675 syslog(LOG_ERR, "cannot execl %s", _PATH_PR);
678 (void) close(p[1]); /* close output side */
685 fi = p[0]; /* use pipe for input */
686 case 'f': /* print plain text file */
687 prog = pp->filters[LPF_INPUT];
693 case 'o': /* print postscript file */
695 * Treat this as a "plain file with control characters", and
696 * assume the standard LPF_INPUT filter will recognize that
697 * the data is postscript and know what to do with it. These
698 * 'o'-file requests could come from MacOS 10.1 systems.
699 * (later versions of MacOS 10 will explicitly use 'l')
700 * A postscript file can contain binary data, which is why 'l'
701 * is somewhat more appropriate than 'f'.
704 case 'l': /* like 'f' but pass control characters */
705 prog = pp->filters[LPF_INPUT];
712 case 'r': /* print a fortran text file */
713 prog = pp->filters[LPF_FORTRAN];
718 case 't': /* print troff output */
719 case 'n': /* print ditroff output */
720 case 'd': /* print tex output */
721 (void) unlink(".railmag");
722 if ((fo = creat(".railmag", FILMOD)) < 0) {
723 syslog(LOG_ERR, "%s: cannot create .railmag",
725 (void) unlink(".railmag");
727 for (n = 0; n < 4; n++) {
728 if (fonts[n][0] != '/')
729 (void) write(fo, _PATH_VFONT,
730 sizeof(_PATH_VFONT) - 1);
731 (void) write(fo, fonts[n], strlen(fonts[n]));
732 (void) write(fo, "\n", 1);
736 prog = (format == 't') ? pp->filters[LPF_TROFF]
737 : ((format == 'n') ? pp->filters[LPF_DITROFF]
738 : pp->filters[LPF_DVI]);
743 case 'c': /* print cifplot output */
744 prog = pp->filters[LPF_CIFPLOT];
749 case 'g': /* print plot(1G) output */
750 prog = pp->filters[LPF_GRAPH];
755 case 'v': /* print raster output */
756 prog = pp->filters[LPF_RASTER];
763 syslog(LOG_ERR, "%s: illegal format character '%c'",
764 pp->printer, format);
770 "%s: no filter found in printcap for format character '%c'",
771 pp->printer, format);
774 if ((av[0] = strrchr(prog, '/')) != NULL)
781 av[n++] = origin_host;
782 av[n++] = pp->acct_file;
785 if (of_pid > 0) { /* stop output filter */
786 write(ofd, "\031\1", 2);
788 wait3(&wstatus, WUNTRACED, 0)) > 0 && wpid != of_pid)
792 "%s: after stopping 'of', wait3() returned: %m",
794 else if (!WIFSTOPPED(wstatus)) {
796 syslog(LOG_WARNING, "%s: output filter died "
797 "(pid=%d retcode=%d termsig=%d)",
798 pp->printer, of_pid, WEXITSTATUS(wstatus),
805 if ((child = dofork(pp, DORETURN)) == 0) { /* child */
808 /* setup stderr for the filter (child process)
809 * so it goes to our temporary errors file */
810 n = open(tempstderr, O_WRONLY|O_TRUNC, 0664);
816 syslog(LOG_ERR, "%s: cannot execv(%s): %m", pp->printer,
825 while ((wpid = wait(&wstatus)) > 0 && wpid != child)
830 "%s: after execv(%s), wait() returned: %m",
834 retcode = WEXITSTATUS(wstatus);
839 if (stopped) { /* restart output filter */
840 if (kill(of_pid, SIGCONT) < 0) {
841 syslog(LOG_ERR, "cannot restart output filter");
847 /* Copy the filter's output to "lf" logfile */
848 if ((fp = fopen(tempstderr, "r"))) {
849 while (fgets(buf, sizeof(buf), fp))
854 if (wstatus_set && !WIFEXITED(wstatus)) {
855 syslog(LOG_WARNING, "%s: filter '%c' terminated (termsig=%d)",
856 pp->printer, format, WTERMSIG(wstatus));
868 syslog(LOG_WARNING, "%s: filter '%c' exited (retcode=%d)",
869 pp->printer, format, retcode);
875 * Send the daemon control file (cf) and any data files.
876 * Return -1 if a non-recoverable error occured, 1 if a recoverable error and
880 sendit(struct printer *pp, char *file)
882 int dfcopies, err, i;
883 char *cp, last[BUFSIZ];
888 if ((cfp = fopen(file, "r")) == NULL)
891 /* initialize job-specific count of datafiles processed */
895 * read the control file for work to do
897 * file format -- first character in the line is a command
898 * rest of the line is the argument.
899 * commands of interest are:
901 * a-z -- "file name" name of file to print
902 * U -- "unlink" name of file to remove
903 * (after we print it. (Pass 2 only)).
910 while (getline(cfp)) {
912 if (line[0] == 'S') {
915 while (*cp >= '0' && *cp <= '9')
916 i = i * 10 + (*cp++ - '0');
920 while (*cp >= '0' && *cp <= '9')
921 i = i * 10 + (*cp++ - '0');
923 } else if (line[0] == 'H') {
924 strlcpy(origin_host, line + 1, sizeof(origin_host));
925 if (class[0] == '\0') {
926 strlcpy(class, line + 1, sizeof(class));
928 } else if (line[0] == 'P') {
929 strlcpy(logname, line + 1, sizeof(logname));
930 if (pp->restricted) { /* restricted */
931 if (getpwnam(logname) == NULL) {
932 sendmail(pp, line+1, NOACCT);
937 } else if (line[0] == 'I') {
938 strlcpy(indent+2, line + 1, sizeof(indent) - 2);
939 } else if (line[0] >= 'a' && line[0] <= 'z') {
942 while ((i = getline(cfp)) != 0) {
943 if (strcmp(last, line) != 0)
947 switch (sendfile(pp, '\3', last+1, *last, dfcopies)) {
956 sendmail(pp, logname, ACCESS);
963 if (err == OK && sendfile(pp, '\2', file, '\0', 1) > 0) {
972 if (line[0] == 'U' && !strchr(line+1, '/'))
973 (void) unlink(line+1);
975 * clean-up in case another control file exists
983 * Send a data file to the remote machine and spool it.
984 * Return positive if we should try resending.
987 sendfile(struct printer *pp, int type, char *file, char format, int copyreq)
991 char *av[15], *filtcmd;
992 char buf[BUFSIZ], opt_c[4], opt_h[4], opt_n[4];
993 int copycnt, filtstat, narg, resp, sfd, sfres, sizerr, statrc;
995 statrc = lstat(file, &stb);
997 syslog(LOG_ERR, "%s: error from lstat(%s): %m",
1001 sfd = open(file, O_RDONLY);
1003 syslog(LOG_ERR, "%s: error from open(%s,O_RDONLY): %m",
1008 * Check to see if data file is a symbolic link. If so, it should
1009 * still point to the same file or someone is trying to print something
1012 if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(sfd, &stb) == 0 &&
1013 (stb.st_dev != fdev || stb.st_ino != fino)) {
1018 /* Everything seems OK for reading the file, now to send it */
1024 * Type == 3 means this is a datafile, not a control file.
1025 * Increment the counter of data-files in this job, and
1026 * then check for input or output filters (which are only
1027 * applied to datafiles, not control files).
1032 * Note that here we are filtering datafiles, one at a time,
1033 * as they are sent to the remote machine. Here, the *only*
1034 * difference between an input filter (`if=') and an output
1035 * filter (`of=') is the argument list that the filter is
1036 * started up with. Here, the output filter is executed
1037 * for each individual file as it is sent. This is not the
1038 * same as local print queues, where the output filter is
1039 * started up once, and then all jobs are passed thru that
1040 * single invocation of the output filter.
1042 * Also note that a queue for a remote-machine can have an
1043 * input filter or an output filter, but not both.
1045 if (pp->filters[LPF_INPUT]) {
1046 filtcmd = pp->filters[LPF_INPUT];
1049 strcpy(opt_c, "-c");
1050 strcpy(opt_h, "-h");
1051 strcpy(opt_n, "-n");
1055 av[++narg] = length;
1056 av[++narg] = indent;
1058 av[++narg] = logname;
1060 av[++narg] = origin_host;
1061 av[++narg] = pp->acct_file;
1063 } else if (pp->filters[LPF_OUTPUT]) {
1064 filtcmd = pp->filters[LPF_OUTPUT];
1068 av[++narg] = length;
1074 * If there is an input or output filter, we have to run
1075 * the datafile thru that filter and store the result as
1076 * a temporary spool file, because the protocol requires
1077 * that we send the remote host the file-size before we
1078 * start to send any of the data.
1080 strcpy(tfile, TFILENAME);
1081 tfd = mkstemp(tfile);
1083 syslog(LOG_ERR, "%s: mkstemp(%s): %m", pp->printer,
1088 filtstat = execfilter(pp, filtcmd, av, sfd, tfd);
1090 /* process the return-code from the filter */
1102 "%s: filter '%c' exited (retcode=%d)",
1103 pp->printer, format, filtstat);
1107 statrc = fstat(tfd, &stb); /* to find size of tfile */
1110 "%s: error processing 'if', fstat(%s): %m",
1111 pp->printer, tfile);
1117 lseek(sfd, 0, SEEK_SET);
1125 (void) sprintf(buf, "%c%qd %s\n", type, stb.st_size, file);
1127 (void) sprintf(buf, "%c%qd %s_c%d\n", type, stb.st_size,
1130 for (i = 0; ; i++) {
1131 if (write(pfd, buf, amt) != amt ||
1132 (resp = response(pp)) < 0 || resp == '\1') {
1135 } else if (resp == '\0')
1139 "no space on remote; waiting for queue to drain");
1141 syslog(LOG_ALERT, "%s: can't send to %s; queue full",
1142 pp->printer, pp->remote_host);
1146 pstatus(pp, "sending to %s", pp->remote_host);
1148 * XXX - we should change trstat_init()/trstat_write() to include
1149 * the copycnt in the statistics record it may write.
1152 trstat_init(pp, file, job_dfcnt);
1153 for (i = 0; i < stb.st_size; i += BUFSIZ) {
1155 if (i + amt > stb.st_size)
1156 amt = stb.st_size - i;
1157 if (sizerr == 0 && read(sfd, buf, amt) != amt)
1159 if (write(pfd, buf, amt) != amt) {
1166 syslog(LOG_INFO, "%s: %s: changed size", pp->printer, file);
1167 /* tell recvjob to ignore this file */
1168 (void) write(pfd, "\1", 1);
1172 if (write(pfd, "", 1) != 1 || response(pp)) {
1177 trstat_write(pp, TR_SENDING, stb.st_size, logname,
1178 pp->remote_host, origin_host);
1180 * Usually we only need to send one copy of a datafile,
1181 * because the control-file will simply print the same
1182 * file multiple times. However, some printers ignore
1183 * the control file, and simply print each data file as
1184 * it arrives. For such "remote hosts", we need to
1185 * transfer the same data file multiple times. Such a
1186 * a host is indicated by adding 'rc' to the printcap
1188 * XXX - Right now this ONLY works for remote hosts which
1189 * do ignore the name of the data file, because
1190 * this sends the file multiple times with slight
1191 * changes to the filename. To do this right would
1192 * require that we also rewrite the control file
1193 * to match those filenames.
1195 if (pp->resend_copies && (copycnt < copyreq)) {
1196 lseek(sfd, 0, SEEK_SET);
1206 * If tfd is set, then it is the same value as sfd, and
1207 * therefore it is already closed at this point. All
1208 * we need to do is remove the temporary file.
1217 * This routine is called to execute one of the filters as was
1218 * specified in a printcap entry. While the child-process will read
1219 * all of 'infd', it is up to the caller to close that file descriptor
1220 * in the parent process.
1223 execfilter(struct printer *pp, char *f_cmd, char *f_av[], int infd, int outfd)
1226 int errfd, retcode, wstatus;
1228 char buf[BUFSIZ], *slash;
1230 fpid = dofork(pp, DORETURN);
1233 * This is the parent process, which just waits for the child
1234 * to complete and then returns the result. Note that it is
1235 * the child process which reads the input stream.
1240 while ((wpid = wait(&wstatus)) > 0 &&
1246 "%s: after execv(%s), wait() returned: %m",
1247 pp->printer, f_cmd);
1249 retcode = WEXITSTATUS(wstatus);
1253 * Copy everything the filter wrote to stderr from our
1254 * temporary errors file to the "lf=" logfile.
1256 errfp = fopen(tempstderr, "r");
1258 while (fgets(buf, sizeof(buf), errfp))
1267 * This is the child process, which is the one that executes the
1271 * If the first parameter has any slashes in it, then change it
1272 * to point to the first character after the last slash.
1274 slash = strrchr(f_av[0], '/');
1276 f_av[0] = slash + 1;
1278 * XXX - in the future, this should setup an explicit list of
1279 * environment variables and use execve()!
1283 * Setup stdin, stdout, and stderr as we want them when the filter
1284 * is running. Stderr is setup so it points to a temporary errors
1285 * file, and the parent process will copy that temporary file to
1286 * the real logfile after the filter completes.
1290 errfd = open(tempstderr, O_WRONLY|O_TRUNC, 0664);
1296 syslog(LOG_ERR, "%s: cannot execv(%s): %m", pp->printer, f_cmd);
1302 * Check to make sure there have been no errors and that both programs
1303 * are in sync with eachother.
1304 * Return non-zero if the connection was lost.
1307 response(const struct printer *pp)
1311 if (read(pfd, &resp, 1) != 1) {
1312 syslog(LOG_INFO, "%s: lost connection", pp->printer);
1319 * Banner printing stuff
1322 banner(struct printer *pp, char *name1, char *name2)
1327 if (!pp->no_formfeed && !pp->tof)
1328 (void) write(ofd, pp->form_feed, strlen(pp->form_feed));
1329 if (pp->short_banner) { /* short banner only */
1331 (void) write(ofd, class, strlen(class));
1332 (void) write(ofd, ":", 1);
1334 (void) write(ofd, name1, strlen(name1));
1335 (void) write(ofd, " Job: ", 7);
1336 (void) write(ofd, name2, strlen(name2));
1337 (void) write(ofd, " Date: ", 8);
1338 (void) write(ofd, ctime(&tvec), 24);
1339 (void) write(ofd, "\n", 1);
1340 } else { /* normal banner */
1341 (void) write(ofd, "\n\n\n", 3);
1342 scan_out(pp, ofd, name1, '\0');
1343 (void) write(ofd, "\n\n", 2);
1344 scan_out(pp, ofd, name2, '\0');
1346 (void) write(ofd,"\n\n\n",3);
1347 scan_out(pp, ofd, class, '\0');
1349 (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15);
1350 (void) write(ofd, name2, strlen(name2));
1351 (void) write(ofd, "\n\t\t\t\t\tDate: ", 12);
1352 (void) write(ofd, ctime(&tvec), 24);
1353 (void) write(ofd, "\n", 1);
1355 if (!pp->no_formfeed)
1356 (void) write(ofd, pp->form_feed, strlen(pp->form_feed));
1361 scnline(int key, char *p, int c)
1363 register int scnwidth;
1365 for (scnwidth = WIDTH; --scnwidth;) {
1367 *p++ = key & 0200 ? c : BACKGND;
1372 #define TRC(q) (((q)-' ')&0177)
1375 scan_out(struct printer *pp, int scfd, char *scsp, int dlm)
1377 register char *strp;
1378 register int nchrs, j;
1379 char outbuf[LINELEN+1], *sp, c, cc;
1382 for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) {
1385 for (nchrs = 0; ; ) {
1386 d = dropit(c = TRC(cc = *sp++));
1387 if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d))
1388 for (j = WIDTH; --j;)
1391 strp = scnline(scnkey[(int)c][scnhgt-1-d], strp, cc);
1392 if (*sp == dlm || *sp == '\0' ||
1393 nchrs++ >= pp->page_width/(WIDTH+1)-1)
1398 while (*--strp == BACKGND && strp >= outbuf)
1402 (void) write(scfd, outbuf, strp-outbuf);
1428 * tell people about job completion
1431 sendmail(struct printer *pp, char *userid, int bombed)
1435 register const char *cp;
1440 if ((s = dofork(pp, DORETURN)) == 0) { /* child */
1444 if ((cp = strrchr(_PATH_SENDMAIL, '/')) != NULL)
1447 cp = _PATH_SENDMAIL;
1448 execl(_PATH_SENDMAIL, cp, "-t", (char *)0);
1450 } else if (s > 0) { /* parent */
1452 printf("To: %s@%s\n", userid, origin_host);
1453 printf("Subject: %s printer job \"%s\"\n", pp->printer,
1454 *jobname ? jobname : "<unknown>");
1455 printf("Reply-To: root@%s\n\n", local_host);
1456 printf("Your printer job ");
1458 printf("(%s) ", jobname);
1463 printf("\ncompleted successfully\n");
1468 printf("\ncould not be printed\n");
1472 printf("\ncould not be printed without an account on %s\n",
1477 if (stat(tempstderr, &stb) < 0 || stb.st_size == 0
1478 || (fp = fopen(tempstderr, "r")) == NULL) {
1479 printf("\nhad some errors and may not have printed\n");
1482 printf("\nhad the following errors and may not have printed:\n");
1483 while ((i = getc(fp)) != EOF)
1489 printf("\nwas not printed because it was not linked to the original file\n");
1494 syslog(LOG_WARNING, "unable to send mail to %s: %m", userid);
1500 syslog(LOG_INFO, "mail sent to user %s about job %s on printer %s (%s)",
1501 userid, *jobname ? jobname : "<unknown>", pp->printer, cp);
1505 * dofork - fork with retries on failure
1508 dofork(const struct printer *pp, int action)
1515 if (daemon_uname == NULL) {
1516 pwd = getpwuid(pp->daemon_user);
1518 syslog(LOG_ERR, "%s: Can't lookup default daemon uid (%ld) in password file",
1519 pp->printer, pp->daemon_user);
1522 daemon_uname = strdup(pwd->pw_name);
1523 daemon_defgid = pwd->pw_gid;
1526 for (i = 0; i < 20; i++) {
1529 sleep((unsigned)(i*i));
1533 * Child should run as daemon instead of root
1537 fail = initgroups(daemon_uname, daemon_defgid);
1539 syslog(LOG_ERR, "%s: initgroups(%s,%u): %m",
1540 pp->printer, daemon_uname, daemon_defgid);
1543 fail = setgid(daemon_defgid);
1545 syslog(LOG_ERR, "%s: setgid(%u): %m",
1546 pp->printer, daemon_defgid);
1549 fail = setuid(pp->daemon_user);
1551 syslog(LOG_ERR, "%s: setuid(%ld): %m",
1552 pp->printer, pp->daemon_user);
1560 * An error occurred. If the error is in the child process, then
1561 * this routine MUST always exit(). DORETURN only effects how
1562 * errors should be handled in the parent process.
1566 syslog(LOG_ERR, "%s: dofork(): aborting child process...",
1570 syslog(LOG_ERR, "%s: dofork(): failure in fork", pp->printer);
1572 sleep(1); /* throttle errors, as a safety measure */
1577 syslog(LOG_ERR, "bad action (%d) to dofork", action);
1586 * Kill child processes to abort current job.
1589 abortpr(int signo __unused)
1592 (void) unlink(tempstderr);
1595 kill(of_pid, SIGCONT);
1596 while (wait(NULL) > 0)
1598 if (of_pid > 0 && tfd != -1)
1604 init(struct printer *pp)
1608 sprintf(&width[2], "%ld", pp->page_width);
1609 sprintf(&length[2], "%ld", pp->page_length);
1610 sprintf(&pxwidth[2], "%ld", pp->page_pwidth);
1611 sprintf(&pxlength[2], "%ld", pp->page_plength);
1612 if ((s = checkremote(pp)) != 0) {
1613 syslog(LOG_WARNING, "%s", s);
1619 startprinting(const char *printer)
1621 struct printer myprinter, *pp = &myprinter;
1625 status = getprintcap(printer, pp);
1628 syslog(LOG_ERR, "can't open printer description file: %m");
1630 case PCAPERR_NOTFOUND:
1631 syslog(LOG_ERR, "unknown printer: %s", printer);
1633 case PCAPERR_TCLOOP:
1634 fatal(pp, "potential reference loop detected in printcap file");
1642 * Acquire line printer or remote connection.
1645 openpr(const struct printer *pp)
1653 * Lpd does support the setting of 'of=' filters for
1654 * jobs going to remote machines, but that does not
1655 * have the same meaning as 'of=' does when handling
1656 * local print queues. For remote machines, all 'of='
1657 * filter processing is handled in sendfile(), and that
1658 * does not use these global "output filter" variables.
1663 } else if (*pp->lp) {
1664 if ((cp = strchr(pp->lp, '@')) != NULL)
1669 syslog(LOG_ERR, "%s: no line printer device or host name",
1675 * Start up an output filter, if needed.
1677 if (pp->filters[LPF_OUTPUT] && !pp->filters[LPF_INPUT] && !of_pid) {
1680 strcpy(tfile, TFILENAME);
1681 tfd = mkstemp(tfile);
1683 if ((of_pid = dofork(pp, DOABORT)) == 0) { /* child */
1684 dup2(p[0], 0); /* pipe is std in */
1685 /* tfile/printer is stdout */
1686 dup2(pp->remote ? tfd : pfd, 1);
1689 if ((cp = strrchr(pp->filters[LPF_OUTPUT], '/')) == NULL)
1690 cp = pp->filters[LPF_OUTPUT];
1693 execl(pp->filters[LPF_OUTPUT], cp, width, length,
1695 syslog(LOG_ERR, "%s: execl(%s): %m", pp->printer,
1696 pp->filters[LPF_OUTPUT]);
1699 (void) close(p[0]); /* close input side */
1700 ofd = p[1]; /* use pipe for output */
1708 * Printer connected directly to the network
1709 * or to a terminal server on the net
1712 opennet(const struct printer *pp)
1718 void (*savealrm)(int);
1720 port = strtoul(pp->lp, &ep, 0);
1721 if (*ep != '@' || port > 65535) {
1722 syslog(LOG_ERR, "%s: bad port number: %s", pp->printer,
1728 for (i = 1; ; i = i < 256 ? i << 1 : i) {
1730 savealrm = signal(SIGALRM, alarmhandler);
1731 alarm(pp->conn_timeout);
1732 pfd = getport(pp, ep, port);
1734 (void)signal(SIGALRM, savealrm);
1735 if (pfd < 0 && errno == ECONNREFUSED)
1737 else if (pfd >= 0) {
1739 * need to delay a bit for rs232 lines
1740 * to stabilize in case printer is
1741 * connected via a terminal server
1748 pstatus(pp, "waiting for %s to come up",
1752 "waiting for access to printer on %s",
1757 pstatus(pp, "sending to %s port %lu", ep, port);
1761 * Printer is connected to an RS232 port on this host
1764 opentty(const struct printer *pp)
1768 for (i = 1; ; i = i < 32 ? i << 1 : i) {
1769 pfd = open(pp->lp, pp->rw ? O_RDWR : O_WRONLY);
1774 if (errno == ENOENT) {
1775 syslog(LOG_ERR, "%s: %m", pp->lp);
1780 "waiting for %s to become ready (offline?)",
1786 pstatus(pp, "%s is ready and printing", pp->printer);
1790 * Printer is on a remote host
1793 openrem(const struct printer *pp)
1797 void (*savealrm)(int);
1799 for (i = 1; ; i = i < 256 ? i << 1 : i) {
1801 savealrm = signal(SIGALRM, alarmhandler);
1802 alarm(pp->conn_timeout);
1803 pfd = getport(pp, pp->remote_host, 0);
1805 (void)signal(SIGALRM, savealrm);
1807 if ((writel(pfd, "\2", pp->remote_queue, "\n",
1809 == 2 + strlen(pp->remote_queue))
1810 && (resp = response(pp)) == 0)
1816 pstatus(pp, "waiting for %s to come up",
1820 "waiting for queue to be enabled on %s",
1827 pstatus(pp, "sending to %s", pp->remote_host);
1834 setty(const struct printer *pp)
1836 struct termios ttybuf;
1838 if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) {
1839 syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", pp->printer);
1842 if (tcgetattr(pfd, &ttybuf) < 0) {
1843 syslog(LOG_ERR, "%s: tcgetattr: %m", pp->printer);
1846 if (pp->baud_rate > 0)
1847 cfsetspeed(&ttybuf, pp->baud_rate);
1849 char *s = strdup(pp->mode_set), *tmp;
1851 while ((tmp = strsep(&s, ",")) != NULL) {
1852 (void) msearch(tmp, &ttybuf);
1855 if (pp->mode_set != 0 || pp->baud_rate > 0) {
1856 if (tcsetattr(pfd, TCSAFLUSH, &ttybuf) == -1) {
1857 syslog(LOG_ERR, "%s: tcsetattr: %m", pp->printer);
1865 pstatus(const struct printer *pp, const char *msg, ...)
1873 fd = open(pp->status_file, O_WRONLY|O_CREAT|O_EXLOCK, STAT_FILE_MODE);
1875 syslog(LOG_ERR, "%s: open(%s): %m", pp->printer,
1880 vasprintf(&buf, msg, ap);
1882 writel(fd, buf, "\n", (char *)0);
1888 alarmhandler(int signo __unused)
1890 /* the signal is ignored */
1891 /* (the '__unused' is just to avoid a compile-time warning) */