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