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[] =
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 /* absorb fork error */
81 #define DOABORT 1 /* abort if dofork 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 int child; /* id of any filters */
98 static int lfd; /* lock file descriptor */
99 static int ofd; /* output filter file descriptor */
100 static int ofilter; /* id of output filter, if any */
101 static int tfd = -1; /* output filter temp file output */
102 static int pfd; /* prstatic inter file descriptor */
103 static int pid; /* pid of lpd process */
104 static int prchild; /* id of pr process */
105 static char title[80]; /* ``pr'' title */
107 static char class[32]; /* classification field */
108 static char fromhost[32]; /* user's host machine */
109 /* indentation size in static characters */
110 static char indent[10] = "-i0";
111 static char jobname[100]; /* job or file name */
112 static char length[10] = "-l"; /* page length in lines */
113 static char logname[32]; /* user's login name */
114 static char pxlength[10] = "-y"; /* page length in pixels */
115 static char pxwidth[10] = "-x"; /* page width in pixels */
116 static char tempfile[] = "errsXXXXXX"; /* file name for filter errors */
117 static char width[10] = "-w"; /* page width in static characters */
118 #define TFILENAME "fltXXXXXX"
119 static char tfile[] = TFILENAME; /* file name for filter output */
121 static void abortpr __P((int));
122 static void alarmhandler __P((int));
123 static void banner __P((struct printer *pp, char *name1, char *name2));
124 static int dofork __P((const struct printer *pp, int action));
125 static int dropit __P((int));
126 static void init __P((struct printer *pp));
127 static void openpr __P((const struct printer *pp));
128 static void opennet __P((const struct printer *pp));
129 static void opentty __P((const struct printer *pp));
130 static void openrem __P((const struct printer *pp));
131 static int print __P((struct printer *pp, int format, char *file));
132 static int printit __P((struct printer *pp, char *file));
133 static void pstatus __P((const struct printer *, const char *, ...));
134 static char response __P((const struct printer *pp));
135 static void scan_out __P((struct printer *pp, int scfd, char *scsp,
137 static char *scnline __P((int, char *, int));
138 static int sendfile __P((struct printer *pp, int type, char *file,
140 static int sendit __P((struct printer *pp, char *file));
141 static void sendmail __P((struct printer *pp, char *user, int bombed));
142 static void setty __P((const struct printer *pp));
144 void msearch __P((char *, struct termios *));
151 register struct queue *q, **qp;
152 struct queue **queue;
153 register int i, nitems;
155 int errcnt, count = 0;
157 init(pp); /* set up capabilities */
158 (void) write(1, "", 1); /* ack that daemon is started */
159 (void) close(2); /* set up log file */
160 if (open(pp->log_file, O_WRONLY|O_APPEND, LOG_FILE_MODE) < 0) {
161 syslog(LOG_ERR, "%s: %m", pp->log_file);
162 (void) open(_PATH_DEVNULL, O_WRONLY);
165 pid = getpid(); /* for use with lprm */
167 signal(SIGHUP, abortpr);
168 signal(SIGINT, abortpr);
169 signal(SIGQUIT, abortpr);
170 signal(SIGTERM, abortpr);
172 (void) mktemp(tempfile);
175 * uses short form file names
177 if (chdir(pp->spool_dir) < 0) {
178 syslog(LOG_ERR, "%s: %m", pp->spool_dir);
181 if (stat(pp->lock_file, &stb) == 0 && (stb.st_mode & LFM_PRINT_DIS))
182 exit(0); /* printing disabled */
183 lfd = open(pp->lock_file, O_WRONLY|O_CREAT|O_EXLOCK|O_NONBLOCK,
186 if (errno == EWOULDBLOCK) /* active daemon present */
188 syslog(LOG_ERR, "%s: %s: %m", pp->printer, pp->lock_file);
191 /* turn off non-blocking mode (was turned on for lock effects only) */
192 if (fcntl(lfd, F_SETFL, 0) < 0) {
193 syslog(LOG_ERR, "%s: %s: %m", pp->printer, pp->lock_file);
198 * write process id for others to know
200 sprintf(line, "%u\n", pid);
201 pidoff = i = strlen(line);
202 if (write(lfd, line, i) != i) {
203 syslog(LOG_ERR, "%s: %s: %m", pp->printer, pp->lock_file);
207 * search the spool directory for work and sort by queue order.
209 if ((nitems = getq(pp, &queue)) < 0) {
210 syslog(LOG_ERR, "%s: can't scan %s", pp->printer,
214 if (nitems == 0) /* no work to do */
216 if (stb.st_mode & LFM_RESET_QUE) { /* reset queue flag */
217 if (fchmod(lfd, stb.st_mode & ~LFM_RESET_QUE) < 0)
218 syslog(LOG_ERR, "%s: %s: %m", pp->printer,
221 openpr(pp); /* open printer or remote */
224 * we found something to do now do it --
225 * write the name of the current control file into the lock file
226 * so the spool queue program can tell what we're working on
228 for (qp = queue; nitems--; free((char *) q)) {
230 if (stat(q->q_name, &stb) < 0)
234 (void) lseek(lfd, pidoff, 0);
235 (void) snprintf(line, sizeof(line), "%s\n", q->q_name);
237 if (write(lfd, line, i) != i)
238 syslog(LOG_ERR, "%s: %s: %m", pp->printer,
241 i = printit(pp, q->q_name);
243 i = sendit(pp, q->q_name);
245 * Check to see if we are supposed to stop printing or
246 * if we are to rebuild the queue.
248 if (fstat(lfd, &stb) == 0) {
249 /* stop printing before starting next job? */
250 if (stb.st_mode & LFM_PRINT_DIS)
252 /* rebuild queue (after lpc topq) */
253 if (stb.st_mode & LFM_RESET_QUE) {
254 for (free(q); nitems--; free(q))
256 if (fchmod(lfd, stb.st_mode & ~LFM_RESET_QUE)
258 syslog(LOG_WARNING, "%s: %s: %m",
259 pp->printer, pp->lock_file);
263 if (i == OK) /* file ok and printed */
265 else if (i == REPRINT && ++errcnt < 5) {
266 /* try reprinting the job */
267 syslog(LOG_INFO, "restarting %s", pp->printer);
269 kill(ofilter, SIGCONT); /* to be sure */
271 while ((i = wait(NULL)) > 0 && i != ofilter)
275 (void) close(pfd); /* close printer */
276 if (ftruncate(lfd, pidoff) < 0)
277 syslog(LOG_WARNING, "%s: %s: %m",
278 pp->printer, pp->lock_file);
279 openpr(pp); /* try to reopen printer */
282 syslog(LOG_WARNING, "%s: job could not be %s (%s)",
284 pp->remote ? "sent to remote host" : "printed",
287 /* ensure we don't attempt this job again */
288 (void) unlink(q->q_name);
290 (void) unlink(q->q_name);
292 sendmail(pp, logname, FATALERR);
298 * search the spool directory for more work.
300 if ((nitems = getq(pp, &queue)) < 0) {
301 syslog(LOG_ERR, "%s: can't scan %s", pp->printer,
305 if (nitems == 0) { /* no more work to do */
307 if (count > 0) { /* Files actually printed */
308 if (!pp->no_formfeed && !pp->tof)
309 (void) write(ofd, pp->form_feed,
310 strlen(pp->form_feed));
311 if (pp->trailer != NULL) /* output trailer */
312 (void) write(ofd, pp->trailer,
313 strlen(pp->trailer));
317 (void) unlink(tempfile);
323 char fonts[4][50]; /* fonts for troff */
325 char ifonts[4][40] = {
333 * The remaining part is the reading of the control file (cf)
334 * and performing the various actions.
346 * open control file; ignore if no longer there.
348 if ((cfp = fopen(file, "r")) == NULL) {
349 syslog(LOG_INFO, "%s: %s: %m", pp->printer, file);
355 for (i = 0; i < 4; i++)
356 strcpy(fonts[i], ifonts[i]);
357 sprintf(&width[2], "%ld", pp->page_width);
358 strcpy(indent+2, "0");
361 * read the control file for work to do
363 * file format -- first character in the line is a command
364 * rest of the line is the argument.
365 * valid commands are:
367 * S -- "stat info" for symbolic link protection
368 * J -- "job name" on banner page
369 * C -- "class name" on banner page
370 * L -- "literal" user's name to print on banner
371 * T -- "title" for pr
372 * H -- "host name" of machine where lpr was done
373 * P -- "person" user's login name
374 * I -- "indent" amount to indent output
375 * R -- laser dpi "resolution"
376 * f -- "file name" name of text file to print
377 * l -- "file name" text file with control chars
378 * p -- "file name" text file to print with pr(1)
379 * t -- "file name" troff(1) file to print
380 * n -- "file name" ditroff(1) file to print
381 * d -- "file name" dvi file to print
382 * g -- "file name" plot(1G) file to print
383 * v -- "file name" plain raster file to print
384 * c -- "file name" cifplot file to print
385 * 1 -- "R font file" for troff
386 * 2 -- "I font file" for troff
387 * 3 -- "B font file" for troff
388 * 4 -- "S font file" for troff
389 * N -- "name" of file (used by lpq)
390 * U -- "unlink" name of file to remove
391 * (after we print it. (Pass 2 only)).
392 * M -- "mail" to user when done printing
394 * getline reads a line and expands tabs to blanks
402 strncpy(fromhost, line+1, sizeof(fromhost) - 1);
403 fromhost[sizeof(fromhost) - 1] = '\0';
404 if (class[0] == '\0') {
405 strncpy(class, line+1, sizeof(class) - 1);
406 class[sizeof(class) - 1] = '\0';
411 strncpy(logname, line+1, sizeof(logname) - 1);
412 logname[sizeof(logname) - 1] = '\0';
413 if (pp->restricted) { /* restricted */
414 if (getpwnam(logname) == NULL) {
416 sendmail(pp, line+1, bombed);
425 while (*cp >= '0' && *cp <= '9')
426 i = i * 10 + (*cp++ - '0');
430 while (*cp >= '0' && *cp <= '9')
431 i = i * 10 + (*cp++ - '0');
436 if (line[1] != '\0') {
437 strncpy(jobname, line+1, sizeof(jobname) - 1);
438 jobname[sizeof(jobname) - 1] = '\0';
440 strcpy(jobname, " ");
445 strncpy(class, line+1, sizeof(class) - 1);
446 else if (class[0] == '\0')
447 gethostname(class, sizeof(class));
448 class[sizeof(class) - 1] = '\0';
451 case 'T': /* header title for pr */
452 strncpy(title, line+1, sizeof(title) - 1);
453 title[sizeof(title) - 1] = '\0';
456 case 'L': /* identification line */
457 if (!pp->no_header && !pp->header_last)
458 banner(pp, line+1, jobname);
461 case '1': /* troff fonts */
465 if (line[1] != '\0') {
466 strncpy(fonts[line[0]-'1'], line+1,
468 fonts[line[0]-'1'][50-1] = '\0';
472 case 'W': /* page width */
473 strncpy(width+2, line+1, sizeof(width) - 3);
474 width[2+sizeof(width) - 3] = '\0';
477 case 'I': /* indent amount */
478 strncpy(indent+2, line+1, sizeof(indent) - 3);
479 indent[2+sizeof(indent) - 3] = '\0';
482 default: /* some file to print */
483 switch (i = print(pp, line[0], line+1)) {
494 sendmail(pp, logname, bombed);
512 case 'L': /* identification line */
513 if (!pp->no_header && pp->header_last)
514 banner(pp, line+1, jobname);
518 if (bombed < NOACCT) /* already sent if >= NOACCT */
519 sendmail(pp, line+1, bombed);
523 if (strchr(line+1, '/'))
525 (void) unlink(line+1);
528 * clean-up in case another control file exists
532 return(bombed == OK ? OK : ERROR);
537 * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}.
538 * Return -1 if a non-recoverable error occured,
539 * 2 if the filter detected some errors (but printed the job anyway),
540 * 1 if we should try to reprint this job and
542 * Note: all filters take stdin as the file, stdout as the printer,
543 * stderr as the log file, and must not ignore SIGINT.
546 print(pp, format, file)
555 char *av[15], buf[BUFSIZ];
556 int pid, p[2], stopped = 0;
560 if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0)
563 * Check to see if data file is a symbolic link. If so, it should
564 * still point to the same file or someone is trying to print
565 * something he shouldn't.
567 if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 &&
568 (stb.st_dev != fdev || stb.st_ino != fino))
570 if (!pp->no_formfeed && !pp->tof) { /* start on a fresh page */
571 (void) write(ofd, pp->form_feed, strlen(pp->form_feed));
574 if (pp->filters[LPF_INPUT] == NULL
575 && (format == 'f' || format == 'l')) {
577 while ((n = read(fi, buf, BUFSIZ)) > 0)
578 if (write(ofd, buf, n) != n) {
586 case 'p': /* print file using 'pr' */
587 if (pp->filters[LPF_INPUT] == NULL) { /* use output filter */
593 av[4] = *title ? title : " ";
600 if ((prchild = dofork(pp, DORETURN)) == 0) { /* child */
601 dup2(fi, 0); /* file is stdin */
602 dup2(p[1], 1); /* pipe is stdout */
605 execl(_PATH_PR, "pr", width, length,
606 "-h", *title ? title : " ", "-F", 0);
607 syslog(LOG_ERR, "cannot execl %s", _PATH_PR);
610 (void) close(p[1]); /* close output side */
617 fi = p[0]; /* use pipe for input */
618 case 'f': /* print plain text file */
619 prog = pp->filters[LPF_INPUT];
625 case 'l': /* like 'f' but pass control characters */
626 prog = pp->filters[LPF_INPUT];
633 case 'r': /* print a fortran text file */
634 prog = pp->filters[LPF_FORTRAN];
639 case 't': /* print troff output */
640 case 'n': /* print ditroff output */
641 case 'd': /* print tex output */
642 (void) unlink(".railmag");
643 if ((fo = creat(".railmag", FILMOD)) < 0) {
644 syslog(LOG_ERR, "%s: cannot create .railmag",
646 (void) unlink(".railmag");
648 for (n = 0; n < 4; n++) {
649 if (fonts[n][0] != '/')
650 (void) write(fo, _PATH_VFONT,
651 sizeof(_PATH_VFONT) - 1);
652 (void) write(fo, fonts[n], strlen(fonts[n]));
653 (void) write(fo, "\n", 1);
657 prog = (format == 't') ? pp->filters[LPF_TROFF]
658 : ((format == 'n') ? pp->filters[LPF_DITROFF]
659 : pp->filters[LPF_DVI]);
664 case 'c': /* print cifplot output */
665 prog = pp->filters[LPF_CIFPLOT];
670 case 'g': /* print plot(1G) output */
671 prog = pp->filters[LPF_GRAPH];
676 case 'v': /* print raster output */
677 prog = pp->filters[LPF_RASTER];
684 syslog(LOG_ERR, "%s: illegal format character '%c'",
685 pp->printer, format);
691 "%s: no filter found in printcap for format character '%c'",
692 pp->printer, format);
695 if ((av[0] = strrchr(prog, '/')) != NULL)
703 av[n++] = pp->acct_file;
706 if (ofilter > 0) { /* stop output filter */
707 write(ofd, "\031\1", 2);
709 wait3((int *)&status, WUNTRACED, 0)) > 0 && pid != ofilter)
711 if (status.w_stopval != WSTOPPED) {
714 "%s: output filter died "
715 "(retcode=%d termsig=%d)",
716 pp->printer, status.w_retcode,
723 if ((child = dofork(pp, DORETURN)) == 0) { /* child */
726 n = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, 0664);
732 syslog(LOG_ERR, "cannot execv %s", prog);
737 status.w_retcode = 100;
739 while ((pid = wait((int *)&status)) > 0 && pid != child)
743 if (stopped) { /* restart output filter */
744 if (kill(ofilter, SIGCONT) < 0) {
745 syslog(LOG_ERR, "cannot restart output filter");
751 /* Copy filter output to "lf" logfile */
752 if ((fp = fopen(tempfile, "r"))) {
753 while (fgets(buf, sizeof(buf), fp))
758 if (!WIFEXITED(status)) {
759 syslog(LOG_WARNING, "%s: filter '%c' terminated (termsig=%d)",
760 pp->printer, format, status.w_termsig);
763 switch (status.w_retcode) {
772 syslog(LOG_WARNING, "%s: filter '%c' exited (retcode=%d)",
773 pp->printer, format, status.w_retcode);
779 * Send the daemon control file (cf) and any data files.
780 * Return -1 if a non-recoverable error occured, 1 if a recoverable error and
788 register int i, err = OK;
789 char *cp, last[BUFSIZ];
794 if ((cfp = fopen(file, "r")) == NULL)
797 * read the control file for work to do
799 * file format -- first character in the line is a command
800 * rest of the line is the argument.
801 * commands of interest are:
803 * a-z -- "file name" name of file to print
804 * U -- "unlink" name of file to remove
805 * (after we print it. (Pass 2 only)).
811 while (getline(cfp)) {
813 if (line[0] == 'S') {
816 while (*cp >= '0' && *cp <= '9')
817 i = i * 10 + (*cp++ - '0');
821 while (*cp >= '0' && *cp <= '9')
822 i = i * 10 + (*cp++ - '0');
824 } else if (line[0] == 'H') {
825 strcpy(fromhost, line+1);
826 if (class[0] == '\0')
827 strncpy(class, line+1, sizeof(class) - 1);
828 } else if (line[0] == 'P') {
829 strncpy(logname, line+1, sizeof(logname) - 1);
830 if (pp->restricted) { /* restricted */
831 if (getpwnam(logname) == NULL) {
832 sendmail(pp, line+1, NOACCT);
837 } else if (line[0] == 'I') {
838 strncpy(indent+2, line+1, sizeof(indent) - 3);
839 } else if (line[0] >= 'a' && line[0] <= 'z') {
841 while ((i = getline(cfp)) != 0)
842 if (strcmp(last, line))
844 switch (sendfile(pp, '\3', last+1, *last)) {
853 sendmail(pp, logname, ACCESS);
860 if (err == OK && sendfile(pp, '\2', file, '\0') > 0) {
869 if (line[0] == 'U' && !strchr(line+1, '/'))
870 (void) unlink(line+1);
872 * clean-up in case another control file exists
880 * Send a data file to the remote machine and spool it.
881 * Return positive if we should try resending.
884 sendfile(pp, type, file, format)
890 register int f, i, amt;
893 int sizerr, resp, closedpr;
895 if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0)
898 * Check to see if data file is a symbolic link. If so, it should
899 * still point to the same file or someone is trying to print something
902 if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 &&
903 (stb.st_dev != fdev || stb.st_ino != fino))
909 if (pp->filters[LPF_INPUT]) {
911 * We're sending something with an ifilter, we have to
912 * run the ifilter and store the output as a
913 * temporary file (tfile)... the protocol requires us
914 * to send the file size
919 union wait status; /* XXX */
921 strcpy(tfile,TFILENAME);
922 if ((tfd = mkstemp(tfile)) == -1) {
923 syslog(LOG_ERR, "mkstemp: %m");
926 if ((av[0] = strrchr(pp->filters[LPF_INPUT], '/')) == NULL)
927 av[0] = pp->filters[LPF_INPUT];
941 av[++n] = pp->acct_file;
943 if ((ifilter = dofork(pp, DORETURN)) == 0) { /* child */
946 n = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC,
952 execv(pp->filters[LPF_INPUT], av);
953 syslog(LOG_ERR, "cannot execv %s",
954 pp->filters[LPF_INPUT]);
959 status.w_retcode = 100;
961 while ((pid = wait((int *)&status)) > 0 &&
964 switch (status.w_retcode) {
974 syslog(LOG_WARNING, "%s: filter '%c' exited"
976 pp->printer, format, status.w_retcode);
980 if (fstat(tfd, &stb) < 0) /* the size of tfile */
984 } else if (ofilter) {
986 * We're sending something with an ofilter, we have to
987 * store the output as a temporary file (tfile)... the
988 * protocol requires us to send the file size
991 for (i = 0; i < stb.st_size; i += BUFSIZ) {
993 if (i + amt > stb.st_size)
994 amt = stb.st_size - i;
995 if (sizerr == 0 && read(f, buf, amt) != amt) {
999 if (write(ofd, buf, amt) != amt) {
1006 while ((i = wait(NULL)) > 0 && i != ofilter)
1009 if (fstat(tfd, &stb) < 0) { /* the size of tfile */
1014 lseek(f,0,SEEK_SET);
1019 (void) sprintf(buf, "%c%qd %s\n", type, stb.st_size, file);
1021 for (i = 0; ; i++) {
1022 if (write(pfd, buf, amt) != amt ||
1023 (resp = response(pp)) < 0 || resp == '\1') {
1025 if (tfd != -1 && type == '\3') {
1032 } else if (resp == '\0')
1036 "no space on remote; waiting for queue to drain");
1038 syslog(LOG_ALERT, "%s: can't send to %s; queue full",
1039 pp->printer, pp->remote_host);
1043 pstatus(pp, "sending to %s", pp->remote_host);
1044 for (i = 0; i < stb.st_size; i += BUFSIZ) {
1046 if (i + amt > stb.st_size)
1047 amt = stb.st_size - i;
1048 if (sizerr == 0 && read(f, buf, amt) != amt)
1050 if (write(pfd, buf, amt) != amt) {
1052 if (tfd != -1 && type == '\3') {
1063 if (tfd != -1 && type == '\3') {
1068 syslog(LOG_INFO, "%s: %s: changed size", pp->printer, file);
1069 /* tell recvjob to ignore this file */
1070 (void) write(pfd, "\1", 1);
1075 if (write(pfd, "", 1) != 1 || response(pp)) {
1086 * Check to make sure there have been no errors and that both programs
1087 * are in sync with eachother.
1088 * Return non-zero if the connection was lost.
1092 const struct printer *pp;
1096 if (read(pfd, &resp, 1) != 1) {
1097 syslog(LOG_INFO, "%s: lost connection", pp->printer);
1104 * Banner printing stuff
1107 banner(pp, name1, name2)
1109 char *name1, *name2;
1114 if (!pp->no_formfeed && !pp->tof)
1115 (void) write(ofd, pp->form_feed, strlen(pp->form_feed));
1116 if (pp->short_banner) { /* short banner only */
1118 (void) write(ofd, class, strlen(class));
1119 (void) write(ofd, ":", 1);
1121 (void) write(ofd, name1, strlen(name1));
1122 (void) write(ofd, " Job: ", 7);
1123 (void) write(ofd, name2, strlen(name2));
1124 (void) write(ofd, " Date: ", 8);
1125 (void) write(ofd, ctime(&tvec), 24);
1126 (void) write(ofd, "\n", 1);
1127 } else { /* normal banner */
1128 (void) write(ofd, "\n\n\n", 3);
1129 scan_out(pp, ofd, name1, '\0');
1130 (void) write(ofd, "\n\n", 2);
1131 scan_out(pp, ofd, name2, '\0');
1133 (void) write(ofd,"\n\n\n",3);
1134 scan_out(pp, ofd, class, '\0');
1136 (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15);
1137 (void) write(ofd, name2, strlen(name2));
1138 (void) write(ofd, "\n\t\t\t\t\tDate: ", 12);
1139 (void) write(ofd, ctime(&tvec), 24);
1140 (void) write(ofd, "\n", 1);
1142 if (!pp->no_formfeed)
1143 (void) write(ofd, pp->form_feed, strlen(pp->form_feed));
1155 for (scnwidth = WIDTH; --scnwidth;) {
1157 *p++ = key & 0200 ? c : BACKGND;
1162 #define TRC(q) (((q)-' ')&0177)
1165 scan_out(pp, scfd, scsp, dlm)
1170 register char *strp;
1172 char outbuf[LINELEN+1], *sp, c, cc;
1175 for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) {
1178 for (nchrs = 0; ; ) {
1179 d = dropit(c = TRC(cc = *sp++));
1180 if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d))
1181 for (j = WIDTH; --j;)
1184 strp = scnline(scnkey[(int)c][scnhgt-1-d], strp, cc);
1185 if (*sp == dlm || *sp == '\0' ||
1186 nchrs++ >= pp->page_width/(WIDTH+1)-1)
1191 while (*--strp == BACKGND && strp >= outbuf)
1195 (void) write(scfd, outbuf, strp-outbuf);
1222 * tell people about job completion
1225 sendmail(pp, user, bombed)
1237 if ((s = dofork(pp, DORETURN)) == 0) { /* child */
1241 if ((cp = strrchr(_PATH_SENDMAIL, '/')) != NULL)
1244 cp = _PATH_SENDMAIL;
1245 execl(_PATH_SENDMAIL, cp, "-t", 0);
1247 } else if (s > 0) { /* parent */
1249 printf("To: %s@%s\n", user, fromhost);
1250 printf("Subject: %s printer job \"%s\"\n", pp->printer,
1251 *jobname ? jobname : "<unknown>");
1252 printf("Reply-To: root@%s\n\n", host);
1253 printf("Your printer job ");
1255 printf("(%s) ", jobname);
1257 cp = "XXX compiler confusion"; /* XXX shut GCC up */
1260 printf("\ncompleted successfully\n");
1265 printf("\ncould not be printed\n");
1269 printf("\ncould not be printed without an account on %s\n", host);
1273 if (stat(tempfile, &stb) < 0 || stb.st_size == 0 ||
1274 (fp = fopen(tempfile, "r")) == NULL) {
1275 printf("\nhad some errors and may not have printed\n");
1278 printf("\nhad the following errors and may not have printed:\n");
1279 while ((i = getc(fp)) != EOF)
1285 printf("\nwas not printed because it was not linked to the original file\n");
1291 syslog(LOG_WARNING, "unable to send mail to %s: %m", user);
1297 syslog(LOG_INFO, "mail sent to user %s about job %s on printer %s (%s)",
1298 user, *jobname ? jobname : "<unknown>", pp->printer, cp);
1302 * dofork - fork with retries on failure
1306 const struct printer *pp;
1309 register int i, pid;
1311 for (i = 0; i < 20; i++) {
1312 if ((pid = fork()) < 0) {
1313 sleep((unsigned)(i*i));
1317 * Child should run as daemon instead of root
1320 setuid(pp->daemon_user);
1323 syslog(LOG_ERR, "can't fork");
1329 syslog(LOG_ERR, "bad action (%d) to dofork", action);
1338 * Kill child processes to abort current job.
1344 (void) unlink(tempfile);
1347 kill(ofilter, SIGCONT);
1348 while (wait(NULL) > 0)
1350 if (ofilter > 0 && tfd != -1)
1361 sprintf(&width[2], "%ld", pp->page_width);
1362 sprintf(&length[2], "%ld", pp->page_length);
1363 sprintf(&pxwidth[2], "%ld", pp->page_pwidth);
1364 sprintf(&pxlength[2], "%ld", pp->page_plength);
1365 if ((s = checkremote(pp)) != 0) {
1366 syslog(LOG_WARNING, "%s", s);
1372 startprinting(printer)
1373 const char *printer;
1375 struct printer myprinter, *pp = &myprinter;
1379 status = getprintcap(printer, pp);
1382 syslog(LOG_ERR, "can't open printer description file: %m");
1384 case PCAPERR_NOTFOUND:
1385 syslog(LOG_ERR, "unknown printer: %s", printer);
1387 case PCAPERR_TCLOOP:
1388 fatal(pp, "potential reference loop detected in printcap file");
1396 * Acquire line printer or remote connection.
1400 const struct printer *pp;
1407 } else if (*pp->lp) {
1408 if ((cp = strchr(pp->lp, '@')) != NULL)
1413 syslog(LOG_ERR, "%s: no line printer device or host name",
1419 * Start up an output filter, if needed.
1421 if (pp->filters[LPF_OUTPUT] && !pp->filters[LPF_INPUT] && !ofilter) {
1424 strcpy(tfile, TFILENAME);
1425 tfd = mkstemp(tfile);
1427 if ((ofilter = dofork(pp, DOABORT)) == 0) { /* child */
1428 dup2(p[0], 0); /* pipe is std in */
1429 /* tfile/printer is stdout */
1430 dup2(pp->remote ? tfd : pfd, 1);
1433 if ((cp = strrchr(pp->filters[LPF_OUTPUT], '/')) == NULL)
1434 cp = pp->filters[LPF_OUTPUT];
1437 execl(pp->filters[LPF_OUTPUT], cp, width, length, 0);
1438 syslog(LOG_ERR, "%s: %s: %m", pp->printer,
1439 pp->filters[LPF_OUTPUT]);
1442 (void) close(p[0]); /* close input side */
1443 ofd = p[1]; /* use pipe for output */
1451 * Printer connected directly to the network
1452 * or to a terminal server on the net
1456 const struct printer *pp;
1462 void (*savealrm)(int);
1464 port = strtoul(pp->lp, &ep, 0);
1465 if (*ep != ':' || port > 65536) {
1466 syslog(LOG_ERR, "%s: bad port number: %s", pp->printer,
1472 for (i = 1; ; i = i < 256 ? i << 1 : i) {
1474 savealrm = signal(SIGALRM, alarmhandler);
1475 alarm(pp->conn_timeout);
1476 pfd = getport(pp, ep, port);
1478 (void)signal(SIGALRM, savealrm);
1479 if (pfd < 0 && errno == ECONNREFUSED)
1481 else if (pfd >= 0) {
1483 * need to delay a bit for rs232 lines
1484 * to stabilize in case printer is
1485 * connected via a terminal server
1492 pstatus(pp, "waiting for %s to come up",
1496 "waiting for access to printer on %s",
1501 pstatus(pp, "sending to %s port %d", ep, port);
1505 * Printer is connected to an RS232 port on this host
1509 const struct printer *pp;
1513 for (i = 1; ; i = i < 32 ? i << 1 : i) {
1514 pfd = open(pp->lp, pp->rw ? O_RDWR : O_WRONLY);
1519 if (errno == ENOENT) {
1520 syslog(LOG_ERR, "%s: %m", pp->lp);
1525 "waiting for %s to become ready (offline?)",
1531 pstatus(pp, "%s is ready and printing", pp->printer);
1535 * Printer is on a remote host
1539 const struct printer *pp;
1543 void (*savealrm)(int);
1545 for (i = 1; ; i = i < 256 ? i << 1 : i) {
1547 savealrm = signal(SIGALRM, alarmhandler);
1548 alarm(pp->conn_timeout);
1549 pfd = getport(pp, pp->remote_host, 0);
1551 (void)signal(SIGALRM, savealrm);
1553 if ((writel(pfd, "\2", pp->remote_queue, "\n",
1555 == 2 + strlen(pp->remote_queue))
1556 && (resp = response(pp)) == 0)
1562 pstatus(pp, "waiting for %s to come up",
1566 "waiting for queue to be enabled on %s",
1573 pstatus(pp, "sending to %s", pp->remote_host);
1581 const struct printer *pp;
1583 struct termios ttybuf;
1585 if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) {
1586 syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", pp->printer);
1589 if (tcgetattr(pfd, &ttybuf) < 0) {
1590 syslog(LOG_ERR, "%s: tcgetattr: %m", pp->printer);
1593 if (pp->baud_rate > 0)
1594 cfsetspeed(&ttybuf, pp->baud_rate);
1596 char *s = strdup(pp->mode_set), *tmp;
1598 while ((tmp = strsep(&s, ",")) != NULL) {
1599 msearch(tmp, &ttybuf);
1602 if (pp->mode_set != 0 || pp->baud_rate > 0) {
1603 if (tcsetattr(pfd, TCSAFLUSH, &ttybuf) == -1) {
1604 syslog(LOG_ERR, "%s: tcsetattr: %m", pp->printer);
1612 #include <varargs.h>
1617 pstatus(const struct printer *pp, const char *msg, ...)
1619 pstatus(pp, msg, va_alist)
1620 const struct printer *pp;
1635 fd = open(pp->status_file, O_WRONLY|O_CREAT|O_EXLOCK, STAT_FILE_MODE);
1637 syslog(LOG_ERR, "%s: %s: %m", pp->printer, pp->status_file);
1641 vasprintf(&buf, msg, ap);
1643 writel(fd, buf, "\n", (char *)0);