122437Sdist /* 222437Sdist * Copyright (c) 1983 Regents of the University of California. 334203Sbostic * All rights reserved. 434203Sbostic * 542802Sbostic * %sccs.include.redist.c% 622437Sdist */ 722437Sdist 813954Ssam #ifndef lint 9*55474Sbostic static char sccsid[] = "@(#)printjob.c 5.15 (Berkeley) 07/21/92"; 1034203Sbostic #endif /* not lint */ 1113954Ssam 1212111Sralph /* 1312111Sralph * printjob -- print jobs in the queue. 1412111Sralph * 1512111Sralph * NOTE: the lock file is used to pass information to lpq and lprm. 1612111Sralph * it does not need to be removed because file locks are dynamic. 1712111Sralph */ 1812111Sralph 19*55474Sbostic #include <sys/param.h> 20*55474Sbostic #include <sys/wait.h> 21*55474Sbostic #include <sys/stat.h> 22*55474Sbostic 23*55474Sbostic #include <signal.h> 24*55474Sbostic #include <sgtty.h> 25*55474Sbostic #include <syslog.h> 26*55474Sbostic #include <fcntl.h> 27*55474Sbostic #include <dirent.h> 28*55474Sbostic #include <errno.h> 29*55474Sbostic #include <stdio.h> 30*55474Sbostic #include <string.h> 3112111Sralph #include "lp.h" 32*55474Sbostic #include "lp.local.h" 3337968Sbostic #include "pathnames.h" 34*55474Sbostic #include "extern.h" 3512111Sralph 3616762Sralph #define DORETURN 0 /* absorb fork error */ 3716762Sralph #define DOABORT 1 /* abort if dofork fails */ 3812111Sralph 3917463Sralph /* 4017463Sralph * Error tokens 4117463Sralph */ 4217463Sralph #define REPRINT -2 4317463Sralph #define ERROR -1 4417463Sralph #define OK 0 4517463Sralph #define FATALERR 1 4617463Sralph #define NOACCT 2 4717463Sralph #define FILTERERR 3 4817463Sralph #define ACCESS 4 4917463Sralph 5016762Sralph char title[80]; /* ``pr'' title */ 5116762Sralph FILE *cfp; /* control file */ 5216762Sralph int pfd; /* printer file descriptor */ 5316762Sralph int ofd; /* output filter file descriptor */ 5416762Sralph int lfd; /* lock file descriptor */ 5516762Sralph int pid; /* pid of lpd process */ 5616762Sralph int prchild; /* id of pr process */ 5716762Sralph int child; /* id of any filters */ 5816762Sralph int ofilter; /* id of output filter, if any */ 5916762Sralph int tof; /* true if at top of form */ 6016762Sralph int remote; /* true if sending files to remote */ 6117463Sralph dev_t fdev; /* device of file pointed to by symlink */ 6217463Sralph ino_t fino; /* inode of file pointed to by symlink */ 6312111Sralph 6416762Sralph char fromhost[32]; /* user's host machine */ 6516762Sralph char logname[32]; /* user's login name */ 6616762Sralph char jobname[100]; /* job or file name */ 6716762Sralph char class[32]; /* classification field */ 6816762Sralph char width[10] = "-w"; /* page width in characters */ 6916762Sralph char length[10] = "-l"; /* page length in lines */ 7016762Sralph char pxwidth[10] = "-x"; /* page width in pixels */ 7116762Sralph char pxlength[10] = "-y"; /* page length in pixels */ 7216762Sralph char indent[10] = "-i0"; /* indentation size in characters */ 7339954Smckusick char tempfile[] = "errsXXXXXX"; /* file name for filter output */ 7412111Sralph 75*55474Sbostic static void abortpr __P((int)); 76*55474Sbostic static void banner __P((char *, char *)); 77*55474Sbostic static int dofork __P((int)); 78*55474Sbostic static int dropit __P((int)); 79*55474Sbostic static void init __P((void)); 80*55474Sbostic static void openpr __P((void)); 81*55474Sbostic static int print __P((int, char *)); 82*55474Sbostic static int printit __P((char *)); 83*55474Sbostic static void pstatus __P((const char *, ...)); 84*55474Sbostic static char response __P((void)); 85*55474Sbostic static void scan_out __P((int, char *, int)); 86*55474Sbostic static char *scnline __P((int, char *, int)); 87*55474Sbostic static int sendfile __P((int, char *)); 88*55474Sbostic static int sendit __P((char *)); 89*55474Sbostic static void sendmail __P((char *, int)); 90*55474Sbostic static void setty __P((void)); 91*55474Sbostic 92*55474Sbostic void 9312111Sralph printjob() 9412111Sralph { 9512111Sralph struct stat stb; 9612111Sralph register struct queue *q, **qp; 9712111Sralph struct queue **queue; 9812111Sralph register int i, nitems; 9912111Sralph long pidoff; 10016762Sralph int count = 0; 10112111Sralph 10212111Sralph init(); /* set up capabilities */ 10313442Sralph (void) write(1, "", 1); /* ack that daemon is started */ 10425496Seric (void) close(2); /* set up log file */ 10525496Seric if (open(LF, O_WRONLY|O_APPEND, 0664) < 0) { 10625496Seric syslog(LOG_ERR, "%s: %m", LF); 10737968Sbostic (void) open(_PATH_DEVNULL, O_WRONLY); 10825496Seric } 10916762Sralph setgid(getegid()); 11012463Sralph pid = getpid(); /* for use with lprm */ 11112111Sralph setpgrp(0, pid); 11216762Sralph signal(SIGHUP, abortpr); 11316762Sralph signal(SIGINT, abortpr); 11416762Sralph signal(SIGQUIT, abortpr); 11516762Sralph signal(SIGTERM, abortpr); 11612111Sralph 11739954Smckusick (void) mktemp(tempfile); 11815811Sralph 11912111Sralph /* 12012111Sralph * uses short form file names 12112111Sralph */ 12212111Sralph if (chdir(SD) < 0) { 12316762Sralph syslog(LOG_ERR, "%s: %m", SD); 12412111Sralph exit(1); 12512111Sralph } 12612463Sralph if (stat(LO, &stb) == 0 && (stb.st_mode & 0100)) 12712463Sralph exit(0); /* printing disabled */ 12814150Sralph lfd = open(LO, O_WRONLY|O_CREAT, 0644); 12913169Sralph if (lfd < 0) { 13016762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, LO); 13113169Sralph exit(1); 13213169Sralph } 13313169Sralph if (flock(lfd, LOCK_EX|LOCK_NB) < 0) { 13412111Sralph if (errno == EWOULDBLOCK) /* active deamon present */ 13512111Sralph exit(0); 13616762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, LO); 13712111Sralph exit(1); 13812111Sralph } 13913148Ssam ftruncate(lfd, 0); 14012111Sralph /* 14112111Sralph * write process id for others to know 14212111Sralph */ 14312111Sralph sprintf(line, "%u\n", pid); 14412111Sralph pidoff = i = strlen(line); 14512463Sralph if (write(lfd, line, i) != i) { 14616762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, LO); 14712111Sralph exit(1); 14812111Sralph } 14912111Sralph /* 15012111Sralph * search the spool directory for work and sort by queue order. 15112111Sralph */ 15212111Sralph if ((nitems = getq(&queue)) < 0) { 15316762Sralph syslog(LOG_ERR, "%s: can't scan %s", printer, SD); 15412111Sralph exit(1); 15512111Sralph } 15612463Sralph if (nitems == 0) /* no work to do */ 15712111Sralph exit(0); 15813169Sralph if (stb.st_mode & 01) { /* reset queue flag */ 15913169Sralph if (fchmod(lfd, stb.st_mode & 0776) < 0) 16016762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, LO); 16113169Sralph } 16212463Sralph openpr(); /* open printer or remote */ 16312463Sralph again: 16412111Sralph /* 16512111Sralph * we found something to do now do it -- 16612111Sralph * write the name of the current control file into the lock file 16712111Sralph * so the spool queue program can tell what we're working on 16812111Sralph */ 16912111Sralph for (qp = queue; nitems--; free((char *) q)) { 17012111Sralph q = *qp++; 17112111Sralph if (stat(q->q_name, &stb) < 0) 17212111Sralph continue; 17312463Sralph restart: 174*55474Sbostic (void) lseek(lfd, (off_t)pidoff, 0); 17512111Sralph (void) sprintf(line, "%s\n", q->q_name); 17612111Sralph i = strlen(line); 17712111Sralph if (write(lfd, line, i) != i) 17816762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, LO); 17912111Sralph if (!remote) 18012111Sralph i = printit(q->q_name); 18112111Sralph else 18212111Sralph i = sendit(q->q_name); 18312463Sralph /* 18413169Sralph * Check to see if we are supposed to stop printing or 18513169Sralph * if we are to rebuild the queue. 18612463Sralph */ 18713169Sralph if (fstat(lfd, &stb) == 0) { 18816762Sralph /* stop printing before starting next job? */ 18913169Sralph if (stb.st_mode & 0100) 19013169Sralph goto done; 19116762Sralph /* rebuild queue (after lpc topq) */ 19213169Sralph if (stb.st_mode & 01) { 19313169Sralph for (free((char *) q); nitems--; free((char *) q)) 19413169Sralph q = *qp++; 19513169Sralph if (fchmod(lfd, stb.st_mode & 0776) < 0) 19616762Sralph syslog(LOG_WARNING, "%s: %s: %m", 19716762Sralph printer, LO); 19813169Sralph break; 19913169Sralph } 20013169Sralph } 20117463Sralph if (i == OK) /* file ok and printed */ 20214150Sralph count++; 20317463Sralph else if (i == REPRINT) { /* try reprinting the job */ 20416762Sralph syslog(LOG_INFO, "restarting %s", printer); 20512111Sralph if (ofilter > 0) { 20612111Sralph kill(ofilter, SIGCONT); /* to be sure */ 20712111Sralph (void) close(ofd); 20812111Sralph while ((i = wait(0)) > 0 && i != ofilter) 20912111Sralph ; 21012111Sralph ofilter = 0; 21112111Sralph } 21212463Sralph (void) close(pfd); /* close printer */ 21315811Sralph if (ftruncate(lfd, pidoff) < 0) 21416762Sralph syslog(LOG_WARNING, "%s: %s: %m", printer, LO); 21512463Sralph openpr(); /* try to reopen printer */ 21612111Sralph goto restart; 21712111Sralph } 21812111Sralph } 21912111Sralph free((char *) queue); 22012463Sralph /* 22112463Sralph * search the spool directory for more work. 22212463Sralph */ 22312463Sralph if ((nitems = getq(&queue)) < 0) { 22416762Sralph syslog(LOG_ERR, "%s: can't scan %s", printer, SD); 22512463Sralph exit(1); 22612463Sralph } 22712463Sralph if (nitems == 0) { /* no more work to do */ 22812463Sralph done: 22914150Sralph if (count > 0) { /* Files actually printed */ 23014150Sralph if (!SF && !tof) 23114150Sralph (void) write(ofd, FF, strlen(FF)); 23214150Sralph if (TR != NULL) /* output trailer */ 23314150Sralph (void) write(ofd, TR, strlen(TR)); 23414150Sralph } 23539954Smckusick (void) unlink(tempfile); 23612463Sralph exit(0); 23712463Sralph } 23812111Sralph goto again; 23912111Sralph } 24012111Sralph 24112111Sralph char fonts[4][50]; /* fonts for troff */ 24212111Sralph 24337968Sbostic char ifonts[4][40] = { 24437968Sbostic _PATH_VFONTR, 24537968Sbostic _PATH_VFONTI, 24637968Sbostic _PATH_VFONTB, 24737968Sbostic _PATH_VFONTS, 24812111Sralph }; 24912111Sralph 25012111Sralph /* 25112111Sralph * The remaining part is the reading of the control file (cf) 25212111Sralph * and performing the various actions. 25312111Sralph */ 254*55474Sbostic static int 25512111Sralph printit(file) 25612111Sralph char *file; 25712111Sralph { 25812111Sralph register int i; 25917463Sralph char *cp; 26017463Sralph int bombed = OK; 26112111Sralph 26212111Sralph /* 26317463Sralph * open control file; ignore if no longer there. 26412111Sralph */ 26512111Sralph if ((cfp = fopen(file, "r")) == NULL) { 26616762Sralph syslog(LOG_INFO, "%s: %s: %m", printer, file); 26717463Sralph return(OK); 26812111Sralph } 26912111Sralph /* 27012111Sralph * Reset troff fonts. 27112111Sralph */ 27212111Sralph for (i = 0; i < 4; i++) 27312111Sralph strcpy(fonts[i], ifonts[i]); 27417339Sralph strcpy(width+2, "0"); 27517302Sralph strcpy(indent+2, "0"); 27612111Sralph 27712111Sralph /* 27812111Sralph * read the control file for work to do 27912111Sralph * 28012111Sralph * file format -- first character in the line is a command 28112111Sralph * rest of the line is the argument. 28212111Sralph * valid commands are: 28312111Sralph * 28417463Sralph * S -- "stat info" for symbolic link protection 28512111Sralph * J -- "job name" on banner page 28612111Sralph * C -- "class name" on banner page 28712111Sralph * L -- "literal" user's name to print on banner 28812111Sralph * T -- "title" for pr 28912111Sralph * H -- "host name" of machine where lpr was done 29012111Sralph * P -- "person" user's login name 29112581Sralph * I -- "indent" amount to indent output 29212111Sralph * f -- "file name" name of text file to print 29312111Sralph * l -- "file name" text file with control chars 29412111Sralph * p -- "file name" text file to print with pr(1) 29512111Sralph * t -- "file name" troff(1) file to print 29613233Sralph * n -- "file name" ditroff(1) file to print 29712111Sralph * d -- "file name" dvi file to print 29812111Sralph * g -- "file name" plot(1G) file to print 29912111Sralph * v -- "file name" plain raster file to print 30012111Sralph * c -- "file name" cifplot file to print 30112111Sralph * 1 -- "R font file" for troff 30212111Sralph * 2 -- "I font file" for troff 30312111Sralph * 3 -- "B font file" for troff 30412111Sralph * 4 -- "S font file" for troff 30512111Sralph * N -- "name" of file (used by lpq) 30612111Sralph * U -- "unlink" name of file to remove 30712111Sralph * (after we print it. (Pass 2 only)). 30812111Sralph * M -- "mail" to user when done printing 30912111Sralph * 31012111Sralph * getline reads a line and expands tabs to blanks 31112111Sralph */ 31212111Sralph 31312111Sralph /* pass 1 */ 31412111Sralph 31512111Sralph while (getline(cfp)) 31612111Sralph switch (line[0]) { 31712111Sralph case 'H': 31814150Sralph strcpy(fromhost, line+1); 31912111Sralph if (class[0] == '\0') 32015552Sralph strncpy(class, line+1, sizeof(class)-1); 32112111Sralph continue; 32212111Sralph 32312111Sralph case 'P': 32415552Sralph strncpy(logname, line+1, sizeof(logname)-1); 32512463Sralph if (RS) { /* restricted */ 326*55474Sbostic if (getpwnam(logname) == NULL) { 32717463Sralph bombed = NOACCT; 32815811Sralph sendmail(line+1, bombed); 32912463Sralph goto pass2; 33012463Sralph } 33112463Sralph } 33212111Sralph continue; 33312111Sralph 33417463Sralph case 'S': 33517463Sralph cp = line+1; 33617463Sralph i = 0; 33717463Sralph while (*cp >= '0' && *cp <= '9') 33817463Sralph i = i * 10 + (*cp++ - '0'); 33917463Sralph fdev = i; 34017463Sralph cp++; 34117463Sralph i = 0; 34217463Sralph while (*cp >= '0' && *cp <= '9') 34317463Sralph i = i * 10 + (*cp++ - '0'); 34417463Sralph fino = i; 34517463Sralph continue; 34617463Sralph 34712111Sralph case 'J': 34812111Sralph if (line[1] != '\0') 34915552Sralph strncpy(jobname, line+1, sizeof(jobname)-1); 35012111Sralph else 35112111Sralph strcpy(jobname, " "); 35212111Sralph continue; 35312111Sralph 35412111Sralph case 'C': 35512111Sralph if (line[1] != '\0') 35615552Sralph strncpy(class, line+1, sizeof(class)-1); 35712111Sralph else if (class[0] == '\0') 35815811Sralph gethostname(class, sizeof(class)); 35912111Sralph continue; 36012111Sralph 36112111Sralph case 'T': /* header title for pr */ 36215552Sralph strncpy(title, line+1, sizeof(title)-1); 36312111Sralph continue; 36412111Sralph 36512111Sralph case 'L': /* identification line */ 36618127Sralph if (!SH && !HL) 36712111Sralph banner(line+1, jobname); 36812111Sralph continue; 36912111Sralph 37012111Sralph case '1': /* troff fonts */ 37112111Sralph case '2': 37212111Sralph case '3': 37312111Sralph case '4': 37412111Sralph if (line[1] != '\0') 37512111Sralph strcpy(fonts[line[0]-'1'], line+1); 37612111Sralph continue; 37712111Sralph 37812111Sralph case 'W': /* page width */ 37915552Sralph strncpy(width+2, line+1, sizeof(width)-3); 38012111Sralph continue; 38112111Sralph 38212581Sralph case 'I': /* indent amount */ 38315552Sralph strncpy(indent+2, line+1, sizeof(indent)-3); 38412581Sralph continue; 38512581Sralph 38612111Sralph default: /* some file to print */ 38715811Sralph switch (i = print(line[0], line+1)) { 38817463Sralph case ERROR: 38917463Sralph if (bombed == OK) 39017463Sralph bombed = FATALERR; 39115811Sralph break; 39217463Sralph case REPRINT: 39312111Sralph (void) fclose(cfp); 39417463Sralph return(REPRINT); 39517463Sralph case FILTERERR: 39617463Sralph case ACCESS: 39717463Sralph bombed = i; 39815811Sralph sendmail(logname, bombed); 39915811Sralph } 40012111Sralph title[0] = '\0'; 40112111Sralph continue; 40212111Sralph 40312111Sralph case 'N': 40412111Sralph case 'U': 40512111Sralph case 'M': 40612111Sralph continue; 40712111Sralph } 40812111Sralph 40912111Sralph /* pass 2 */ 41012111Sralph 41112463Sralph pass2: 41212111Sralph fseek(cfp, 0L, 0); 41312111Sralph while (getline(cfp)) 41412111Sralph switch (line[0]) { 41518127Sralph case 'L': /* identification line */ 41618127Sralph if (!SH && HL) 41718127Sralph banner(line+1, jobname); 41818127Sralph continue; 41918127Sralph 42012111Sralph case 'M': 42117463Sralph if (bombed < NOACCT) /* already sent if >= NOACCT */ 42215811Sralph sendmail(line+1, bombed); 42312111Sralph continue; 42412111Sralph 42512111Sralph case 'U': 42612111Sralph (void) unlink(line+1); 42712111Sralph } 42812111Sralph /* 42915811Sralph * clean-up in case another control file exists 43012111Sralph */ 43112111Sralph (void) fclose(cfp); 43212111Sralph (void) unlink(file); 43317463Sralph return(bombed == OK ? OK : ERROR); 43412111Sralph } 43512111Sralph 43612111Sralph /* 43712111Sralph * Print a file. 43813233Sralph * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}. 43915811Sralph * Return -1 if a non-recoverable error occured, 44015811Sralph * 2 if the filter detected some errors (but printed the job anyway), 44115811Sralph * 1 if we should try to reprint this job and 44212111Sralph * 0 if all is well. 44312111Sralph * Note: all filters take stdin as the file, stdout as the printer, 44412111Sralph * stderr as the log file, and must not ignore SIGINT. 44512111Sralph */ 446*55474Sbostic static int 44712111Sralph print(format, file) 44812111Sralph int format; 44912111Sralph char *file; 45012111Sralph { 45115811Sralph register int n; 45212111Sralph register char *prog; 45315811Sralph int fi, fo; 45439954Smckusick FILE *fp; 45512111Sralph char *av[15], buf[BUFSIZ]; 45612111Sralph int pid, p[2], stopped = 0; 45712111Sralph union wait status; 45817463Sralph struct stat stb; 45912111Sralph 46017463Sralph if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0) 46117463Sralph return(ERROR); 46217463Sralph /* 46317463Sralph * Check to see if data file is a symbolic link. If so, it should 46417463Sralph * still point to the same file or someone is trying to print 46517463Sralph * something he shouldn't. 46617463Sralph */ 46717463Sralph if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 && 46817463Sralph (stb.st_dev != fdev || stb.st_ino != fino)) 46917463Sralph return(ACCESS); 47012111Sralph if (!SF && !tof) { /* start on a fresh page */ 47112111Sralph (void) write(ofd, FF, strlen(FF)); 47212111Sralph tof = 1; 47312111Sralph } 47412111Sralph if (IF == NULL && (format == 'f' || format == 'l')) { 47512111Sralph tof = 0; 47612111Sralph while ((n = read(fi, buf, BUFSIZ)) > 0) 47712111Sralph if (write(ofd, buf, n) != n) { 47812111Sralph (void) close(fi); 47917463Sralph return(REPRINT); 48012111Sralph } 48112111Sralph (void) close(fi); 48217463Sralph return(OK); 48312111Sralph } 48412111Sralph switch (format) { 48512111Sralph case 'p': /* print file using 'pr' */ 48612111Sralph if (IF == NULL) { /* use output filter */ 48737968Sbostic prog = _PATH_PR; 48812111Sralph av[0] = "pr"; 48912111Sralph av[1] = width; 49012111Sralph av[2] = length; 49112111Sralph av[3] = "-h"; 49212111Sralph av[4] = *title ? title : " "; 49312111Sralph av[5] = 0; 49412111Sralph fo = ofd; 49512111Sralph goto start; 49612111Sralph } 49712111Sralph pipe(p); 49812111Sralph if ((prchild = dofork(DORETURN)) == 0) { /* child */ 49912111Sralph dup2(fi, 0); /* file is stdin */ 50012111Sralph dup2(p[1], 1); /* pipe is stdout */ 50112111Sralph for (n = 3; n < NOFILE; n++) 50212111Sralph (void) close(n); 50337968Sbostic execl(_PATH_PR, "pr", width, length, 50437968Sbostic "-h", *title ? title : " ", 0); 50537968Sbostic syslog(LOG_ERR, "cannot execl %s", _PATH_PR); 50612111Sralph exit(2); 50712111Sralph } 50812111Sralph (void) close(p[1]); /* close output side */ 50912111Sralph (void) close(fi); 51012111Sralph if (prchild < 0) { 51112111Sralph prchild = 0; 51212111Sralph (void) close(p[0]); 51317463Sralph return(ERROR); 51412111Sralph } 51512111Sralph fi = p[0]; /* use pipe for input */ 51612111Sralph case 'f': /* print plain text file */ 51712111Sralph prog = IF; 51812111Sralph av[1] = width; 51912111Sralph av[2] = length; 52012581Sralph av[3] = indent; 52112581Sralph n = 4; 52212111Sralph break; 52312111Sralph case 'l': /* like 'f' but pass control characters */ 52412111Sralph prog = IF; 52514325Sralph av[1] = "-c"; 52612111Sralph av[2] = width; 52712111Sralph av[3] = length; 52812581Sralph av[4] = indent; 52912581Sralph n = 5; 53012111Sralph break; 53112463Sralph case 'r': /* print a fortran text file */ 53212463Sralph prog = RF; 53312463Sralph av[1] = width; 53412463Sralph av[2] = length; 53512463Sralph n = 3; 53612463Sralph break; 53712111Sralph case 't': /* print troff output */ 53813233Sralph case 'n': /* print ditroff output */ 53912463Sralph case 'd': /* print tex output */ 54012111Sralph (void) unlink(".railmag"); 54112463Sralph if ((fo = creat(".railmag", FILMOD)) < 0) { 54216762Sralph syslog(LOG_ERR, "%s: cannot create .railmag", printer); 54312111Sralph (void) unlink(".railmag"); 54412111Sralph } else { 54512111Sralph for (n = 0; n < 4; n++) { 54612111Sralph if (fonts[n][0] != '/') 54754520Sbostic (void) write(fo, _PATH_VFONT, 54854520Sbostic sizeof(_PATH_VFONT) - 1); 54912111Sralph (void) write(fo, fonts[n], strlen(fonts[n])); 55012111Sralph (void) write(fo, "\n", 1); 55112111Sralph } 55212111Sralph (void) close(fo); 55312111Sralph } 55413233Sralph prog = (format == 't') ? TF : (format == 'n') ? NF : DF; 55512463Sralph av[1] = pxwidth; 55612463Sralph av[2] = pxlength; 55712463Sralph n = 3; 55812111Sralph break; 55912111Sralph case 'c': /* print cifplot output */ 56012111Sralph prog = CF; 56112463Sralph av[1] = pxwidth; 56212463Sralph av[2] = pxlength; 56312463Sralph n = 3; 56412111Sralph break; 56512111Sralph case 'g': /* print plot(1G) output */ 56612111Sralph prog = GF; 56712463Sralph av[1] = pxwidth; 56812463Sralph av[2] = pxlength; 56912463Sralph n = 3; 57012111Sralph break; 57112111Sralph case 'v': /* print raster output */ 57212111Sralph prog = VF; 57312463Sralph av[1] = pxwidth; 57412463Sralph av[2] = pxlength; 57512463Sralph n = 3; 57612111Sralph break; 57712111Sralph default: 57812111Sralph (void) close(fi); 57916762Sralph syslog(LOG_ERR, "%s: illegal format character '%c'", 58016762Sralph printer, format); 58117463Sralph return(ERROR); 58212111Sralph } 58312111Sralph if ((av[0] = rindex(prog, '/')) != NULL) 58412111Sralph av[0]++; 58512111Sralph else 58612111Sralph av[0] = prog; 58712111Sralph av[n++] = "-n"; 58812111Sralph av[n++] = logname; 58912111Sralph av[n++] = "-h"; 59014150Sralph av[n++] = fromhost; 59112111Sralph av[n++] = AF; 59212111Sralph av[n] = 0; 59312111Sralph fo = pfd; 59412111Sralph if (ofilter > 0) { /* stop output filter */ 59512111Sralph write(ofd, "\031\1", 2); 59646912Sbostic while ((pid = 59746912Sbostic wait3((int *)&status, WUNTRACED, 0)) > 0 && pid != ofilter) 59812111Sralph ; 59912111Sralph if (status.w_stopval != WSTOPPED) { 60012111Sralph (void) close(fi); 60116762Sralph syslog(LOG_WARNING, "%s: output filter died (%d)", 60216762Sralph printer, status.w_retcode); 60317463Sralph return(REPRINT); 60412111Sralph } 60512111Sralph stopped++; 60612111Sralph } 60712111Sralph start: 60812111Sralph if ((child = dofork(DORETURN)) == 0) { /* child */ 60912111Sralph dup2(fi, 0); 61012111Sralph dup2(fo, 1); 61139954Smckusick n = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, 0664); 61215811Sralph if (n >= 0) 61315811Sralph dup2(n, 2); 61412111Sralph for (n = 3; n < NOFILE; n++) 61512111Sralph (void) close(n); 61612111Sralph execv(prog, av); 61716762Sralph syslog(LOG_ERR, "cannot execv %s", prog); 61812111Sralph exit(2); 61912111Sralph } 62012111Sralph (void) close(fi); 62112111Sralph if (child < 0) 62212111Sralph status.w_retcode = 100; 62312111Sralph else 62446912Sbostic while ((pid = wait((int *)&status)) > 0 && pid != child) 62512111Sralph ; 62612111Sralph child = 0; 62712111Sralph prchild = 0; 62812111Sralph if (stopped) { /* restart output filter */ 62912111Sralph if (kill(ofilter, SIGCONT) < 0) { 63016762Sralph syslog(LOG_ERR, "cannot restart output filter"); 63112111Sralph exit(1); 63212111Sralph } 63312111Sralph } 63412111Sralph tof = 0; 63539954Smckusick 63639954Smckusick /* Copy filter output to "lf" logfile */ 63739954Smckusick if (fp = fopen(tempfile, "r")) { 63839954Smckusick char tbuf[512]; 63939954Smckusick 64039954Smckusick while (fgets(buf, sizeof(buf), fp)) 64139954Smckusick fputs(buf, stderr); 64239954Smckusick close(fp); 64339954Smckusick } 64439954Smckusick 64515811Sralph if (!WIFEXITED(status)) { 64616762Sralph syslog(LOG_WARNING, "%s: Daemon filter '%c' terminated (%d)", 64716762Sralph printer, format, status.w_termsig); 64817463Sralph return(ERROR); 64917463Sralph } 65017463Sralph switch (status.w_retcode) { 65117463Sralph case 0: 65217463Sralph tof = 1; 65317463Sralph return(OK); 65417463Sralph case 1: 65517463Sralph return(REPRINT); 65617463Sralph default: 65716762Sralph syslog(LOG_WARNING, "%s: Daemon filter '%c' exited (%d)", 65816762Sralph printer, format, status.w_retcode); 65917463Sralph case 2: 66017463Sralph return(ERROR); 66117463Sralph } 66212111Sralph } 66312111Sralph 66412111Sralph /* 66512111Sralph * Send the daemon control file (cf) and any data files. 66612111Sralph * Return -1 if a non-recoverable error occured, 1 if a recoverable error and 66712111Sralph * 0 if all is well. 66812111Sralph */ 669*55474Sbostic static int 67012111Sralph sendit(file) 67112111Sralph char *file; 67212111Sralph { 67317463Sralph register int i, err = OK; 67417463Sralph char *cp, last[BUFSIZ]; 67512111Sralph 67612111Sralph /* 67712111Sralph * open control file 67812111Sralph */ 67916762Sralph if ((cfp = fopen(file, "r")) == NULL) 68017463Sralph return(OK); 68112111Sralph /* 68212111Sralph * read the control file for work to do 68312111Sralph * 68412111Sralph * file format -- first character in the line is a command 68512111Sralph * rest of the line is the argument. 68612111Sralph * commands of interest are: 68712111Sralph * 68812111Sralph * a-z -- "file name" name of file to print 68912111Sralph * U -- "unlink" name of file to remove 69012111Sralph * (after we print it. (Pass 2 only)). 69112111Sralph */ 69212111Sralph 69312111Sralph /* 69412111Sralph * pass 1 69512111Sralph */ 69612111Sralph while (getline(cfp)) { 69712111Sralph again: 69817463Sralph if (line[0] == 'S') { 69917463Sralph cp = line+1; 70017463Sralph i = 0; 70117463Sralph while (*cp >= '0' && *cp <= '9') 70217463Sralph i = i * 10 + (*cp++ - '0'); 70317463Sralph fdev = i; 70417463Sralph cp++; 70517463Sralph i = 0; 70617463Sralph while (*cp >= '0' && *cp <= '9') 70717463Sralph i = i * 10 + (*cp++ - '0'); 70817463Sralph fino = i; 70917463Sralph continue; 71017463Sralph } 71112111Sralph if (line[0] >= 'a' && line[0] <= 'z') { 71212111Sralph strcpy(last, line); 71317463Sralph while (i = getline(cfp)) 71412111Sralph if (strcmp(last, line)) 71512111Sralph break; 71617463Sralph switch (sendfile('\3', last+1)) { 71717463Sralph case OK: 71817463Sralph if (i) 71917463Sralph goto again; 72017463Sralph break; 72117463Sralph case REPRINT: 72212111Sralph (void) fclose(cfp); 72317463Sralph return(REPRINT); 72417463Sralph case ACCESS: 72517463Sralph sendmail(logname, ACCESS); 72617463Sralph case ERROR: 72717463Sralph err = ERROR; 72817463Sralph } 72912111Sralph break; 73012111Sralph } 73112111Sralph } 73217463Sralph if (err == OK && sendfile('\2', file) > 0) { 73312111Sralph (void) fclose(cfp); 73417463Sralph return(REPRINT); 73512111Sralph } 73612111Sralph /* 73712111Sralph * pass 2 73812111Sralph */ 73912111Sralph fseek(cfp, 0L, 0); 74012111Sralph while (getline(cfp)) 74112111Sralph if (line[0] == 'U') 74212111Sralph (void) unlink(line+1); 74312111Sralph /* 74417463Sralph * clean-up in case another control file exists 74512111Sralph */ 74612111Sralph (void) fclose(cfp); 74712111Sralph (void) unlink(file); 74817463Sralph return(err); 74912111Sralph } 75012111Sralph 75112111Sralph /* 75212111Sralph * Send a data file to the remote machine and spool it. 75312111Sralph * Return positive if we should try resending. 75412111Sralph */ 755*55474Sbostic static int 75612111Sralph sendfile(type, file) 757*55474Sbostic int type; 758*55474Sbostic char *file; 75912111Sralph { 76012111Sralph register int f, i, amt; 76112111Sralph struct stat stb; 76212111Sralph char buf[BUFSIZ]; 76316762Sralph int sizerr, resp; 76412111Sralph 76517463Sralph if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0) 76617463Sralph return(ERROR); 76717463Sralph /* 76817463Sralph * Check to see if data file is a symbolic link. If so, it should 76917463Sralph * still point to the same file or someone is trying to print something 77017463Sralph * he shouldn't. 77117463Sralph */ 77217463Sralph if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 && 77317463Sralph (stb.st_dev != fdev || stb.st_ino != fino)) 77417463Sralph return(ACCESS); 775*55474Sbostic (void) sprintf(buf, "%c%qd %s\n", type, stb.st_size, file); 77612111Sralph amt = strlen(buf); 77716762Sralph for (i = 0; ; i++) { 77816762Sralph if (write(pfd, buf, amt) != amt || 77916762Sralph (resp = response()) < 0 || resp == '\1') { 78016762Sralph (void) close(f); 78117463Sralph return(REPRINT); 78216762Sralph } else if (resp == '\0') 78316762Sralph break; 78416762Sralph if (i == 0) 785*55474Sbostic pstatus("no space on remote; waiting for queue to drain"); 78616762Sralph if (i == 10) 78724861Seric syslog(LOG_ALERT, "%s: can't send to %s; queue full", 78816762Sralph printer, RM); 78916762Sralph sleep(5 * 60); 79012692Sralph } 79116762Sralph if (i) 792*55474Sbostic pstatus("sending to %s", RM); 79312111Sralph sizerr = 0; 79412111Sralph for (i = 0; i < stb.st_size; i += BUFSIZ) { 79512111Sralph amt = BUFSIZ; 79612111Sralph if (i + amt > stb.st_size) 79712111Sralph amt = stb.st_size - i; 79812111Sralph if (sizerr == 0 && read(f, buf, amt) != amt) 79912111Sralph sizerr = 1; 80012692Sralph if (write(pfd, buf, amt) != amt) { 80112692Sralph (void) close(f); 80217463Sralph return(REPRINT); 80312692Sralph } 80412111Sralph } 805*55474Sbostic 806*55474Sbostic 807*55474Sbostic 808*55474Sbostic 80912111Sralph (void) close(f); 81012111Sralph if (sizerr) { 81116762Sralph syslog(LOG_INFO, "%s: %s: changed size", printer, file); 81217463Sralph /* tell recvjob to ignore this file */ 81317463Sralph (void) write(pfd, "\1", 1); 81417463Sralph return(ERROR); 81517463Sralph } 81617463Sralph if (write(pfd, "", 1) != 1 || response()) 81717463Sralph return(REPRINT); 81817463Sralph return(OK); 81912111Sralph } 82012111Sralph 82112111Sralph /* 82212111Sralph * Check to make sure there have been no errors and that both programs 82312111Sralph * are in sync with eachother. 82412111Sralph * Return non-zero if the connection was lost. 82512111Sralph */ 826*55474Sbostic static char 82716762Sralph response() 82812111Sralph { 82912111Sralph char resp; 83012111Sralph 83116762Sralph if (read(pfd, &resp, 1) != 1) { 83216762Sralph syslog(LOG_INFO, "%s: lost connection", printer); 83316762Sralph return(-1); 83412111Sralph } 83516762Sralph return(resp); 83612111Sralph } 83712111Sralph 83812111Sralph /* 83912111Sralph * Banner printing stuff 84012111Sralph */ 841*55474Sbostic static void 84212111Sralph banner(name1, name2) 84312111Sralph char *name1, *name2; 84412111Sralph { 84512111Sralph time_t tvec; 84612111Sralph extern char *ctime(); 84712111Sralph 84812111Sralph time(&tvec); 84912111Sralph if (!SF && !tof) 85012111Sralph (void) write(ofd, FF, strlen(FF)); 85112111Sralph if (SB) { /* short banner only */ 85212111Sralph if (class[0]) { 85312111Sralph (void) write(ofd, class, strlen(class)); 85412111Sralph (void) write(ofd, ":", 1); 85512111Sralph } 85612111Sralph (void) write(ofd, name1, strlen(name1)); 85712111Sralph (void) write(ofd, " Job: ", 7); 85812111Sralph (void) write(ofd, name2, strlen(name2)); 85912111Sralph (void) write(ofd, " Date: ", 8); 86012111Sralph (void) write(ofd, ctime(&tvec), 24); 86112111Sralph (void) write(ofd, "\n", 1); 86212111Sralph } else { /* normal banner */ 86312111Sralph (void) write(ofd, "\n\n\n", 3); 86412111Sralph scan_out(ofd, name1, '\0'); 86512111Sralph (void) write(ofd, "\n\n", 2); 86612111Sralph scan_out(ofd, name2, '\0'); 86712111Sralph if (class[0]) { 86812111Sralph (void) write(ofd,"\n\n\n",3); 86912111Sralph scan_out(ofd, class, '\0'); 87012111Sralph } 87112111Sralph (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15); 87212111Sralph (void) write(ofd, name2, strlen(name2)); 87312111Sralph (void) write(ofd, "\n\t\t\t\t\tDate: ", 12); 87412111Sralph (void) write(ofd, ctime(&tvec), 24); 87512111Sralph (void) write(ofd, "\n", 1); 87612111Sralph } 87712111Sralph if (!SF) 87812111Sralph (void) write(ofd, FF, strlen(FF)); 87912111Sralph tof = 1; 88012111Sralph } 88112111Sralph 882*55474Sbostic static char * 88312111Sralph scnline(key, p, c) 884*55474Sbostic register int key; 885*55474Sbostic register char *p; 886*55474Sbostic int c; 88712111Sralph { 88812111Sralph register scnwidth; 88912111Sralph 89012111Sralph for (scnwidth = WIDTH; --scnwidth;) { 89112111Sralph key <<= 1; 89212111Sralph *p++ = key & 0200 ? c : BACKGND; 89312111Sralph } 89412111Sralph return (p); 89512111Sralph } 89612111Sralph 89712111Sralph #define TRC(q) (((q)-' ')&0177) 89812111Sralph 899*55474Sbostic static void 90012111Sralph scan_out(scfd, scsp, dlm) 901*55474Sbostic int scfd, dlm; 902*55474Sbostic char *scsp; 90312111Sralph { 90412111Sralph register char *strp; 90512111Sralph register nchrs, j; 90612111Sralph char outbuf[LINELEN+1], *sp, c, cc; 90712111Sralph int d, scnhgt; 90812111Sralph extern char scnkey[][HEIGHT]; /* in lpdchar.c */ 90912111Sralph 91012111Sralph for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) { 91112111Sralph strp = &outbuf[0]; 91212111Sralph sp = scsp; 91312111Sralph for (nchrs = 0; ; ) { 91412111Sralph d = dropit(c = TRC(cc = *sp++)); 91512111Sralph if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d)) 91612111Sralph for (j = WIDTH; --j;) 91712111Sralph *strp++ = BACKGND; 91812111Sralph else 91912111Sralph strp = scnline(scnkey[c][scnhgt-1-d], strp, cc); 92012111Sralph if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1) 92112111Sralph break; 92212111Sralph *strp++ = BACKGND; 92312111Sralph *strp++ = BACKGND; 92412111Sralph } 92512111Sralph while (*--strp == BACKGND && strp >= outbuf) 92612111Sralph ; 92712111Sralph strp++; 92812111Sralph *strp++ = '\n'; 92912111Sralph (void) write(scfd, outbuf, strp-outbuf); 93012111Sralph } 93112111Sralph } 93212111Sralph 933*55474Sbostic static int 93412111Sralph dropit(c) 935*55474Sbostic int c; 93612111Sralph { 93712111Sralph switch(c) { 93812111Sralph 93912111Sralph case TRC('_'): 94012111Sralph case TRC(';'): 94112111Sralph case TRC(','): 94212111Sralph case TRC('g'): 94312111Sralph case TRC('j'): 94412111Sralph case TRC('p'): 94512111Sralph case TRC('q'): 94612111Sralph case TRC('y'): 94712111Sralph return (DROP); 94812111Sralph 94912111Sralph default: 95012111Sralph return (0); 95112111Sralph } 95212111Sralph } 95312111Sralph 95412111Sralph /* 95512111Sralph * sendmail --- 95612111Sralph * tell people about job completion 95712111Sralph */ 958*55474Sbostic static void 95915811Sralph sendmail(user, bombed) 96015811Sralph char *user; 96112111Sralph int bombed; 96212111Sralph { 96312111Sralph register int i; 96415811Sralph int p[2], s; 96512111Sralph register char *cp; 96612111Sralph char buf[100]; 96715811Sralph struct stat stb; 96815811Sralph FILE *fp; 96912111Sralph 97012111Sralph pipe(p); 97115811Sralph if ((s = dofork(DORETURN)) == 0) { /* child */ 97212111Sralph dup2(p[0], 0); 97312111Sralph for (i = 3; i < NOFILE; i++) 97412111Sralph (void) close(i); 97537968Sbostic if ((cp = rindex(_PATH_SENDMAIL, '/')) != NULL) 97612111Sralph cp++; 977*55474Sbostic else 97837968Sbostic cp = _PATH_SENDMAIL; 97915811Sralph sprintf(buf, "%s@%s", user, fromhost); 98037968Sbostic execl(_PATH_SENDMAIL, cp, buf, 0); 98112111Sralph exit(0); 98215811Sralph } else if (s > 0) { /* parent */ 98312111Sralph dup2(p[1], 1); 98415811Sralph printf("To: %s@%s\n", user, fromhost); 98512111Sralph printf("Subject: printer job\n\n"); 98612111Sralph printf("Your printer job "); 98712111Sralph if (*jobname) 98812111Sralph printf("(%s) ", jobname); 98912463Sralph switch (bombed) { 99017463Sralph case OK: 99112463Sralph printf("\ncompleted successfully\n"); 99212463Sralph break; 99312463Sralph default: 99417463Sralph case FATALERR: 99512463Sralph printf("\ncould not be printed\n"); 99612463Sralph break; 99717463Sralph case NOACCT: 99812463Sralph printf("\ncould not be printed without an account on %s\n", host); 99912463Sralph break; 100017463Sralph case FILTERERR: 100139954Smckusick if (stat(tempfile, &stb) < 0 || stb.st_size == 0 || 100239954Smckusick (fp = fopen(tempfile, "r")) == NULL) { 100315811Sralph printf("\nwas printed but had some errors\n"); 100415811Sralph break; 100515811Sralph } 100615811Sralph printf("\nwas printed but had the following errors:\n"); 100715811Sralph while ((i = getc(fp)) != EOF) 100815811Sralph putchar(i); 100915811Sralph (void) fclose(fp); 101017463Sralph break; 101117463Sralph case ACCESS: 101217463Sralph printf("\nwas not printed because it was not linked to the original file\n"); 101312463Sralph } 101412111Sralph fflush(stdout); 101512111Sralph (void) close(1); 101612111Sralph } 101712111Sralph (void) close(p[0]); 101812111Sralph (void) close(p[1]); 101915811Sralph wait(&s); 102012111Sralph } 102112111Sralph 102212111Sralph /* 102312111Sralph * dofork - fork with retries on failure 102412111Sralph */ 1025*55474Sbostic static int 102612111Sralph dofork(action) 102712111Sralph int action; 102812111Sralph { 102912111Sralph register int i, pid; 103012111Sralph 103112111Sralph for (i = 0; i < 20; i++) { 103212463Sralph if ((pid = fork()) < 0) { 103312111Sralph sleep((unsigned)(i*i)); 103412463Sralph continue; 103512463Sralph } 103612463Sralph /* 103712463Sralph * Child should run as daemon instead of root 103812463Sralph */ 103912463Sralph if (pid == 0) 104012463Sralph setuid(DU); 104112463Sralph return(pid); 104212111Sralph } 104316762Sralph syslog(LOG_ERR, "can't fork"); 104412111Sralph 104512111Sralph switch (action) { 104612111Sralph case DORETURN: 104712111Sralph return (-1); 104812111Sralph default: 104916762Sralph syslog(LOG_ERR, "bad action (%d) to dofork", action); 105012111Sralph /*FALL THRU*/ 105112111Sralph case DOABORT: 105212111Sralph exit(1); 105312111Sralph } 105412111Sralph /*NOTREACHED*/ 105512111Sralph } 105612111Sralph 105712111Sralph /* 105816762Sralph * Kill child processes to abort current job. 105912111Sralph */ 1060*55474Sbostic static void 1061*55474Sbostic abortpr(signo) 1062*55474Sbostic int signo; 106312111Sralph { 106439954Smckusick (void) unlink(tempfile); 106512111Sralph kill(0, SIGINT); 106612111Sralph if (ofilter > 0) 106712111Sralph kill(ofilter, SIGCONT); 106846912Sbostic while (wait(NULL) > 0) 106912111Sralph ; 107012111Sralph exit(0); 107112111Sralph } 107212111Sralph 1073*55474Sbostic static void 107412111Sralph init() 107512111Sralph { 107612111Sralph int status; 107738736Stef char *s; 107812111Sralph 107925468Stef if ((status = pgetent(line, printer)) < 0) { 108025468Stef syslog(LOG_ERR, "can't open printer description file"); 108125468Stef exit(1); 108225468Stef } else if (status == 0) { 108325468Stef syslog(LOG_ERR, "unknown printer: %s", printer); 108425468Stef exit(1); 108525468Stef } 108612111Sralph if ((LP = pgetstr("lp", &bp)) == NULL) 108737968Sbostic LP = _PATH_DEFDEVLP; 108812111Sralph if ((RP = pgetstr("rp", &bp)) == NULL) 108912463Sralph RP = DEFLP; 109012111Sralph if ((LO = pgetstr("lo", &bp)) == NULL) 109112111Sralph LO = DEFLOCK; 109212111Sralph if ((ST = pgetstr("st", &bp)) == NULL) 109312111Sralph ST = DEFSTAT; 109412111Sralph if ((LF = pgetstr("lf", &bp)) == NULL) 109537968Sbostic LF = _PATH_CONSOLE; 109612111Sralph if ((SD = pgetstr("sd", &bp)) == NULL) 109737968Sbostic SD = _PATH_DEFSPOOL; 109812111Sralph if ((DU = pgetnum("du")) < 0) 109912111Sralph DU = DEFUID; 110012111Sralph if ((FF = pgetstr("ff", &bp)) == NULL) 110112111Sralph FF = DEFFF; 110212111Sralph if ((PW = pgetnum("pw")) < 0) 110312111Sralph PW = DEFWIDTH; 110412111Sralph sprintf(&width[2], "%d", PW); 110512111Sralph if ((PL = pgetnum("pl")) < 0) 110612111Sralph PL = DEFLENGTH; 110712111Sralph sprintf(&length[2], "%d", PL); 110812463Sralph if ((PX = pgetnum("px")) < 0) 110912463Sralph PX = 0; 111012463Sralph sprintf(&pxwidth[2], "%d", PX); 111112463Sralph if ((PY = pgetnum("py")) < 0) 111212463Sralph PY = 0; 111312463Sralph sprintf(&pxlength[2], "%d", PY); 111412111Sralph RM = pgetstr("rm", &bp); 111538736Stef if (s = checkremote()) 111638736Stef syslog(LOG_WARNING, s); 111725468Stef 111812111Sralph AF = pgetstr("af", &bp); 111912111Sralph OF = pgetstr("of", &bp); 112012111Sralph IF = pgetstr("if", &bp); 112112463Sralph RF = pgetstr("rf", &bp); 112212111Sralph TF = pgetstr("tf", &bp); 112313233Sralph NF = pgetstr("nf", &bp); 112412111Sralph DF = pgetstr("df", &bp); 112512111Sralph GF = pgetstr("gf", &bp); 112612111Sralph VF = pgetstr("vf", &bp); 112712111Sralph CF = pgetstr("cf", &bp); 112812111Sralph TR = pgetstr("tr", &bp); 112912463Sralph RS = pgetflag("rs"); 113012111Sralph SF = pgetflag("sf"); 113112111Sralph SH = pgetflag("sh"); 113212111Sralph SB = pgetflag("sb"); 113318127Sralph HL = pgetflag("hl"); 113412111Sralph RW = pgetflag("rw"); 113512111Sralph BR = pgetnum("br"); 113612111Sralph if ((FC = pgetnum("fc")) < 0) 113712111Sralph FC = 0; 113812111Sralph if ((FS = pgetnum("fs")) < 0) 113912111Sralph FS = 0; 114012111Sralph if ((XC = pgetnum("xc")) < 0) 114112111Sralph XC = 0; 114212111Sralph if ((XS = pgetnum("xs")) < 0) 114312111Sralph XS = 0; 114412581Sralph tof = !pgetflag("fo"); 114512111Sralph } 114612111Sralph 114712463Sralph /* 114812463Sralph * Acquire line printer or remote connection. 114912463Sralph */ 1150*55474Sbostic static void 115112463Sralph openpr() 115212463Sralph { 115312463Sralph register int i, n; 115416762Sralph int resp; 115512463Sralph 115638736Stef if (!sendtorem && *LP) { 115712463Sralph for (i = 1; ; i = i < 32 ? i << 1 : i) { 115813148Ssam pfd = open(LP, RW ? O_RDWR : O_WRONLY); 115912463Sralph if (pfd >= 0) 116012463Sralph break; 116112463Sralph if (errno == ENOENT) { 116216762Sralph syslog(LOG_ERR, "%s: %m", LP); 116312463Sralph exit(1); 116412463Sralph } 116512463Sralph if (i == 1) 1166*55474Sbostic pstatus("waiting for %s to become ready (offline ?)", printer); 116712463Sralph sleep(i); 116812463Sralph } 116912463Sralph if (isatty(pfd)) 117012463Sralph setty(); 1171*55474Sbostic pstatus("%s is ready and printing", printer); 117212463Sralph } else if (RM != NULL) { 117316762Sralph for (i = 1; ; i = i < 256 ? i << 1 : i) { 117416762Sralph resp = -1; 117512528Sralph pfd = getport(RM); 117612463Sralph if (pfd >= 0) { 117712463Sralph (void) sprintf(line, "\2%s\n", RP); 117812463Sralph n = strlen(line); 117916762Sralph if (write(pfd, line, n) == n && 118016762Sralph (resp = response()) == '\0') 118112463Sralph break; 118216031Sralph (void) close(pfd); 118312463Sralph } 118416031Sralph if (i == 1) { 118516762Sralph if (resp < 0) 1186*55474Sbostic pstatus("waiting for %s to come up", RM); 118716762Sralph else { 1188*55474Sbostic pstatus("waiting for queue to be enabled on %s", RM); 118916762Sralph i = 256; 119016762Sralph } 119116031Sralph } 119212463Sralph sleep(i); 119312463Sralph } 1194*55474Sbostic pstatus("sending to %s", RM); 119512463Sralph remote = 1; 119612463Sralph } else { 119716762Sralph syslog(LOG_ERR, "%s: no line printer device or host name", 119816762Sralph printer); 119912463Sralph exit(1); 120012463Sralph } 120112463Sralph /* 120212463Sralph * Start up an output filter, if needed. 120312463Sralph */ 120440049Stef if (!remote && OF) { 120512463Sralph int p[2]; 120612463Sralph char *cp; 120712463Sralph 120812463Sralph pipe(p); 120912463Sralph if ((ofilter = dofork(DOABORT)) == 0) { /* child */ 121012463Sralph dup2(p[0], 0); /* pipe is std in */ 121112463Sralph dup2(pfd, 1); /* printer is std out */ 121212463Sralph for (i = 3; i < NOFILE; i++) 121312463Sralph (void) close(i); 121412463Sralph if ((cp = rindex(OF, '/')) == NULL) 121512463Sralph cp = OF; 121612463Sralph else 121712463Sralph cp++; 121812463Sralph execl(OF, cp, width, length, 0); 121916762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, OF); 122012463Sralph exit(1); 122112463Sralph } 122212463Sralph (void) close(p[0]); /* close input side */ 122312463Sralph ofd = p[1]; /* use pipe for output */ 122412463Sralph } else { 122512463Sralph ofd = pfd; 122612463Sralph ofilter = 0; 122712463Sralph } 122812463Sralph } 122912463Sralph 123012111Sralph struct bauds { 123112111Sralph int baud; 123212111Sralph int speed; 123312111Sralph } bauds[] = { 123412111Sralph 50, B50, 123512111Sralph 75, B75, 123612111Sralph 110, B110, 123712111Sralph 134, B134, 123812111Sralph 150, B150, 123912111Sralph 200, B200, 124012111Sralph 300, B300, 124112111Sralph 600, B600, 124212111Sralph 1200, B1200, 124312111Sralph 1800, B1800, 124412111Sralph 2400, B2400, 124512111Sralph 4800, B4800, 124612111Sralph 9600, B9600, 124712111Sralph 19200, EXTA, 124812111Sralph 38400, EXTB, 124912111Sralph 0, 0 125012111Sralph }; 125112111Sralph 125212111Sralph /* 125312111Sralph * setup tty lines. 125412111Sralph */ 1255*55474Sbostic static void 125612111Sralph setty() 125712111Sralph { 125812111Sralph struct sgttyb ttybuf; 125912111Sralph register struct bauds *bp; 126012111Sralph 126112111Sralph if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) { 126216762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer); 126312111Sralph exit(1); 126412111Sralph } 126512111Sralph if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) { 126616762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCGETP): %m", printer); 126712111Sralph exit(1); 126812111Sralph } 126912111Sralph if (BR > 0) { 127012111Sralph for (bp = bauds; bp->baud; bp++) 127112111Sralph if (BR == bp->baud) 127212111Sralph break; 127312111Sralph if (!bp->baud) { 127416762Sralph syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR); 127512111Sralph exit(1); 127612111Sralph } 127712111Sralph ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed; 127812111Sralph } 127913169Sralph ttybuf.sg_flags &= ~FC; 128013169Sralph ttybuf.sg_flags |= FS; 128112111Sralph if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) { 128216762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCSETP): %m", printer); 128312111Sralph exit(1); 128412111Sralph } 128512111Sralph if (XC) { 128612111Sralph if (ioctl(pfd, TIOCLBIC, &XC) < 0) { 128716762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCLBIC): %m", printer); 128812111Sralph exit(1); 128912111Sralph } 129012111Sralph } 129112111Sralph if (XS) { 129212111Sralph if (ioctl(pfd, TIOCLBIS, &XS) < 0) { 129316762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCLBIS): %m", printer); 129412111Sralph exit(1); 129512111Sralph } 129612111Sralph } 129712111Sralph } 129812463Sralph 1299*55474Sbostic #if __STDC__ 1300*55474Sbostic #include <stdarg.h> 1301*55474Sbostic #else 1302*55474Sbostic #include <varargs.h> 1303*55474Sbostic #endif 1304*55474Sbostic 1305*55474Sbostic void 1306*55474Sbostic #if __STDC__ 1307*55474Sbostic pstatus(const char *msg, ...) 1308*55474Sbostic #else 1309*55474Sbostic pstatus(msg, va_alist) 131012463Sralph char *msg; 1311*55474Sbostic va_dcl 1312*55474Sbostic #endif 131312463Sralph { 131412463Sralph register int fd; 131512463Sralph char buf[BUFSIZ]; 1316*55474Sbostic va_list ap; 1317*55474Sbostic #if __STDC__ 1318*55474Sbostic va_start(ap, msg); 1319*55474Sbostic #else 1320*55474Sbostic va_start(ap); 1321*55474Sbostic #endif 132212463Sralph 132312463Sralph umask(0); 132413148Ssam fd = open(ST, O_WRONLY|O_CREAT, 0664); 132516762Sralph if (fd < 0 || flock(fd, LOCK_EX) < 0) { 132616762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, ST); 132716762Sralph exit(1); 132816762Sralph } 132913148Ssam ftruncate(fd, 0); 1330*55474Sbostic (void)vsnprintf(buf, sizeof(buf), msg, ap); 1331*55474Sbostic va_end(ap); 133212463Sralph strcat(buf, "\n"); 133312463Sralph (void) write(fd, buf, strlen(buf)); 133412463Sralph (void) close(fd); 133512463Sralph } 1336