Deleted Added
full compact
printjob.c (117554) printjob.c (117587)
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 const 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#if 0
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 const 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#if 0
42#ifndef lint
42static char sccsid[] = "@(#)printjob.c 8.7 (Berkeley) 5/10/95";
43static char sccsid[] = "@(#)printjob.c 8.7 (Berkeley) 5/10/95";
44#endif /* not lint */
43#endif
44
45#include "lp.cdefs.h" /* A cross-platform version of <sys/cdefs.h> */
45#endif
46
47#include "lp.cdefs.h" /* A cross-platform version of <sys/cdefs.h> */
46__FBSDID("$FreeBSD: head/usr.sbin/lpr/lpd/printjob.c 117554 2003-07-14 15:54:41Z gad $");
48__FBSDID("$FreeBSD: head/usr.sbin/lpr/lpd/printjob.c 117587 2003-07-14 19:59:33Z gad $");
47
48/*
49 * printjob -- print jobs in the queue.
50 *
51 * NOTE: the lock file is used to pass information to lpq and lprm.
52 * it does not need to be removed because file locks are dynamic.
53 */
54
55#include <sys/param.h>
56#include <sys/wait.h>
57#include <sys/stat.h>
58#include <sys/types.h>
59
60#include <pwd.h>
61#include <unistd.h>
62#include <signal.h>
63#include <syslog.h>
64#include <fcntl.h>
65#include <dirent.h>
66#include <errno.h>
67#include <stdio.h>
68#include <string.h>
69#include <stdlib.h>
70#include <sys/ioctl.h>
71#include <termios.h>
72#include <time.h>
73#include "lp.h"
74#include "lp.local.h"
75#include "pathnames.h"
76#include "extern.h"
77
78#define DORETURN 0 /* dofork should return "can't fork" error */
79#define DOABORT 1 /* dofork should just die if fork() fails */
80
81/*
82 * Error tokens
83 */
84#define REPRINT -2
85#define ERROR -1
86#define OK 0
87#define FATALERR 1
88#define NOACCT 2
89#define FILTERERR 3
90#define ACCESS 4
91
92static dev_t fdev; /* device of file pointed to by symlink */
93static ino_t fino; /* inode of file pointed to by symlink */
94static FILE *cfp; /* control file */
95static pid_t of_pid; /* process id of output filter, if any */
96static int child; /* id of any filters */
97static int job_dfcnt; /* count of datafiles in current user job */
98static int lfd; /* lock file descriptor */
99static int ofd; /* output filter file descriptor */
100static int tfd = -1; /* output filter temp file output */
101static int pfd; /* prstatic inter file descriptor */
102static int prchild; /* id of pr process */
103static char title[80]; /* ``pr'' title */
104static char locale[80]; /* ``pr'' locale */
105
106/* these two are set from pp->daemon_user, but only if they are needed */
107static char *daemon_uname; /* set from pwd->pw_name */
108static int daemon_defgid;
109
110static char class[32]; /* classification field */
111static char origin_host[MAXHOSTNAMELEN]; /* user's host machine */
112 /* indentation size in static characters */
113static char indent[10] = "-i0";
114static char jobname[100]; /* job or file name */
115static char length[10] = "-l"; /* page length in lines */
116static char logname[32]; /* user's login name */
117static char pxlength[10] = "-y"; /* page length in pixels */
118static char pxwidth[10] = "-x"; /* page width in pixels */
119/* tempstderr is the filename used to catch stderr from exec-ing filters */
120static char tempstderr[] = "errs.XXXXXXX";
121static char width[10] = "-w"; /* page width in static characters */
122#define TFILENAME "fltXXXXXX"
123static char tfile[] = TFILENAME; /* file name for filter output */
124
125static void abortpr(int _signo);
126static void alarmhandler(int _signo);
127static void banner(struct printer *_pp, char *_name1, char *_name2);
128static int dofork(const struct printer *_pp, int _action);
129static int dropit(int _c);
130static int execfilter(struct printer *_pp, char *_f_cmd, char **_f_av,
131 int _infd, int _outfd);
132static void init(struct printer *_pp);
133static void openpr(const struct printer *_pp);
134static void opennet(const struct printer *_pp);
135static void opentty(const struct printer *_pp);
136static void openrem(const struct printer *pp);
137static int print(struct printer *_pp, int _format, char *_file);
138static int printit(struct printer *_pp, char *_file);
139static void pstatus(const struct printer *_pp, const char *_msg, ...)
140 __printflike(2, 3);
141static char response(const struct printer *_pp);
142static void scan_out(struct printer *_pp, int _scfd, char *_scsp,
143 int _dlm);
144static char *scnline(int _key, char *_p, int _c);
145static int sendfile(struct printer *_pp, int _type, char *_file,
146 char _format, int _copyreq);
147static int sendit(struct printer *_pp, char *_file);
148static void sendmail(struct printer *_pp, char *_userid, int _bombed);
149static void setty(const struct printer *_pp);
150
151void
152printjob(struct printer *pp)
153{
154 struct stat stb;
155 register struct jobqueue *q, **qp;
156 struct jobqueue **queue;
157 register int i, nitems;
158 off_t pidoff;
159 pid_t printpid;
160 int errcnt, jobcount, tempfd;
161
162 jobcount = 0;
163 init(pp); /* set up capabilities */
164 (void) write(1, "", 1); /* ack that daemon is started */
165 (void) close(2); /* set up log file */
166 if (open(pp->log_file, O_WRONLY|O_APPEND, LOG_FILE_MODE) < 0) {
167 syslog(LOG_ERR, "%s: open(%s): %m", pp->printer,
168 pp->log_file);
169 (void) open(_PATH_DEVNULL, O_WRONLY);
170 }
171 setgid(getegid());
172 printpid = getpid(); /* for use with lprm */
173 setpgrp(0, printpid);
174
175 /*
176 * At initial lpd startup, printjob may be called with various
177 * signal handlers in effect. After that initial startup, any
178 * calls to printjob will have a *different* set of signal-handlers
179 * in effect. Make sure all handlers are the ones we want.
180 */
181 signal(SIGCHLD, SIG_DFL);
182 signal(SIGHUP, abortpr);
183 signal(SIGINT, abortpr);
184 signal(SIGQUIT, abortpr);
185 signal(SIGTERM, abortpr);
186
187 /*
188 * uses short form file names
189 */
190 if (chdir(pp->spool_dir) < 0) {
191 syslog(LOG_ERR, "%s: chdir(%s): %m", pp->printer,
192 pp->spool_dir);
193 exit(1);
194 }
195 if (stat(pp->lock_file, &stb) == 0 && (stb.st_mode & LFM_PRINT_DIS))
196 exit(0); /* printing disabled */
197 lfd = open(pp->lock_file, O_WRONLY|O_CREAT|O_EXLOCK|O_NONBLOCK,
198 LOCK_FILE_MODE);
199 if (lfd < 0) {
200 if (errno == EWOULDBLOCK) /* active daemon present */
201 exit(0);
202 syslog(LOG_ERR, "%s: open(%s): %m", pp->printer,
203 pp->lock_file);
204 exit(1);
205 }
206 /* turn off non-blocking mode (was turned on for lock effects only) */
207 if (fcntl(lfd, F_SETFL, 0) < 0) {
208 syslog(LOG_ERR, "%s: fcntl(%s): %m", pp->printer,
209 pp->lock_file);
210 exit(1);
211 }
212 ftruncate(lfd, 0);
213 /*
214 * write process id for others to know
215 */
216 sprintf(line, "%u\n", printpid);
217 pidoff = i = strlen(line);
218 if (write(lfd, line, i) != i) {
219 syslog(LOG_ERR, "%s: write(%s): %m", pp->printer,
220 pp->lock_file);
221 exit(1);
222 }
223 /*
224 * search the spool directory for work and sort by queue order.
225 */
226 if ((nitems = getq(pp, &queue)) < 0) {
227 syslog(LOG_ERR, "%s: can't scan %s", pp->printer,
228 pp->spool_dir);
229 exit(1);
230 }
231 if (nitems == 0) /* no work to do */
232 exit(0);
233 if (stb.st_mode & LFM_RESET_QUE) { /* reset queue flag */
234 if (fchmod(lfd, stb.st_mode & ~LFM_RESET_QUE) < 0)
235 syslog(LOG_ERR, "%s: fchmod(%s): %m", pp->printer,
236 pp->lock_file);
237 }
238
239 /* create a file which will be used to hold stderr from filters */
240 if ((tempfd = mkstemp(tempstderr)) == -1) {
241 syslog(LOG_ERR, "%s: mkstemp(%s): %m", pp->printer,
242 tempstderr);
243 exit(1);
244 }
245 if ((i = fchmod(tempfd, 0664)) == -1) {
246 syslog(LOG_ERR, "%s: fchmod(%s): %m", pp->printer,
247 tempstderr);
248 exit(1);
249 }
250 /* lpd doesn't need it to be open, it just needs it to exist */
251 close(tempfd);
252
253 openpr(pp); /* open printer or remote */
254again:
255 /*
256 * we found something to do now do it --
257 * write the name of the current control file into the lock file
258 * so the spool queue program can tell what we're working on
259 */
260 for (qp = queue; nitems--; free((char *) q)) {
261 q = *qp++;
262 if (stat(q->job_cfname, &stb) < 0)
263 continue;
264 errcnt = 0;
265 restart:
266 (void) lseek(lfd, pidoff, 0);
267 (void) snprintf(line, sizeof(line), "%s\n", q->job_cfname);
268 i = strlen(line);
269 if (write(lfd, line, i) != i)
270 syslog(LOG_ERR, "%s: write(%s): %m", pp->printer,
271 pp->lock_file);
272 if (!pp->remote)
273 i = printit(pp, q->job_cfname);
274 else
275 i = sendit(pp, q->job_cfname);
276 /*
277 * Check to see if we are supposed to stop printing or
278 * if we are to rebuild the queue.
279 */
280 if (fstat(lfd, &stb) == 0) {
281 /* stop printing before starting next job? */
282 if (stb.st_mode & LFM_PRINT_DIS)
283 goto done;
284 /* rebuild queue (after lpc topq) */
285 if (stb.st_mode & LFM_RESET_QUE) {
286 for (free(q); nitems--; free(q))
287 q = *qp++;
288 if (fchmod(lfd, stb.st_mode & ~LFM_RESET_QUE)
289 < 0)
290 syslog(LOG_WARNING,
291 "%s: fchmod(%s): %m",
292 pp->printer, pp->lock_file);
293 break;
294 }
295 }
296 if (i == OK) /* all files of this job printed */
297 jobcount++;
298 else if (i == REPRINT && ++errcnt < 5) {
299 /* try reprinting the job */
300 syslog(LOG_INFO, "restarting %s", pp->printer);
301 if (of_pid > 0) {
302 kill(of_pid, SIGCONT); /* to be sure */
303 (void) close(ofd);
304 while ((i = wait(NULL)) > 0 && i != of_pid)
305 ;
306 if (i < 0)
307 syslog(LOG_WARNING, "%s: after kill(of=%d), wait() returned: %m",
308 pp->printer, of_pid);
309 of_pid = 0;
310 }
311 (void) close(pfd); /* close printer */
312 if (ftruncate(lfd, pidoff) < 0)
313 syslog(LOG_WARNING, "%s: ftruncate(%s): %m",
314 pp->printer, pp->lock_file);
315 openpr(pp); /* try to reopen printer */
316 goto restart;
317 } else {
318 syslog(LOG_WARNING, "%s: job could not be %s (%s)",
319 pp->printer,
320 pp->remote ? "sent to remote host" : "printed",
321 q->job_cfname);
322 if (i == REPRINT) {
323 /* ensure we don't attempt this job again */
324 (void) unlink(q->job_cfname);
325 q->job_cfname[0] = 'd';
326 (void) unlink(q->job_cfname);
327 if (logname[0])
328 sendmail(pp, logname, FATALERR);
329 }
330 }
331 }
332 free(queue);
333 /*
334 * search the spool directory for more work.
335 */
336 if ((nitems = getq(pp, &queue)) < 0) {
337 syslog(LOG_ERR, "%s: can't scan %s", pp->printer,
338 pp->spool_dir);
339 exit(1);
340 }
341 if (nitems == 0) { /* no more work to do */
342 done:
343 if (jobcount > 0) { /* jobs actually printed */
344 if (!pp->no_formfeed && !pp->tof)
345 (void) write(ofd, pp->form_feed,
346 strlen(pp->form_feed));
347 if (pp->trailer != NULL) /* output trailer */
348 (void) write(ofd, pp->trailer,
349 strlen(pp->trailer));
350 }
351 (void) close(ofd);
352 (void) wait(NULL);
353 (void) unlink(tempstderr);
354 exit(0);
355 }
356 goto again;
357}
358
359char fonts[4][50]; /* fonts for troff */
360
361char ifonts[4][40] = {
362 _PATH_VFONTR,
363 _PATH_VFONTI,
364 _PATH_VFONTB,
365 _PATH_VFONTS,
366};
367
368/*
369 * The remaining part is the reading of the control file (cf)
370 * and performing the various actions.
371 */
372static int
373printit(struct printer *pp, char *file)
374{
375 register int i;
376 char *cp;
377 int bombed, didignorehdr;
378
379 bombed = OK;
380 didignorehdr = 0;
381 /*
382 * open control file; ignore if no longer there.
383 */
384 if ((cfp = fopen(file, "r")) == NULL) {
385 syslog(LOG_INFO, "%s: fopen(%s): %m", pp->printer, file);
386 return (OK);
387 }
388 /*
389 * Reset troff fonts.
390 */
391 for (i = 0; i < 4; i++)
392 strcpy(fonts[i], ifonts[i]);
393 sprintf(&width[2], "%ld", pp->page_width);
394 strcpy(indent+2, "0");
395
396 /* initialize job-specific count of datafiles processed */
397 job_dfcnt = 0;
398
399 /*
400 * read the control file for work to do
401 *
402 * file format -- first character in the line is a command
403 * rest of the line is the argument.
404 * valid commands are:
405 *
406 * S -- "stat info" for symbolic link protection
407 * J -- "job name" on banner page
408 * C -- "class name" on banner page
409 * L -- "literal" user's name to print on banner
410 * T -- "title" for pr
411 * H -- "host name" of machine where lpr was done
412 * P -- "person" user's login name
413 * I -- "indent" amount to indent output
414 * R -- laser dpi "resolution"
415 * f -- "file name" name of text file to print
416 * l -- "file name" text file with control chars
417 * o -- "file name" postscript file, according to
418 * the RFC. Here it is treated like an 'f'.
419 * p -- "file name" text file to print with pr(1)
420 * t -- "file name" troff(1) file to print
421 * n -- "file name" ditroff(1) file to print
422 * d -- "file name" dvi file to print
423 * g -- "file name" plot(1G) file to print
424 * v -- "file name" plain raster file to print
425 * c -- "file name" cifplot file to print
426 * 1 -- "R font file" for troff
427 * 2 -- "I font file" for troff
428 * 3 -- "B font file" for troff
429 * 4 -- "S font file" for troff
430 * N -- "name" of file (used by lpq)
431 * U -- "unlink" name of file to remove
432 * (after we print it. (Pass 2 only)).
433 * M -- "mail" to user when done printing
434 * Z -- "locale" for pr
435 *
436 * getline reads a line and expands tabs to blanks
437 */
438
439 /* pass 1 */
440
441 while (getline(cfp))
442 switch (line[0]) {
443 case 'H':
444 strlcpy(origin_host, line + 1, sizeof(origin_host));
445 if (class[0] == '\0') {
446 strlcpy(class, line+1, sizeof(class));
447 }
448 continue;
449
450 case 'P':
451 strlcpy(logname, line + 1, sizeof(logname));
452 if (pp->restricted) { /* restricted */
453 if (getpwnam(logname) == NULL) {
454 bombed = NOACCT;
455 sendmail(pp, line+1, bombed);
456 goto pass2;
457 }
458 }
459 continue;
460
461 case 'S':
462 cp = line+1;
463 i = 0;
464 while (*cp >= '0' && *cp <= '9')
465 i = i * 10 + (*cp++ - '0');
466 fdev = i;
467 cp++;
468 i = 0;
469 while (*cp >= '0' && *cp <= '9')
470 i = i * 10 + (*cp++ - '0');
471 fino = i;
472 continue;
473
474 case 'J':
475 if (line[1] != '\0') {
476 strlcpy(jobname, line + 1, sizeof(jobname));
477 } else
478 strcpy(jobname, " ");
479 continue;
480
481 case 'C':
482 if (line[1] != '\0')
483 strlcpy(class, line + 1, sizeof(class));
484 else if (class[0] == '\0') {
485 /* XXX - why call gethostname instead of
486 * just strlcpy'ing local_host? */
487 gethostname(class, sizeof(class));
488 class[sizeof(class) - 1] = '\0';
489 }
490 continue;
491
492 case 'T': /* header title for pr */
493 strlcpy(title, line + 1, sizeof(title));
494 continue;
495
496 case 'L': /* identification line */
497 if (!pp->no_header && !pp->header_last)
498 banner(pp, line+1, jobname);
499 continue;
500
501 case '1': /* troff fonts */
502 case '2':
503 case '3':
504 case '4':
505 if (line[1] != '\0') {
506 strlcpy(fonts[line[0]-'1'], line + 1,
507 (size_t)50);
508 }
509 continue;
510
511 case 'W': /* page width */
512 strlcpy(width+2, line + 1, sizeof(width) - 2);
513 continue;
514
515 case 'I': /* indent amount */
516 strlcpy(indent+2, line + 1, sizeof(indent) - 2);
517 continue;
518
519 case 'Z': /* locale for pr */
520 strlcpy(locale, line + 1, sizeof(locale));
521 continue;
522
523 default: /* some file to print */
524 /* only lowercase cmd-codes include a file-to-print */
525 if ((line[0] < 'a') || (line[0] > 'z')) {
526 /* ignore any other lines */
527 if (lflag <= 1)
528 continue;
529 if (!didignorehdr) {
530 syslog(LOG_INFO, "%s: in %s :",
531 pp->printer, file);
532 didignorehdr = 1;
533 }
534 syslog(LOG_INFO, "%s: ignoring line: '%c' %s",
535 pp->printer, line[0], &line[1]);
536 continue;
537 }
538 i = print(pp, line[0], line+1);
539 switch (i) {
540 case ERROR:
541 if (bombed == OK)
542 bombed = FATALERR;
543 break;
544 case REPRINT:
545 (void) fclose(cfp);
546 return (REPRINT);
547 case FILTERERR:
548 case ACCESS:
549 bombed = i;
550 sendmail(pp, logname, bombed);
551 }
552 title[0] = '\0';
553 continue;
554
555 case 'N':
556 case 'U':
557 case 'M':
558 case 'R':
559 continue;
560 }
561
562 /* pass 2 */
563
564pass2:
565 fseek(cfp, 0L, 0);
566 while (getline(cfp))
567 switch (line[0]) {
568 case 'L': /* identification line */
569 if (!pp->no_header && pp->header_last)
570 banner(pp, line+1, jobname);
571 continue;
572
573 case 'M':
574 if (bombed < NOACCT) /* already sent if >= NOACCT */
575 sendmail(pp, line+1, bombed);
576 continue;
577
578 case 'U':
579 if (strchr(line+1, '/'))
580 continue;
581 (void) unlink(line+1);
582 }
583 /*
584 * clean-up in case another control file exists
585 */
586 (void) fclose(cfp);
587 (void) unlink(file);
588 return (bombed == OK ? OK : ERROR);
589}
590
591/*
592 * Print a file.
593 * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}.
594 * Return -1 if a non-recoverable error occured,
595 * 2 if the filter detected some errors (but printed the job anyway),
596 * 1 if we should try to reprint this job and
597 * 0 if all is well.
598 * Note: all filters take stdin as the file, stdout as the printer,
599 * stderr as the log file, and must not ignore SIGINT.
600 */
601static int
602print(struct printer *pp, int format, char *file)
603{
604 register int n, i;
605 register char *prog;
606 int fi, fo;
607 FILE *fp;
608 char *av[15], buf[BUFSIZ];
609 pid_t wpid;
610 int p[2], retcode, stopped, wstatus, wstatus_set;
611 struct stat stb;
612
613 if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0) {
614 syslog(LOG_INFO, "%s: unable to open %s ('%c' line)",
615 pp->printer, file, format);
616 return (ERROR);
617 }
618 /*
619 * Check to see if data file is a symbolic link. If so, it should
620 * still point to the same file or someone is trying to print
621 * something he shouldn't.
622 */
623 if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 &&
624 (stb.st_dev != fdev || stb.st_ino != fino))
625 return (ACCESS);
626
627 job_dfcnt++; /* increment datafile counter for this job */
628 stopped = 0; /* output filter is not stopped */
629
630 /* everything seems OK, start it up */
631 if (!pp->no_formfeed && !pp->tof) { /* start on a fresh page */
632 (void) write(ofd, pp->form_feed, strlen(pp->form_feed));
633 pp->tof = 1;
634 }
635 if (pp->filters[LPF_INPUT] == NULL
636 && (format == 'f' || format == 'l' || format == 'o')) {
637 pp->tof = 0;
638 while ((n = read(fi, buf, BUFSIZ)) > 0)
639 if (write(ofd, buf, n) != n) {
640 (void) close(fi);
641 return (REPRINT);
642 }
643 (void) close(fi);
644 return (OK);
645 }
646 switch (format) {
647 case 'p': /* print file using 'pr' */
648 if (pp->filters[LPF_INPUT] == NULL) { /* use output filter */
649 prog = _PATH_PR;
650 i = 0;
651 av[i++] = "pr";
652 av[i++] = width;
653 av[i++] = length;
654 av[i++] = "-h";
655 av[i++] = *title ? title : " ";
656 av[i++] = "-L";
657 av[i++] = *locale ? locale : "C";
658 av[i++] = "-F";
659 av[i] = 0;
660 fo = ofd;
661 goto start;
662 }
663 pipe(p);
664 if ((prchild = dofork(pp, DORETURN)) == 0) { /* child */
665 dup2(fi, 0); /* file is stdin */
666 dup2(p[1], 1); /* pipe is stdout */
667 closelog();
668 closeallfds(3);
669 execl(_PATH_PR, "pr", width, length,
670 "-h", *title ? title : " ",
671 "-L", *locale ? locale : "C",
672 "-F", (char *)0);
673 syslog(LOG_ERR, "cannot execl %s", _PATH_PR);
674 exit(2);
675 }
676 (void) close(p[1]); /* close output side */
677 (void) close(fi);
678 if (prchild < 0) {
679 prchild = 0;
680 (void) close(p[0]);
681 return (ERROR);
682 }
683 fi = p[0]; /* use pipe for input */
684 case 'f': /* print plain text file */
685 prog = pp->filters[LPF_INPUT];
686 av[1] = width;
687 av[2] = length;
688 av[3] = indent;
689 n = 4;
690 break;
691 case 'o': /* print postscript file */
692 /*
693 * Treat this as a "plain file with control characters", and
694 * assume the standard LPF_INPUT filter will recognize that
695 * the data is postscript and know what to do with it. These
696 * 'o'-file requests could come from MacOS 10.1 systems.
697 * (later versions of MacOS 10 will explicitly use 'l')
698 * A postscript file can contain binary data, which is why 'l'
699 * is somewhat more appropriate than 'f'.
700 */
701 /* FALLTHROUGH */
702 case 'l': /* like 'f' but pass control characters */
703 prog = pp->filters[LPF_INPUT];
704 av[1] = "-c";
705 av[2] = width;
706 av[3] = length;
707 av[4] = indent;
708 n = 5;
709 break;
710 case 'r': /* print a fortran text file */
711 prog = pp->filters[LPF_FORTRAN];
712 av[1] = width;
713 av[2] = length;
714 n = 3;
715 break;
716 case 't': /* print troff output */
717 case 'n': /* print ditroff output */
718 case 'd': /* print tex output */
719 (void) unlink(".railmag");
720 if ((fo = creat(".railmag", FILMOD)) < 0) {
721 syslog(LOG_ERR, "%s: cannot create .railmag",
722 pp->printer);
723 (void) unlink(".railmag");
724 } else {
725 for (n = 0; n < 4; n++) {
726 if (fonts[n][0] != '/')
727 (void) write(fo, _PATH_VFONT,
728 sizeof(_PATH_VFONT) - 1);
729 (void) write(fo, fonts[n], strlen(fonts[n]));
730 (void) write(fo, "\n", 1);
731 }
732 (void) close(fo);
733 }
734 prog = (format == 't') ? pp->filters[LPF_TROFF]
735 : ((format == 'n') ? pp->filters[LPF_DITROFF]
736 : pp->filters[LPF_DVI]);
737 av[1] = pxwidth;
738 av[2] = pxlength;
739 n = 3;
740 break;
741 case 'c': /* print cifplot output */
742 prog = pp->filters[LPF_CIFPLOT];
743 av[1] = pxwidth;
744 av[2] = pxlength;
745 n = 3;
746 break;
747 case 'g': /* print plot(1G) output */
748 prog = pp->filters[LPF_GRAPH];
749 av[1] = pxwidth;
750 av[2] = pxlength;
751 n = 3;
752 break;
753 case 'v': /* print raster output */
754 prog = pp->filters[LPF_RASTER];
755 av[1] = pxwidth;
756 av[2] = pxlength;
757 n = 3;
758 break;
759 default:
760 (void) close(fi);
761 syslog(LOG_ERR, "%s: illegal format character '%c'",
762 pp->printer, format);
763 return (ERROR);
764 }
765 if (prog == NULL) {
766 (void) close(fi);
767 syslog(LOG_ERR,
768 "%s: no filter found in printcap for format character '%c'",
769 pp->printer, format);
770 return (ERROR);
771 }
772 if ((av[0] = strrchr(prog, '/')) != NULL)
773 av[0]++;
774 else
775 av[0] = prog;
776 av[n++] = "-n";
777 av[n++] = logname;
778 av[n++] = "-h";
779 av[n++] = origin_host;
780 av[n++] = pp->acct_file;
781 av[n] = 0;
782 fo = pfd;
783 if (of_pid > 0) { /* stop output filter */
784 write(ofd, "\031\1", 2);
785 while ((wpid =
786 wait3(&wstatus, WUNTRACED, 0)) > 0 && wpid != of_pid)
787 ;
788 if (wpid < 0)
789 syslog(LOG_WARNING,
790 "%s: after stopping 'of', wait3() returned: %m",
791 pp->printer);
792 else if (!WIFSTOPPED(wstatus)) {
793 (void) close(fi);
794 syslog(LOG_WARNING, "%s: output filter died "
795 "(pid=%d retcode=%d termsig=%d)",
796 pp->printer, of_pid, WEXITSTATUS(wstatus),
797 WTERMSIG(wstatus));
798 return (REPRINT);
799 }
800 stopped++;
801 }
802start:
803 if ((child = dofork(pp, DORETURN)) == 0) { /* child */
804 dup2(fi, 0);
805 dup2(fo, 1);
806 /* setup stderr for the filter (child process)
807 * so it goes to our temporary errors file */
808 n = open(tempstderr, O_WRONLY|O_TRUNC, 0664);
809 if (n >= 0)
810 dup2(n, 2);
811 closelog();
812 closeallfds(3);
813 execv(prog, av);
814 syslog(LOG_ERR, "%s: cannot execv(%s): %m", pp->printer,
815 prog);
816 exit(2);
817 }
818 (void) close(fi);
819 wstatus_set = 0;
820 if (child < 0)
821 retcode = 100;
822 else {
823 while ((wpid = wait(&wstatus)) > 0 && wpid != child)
824 ;
825 if (wpid < 0) {
826 retcode = 100;
827 syslog(LOG_WARNING,
828 "%s: after execv(%s), wait() returned: %m",
829 pp->printer, prog);
830 } else {
831 wstatus_set = 1;
832 retcode = WEXITSTATUS(wstatus);
833 }
834 }
835 child = 0;
836 prchild = 0;
837 if (stopped) { /* restart output filter */
838 if (kill(of_pid, SIGCONT) < 0) {
839 syslog(LOG_ERR, "cannot restart output filter");
840 exit(1);
841 }
842 }
843 pp->tof = 0;
844
845 /* Copy the filter's output to "lf" logfile */
846 if ((fp = fopen(tempstderr, "r"))) {
847 while (fgets(buf, sizeof(buf), fp))
848 fputs(buf, stderr);
849 fclose(fp);
850 }
851
852 if (wstatus_set && !WIFEXITED(wstatus)) {
853 syslog(LOG_WARNING, "%s: filter '%c' terminated (termsig=%d)",
854 pp->printer, format, WTERMSIG(wstatus));
855 return (ERROR);
856 }
857 switch (retcode) {
858 case 0:
859 pp->tof = 1;
860 return (OK);
861 case 1:
862 return (REPRINT);
863 case 2:
864 return (ERROR);
865 default:
866 syslog(LOG_WARNING, "%s: filter '%c' exited (retcode=%d)",
867 pp->printer, format, retcode);
868 return (FILTERERR);
869 }
870}
871
872/*
873 * Send the daemon control file (cf) and any data files.
874 * Return -1 if a non-recoverable error occured, 1 if a recoverable error and
875 * 0 if all is well.
876 */
877static int
878sendit(struct printer *pp, char *file)
879{
880 int dfcopies, err, i;
881 char *cp, last[BUFSIZ];
882
883 /*
884 * open control file
885 */
886 if ((cfp = fopen(file, "r")) == NULL)
887 return (OK);
888
889 /* initialize job-specific count of datafiles processed */
890 job_dfcnt = 0;
891
892 /*
893 * read the control file for work to do
894 *
895 * file format -- first character in the line is a command
896 * rest of the line is the argument.
897 * commands of interest are:
898 *
899 * a-z -- "file name" name of file to print
900 * U -- "unlink" name of file to remove
901 * (after we print it. (Pass 2 only)).
902 */
903
904 /*
905 * pass 1
906 */
907 err = OK;
908 while (getline(cfp)) {
909 again:
910 if (line[0] == 'S') {
911 cp = line+1;
912 i = 0;
913 while (*cp >= '0' && *cp <= '9')
914 i = i * 10 + (*cp++ - '0');
915 fdev = i;
916 cp++;
917 i = 0;
918 while (*cp >= '0' && *cp <= '9')
919 i = i * 10 + (*cp++ - '0');
920 fino = i;
921 } else if (line[0] == 'H') {
922 strlcpy(origin_host, line + 1, sizeof(origin_host));
923 if (class[0] == '\0') {
924 strlcpy(class, line + 1, sizeof(class));
925 }
926 } else if (line[0] == 'P') {
927 strlcpy(logname, line + 1, sizeof(logname));
928 if (pp->restricted) { /* restricted */
929 if (getpwnam(logname) == NULL) {
930 sendmail(pp, line+1, NOACCT);
931 err = ERROR;
932 break;
933 }
934 }
935 } else if (line[0] == 'I') {
936 strlcpy(indent+2, line + 1, sizeof(indent) - 2);
937 } else if (line[0] >= 'a' && line[0] <= 'z') {
938 dfcopies = 1;
939 strcpy(last, line);
940 while ((i = getline(cfp)) != 0) {
941 if (strcmp(last, line) != 0)
942 break;
943 dfcopies++;
944 }
945 switch (sendfile(pp, '\3', last+1, *last, dfcopies)) {
946 case OK:
947 if (i)
948 goto again;
949 break;
950 case REPRINT:
951 (void) fclose(cfp);
952 return (REPRINT);
953 case ACCESS:
954 sendmail(pp, logname, ACCESS);
955 case ERROR:
956 err = ERROR;
957 }
958 break;
959 }
960 }
961 if (err == OK && sendfile(pp, '\2', file, '\0', 1) > 0) {
962 (void) fclose(cfp);
963 return (REPRINT);
964 }
965 /*
966 * pass 2
967 */
968 fseek(cfp, 0L, 0);
969 while (getline(cfp))
970 if (line[0] == 'U' && !strchr(line+1, '/'))
971 (void) unlink(line+1);
972 /*
973 * clean-up in case another control file exists
974 */
975 (void) fclose(cfp);
976 (void) unlink(file);
977 return (err);
978}
979
980/*
981 * Send a data file to the remote machine and spool it.
982 * Return positive if we should try resending.
983 */
984static int
985sendfile(struct printer *pp, int type, char *file, char format, int copyreq)
986{
987 int i, amt;
988 struct stat stb;
989 char *av[15], *filtcmd;
990 char buf[BUFSIZ], opt_c[4], opt_h[4], opt_n[4];
991 int copycnt, filtstat, narg, resp, sfd, sfres, sizerr, statrc;
992
993 statrc = lstat(file, &stb);
994 if (statrc < 0) {
995 syslog(LOG_ERR, "%s: error from lstat(%s): %m",
996 pp->printer, file);
997 return (ERROR);
998 }
999 sfd = open(file, O_RDONLY);
1000 if (sfd < 0) {
1001 syslog(LOG_ERR, "%s: error from open(%s,O_RDONLY): %m",
1002 pp->printer, file);
1003 return (ERROR);
1004 }
1005 /*
1006 * Check to see if data file is a symbolic link. If so, it should
1007 * still point to the same file or someone is trying to print something
1008 * he shouldn't.
1009 */
1010 if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(sfd, &stb) == 0 &&
1011 (stb.st_dev != fdev || stb.st_ino != fino)) {
1012 close(sfd);
1013 return (ACCESS);
1014 }
1015
1016 /* Everything seems OK for reading the file, now to send it */
1017 filtcmd = NULL;
1018 sizerr = 0;
1019 tfd = -1;
1020 if (type == '\3') {
1021 /*
1022 * Type == 3 means this is a datafile, not a control file.
1023 * Increment the counter of data-files in this job, and
1024 * then check for input or output filters (which are only
1025 * applied to datafiles, not control files).
1026 */
1027 job_dfcnt++;
1028
1029 /*
1030 * Note that here we are filtering datafiles, one at a time,
1031 * as they are sent to the remote machine. Here, the *only*
1032 * difference between an input filter (`if=') and an output
1033 * filter (`of=') is the argument list that the filter is
1034 * started up with. Here, the output filter is executed
1035 * for each individual file as it is sent. This is not the
1036 * same as local print queues, where the output filter is
1037 * started up once, and then all jobs are passed thru that
1038 * single invocation of the output filter.
1039 *
1040 * Also note that a queue for a remote-machine can have an
1041 * input filter or an output filter, but not both.
1042 */
1043 if (pp->filters[LPF_INPUT]) {
1044 filtcmd = pp->filters[LPF_INPUT];
1045 av[0] = filtcmd;
1046 narg = 0;
1047 strcpy(opt_c, "-c");
1048 strcpy(opt_h, "-h");
1049 strcpy(opt_n, "-n");
1050 if (format == 'l')
1051 av[++narg] = opt_c;
1052 av[++narg] = width;
1053 av[++narg] = length;
1054 av[++narg] = indent;
1055 av[++narg] = opt_n;
1056 av[++narg] = logname;
1057 av[++narg] = opt_h;
1058 av[++narg] = origin_host;
1059 av[++narg] = pp->acct_file;
1060 av[++narg] = NULL;
1061 } else if (pp->filters[LPF_OUTPUT]) {
1062 filtcmd = pp->filters[LPF_OUTPUT];
1063 av[0] = filtcmd;
1064 narg = 0;
1065 av[++narg] = width;
1066 av[++narg] = length;
1067 av[++narg] = NULL;
1068 }
1069 }
1070 if (filtcmd) {
1071 /*
1072 * If there is an input or output filter, we have to run
1073 * the datafile thru that filter and store the result as
1074 * a temporary spool file, because the protocol requires
1075 * that we send the remote host the file-size before we
1076 * start to send any of the data.
1077 */
1078 strcpy(tfile, TFILENAME);
1079 tfd = mkstemp(tfile);
1080 if (tfd == -1) {
1081 syslog(LOG_ERR, "%s: mkstemp(%s): %m", pp->printer,
1082 TFILENAME);
1083 sfres = ERROR;
1084 goto return_sfres;
1085 }
1086 filtstat = execfilter(pp, filtcmd, av, sfd, tfd);
1087
1088 /* process the return-code from the filter */
1089 switch (filtstat) {
1090 case 0:
1091 break;
1092 case 1:
1093 sfres = REPRINT;
1094 goto return_sfres;
1095 case 2:
1096 sfres = ERROR;
1097 goto return_sfres;
1098 default:
1099 syslog(LOG_WARNING,
1100 "%s: filter '%c' exited (retcode=%d)",
1101 pp->printer, format, filtstat);
1102 sfres = FILTERERR;
1103 goto return_sfres;
1104 }
1105 statrc = fstat(tfd, &stb); /* to find size of tfile */
1106 if (statrc < 0) {
1107 syslog(LOG_ERR,
1108 "%s: error processing 'if', fstat(%s): %m",
1109 pp->printer, tfile);
1110 sfres = ERROR;
1111 goto return_sfres;
1112 }
1113 close(sfd);
1114 sfd = tfd;
1115 lseek(sfd, 0, SEEK_SET);
1116 }
1117
1118 copycnt = 0;
1119sendagain:
1120 copycnt++;
1121
1122 if (copycnt < 2)
1123 (void) sprintf(buf, "%c%qd %s\n", type, stb.st_size, file);
1124 else
1125 (void) sprintf(buf, "%c%qd %s_c%d\n", type, stb.st_size,
1126 file, copycnt);
1127 amt = strlen(buf);
1128 for (i = 0; ; i++) {
1129 if (write(pfd, buf, amt) != amt ||
1130 (resp = response(pp)) < 0 || resp == '\1') {
1131 sfres = REPRINT;
1132 goto return_sfres;
1133 } else if (resp == '\0')
1134 break;
1135 if (i == 0)
1136 pstatus(pp,
1137 "no space on remote; waiting for queue to drain");
1138 if (i == 10)
1139 syslog(LOG_ALERT, "%s: can't send to %s; queue full",
1140 pp->printer, pp->remote_host);
1141 sleep(5 * 60);
1142 }
1143 if (i)
1144 pstatus(pp, "sending to %s", pp->remote_host);
1145 /*
1146 * XXX - we should change trstat_init()/trstat_write() to include
1147 * the copycnt in the statistics record it may write.
1148 */
1149 if (type == '\3')
1150 trstat_init(pp, file, job_dfcnt);
1151 for (i = 0; i < stb.st_size; i += BUFSIZ) {
1152 amt = BUFSIZ;
1153 if (i + amt > stb.st_size)
1154 amt = stb.st_size - i;
1155 if (sizerr == 0 && read(sfd, buf, amt) != amt)
1156 sizerr = 1;
1157 if (write(pfd, buf, amt) != amt) {
1158 sfres = REPRINT;
1159 goto return_sfres;
1160 }
1161 }
1162
1163 if (sizerr) {
1164 syslog(LOG_INFO, "%s: %s: changed size", pp->printer, file);
1165 /* tell recvjob to ignore this file */
1166 (void) write(pfd, "\1", 1);
1167 sfres = ERROR;
1168 goto return_sfres;
1169 }
1170 if (write(pfd, "", 1) != 1 || response(pp)) {
1171 sfres = REPRINT;
1172 goto return_sfres;
1173 }
1174 if (type == '\3') {
1175 trstat_write(pp, TR_SENDING, stb.st_size, logname,
1176 pp->remote_host, origin_host);
1177 /*
1178 * Usually we only need to send one copy of a datafile,
1179 * because the control-file will simply print the same
1180 * file multiple times. However, some printers ignore
1181 * the control file, and simply print each data file as
1182 * it arrives. For such "remote hosts", we need to
1183 * transfer the same data file multiple times. Such a
1184 * a host is indicated by adding 'rc' to the printcap
1185 * entry.
1186 * XXX - Right now this ONLY works for remote hosts which
1187 * do ignore the name of the data file, because
1188 * this sends the file multiple times with slight
1189 * changes to the filename. To do this right would
1190 * require that we also rewrite the control file
1191 * to match those filenames.
1192 */
1193 if (pp->resend_copies && (copycnt < copyreq)) {
1194 lseek(sfd, 0, SEEK_SET);
1195 goto sendagain;
1196 }
1197 }
1198 sfres = OK;
1199
1200return_sfres:
1201 (void)close(sfd);
1202 if (tfd != -1) {
1203 /*
1204 * If tfd is set, then it is the same value as sfd, and
1205 * therefore it is already closed at this point. All
1206 * we need to do is remove the temporary file.
1207 */
1208 tfd = -1;
1209 unlink(tfile);
1210 }
1211 return (sfres);
1212}
1213
1214/*
1215 * This routine is called to execute one of the filters as was
1216 * specified in a printcap entry. While the child-process will read
1217 * all of 'infd', it is up to the caller to close that file descriptor
1218 * in the parent process.
1219 */
1220static int
1221execfilter(struct printer *pp, char *f_cmd, char *f_av[], int infd, int outfd)
1222{
1223 pid_t fpid, wpid;
1224 int errfd, retcode, wstatus;
1225 FILE *errfp;
1226 char buf[BUFSIZ], *slash;
1227
1228 fpid = dofork(pp, DORETURN);
1229 if (fpid != 0) {
1230 /*
1231 * This is the parent process, which just waits for the child
1232 * to complete and then returns the result. Note that it is
1233 * the child process which reads the input stream.
1234 */
1235 if (fpid < 0)
1236 retcode = 100;
1237 else {
1238 while ((wpid = wait(&wstatus)) > 0 &&
1239 wpid != fpid)
1240 ;
1241 if (wpid < 0) {
1242 retcode = 100;
1243 syslog(LOG_WARNING,
1244 "%s: after execv(%s), wait() returned: %m",
1245 pp->printer, f_cmd);
1246 } else
1247 retcode = WEXITSTATUS(wstatus);
1248 }
1249
1250 /*
1251 * Copy everything the filter wrote to stderr from our
1252 * temporary errors file to the "lf=" logfile.
1253 */
1254 errfp = fopen(tempstderr, "r");
1255 if (errfp) {
1256 while (fgets(buf, sizeof(buf), errfp))
1257 fputs(buf, stderr);
1258 fclose(errfp);
1259 }
1260
1261 return (retcode);
1262 }
1263
1264 /*
1265 * This is the child process, which is the one that executes the
1266 * given filter.
1267 */
1268 /*
1269 * If the first parameter has any slashes in it, then change it
1270 * to point to the first character after the last slash.
1271 */
1272 slash = strrchr(f_av[0], '/');
1273 if (slash != NULL)
1274 f_av[0] = slash + 1;
1275 /*
1276 * XXX - in the future, this should setup an explicit list of
1277 * environment variables and use execve()!
1278 */
1279
1280 /*
1281 * Setup stdin, stdout, and stderr as we want them when the filter
1282 * is running. Stderr is setup so it points to a temporary errors
1283 * file, and the parent process will copy that temporary file to
1284 * the real logfile after the filter completes.
1285 */
1286 dup2(infd, 0);
1287 dup2(outfd, 1);
1288 errfd = open(tempstderr, O_WRONLY|O_TRUNC, 0664);
1289 if (errfd >= 0)
1290 dup2(errfd, 2);
1291 closelog();
1292 closeallfds(3);
1293 execv(f_cmd, f_av);
1294 syslog(LOG_ERR, "%s: cannot execv(%s): %m", pp->printer, f_cmd);
1295 exit(2);
1296 /* NOTREACHED */
1297}
1298
1299/*
1300 * Check to make sure there have been no errors and that both programs
1301 * are in sync with eachother.
1302 * Return non-zero if the connection was lost.
1303 */
1304static char
1305response(const struct printer *pp)
1306{
1307 char resp;
1308
1309 if (read(pfd, &resp, 1) != 1) {
1310 syslog(LOG_INFO, "%s: lost connection", pp->printer);
1311 return (-1);
1312 }
1313 return (resp);
1314}
1315
1316/*
1317 * Banner printing stuff
1318 */
1319static void
1320banner(struct printer *pp, char *name1, char *name2)
1321{
1322 time_t tvec;
1323
1324 time(&tvec);
1325 if (!pp->no_formfeed && !pp->tof)
1326 (void) write(ofd, pp->form_feed, strlen(pp->form_feed));
1327 if (pp->short_banner) { /* short banner only */
1328 if (class[0]) {
1329 (void) write(ofd, class, strlen(class));
1330 (void) write(ofd, ":", 1);
1331 }
1332 (void) write(ofd, name1, strlen(name1));
1333 (void) write(ofd, " Job: ", 7);
1334 (void) write(ofd, name2, strlen(name2));
1335 (void) write(ofd, " Date: ", 8);
1336 (void) write(ofd, ctime(&tvec), 24);
1337 (void) write(ofd, "\n", 1);
1338 } else { /* normal banner */
1339 (void) write(ofd, "\n\n\n", 3);
1340 scan_out(pp, ofd, name1, '\0');
1341 (void) write(ofd, "\n\n", 2);
1342 scan_out(pp, ofd, name2, '\0');
1343 if (class[0]) {
1344 (void) write(ofd,"\n\n\n",3);
1345 scan_out(pp, ofd, class, '\0');
1346 }
1347 (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15);
1348 (void) write(ofd, name2, strlen(name2));
1349 (void) write(ofd, "\n\t\t\t\t\tDate: ", 12);
1350 (void) write(ofd, ctime(&tvec), 24);
1351 (void) write(ofd, "\n", 1);
1352 }
1353 if (!pp->no_formfeed)
1354 (void) write(ofd, pp->form_feed, strlen(pp->form_feed));
1355 pp->tof = 1;
1356}
1357
1358static char *
1359scnline(int key, char *p, int c)
1360{
1361 register int scnwidth;
1362
1363 for (scnwidth = WIDTH; --scnwidth;) {
1364 key <<= 1;
1365 *p++ = key & 0200 ? c : BACKGND;
1366 }
1367 return (p);
1368}
1369
1370#define TRC(q) (((q)-' ')&0177)
1371
1372static void
1373scan_out(struct printer *pp, int scfd, char *scsp, int dlm)
1374{
1375 register char *strp;
1376 register int nchrs, j;
1377 char outbuf[LINELEN+1], *sp, c, cc;
1378 int d, scnhgt;
1379
1380 for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) {
1381 strp = &outbuf[0];
1382 sp = scsp;
1383 for (nchrs = 0; ; ) {
1384 d = dropit(c = TRC(cc = *sp++));
1385 if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d))
1386 for (j = WIDTH; --j;)
1387 *strp++ = BACKGND;
1388 else
1389 strp = scnline(scnkey[(int)c][scnhgt-1-d], strp, cc);
1390 if (*sp == dlm || *sp == '\0' ||
1391 nchrs++ >= pp->page_width/(WIDTH+1)-1)
1392 break;
1393 *strp++ = BACKGND;
1394 *strp++ = BACKGND;
1395 }
1396 while (*--strp == BACKGND && strp >= outbuf)
1397 ;
1398 strp++;
1399 *strp++ = '\n';
1400 (void) write(scfd, outbuf, strp-outbuf);
1401 }
1402}
1403
1404static int
1405dropit(int c)
1406{
1407 switch(c) {
1408
1409 case TRC('_'):
1410 case TRC(';'):
1411 case TRC(','):
1412 case TRC('g'):
1413 case TRC('j'):
1414 case TRC('p'):
1415 case TRC('q'):
1416 case TRC('y'):
1417 return (DROP);
1418
1419 default:
1420 return (0);
1421 }
1422}
1423
1424/*
1425 * sendmail ---
1426 * tell people about job completion
1427 */
1428static void
1429sendmail(struct printer *pp, char *userid, int bombed)
1430{
1431 register int i;
1432 int p[2], s;
1433 register const char *cp;
1434 struct stat stb;
1435 FILE *fp;
1436
1437 pipe(p);
1438 if ((s = dofork(pp, DORETURN)) == 0) { /* child */
1439 dup2(p[0], 0);
1440 closelog();
1441 closeallfds(3);
1442 if ((cp = strrchr(_PATH_SENDMAIL, '/')) != NULL)
1443 cp++;
1444 else
1445 cp = _PATH_SENDMAIL;
1446 execl(_PATH_SENDMAIL, cp, "-t", (char *)0);
1447 _exit(0);
1448 } else if (s > 0) { /* parent */
1449 dup2(p[1], 1);
1450 printf("To: %s@%s\n", userid, origin_host);
1451 printf("Subject: %s printer job \"%s\"\n", pp->printer,
1452 *jobname ? jobname : "<unknown>");
1453 printf("Reply-To: root@%s\n\n", local_host);
1454 printf("Your printer job ");
1455 if (*jobname)
1456 printf("(%s) ", jobname);
1457
1458 switch (bombed) {
1459 case OK:
1460 cp = "OK";
1461 printf("\ncompleted successfully\n");
1462 break;
1463 default:
1464 case FATALERR:
1465 cp = "FATALERR";
1466 printf("\ncould not be printed\n");
1467 break;
1468 case NOACCT:
1469 cp = "NOACCT";
1470 printf("\ncould not be printed without an account on %s\n",
1471 local_host);
1472 break;
1473 case FILTERERR:
1474 cp = "FILTERERR";
1475 if (stat(tempstderr, &stb) < 0 || stb.st_size == 0
1476 || (fp = fopen(tempstderr, "r")) == NULL) {
1477 printf("\nhad some errors and may not have printed\n");
1478 break;
1479 }
1480 printf("\nhad the following errors and may not have printed:\n");
1481 while ((i = getc(fp)) != EOF)
1482 putchar(i);
1483 (void) fclose(fp);
1484 break;
1485 case ACCESS:
1486 cp = "ACCESS";
1487 printf("\nwas not printed because it was not linked to the original file\n");
1488 }
1489 fflush(stdout);
1490 (void) close(1);
1491 } else {
1492 syslog(LOG_WARNING, "unable to send mail to %s: %m", userid);
1493 return;
1494 }
1495 (void) close(p[0]);
1496 (void) close(p[1]);
1497 wait(NULL);
1498 syslog(LOG_INFO, "mail sent to user %s about job %s on printer %s (%s)",
1499 userid, *jobname ? jobname : "<unknown>", pp->printer, cp);
1500}
1501
1502/*
1503 * dofork - fork with retries on failure
1504 */
1505static int
1506dofork(const struct printer *pp, int action)
1507{
1508 pid_t forkpid;
1509 int i, fail;
1510 struct passwd *pwd;
1511
1512 forkpid = -1;
1513 if (daemon_uname == NULL) {
1514 pwd = getpwuid(pp->daemon_user);
1515 if (pwd == NULL) {
1516 syslog(LOG_ERR, "%s: Can't lookup default daemon uid (%ld) in password file",
1517 pp->printer, pp->daemon_user);
1518 goto error_ret;
1519 }
1520 daemon_uname = strdup(pwd->pw_name);
1521 daemon_defgid = pwd->pw_gid;
1522 }
1523
1524 for (i = 0; i < 20; i++) {
1525 forkpid = fork();
1526 if (forkpid < 0) {
1527 sleep((unsigned)(i*i));
1528 continue;
1529 }
1530 /*
1531 * Child should run as daemon instead of root
1532 */
1533 if (forkpid == 0) {
1534 errno = 0;
1535 fail = initgroups(daemon_uname, daemon_defgid);
1536 if (fail) {
1537 syslog(LOG_ERR, "%s: initgroups(%s,%u): %m",
1538 pp->printer, daemon_uname, daemon_defgid);
1539 break;
1540 }
1541 fail = setgid(daemon_defgid);
1542 if (fail) {
1543 syslog(LOG_ERR, "%s: setgid(%u): %m",
1544 pp->printer, daemon_defgid);
1545 break;
1546 }
1547 fail = setuid(pp->daemon_user);
1548 if (fail) {
1549 syslog(LOG_ERR, "%s: setuid(%ld): %m",
1550 pp->printer, pp->daemon_user);
1551 break;
1552 }
1553 }
1554 return (forkpid);
1555 }
1556
1557 /*
1558 * An error occurred. If the error is in the child process, then
1559 * this routine MUST always exit(). DORETURN only effects how
1560 * errors should be handled in the parent process.
1561 */
1562error_ret:
1563 if (forkpid == 0) {
1564 syslog(LOG_ERR, "%s: dofork(): aborting child process...",
1565 pp->printer);
1566 exit(1);
1567 }
1568 syslog(LOG_ERR, "%s: dofork(): failure in fork", pp->printer);
1569
1570 sleep(1); /* throttle errors, as a safety measure */
1571 switch (action) {
1572 case DORETURN:
1573 return (-1);
1574 default:
1575 syslog(LOG_ERR, "bad action (%d) to dofork", action);
1576 /* FALLTHROUGH */
1577 case DOABORT:
1578 exit(1);
1579 }
1580 /*NOTREACHED*/
1581}
1582
1583/*
1584 * Kill child processes to abort current job.
1585 */
1586static void
1587abortpr(int signo __unused)
1588{
1589
1590 (void) unlink(tempstderr);
1591 kill(0, SIGINT);
1592 if (of_pid > 0)
1593 kill(of_pid, SIGCONT);
1594 while (wait(NULL) > 0)
1595 ;
1596 if (of_pid > 0 && tfd != -1)
1597 unlink(tfile);
1598 exit(0);
1599}
1600
1601static void
1602init(struct printer *pp)
1603{
1604 char *s;
1605
1606 sprintf(&width[2], "%ld", pp->page_width);
1607 sprintf(&length[2], "%ld", pp->page_length);
1608 sprintf(&pxwidth[2], "%ld", pp->page_pwidth);
1609 sprintf(&pxlength[2], "%ld", pp->page_plength);
1610 if ((s = checkremote(pp)) != 0) {
1611 syslog(LOG_WARNING, "%s", s);
1612 free(s);
1613 }
1614}
1615
1616void
1617startprinting(const char *printer)
1618{
1619 struct printer myprinter, *pp = &myprinter;
1620 int status;
1621
1622 init_printer(pp);
1623 status = getprintcap(printer, pp);
1624 switch(status) {
1625 case PCAPERR_OSERR:
1626 syslog(LOG_ERR, "can't open printer description file: %m");
1627 exit(1);
1628 case PCAPERR_NOTFOUND:
1629 syslog(LOG_ERR, "unknown printer: %s", printer);
1630 exit(1);
1631 case PCAPERR_TCLOOP:
1632 fatal(pp, "potential reference loop detected in printcap file");
1633 default:
1634 break;
1635 }
1636 printjob(pp);
1637}
1638
1639/*
1640 * Acquire line printer or remote connection.
1641 */
1642static void
1643openpr(const struct printer *pp)
1644{
1645 int p[2];
1646 char *cp;
1647
1648 if (pp->remote) {
1649 openrem(pp);
1650 /*
1651 * Lpd does support the setting of 'of=' filters for
1652 * jobs going to remote machines, but that does not
1653 * have the same meaning as 'of=' does when handling
1654 * local print queues. For remote machines, all 'of='
1655 * filter processing is handled in sendfile(), and that
1656 * does not use these global "output filter" variables.
1657 */
1658 ofd = -1;
1659 of_pid = 0;
1660 return;
1661 } else if (*pp->lp) {
1662 if ((cp = strchr(pp->lp, '@')) != NULL)
1663 opennet(pp);
1664 else
1665 opentty(pp);
1666 } else {
1667 syslog(LOG_ERR, "%s: no line printer device or host name",
1668 pp->printer);
1669 exit(1);
1670 }
1671
1672 /*
1673 * Start up an output filter, if needed.
1674 */
1675 if (pp->filters[LPF_OUTPUT] && !pp->filters[LPF_INPUT] && !of_pid) {
1676 pipe(p);
1677 if (pp->remote) {
1678 strcpy(tfile, TFILENAME);
1679 tfd = mkstemp(tfile);
1680 }
1681 if ((of_pid = dofork(pp, DOABORT)) == 0) { /* child */
1682 dup2(p[0], 0); /* pipe is std in */
1683 /* tfile/printer is stdout */
1684 dup2(pp->remote ? tfd : pfd, 1);
1685 closelog();
1686 closeallfds(3);
1687 if ((cp = strrchr(pp->filters[LPF_OUTPUT], '/')) == NULL)
1688 cp = pp->filters[LPF_OUTPUT];
1689 else
1690 cp++;
1691 execl(pp->filters[LPF_OUTPUT], cp, width, length,
1692 (char *)0);
1693 syslog(LOG_ERR, "%s: execl(%s): %m", pp->printer,
1694 pp->filters[LPF_OUTPUT]);
1695 exit(1);
1696 }
1697 (void) close(p[0]); /* close input side */
1698 ofd = p[1]; /* use pipe for output */
1699 } else {
1700 ofd = pfd;
1701 of_pid = 0;
1702 }
1703}
1704
1705/*
1706 * Printer connected directly to the network
1707 * or to a terminal server on the net
1708 */
1709static void
1710opennet(const struct printer *pp)
1711{
1712 register int i;
1713 int resp;
1714 u_long port;
1715 char *ep;
1716 void (*savealrm)(int);
1717
1718 port = strtoul(pp->lp, &ep, 0);
1719 if (*ep != '@' || port > 65535) {
1720 syslog(LOG_ERR, "%s: bad port number: %s", pp->printer,
1721 pp->lp);
1722 exit(1);
1723 }
1724 ep++;
1725
1726 for (i = 1; ; i = i < 256 ? i << 1 : i) {
1727 resp = -1;
1728 savealrm = signal(SIGALRM, alarmhandler);
1729 alarm(pp->conn_timeout);
1730 pfd = getport(pp, ep, port);
1731 alarm(0);
1732 (void)signal(SIGALRM, savealrm);
1733 if (pfd < 0 && errno == ECONNREFUSED)
1734 resp = 1;
1735 else if (pfd >= 0) {
1736 /*
1737 * need to delay a bit for rs232 lines
1738 * to stabilize in case printer is
1739 * connected via a terminal server
1740 */
1741 delay(500);
1742 break;
1743 }
1744 if (i == 1) {
1745 if (resp < 0)
1746 pstatus(pp, "waiting for %s to come up",
1747 pp->lp);
1748 else
1749 pstatus(pp,
1750 "waiting for access to printer on %s",
1751 pp->lp);
1752 }
1753 sleep(i);
1754 }
1755 pstatus(pp, "sending to %s port %lu", ep, port);
1756}
1757
1758/*
1759 * Printer is connected to an RS232 port on this host
1760 */
1761static void
1762opentty(const struct printer *pp)
1763{
1764 register int i;
1765
1766 for (i = 1; ; i = i < 32 ? i << 1 : i) {
1767 pfd = open(pp->lp, pp->rw ? O_RDWR : O_WRONLY);
1768 if (pfd >= 0) {
1769 delay(500);
1770 break;
1771 }
1772 if (errno == ENOENT) {
1773 syslog(LOG_ERR, "%s: %m", pp->lp);
1774 exit(1);
1775 }
1776 if (i == 1)
1777 pstatus(pp,
1778 "waiting for %s to become ready (offline?)",
1779 pp->printer);
1780 sleep(i);
1781 }
1782 if (isatty(pfd))
1783 setty(pp);
1784 pstatus(pp, "%s is ready and printing", pp->printer);
1785}
1786
1787/*
1788 * Printer is on a remote host
1789 */
1790static void
1791openrem(const struct printer *pp)
1792{
1793 register int i;
1794 int resp;
1795 void (*savealrm)(int);
1796
1797 for (i = 1; ; i = i < 256 ? i << 1 : i) {
1798 resp = -1;
1799 savealrm = signal(SIGALRM, alarmhandler);
1800 alarm(pp->conn_timeout);
1801 pfd = getport(pp, pp->remote_host, 0);
1802 alarm(0);
1803 (void)signal(SIGALRM, savealrm);
1804 if (pfd >= 0) {
1805 if ((writel(pfd, "\2", pp->remote_queue, "\n",
1806 (char *)0)
1807 == 2 + strlen(pp->remote_queue))
1808 && (resp = response(pp)) == 0)
1809 break;
1810 (void) close(pfd);
1811 }
1812 if (i == 1) {
1813 if (resp < 0)
1814 pstatus(pp, "waiting for %s to come up",
1815 pp->remote_host);
1816 else {
1817 pstatus(pp,
1818 "waiting for queue to be enabled on %s",
1819 pp->remote_host);
1820 i = 256;
1821 }
1822 }
1823 sleep(i);
1824 }
1825 pstatus(pp, "sending to %s", pp->remote_host);
1826}
1827
1828/*
1829 * setup tty lines.
1830 */
1831static void
1832setty(const struct printer *pp)
1833{
1834 struct termios ttybuf;
1835
1836 if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) {
1837 syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", pp->printer);
1838 exit(1);
1839 }
1840 if (tcgetattr(pfd, &ttybuf) < 0) {
1841 syslog(LOG_ERR, "%s: tcgetattr: %m", pp->printer);
1842 exit(1);
1843 }
1844 if (pp->baud_rate > 0)
1845 cfsetspeed(&ttybuf, pp->baud_rate);
1846 if (pp->mode_set) {
1847 char *s = strdup(pp->mode_set), *tmp;
1848
1849 while ((tmp = strsep(&s, ",")) != NULL) {
1850 (void) msearch(tmp, &ttybuf);
1851 }
1852 }
1853 if (pp->mode_set != 0 || pp->baud_rate > 0) {
1854 if (tcsetattr(pfd, TCSAFLUSH, &ttybuf) == -1) {
1855 syslog(LOG_ERR, "%s: tcsetattr: %m", pp->printer);
1856 }
1857 }
1858}
1859
1860#include <stdarg.h>
1861
1862static void
1863pstatus(const struct printer *pp, const char *msg, ...)
1864{
1865 int fd;
1866 char *buf;
1867 va_list ap;
1868 va_start(ap, msg);
1869
1870 umask(0);
1871 fd = open(pp->status_file, O_WRONLY|O_CREAT|O_EXLOCK, STAT_FILE_MODE);
1872 if (fd < 0) {
1873 syslog(LOG_ERR, "%s: open(%s): %m", pp->printer,
1874 pp->status_file);
1875 exit(1);
1876 }
1877 ftruncate(fd, 0);
1878 vasprintf(&buf, msg, ap);
1879 va_end(ap);
1880 writel(fd, buf, "\n", (char *)0);
1881 close(fd);
1882 free(buf);
1883}
1884
1885void
1886alarmhandler(int signo __unused)
1887{
1888 /* the signal is ignored */
1889 /* (the '__unused' is just to avoid a compile-time warning) */
1890}
49
50/*
51 * printjob -- print jobs in the queue.
52 *
53 * NOTE: the lock file is used to pass information to lpq and lprm.
54 * it does not need to be removed because file locks are dynamic.
55 */
56
57#include <sys/param.h>
58#include <sys/wait.h>
59#include <sys/stat.h>
60#include <sys/types.h>
61
62#include <pwd.h>
63#include <unistd.h>
64#include <signal.h>
65#include <syslog.h>
66#include <fcntl.h>
67#include <dirent.h>
68#include <errno.h>
69#include <stdio.h>
70#include <string.h>
71#include <stdlib.h>
72#include <sys/ioctl.h>
73#include <termios.h>
74#include <time.h>
75#include "lp.h"
76#include "lp.local.h"
77#include "pathnames.h"
78#include "extern.h"
79
80#define DORETURN 0 /* dofork should return "can't fork" error */
81#define DOABORT 1 /* dofork should just die if fork() fails */
82
83/*
84 * Error tokens
85 */
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
93
94static dev_t fdev; /* device of file pointed to by symlink */
95static ino_t fino; /* inode of file pointed to by symlink */
96static FILE *cfp; /* control file */
97static pid_t of_pid; /* process id of output filter, if any */
98static int child; /* id of any filters */
99static int job_dfcnt; /* count of datafiles in current user job */
100static int lfd; /* lock file descriptor */
101static int ofd; /* output filter file descriptor */
102static int tfd = -1; /* output filter temp file output */
103static int pfd; /* prstatic inter file descriptor */
104static int prchild; /* id of pr process */
105static char title[80]; /* ``pr'' title */
106static char locale[80]; /* ``pr'' locale */
107
108/* these two are set from pp->daemon_user, but only if they are needed */
109static char *daemon_uname; /* set from pwd->pw_name */
110static int daemon_defgid;
111
112static char class[32]; /* classification field */
113static char origin_host[MAXHOSTNAMELEN]; /* user's host machine */
114 /* indentation size in static characters */
115static char indent[10] = "-i0";
116static char jobname[100]; /* job or file name */
117static char length[10] = "-l"; /* page length in lines */
118static char logname[32]; /* user's login name */
119static char pxlength[10] = "-y"; /* page length in pixels */
120static char pxwidth[10] = "-x"; /* page width in pixels */
121/* tempstderr is the filename used to catch stderr from exec-ing filters */
122static char tempstderr[] = "errs.XXXXXXX";
123static char width[10] = "-w"; /* page width in static characters */
124#define TFILENAME "fltXXXXXX"
125static char tfile[] = TFILENAME; /* file name for filter output */
126
127static void abortpr(int _signo);
128static void alarmhandler(int _signo);
129static void banner(struct printer *_pp, char *_name1, char *_name2);
130static int dofork(const struct printer *_pp, int _action);
131static int dropit(int _c);
132static int execfilter(struct printer *_pp, char *_f_cmd, char **_f_av,
133 int _infd, int _outfd);
134static void init(struct printer *_pp);
135static void openpr(const struct printer *_pp);
136static void opennet(const struct printer *_pp);
137static void opentty(const struct printer *_pp);
138static void openrem(const struct printer *pp);
139static int print(struct printer *_pp, int _format, char *_file);
140static int printit(struct printer *_pp, char *_file);
141static void pstatus(const struct printer *_pp, const char *_msg, ...)
142 __printflike(2, 3);
143static char response(const struct printer *_pp);
144static void scan_out(struct printer *_pp, int _scfd, char *_scsp,
145 int _dlm);
146static char *scnline(int _key, char *_p, int _c);
147static int sendfile(struct printer *_pp, int _type, char *_file,
148 char _format, int _copyreq);
149static int sendit(struct printer *_pp, char *_file);
150static void sendmail(struct printer *_pp, char *_userid, int _bombed);
151static void setty(const struct printer *_pp);
152
153void
154printjob(struct printer *pp)
155{
156 struct stat stb;
157 register struct jobqueue *q, **qp;
158 struct jobqueue **queue;
159 register int i, nitems;
160 off_t pidoff;
161 pid_t printpid;
162 int errcnt, jobcount, tempfd;
163
164 jobcount = 0;
165 init(pp); /* set up capabilities */
166 (void) write(1, "", 1); /* ack that daemon is started */
167 (void) close(2); /* set up log file */
168 if (open(pp->log_file, O_WRONLY|O_APPEND, LOG_FILE_MODE) < 0) {
169 syslog(LOG_ERR, "%s: open(%s): %m", pp->printer,
170 pp->log_file);
171 (void) open(_PATH_DEVNULL, O_WRONLY);
172 }
173 setgid(getegid());
174 printpid = getpid(); /* for use with lprm */
175 setpgrp(0, printpid);
176
177 /*
178 * At initial lpd startup, printjob may be called with various
179 * signal handlers in effect. After that initial startup, any
180 * calls to printjob will have a *different* set of signal-handlers
181 * in effect. Make sure all handlers are the ones we want.
182 */
183 signal(SIGCHLD, SIG_DFL);
184 signal(SIGHUP, abortpr);
185 signal(SIGINT, abortpr);
186 signal(SIGQUIT, abortpr);
187 signal(SIGTERM, abortpr);
188
189 /*
190 * uses short form file names
191 */
192 if (chdir(pp->spool_dir) < 0) {
193 syslog(LOG_ERR, "%s: chdir(%s): %m", pp->printer,
194 pp->spool_dir);
195 exit(1);
196 }
197 if (stat(pp->lock_file, &stb) == 0 && (stb.st_mode & LFM_PRINT_DIS))
198 exit(0); /* printing disabled */
199 lfd = open(pp->lock_file, O_WRONLY|O_CREAT|O_EXLOCK|O_NONBLOCK,
200 LOCK_FILE_MODE);
201 if (lfd < 0) {
202 if (errno == EWOULDBLOCK) /* active daemon present */
203 exit(0);
204 syslog(LOG_ERR, "%s: open(%s): %m", pp->printer,
205 pp->lock_file);
206 exit(1);
207 }
208 /* turn off non-blocking mode (was turned on for lock effects only) */
209 if (fcntl(lfd, F_SETFL, 0) < 0) {
210 syslog(LOG_ERR, "%s: fcntl(%s): %m", pp->printer,
211 pp->lock_file);
212 exit(1);
213 }
214 ftruncate(lfd, 0);
215 /*
216 * write process id for others to know
217 */
218 sprintf(line, "%u\n", printpid);
219 pidoff = i = strlen(line);
220 if (write(lfd, line, i) != i) {
221 syslog(LOG_ERR, "%s: write(%s): %m", pp->printer,
222 pp->lock_file);
223 exit(1);
224 }
225 /*
226 * search the spool directory for work and sort by queue order.
227 */
228 if ((nitems = getq(pp, &queue)) < 0) {
229 syslog(LOG_ERR, "%s: can't scan %s", pp->printer,
230 pp->spool_dir);
231 exit(1);
232 }
233 if (nitems == 0) /* no work to do */
234 exit(0);
235 if (stb.st_mode & LFM_RESET_QUE) { /* reset queue flag */
236 if (fchmod(lfd, stb.st_mode & ~LFM_RESET_QUE) < 0)
237 syslog(LOG_ERR, "%s: fchmod(%s): %m", pp->printer,
238 pp->lock_file);
239 }
240
241 /* create a file which will be used to hold stderr from filters */
242 if ((tempfd = mkstemp(tempstderr)) == -1) {
243 syslog(LOG_ERR, "%s: mkstemp(%s): %m", pp->printer,
244 tempstderr);
245 exit(1);
246 }
247 if ((i = fchmod(tempfd, 0664)) == -1) {
248 syslog(LOG_ERR, "%s: fchmod(%s): %m", pp->printer,
249 tempstderr);
250 exit(1);
251 }
252 /* lpd doesn't need it to be open, it just needs it to exist */
253 close(tempfd);
254
255 openpr(pp); /* open printer or remote */
256again:
257 /*
258 * we found something to do now do it --
259 * write the name of the current control file into the lock file
260 * so the spool queue program can tell what we're working on
261 */
262 for (qp = queue; nitems--; free((char *) q)) {
263 q = *qp++;
264 if (stat(q->job_cfname, &stb) < 0)
265 continue;
266 errcnt = 0;
267 restart:
268 (void) lseek(lfd, pidoff, 0);
269 (void) snprintf(line, sizeof(line), "%s\n", q->job_cfname);
270 i = strlen(line);
271 if (write(lfd, line, i) != i)
272 syslog(LOG_ERR, "%s: write(%s): %m", pp->printer,
273 pp->lock_file);
274 if (!pp->remote)
275 i = printit(pp, q->job_cfname);
276 else
277 i = sendit(pp, q->job_cfname);
278 /*
279 * Check to see if we are supposed to stop printing or
280 * if we are to rebuild the queue.
281 */
282 if (fstat(lfd, &stb) == 0) {
283 /* stop printing before starting next job? */
284 if (stb.st_mode & LFM_PRINT_DIS)
285 goto done;
286 /* rebuild queue (after lpc topq) */
287 if (stb.st_mode & LFM_RESET_QUE) {
288 for (free(q); nitems--; free(q))
289 q = *qp++;
290 if (fchmod(lfd, stb.st_mode & ~LFM_RESET_QUE)
291 < 0)
292 syslog(LOG_WARNING,
293 "%s: fchmod(%s): %m",
294 pp->printer, pp->lock_file);
295 break;
296 }
297 }
298 if (i == OK) /* all files of this job printed */
299 jobcount++;
300 else if (i == REPRINT && ++errcnt < 5) {
301 /* try reprinting the job */
302 syslog(LOG_INFO, "restarting %s", pp->printer);
303 if (of_pid > 0) {
304 kill(of_pid, SIGCONT); /* to be sure */
305 (void) close(ofd);
306 while ((i = wait(NULL)) > 0 && i != of_pid)
307 ;
308 if (i < 0)
309 syslog(LOG_WARNING, "%s: after kill(of=%d), wait() returned: %m",
310 pp->printer, of_pid);
311 of_pid = 0;
312 }
313 (void) close(pfd); /* close printer */
314 if (ftruncate(lfd, pidoff) < 0)
315 syslog(LOG_WARNING, "%s: ftruncate(%s): %m",
316 pp->printer, pp->lock_file);
317 openpr(pp); /* try to reopen printer */
318 goto restart;
319 } else {
320 syslog(LOG_WARNING, "%s: job could not be %s (%s)",
321 pp->printer,
322 pp->remote ? "sent to remote host" : "printed",
323 q->job_cfname);
324 if (i == REPRINT) {
325 /* ensure we don't attempt this job again */
326 (void) unlink(q->job_cfname);
327 q->job_cfname[0] = 'd';
328 (void) unlink(q->job_cfname);
329 if (logname[0])
330 sendmail(pp, logname, FATALERR);
331 }
332 }
333 }
334 free(queue);
335 /*
336 * search the spool directory for more work.
337 */
338 if ((nitems = getq(pp, &queue)) < 0) {
339 syslog(LOG_ERR, "%s: can't scan %s", pp->printer,
340 pp->spool_dir);
341 exit(1);
342 }
343 if (nitems == 0) { /* no more work to do */
344 done:
345 if (jobcount > 0) { /* jobs actually printed */
346 if (!pp->no_formfeed && !pp->tof)
347 (void) write(ofd, pp->form_feed,
348 strlen(pp->form_feed));
349 if (pp->trailer != NULL) /* output trailer */
350 (void) write(ofd, pp->trailer,
351 strlen(pp->trailer));
352 }
353 (void) close(ofd);
354 (void) wait(NULL);
355 (void) unlink(tempstderr);
356 exit(0);
357 }
358 goto again;
359}
360
361char fonts[4][50]; /* fonts for troff */
362
363char ifonts[4][40] = {
364 _PATH_VFONTR,
365 _PATH_VFONTI,
366 _PATH_VFONTB,
367 _PATH_VFONTS,
368};
369
370/*
371 * The remaining part is the reading of the control file (cf)
372 * and performing the various actions.
373 */
374static int
375printit(struct printer *pp, char *file)
376{
377 register int i;
378 char *cp;
379 int bombed, didignorehdr;
380
381 bombed = OK;
382 didignorehdr = 0;
383 /*
384 * open control file; ignore if no longer there.
385 */
386 if ((cfp = fopen(file, "r")) == NULL) {
387 syslog(LOG_INFO, "%s: fopen(%s): %m", pp->printer, file);
388 return (OK);
389 }
390 /*
391 * Reset troff fonts.
392 */
393 for (i = 0; i < 4; i++)
394 strcpy(fonts[i], ifonts[i]);
395 sprintf(&width[2], "%ld", pp->page_width);
396 strcpy(indent+2, "0");
397
398 /* initialize job-specific count of datafiles processed */
399 job_dfcnt = 0;
400
401 /*
402 * read the control file for work to do
403 *
404 * file format -- first character in the line is a command
405 * rest of the line is the argument.
406 * valid commands are:
407 *
408 * S -- "stat info" for symbolic link protection
409 * J -- "job name" on banner page
410 * C -- "class name" on banner page
411 * L -- "literal" user's name to print on banner
412 * T -- "title" for pr
413 * H -- "host name" of machine where lpr was done
414 * P -- "person" user's login name
415 * I -- "indent" amount to indent output
416 * R -- laser dpi "resolution"
417 * f -- "file name" name of text file to print
418 * l -- "file name" text file with control chars
419 * o -- "file name" postscript file, according to
420 * the RFC. Here it is treated like an 'f'.
421 * p -- "file name" text file to print with pr(1)
422 * t -- "file name" troff(1) file to print
423 * n -- "file name" ditroff(1) file to print
424 * d -- "file name" dvi file to print
425 * g -- "file name" plot(1G) file to print
426 * v -- "file name" plain raster file to print
427 * c -- "file name" cifplot file to print
428 * 1 -- "R font file" for troff
429 * 2 -- "I font file" for troff
430 * 3 -- "B font file" for troff
431 * 4 -- "S font file" for troff
432 * N -- "name" of file (used by lpq)
433 * U -- "unlink" name of file to remove
434 * (after we print it. (Pass 2 only)).
435 * M -- "mail" to user when done printing
436 * Z -- "locale" for pr
437 *
438 * getline reads a line and expands tabs to blanks
439 */
440
441 /* pass 1 */
442
443 while (getline(cfp))
444 switch (line[0]) {
445 case 'H':
446 strlcpy(origin_host, line + 1, sizeof(origin_host));
447 if (class[0] == '\0') {
448 strlcpy(class, line+1, sizeof(class));
449 }
450 continue;
451
452 case 'P':
453 strlcpy(logname, line + 1, sizeof(logname));
454 if (pp->restricted) { /* restricted */
455 if (getpwnam(logname) == NULL) {
456 bombed = NOACCT;
457 sendmail(pp, line+1, bombed);
458 goto pass2;
459 }
460 }
461 continue;
462
463 case 'S':
464 cp = line+1;
465 i = 0;
466 while (*cp >= '0' && *cp <= '9')
467 i = i * 10 + (*cp++ - '0');
468 fdev = i;
469 cp++;
470 i = 0;
471 while (*cp >= '0' && *cp <= '9')
472 i = i * 10 + (*cp++ - '0');
473 fino = i;
474 continue;
475
476 case 'J':
477 if (line[1] != '\0') {
478 strlcpy(jobname, line + 1, sizeof(jobname));
479 } else
480 strcpy(jobname, " ");
481 continue;
482
483 case 'C':
484 if (line[1] != '\0')
485 strlcpy(class, line + 1, sizeof(class));
486 else if (class[0] == '\0') {
487 /* XXX - why call gethostname instead of
488 * just strlcpy'ing local_host? */
489 gethostname(class, sizeof(class));
490 class[sizeof(class) - 1] = '\0';
491 }
492 continue;
493
494 case 'T': /* header title for pr */
495 strlcpy(title, line + 1, sizeof(title));
496 continue;
497
498 case 'L': /* identification line */
499 if (!pp->no_header && !pp->header_last)
500 banner(pp, line+1, jobname);
501 continue;
502
503 case '1': /* troff fonts */
504 case '2':
505 case '3':
506 case '4':
507 if (line[1] != '\0') {
508 strlcpy(fonts[line[0]-'1'], line + 1,
509 (size_t)50);
510 }
511 continue;
512
513 case 'W': /* page width */
514 strlcpy(width+2, line + 1, sizeof(width) - 2);
515 continue;
516
517 case 'I': /* indent amount */
518 strlcpy(indent+2, line + 1, sizeof(indent) - 2);
519 continue;
520
521 case 'Z': /* locale for pr */
522 strlcpy(locale, line + 1, sizeof(locale));
523 continue;
524
525 default: /* some file to print */
526 /* only lowercase cmd-codes include a file-to-print */
527 if ((line[0] < 'a') || (line[0] > 'z')) {
528 /* ignore any other lines */
529 if (lflag <= 1)
530 continue;
531 if (!didignorehdr) {
532 syslog(LOG_INFO, "%s: in %s :",
533 pp->printer, file);
534 didignorehdr = 1;
535 }
536 syslog(LOG_INFO, "%s: ignoring line: '%c' %s",
537 pp->printer, line[0], &line[1]);
538 continue;
539 }
540 i = print(pp, line[0], line+1);
541 switch (i) {
542 case ERROR:
543 if (bombed == OK)
544 bombed = FATALERR;
545 break;
546 case REPRINT:
547 (void) fclose(cfp);
548 return (REPRINT);
549 case FILTERERR:
550 case ACCESS:
551 bombed = i;
552 sendmail(pp, logname, bombed);
553 }
554 title[0] = '\0';
555 continue;
556
557 case 'N':
558 case 'U':
559 case 'M':
560 case 'R':
561 continue;
562 }
563
564 /* pass 2 */
565
566pass2:
567 fseek(cfp, 0L, 0);
568 while (getline(cfp))
569 switch (line[0]) {
570 case 'L': /* identification line */
571 if (!pp->no_header && pp->header_last)
572 banner(pp, line+1, jobname);
573 continue;
574
575 case 'M':
576 if (bombed < NOACCT) /* already sent if >= NOACCT */
577 sendmail(pp, line+1, bombed);
578 continue;
579
580 case 'U':
581 if (strchr(line+1, '/'))
582 continue;
583 (void) unlink(line+1);
584 }
585 /*
586 * clean-up in case another control file exists
587 */
588 (void) fclose(cfp);
589 (void) unlink(file);
590 return (bombed == OK ? OK : ERROR);
591}
592
593/*
594 * Print a file.
595 * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}.
596 * Return -1 if a non-recoverable error occured,
597 * 2 if the filter detected some errors (but printed the job anyway),
598 * 1 if we should try to reprint this job and
599 * 0 if all is well.
600 * Note: all filters take stdin as the file, stdout as the printer,
601 * stderr as the log file, and must not ignore SIGINT.
602 */
603static int
604print(struct printer *pp, int format, char *file)
605{
606 register int n, i;
607 register char *prog;
608 int fi, fo;
609 FILE *fp;
610 char *av[15], buf[BUFSIZ];
611 pid_t wpid;
612 int p[2], retcode, stopped, wstatus, wstatus_set;
613 struct stat stb;
614
615 if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0) {
616 syslog(LOG_INFO, "%s: unable to open %s ('%c' line)",
617 pp->printer, file, format);
618 return (ERROR);
619 }
620 /*
621 * Check to see if data file is a symbolic link. If so, it should
622 * still point to the same file or someone is trying to print
623 * something he shouldn't.
624 */
625 if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 &&
626 (stb.st_dev != fdev || stb.st_ino != fino))
627 return (ACCESS);
628
629 job_dfcnt++; /* increment datafile counter for this job */
630 stopped = 0; /* output filter is not stopped */
631
632 /* everything seems OK, start it up */
633 if (!pp->no_formfeed && !pp->tof) { /* start on a fresh page */
634 (void) write(ofd, pp->form_feed, strlen(pp->form_feed));
635 pp->tof = 1;
636 }
637 if (pp->filters[LPF_INPUT] == NULL
638 && (format == 'f' || format == 'l' || format == 'o')) {
639 pp->tof = 0;
640 while ((n = read(fi, buf, BUFSIZ)) > 0)
641 if (write(ofd, buf, n) != n) {
642 (void) close(fi);
643 return (REPRINT);
644 }
645 (void) close(fi);
646 return (OK);
647 }
648 switch (format) {
649 case 'p': /* print file using 'pr' */
650 if (pp->filters[LPF_INPUT] == NULL) { /* use output filter */
651 prog = _PATH_PR;
652 i = 0;
653 av[i++] = "pr";
654 av[i++] = width;
655 av[i++] = length;
656 av[i++] = "-h";
657 av[i++] = *title ? title : " ";
658 av[i++] = "-L";
659 av[i++] = *locale ? locale : "C";
660 av[i++] = "-F";
661 av[i] = 0;
662 fo = ofd;
663 goto start;
664 }
665 pipe(p);
666 if ((prchild = dofork(pp, DORETURN)) == 0) { /* child */
667 dup2(fi, 0); /* file is stdin */
668 dup2(p[1], 1); /* pipe is stdout */
669 closelog();
670 closeallfds(3);
671 execl(_PATH_PR, "pr", width, length,
672 "-h", *title ? title : " ",
673 "-L", *locale ? locale : "C",
674 "-F", (char *)0);
675 syslog(LOG_ERR, "cannot execl %s", _PATH_PR);
676 exit(2);
677 }
678 (void) close(p[1]); /* close output side */
679 (void) close(fi);
680 if (prchild < 0) {
681 prchild = 0;
682 (void) close(p[0]);
683 return (ERROR);
684 }
685 fi = p[0]; /* use pipe for input */
686 case 'f': /* print plain text file */
687 prog = pp->filters[LPF_INPUT];
688 av[1] = width;
689 av[2] = length;
690 av[3] = indent;
691 n = 4;
692 break;
693 case 'o': /* print postscript file */
694 /*
695 * Treat this as a "plain file with control characters", and
696 * assume the standard LPF_INPUT filter will recognize that
697 * the data is postscript and know what to do with it. These
698 * 'o'-file requests could come from MacOS 10.1 systems.
699 * (later versions of MacOS 10 will explicitly use 'l')
700 * A postscript file can contain binary data, which is why 'l'
701 * is somewhat more appropriate than 'f'.
702 */
703 /* FALLTHROUGH */
704 case 'l': /* like 'f' but pass control characters */
705 prog = pp->filters[LPF_INPUT];
706 av[1] = "-c";
707 av[2] = width;
708 av[3] = length;
709 av[4] = indent;
710 n = 5;
711 break;
712 case 'r': /* print a fortran text file */
713 prog = pp->filters[LPF_FORTRAN];
714 av[1] = width;
715 av[2] = length;
716 n = 3;
717 break;
718 case 't': /* print troff output */
719 case 'n': /* print ditroff output */
720 case 'd': /* print tex output */
721 (void) unlink(".railmag");
722 if ((fo = creat(".railmag", FILMOD)) < 0) {
723 syslog(LOG_ERR, "%s: cannot create .railmag",
724 pp->printer);
725 (void) unlink(".railmag");
726 } else {
727 for (n = 0; n < 4; n++) {
728 if (fonts[n][0] != '/')
729 (void) write(fo, _PATH_VFONT,
730 sizeof(_PATH_VFONT) - 1);
731 (void) write(fo, fonts[n], strlen(fonts[n]));
732 (void) write(fo, "\n", 1);
733 }
734 (void) close(fo);
735 }
736 prog = (format == 't') ? pp->filters[LPF_TROFF]
737 : ((format == 'n') ? pp->filters[LPF_DITROFF]
738 : pp->filters[LPF_DVI]);
739 av[1] = pxwidth;
740 av[2] = pxlength;
741 n = 3;
742 break;
743 case 'c': /* print cifplot output */
744 prog = pp->filters[LPF_CIFPLOT];
745 av[1] = pxwidth;
746 av[2] = pxlength;
747 n = 3;
748 break;
749 case 'g': /* print plot(1G) output */
750 prog = pp->filters[LPF_GRAPH];
751 av[1] = pxwidth;
752 av[2] = pxlength;
753 n = 3;
754 break;
755 case 'v': /* print raster output */
756 prog = pp->filters[LPF_RASTER];
757 av[1] = pxwidth;
758 av[2] = pxlength;
759 n = 3;
760 break;
761 default:
762 (void) close(fi);
763 syslog(LOG_ERR, "%s: illegal format character '%c'",
764 pp->printer, format);
765 return (ERROR);
766 }
767 if (prog == NULL) {
768 (void) close(fi);
769 syslog(LOG_ERR,
770 "%s: no filter found in printcap for format character '%c'",
771 pp->printer, format);
772 return (ERROR);
773 }
774 if ((av[0] = strrchr(prog, '/')) != NULL)
775 av[0]++;
776 else
777 av[0] = prog;
778 av[n++] = "-n";
779 av[n++] = logname;
780 av[n++] = "-h";
781 av[n++] = origin_host;
782 av[n++] = pp->acct_file;
783 av[n] = 0;
784 fo = pfd;
785 if (of_pid > 0) { /* stop output filter */
786 write(ofd, "\031\1", 2);
787 while ((wpid =
788 wait3(&wstatus, WUNTRACED, 0)) > 0 && wpid != of_pid)
789 ;
790 if (wpid < 0)
791 syslog(LOG_WARNING,
792 "%s: after stopping 'of', wait3() returned: %m",
793 pp->printer);
794 else if (!WIFSTOPPED(wstatus)) {
795 (void) close(fi);
796 syslog(LOG_WARNING, "%s: output filter died "
797 "(pid=%d retcode=%d termsig=%d)",
798 pp->printer, of_pid, WEXITSTATUS(wstatus),
799 WTERMSIG(wstatus));
800 return (REPRINT);
801 }
802 stopped++;
803 }
804start:
805 if ((child = dofork(pp, DORETURN)) == 0) { /* child */
806 dup2(fi, 0);
807 dup2(fo, 1);
808 /* setup stderr for the filter (child process)
809 * so it goes to our temporary errors file */
810 n = open(tempstderr, O_WRONLY|O_TRUNC, 0664);
811 if (n >= 0)
812 dup2(n, 2);
813 closelog();
814 closeallfds(3);
815 execv(prog, av);
816 syslog(LOG_ERR, "%s: cannot execv(%s): %m", pp->printer,
817 prog);
818 exit(2);
819 }
820 (void) close(fi);
821 wstatus_set = 0;
822 if (child < 0)
823 retcode = 100;
824 else {
825 while ((wpid = wait(&wstatus)) > 0 && wpid != child)
826 ;
827 if (wpid < 0) {
828 retcode = 100;
829 syslog(LOG_WARNING,
830 "%s: after execv(%s), wait() returned: %m",
831 pp->printer, prog);
832 } else {
833 wstatus_set = 1;
834 retcode = WEXITSTATUS(wstatus);
835 }
836 }
837 child = 0;
838 prchild = 0;
839 if (stopped) { /* restart output filter */
840 if (kill(of_pid, SIGCONT) < 0) {
841 syslog(LOG_ERR, "cannot restart output filter");
842 exit(1);
843 }
844 }
845 pp->tof = 0;
846
847 /* Copy the filter's output to "lf" logfile */
848 if ((fp = fopen(tempstderr, "r"))) {
849 while (fgets(buf, sizeof(buf), fp))
850 fputs(buf, stderr);
851 fclose(fp);
852 }
853
854 if (wstatus_set && !WIFEXITED(wstatus)) {
855 syslog(LOG_WARNING, "%s: filter '%c' terminated (termsig=%d)",
856 pp->printer, format, WTERMSIG(wstatus));
857 return (ERROR);
858 }
859 switch (retcode) {
860 case 0:
861 pp->tof = 1;
862 return (OK);
863 case 1:
864 return (REPRINT);
865 case 2:
866 return (ERROR);
867 default:
868 syslog(LOG_WARNING, "%s: filter '%c' exited (retcode=%d)",
869 pp->printer, format, retcode);
870 return (FILTERERR);
871 }
872}
873
874/*
875 * Send the daemon control file (cf) and any data files.
876 * Return -1 if a non-recoverable error occured, 1 if a recoverable error and
877 * 0 if all is well.
878 */
879static int
880sendit(struct printer *pp, char *file)
881{
882 int dfcopies, err, i;
883 char *cp, last[BUFSIZ];
884
885 /*
886 * open control file
887 */
888 if ((cfp = fopen(file, "r")) == NULL)
889 return (OK);
890
891 /* initialize job-specific count of datafiles processed */
892 job_dfcnt = 0;
893
894 /*
895 * read the control file for work to do
896 *
897 * file format -- first character in the line is a command
898 * rest of the line is the argument.
899 * commands of interest are:
900 *
901 * a-z -- "file name" name of file to print
902 * U -- "unlink" name of file to remove
903 * (after we print it. (Pass 2 only)).
904 */
905
906 /*
907 * pass 1
908 */
909 err = OK;
910 while (getline(cfp)) {
911 again:
912 if (line[0] == 'S') {
913 cp = line+1;
914 i = 0;
915 while (*cp >= '0' && *cp <= '9')
916 i = i * 10 + (*cp++ - '0');
917 fdev = i;
918 cp++;
919 i = 0;
920 while (*cp >= '0' && *cp <= '9')
921 i = i * 10 + (*cp++ - '0');
922 fino = i;
923 } else if (line[0] == 'H') {
924 strlcpy(origin_host, line + 1, sizeof(origin_host));
925 if (class[0] == '\0') {
926 strlcpy(class, line + 1, sizeof(class));
927 }
928 } else if (line[0] == 'P') {
929 strlcpy(logname, line + 1, sizeof(logname));
930 if (pp->restricted) { /* restricted */
931 if (getpwnam(logname) == NULL) {
932 sendmail(pp, line+1, NOACCT);
933 err = ERROR;
934 break;
935 }
936 }
937 } else if (line[0] == 'I') {
938 strlcpy(indent+2, line + 1, sizeof(indent) - 2);
939 } else if (line[0] >= 'a' && line[0] <= 'z') {
940 dfcopies = 1;
941 strcpy(last, line);
942 while ((i = getline(cfp)) != 0) {
943 if (strcmp(last, line) != 0)
944 break;
945 dfcopies++;
946 }
947 switch (sendfile(pp, '\3', last+1, *last, dfcopies)) {
948 case OK:
949 if (i)
950 goto again;
951 break;
952 case REPRINT:
953 (void) fclose(cfp);
954 return (REPRINT);
955 case ACCESS:
956 sendmail(pp, logname, ACCESS);
957 case ERROR:
958 err = ERROR;
959 }
960 break;
961 }
962 }
963 if (err == OK && sendfile(pp, '\2', file, '\0', 1) > 0) {
964 (void) fclose(cfp);
965 return (REPRINT);
966 }
967 /*
968 * pass 2
969 */
970 fseek(cfp, 0L, 0);
971 while (getline(cfp))
972 if (line[0] == 'U' && !strchr(line+1, '/'))
973 (void) unlink(line+1);
974 /*
975 * clean-up in case another control file exists
976 */
977 (void) fclose(cfp);
978 (void) unlink(file);
979 return (err);
980}
981
982/*
983 * Send a data file to the remote machine and spool it.
984 * Return positive if we should try resending.
985 */
986static int
987sendfile(struct printer *pp, int type, char *file, char format, int copyreq)
988{
989 int i, amt;
990 struct stat stb;
991 char *av[15], *filtcmd;
992 char buf[BUFSIZ], opt_c[4], opt_h[4], opt_n[4];
993 int copycnt, filtstat, narg, resp, sfd, sfres, sizerr, statrc;
994
995 statrc = lstat(file, &stb);
996 if (statrc < 0) {
997 syslog(LOG_ERR, "%s: error from lstat(%s): %m",
998 pp->printer, file);
999 return (ERROR);
1000 }
1001 sfd = open(file, O_RDONLY);
1002 if (sfd < 0) {
1003 syslog(LOG_ERR, "%s: error from open(%s,O_RDONLY): %m",
1004 pp->printer, file);
1005 return (ERROR);
1006 }
1007 /*
1008 * Check to see if data file is a symbolic link. If so, it should
1009 * still point to the same file or someone is trying to print something
1010 * he shouldn't.
1011 */
1012 if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(sfd, &stb) == 0 &&
1013 (stb.st_dev != fdev || stb.st_ino != fino)) {
1014 close(sfd);
1015 return (ACCESS);
1016 }
1017
1018 /* Everything seems OK for reading the file, now to send it */
1019 filtcmd = NULL;
1020 sizerr = 0;
1021 tfd = -1;
1022 if (type == '\3') {
1023 /*
1024 * Type == 3 means this is a datafile, not a control file.
1025 * Increment the counter of data-files in this job, and
1026 * then check for input or output filters (which are only
1027 * applied to datafiles, not control files).
1028 */
1029 job_dfcnt++;
1030
1031 /*
1032 * Note that here we are filtering datafiles, one at a time,
1033 * as they are sent to the remote machine. Here, the *only*
1034 * difference between an input filter (`if=') and an output
1035 * filter (`of=') is the argument list that the filter is
1036 * started up with. Here, the output filter is executed
1037 * for each individual file as it is sent. This is not the
1038 * same as local print queues, where the output filter is
1039 * started up once, and then all jobs are passed thru that
1040 * single invocation of the output filter.
1041 *
1042 * Also note that a queue for a remote-machine can have an
1043 * input filter or an output filter, but not both.
1044 */
1045 if (pp->filters[LPF_INPUT]) {
1046 filtcmd = pp->filters[LPF_INPUT];
1047 av[0] = filtcmd;
1048 narg = 0;
1049 strcpy(opt_c, "-c");
1050 strcpy(opt_h, "-h");
1051 strcpy(opt_n, "-n");
1052 if (format == 'l')
1053 av[++narg] = opt_c;
1054 av[++narg] = width;
1055 av[++narg] = length;
1056 av[++narg] = indent;
1057 av[++narg] = opt_n;
1058 av[++narg] = logname;
1059 av[++narg] = opt_h;
1060 av[++narg] = origin_host;
1061 av[++narg] = pp->acct_file;
1062 av[++narg] = NULL;
1063 } else if (pp->filters[LPF_OUTPUT]) {
1064 filtcmd = pp->filters[LPF_OUTPUT];
1065 av[0] = filtcmd;
1066 narg = 0;
1067 av[++narg] = width;
1068 av[++narg] = length;
1069 av[++narg] = NULL;
1070 }
1071 }
1072 if (filtcmd) {
1073 /*
1074 * If there is an input or output filter, we have to run
1075 * the datafile thru that filter and store the result as
1076 * a temporary spool file, because the protocol requires
1077 * that we send the remote host the file-size before we
1078 * start to send any of the data.
1079 */
1080 strcpy(tfile, TFILENAME);
1081 tfd = mkstemp(tfile);
1082 if (tfd == -1) {
1083 syslog(LOG_ERR, "%s: mkstemp(%s): %m", pp->printer,
1084 TFILENAME);
1085 sfres = ERROR;
1086 goto return_sfres;
1087 }
1088 filtstat = execfilter(pp, filtcmd, av, sfd, tfd);
1089
1090 /* process the return-code from the filter */
1091 switch (filtstat) {
1092 case 0:
1093 break;
1094 case 1:
1095 sfres = REPRINT;
1096 goto return_sfres;
1097 case 2:
1098 sfres = ERROR;
1099 goto return_sfres;
1100 default:
1101 syslog(LOG_WARNING,
1102 "%s: filter '%c' exited (retcode=%d)",
1103 pp->printer, format, filtstat);
1104 sfres = FILTERERR;
1105 goto return_sfres;
1106 }
1107 statrc = fstat(tfd, &stb); /* to find size of tfile */
1108 if (statrc < 0) {
1109 syslog(LOG_ERR,
1110 "%s: error processing 'if', fstat(%s): %m",
1111 pp->printer, tfile);
1112 sfres = ERROR;
1113 goto return_sfres;
1114 }
1115 close(sfd);
1116 sfd = tfd;
1117 lseek(sfd, 0, SEEK_SET);
1118 }
1119
1120 copycnt = 0;
1121sendagain:
1122 copycnt++;
1123
1124 if (copycnt < 2)
1125 (void) sprintf(buf, "%c%qd %s\n", type, stb.st_size, file);
1126 else
1127 (void) sprintf(buf, "%c%qd %s_c%d\n", type, stb.st_size,
1128 file, copycnt);
1129 amt = strlen(buf);
1130 for (i = 0; ; i++) {
1131 if (write(pfd, buf, amt) != amt ||
1132 (resp = response(pp)) < 0 || resp == '\1') {
1133 sfres = REPRINT;
1134 goto return_sfres;
1135 } else if (resp == '\0')
1136 break;
1137 if (i == 0)
1138 pstatus(pp,
1139 "no space on remote; waiting for queue to drain");
1140 if (i == 10)
1141 syslog(LOG_ALERT, "%s: can't send to %s; queue full",
1142 pp->printer, pp->remote_host);
1143 sleep(5 * 60);
1144 }
1145 if (i)
1146 pstatus(pp, "sending to %s", pp->remote_host);
1147 /*
1148 * XXX - we should change trstat_init()/trstat_write() to include
1149 * the copycnt in the statistics record it may write.
1150 */
1151 if (type == '\3')
1152 trstat_init(pp, file, job_dfcnt);
1153 for (i = 0; i < stb.st_size; i += BUFSIZ) {
1154 amt = BUFSIZ;
1155 if (i + amt > stb.st_size)
1156 amt = stb.st_size - i;
1157 if (sizerr == 0 && read(sfd, buf, amt) != amt)
1158 sizerr = 1;
1159 if (write(pfd, buf, amt) != amt) {
1160 sfres = REPRINT;
1161 goto return_sfres;
1162 }
1163 }
1164
1165 if (sizerr) {
1166 syslog(LOG_INFO, "%s: %s: changed size", pp->printer, file);
1167 /* tell recvjob to ignore this file */
1168 (void) write(pfd, "\1", 1);
1169 sfres = ERROR;
1170 goto return_sfres;
1171 }
1172 if (write(pfd, "", 1) != 1 || response(pp)) {
1173 sfres = REPRINT;
1174 goto return_sfres;
1175 }
1176 if (type == '\3') {
1177 trstat_write(pp, TR_SENDING, stb.st_size, logname,
1178 pp->remote_host, origin_host);
1179 /*
1180 * Usually we only need to send one copy of a datafile,
1181 * because the control-file will simply print the same
1182 * file multiple times. However, some printers ignore
1183 * the control file, and simply print each data file as
1184 * it arrives. For such "remote hosts", we need to
1185 * transfer the same data file multiple times. Such a
1186 * a host is indicated by adding 'rc' to the printcap
1187 * entry.
1188 * XXX - Right now this ONLY works for remote hosts which
1189 * do ignore the name of the data file, because
1190 * this sends the file multiple times with slight
1191 * changes to the filename. To do this right would
1192 * require that we also rewrite the control file
1193 * to match those filenames.
1194 */
1195 if (pp->resend_copies && (copycnt < copyreq)) {
1196 lseek(sfd, 0, SEEK_SET);
1197 goto sendagain;
1198 }
1199 }
1200 sfres = OK;
1201
1202return_sfres:
1203 (void)close(sfd);
1204 if (tfd != -1) {
1205 /*
1206 * If tfd is set, then it is the same value as sfd, and
1207 * therefore it is already closed at this point. All
1208 * we need to do is remove the temporary file.
1209 */
1210 tfd = -1;
1211 unlink(tfile);
1212 }
1213 return (sfres);
1214}
1215
1216/*
1217 * This routine is called to execute one of the filters as was
1218 * specified in a printcap entry. While the child-process will read
1219 * all of 'infd', it is up to the caller to close that file descriptor
1220 * in the parent process.
1221 */
1222static int
1223execfilter(struct printer *pp, char *f_cmd, char *f_av[], int infd, int outfd)
1224{
1225 pid_t fpid, wpid;
1226 int errfd, retcode, wstatus;
1227 FILE *errfp;
1228 char buf[BUFSIZ], *slash;
1229
1230 fpid = dofork(pp, DORETURN);
1231 if (fpid != 0) {
1232 /*
1233 * This is the parent process, which just waits for the child
1234 * to complete and then returns the result. Note that it is
1235 * the child process which reads the input stream.
1236 */
1237 if (fpid < 0)
1238 retcode = 100;
1239 else {
1240 while ((wpid = wait(&wstatus)) > 0 &&
1241 wpid != fpid)
1242 ;
1243 if (wpid < 0) {
1244 retcode = 100;
1245 syslog(LOG_WARNING,
1246 "%s: after execv(%s), wait() returned: %m",
1247 pp->printer, f_cmd);
1248 } else
1249 retcode = WEXITSTATUS(wstatus);
1250 }
1251
1252 /*
1253 * Copy everything the filter wrote to stderr from our
1254 * temporary errors file to the "lf=" logfile.
1255 */
1256 errfp = fopen(tempstderr, "r");
1257 if (errfp) {
1258 while (fgets(buf, sizeof(buf), errfp))
1259 fputs(buf, stderr);
1260 fclose(errfp);
1261 }
1262
1263 return (retcode);
1264 }
1265
1266 /*
1267 * This is the child process, which is the one that executes the
1268 * given filter.
1269 */
1270 /*
1271 * If the first parameter has any slashes in it, then change it
1272 * to point to the first character after the last slash.
1273 */
1274 slash = strrchr(f_av[0], '/');
1275 if (slash != NULL)
1276 f_av[0] = slash + 1;
1277 /*
1278 * XXX - in the future, this should setup an explicit list of
1279 * environment variables and use execve()!
1280 */
1281
1282 /*
1283 * Setup stdin, stdout, and stderr as we want them when the filter
1284 * is running. Stderr is setup so it points to a temporary errors
1285 * file, and the parent process will copy that temporary file to
1286 * the real logfile after the filter completes.
1287 */
1288 dup2(infd, 0);
1289 dup2(outfd, 1);
1290 errfd = open(tempstderr, O_WRONLY|O_TRUNC, 0664);
1291 if (errfd >= 0)
1292 dup2(errfd, 2);
1293 closelog();
1294 closeallfds(3);
1295 execv(f_cmd, f_av);
1296 syslog(LOG_ERR, "%s: cannot execv(%s): %m", pp->printer, f_cmd);
1297 exit(2);
1298 /* NOTREACHED */
1299}
1300
1301/*
1302 * Check to make sure there have been no errors and that both programs
1303 * are in sync with eachother.
1304 * Return non-zero if the connection was lost.
1305 */
1306static char
1307response(const struct printer *pp)
1308{
1309 char resp;
1310
1311 if (read(pfd, &resp, 1) != 1) {
1312 syslog(LOG_INFO, "%s: lost connection", pp->printer);
1313 return (-1);
1314 }
1315 return (resp);
1316}
1317
1318/*
1319 * Banner printing stuff
1320 */
1321static void
1322banner(struct printer *pp, char *name1, char *name2)
1323{
1324 time_t tvec;
1325
1326 time(&tvec);
1327 if (!pp->no_formfeed && !pp->tof)
1328 (void) write(ofd, pp->form_feed, strlen(pp->form_feed));
1329 if (pp->short_banner) { /* short banner only */
1330 if (class[0]) {
1331 (void) write(ofd, class, strlen(class));
1332 (void) write(ofd, ":", 1);
1333 }
1334 (void) write(ofd, name1, strlen(name1));
1335 (void) write(ofd, " Job: ", 7);
1336 (void) write(ofd, name2, strlen(name2));
1337 (void) write(ofd, " Date: ", 8);
1338 (void) write(ofd, ctime(&tvec), 24);
1339 (void) write(ofd, "\n", 1);
1340 } else { /* normal banner */
1341 (void) write(ofd, "\n\n\n", 3);
1342 scan_out(pp, ofd, name1, '\0');
1343 (void) write(ofd, "\n\n", 2);
1344 scan_out(pp, ofd, name2, '\0');
1345 if (class[0]) {
1346 (void) write(ofd,"\n\n\n",3);
1347 scan_out(pp, ofd, class, '\0');
1348 }
1349 (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15);
1350 (void) write(ofd, name2, strlen(name2));
1351 (void) write(ofd, "\n\t\t\t\t\tDate: ", 12);
1352 (void) write(ofd, ctime(&tvec), 24);
1353 (void) write(ofd, "\n", 1);
1354 }
1355 if (!pp->no_formfeed)
1356 (void) write(ofd, pp->form_feed, strlen(pp->form_feed));
1357 pp->tof = 1;
1358}
1359
1360static char *
1361scnline(int key, char *p, int c)
1362{
1363 register int scnwidth;
1364
1365 for (scnwidth = WIDTH; --scnwidth;) {
1366 key <<= 1;
1367 *p++ = key & 0200 ? c : BACKGND;
1368 }
1369 return (p);
1370}
1371
1372#define TRC(q) (((q)-' ')&0177)
1373
1374static void
1375scan_out(struct printer *pp, int scfd, char *scsp, int dlm)
1376{
1377 register char *strp;
1378 register int nchrs, j;
1379 char outbuf[LINELEN+1], *sp, c, cc;
1380 int d, scnhgt;
1381
1382 for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) {
1383 strp = &outbuf[0];
1384 sp = scsp;
1385 for (nchrs = 0; ; ) {
1386 d = dropit(c = TRC(cc = *sp++));
1387 if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d))
1388 for (j = WIDTH; --j;)
1389 *strp++ = BACKGND;
1390 else
1391 strp = scnline(scnkey[(int)c][scnhgt-1-d], strp, cc);
1392 if (*sp == dlm || *sp == '\0' ||
1393 nchrs++ >= pp->page_width/(WIDTH+1)-1)
1394 break;
1395 *strp++ = BACKGND;
1396 *strp++ = BACKGND;
1397 }
1398 while (*--strp == BACKGND && strp >= outbuf)
1399 ;
1400 strp++;
1401 *strp++ = '\n';
1402 (void) write(scfd, outbuf, strp-outbuf);
1403 }
1404}
1405
1406static int
1407dropit(int c)
1408{
1409 switch(c) {
1410
1411 case TRC('_'):
1412 case TRC(';'):
1413 case TRC(','):
1414 case TRC('g'):
1415 case TRC('j'):
1416 case TRC('p'):
1417 case TRC('q'):
1418 case TRC('y'):
1419 return (DROP);
1420
1421 default:
1422 return (0);
1423 }
1424}
1425
1426/*
1427 * sendmail ---
1428 * tell people about job completion
1429 */
1430static void
1431sendmail(struct printer *pp, char *userid, int bombed)
1432{
1433 register int i;
1434 int p[2], s;
1435 register const char *cp;
1436 struct stat stb;
1437 FILE *fp;
1438
1439 pipe(p);
1440 if ((s = dofork(pp, DORETURN)) == 0) { /* child */
1441 dup2(p[0], 0);
1442 closelog();
1443 closeallfds(3);
1444 if ((cp = strrchr(_PATH_SENDMAIL, '/')) != NULL)
1445 cp++;
1446 else
1447 cp = _PATH_SENDMAIL;
1448 execl(_PATH_SENDMAIL, cp, "-t", (char *)0);
1449 _exit(0);
1450 } else if (s > 0) { /* parent */
1451 dup2(p[1], 1);
1452 printf("To: %s@%s\n", userid, origin_host);
1453 printf("Subject: %s printer job \"%s\"\n", pp->printer,
1454 *jobname ? jobname : "<unknown>");
1455 printf("Reply-To: root@%s\n\n", local_host);
1456 printf("Your printer job ");
1457 if (*jobname)
1458 printf("(%s) ", jobname);
1459
1460 switch (bombed) {
1461 case OK:
1462 cp = "OK";
1463 printf("\ncompleted successfully\n");
1464 break;
1465 default:
1466 case FATALERR:
1467 cp = "FATALERR";
1468 printf("\ncould not be printed\n");
1469 break;
1470 case NOACCT:
1471 cp = "NOACCT";
1472 printf("\ncould not be printed without an account on %s\n",
1473 local_host);
1474 break;
1475 case FILTERERR:
1476 cp = "FILTERERR";
1477 if (stat(tempstderr, &stb) < 0 || stb.st_size == 0
1478 || (fp = fopen(tempstderr, "r")) == NULL) {
1479 printf("\nhad some errors and may not have printed\n");
1480 break;
1481 }
1482 printf("\nhad the following errors and may not have printed:\n");
1483 while ((i = getc(fp)) != EOF)
1484 putchar(i);
1485 (void) fclose(fp);
1486 break;
1487 case ACCESS:
1488 cp = "ACCESS";
1489 printf("\nwas not printed because it was not linked to the original file\n");
1490 }
1491 fflush(stdout);
1492 (void) close(1);
1493 } else {
1494 syslog(LOG_WARNING, "unable to send mail to %s: %m", userid);
1495 return;
1496 }
1497 (void) close(p[0]);
1498 (void) close(p[1]);
1499 wait(NULL);
1500 syslog(LOG_INFO, "mail sent to user %s about job %s on printer %s (%s)",
1501 userid, *jobname ? jobname : "<unknown>", pp->printer, cp);
1502}
1503
1504/*
1505 * dofork - fork with retries on failure
1506 */
1507static int
1508dofork(const struct printer *pp, int action)
1509{
1510 pid_t forkpid;
1511 int i, fail;
1512 struct passwd *pwd;
1513
1514 forkpid = -1;
1515 if (daemon_uname == NULL) {
1516 pwd = getpwuid(pp->daemon_user);
1517 if (pwd == NULL) {
1518 syslog(LOG_ERR, "%s: Can't lookup default daemon uid (%ld) in password file",
1519 pp->printer, pp->daemon_user);
1520 goto error_ret;
1521 }
1522 daemon_uname = strdup(pwd->pw_name);
1523 daemon_defgid = pwd->pw_gid;
1524 }
1525
1526 for (i = 0; i < 20; i++) {
1527 forkpid = fork();
1528 if (forkpid < 0) {
1529 sleep((unsigned)(i*i));
1530 continue;
1531 }
1532 /*
1533 * Child should run as daemon instead of root
1534 */
1535 if (forkpid == 0) {
1536 errno = 0;
1537 fail = initgroups(daemon_uname, daemon_defgid);
1538 if (fail) {
1539 syslog(LOG_ERR, "%s: initgroups(%s,%u): %m",
1540 pp->printer, daemon_uname, daemon_defgid);
1541 break;
1542 }
1543 fail = setgid(daemon_defgid);
1544 if (fail) {
1545 syslog(LOG_ERR, "%s: setgid(%u): %m",
1546 pp->printer, daemon_defgid);
1547 break;
1548 }
1549 fail = setuid(pp->daemon_user);
1550 if (fail) {
1551 syslog(LOG_ERR, "%s: setuid(%ld): %m",
1552 pp->printer, pp->daemon_user);
1553 break;
1554 }
1555 }
1556 return (forkpid);
1557 }
1558
1559 /*
1560 * An error occurred. If the error is in the child process, then
1561 * this routine MUST always exit(). DORETURN only effects how
1562 * errors should be handled in the parent process.
1563 */
1564error_ret:
1565 if (forkpid == 0) {
1566 syslog(LOG_ERR, "%s: dofork(): aborting child process...",
1567 pp->printer);
1568 exit(1);
1569 }
1570 syslog(LOG_ERR, "%s: dofork(): failure in fork", pp->printer);
1571
1572 sleep(1); /* throttle errors, as a safety measure */
1573 switch (action) {
1574 case DORETURN:
1575 return (-1);
1576 default:
1577 syslog(LOG_ERR, "bad action (%d) to dofork", action);
1578 /* FALLTHROUGH */
1579 case DOABORT:
1580 exit(1);
1581 }
1582 /*NOTREACHED*/
1583}
1584
1585/*
1586 * Kill child processes to abort current job.
1587 */
1588static void
1589abortpr(int signo __unused)
1590{
1591
1592 (void) unlink(tempstderr);
1593 kill(0, SIGINT);
1594 if (of_pid > 0)
1595 kill(of_pid, SIGCONT);
1596 while (wait(NULL) > 0)
1597 ;
1598 if (of_pid > 0 && tfd != -1)
1599 unlink(tfile);
1600 exit(0);
1601}
1602
1603static void
1604init(struct printer *pp)
1605{
1606 char *s;
1607
1608 sprintf(&width[2], "%ld", pp->page_width);
1609 sprintf(&length[2], "%ld", pp->page_length);
1610 sprintf(&pxwidth[2], "%ld", pp->page_pwidth);
1611 sprintf(&pxlength[2], "%ld", pp->page_plength);
1612 if ((s = checkremote(pp)) != 0) {
1613 syslog(LOG_WARNING, "%s", s);
1614 free(s);
1615 }
1616}
1617
1618void
1619startprinting(const char *printer)
1620{
1621 struct printer myprinter, *pp = &myprinter;
1622 int status;
1623
1624 init_printer(pp);
1625 status = getprintcap(printer, pp);
1626 switch(status) {
1627 case PCAPERR_OSERR:
1628 syslog(LOG_ERR, "can't open printer description file: %m");
1629 exit(1);
1630 case PCAPERR_NOTFOUND:
1631 syslog(LOG_ERR, "unknown printer: %s", printer);
1632 exit(1);
1633 case PCAPERR_TCLOOP:
1634 fatal(pp, "potential reference loop detected in printcap file");
1635 default:
1636 break;
1637 }
1638 printjob(pp);
1639}
1640
1641/*
1642 * Acquire line printer or remote connection.
1643 */
1644static void
1645openpr(const struct printer *pp)
1646{
1647 int p[2];
1648 char *cp;
1649
1650 if (pp->remote) {
1651 openrem(pp);
1652 /*
1653 * Lpd does support the setting of 'of=' filters for
1654 * jobs going to remote machines, but that does not
1655 * have the same meaning as 'of=' does when handling
1656 * local print queues. For remote machines, all 'of='
1657 * filter processing is handled in sendfile(), and that
1658 * does not use these global "output filter" variables.
1659 */
1660 ofd = -1;
1661 of_pid = 0;
1662 return;
1663 } else if (*pp->lp) {
1664 if ((cp = strchr(pp->lp, '@')) != NULL)
1665 opennet(pp);
1666 else
1667 opentty(pp);
1668 } else {
1669 syslog(LOG_ERR, "%s: no line printer device or host name",
1670 pp->printer);
1671 exit(1);
1672 }
1673
1674 /*
1675 * Start up an output filter, if needed.
1676 */
1677 if (pp->filters[LPF_OUTPUT] && !pp->filters[LPF_INPUT] && !of_pid) {
1678 pipe(p);
1679 if (pp->remote) {
1680 strcpy(tfile, TFILENAME);
1681 tfd = mkstemp(tfile);
1682 }
1683 if ((of_pid = dofork(pp, DOABORT)) == 0) { /* child */
1684 dup2(p[0], 0); /* pipe is std in */
1685 /* tfile/printer is stdout */
1686 dup2(pp->remote ? tfd : pfd, 1);
1687 closelog();
1688 closeallfds(3);
1689 if ((cp = strrchr(pp->filters[LPF_OUTPUT], '/')) == NULL)
1690 cp = pp->filters[LPF_OUTPUT];
1691 else
1692 cp++;
1693 execl(pp->filters[LPF_OUTPUT], cp, width, length,
1694 (char *)0);
1695 syslog(LOG_ERR, "%s: execl(%s): %m", pp->printer,
1696 pp->filters[LPF_OUTPUT]);
1697 exit(1);
1698 }
1699 (void) close(p[0]); /* close input side */
1700 ofd = p[1]; /* use pipe for output */
1701 } else {
1702 ofd = pfd;
1703 of_pid = 0;
1704 }
1705}
1706
1707/*
1708 * Printer connected directly to the network
1709 * or to a terminal server on the net
1710 */
1711static void
1712opennet(const struct printer *pp)
1713{
1714 register int i;
1715 int resp;
1716 u_long port;
1717 char *ep;
1718 void (*savealrm)(int);
1719
1720 port = strtoul(pp->lp, &ep, 0);
1721 if (*ep != '@' || port > 65535) {
1722 syslog(LOG_ERR, "%s: bad port number: %s", pp->printer,
1723 pp->lp);
1724 exit(1);
1725 }
1726 ep++;
1727
1728 for (i = 1; ; i = i < 256 ? i << 1 : i) {
1729 resp = -1;
1730 savealrm = signal(SIGALRM, alarmhandler);
1731 alarm(pp->conn_timeout);
1732 pfd = getport(pp, ep, port);
1733 alarm(0);
1734 (void)signal(SIGALRM, savealrm);
1735 if (pfd < 0 && errno == ECONNREFUSED)
1736 resp = 1;
1737 else if (pfd >= 0) {
1738 /*
1739 * need to delay a bit for rs232 lines
1740 * to stabilize in case printer is
1741 * connected via a terminal server
1742 */
1743 delay(500);
1744 break;
1745 }
1746 if (i == 1) {
1747 if (resp < 0)
1748 pstatus(pp, "waiting for %s to come up",
1749 pp->lp);
1750 else
1751 pstatus(pp,
1752 "waiting for access to printer on %s",
1753 pp->lp);
1754 }
1755 sleep(i);
1756 }
1757 pstatus(pp, "sending to %s port %lu", ep, port);
1758}
1759
1760/*
1761 * Printer is connected to an RS232 port on this host
1762 */
1763static void
1764opentty(const struct printer *pp)
1765{
1766 register int i;
1767
1768 for (i = 1; ; i = i < 32 ? i << 1 : i) {
1769 pfd = open(pp->lp, pp->rw ? O_RDWR : O_WRONLY);
1770 if (pfd >= 0) {
1771 delay(500);
1772 break;
1773 }
1774 if (errno == ENOENT) {
1775 syslog(LOG_ERR, "%s: %m", pp->lp);
1776 exit(1);
1777 }
1778 if (i == 1)
1779 pstatus(pp,
1780 "waiting for %s to become ready (offline?)",
1781 pp->printer);
1782 sleep(i);
1783 }
1784 if (isatty(pfd))
1785 setty(pp);
1786 pstatus(pp, "%s is ready and printing", pp->printer);
1787}
1788
1789/*
1790 * Printer is on a remote host
1791 */
1792static void
1793openrem(const struct printer *pp)
1794{
1795 register int i;
1796 int resp;
1797 void (*savealrm)(int);
1798
1799 for (i = 1; ; i = i < 256 ? i << 1 : i) {
1800 resp = -1;
1801 savealrm = signal(SIGALRM, alarmhandler);
1802 alarm(pp->conn_timeout);
1803 pfd = getport(pp, pp->remote_host, 0);
1804 alarm(0);
1805 (void)signal(SIGALRM, savealrm);
1806 if (pfd >= 0) {
1807 if ((writel(pfd, "\2", pp->remote_queue, "\n",
1808 (char *)0)
1809 == 2 + strlen(pp->remote_queue))
1810 && (resp = response(pp)) == 0)
1811 break;
1812 (void) close(pfd);
1813 }
1814 if (i == 1) {
1815 if (resp < 0)
1816 pstatus(pp, "waiting for %s to come up",
1817 pp->remote_host);
1818 else {
1819 pstatus(pp,
1820 "waiting for queue to be enabled on %s",
1821 pp->remote_host);
1822 i = 256;
1823 }
1824 }
1825 sleep(i);
1826 }
1827 pstatus(pp, "sending to %s", pp->remote_host);
1828}
1829
1830/*
1831 * setup tty lines.
1832 */
1833static void
1834setty(const struct printer *pp)
1835{
1836 struct termios ttybuf;
1837
1838 if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) {
1839 syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", pp->printer);
1840 exit(1);
1841 }
1842 if (tcgetattr(pfd, &ttybuf) < 0) {
1843 syslog(LOG_ERR, "%s: tcgetattr: %m", pp->printer);
1844 exit(1);
1845 }
1846 if (pp->baud_rate > 0)
1847 cfsetspeed(&ttybuf, pp->baud_rate);
1848 if (pp->mode_set) {
1849 char *s = strdup(pp->mode_set), *tmp;
1850
1851 while ((tmp = strsep(&s, ",")) != NULL) {
1852 (void) msearch(tmp, &ttybuf);
1853 }
1854 }
1855 if (pp->mode_set != 0 || pp->baud_rate > 0) {
1856 if (tcsetattr(pfd, TCSAFLUSH, &ttybuf) == -1) {
1857 syslog(LOG_ERR, "%s: tcsetattr: %m", pp->printer);
1858 }
1859 }
1860}
1861
1862#include <stdarg.h>
1863
1864static void
1865pstatus(const struct printer *pp, const char *msg, ...)
1866{
1867 int fd;
1868 char *buf;
1869 va_list ap;
1870 va_start(ap, msg);
1871
1872 umask(0);
1873 fd = open(pp->status_file, O_WRONLY|O_CREAT|O_EXLOCK, STAT_FILE_MODE);
1874 if (fd < 0) {
1875 syslog(LOG_ERR, "%s: open(%s): %m", pp->printer,
1876 pp->status_file);
1877 exit(1);
1878 }
1879 ftruncate(fd, 0);
1880 vasprintf(&buf, msg, ap);
1881 va_end(ap);
1882 writel(fd, buf, "\n", (char *)0);
1883 close(fd);
1884 free(buf);
1885}
1886
1887void
1888alarmhandler(int signo __unused)
1889{
1890 /* the signal is ignored */
1891 /* (the '__unused' is just to avoid a compile-time warning) */
1892}