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*69061Stef static char sccsid[] = "@(#)printjob.c 8.6 (Berkeley) 04/28/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> 31*69061Stef #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 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); 226*69061Stef 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 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 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 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 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 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 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 * 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 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 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 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]); 1067*69061Stef 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 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 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 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 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 125869008Stef opennet(cp) 125969008Stef char *cp; 126069008Stef { 126169008Stef register int i; 126269008Stef int resp, port; 126369008Stef 126469008Stef *cp++ = '\0'; 126569008Stef port = atoi(cp); 126669008Stef if (port <= 0) { 126769008Stef syslog(LOG_ERR, "%s: bad port number: %s", printer, cp); 126869008Stef exit(1); 126969008Stef } 127069008Stef 127169008Stef for (i = 1; ; i = i < 256 ? i << 1 : i) { 127269008Stef resp = -1; 127369008Stef pfd = getport(LP, port); 127469008Stef if (pfd < 0 && errno == ECONNREFUSED) 127569008Stef resp = 1; 127669008Stef else if (pfd >= 0) { 127769008Stef /* 127869008Stef * need to delay a bit for rs232 lines 127969008Stef * to stabilize in case printer is 128069008Stef * connected via a terminal server 128169008Stef */ 128269008Stef delay(500); 128369008Stef break; 128469008Stef } 128569008Stef if (i == 1) { 128669008Stef if (resp < 0) 128769008Stef pstatus("waiting for %s to come up", LP); 128869008Stef else 128969008Stef pstatus("waiting for access to printer on %s", LP); 129069008Stef } 129169008Stef sleep(i); 129269008Stef } 129369008Stef pstatus("sending to %s port %d", LP, port); 129469008Stef *(--cp) = '@'; /* restore LP parameter in case we are called again */ 129569008Stef } 129669008Stef 129769008Stef /* 129869008Stef * Printer is connected to an RS232 port on this host 129969008Stef */ 130069008Stef static void 130169008Stef opentty() 130269008Stef { 130369008Stef register int i; 130469008Stef int resp, port; 130569008Stef 130669008Stef for (i = 1; ; i = i < 32 ? i << 1 : i) { 130769008Stef pfd = open(LP, RW ? O_RDWR : O_WRONLY); 130869008Stef if (pfd >= 0) { 130969008Stef delay(500); 131069008Stef break; 131169008Stef } 131269008Stef if (errno == ENOENT) { 131369008Stef syslog(LOG_ERR, "%s: %m", LP); 131469008Stef exit(1); 131569008Stef } 131669008Stef if (i == 1) 131769008Stef pstatus("waiting for %s to become ready (offline ?)", 131869008Stef printer); 131969008Stef sleep(i); 132069008Stef } 132169008Stef if (isatty(pfd)) 132269008Stef setty(); 132369008Stef pstatus("%s is ready and printing", printer); 132469008Stef } 132569008Stef 132669008Stef /* 132769008Stef * Printer is on a remote host 132869008Stef */ 132969008Stef static void 133069008Stef openrem() 133169008Stef { 133269008Stef register int i, n; 133369008Stef int resp, port; 133469008Stef 133569008Stef for (i = 1; ; i = i < 256 ? i << 1 : i) { 133669008Stef resp = -1; 133769008Stef pfd = getport(RM, 0); 133869008Stef if (pfd >= 0) { 133969008Stef (void) sprintf(line, "\2%s\n", RP); 134069008Stef n = strlen(line); 134169008Stef if (write(pfd, line, n) == n && 134269008Stef (resp = response()) == '\0') 134369008Stef break; 134469008Stef (void) close(pfd); 134569008Stef } 134669008Stef if (i == 1) { 134769008Stef if (resp < 0) 134869008Stef pstatus("waiting for %s to come up", RM); 134969008Stef else { 135069008Stef pstatus("waiting for queue to be enabled on %s", 135169008Stef RM); 135269008Stef i = 256; 135369008Stef } 135469008Stef } 135569008Stef sleep(i); 135669008Stef } 135769008Stef pstatus("sending to %s", RM); 135869008Stef } 135969008Stef 136012111Sralph struct bauds { 136112111Sralph int baud; 136212111Sralph int speed; 136312111Sralph } bauds[] = { 136412111Sralph 50, B50, 136512111Sralph 75, B75, 136612111Sralph 110, B110, 136712111Sralph 134, B134, 136812111Sralph 150, B150, 136912111Sralph 200, B200, 137012111Sralph 300, B300, 137112111Sralph 600, B600, 137212111Sralph 1200, B1200, 137312111Sralph 1800, B1800, 137412111Sralph 2400, B2400, 137512111Sralph 4800, B4800, 137612111Sralph 9600, B9600, 137712111Sralph 19200, EXTA, 137812111Sralph 38400, EXTB, 137912111Sralph 0, 0 138012111Sralph }; 138112111Sralph 138212111Sralph /* 138312111Sralph * setup tty lines. 138412111Sralph */ 138555474Sbostic static void 138612111Sralph setty() 138712111Sralph { 138812111Sralph struct sgttyb ttybuf; 138912111Sralph register struct bauds *bp; 139012111Sralph 139112111Sralph if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) { 139216762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer); 139312111Sralph exit(1); 139412111Sralph } 139512111Sralph if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) { 139616762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCGETP): %m", printer); 139712111Sralph exit(1); 139812111Sralph } 139912111Sralph if (BR > 0) { 140012111Sralph for (bp = bauds; bp->baud; bp++) 140112111Sralph if (BR == bp->baud) 140212111Sralph break; 140312111Sralph if (!bp->baud) { 140416762Sralph syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR); 140512111Sralph exit(1); 140612111Sralph } 140712111Sralph ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed; 140812111Sralph } 140913169Sralph ttybuf.sg_flags &= ~FC; 141013169Sralph ttybuf.sg_flags |= FS; 141112111Sralph if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) { 141216762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCSETP): %m", printer); 141312111Sralph exit(1); 141412111Sralph } 141512111Sralph if (XC) { 141612111Sralph if (ioctl(pfd, TIOCLBIC, &XC) < 0) { 141716762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCLBIC): %m", printer); 141812111Sralph exit(1); 141912111Sralph } 142012111Sralph } 142112111Sralph if (XS) { 142212111Sralph if (ioctl(pfd, TIOCLBIS, &XS) < 0) { 142316762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCLBIS): %m", printer); 142412111Sralph exit(1); 142512111Sralph } 142612111Sralph } 142712111Sralph } 142812463Sralph 142955474Sbostic #if __STDC__ 143055474Sbostic #include <stdarg.h> 143155474Sbostic #else 143255474Sbostic #include <varargs.h> 143355474Sbostic #endif 143455474Sbostic 1435*69061Stef static void 143655474Sbostic #if __STDC__ 143755474Sbostic pstatus(const char *msg, ...) 143855474Sbostic #else 143955474Sbostic pstatus(msg, va_alist) 144012463Sralph char *msg; 144155474Sbostic va_dcl 144255474Sbostic #endif 144312463Sralph { 144412463Sralph register int fd; 144512463Sralph char buf[BUFSIZ]; 144655474Sbostic va_list ap; 144755474Sbostic #if __STDC__ 144855474Sbostic va_start(ap, msg); 144955474Sbostic #else 145055474Sbostic va_start(ap); 145155474Sbostic #endif 145212463Sralph 145312463Sralph umask(0); 145413148Ssam fd = open(ST, O_WRONLY|O_CREAT, 0664); 145516762Sralph if (fd < 0 || flock(fd, LOCK_EX) < 0) { 145616762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, ST); 145716762Sralph exit(1); 145816762Sralph } 145913148Ssam ftruncate(fd, 0); 146055474Sbostic (void)vsnprintf(buf, sizeof(buf), msg, ap); 146155474Sbostic va_end(ap); 146212463Sralph strcat(buf, "\n"); 146312463Sralph (void) write(fd, buf, strlen(buf)); 146412463Sralph (void) close(fd); 146512463Sralph } 1466