1 /* $NetBSD: printjob.c,v 1.54 2008/07/21 13:36:58 lukem Exp $ */
4 * Copyright (c) 1983, 1993
5 * The Regents of the University of California. All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 #include <sys/cdefs.h>
36 __COPYRIGHT("@(#) Copyright (c) 1983, 1993\
37 The Regents of the University of California. All rights reserved.");
42 static char sccsid
[] = "@(#)printjob.c 8.7 (Berkeley) 5/10/95";
44 __RCSID("$NetBSD: printjob.c,v 1.54 2008/07/21 13:36:58 lukem Exp $");
50 * printjob -- print jobs in the queue.
52 * NOTE: the lock file is used to pass information to lpq and lprm.
53 * it does not need to be removed because file locks are dynamic.
56 #include <sys/param.h>
59 #include <sys/types.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 pfd
; /* printer file descriptor */
102 static int pid
; /* pid of lpd process */
103 static int prchild
; /* id of pr process */
104 static char title
[80]; /* ``pr'' title */
105 static int tof
; /* true if at top of form */
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 output */
117 static char tempremote
[] = "remoteXXXXXX"; /* file name for remote filter */
118 static char width
[10] = "-w"; /* page width in static characters */
120 static void abortpr(int);
121 static void banner(char *, char *);
122 static int dofork(int);
123 static int dropit(int);
124 static void init(void);
125 static void setup_ofilter(int);
126 static void close_ofilter(void);
127 static void openpr(void);
128 static void opennet(void);
129 static void opentty(void);
130 static void openrem(void);
131 static int print(int, char *);
132 static int printit(char *);
133 static void pstatus(const char *, ...)
134 __attribute__((__format__(__printf__
, 1, 2)));
135 static char response(void);
136 static void scan_out(int, char *, int);
137 static char *scnline(int, char *, int);
138 static int sendfile(int, char *);
139 static int sendit(char *);
140 static void sendmail(char *, int);
141 static void setty(void);
142 static void alarmer(int);
148 struct queue
*q
, **qp
;
149 struct queue
**queue
;
152 int errcnt
, count
= 0;
154 init(); /* set up capabilities */
155 (void)write(STDOUT_FILENO
, "", 1); /* ack that daemon is started */
157 /* set up log file */
158 if ((fd
= open(LF
, O_WRONLY
|O_APPEND
, 0664)) < 0) {
159 syslog(LOG_ERR
, "%s: %m", LF
);
160 fd
= open(_PATH_DEVNULL
, O_WRONLY
);
163 (void) dup2(fd
, STDERR_FILENO
);
166 (void)close(STDERR_FILENO
);
169 pid
= getpid(); /* for use with lprm */
171 signal(SIGHUP
, abortpr
);
172 signal(SIGINT
, abortpr
);
173 signal(SIGQUIT
, abortpr
);
174 signal(SIGTERM
, abortpr
);
177 * uses short form file names
180 syslog(LOG_ERR
, "%s: %m", SD
);
183 if (stat(LO
, &stb
) == 0 && (stb
.st_mode
& S_IXUSR
))
184 exit(0); /* printing disabled */
185 lfd
= open(LO
, O_WRONLY
|O_CREAT
, 0644);
187 syslog(LOG_ERR
, "%s: %s: %m", printer
, LO
);
190 if (flock(lfd
, LOCK_EX
|LOCK_NB
) < 0) {
191 if (errno
== EWOULDBLOCK
) /* active daemon present */
193 syslog(LOG_ERR
, "%s: %s: %m", printer
, LO
);
198 * write process id for others to know
200 pidoff
= i
= snprintf(line
, sizeof(line
), "%u\n", pid
);
201 if (write(lfd
, line
, i
) != i
) {
202 syslog(LOG_ERR
, "%s: %s: %m", printer
, LO
);
207 * create the temp filenames.
208 * XXX arguably we should keep the fds open and fdopen(3) dup()s,
209 * XXX but we're in a protected directory so it shouldn't matter.
211 if ((fd
= mkstemp(tempfile
)) != -1) {
213 (void)unlink(tempfile
);
215 if ((fd
= mkstemp(tempremote
)) != -1) {
217 (void)unlink(tempremote
);
221 * search the spool directory for work and sort by queue order.
223 if ((nitems
= getq(&queue
)) < 0) {
224 syslog(LOG_ERR
, "%s: can't scan %s", printer
, SD
);
227 if (nitems
== 0) /* no work to do */
229 if (stb
.st_mode
& S_IXOTH
) { /* reset queue flag */
230 stb
.st_mode
&= ~S_IXOTH
;
231 if (fchmod(lfd
, stb
.st_mode
& 0777) < 0)
232 syslog(LOG_ERR
, "%s: %s: %m", printer
, LO
);
234 openpr(); /* open printer or remote */
237 * we found something to do now do it --
238 * write the name of the current control file into the lock file
239 * so the spool queue program can tell what we're working on
241 for (qp
= queue
; nitems
--; free((char *) q
)) {
243 if (stat(q
->q_name
, &stb
) < 0)
247 (void)lseek(lfd
, pidoff
, 0);
248 i
= snprintf(line
, sizeof(line
), "%s\n", q
->q_name
);
249 if (write(lfd
, line
, i
) != i
)
250 syslog(LOG_ERR
, "%s: %s: %m", printer
, LO
);
252 i
= printit(q
->q_name
);
254 i
= sendit(q
->q_name
);
256 * Check to see if we are supposed to stop printing or
257 * if we are to rebuild the queue.
259 if (fstat(lfd
, &stb
) == 0) {
260 /* stop printing before starting next job? */
261 if (stb
.st_mode
& S_IXUSR
)
263 /* rebuild queue (after lpc topq) */
264 if (stb
.st_mode
& S_IXOTH
) {
265 for (free((char *) q
); nitems
--; free((char *) q
))
267 stb
.st_mode
&= ~S_IXOTH
;
268 if (fchmod(lfd
, stb
.st_mode
& 0777) < 0)
269 syslog(LOG_WARNING
, "%s: %s: %m",
274 if (i
== OK
) /* file ok and printed */
276 else if (i
== REPRINT
&& ++errcnt
< 5) {
277 /* try reprinting the job */
278 syslog(LOG_INFO
, "restarting %s", printer
);
281 (void)close(pfd
); /* close printer */
282 if (ftruncate(lfd
, pidoff
) < 0)
283 syslog(LOG_WARNING
, "%s: %s: %m", printer
, LO
);
284 openpr(); /* try to reopen printer */
287 syslog(LOG_WARNING
, "%s: job could not be %s (%s)", printer
,
288 remote
? "sent to remote host" : "printed", q
->q_name
);
290 /* ensure we don't attempt this job again */
291 (void) unlink(q
->q_name
);
293 (void) unlink(q
->q_name
);
295 sendmail(logname
, FATALERR
);
302 * search the spool directory for more work.
304 if ((nitems
= getq(&queue
)) < 0) {
305 syslog(LOG_ERR
, "%s: can't scan %s", printer
, SD
);
308 if (nitems
== 0) { /* no more work to do */
310 if (count
> 0) { /* Files actually printed */
312 (void)write(ofd
, FF
, strlen(FF
));
313 if (TR
!= NULL
) /* output trailer */
314 (void)write(ofd
, TR
, strlen(TR
));
316 (void)unlink(tempfile
);
317 (void)unlink(tempremote
);
324 char fonts
[4][FONTLEN
]; /* fonts for troff */
326 char ifonts
[4][40] = {
334 * The remaining part is the reading of the control file (cf)
335 * and performing the various actions.
345 * open control file; ignore if no longer there.
347 if ((cfp
= fopen(file
, "r")) == NULL
) {
348 syslog(LOG_INFO
, "%s: %s: %m", printer
, file
);
354 for (i
= 0; i
< 4; i
++)
355 strlcpy(fonts
[i
], ifonts
[i
], sizeof(fonts
[i
]));
356 (void)snprintf(&width
[2], sizeof(width
) - 2, "%ld", PW
);
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 * o -- "file name" postscript file to print
386 * 1 -- "R font file" for troff
387 * 2 -- "I font file" for troff
388 * 3 -- "B font file" for troff
389 * 4 -- "S font file" for troff
390 * N -- "name" of file (used by lpq)
391 * U -- "unlink" name of file to remove
392 * (after we print it. (Pass 2 only)).
393 * M -- "mail" to user when done printing
395 * get_line reads a line and expands tabs to blanks
400 while (get_line(cfp
))
403 strlcpy(fromhost
, line
+1, sizeof(fromhost
));
404 if (class[0] == '\0')
405 strlcpy(class, line
+1, sizeof(class));
409 strlcpy(logname
, line
+1, sizeof(logname
));
410 if (RS
) { /* restricted */
411 if (getpwnam(logname
) == NULL
) {
413 sendmail(line
+1, bombed
);
422 while (*cp
>= '0' && *cp
<= '9')
423 i
= i
* 10 + (*cp
++ - '0');
427 while (*cp
>= '0' && *cp
<= '9')
428 i
= i
* 10 + (*cp
++ - '0');
434 strlcpy(jobname
, line
+1, sizeof(jobname
));
443 strlcpy(class, line
+1, sizeof(class));
444 else if (class[0] == '\0') {
445 gethostname(class, sizeof(class));
446 class[sizeof(class) - 1] = '\0';
450 case 'T': /* header title for pr */
451 strlcpy(title
, line
+1, sizeof(title
));
454 case 'L': /* identification line */
456 banner(line
+1, jobname
);
459 case '1': /* troff fonts */
463 if (line
[1] != '\0') {
464 strlcpy(fonts
[line
[0]-'1'], line
+1,
465 sizeof(fonts
[line
[0]-'1']));
469 case 'W': /* page width */
470 strlcpy(width
+2, line
+1, sizeof(width
) - 2);
473 case 'I': /* indent amount */
474 strlcpy(indent
+2, line
+1, sizeof(indent
) - 2);
477 default: /* some file to print */
478 switch (i
= print(line
[0], line
+1)) {
489 sendmail(logname
, bombed
);
505 while (get_line(cfp
))
507 case 'L': /* identification line */
509 banner(line
+1, jobname
);
513 if (bombed
< NOACCT
) /* already sent if >= NOACCT */
514 sendmail(line
+1, bombed
);
518 if (strchr(line
+1, '/'))
520 (void)unlink(line
+1);
523 * clean-up in case another control file exists
527 return(bombed
== OK
? OK
: ERROR
);
532 * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}.
533 * Return -1 if a non-recoverable error occurred,
534 * 2 if the filter detected some errors (but printed the job anyway),
535 * 1 if we should try to reprint this job and
537 * Note: all filters take stdin as the file, stdout as the printer,
538 * stderr as the log file, and must not ignore SIGINT.
541 print(int format
, char *file
)
546 const char *prog
, *av
[17];
548 int n
, fi
, fo
, child_pid
, p
[2], stopped
= 0, nofile
;
550 if (lstat(file
, &stb
) < 0 || (fi
= open(file
, O_RDONLY
)) < 0)
553 * Check to see if data file is a symbolic link. If so, it should
554 * still point to the same file or someone is trying to print
555 * something he shouldn't.
557 if (S_ISLNK(stb
.st_mode
) && fstat(fi
, &stb
) == 0 &&
558 (stb
.st_dev
!= fdev
|| stb
.st_ino
!= fino
))
560 if (!SF
&& !tof
) { /* start on a fresh page */
561 (void)write(ofd
, FF
, strlen(FF
));
564 if (IF
== NULL
&& (format
== 'f' || format
== 'l')) {
566 while ((n
= read(fi
, buf
, BUFSIZ
)) > 0)
567 if (write(ofd
, buf
, n
) != n
) {
575 case 'p': /* print file using 'pr' */
576 if (IF
== NULL
) { /* use output filter */
582 av
[4] = *title
? title
: " ";
588 if ((prchild
= dofork(DORETURN
)) == 0) { /* child */
589 dup2(fi
, 0); /* file is stdin */
590 dup2(p
[1], 1); /* pipe is stdout */
592 nofile
= sysconf(_SC_OPEN_MAX
);
593 for (n
= 3; n
< nofile
; n
++)
595 execl(_PATH_PR
, "pr", width
, length
,
596 "-h", *title
? title
: " ", NULL
);
597 syslog(LOG_ERR
, "cannot execl %s", _PATH_PR
);
600 (void)close(p
[1]); /* close output side */
607 fi
= p
[0]; /* use pipe for input */
608 case 'f': /* print plain text file */
615 case 'o': /* print a postscript file */
617 /* if PF is not set, handle it like an 'l' */
632 case 'l': /* like 'f' but pass control characters */
640 case 'r': /* print a fortran text file */
646 case 't': /* print troff output */
647 case 'n': /* print ditroff output */
648 case 'd': /* print tex output */
649 (void)unlink(".railmag");
650 if ((fo
= creat(".railmag", FILMOD
)) < 0) {
651 syslog(LOG_ERR
, "%s: cannot create .railmag", printer
);
652 (void)unlink(".railmag");
654 for (n
= 0; n
< 4; n
++) {
655 if (fonts
[n
][0] != '/')
656 (void)write(fo
, _PATH_VFONT
,
657 sizeof(_PATH_VFONT
) - 1);
658 (void)write(fo
, fonts
[n
], strlen(fonts
[n
]));
659 (void)write(fo
, "\n", 1);
663 prog
= (format
== 't') ? TF
: (format
== 'n') ? NF
: DF
;
668 case 'c': /* print cifplot output */
674 case 'g': /* print plot(1G) output */
680 case 'v': /* print raster output */
688 syslog(LOG_ERR
, "%s: illegal format character '%c'",
695 "%s: no filter found in printcap for format character '%c'",
699 if ((av
[0] = strrchr(prog
, '/')) != NULL
)
705 if (*jobname
!= '\0' && strcmp(jobname
, " ") != 0) {
714 if (ofilter
> 0) { /* stop output filter */
715 write(ofd
, "\031\1", 2);
717 wait3(&status
, WUNTRACED
, 0)) > 0 && child_pid
!= ofilter
)
719 if (WIFSTOPPED(status
) == 0) {
722 "%s: output filter died (retcode=%d termsig=%d)",
723 printer
, WEXITSTATUS(status
), WTERMSIG(status
));
729 if ((child
= dofork(DORETURN
)) == 0) { /* child */
733 n
= open(tempfile
, O_WRONLY
|O_CREAT
|O_TRUNC
|O_EXCL
, 0664);
737 nofile
= sysconf(_SC_OPEN_MAX
);
738 for (n
= 3; n
< nofile
; n
++)
740 execv(prog
, __UNCONST(av
));
741 syslog(LOG_ERR
, "cannot execv %s", prog
);
748 syslog(LOG_ERR
, "cannot start child process: %m");
752 while ((child_pid
= wait(&status
)) > 0 && child_pid
!= child
)
756 if (stopped
) { /* restart output filter */
757 if (kill(ofilter
, SIGCONT
) < 0) {
758 syslog(LOG_ERR
, "cannot restart output filter");
764 /* Copy filter output to "lf" logfile */
765 if ((fp
= fopen(tempfile
, "r")) != NULL
) {
766 while (fgets(buf
, sizeof(buf
), fp
))
771 if (!WIFEXITED(status
)) {
773 "%s: Daemon filter '%c' terminated (pid=%d) (termsig=%d)",
774 printer
, format
, (int)child_pid
, WTERMSIG(status
));
777 switch (WEXITSTATUS(status
)) {
786 syslog(LOG_WARNING
, "%s: filter '%c' exited (retcode=%d)",
787 printer
, format
, WEXITSTATUS(status
));
793 * Send the daemon control file (cf) and any data files.
794 * Return -1 if a non-recoverable error occurred, 1 if a recoverable error and
801 char *cp
, last
[BUFSIZ
];
806 if ((cfp
= fopen(file
, "r")) == NULL
)
809 * read the control file for work to do
811 * file format -- first character in the line is a command
812 * rest of the line is the argument.
813 * commands of interest are:
815 * a-z -- "file name" name of file to print
816 * U -- "unlink" name of file to remove
817 * (after we print it. (Pass 2 only)).
823 while (get_line(cfp
)) {
825 if (line
[0] == 'S') {
828 while (*cp
>= '0' && *cp
<= '9')
829 i
= i
* 10 + (*cp
++ - '0');
833 while (*cp
>= '0' && *cp
<= '9')
834 i
= i
* 10 + (*cp
++ - '0');
838 if (line
[0] >= 'a' && line
[0] <= 'z') {
839 strlcpy(last
, line
, sizeof(last
));
840 while ((i
= get_line(cfp
)) != 0)
841 if (strcmp(last
, line
))
843 switch (sendfile('\3', last
+1)) {
852 sendmail(logname
, ACCESS
);
859 if (err
== OK
&& sendfile('\2', file
) > 0) {
867 while (get_line(cfp
))
868 if (line
[0] == 'U' && strchr(line
+1, '/') == 0)
869 (void)unlink(line
+1);
871 * clean-up in case another control file exists
879 * Send a data file to the remote machine and spool it.
880 * Return positive if we should try resending.
883 sendfile(int type
, char *file
)
893 if (type
== '\3' && rflag
&& (OF
|| IF
)) {
896 (void)unlink(tempremote
);
897 pfd
= open(tempremote
, O_WRONLY
|O_CREAT
|O_TRUNC
|O_EXCL
, 0664);
903 switch (i
= print('f', file
)) {
915 if (lstat(file
, &stb
) < 0 || (f
= open(file
, O_RDONLY
)) < 0)
918 * Check to see if data file is a symbolic link. If so, it should
919 * still point to the same file or someone is trying to print something
922 if (S_ISLNK(stb
.st_mode
) && fstat(f
, &stb
) == 0 &&
923 (stb
.st_dev
!= fdev
|| stb
.st_ino
!= fino
))
926 amt
= snprintf(buf
, sizeof(buf
), "%c%lld %s\n", type
,
927 (long long)stb
.st_size
, save_file
);
929 if (write(pfd
, buf
, amt
) != amt
||
930 (resp
= response()) < 0 || resp
== '\1') {
933 } else if (resp
== '\0')
936 pstatus("no space on remote; waiting for queue to drain");
938 syslog(LOG_ALERT
, "%s: can't send to %s; queue full",
943 pstatus("sending to %s", RM
);
945 for (i
= 0; i
< stb
.st_size
; i
+= BUFSIZ
) {
946 struct sigaction osa
, nsa
;
949 if (i
+ amt
> stb
.st_size
)
950 amt
= stb
.st_size
- i
;
951 if (sizerr
== 0 && read(f
, buf
, amt
) != amt
)
953 nsa
.sa_handler
= alarmer
;
954 sigemptyset(&nsa
.sa_mask
);
955 sigaddset(&nsa
.sa_mask
, SIGALRM
);
957 (void)sigaction(SIGALRM
, &nsa
, &osa
);
959 if (write(pfd
, buf
, amt
) != amt
) {
961 (void)sigaction(SIGALRM
, &osa
, NULL
);
966 (void)sigaction(SIGALRM
, &osa
, NULL
);
971 syslog(LOG_INFO
, "%s: %s: changed size", printer
, file
);
972 /* tell recvjob to ignore this file */
973 (void)write(pfd
, "\1", 1);
976 if (write(pfd
, "", 1) != 1 || response())
982 * Check to make sure there have been no errors and that both programs
983 * are in sync with eachother.
984 * Return non-zero if the connection was lost.
989 struct sigaction osa
, nsa
;
992 nsa
.sa_handler
= alarmer
;
993 sigemptyset(&nsa
.sa_mask
);
994 sigaddset(&nsa
.sa_mask
, SIGALRM
);
996 (void)sigaction(SIGALRM
, &nsa
, &osa
);
998 if (read(pfd
, &resp
, 1) != 1) {
999 syslog(LOG_INFO
, "%s: lost connection", printer
);
1003 (void)sigaction(SIGALRM
, &osa
, NULL
);
1008 * Banner printing stuff
1011 banner(char *name1
, char *name2
)
1017 (void)write(ofd
, FF
, strlen(FF
));
1018 if (SB
) { /* short banner only */
1020 (void)write(ofd
, class, strlen(class));
1021 (void)write(ofd
, ":", 1);
1023 (void)write(ofd
, name1
, strlen(name1
));
1024 (void)write(ofd
, " Job: ", 7);
1025 (void)write(ofd
, name2
, strlen(name2
));
1026 (void)write(ofd
, " Date: ", 8);
1027 (void)write(ofd
, ctime(&tvec
), 24);
1028 (void)write(ofd
, "\n", 1);
1029 } else { /* normal banner */
1030 (void)write(ofd
, "\n\n\n", 3);
1031 scan_out(ofd
, name1
, '\0');
1032 (void)write(ofd
, "\n\n", 2);
1033 scan_out(ofd
, name2
, '\0');
1035 (void)write(ofd
,"\n\n\n",3);
1036 scan_out(ofd
, class, '\0');
1038 (void)write(ofd
, "\n\n\n\n\t\t\t\t\tJob: ", 15);
1039 (void)write(ofd
, name2
, strlen(name2
));
1040 (void)write(ofd
, "\n\t\t\t\t\tDate: ", 12);
1041 (void)write(ofd
, ctime(&tvec
), 24);
1042 (void)write(ofd
, "\n", 1);
1045 (void)write(ofd
, FF
, strlen(FF
));
1050 scnline(int key
, char *p
, int c
)
1054 for (scnwidth
= WIDTH
; --scnwidth
;) {
1056 *p
++ = key
& 0200 ? c
: BACKGND
;
1061 #define TRC(q) (((q)-' ')&0177)
1064 scan_out(int scfd
, char *scsp
, int dlm
)
1068 char outbuf
[LINELEN
+1], *sp
, c
, cc
;
1070 extern const char scnkey
[][HEIGHT
]; /* in lpdchar.c */
1072 for (scnhgt
= 0; scnhgt
++ < HEIGHT
+DROP
; ) {
1075 for (nchrs
= 0; ; ) {
1076 d
= dropit(c
= TRC(cc
= *sp
++));
1077 if ((!d
&& scnhgt
> HEIGHT
) || (scnhgt
<= DROP
&& d
))
1078 for (j
= WIDTH
; --j
;)
1081 strp
= scnline(scnkey
[(int)c
][scnhgt
-1-d
],
1083 if (*sp
== dlm
|| *sp
== '\0' ||
1084 nchrs
++ >= PW
/(WIDTH
+1)-1)
1089 while (*--strp
== BACKGND
&& strp
>= outbuf
)
1093 (void)write(scfd
, outbuf
, strp
-outbuf
);
1119 * tell people about job completion
1122 sendmail(char *user
, int bombed
)
1124 int i
, p
[2], s
, nofile
;
1125 const char *cp
= NULL
; /* XXX gcc */
1129 if (user
[0] == '-' || user
[0] == '/' || !isprint((unsigned char)user
[0]))
1132 if ((s
= dofork(DORETURN
)) == 0) { /* child */
1135 nofile
= sysconf(_SC_OPEN_MAX
);
1136 for (i
= 3; i
< nofile
; i
++)
1138 if ((cp
= strrchr(_PATH_SENDMAIL
, '/')) != NULL
)
1141 cp
= _PATH_SENDMAIL
;
1142 execl(_PATH_SENDMAIL
, cp
, "-t", NULL
);
1144 } else if (s
> 0) { /* parent */
1146 printf("To: %s@%s\n", user
, fromhost
);
1147 printf("Subject: %s printer job \"%s\"\n", printer
,
1148 *jobname
? jobname
: "<unknown>");
1149 printf("Reply-To: root@%s\n\n", host
);
1150 printf("Your printer job ");
1152 printf("(%s) ", jobname
);
1155 printf("\ncompleted successfully\n");
1160 printf("\ncould not be printed\n");
1164 printf("\ncould not be printed without an account on %s\n", host
);
1169 if (stat(tempfile
, &stb
) < 0 || stb
.st_size
== 0 ||
1170 (fp
= fopen(tempfile
, "r")) == NULL
) {
1171 printf("\nhad some errors and may not have printed\n");
1174 printf("\nhad the following errors and may not have printed:\n");
1175 while ((i
= getc(fp
)) != EOF
)
1180 printf("\nwas not printed because it was not linked to the original file\n");
1186 syslog(LOG_ERR
, "fork for sendmail failed: %m");
1192 syslog(LOG_INFO
, "mail sent to user %s about job %s on "
1193 "printer %s (%s)", user
, *jobname
? jobname
: "<unknown>",
1199 * dofork - fork with retries on failure
1207 for (i
= 0; i
< 20; i
++) {
1208 if ((child_pid
= fork()) < 0) {
1209 sleep((unsigned)(i
*i
));
1213 * Child should run as daemon instead of root
1215 if (child_pid
== 0) {
1218 syslog(LOG_ERR
, "uid %ld not in password file",
1222 initgroups(pw
->pw_name
, pw
->pw_gid
);
1225 signal(SIGCHLD
, SIG_DFL
);
1229 syslog(LOG_ERR
, "can't fork");
1235 syslog(LOG_ERR
, "bad action (%d) to dofork", action
);
1244 * Kill child processes to abort current job.
1249 (void)unlink(tempfile
);
1250 (void)unlink(tempremote
);
1253 kill(ofilter
, SIGCONT
);
1254 while (wait(NULL
) > 0)
1264 getprintcap(printer
);
1266 FF
= cgetstr(bp
, "ff", &s
) == -1 ? DEFFF
: s
;
1268 if (cgetnum(bp
, "du", &DU
) < 0)
1270 if (cgetnum(bp
, "pw", &PW
) < 0)
1272 (void)snprintf(&width
[2], sizeof(width
) - 2, "%ld", PW
);
1273 if (cgetnum(bp
, "pl", &PL
) < 0)
1275 (void)snprintf(&length
[2], sizeof(length
) - 2, "%ld", PL
);
1276 if (cgetnum(bp
,"px", &PX
) < 0)
1278 (void)snprintf(&pxwidth
[2], sizeof(pxwidth
) - 2, "%ld", PX
);
1279 if (cgetnum(bp
, "py", &PY
) < 0)
1281 (void)snprintf(&pxlength
[2], sizeof(pxlength
) - 2, "%ld", PY
);
1283 AF
= cgetstr(bp
, "af", &s
) == -1 ? NULL
: s
;
1284 OF
= cgetstr(bp
, "of", &s
) == -1 ? NULL
: s
;
1285 IF
= cgetstr(bp
, "if", &s
) == -1 ? NULL
: s
;
1286 RF
= cgetstr(bp
, "rf", &s
) == -1 ? NULL
: s
;
1287 TF
= cgetstr(bp
, "tf", &s
) == -1 ? NULL
: s
;
1288 NF
= cgetstr(bp
, "nf", &s
) == -1 ? NULL
: s
;
1289 DF
= cgetstr(bp
, "df", &s
) == -1 ? NULL
: s
;
1290 GF
= cgetstr(bp
, "gf", &s
) == -1 ? NULL
: s
;
1291 VF
= cgetstr(bp
, "vf", &s
) == -1 ? NULL
: s
;
1292 CF
= cgetstr(bp
, "cf", &s
) == -1 ? NULL
: s
;
1293 PF
= cgetstr(bp
, "pf", &s
) == -1 ? NULL
: s
;
1294 TR
= cgetstr(bp
, "tr", &s
) == -1 ? NULL
: s
;
1296 RS
= (cgetcap(bp
, "rs", ':') != NULL
);
1297 SF
= (cgetcap(bp
, "sf", ':') != NULL
);
1298 SH
= (cgetcap(bp
, "sh", ':') != NULL
);
1299 SB
= (cgetcap(bp
, "sb", ':') != NULL
);
1300 HL
= (cgetcap(bp
, "hl", ':') != NULL
);
1301 RW
= (cgetcap(bp
, "rw", ':') != NULL
);
1303 cgetnum(bp
, "br", &BR
);
1304 if (cgetnum(bp
, "fc", &FC
) < 0)
1306 if (cgetnum(bp
, "fs", &FS
) < 0)
1308 if (cgetnum(bp
, "xc", &XC
) < 0)
1310 if (cgetnum(bp
, "xs", &XS
) < 0)
1312 MS
= cgetstr(bp
, "ms", &s
) == -1 ? NULL
: s
;
1314 tof
= (cgetcap(bp
, "fo", ':') == NULL
);
1318 * Setup output filter - called once for local printer, or (if -r given to lpd)
1319 * once per file for remote printers
1322 setup_ofilter(int check_rflag
)
1326 if (OF
&& (!remote
|| (check_rflag
&& rflag
))) {
1332 if ((ofilter
= dofork(DOABORT
)) == 0) { /* child */
1333 dup2(p
[0], 0); /* pipe is std in */
1334 dup2(pfd
, 1); /* printer is std out */
1336 nofile
= sysconf(_SC_OPEN_MAX
);
1337 for (i
= 3; i
< nofile
; i
++)
1339 if ((cp
= strrchr(OF
, '/')) == NULL
)
1343 execl(OF
, cp
, width
, length
, NULL
);
1344 syslog(LOG_ERR
, "%s: %s: %m", printer
, OF
);
1347 (void)close(p
[0]); /* close input side */
1348 ofd
= p
[1]; /* use pipe for output */
1356 * Close the output filter and reset ofd back to the main pfd descriptor
1364 kill(ofilter
, SIGCONT
); /* to be sure */
1367 while ((i
= wait(NULL
)) > 0 && i
!= ofilter
)
1374 * Acquire line printer or remote connection.
1379 if (!remote
&& *LP
) {
1380 if (strchr(LP
, '@') != NULL
)
1384 } else if (remote
) {
1387 syslog(LOG_ERR
, "%s: no line printer device or host name",
1393 * Start up an output filter, if needed.
1399 * Printer connected directly to the network
1400 * or to a terminal server on the net
1408 for (i
= 1; ; i
= i
< 256 ? i
<< 1 : i
) {
1411 if (pfd
< 0 && errno
== ECONNREFUSED
)
1413 else if (pfd
>= 0) {
1415 * need to delay a bit for rs232 lines
1416 * to stabilize in case printer is
1417 * connected via a terminal server
1424 pstatus("waiting for %s to come up", LP
);
1426 pstatus("waiting for access to printer on %s", LP
);
1430 pstatus("sending to %s", LP
);
1434 * Printer is connected to an RS232 port on this host
1441 for (i
= 1; ; i
= i
< 32 ? i
<< 1 : i
) {
1442 pfd
= open(LP
, RW
? O_RDWR
: O_WRONLY
);
1447 if (errno
== ENOENT
) {
1448 syslog(LOG_ERR
, "%s: %m", LP
);
1452 pstatus("waiting for %s to become ready (offline ?)",
1458 pstatus("%s is ready and printing", printer
);
1462 * Printer is on a remote host
1470 for (i
= 1; ; i
= i
< 256 ? i
<< 1 : i
) {
1474 n
= snprintf(line
, sizeof(line
), "\2%s\n", RP
);
1475 if (write(pfd
, line
, n
) == n
&&
1476 (resp
= response()) == '\0')
1482 pstatus("waiting for %s to come up", RM
);
1484 pstatus("waiting for queue to be enabled on %s",
1491 pstatus("sending to %s", RM
);
1500 #if !defined(__NetBSD__)
1533 char **argv
, **ap
, *p
, *val
;
1537 if (ioctl(i
.fd
, TIOCEXCL
, (char *)0) < 0) {
1538 syslog(LOG_ERR
, "%s: ioctl(TIOCEXCL): %m", printer
);
1541 if (tcgetattr(i
.fd
, &i
.t
) < 0) {
1542 syslog(LOG_ERR
, "%s: tcgetattr: %m", printer
);
1546 #if !defined(__NetBSD__)
1548 for (bp
= bauds
; bp
->baud
; bp
++)
1552 syslog(LOG_ERR
, "%s: illegal baud rate %d", printer
, BR
);
1555 cfsetspeed(&i
.t
, bp
->speed
);
1557 cfsetspeed(&i
.t
, BR
);
1562 if (ioctl(i
.fd
, TIOCGETD
, &i
.ldisc
) < 0) {
1563 syslog(LOG_ERR
, "%s: ioctl(TIOCGETD): %m", printer
);
1566 if (ioctl(i
.fd
, TIOCGWINSZ
, &i
.win
) < 0)
1567 syslog(LOG_INFO
, "%s: ioctl(TIOCGWINSZ): %m",
1570 argv
= (char **)calloc(256, sizeof(char *));
1572 syslog(LOG_ERR
, "%s: calloc: %m", printer
);
1577 while ((val
= strsep(&p
, " \t,")) != NULL
) {
1578 *ap
++ = strdup(val
);
1581 for (; *argv
; ++argv
) {
1582 if (ksearch(&argv
, &i
))
1584 if (msearch(&argv
, &i
))
1586 syslog(LOG_INFO
, "%s: unknown stty flag: %s",
1591 sttyclearflags(&i
.t
, FC
);
1595 sttysetflags(&i
.t
, FS
);
1599 sttyclearlflags(&i
.t
, XC
);
1603 sttysetlflags(&i
.t
, XS
);
1608 if (i
.set
&& tcsetattr(i
.fd
, TCSANOW
, &i
.t
) < 0) {
1609 syslog(LOG_ERR
, "%s: tcsetattr: %m", printer
);
1612 if (i
.wset
&& ioctl(i
.fd
, TIOCSWINSZ
, &i
.win
) < 0)
1613 syslog(LOG_INFO
, "%s: ioctl(TIOCSWINSZ): %m", printer
);
1620 pstatus(const char *msg
, ...)
1625 struct iovec iov
[2];
1628 fd
= open(ST
, O_WRONLY
|O_CREAT
, 0664);
1629 if (fd
< 0 || flock(fd
, LOCK_EX
) < 0) {
1630 syslog(LOG_ERR
, "%s: %s: %m", printer
, ST
);
1635 (void)vasprintf(&buf
, msg
, ap
);
1638 iov
[0].iov_base
= buf
;
1639 iov
[0].iov_len
= strlen(buf
);
1640 iov
[1].iov_base
= __UNCONST("\n");
1642 (void)writev(fd
, iov
, 2);