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