122437Sdist /*
261845Sbostic * Copyright (c) 1983, 1993
361845Sbostic * The Regents of the University of California. All rights reserved.
434203Sbostic *
556123Selan *
656251Selan * %sccs.include.redist.c%
722437Sdist */
822437Sdist
913954Ssam #ifndef lint
1061845Sbostic static char copyright[] =
1161845Sbostic "@(#) Copyright (c) 1983, 1993\n\
1261845Sbostic The Regents of the University of California. All rights reserved.\n";
1334203Sbostic #endif /* not lint */
1413954Ssam
1556251Selan #ifndef lint
16*69331Sbostic static char sccsid[] = "@(#)printjob.c 8.7 (Berkeley) 05/10/95";
1756251Selan #endif /* not lint */
1856251Selan
1956251Selan
2012111Sralph /*
2112111Sralph * printjob -- print jobs in the queue.
2212111Sralph *
2312111Sralph * NOTE: the lock file is used to pass information to lpq and lprm.
2412111Sralph * it does not need to be removed because file locks are dynamic.
2512111Sralph */
2612111Sralph
2755474Sbostic #include <sys/param.h>
2855474Sbostic #include <sys/wait.h>
2955474Sbostic #include <sys/stat.h>
3056123Selan #include <sys/types.h>
3169061Stef #include <sys/file.h>
3255474Sbostic
3356123Selan #include <pwd.h>
3456123Selan #include <unistd.h>
3555474Sbostic #include <signal.h>
3655474Sbostic #include <sgtty.h>
3755474Sbostic #include <syslog.h>
3855474Sbostic #include <fcntl.h>
3955474Sbostic #include <dirent.h>
4055474Sbostic #include <errno.h>
4155474Sbostic #include <stdio.h>
4255474Sbostic #include <string.h>
4356123Selan #include <stdlib.h>
4412111Sralph #include "lp.h"
4555474Sbostic #include "lp.local.h"
4637968Sbostic #include "pathnames.h"
4755474Sbostic #include "extern.h"
4812111Sralph
4916762Sralph #define DORETURN 0 /* absorb fork error */
5016762Sralph #define DOABORT 1 /* abort if dofork fails */
5112111Sralph
5217463Sralph /*
5317463Sralph * Error tokens
5417463Sralph */
5517463Sralph #define REPRINT -2
5617463Sralph #define ERROR -1
5717463Sralph #define OK 0
5817463Sralph #define FATALERR 1
5917463Sralph #define NOACCT 2
6017463Sralph #define FILTERERR 3
6117463Sralph #define ACCESS 4
6217463Sralph
6356123Selan static dev_t fdev; /* device of file pointed to by symlink */
6456123Selan static ino_t fino; /* inode of file pointed to by symlink */
6556123Selan static FILE *cfp; /* control file */
6656123Selan static int child; /* id of any filters */
6756123Selan static int lfd; /* lock file descriptor */
6856123Selan static int ofd; /* output filter file descriptor */
6956123Selan static int ofilter; /* id of output filter, if any */
7056123Selan static int pfd; /* prstatic inter file descriptor */
7156123Selan static int pid; /* pid of lpd process */
7256123Selan static int prchild; /* id of pr process */
7356123Selan static char title[80]; /* ``pr'' title */
7456123Selan static int tof; /* true if at top of form */
7512111Sralph
7656123Selan static char class[32]; /* classification field */
7756123Selan static char fromhost[32]; /* user's host machine */
7856123Selan /* indentation size in static characters */
7956123Selan static char indent[10] = "-i0";
8056123Selan static char jobname[100]; /* job or file name */
8156123Selan static char length[10] = "-l"; /* page length in lines */
8256123Selan static char logname[32]; /* user's login name */
8356123Selan static char pxlength[10] = "-y"; /* page length in pixels */
8456123Selan static char pxwidth[10] = "-x"; /* page width in pixels */
8556123Selan static char tempfile[] = "errsXXXXXX"; /* file name for filter output */
8656123Selan static char width[10] = "-w"; /* page width in static characters */
8712111Sralph
8855474Sbostic static void abortpr __P((int));
8955474Sbostic static void banner __P((char *, char *));
9055474Sbostic static int dofork __P((int));
9155474Sbostic static int dropit __P((int));
9255474Sbostic static void init __P((void));
9355474Sbostic static void openpr __P((void));
9469008Stef static void opennet __P((char *));
9569008Stef static void opentty __P((void));
9669008Stef static void openrem __P((void));
9755474Sbostic static int print __P((int, char *));
9855474Sbostic static int printit __P((char *));
9955474Sbostic static void pstatus __P((const char *, ...));
10055474Sbostic static char response __P((void));
10155474Sbostic static void scan_out __P((int, char *, int));
10255474Sbostic static char *scnline __P((int, char *, int));
10355474Sbostic static int sendfile __P((int, char *));
10455474Sbostic static int sendit __P((char *));
10555474Sbostic static void sendmail __P((char *, int));
10655474Sbostic static void setty __P((void));
10755474Sbostic
10855474Sbostic void
printjob()10912111Sralph printjob()
11012111Sralph {
11112111Sralph struct stat stb;
11212111Sralph register struct queue *q, **qp;
11312111Sralph struct queue **queue;
11412111Sralph register int i, nitems;
11568972Stef off_t pidoff;
11669007Stef int errcnt, count = 0;
11712111Sralph
11812111Sralph init(); /* set up capabilities */
11913442Sralph (void) write(1, "", 1); /* ack that daemon is started */
12025496Seric (void) close(2); /* set up log file */
12125496Seric if (open(LF, O_WRONLY|O_APPEND, 0664) < 0) {
12225496Seric syslog(LOG_ERR, "%s: %m", LF);
12337968Sbostic (void) open(_PATH_DEVNULL, O_WRONLY);
12425496Seric }
12516762Sralph setgid(getegid());
12612463Sralph pid = getpid(); /* for use with lprm */
12712111Sralph setpgrp(0, pid);
12816762Sralph signal(SIGHUP, abortpr);
12916762Sralph signal(SIGINT, abortpr);
13016762Sralph signal(SIGQUIT, abortpr);
13116762Sralph signal(SIGTERM, abortpr);
13212111Sralph
13339954Smckusick (void) mktemp(tempfile);
13415811Sralph
13512111Sralph /*
13612111Sralph * uses short form file names
13712111Sralph */
13812111Sralph if (chdir(SD) < 0) {
13916762Sralph syslog(LOG_ERR, "%s: %m", SD);
14012111Sralph exit(1);
14112111Sralph }
14212463Sralph if (stat(LO, &stb) == 0 && (stb.st_mode & 0100))
14312463Sralph exit(0); /* printing disabled */
14414150Sralph lfd = open(LO, O_WRONLY|O_CREAT, 0644);
14513169Sralph if (lfd < 0) {
14616762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, LO);
14713169Sralph exit(1);
14813169Sralph }
14913169Sralph if (flock(lfd, LOCK_EX|LOCK_NB) < 0) {
15012111Sralph if (errno == EWOULDBLOCK) /* active deamon present */
15112111Sralph exit(0);
15216762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, LO);
15312111Sralph exit(1);
15412111Sralph }
15513148Ssam ftruncate(lfd, 0);
15612111Sralph /*
15712111Sralph * write process id for others to know
15812111Sralph */
15912111Sralph sprintf(line, "%u\n", pid);
16012111Sralph pidoff = i = strlen(line);
16112463Sralph if (write(lfd, line, i) != i) {
16216762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, LO);
16312111Sralph exit(1);
16412111Sralph }
16512111Sralph /*
16612111Sralph * search the spool directory for work and sort by queue order.
16712111Sralph */
16812111Sralph if ((nitems = getq(&queue)) < 0) {
16916762Sralph syslog(LOG_ERR, "%s: can't scan %s", printer, SD);
17012111Sralph exit(1);
17112111Sralph }
17212463Sralph if (nitems == 0) /* no work to do */
17312111Sralph exit(0);
17413169Sralph if (stb.st_mode & 01) { /* reset queue flag */
17513169Sralph if (fchmod(lfd, stb.st_mode & 0776) < 0)
17616762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, LO);
17713169Sralph }
17812463Sralph openpr(); /* open printer or remote */
17912463Sralph again:
18012111Sralph /*
18112111Sralph * we found something to do now do it --
18212111Sralph * write the name of the current control file into the lock file
18312111Sralph * so the spool queue program can tell what we're working on
18412111Sralph */
18512111Sralph for (qp = queue; nitems--; free((char *) q)) {
18612111Sralph q = *qp++;
18712111Sralph if (stat(q->q_name, &stb) < 0)
18812111Sralph continue;
18969007Stef errcnt = 0;
19012463Sralph restart:
19168972Stef (void) lseek(lfd, pidoff, 0);
19212111Sralph (void) sprintf(line, "%s\n", q->q_name);
19312111Sralph i = strlen(line);
19412111Sralph if (write(lfd, line, i) != i)
19516762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, LO);
19612111Sralph if (!remote)
19712111Sralph i = printit(q->q_name);
19812111Sralph else
19912111Sralph i = sendit(q->q_name);
20012463Sralph /*
20113169Sralph * Check to see if we are supposed to stop printing or
20213169Sralph * if we are to rebuild the queue.
20312463Sralph */
20413169Sralph if (fstat(lfd, &stb) == 0) {
20516762Sralph /* stop printing before starting next job? */
20613169Sralph if (stb.st_mode & 0100)
20713169Sralph goto done;
20816762Sralph /* rebuild queue (after lpc topq) */
20913169Sralph if (stb.st_mode & 01) {
21013169Sralph for (free((char *) q); nitems--; free((char *) q))
21113169Sralph q = *qp++;
21213169Sralph if (fchmod(lfd, stb.st_mode & 0776) < 0)
21316762Sralph syslog(LOG_WARNING, "%s: %s: %m",
21416762Sralph printer, LO);
21513169Sralph break;
21613169Sralph }
21713169Sralph }
21817463Sralph if (i == OK) /* file ok and printed */
21914150Sralph count++;
22069007Stef else if (i == REPRINT && ++errcnt < 5) {
22169007Stef /* try reprinting the job */
22216762Sralph syslog(LOG_INFO, "restarting %s", printer);
22312111Sralph if (ofilter > 0) {
22412111Sralph kill(ofilter, SIGCONT); /* to be sure */
22512111Sralph (void) close(ofd);
22669061Stef while ((i = wait(NULL)) > 0 && i != ofilter)
22712111Sralph ;
22812111Sralph ofilter = 0;
22912111Sralph }
23012463Sralph (void) close(pfd); /* close printer */
23115811Sralph if (ftruncate(lfd, pidoff) < 0)
23216762Sralph syslog(LOG_WARNING, "%s: %s: %m", printer, LO);
23312463Sralph openpr(); /* try to reopen printer */
23412111Sralph goto restart;
23569007Stef } else {
23669007Stef syslog(LOG_WARNING, "%s: job could not be %s (%s)", printer,
23769007Stef remote ? "sent to remote host" : "printed", q->q_name);
23869007Stef if (i == REPRINT) {
23969007Stef /* insure we don't attempt this job again */
24069007Stef (void) unlink(q->q_name);
24169007Stef q->q_name[0] = 'd';
24269007Stef (void) unlink(q->q_name);
24369007Stef if (logname[0])
24469007Stef sendmail(logname, FATALERR);
24569007Stef }
24612111Sralph }
24712111Sralph }
24812111Sralph free((char *) queue);
24912463Sralph /*
25012463Sralph * search the spool directory for more work.
25112463Sralph */
25212463Sralph if ((nitems = getq(&queue)) < 0) {
25316762Sralph syslog(LOG_ERR, "%s: can't scan %s", printer, SD);
25412463Sralph exit(1);
25512463Sralph }
25612463Sralph if (nitems == 0) { /* no more work to do */
25712463Sralph done:
25814150Sralph if (count > 0) { /* Files actually printed */
25914150Sralph if (!SF && !tof)
26014150Sralph (void) write(ofd, FF, strlen(FF));
26114150Sralph if (TR != NULL) /* output trailer */
26214150Sralph (void) write(ofd, TR, strlen(TR));
26314150Sralph }
26439954Smckusick (void) unlink(tempfile);
26512463Sralph exit(0);
26612463Sralph }
26712111Sralph goto again;
26812111Sralph }
26912111Sralph
27012111Sralph char fonts[4][50]; /* fonts for troff */
27112111Sralph
27237968Sbostic char ifonts[4][40] = {
27337968Sbostic _PATH_VFONTR,
27437968Sbostic _PATH_VFONTI,
27537968Sbostic _PATH_VFONTB,
27637968Sbostic _PATH_VFONTS,
27712111Sralph };
27812111Sralph
27912111Sralph /*
28012111Sralph * The remaining part is the reading of the control file (cf)
28112111Sralph * and performing the various actions.
28212111Sralph */
28355474Sbostic static int
printit(file)28412111Sralph printit(file)
28512111Sralph char *file;
28612111Sralph {
28712111Sralph register int i;
28817463Sralph char *cp;
28917463Sralph int bombed = OK;
29012111Sralph
29112111Sralph /*
29217463Sralph * open control file; ignore if no longer there.
29312111Sralph */
29412111Sralph if ((cfp = fopen(file, "r")) == NULL) {
29516762Sralph syslog(LOG_INFO, "%s: %s: %m", printer, file);
29617463Sralph return(OK);
29712111Sralph }
29812111Sralph /*
29912111Sralph * Reset troff fonts.
30012111Sralph */
30112111Sralph for (i = 0; i < 4; i++)
30212111Sralph strcpy(fonts[i], ifonts[i]);
30366833Sbostic sprintf(&width[2], "%d", PW);
30417302Sralph strcpy(indent+2, "0");
30512111Sralph
30612111Sralph /*
30712111Sralph * read the control file for work to do
30812111Sralph *
30912111Sralph * file format -- first character in the line is a command
31012111Sralph * rest of the line is the argument.
31112111Sralph * valid commands are:
31212111Sralph *
31317463Sralph * S -- "stat info" for symbolic link protection
31412111Sralph * J -- "job name" on banner page
31512111Sralph * C -- "class name" on banner page
31612111Sralph * L -- "literal" user's name to print on banner
31712111Sralph * T -- "title" for pr
31812111Sralph * H -- "host name" of machine where lpr was done
31912111Sralph * P -- "person" user's login name
32012581Sralph * I -- "indent" amount to indent output
32169007Stef * R -- laser dpi "resolution"
32212111Sralph * f -- "file name" name of text file to print
32312111Sralph * l -- "file name" text file with control chars
32412111Sralph * p -- "file name" text file to print with pr(1)
32512111Sralph * t -- "file name" troff(1) file to print
32613233Sralph * n -- "file name" ditroff(1) file to print
32712111Sralph * d -- "file name" dvi file to print
32812111Sralph * g -- "file name" plot(1G) file to print
32912111Sralph * v -- "file name" plain raster file to print
33012111Sralph * c -- "file name" cifplot file to print
33112111Sralph * 1 -- "R font file" for troff
33212111Sralph * 2 -- "I font file" for troff
33312111Sralph * 3 -- "B font file" for troff
33412111Sralph * 4 -- "S font file" for troff
33512111Sralph * N -- "name" of file (used by lpq)
33612111Sralph * U -- "unlink" name of file to remove
33712111Sralph * (after we print it. (Pass 2 only)).
33812111Sralph * M -- "mail" to user when done printing
33912111Sralph *
34012111Sralph * getline reads a line and expands tabs to blanks
34112111Sralph */
34212111Sralph
34312111Sralph /* pass 1 */
34412111Sralph
34512111Sralph while (getline(cfp))
34612111Sralph switch (line[0]) {
34712111Sralph case 'H':
34814150Sralph strcpy(fromhost, line+1);
34912111Sralph if (class[0] == '\0')
35015552Sralph strncpy(class, line+1, sizeof(class)-1);
35112111Sralph continue;
35212111Sralph
35312111Sralph case 'P':
35415552Sralph strncpy(logname, line+1, sizeof(logname)-1);
35512463Sralph if (RS) { /* restricted */
35655474Sbostic if (getpwnam(logname) == NULL) {
35717463Sralph bombed = NOACCT;
35815811Sralph sendmail(line+1, bombed);
35912463Sralph goto pass2;
36012463Sralph }
36112463Sralph }
36212111Sralph continue;
36312111Sralph
36417463Sralph case 'S':
36517463Sralph cp = line+1;
36617463Sralph i = 0;
36717463Sralph while (*cp >= '0' && *cp <= '9')
36817463Sralph i = i * 10 + (*cp++ - '0');
36917463Sralph fdev = i;
37017463Sralph cp++;
37117463Sralph i = 0;
37217463Sralph while (*cp >= '0' && *cp <= '9')
37317463Sralph i = i * 10 + (*cp++ - '0');
37417463Sralph fino = i;
37517463Sralph continue;
37617463Sralph
37712111Sralph case 'J':
37812111Sralph if (line[1] != '\0')
37915552Sralph strncpy(jobname, line+1, sizeof(jobname)-1);
38012111Sralph else
38112111Sralph strcpy(jobname, " ");
38212111Sralph continue;
38312111Sralph
38412111Sralph case 'C':
38512111Sralph if (line[1] != '\0')
38615552Sralph strncpy(class, line+1, sizeof(class)-1);
38712111Sralph else if (class[0] == '\0')
38815811Sralph gethostname(class, sizeof(class));
38912111Sralph continue;
39012111Sralph
39112111Sralph case 'T': /* header title for pr */
39215552Sralph strncpy(title, line+1, sizeof(title)-1);
39312111Sralph continue;
39412111Sralph
39512111Sralph case 'L': /* identification line */
39618127Sralph if (!SH && !HL)
39712111Sralph banner(line+1, jobname);
39812111Sralph continue;
39912111Sralph
40012111Sralph case '1': /* troff fonts */
40112111Sralph case '2':
40212111Sralph case '3':
40312111Sralph case '4':
40412111Sralph if (line[1] != '\0')
40512111Sralph strcpy(fonts[line[0]-'1'], line+1);
40612111Sralph continue;
40712111Sralph
40812111Sralph case 'W': /* page width */
40915552Sralph strncpy(width+2, line+1, sizeof(width)-3);
41012111Sralph continue;
41112111Sralph
41212581Sralph case 'I': /* indent amount */
41315552Sralph strncpy(indent+2, line+1, sizeof(indent)-3);
41412581Sralph continue;
41512581Sralph
41612111Sralph default: /* some file to print */
41715811Sralph switch (i = print(line[0], line+1)) {
41817463Sralph case ERROR:
41917463Sralph if (bombed == OK)
42017463Sralph bombed = FATALERR;
42115811Sralph break;
42217463Sralph case REPRINT:
42312111Sralph (void) fclose(cfp);
42417463Sralph return(REPRINT);
42517463Sralph case FILTERERR:
42617463Sralph case ACCESS:
42717463Sralph bombed = i;
42815811Sralph sendmail(logname, bombed);
42915811Sralph }
43012111Sralph title[0] = '\0';
43112111Sralph continue;
43212111Sralph
43312111Sralph case 'N':
43412111Sralph case 'U':
43512111Sralph case 'M':
43669007Stef case 'R':
43712111Sralph continue;
43812111Sralph }
43912111Sralph
44012111Sralph /* pass 2 */
44112111Sralph
44212463Sralph pass2:
44312111Sralph fseek(cfp, 0L, 0);
44412111Sralph while (getline(cfp))
44512111Sralph switch (line[0]) {
44618127Sralph case 'L': /* identification line */
44718127Sralph if (!SH && HL)
44818127Sralph banner(line+1, jobname);
44918127Sralph continue;
45018127Sralph
45112111Sralph case 'M':
45217463Sralph if (bombed < NOACCT) /* already sent if >= NOACCT */
45315811Sralph sendmail(line+1, bombed);
45412111Sralph continue;
45512111Sralph
45612111Sralph case 'U':
45712111Sralph (void) unlink(line+1);
45812111Sralph }
45912111Sralph /*
46015811Sralph * clean-up in case another control file exists
46112111Sralph */
46212111Sralph (void) fclose(cfp);
46312111Sralph (void) unlink(file);
46417463Sralph return(bombed == OK ? OK : ERROR);
46512111Sralph }
46612111Sralph
46712111Sralph /*
46812111Sralph * Print a file.
46913233Sralph * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}.
47015811Sralph * Return -1 if a non-recoverable error occured,
47115811Sralph * 2 if the filter detected some errors (but printed the job anyway),
47215811Sralph * 1 if we should try to reprint this job and
47312111Sralph * 0 if all is well.
47412111Sralph * Note: all filters take stdin as the file, stdout as the printer,
47512111Sralph * stderr as the log file, and must not ignore SIGINT.
47612111Sralph */
47755474Sbostic static int
print(format,file)47812111Sralph print(format, file)
47912111Sralph int format;
48012111Sralph char *file;
48112111Sralph {
48215811Sralph register int n;
48312111Sralph register char *prog;
48415811Sralph int fi, fo;
48539954Smckusick FILE *fp;
48612111Sralph char *av[15], buf[BUFSIZ];
48712111Sralph int pid, p[2], stopped = 0;
48812111Sralph union wait status;
48917463Sralph struct stat stb;
49012111Sralph
49117463Sralph if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0)
49217463Sralph return(ERROR);
49317463Sralph /*
49417463Sralph * Check to see if data file is a symbolic link. If so, it should
49517463Sralph * still point to the same file or someone is trying to print
49617463Sralph * something he shouldn't.
49717463Sralph */
49817463Sralph if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 &&
49917463Sralph (stb.st_dev != fdev || stb.st_ino != fino))
50017463Sralph return(ACCESS);
50112111Sralph if (!SF && !tof) { /* start on a fresh page */
50212111Sralph (void) write(ofd, FF, strlen(FF));
50312111Sralph tof = 1;
50412111Sralph }
50512111Sralph if (IF == NULL && (format == 'f' || format == 'l')) {
50612111Sralph tof = 0;
50712111Sralph while ((n = read(fi, buf, BUFSIZ)) > 0)
50812111Sralph if (write(ofd, buf, n) != n) {
50912111Sralph (void) close(fi);
51017463Sralph return(REPRINT);
51112111Sralph }
51212111Sralph (void) close(fi);
51317463Sralph return(OK);
51412111Sralph }
51512111Sralph switch (format) {
51612111Sralph case 'p': /* print file using 'pr' */
51712111Sralph if (IF == NULL) { /* use output filter */
51837968Sbostic prog = _PATH_PR;
51912111Sralph av[0] = "pr";
52012111Sralph av[1] = width;
52112111Sralph av[2] = length;
52212111Sralph av[3] = "-h";
52312111Sralph av[4] = *title ? title : " ";
52412111Sralph av[5] = 0;
52512111Sralph fo = ofd;
52612111Sralph goto start;
52712111Sralph }
52812111Sralph pipe(p);
52912111Sralph if ((prchild = dofork(DORETURN)) == 0) { /* child */
53012111Sralph dup2(fi, 0); /* file is stdin */
53112111Sralph dup2(p[1], 1); /* pipe is stdout */
53268972Stef closelog();
53312111Sralph for (n = 3; n < NOFILE; n++)
53412111Sralph (void) close(n);
53537968Sbostic execl(_PATH_PR, "pr", width, length,
53637968Sbostic "-h", *title ? title : " ", 0);
53737968Sbostic syslog(LOG_ERR, "cannot execl %s", _PATH_PR);
53812111Sralph exit(2);
53912111Sralph }
54012111Sralph (void) close(p[1]); /* close output side */
54112111Sralph (void) close(fi);
54212111Sralph if (prchild < 0) {
54312111Sralph prchild = 0;
54412111Sralph (void) close(p[0]);
54517463Sralph return(ERROR);
54612111Sralph }
54712111Sralph fi = p[0]; /* use pipe for input */
54812111Sralph case 'f': /* print plain text file */
54912111Sralph prog = IF;
55012111Sralph av[1] = width;
55112111Sralph av[2] = length;
55212581Sralph av[3] = indent;
55312581Sralph n = 4;
55412111Sralph break;
55512111Sralph case 'l': /* like 'f' but pass control characters */
55612111Sralph prog = IF;
55714325Sralph av[1] = "-c";
55812111Sralph av[2] = width;
55912111Sralph av[3] = length;
56012581Sralph av[4] = indent;
56112581Sralph n = 5;
56212111Sralph break;
56312463Sralph case 'r': /* print a fortran text file */
56412463Sralph prog = RF;
56512463Sralph av[1] = width;
56612463Sralph av[2] = length;
56712463Sralph n = 3;
56812463Sralph break;
56912111Sralph case 't': /* print troff output */
57013233Sralph case 'n': /* print ditroff output */
57112463Sralph case 'd': /* print tex output */
57212111Sralph (void) unlink(".railmag");
57312463Sralph if ((fo = creat(".railmag", FILMOD)) < 0) {
57416762Sralph syslog(LOG_ERR, "%s: cannot create .railmag", printer);
57512111Sralph (void) unlink(".railmag");
57612111Sralph } else {
57712111Sralph for (n = 0; n < 4; n++) {
57812111Sralph if (fonts[n][0] != '/')
57954520Sbostic (void) write(fo, _PATH_VFONT,
58054520Sbostic sizeof(_PATH_VFONT) - 1);
58112111Sralph (void) write(fo, fonts[n], strlen(fonts[n]));
58212111Sralph (void) write(fo, "\n", 1);
58312111Sralph }
58412111Sralph (void) close(fo);
58512111Sralph }
58613233Sralph prog = (format == 't') ? TF : (format == 'n') ? NF : DF;
58712463Sralph av[1] = pxwidth;
58812463Sralph av[2] = pxlength;
58912463Sralph n = 3;
59012111Sralph break;
59112111Sralph case 'c': /* print cifplot output */
59212111Sralph prog = CF;
59312463Sralph av[1] = pxwidth;
59412463Sralph av[2] = pxlength;
59512463Sralph n = 3;
59612111Sralph break;
59712111Sralph case 'g': /* print plot(1G) output */
59812111Sralph prog = GF;
59912463Sralph av[1] = pxwidth;
60012463Sralph av[2] = pxlength;
60112463Sralph n = 3;
60212111Sralph break;
60312111Sralph case 'v': /* print raster output */
60412111Sralph prog = VF;
60512463Sralph av[1] = pxwidth;
60612463Sralph av[2] = pxlength;
60712463Sralph n = 3;
60812111Sralph break;
60912111Sralph default:
61012111Sralph (void) close(fi);
61116762Sralph syslog(LOG_ERR, "%s: illegal format character '%c'",
61216762Sralph printer, format);
61317463Sralph return(ERROR);
61412111Sralph }
61569007Stef if (prog == NULL) {
61669007Stef (void) close(fi);
61769007Stef syslog(LOG_ERR,
61869007Stef "%s: no filter found in printcap for format character '%c'",
61969007Stef printer, format);
62069007Stef return(ERROR);
62169007Stef }
62212111Sralph if ((av[0] = rindex(prog, '/')) != NULL)
62312111Sralph av[0]++;
62412111Sralph else
62512111Sralph av[0] = prog;
62612111Sralph av[n++] = "-n";
62712111Sralph av[n++] = logname;
62812111Sralph av[n++] = "-h";
62914150Sralph av[n++] = fromhost;
63012111Sralph av[n++] = AF;
63112111Sralph av[n] = 0;
63212111Sralph fo = pfd;
63312111Sralph if (ofilter > 0) { /* stop output filter */
63412111Sralph write(ofd, "\031\1", 2);
63546912Sbostic while ((pid =
63646912Sbostic wait3((int *)&status, WUNTRACED, 0)) > 0 && pid != ofilter)
63712111Sralph ;
63812111Sralph if (status.w_stopval != WSTOPPED) {
63912111Sralph (void) close(fi);
64069007Stef syslog(LOG_WARNING,
64169007Stef "%s: output filter died (retcode=%d termsig=%d)",
64269007Stef printer, status.w_retcode, status.w_termsig);
64317463Sralph return(REPRINT);
64412111Sralph }
64512111Sralph stopped++;
64612111Sralph }
64712111Sralph start:
64812111Sralph if ((child = dofork(DORETURN)) == 0) { /* child */
64912111Sralph dup2(fi, 0);
65012111Sralph dup2(fo, 1);
65139954Smckusick n = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, 0664);
65215811Sralph if (n >= 0)
65315811Sralph dup2(n, 2);
65468972Stef closelog();
65512111Sralph for (n = 3; n < NOFILE; n++)
65612111Sralph (void) close(n);
65712111Sralph execv(prog, av);
65816762Sralph syslog(LOG_ERR, "cannot execv %s", prog);
65912111Sralph exit(2);
66012111Sralph }
66112111Sralph (void) close(fi);
66212111Sralph if (child < 0)
66312111Sralph status.w_retcode = 100;
66412111Sralph else
66546912Sbostic while ((pid = wait((int *)&status)) > 0 && pid != child)
66612111Sralph ;
66712111Sralph child = 0;
66812111Sralph prchild = 0;
66912111Sralph if (stopped) { /* restart output filter */
67012111Sralph if (kill(ofilter, SIGCONT) < 0) {
67116762Sralph syslog(LOG_ERR, "cannot restart output filter");
67212111Sralph exit(1);
67312111Sralph }
67412111Sralph }
67512111Sralph tof = 0;
67639954Smckusick
67739954Smckusick /* Copy filter output to "lf" logfile */
67839954Smckusick if (fp = fopen(tempfile, "r")) {
67939954Smckusick while (fgets(buf, sizeof(buf), fp))
68039954Smckusick fputs(buf, stderr);
68156123Selan fclose(fp);
68239954Smckusick }
68339954Smckusick
68415811Sralph if (!WIFEXITED(status)) {
68569007Stef syslog(LOG_WARNING, "%s: filter '%c' terminated (termsig=%d)",
68616762Sralph printer, format, status.w_termsig);
68717463Sralph return(ERROR);
68817463Sralph }
68917463Sralph switch (status.w_retcode) {
69017463Sralph case 0:
69117463Sralph tof = 1;
69217463Sralph return(OK);
69317463Sralph case 1:
69417463Sralph return(REPRINT);
69569007Stef case 2:
69669007Stef return(ERROR);
69717463Sralph default:
69869007Stef syslog(LOG_WARNING, "%s: filter '%c' exited (retcode=%d)",
69916762Sralph printer, format, status.w_retcode);
70069007Stef return(FILTERERR);
70117463Sralph }
70212111Sralph }
70312111Sralph
70412111Sralph /*
70512111Sralph * Send the daemon control file (cf) and any data files.
70612111Sralph * Return -1 if a non-recoverable error occured, 1 if a recoverable error and
70712111Sralph * 0 if all is well.
70812111Sralph */
70955474Sbostic static int
sendit(file)71012111Sralph sendit(file)
71112111Sralph char *file;
71212111Sralph {
71317463Sralph register int i, err = OK;
71417463Sralph char *cp, last[BUFSIZ];
71512111Sralph
71612111Sralph /*
71712111Sralph * open control file
71812111Sralph */
71916762Sralph if ((cfp = fopen(file, "r")) == NULL)
72017463Sralph return(OK);
72112111Sralph /*
72212111Sralph * read the control file for work to do
72312111Sralph *
72412111Sralph * file format -- first character in the line is a command
72512111Sralph * rest of the line is the argument.
72612111Sralph * commands of interest are:
72712111Sralph *
72812111Sralph * a-z -- "file name" name of file to print
72912111Sralph * U -- "unlink" name of file to remove
73012111Sralph * (after we print it. (Pass 2 only)).
73112111Sralph */
73212111Sralph
73312111Sralph /*
73412111Sralph * pass 1
73512111Sralph */
73612111Sralph while (getline(cfp)) {
73712111Sralph again:
73817463Sralph if (line[0] == 'S') {
73917463Sralph cp = line+1;
74017463Sralph i = 0;
74117463Sralph while (*cp >= '0' && *cp <= '9')
74217463Sralph i = i * 10 + (*cp++ - '0');
74317463Sralph fdev = i;
74417463Sralph cp++;
74517463Sralph i = 0;
74617463Sralph while (*cp >= '0' && *cp <= '9')
74717463Sralph i = i * 10 + (*cp++ - '0');
74817463Sralph fino = i;
74917463Sralph continue;
75017463Sralph }
75112111Sralph if (line[0] >= 'a' && line[0] <= 'z') {
75212111Sralph strcpy(last, line);
75317463Sralph while (i = getline(cfp))
75412111Sralph if (strcmp(last, line))
75512111Sralph break;
75617463Sralph switch (sendfile('\3', last+1)) {
75717463Sralph case OK:
75817463Sralph if (i)
75917463Sralph goto again;
76017463Sralph break;
76117463Sralph case REPRINT:
76212111Sralph (void) fclose(cfp);
76317463Sralph return(REPRINT);
76417463Sralph case ACCESS:
76517463Sralph sendmail(logname, ACCESS);
76617463Sralph case ERROR:
76717463Sralph err = ERROR;
76817463Sralph }
76912111Sralph break;
77012111Sralph }
77112111Sralph }
77217463Sralph if (err == OK && sendfile('\2', file) > 0) {
77312111Sralph (void) fclose(cfp);
77417463Sralph return(REPRINT);
77512111Sralph }
77612111Sralph /*
77712111Sralph * pass 2
77812111Sralph */
77912111Sralph fseek(cfp, 0L, 0);
78012111Sralph while (getline(cfp))
78112111Sralph if (line[0] == 'U')
78212111Sralph (void) unlink(line+1);
78312111Sralph /*
78417463Sralph * clean-up in case another control file exists
78512111Sralph */
78612111Sralph (void) fclose(cfp);
78712111Sralph (void) unlink(file);
78817463Sralph return(err);
78912111Sralph }
79012111Sralph
79112111Sralph /*
79212111Sralph * Send a data file to the remote machine and spool it.
79312111Sralph * Return positive if we should try resending.
79412111Sralph */
79555474Sbostic static int
sendfile(type,file)79612111Sralph sendfile(type, file)
79755474Sbostic int type;
79855474Sbostic char *file;
79912111Sralph {
80012111Sralph register int f, i, amt;
80112111Sralph struct stat stb;
80212111Sralph char buf[BUFSIZ];
80316762Sralph int sizerr, resp;
80412111Sralph
80517463Sralph if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0)
80617463Sralph return(ERROR);
80717463Sralph /*
80817463Sralph * Check to see if data file is a symbolic link. If so, it should
80917463Sralph * still point to the same file or someone is trying to print something
81017463Sralph * he shouldn't.
81117463Sralph */
81217463Sralph if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 &&
81317463Sralph (stb.st_dev != fdev || stb.st_ino != fino))
81417463Sralph return(ACCESS);
81568972Stef (void) sprintf(buf, "%c%ld %s\n", type, (long)stb.st_size, file);
81612111Sralph amt = strlen(buf);
81716762Sralph for (i = 0; ; i++) {
81816762Sralph if (write(pfd, buf, amt) != amt ||
81916762Sralph (resp = response()) < 0 || resp == '\1') {
82016762Sralph (void) close(f);
82117463Sralph return(REPRINT);
82216762Sralph } else if (resp == '\0')
82316762Sralph break;
82416762Sralph if (i == 0)
82555474Sbostic pstatus("no space on remote; waiting for queue to drain");
82616762Sralph if (i == 10)
82724861Seric syslog(LOG_ALERT, "%s: can't send to %s; queue full",
82816762Sralph printer, RM);
82916762Sralph sleep(5 * 60);
83012692Sralph }
83116762Sralph if (i)
83255474Sbostic pstatus("sending to %s", RM);
83312111Sralph sizerr = 0;
83412111Sralph for (i = 0; i < stb.st_size; i += BUFSIZ) {
83512111Sralph amt = BUFSIZ;
83612111Sralph if (i + amt > stb.st_size)
83712111Sralph amt = stb.st_size - i;
83812111Sralph if (sizerr == 0 && read(f, buf, amt) != amt)
83912111Sralph sizerr = 1;
84012692Sralph if (write(pfd, buf, amt) != amt) {
84112692Sralph (void) close(f);
84217463Sralph return(REPRINT);
84312692Sralph }
84412111Sralph }
84555474Sbostic
84655474Sbostic
84755474Sbostic
84855474Sbostic
84912111Sralph (void) close(f);
85012111Sralph if (sizerr) {
85116762Sralph syslog(LOG_INFO, "%s: %s: changed size", printer, file);
85217463Sralph /* tell recvjob to ignore this file */
85317463Sralph (void) write(pfd, "\1", 1);
85417463Sralph return(ERROR);
85517463Sralph }
85617463Sralph if (write(pfd, "", 1) != 1 || response())
85717463Sralph return(REPRINT);
85817463Sralph return(OK);
85912111Sralph }
86012111Sralph
86112111Sralph /*
86212111Sralph * Check to make sure there have been no errors and that both programs
86312111Sralph * are in sync with eachother.
86412111Sralph * Return non-zero if the connection was lost.
86512111Sralph */
86655474Sbostic static char
response()86716762Sralph response()
86812111Sralph {
86912111Sralph char resp;
87012111Sralph
87116762Sralph if (read(pfd, &resp, 1) != 1) {
87216762Sralph syslog(LOG_INFO, "%s: lost connection", printer);
87316762Sralph return(-1);
87412111Sralph }
87516762Sralph return(resp);
87612111Sralph }
87712111Sralph
87812111Sralph /*
87912111Sralph * Banner printing stuff
88012111Sralph */
88155474Sbostic static void
banner(name1,name2)88212111Sralph banner(name1, name2)
88312111Sralph char *name1, *name2;
88412111Sralph {
88512111Sralph time_t tvec;
88612111Sralph extern char *ctime();
88712111Sralph
88812111Sralph time(&tvec);
88912111Sralph if (!SF && !tof)
89012111Sralph (void) write(ofd, FF, strlen(FF));
89112111Sralph if (SB) { /* short banner only */
89212111Sralph if (class[0]) {
89312111Sralph (void) write(ofd, class, strlen(class));
89412111Sralph (void) write(ofd, ":", 1);
89512111Sralph }
89612111Sralph (void) write(ofd, name1, strlen(name1));
89712111Sralph (void) write(ofd, " Job: ", 7);
89812111Sralph (void) write(ofd, name2, strlen(name2));
89912111Sralph (void) write(ofd, " Date: ", 8);
90012111Sralph (void) write(ofd, ctime(&tvec), 24);
90112111Sralph (void) write(ofd, "\n", 1);
90212111Sralph } else { /* normal banner */
90312111Sralph (void) write(ofd, "\n\n\n", 3);
90412111Sralph scan_out(ofd, name1, '\0');
90512111Sralph (void) write(ofd, "\n\n", 2);
90612111Sralph scan_out(ofd, name2, '\0');
90712111Sralph if (class[0]) {
90812111Sralph (void) write(ofd,"\n\n\n",3);
90912111Sralph scan_out(ofd, class, '\0');
91012111Sralph }
91112111Sralph (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15);
91212111Sralph (void) write(ofd, name2, strlen(name2));
91312111Sralph (void) write(ofd, "\n\t\t\t\t\tDate: ", 12);
91412111Sralph (void) write(ofd, ctime(&tvec), 24);
91512111Sralph (void) write(ofd, "\n", 1);
91612111Sralph }
91712111Sralph if (!SF)
91812111Sralph (void) write(ofd, FF, strlen(FF));
91912111Sralph tof = 1;
92012111Sralph }
92112111Sralph
92255474Sbostic static char *
scnline(key,p,c)92312111Sralph scnline(key, p, c)
92455474Sbostic register int key;
92555474Sbostic register char *p;
92655474Sbostic int c;
92712111Sralph {
92812111Sralph register scnwidth;
92912111Sralph
93012111Sralph for (scnwidth = WIDTH; --scnwidth;) {
93112111Sralph key <<= 1;
93212111Sralph *p++ = key & 0200 ? c : BACKGND;
93312111Sralph }
93412111Sralph return (p);
93512111Sralph }
93612111Sralph
93712111Sralph #define TRC(q) (((q)-' ')&0177)
93812111Sralph
93955474Sbostic static void
scan_out(scfd,scsp,dlm)94012111Sralph scan_out(scfd, scsp, dlm)
94155474Sbostic int scfd, dlm;
94255474Sbostic char *scsp;
94312111Sralph {
94412111Sralph register char *strp;
94512111Sralph register nchrs, j;
94612111Sralph char outbuf[LINELEN+1], *sp, c, cc;
94712111Sralph int d, scnhgt;
94812111Sralph extern char scnkey[][HEIGHT]; /* in lpdchar.c */
94912111Sralph
95012111Sralph for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) {
95112111Sralph strp = &outbuf[0];
95212111Sralph sp = scsp;
95312111Sralph for (nchrs = 0; ; ) {
95412111Sralph d = dropit(c = TRC(cc = *sp++));
95512111Sralph if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d))
95612111Sralph for (j = WIDTH; --j;)
95712111Sralph *strp++ = BACKGND;
95812111Sralph else
95912111Sralph strp = scnline(scnkey[c][scnhgt-1-d], strp, cc);
96012111Sralph if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1)
96112111Sralph break;
96212111Sralph *strp++ = BACKGND;
96312111Sralph *strp++ = BACKGND;
96412111Sralph }
96512111Sralph while (*--strp == BACKGND && strp >= outbuf)
96612111Sralph ;
96712111Sralph strp++;
96812111Sralph *strp++ = '\n';
96912111Sralph (void) write(scfd, outbuf, strp-outbuf);
97012111Sralph }
97112111Sralph }
97212111Sralph
97355474Sbostic static int
dropit(c)97412111Sralph dropit(c)
97555474Sbostic int c;
97612111Sralph {
97712111Sralph switch(c) {
97812111Sralph
97912111Sralph case TRC('_'):
98012111Sralph case TRC(';'):
98112111Sralph case TRC(','):
98212111Sralph case TRC('g'):
98312111Sralph case TRC('j'):
98412111Sralph case TRC('p'):
98512111Sralph case TRC('q'):
98612111Sralph case TRC('y'):
98712111Sralph return (DROP);
98812111Sralph
98912111Sralph default:
99012111Sralph return (0);
99112111Sralph }
99212111Sralph }
99312111Sralph
99412111Sralph /*
99512111Sralph * sendmail ---
99612111Sralph * tell people about job completion
99712111Sralph */
99855474Sbostic static void
sendmail(user,bombed)99915811Sralph sendmail(user, bombed)
100015811Sralph char *user;
100112111Sralph int bombed;
100212111Sralph {
100312111Sralph register int i;
100415811Sralph int p[2], s;
100512111Sralph register char *cp;
100612111Sralph char buf[100];
100715811Sralph struct stat stb;
100815811Sralph FILE *fp;
100912111Sralph
101012111Sralph pipe(p);
101115811Sralph if ((s = dofork(DORETURN)) == 0) { /* child */
101212111Sralph dup2(p[0], 0);
101368972Stef closelog();
101412111Sralph for (i = 3; i < NOFILE; i++)
101512111Sralph (void) close(i);
101637968Sbostic if ((cp = rindex(_PATH_SENDMAIL, '/')) != NULL)
101712111Sralph cp++;
101855474Sbostic else
101937968Sbostic cp = _PATH_SENDMAIL;
102015811Sralph sprintf(buf, "%s@%s", user, fromhost);
102137968Sbostic execl(_PATH_SENDMAIL, cp, buf, 0);
102212111Sralph exit(0);
102315811Sralph } else if (s > 0) { /* parent */
102412111Sralph dup2(p[1], 1);
102515811Sralph printf("To: %s@%s\n", user, fromhost);
102669007Stef printf("Subject: %s printer job \"%s\"\n", printer,
102769007Stef *jobname ? jobname : "<unknown>");
102869007Stef printf("Reply-To: root@%s\n\n", host);
102912111Sralph printf("Your printer job ");
103012111Sralph if (*jobname)
103112111Sralph printf("(%s) ", jobname);
103212463Sralph switch (bombed) {
103317463Sralph case OK:
103412463Sralph printf("\ncompleted successfully\n");
103569008Stef cp = "OK";
103612463Sralph break;
103712463Sralph default:
103817463Sralph case FATALERR:
103912463Sralph printf("\ncould not be printed\n");
104069008Stef cp = "FATALERR";
104112463Sralph break;
104217463Sralph case NOACCT:
104312463Sralph printf("\ncould not be printed without an account on %s\n", host);
104469008Stef cp = "NOACCT";
104512463Sralph break;
104617463Sralph case FILTERERR:
104739954Smckusick if (stat(tempfile, &stb) < 0 || stb.st_size == 0 ||
104839954Smckusick (fp = fopen(tempfile, "r")) == NULL) {
104969007Stef printf("\nhad some errors and may not have printed\n");
105015811Sralph break;
105115811Sralph }
105269007Stef printf("\nhad the following errors and may not have printed:\n");
105315811Sralph while ((i = getc(fp)) != EOF)
105415811Sralph putchar(i);
105515811Sralph (void) fclose(fp);
105669008Stef cp = "FILTERERR";
105717463Sralph break;
105817463Sralph case ACCESS:
105917463Sralph printf("\nwas not printed because it was not linked to the original file\n");
106069008Stef cp = "ACCESS";
106112463Sralph }
106212111Sralph fflush(stdout);
106312111Sralph (void) close(1);
106412111Sralph }
106512111Sralph (void) close(p[0]);
106612111Sralph (void) close(p[1]);
106769061Stef wait(NULL);
106869008Stef syslog(LOG_INFO, "mail sent to user %s about job %s on printer %s (%s)",
106969008Stef user, *jobname ? jobname : "<unknown>", printer, cp);
107012111Sralph }
107112111Sralph
107212111Sralph /*
107312111Sralph * dofork - fork with retries on failure
107412111Sralph */
107555474Sbostic static int
dofork(action)107612111Sralph dofork(action)
107712111Sralph int action;
107812111Sralph {
107912111Sralph register int i, pid;
108012111Sralph
108112111Sralph for (i = 0; i < 20; i++) {
108212463Sralph if ((pid = fork()) < 0) {
108312111Sralph sleep((unsigned)(i*i));
108412463Sralph continue;
108512463Sralph }
108612463Sralph /*
108712463Sralph * Child should run as daemon instead of root
108812463Sralph */
108912463Sralph if (pid == 0)
109012463Sralph setuid(DU);
109112463Sralph return(pid);
109212111Sralph }
109316762Sralph syslog(LOG_ERR, "can't fork");
109412111Sralph
109512111Sralph switch (action) {
109612111Sralph case DORETURN:
109712111Sralph return (-1);
109812111Sralph default:
109916762Sralph syslog(LOG_ERR, "bad action (%d) to dofork", action);
110012111Sralph /*FALL THRU*/
110112111Sralph case DOABORT:
110212111Sralph exit(1);
110312111Sralph }
110412111Sralph /*NOTREACHED*/
110512111Sralph }
110612111Sralph
110712111Sralph /*
110816762Sralph * Kill child processes to abort current job.
110912111Sralph */
111055474Sbostic static void
abortpr(signo)111155474Sbostic abortpr(signo)
111255474Sbostic int signo;
111312111Sralph {
111439954Smckusick (void) unlink(tempfile);
111512111Sralph kill(0, SIGINT);
111612111Sralph if (ofilter > 0)
111712111Sralph kill(ofilter, SIGCONT);
111846912Sbostic while (wait(NULL) > 0)
111912111Sralph ;
112012111Sralph exit(0);
112112111Sralph }
112212111Sralph
112355474Sbostic static void
init()112412111Sralph init()
112512111Sralph {
112612111Sralph int status;
112738736Stef char *s;
112812111Sralph
112956123Selan if ((status = cgetent(&bp, printcapdb, printer)) == -2) {
113025468Stef syslog(LOG_ERR, "can't open printer description file");
113125468Stef exit(1);
113256123Selan } else if (status == -1) {
113325468Stef syslog(LOG_ERR, "unknown printer: %s", printer);
113425468Stef exit(1);
113556123Selan } else if (status == -3)
113656123Selan fatal("potential reference loop detected in printcap file");
113756123Selan
113856123Selan if (cgetstr(bp, "lp", &LP) == -1)
113937968Sbostic LP = _PATH_DEFDEVLP;
114056123Selan if (cgetstr(bp, "rp", &RP) == -1)
114112463Sralph RP = DEFLP;
114256123Selan if (cgetstr(bp, "lo", &LO) == -1)
114312111Sralph LO = DEFLOCK;
114456123Selan if (cgetstr(bp, "st", &ST) == -1)
114512111Sralph ST = DEFSTAT;
114656123Selan if (cgetstr(bp, "lf", &LF) == -1)
114737968Sbostic LF = _PATH_CONSOLE;
114856123Selan if (cgetstr(bp, "sd", &SD) == -1)
114937968Sbostic SD = _PATH_DEFSPOOL;
115056123Selan if (cgetnum(bp, "du", &DU) < 0)
115112111Sralph DU = DEFUID;
115256123Selan if (cgetstr(bp,"ff", &FF) == -1)
115312111Sralph FF = DEFFF;
115456123Selan if (cgetnum(bp, "pw", &PW) < 0)
115512111Sralph PW = DEFWIDTH;
115612111Sralph sprintf(&width[2], "%d", PW);
115756123Selan if (cgetnum(bp, "pl", &PL) < 0)
115812111Sralph PL = DEFLENGTH;
115912111Sralph sprintf(&length[2], "%d", PL);
116056123Selan if (cgetnum(bp,"px", &PX) < 0)
116112463Sralph PX = 0;
116212463Sralph sprintf(&pxwidth[2], "%d", PX);
116356123Selan if (cgetnum(bp, "py", &PY) < 0)
116412463Sralph PY = 0;
116512463Sralph sprintf(&pxlength[2], "%d", PY);
116656123Selan cgetstr(bp, "rm", &RM);
116738736Stef if (s = checkremote())
116838736Stef syslog(LOG_WARNING, s);
116925468Stef
117056123Selan cgetstr(bp, "af", &AF);
117156123Selan cgetstr(bp, "of", &OF);
117256123Selan cgetstr(bp, "if", &IF);
117356123Selan cgetstr(bp, "rf", &RF);
117456123Selan cgetstr(bp, "tf", &TF);
117556123Selan cgetstr(bp, "nf", &NF);
117656123Selan cgetstr(bp, "df", &DF);
117756123Selan cgetstr(bp, "gf", &GF);
117856123Selan cgetstr(bp, "vf", &VF);
117956123Selan cgetstr(bp, "cf", &CF);
118056123Selan cgetstr(bp, "tr", &TR);
118156123Selan
118256123Selan RS = (cgetcap(bp, "rs", ':') != NULL);
118356123Selan SF = (cgetcap(bp, "sf", ':') != NULL);
118456123Selan SH = (cgetcap(bp, "sh", ':') != NULL);
118556123Selan SB = (cgetcap(bp, "sb", ':') != NULL);
118656123Selan HL = (cgetcap(bp, "hl", ':') != NULL);
118756123Selan RW = (cgetcap(bp, "rw", ':') != NULL);
118856123Selan
118956123Selan cgetnum(bp, "br", &BR);
119056123Selan if (cgetnum(bp, "fc", &FC) < 0)
119112111Sralph FC = 0;
119256123Selan if (cgetnum(bp, "fs", &FS) < 0)
119312111Sralph FS = 0;
119456123Selan if (cgetnum(bp, "xc", &XC) < 0)
119512111Sralph XC = 0;
119656123Selan if (cgetnum(bp, "xs", &XS) < 0)
119712111Sralph XS = 0;
119856123Selan
119956123Selan tof = (cgetcap(bp, "fo", ':') == NULL);
120012111Sralph }
120112111Sralph
120212463Sralph /*
120312463Sralph * Acquire line printer or remote connection.
120412463Sralph */
120555474Sbostic static void
openpr()120612463Sralph openpr()
120712463Sralph {
120869008Stef register int i;
120969008Stef char *cp;
121012463Sralph
121169008Stef if (!remote && *LP) {
121269008Stef if (cp = index(LP, '@'))
121369008Stef opennet(cp);
121469008Stef else
121569008Stef opentty();
121669008Stef } else if (remote) {
121769008Stef openrem();
121812463Sralph } else {
121916762Sralph syslog(LOG_ERR, "%s: no line printer device or host name",
122016762Sralph printer);
122112463Sralph exit(1);
122212463Sralph }
122369008Stef
122412463Sralph /*
122512463Sralph * Start up an output filter, if needed.
122612463Sralph */
122740049Stef if (!remote && OF) {
122812463Sralph int p[2];
122912463Sralph
123012463Sralph pipe(p);
123112463Sralph if ((ofilter = dofork(DOABORT)) == 0) { /* child */
123212463Sralph dup2(p[0], 0); /* pipe is std in */
123312463Sralph dup2(pfd, 1); /* printer is std out */
123468972Stef closelog();
123512463Sralph for (i = 3; i < NOFILE; i++)
123612463Sralph (void) close(i);
123712463Sralph if ((cp = rindex(OF, '/')) == NULL)
123812463Sralph cp = OF;
123912463Sralph else
124012463Sralph cp++;
124112463Sralph execl(OF, cp, width, length, 0);
124216762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, OF);
124312463Sralph exit(1);
124412463Sralph }
124512463Sralph (void) close(p[0]); /* close input side */
124612463Sralph ofd = p[1]; /* use pipe for output */
124712463Sralph } else {
124812463Sralph ofd = pfd;
124912463Sralph ofilter = 0;
125012463Sralph }
125112463Sralph }
125212463Sralph
125369008Stef /*
125469008Stef * Printer connected directly to the network
125569008Stef * or to a terminal server on the net
125669008Stef */
125769008Stef static void
opennet(cp)125869008Stef opennet(cp)
125969008Stef char *cp;
126069008Stef {
126169008Stef register int i;
126269008Stef int resp, port;
1263*69331Sbostic char save_ch;
126469008Stef
1265*69331Sbostic save_ch = *cp;
1266*69331Sbostic *cp = '\0';
1267*69331Sbostic port = atoi(LP);
126869008Stef if (port <= 0) {
1269*69331Sbostic syslog(LOG_ERR, "%s: bad port number: %s", printer, LP);
127069008Stef exit(1);
127169008Stef }
1272*69331Sbostic *cp++ = save_ch;
127369008Stef
127469008Stef for (i = 1; ; i = i < 256 ? i << 1 : i) {
127569008Stef resp = -1;
1276*69331Sbostic pfd = getport(cp, port);
127769008Stef if (pfd < 0 && errno == ECONNREFUSED)
127869008Stef resp = 1;
127969008Stef else if (pfd >= 0) {
128069008Stef /*
128169008Stef * need to delay a bit for rs232 lines
128269008Stef * to stabilize in case printer is
128369008Stef * connected via a terminal server
128469008Stef */
128569008Stef delay(500);
128669008Stef break;
128769008Stef }
128869008Stef if (i == 1) {
128969008Stef if (resp < 0)
129069008Stef pstatus("waiting for %s to come up", LP);
129169008Stef else
129269008Stef pstatus("waiting for access to printer on %s", LP);
129369008Stef }
129469008Stef sleep(i);
129569008Stef }
1296*69331Sbostic pstatus("sending to %s port %d", cp, port);
129769008Stef }
129869008Stef
129969008Stef /*
130069008Stef * Printer is connected to an RS232 port on this host
130169008Stef */
130269008Stef static void
opentty()130369008Stef opentty()
130469008Stef {
130569008Stef register int i;
130669008Stef int resp, port;
130769008Stef
130869008Stef for (i = 1; ; i = i < 32 ? i << 1 : i) {
130969008Stef pfd = open(LP, RW ? O_RDWR : O_WRONLY);
131069008Stef if (pfd >= 0) {
131169008Stef delay(500);
131269008Stef break;
131369008Stef }
131469008Stef if (errno == ENOENT) {
131569008Stef syslog(LOG_ERR, "%s: %m", LP);
131669008Stef exit(1);
131769008Stef }
131869008Stef if (i == 1)
131969008Stef pstatus("waiting for %s to become ready (offline ?)",
132069008Stef printer);
132169008Stef sleep(i);
132269008Stef }
132369008Stef if (isatty(pfd))
132469008Stef setty();
132569008Stef pstatus("%s is ready and printing", printer);
132669008Stef }
132769008Stef
132869008Stef /*
132969008Stef * Printer is on a remote host
133069008Stef */
133169008Stef static void
openrem()133269008Stef openrem()
133369008Stef {
133469008Stef register int i, n;
133569008Stef int resp, port;
133669008Stef
133769008Stef for (i = 1; ; i = i < 256 ? i << 1 : i) {
133869008Stef resp = -1;
133969008Stef pfd = getport(RM, 0);
134069008Stef if (pfd >= 0) {
134169008Stef (void) sprintf(line, "\2%s\n", RP);
134269008Stef n = strlen(line);
134369008Stef if (write(pfd, line, n) == n &&
134469008Stef (resp = response()) == '\0')
134569008Stef break;
134669008Stef (void) close(pfd);
134769008Stef }
134869008Stef if (i == 1) {
134969008Stef if (resp < 0)
135069008Stef pstatus("waiting for %s to come up", RM);
135169008Stef else {
135269008Stef pstatus("waiting for queue to be enabled on %s",
135369008Stef RM);
135469008Stef i = 256;
135569008Stef }
135669008Stef }
135769008Stef sleep(i);
135869008Stef }
135969008Stef pstatus("sending to %s", RM);
136069008Stef }
136169008Stef
136212111Sralph struct bauds {
136312111Sralph int baud;
136412111Sralph int speed;
136512111Sralph } bauds[] = {
136612111Sralph 50, B50,
136712111Sralph 75, B75,
136812111Sralph 110, B110,
136912111Sralph 134, B134,
137012111Sralph 150, B150,
137112111Sralph 200, B200,
137212111Sralph 300, B300,
137312111Sralph 600, B600,
137412111Sralph 1200, B1200,
137512111Sralph 1800, B1800,
137612111Sralph 2400, B2400,
137712111Sralph 4800, B4800,
137812111Sralph 9600, B9600,
137912111Sralph 19200, EXTA,
138012111Sralph 38400, EXTB,
138112111Sralph 0, 0
138212111Sralph };
138312111Sralph
138412111Sralph /*
138512111Sralph * setup tty lines.
138612111Sralph */
138755474Sbostic static void
setty()138812111Sralph setty()
138912111Sralph {
139012111Sralph struct sgttyb ttybuf;
139112111Sralph register struct bauds *bp;
139212111Sralph
139312111Sralph if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) {
139416762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer);
139512111Sralph exit(1);
139612111Sralph }
139712111Sralph if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) {
139816762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCGETP): %m", printer);
139912111Sralph exit(1);
140012111Sralph }
140112111Sralph if (BR > 0) {
140212111Sralph for (bp = bauds; bp->baud; bp++)
140312111Sralph if (BR == bp->baud)
140412111Sralph break;
140512111Sralph if (!bp->baud) {
140616762Sralph syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR);
140712111Sralph exit(1);
140812111Sralph }
140912111Sralph ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed;
141012111Sralph }
141113169Sralph ttybuf.sg_flags &= ~FC;
141213169Sralph ttybuf.sg_flags |= FS;
141312111Sralph if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) {
141416762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCSETP): %m", printer);
141512111Sralph exit(1);
141612111Sralph }
141712111Sralph if (XC) {
141812111Sralph if (ioctl(pfd, TIOCLBIC, &XC) < 0) {
141916762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCLBIC): %m", printer);
142012111Sralph exit(1);
142112111Sralph }
142212111Sralph }
142312111Sralph if (XS) {
142412111Sralph if (ioctl(pfd, TIOCLBIS, &XS) < 0) {
142516762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCLBIS): %m", printer);
142612111Sralph exit(1);
142712111Sralph }
142812111Sralph }
142912111Sralph }
143012463Sralph
143155474Sbostic #if __STDC__
143255474Sbostic #include <stdarg.h>
143355474Sbostic #else
143455474Sbostic #include <varargs.h>
143555474Sbostic #endif
143655474Sbostic
143769061Stef static void
143855474Sbostic #if __STDC__
pstatus(const char * msg,...)143955474Sbostic pstatus(const char *msg, ...)
144055474Sbostic #else
144155474Sbostic pstatus(msg, va_alist)
144212463Sralph char *msg;
144355474Sbostic va_dcl
144455474Sbostic #endif
144512463Sralph {
144612463Sralph register int fd;
144712463Sralph char buf[BUFSIZ];
144855474Sbostic va_list ap;
144955474Sbostic #if __STDC__
145055474Sbostic va_start(ap, msg);
145155474Sbostic #else
145255474Sbostic va_start(ap);
145355474Sbostic #endif
145412463Sralph
145512463Sralph umask(0);
145613148Ssam fd = open(ST, O_WRONLY|O_CREAT, 0664);
145716762Sralph if (fd < 0 || flock(fd, LOCK_EX) < 0) {
145816762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, ST);
145916762Sralph exit(1);
146016762Sralph }
146113148Ssam ftruncate(fd, 0);
146255474Sbostic (void)vsnprintf(buf, sizeof(buf), msg, ap);
146355474Sbostic va_end(ap);
146412463Sralph strcat(buf, "\n");
146512463Sralph (void) write(fd, buf, strlen(buf));
146612463Sralph (void) close(fd);
146712463Sralph }
1468