Sync usage with man page.
[netbsd-mini2440.git] / usr.sbin / lpr / lpd / printjob.c
blob82d0f8b0d859da1c17f726ff7902e18466145d5a
1 /* $NetBSD: printjob.c,v 1.54 2008/07/21 13:36:58 lukem Exp $ */
3 /*
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
10 * are met:
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
30 * SUCH DAMAGE.
33 #include <sys/cdefs.h>
35 #ifndef lint
36 __COPYRIGHT("@(#) Copyright (c) 1983, 1993\
37 The Regents of the University of California. All rights reserved.");
38 #endif /* not lint */
40 #ifndef lint
41 #if 0
42 static char sccsid[] = "@(#)printjob.c 8.7 (Berkeley) 5/10/95";
43 #else
44 __RCSID("$NetBSD: printjob.c,v 1.54 2008/07/21 13:36:58 lukem Exp $");
45 #endif
46 #endif /* not lint */
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>
57 #include <sys/wait.h>
58 #include <sys/stat.h>
59 #include <sys/types.h>
60 #include <sys/file.h>
62 #include <pwd.h>
63 #include <unistd.h>
64 #include <sys/uio.h>
65 #include <signal.h>
66 #include <termios.h>
67 #include <syslog.h>
68 #include <fcntl.h>
69 #include <dirent.h>
70 #include <errno.h>
71 #include <stdio.h>
72 #include <string.h>
73 #include <stdlib.h>
74 #include <ctype.h>
75 #include "lp.h"
76 #include "lp.local.h"
77 #include "pathnames.h"
78 #include "extern.h"
80 #define DORETURN 0 /* absorb fork error */
81 #define DOABORT 1 /* abort if dofork fails */
84 * Error tokens
86 #define REPRINT -2
87 #define ERROR -1
88 #define OK 0
89 #define FATALERR 1
90 #define NOACCT 2
91 #define FILTERERR 3
92 #define ACCESS 4
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);
144 void
145 printjob(void)
147 struct stat stb;
148 struct queue *q, **qp;
149 struct queue **queue;
150 int i, nitems, fd;
151 off_t pidoff;
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);
162 if (fd > 0) {
163 (void) dup2(fd, STDERR_FILENO);
164 (void) close(fd);
165 } else
166 (void)close(STDERR_FILENO);
168 setgid(getegid());
169 pid = getpid(); /* for use with lprm */
170 setpgrp(0, pid);
171 signal(SIGHUP, abortpr);
172 signal(SIGINT, abortpr);
173 signal(SIGQUIT, abortpr);
174 signal(SIGTERM, abortpr);
177 * uses short form file names
179 if (chdir(SD) < 0) {
180 syslog(LOG_ERR, "%s: %m", SD);
181 exit(1);
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);
186 if (lfd < 0) {
187 syslog(LOG_ERR, "%s: %s: %m", printer, LO);
188 exit(1);
190 if (flock(lfd, LOCK_EX|LOCK_NB) < 0) {
191 if (errno == EWOULDBLOCK) /* active daemon present */
192 exit(0);
193 syslog(LOG_ERR, "%s: %s: %m", printer, LO);
194 exit(1);
196 ftruncate(lfd, 0);
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);
203 exit(1);
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) {
212 (void)close(fd);
213 (void)unlink(tempfile);
215 if ((fd = mkstemp(tempremote)) != -1) {
216 (void)close(fd);
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);
225 exit(1);
227 if (nitems == 0) /* no work to do */
228 exit(0);
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 */
235 again:
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)) {
242 q = *qp++;
243 if (stat(q->q_name, &stb) < 0)
244 continue;
245 errcnt = 0;
246 restart:
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);
251 if (!remote)
252 i = printit(q->q_name);
253 else
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)
262 goto done;
263 /* rebuild queue (after lpc topq) */
264 if (stb.st_mode & S_IXOTH) {
265 for (free((char *) q); nitems--; free((char *) q))
266 q = *qp++;
267 stb.st_mode &= ~S_IXOTH;
268 if (fchmod(lfd, stb.st_mode & 0777) < 0)
269 syslog(LOG_WARNING, "%s: %s: %m",
270 printer, LO);
271 break;
274 if (i == OK) /* file ok and printed */
275 count++;
276 else if (i == REPRINT && ++errcnt < 5) {
277 /* try reprinting the job */
278 syslog(LOG_INFO, "restarting %s", printer);
279 if (ofilter > 0)
280 close_ofilter();
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 */
285 goto restart;
286 } else {
287 syslog(LOG_WARNING, "%s: job could not be %s (%s)", printer,
288 remote ? "sent to remote host" : "printed", q->q_name);
289 if (i == REPRINT) {
290 /* ensure we don't attempt this job again */
291 (void) unlink(q->q_name);
292 q->q_name[0] = 'd';
293 (void) unlink(q->q_name);
294 if (logname[0])
295 sendmail(logname, FATALERR);
299 free(queue);
300 queue = NULL;
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);
306 exit(1);
308 if (nitems == 0) { /* no more work to do */
309 done:
310 if (count > 0) { /* Files actually printed */
311 if (!SF && !tof)
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);
318 exit(0);
320 goto again;
323 #define FONTLEN 50
324 char fonts[4][FONTLEN]; /* fonts for troff */
326 char ifonts[4][40] = {
327 _PATH_VFONTR,
328 _PATH_VFONTI,
329 _PATH_VFONTB,
330 _PATH_VFONTS,
334 * The remaining part is the reading of the control file (cf)
335 * and performing the various actions.
337 static int
338 printit(char *file)
340 int i;
341 char *cp;
342 int bombed = OK;
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);
349 return(OK);
352 * Reset troff fonts.
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);
357 indent[2] = '0';
358 indent[3] = '\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 * 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
398 /* pass 1 */
400 while (get_line(cfp))
401 switch (line[0]) {
402 case 'H':
403 strlcpy(fromhost, line+1, sizeof(fromhost));
404 if (class[0] == '\0')
405 strlcpy(class, line+1, sizeof(class));
406 continue;
408 case 'P':
409 strlcpy(logname, line+1, sizeof(logname));
410 if (RS) { /* restricted */
411 if (getpwnam(logname) == NULL) {
412 bombed = NOACCT;
413 sendmail(line+1, bombed);
414 goto pass2;
417 continue;
419 case 'S':
420 cp = line+1;
421 i = 0;
422 while (*cp >= '0' && *cp <= '9')
423 i = i * 10 + (*cp++ - '0');
424 fdev = i;
425 cp++;
426 i = 0;
427 while (*cp >= '0' && *cp <= '9')
428 i = i * 10 + (*cp++ - '0');
429 fino = i;
430 continue;
432 case 'J':
433 if (line[1] != '\0')
434 strlcpy(jobname, line+1, sizeof(jobname));
435 else {
436 jobname[0] = ' ';
437 jobname[1] = '\0';
439 continue;
441 case 'C':
442 if (line[1] != '\0')
443 strlcpy(class, line+1, sizeof(class));
444 else if (class[0] == '\0') {
445 gethostname(class, sizeof(class));
446 class[sizeof(class) - 1] = '\0';
448 continue;
450 case 'T': /* header title for pr */
451 strlcpy(title, line+1, sizeof(title));
452 continue;
454 case 'L': /* identification line */
455 if (!SH && !HL)
456 banner(line+1, jobname);
457 continue;
459 case '1': /* troff fonts */
460 case '2':
461 case '3':
462 case '4':
463 if (line[1] != '\0') {
464 strlcpy(fonts[line[0]-'1'], line+1,
465 sizeof(fonts[line[0]-'1']));
467 continue;
469 case 'W': /* page width */
470 strlcpy(width+2, line+1, sizeof(width) - 2);
471 continue;
473 case 'I': /* indent amount */
474 strlcpy(indent+2, line+1, sizeof(indent) - 2);
475 continue;
477 default: /* some file to print */
478 switch (i = print(line[0], line+1)) {
479 case ERROR:
480 if (bombed == OK)
481 bombed = FATALERR;
482 break;
483 case REPRINT:
484 (void)fclose(cfp);
485 return(REPRINT);
486 case FILTERERR:
487 case ACCESS:
488 bombed = i;
489 sendmail(logname, bombed);
491 title[0] = '\0';
492 continue;
494 case 'N':
495 case 'U':
496 case 'M':
497 case 'R':
498 continue;
501 /* pass 2 */
503 pass2:
504 fseek(cfp, 0L, 0);
505 while (get_line(cfp))
506 switch (line[0]) {
507 case 'L': /* identification line */
508 if (!SH && HL)
509 banner(line+1, jobname);
510 continue;
512 case 'M':
513 if (bombed < NOACCT) /* already sent if >= NOACCT */
514 sendmail(line+1, bombed);
515 continue;
517 case 'U':
518 if (strchr(line+1, '/'))
519 continue;
520 (void)unlink(line+1);
523 * clean-up in case another control file exists
525 (void)fclose(cfp);
526 (void)unlink(file);
527 return(bombed == OK ? OK : ERROR);
531 * Print a file.
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
536 * 0 if all is well.
537 * Note: all filters take stdin as the file, stdout as the printer,
538 * stderr as the log file, and must not ignore SIGINT.
540 static int
541 print(int format, char *file)
543 FILE *fp;
544 int status;
545 struct stat stb;
546 const char *prog, *av[17];
547 char buf[BUFSIZ];
548 int n, fi, fo, child_pid, p[2], stopped = 0, nofile;
550 if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0)
551 return(ERROR);
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))
559 return(ACCESS);
560 if (!SF && !tof) { /* start on a fresh page */
561 (void)write(ofd, FF, strlen(FF));
562 tof = 1;
564 if (IF == NULL && (format == 'f' || format == 'l')) {
565 tof = 0;
566 while ((n = read(fi, buf, BUFSIZ)) > 0)
567 if (write(ofd, buf, n) != n) {
568 (void)close(fi);
569 return(REPRINT);
571 (void)close(fi);
572 return(OK);
574 switch (format) {
575 case 'p': /* print file using 'pr' */
576 if (IF == NULL) { /* use output filter */
577 prog = _PATH_PR;
578 av[0] = "pr";
579 av[1] = width;
580 av[2] = length;
581 av[3] = "-h";
582 av[4] = *title ? title : " ";
583 av[5] = 0;
584 fo = ofd;
585 goto start;
587 pipe(p);
588 if ((prchild = dofork(DORETURN)) == 0) { /* child */
589 dup2(fi, 0); /* file is stdin */
590 dup2(p[1], 1); /* pipe is stdout */
591 closelog();
592 nofile = sysconf(_SC_OPEN_MAX);
593 for (n = 3; n < nofile; n++)
594 (void)close(n);
595 execl(_PATH_PR, "pr", width, length,
596 "-h", *title ? title : " ", NULL);
597 syslog(LOG_ERR, "cannot execl %s", _PATH_PR);
598 exit(2);
600 (void)close(p[1]); /* close output side */
601 (void)close(fi);
602 if (prchild < 0) {
603 prchild = 0;
604 (void)close(p[0]);
605 return(ERROR);
607 fi = p[0]; /* use pipe for input */
608 case 'f': /* print plain text file */
609 prog = IF;
610 av[1] = width;
611 av[2] = length;
612 av[3] = indent;
613 n = 4;
614 break;
615 case 'o': /* print a postscript file */
616 if (PF == NULL) {
617 /* if PF is not set, handle it like an 'l' */
618 prog = IF;
619 av[1] = "-c";
620 av[2] = width;
621 av[3] = length;
622 av[4] = indent;
623 n = 5;
624 break;
625 } else {
626 prog = PF;
627 av[1] = pxwidth;
628 av[2] = pxlength;
629 n = 3;
630 break;
632 case 'l': /* like 'f' but pass control characters */
633 prog = IF;
634 av[1] = "-c";
635 av[2] = width;
636 av[3] = length;
637 av[4] = indent;
638 n = 5;
639 break;
640 case 'r': /* print a fortran text file */
641 prog = RF;
642 av[1] = width;
643 av[2] = length;
644 n = 3;
645 break;
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");
653 } else {
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);
661 (void)close(fo);
663 prog = (format == 't') ? TF : (format == 'n') ? NF : DF;
664 av[1] = pxwidth;
665 av[2] = pxlength;
666 n = 3;
667 break;
668 case 'c': /* print cifplot output */
669 prog = CF;
670 av[1] = pxwidth;
671 av[2] = pxlength;
672 n = 3;
673 break;
674 case 'g': /* print plot(1G) output */
675 prog = GF;
676 av[1] = pxwidth;
677 av[2] = pxlength;
678 n = 3;
679 break;
680 case 'v': /* print raster output */
681 prog = VF;
682 av[1] = pxwidth;
683 av[2] = pxlength;
684 n = 3;
685 break;
686 default:
687 (void)close(fi);
688 syslog(LOG_ERR, "%s: illegal format character '%c'",
689 printer, format);
690 return(ERROR);
692 if (prog == NULL) {
693 (void)close(fi);
694 syslog(LOG_ERR,
695 "%s: no filter found in printcap for format character '%c'",
696 printer, format);
697 return (ERROR);
699 if ((av[0] = strrchr(prog, '/')) != NULL)
700 av[0]++;
701 else
702 av[0] = prog;
703 av[n++] = "-n";
704 av[n++] = logname;
705 if (*jobname != '\0' && strcmp(jobname, " ") != 0) {
706 av[n++] = "-j";
707 av[n++] = jobname;
709 av[n++] = "-h";
710 av[n++] = fromhost;
711 av[n++] = AF;
712 av[n] = 0;
713 fo = pfd;
714 if (ofilter > 0) { /* stop output filter */
715 write(ofd, "\031\1", 2);
716 while ((child_pid =
717 wait3(&status, WUNTRACED, 0)) > 0 && child_pid != ofilter)
719 if (WIFSTOPPED(status) == 0) {
720 (void)close(fi);
721 syslog(LOG_WARNING,
722 "%s: output filter died (retcode=%d termsig=%d)",
723 printer, WEXITSTATUS(status), WTERMSIG(status));
724 return(REPRINT);
726 stopped++;
728 start:
729 if ((child = dofork(DORETURN)) == 0) { /* child */
730 dup2(fi, 0);
731 dup2(fo, 1);
732 unlink(tempfile);
733 n = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0664);
734 if (n >= 0)
735 dup2(n, 2);
736 closelog();
737 nofile = sysconf(_SC_OPEN_MAX);
738 for (n = 3; n < nofile; n++)
739 (void)close(n);
740 execv(prog, __UNCONST(av));
741 syslog(LOG_ERR, "cannot execv %s", prog);
742 exit(2);
744 if (child < 0) {
745 child = 0;
746 prchild = 0;
747 tof = 0;
748 syslog(LOG_ERR, "cannot start child process: %m");
749 return (ERROR);
751 (void)close(fi);
752 while ((child_pid = wait(&status)) > 0 && child_pid != child)
754 child = 0;
755 prchild = 0;
756 if (stopped) { /* restart output filter */
757 if (kill(ofilter, SIGCONT) < 0) {
758 syslog(LOG_ERR, "cannot restart output filter");
759 exit(1);
762 tof = 0;
764 /* Copy filter output to "lf" logfile */
765 if ((fp = fopen(tempfile, "r")) != NULL) {
766 while (fgets(buf, sizeof(buf), fp))
767 fputs(buf, stderr);
768 fclose(fp);
771 if (!WIFEXITED(status)) {
772 syslog(LOG_WARNING,
773 "%s: Daemon filter '%c' terminated (pid=%d) (termsig=%d)",
774 printer, format, (int)child_pid, WTERMSIG(status));
775 return(ERROR);
777 switch (WEXITSTATUS(status)) {
778 case 0:
779 tof = 1;
780 return(OK);
781 case 1:
782 return(REPRINT);
783 case 2:
784 return(ERROR);
785 default:
786 syslog(LOG_WARNING, "%s: filter '%c' exited (retcode=%d)",
787 printer, format, WEXITSTATUS(status));
788 return(FILTERERR);
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
795 * 0 if all is well.
797 static int
798 sendit(char *file)
800 int i, err = OK;
801 char *cp, last[BUFSIZ];
804 * open control file
806 if ((cfp = fopen(file, "r")) == NULL)
807 return(OK);
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)).
821 * pass 1
823 while (get_line(cfp)) {
824 again:
825 if (line[0] == 'S') {
826 cp = line+1;
827 i = 0;
828 while (*cp >= '0' && *cp <= '9')
829 i = i * 10 + (*cp++ - '0');
830 fdev = i;
831 cp++;
832 i = 0;
833 while (*cp >= '0' && *cp <= '9')
834 i = i * 10 + (*cp++ - '0');
835 fino = i;
836 continue;
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))
842 break;
843 switch (sendfile('\3', last+1)) {
844 case OK:
845 if (i)
846 goto again;
847 break;
848 case REPRINT:
849 (void)fclose(cfp);
850 return(REPRINT);
851 case ACCESS:
852 sendmail(logname, ACCESS);
853 case ERROR:
854 err = ERROR;
856 break;
859 if (err == OK && sendfile('\2', file) > 0) {
860 (void)fclose(cfp);
861 return(REPRINT);
864 * pass 2
866 fseek(cfp, 0L, 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
873 (void)fclose(cfp);
874 (void)unlink(file);
875 return(err);
879 * Send a data file to the remote machine and spool it.
880 * Return positive if we should try resending.
882 static int
883 sendfile(int type, char *file)
885 int f, i, amt;
886 struct stat stb;
887 char buf[BUFSIZ];
888 int sizerr, resp;
889 extern int rflag;
890 char *save_file;
892 save_file = file;
893 if (type == '\3' && rflag && (OF || IF)) {
894 int save_pfd = pfd;
896 (void)unlink(tempremote);
897 pfd = open(tempremote, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0664);
898 if (pfd == -1) {
899 pfd = save_pfd;
900 return ERROR;
902 setup_ofilter(1);
903 switch (i = print('f', file)) {
904 case ERROR:
905 case REPRINT:
906 case FILTERERR:
907 case ACCESS:
908 return(i);
910 close_ofilter();
911 pfd = save_pfd;
912 file = tempremote;
915 if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0)
916 return(ERROR);
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
920 * he shouldn't.
922 if (S_ISLNK(stb.st_mode) && fstat(f, &stb) == 0 &&
923 (stb.st_dev != fdev || stb.st_ino != fino))
924 return(ACCESS);
926 amt = snprintf(buf, sizeof(buf), "%c%lld %s\n", type,
927 (long long)stb.st_size, save_file);
928 for (i = 0; ; i++) {
929 if (write(pfd, buf, amt) != amt ||
930 (resp = response()) < 0 || resp == '\1') {
931 (void)close(f);
932 return(REPRINT);
933 } else if (resp == '\0')
934 break;
935 if (i == 0)
936 pstatus("no space on remote; waiting for queue to drain");
937 if (i == 10)
938 syslog(LOG_ALERT, "%s: can't send to %s; queue full",
939 printer, RM);
940 sleep(5 * 60);
942 if (i)
943 pstatus("sending to %s", RM);
944 sizerr = 0;
945 for (i = 0; i < stb.st_size; i += BUFSIZ) {
946 struct sigaction osa, nsa;
948 amt = BUFSIZ;
949 if (i + amt > stb.st_size)
950 amt = stb.st_size - i;
951 if (sizerr == 0 && read(f, buf, amt) != amt)
952 sizerr = 1;
953 nsa.sa_handler = alarmer;
954 sigemptyset(&nsa.sa_mask);
955 sigaddset(&nsa.sa_mask, SIGALRM);
956 nsa.sa_flags = 0;
957 (void)sigaction(SIGALRM, &nsa, &osa);
958 alarm(wait_time);
959 if (write(pfd, buf, amt) != amt) {
960 alarm(0);
961 (void)sigaction(SIGALRM, &osa, NULL);
962 (void)close(f);
963 return(REPRINT);
965 alarm(0);
966 (void)sigaction(SIGALRM, &osa, NULL);
969 (void)close(f);
970 if (sizerr) {
971 syslog(LOG_INFO, "%s: %s: changed size", printer, file);
972 /* tell recvjob to ignore this file */
973 (void)write(pfd, "\1", 1);
974 return(ERROR);
976 if (write(pfd, "", 1) != 1 || response())
977 return(REPRINT);
978 return(OK);
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.
986 static char
987 response(void)
989 struct sigaction osa, nsa;
990 char resp;
992 nsa.sa_handler = alarmer;
993 sigemptyset(&nsa.sa_mask);
994 sigaddset(&nsa.sa_mask, SIGALRM);
995 nsa.sa_flags = 0;
996 (void)sigaction(SIGALRM, &nsa, &osa);
997 alarm(wait_time);
998 if (read(pfd, &resp, 1) != 1) {
999 syslog(LOG_INFO, "%s: lost connection", printer);
1000 resp = -1;
1002 alarm(0);
1003 (void)sigaction(SIGALRM, &osa, NULL);
1004 return (resp);
1008 * Banner printing stuff
1010 static void
1011 banner(char *name1, char *name2)
1013 time_t tvec;
1015 time(&tvec);
1016 if (!SF && !tof)
1017 (void)write(ofd, FF, strlen(FF));
1018 if (SB) { /* short banner only */
1019 if (class[0]) {
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');
1034 if (class[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);
1044 if (!SF)
1045 (void)write(ofd, FF, strlen(FF));
1046 tof = 1;
1049 static char *
1050 scnline(int key, char *p, int c)
1052 int scnwidth;
1054 for (scnwidth = WIDTH; --scnwidth;) {
1055 key <<= 1;
1056 *p++ = key & 0200 ? c : BACKGND;
1058 return (p);
1061 #define TRC(q) (((q)-' ')&0177)
1063 static void
1064 scan_out(int scfd, char *scsp, int dlm)
1066 char *strp;
1067 int nchrs, j;
1068 char outbuf[LINELEN+1], *sp, c, cc;
1069 int d, scnhgt;
1070 extern const char scnkey[][HEIGHT]; /* in lpdchar.c */
1072 for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) {
1073 strp = &outbuf[0];
1074 sp = scsp;
1075 for (nchrs = 0; ; ) {
1076 d = dropit(c = TRC(cc = *sp++));
1077 if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d))
1078 for (j = WIDTH; --j;)
1079 *strp++ = BACKGND;
1080 else
1081 strp = scnline(scnkey[(int)c][scnhgt-1-d],
1082 strp, cc);
1083 if (*sp == dlm || *sp == '\0' ||
1084 nchrs++ >= PW/(WIDTH+1)-1)
1085 break;
1086 *strp++ = BACKGND;
1087 *strp++ = BACKGND;
1089 while (*--strp == BACKGND && strp >= outbuf)
1091 strp++;
1092 *strp++ = '\n';
1093 (void)write(scfd, outbuf, strp-outbuf);
1097 static int
1098 dropit(int c)
1100 switch(c) {
1102 case TRC('_'):
1103 case TRC(';'):
1104 case TRC(','):
1105 case TRC('g'):
1106 case TRC('j'):
1107 case TRC('p'):
1108 case TRC('q'):
1109 case TRC('y'):
1110 return (DROP);
1112 default:
1113 return (0);
1118 * sendmail ---
1119 * tell people about job completion
1121 static void
1122 sendmail(char *user, int bombed)
1124 int i, p[2], s, nofile;
1125 const char *cp = NULL; /* XXX gcc */
1126 struct stat stb;
1127 FILE *fp;
1129 if (user[0] == '-' || user[0] == '/' || !isprint((unsigned char)user[0]))
1130 return;
1131 pipe(p);
1132 if ((s = dofork(DORETURN)) == 0) { /* child */
1133 dup2(p[0], 0);
1134 closelog();
1135 nofile = sysconf(_SC_OPEN_MAX);
1136 for (i = 3; i < nofile; i++)
1137 (void)close(i);
1138 if ((cp = strrchr(_PATH_SENDMAIL, '/')) != NULL)
1139 cp++;
1140 else
1141 cp = _PATH_SENDMAIL;
1142 execl(_PATH_SENDMAIL, cp, "-t", NULL);
1143 _exit(0);
1144 } else if (s > 0) { /* parent */
1145 dup2(p[1], 1);
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 ");
1151 if (*jobname)
1152 printf("(%s) ", jobname);
1153 switch (bombed) {
1154 case OK:
1155 printf("\ncompleted successfully\n");
1156 cp = "OK";
1157 break;
1158 default:
1159 case FATALERR:
1160 printf("\ncould not be printed\n");
1161 cp = "FATALERR";
1162 break;
1163 case NOACCT:
1164 printf("\ncould not be printed without an account on %s\n", host);
1165 cp = "NOACCT";
1166 break;
1167 case FILTERERR:
1168 cp = "FILTERERR";
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");
1172 break;
1174 printf("\nhad the following errors and may not have printed:\n");
1175 while ((i = getc(fp)) != EOF)
1176 putchar(i);
1177 (void)fclose(fp);
1178 break;
1179 case ACCESS:
1180 printf("\nwas not printed because it was not linked to the original file\n");
1181 cp = "ACCESS";
1183 fflush(stdout);
1184 (void)close(1);
1185 } else {
1186 syslog(LOG_ERR, "fork for sendmail failed: %m");
1188 (void)close(p[0]);
1189 (void)close(p[1]);
1190 if (s > 0) {
1191 wait(NULL);
1192 syslog(LOG_INFO, "mail sent to user %s about job %s on "
1193 "printer %s (%s)", user, *jobname ? jobname : "<unknown>",
1194 printer, cp);
1199 * dofork - fork with retries on failure
1201 static int
1202 dofork(int action)
1204 int i, child_pid;
1205 struct passwd *pw;
1207 for (i = 0; i < 20; i++) {
1208 if ((child_pid = fork()) < 0) {
1209 sleep((unsigned)(i*i));
1210 continue;
1213 * Child should run as daemon instead of root
1215 if (child_pid == 0) {
1216 pw = getpwuid(DU);
1217 if (pw == 0) {
1218 syslog(LOG_ERR, "uid %ld not in password file",
1219 DU);
1220 break;
1222 initgroups(pw->pw_name, pw->pw_gid);
1223 setgid(pw->pw_gid);
1224 setuid(DU);
1225 signal(SIGCHLD, SIG_DFL);
1227 return (child_pid);
1229 syslog(LOG_ERR, "can't fork");
1231 switch (action) {
1232 case DORETURN:
1233 return (-1);
1234 default:
1235 syslog(LOG_ERR, "bad action (%d) to dofork", action);
1236 /*FALL THRU*/
1237 case DOABORT:
1238 exit(1);
1240 /*NOTREACHED*/
1244 * Kill child processes to abort current job.
1246 static void
1247 abortpr(int signo)
1249 (void)unlink(tempfile);
1250 (void)unlink(tempremote);
1251 kill(0, SIGINT);
1252 if (ofilter > 0)
1253 kill(ofilter, SIGCONT);
1254 while (wait(NULL) > 0)
1256 exit(0);
1259 static void
1260 init(void)
1262 char *s;
1264 getprintcap(printer);
1266 FF = cgetstr(bp, "ff", &s) == -1 ? DEFFF : s;
1268 if (cgetnum(bp, "du", &DU) < 0)
1269 DU = DEFUID;
1270 if (cgetnum(bp, "pw", &PW) < 0)
1271 PW = DEFWIDTH;
1272 (void)snprintf(&width[2], sizeof(width) - 2, "%ld", PW);
1273 if (cgetnum(bp, "pl", &PL) < 0)
1274 PL = DEFLENGTH;
1275 (void)snprintf(&length[2], sizeof(length) - 2, "%ld", PL);
1276 if (cgetnum(bp,"px", &PX) < 0)
1277 PX = 0;
1278 (void)snprintf(&pxwidth[2], sizeof(pxwidth) - 2, "%ld", PX);
1279 if (cgetnum(bp, "py", &PY) < 0)
1280 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)
1305 FC = 0;
1306 if (cgetnum(bp, "fs", &FS) < 0)
1307 FS = 0;
1308 if (cgetnum(bp, "xc", &XC) < 0)
1309 XC = 0;
1310 if (cgetnum(bp, "xs", &XS) < 0)
1311 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
1321 static void
1322 setup_ofilter(int check_rflag)
1324 extern int rflag;
1326 if (OF && (!remote || (check_rflag && rflag))) {
1327 int p[2];
1328 int i, nofile;
1329 const char *cp;
1331 pipe(p);
1332 if ((ofilter = dofork(DOABORT)) == 0) { /* child */
1333 dup2(p[0], 0); /* pipe is std in */
1334 dup2(pfd, 1); /* printer is std out */
1335 closelog();
1336 nofile = sysconf(_SC_OPEN_MAX);
1337 for (i = 3; i < nofile; i++)
1338 (void)close(i);
1339 if ((cp = strrchr(OF, '/')) == NULL)
1340 cp = OF;
1341 else
1342 cp++;
1343 execl(OF, cp, width, length, NULL);
1344 syslog(LOG_ERR, "%s: %s: %m", printer, OF);
1345 exit(1);
1347 (void)close(p[0]); /* close input side */
1348 ofd = p[1]; /* use pipe for output */
1349 } else {
1350 ofd = pfd;
1351 ofilter = 0;
1356 * Close the output filter and reset ofd back to the main pfd descriptor
1358 static void
1359 close_ofilter(void)
1361 int i;
1363 if (ofilter) {
1364 kill(ofilter, SIGCONT); /* to be sure */
1365 (void)close(ofd);
1366 ofd = pfd;
1367 while ((i = wait(NULL)) > 0 && i != ofilter)
1369 ofilter = 0;
1374 * Acquire line printer or remote connection.
1376 static void
1377 openpr(void)
1379 if (!remote && *LP) {
1380 if (strchr(LP, '@') != NULL)
1381 opennet();
1382 else
1383 opentty();
1384 } else if (remote) {
1385 openrem();
1386 } else {
1387 syslog(LOG_ERR, "%s: no line printer device or host name",
1388 printer);
1389 exit(1);
1393 * Start up an output filter, if needed.
1395 setup_ofilter(0);
1399 * Printer connected directly to the network
1400 * or to a terminal server on the net
1402 static void
1403 opennet(void)
1405 int i;
1406 int resp;
1408 for (i = 1; ; i = i < 256 ? i << 1 : i) {
1409 resp = -1;
1410 pfd = getport(LP);
1411 if (pfd < 0 && errno == ECONNREFUSED)
1412 resp = 1;
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
1419 delay(500);
1420 break;
1422 if (i == 1) {
1423 if (resp < 0)
1424 pstatus("waiting for %s to come up", LP);
1425 else
1426 pstatus("waiting for access to printer on %s", LP);
1428 sleep(i);
1430 pstatus("sending to %s", LP);
1434 * Printer is connected to an RS232 port on this host
1436 static void
1437 opentty(void)
1439 int i;
1441 for (i = 1; ; i = i < 32 ? i << 1 : i) {
1442 pfd = open(LP, RW ? O_RDWR : O_WRONLY);
1443 if (pfd >= 0) {
1444 delay(500);
1445 break;
1447 if (errno == ENOENT) {
1448 syslog(LOG_ERR, "%s: %m", LP);
1449 exit(1);
1451 if (i == 1)
1452 pstatus("waiting for %s to become ready (offline ?)",
1453 printer);
1454 sleep(i);
1456 if (isatty(pfd))
1457 setty();
1458 pstatus("%s is ready and printing", printer);
1462 * Printer is on a remote host
1464 static void
1465 openrem(void)
1467 int i, n;
1468 int resp;
1470 for (i = 1; ; i = i < 256 ? i << 1 : i) {
1471 resp = -1;
1472 pfd = getport(RM);
1473 if (pfd >= 0) {
1474 n = snprintf(line, sizeof(line), "\2%s\n", RP);
1475 if (write(pfd, line, n) == n &&
1476 (resp = response()) == '\0')
1477 break;
1478 (void) close(pfd);
1480 if (i == 1) {
1481 if (resp < 0)
1482 pstatus("waiting for %s to come up", RM);
1483 else {
1484 pstatus("waiting for queue to be enabled on %s",
1485 RM);
1486 i = 256;
1489 sleep(i);
1491 pstatus("sending to %s", RM);
1494 static void
1495 alarmer(int s)
1497 /* nothing */
1500 #if !defined(__NetBSD__)
1501 struct bauds {
1502 int baud;
1503 int speed;
1504 } bauds[] = {
1505 50, B50,
1506 75, B75,
1507 110, B110,
1508 134, B134,
1509 150, B150,
1510 200, B200,
1511 300, B300,
1512 600, B600,
1513 1200, B1200,
1514 1800, B1800,
1515 2400, B2400,
1516 4800, B4800,
1517 9600, B9600,
1518 19200, B19200,
1519 38400, B38400,
1520 57600, B57600,
1521 115200, B115200,
1522 0, 0
1524 #endif
1527 * setup tty lines.
1529 static void
1530 setty(void)
1532 struct info i;
1533 char **argv, **ap, *p, *val;
1535 i.fd = pfd;
1536 i.set = i.wset = 0;
1537 if (ioctl(i.fd, TIOCEXCL, (char *)0) < 0) {
1538 syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer);
1539 exit(1);
1541 if (tcgetattr(i.fd, &i.t) < 0) {
1542 syslog(LOG_ERR, "%s: tcgetattr: %m", printer);
1543 exit(1);
1545 if (BR > 0) {
1546 #if !defined(__NetBSD__)
1547 struct bauds *bp;
1548 for (bp = bauds; bp->baud; bp++)
1549 if (BR == bp->baud)
1550 break;
1551 if (!bp->baud) {
1552 syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR);
1553 exit(1);
1555 cfsetspeed(&i.t, bp->speed);
1556 #else
1557 cfsetspeed(&i.t, BR);
1558 #endif
1559 i.set = 1;
1561 if (MS) {
1562 if (ioctl(i.fd, TIOCGETD, &i.ldisc) < 0) {
1563 syslog(LOG_ERR, "%s: ioctl(TIOCGETD): %m", printer);
1564 exit(1);
1566 if (ioctl(i.fd, TIOCGWINSZ, &i.win) < 0)
1567 syslog(LOG_INFO, "%s: ioctl(TIOCGWINSZ): %m",
1568 printer);
1570 argv = (char **)calloc(256, sizeof(char *));
1571 if (argv == NULL) {
1572 syslog(LOG_ERR, "%s: calloc: %m", printer);
1573 exit(1);
1575 p = strdup(MS);
1576 ap = argv;
1577 while ((val = strsep(&p, " \t,")) != NULL) {
1578 *ap++ = strdup(val);
1581 for (; *argv; ++argv) {
1582 if (ksearch(&argv, &i))
1583 continue;
1584 if (msearch(&argv, &i))
1585 continue;
1586 syslog(LOG_INFO, "%s: unknown stty flag: %s",
1587 printer, *argv);
1589 } else {
1590 if (FC) {
1591 sttyclearflags(&i.t, FC);
1592 i.set = 1;
1594 if (FS) {
1595 sttysetflags(&i.t, FS);
1596 i.set = 1;
1598 if (XC) {
1599 sttyclearlflags(&i.t, XC);
1600 i.set = 1;
1602 if (XS) {
1603 sttysetlflags(&i.t, XS);
1604 i.set = 1;
1608 if (i.set && tcsetattr(i.fd, TCSANOW, &i.t) < 0) {
1609 syslog(LOG_ERR, "%s: tcsetattr: %m", printer);
1610 exit(1);
1612 if (i.wset && ioctl(i.fd, TIOCSWINSZ, &i.win) < 0)
1613 syslog(LOG_INFO, "%s: ioctl(TIOCSWINSZ): %m", printer);
1614 return;
1617 #include <stdarg.h>
1619 static void
1620 pstatus(const char *msg, ...)
1622 int fd;
1623 char *buf;
1624 va_list ap;
1625 struct iovec iov[2];
1627 umask(0);
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);
1631 exit(1);
1633 ftruncate(fd, 0);
1634 va_start(ap, msg);
1635 (void)vasprintf(&buf, msg, ap);
1636 va_end(ap);
1638 iov[0].iov_base = buf;
1639 iov[0].iov_len = strlen(buf);
1640 iov[1].iov_base = __UNCONST("\n");
1641 iov[1].iov_len = 1;
1642 (void)writev(fd, iov, 2);
1643 (void)close(fd);
1644 free(buf);