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*68972Stef static char sccsid[] = "@(#)printjob.c 8.3 (Berkeley) 04/27/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> 3155474Sbostic 3256123Selan #include <pwd.h> 3356123Selan #include <unistd.h> 3455474Sbostic #include <signal.h> 3555474Sbostic #include <sgtty.h> 3655474Sbostic #include <syslog.h> 3755474Sbostic #include <fcntl.h> 3855474Sbostic #include <dirent.h> 3955474Sbostic #include <errno.h> 4055474Sbostic #include <stdio.h> 4155474Sbostic #include <string.h> 4256123Selan #include <stdlib.h> 4312111Sralph #include "lp.h" 4455474Sbostic #include "lp.local.h" 4537968Sbostic #include "pathnames.h" 4655474Sbostic #include "extern.h" 4712111Sralph 4816762Sralph #define DORETURN 0 /* absorb fork error */ 4916762Sralph #define DOABORT 1 /* abort if dofork fails */ 5012111Sralph 5117463Sralph /* 5217463Sralph * Error tokens 5317463Sralph */ 5417463Sralph #define REPRINT -2 5517463Sralph #define ERROR -1 5617463Sralph #define OK 0 5717463Sralph #define FATALERR 1 5817463Sralph #define NOACCT 2 5917463Sralph #define FILTERERR 3 6017463Sralph #define ACCESS 4 6117463Sralph 6256123Selan static dev_t fdev; /* device of file pointed to by symlink */ 6356123Selan static ino_t fino; /* inode of file pointed to by symlink */ 6456123Selan static FILE *cfp; /* control file */ 6556123Selan static int child; /* id of any filters */ 6656123Selan static int lfd; /* lock file descriptor */ 6756123Selan static int ofd; /* output filter file descriptor */ 6856123Selan static int ofilter; /* id of output filter, if any */ 6956123Selan static int pfd; /* prstatic inter file descriptor */ 7056123Selan static int pid; /* pid of lpd process */ 7156123Selan static int prchild; /* id of pr process */ 7256123Selan static int remote; /* true if sending files to remote */ 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)); 9455474Sbostic static int print __P((int, char *)); 9555474Sbostic static int printit __P((char *)); 9655474Sbostic static void pstatus __P((const char *, ...)); 9755474Sbostic static char response __P((void)); 9855474Sbostic static void scan_out __P((int, char *, int)); 9955474Sbostic static char *scnline __P((int, char *, int)); 10055474Sbostic static int sendfile __P((int, char *)); 10155474Sbostic static int sendit __P((char *)); 10255474Sbostic static void sendmail __P((char *, int)); 10355474Sbostic static void setty __P((void)); 10455474Sbostic 10555474Sbostic void 10612111Sralph printjob() 10712111Sralph { 10812111Sralph struct stat stb; 10912111Sralph register struct queue *q, **qp; 11012111Sralph struct queue **queue; 11112111Sralph register int i, nitems; 112*68972Stef off_t pidoff; 11316762Sralph int count = 0; 11412111Sralph 11512111Sralph init(); /* set up capabilities */ 11613442Sralph (void) write(1, "", 1); /* ack that daemon is started */ 11725496Seric (void) close(2); /* set up log file */ 11825496Seric if (open(LF, O_WRONLY|O_APPEND, 0664) < 0) { 11925496Seric syslog(LOG_ERR, "%s: %m", LF); 12037968Sbostic (void) open(_PATH_DEVNULL, O_WRONLY); 12125496Seric } 12216762Sralph setgid(getegid()); 12312463Sralph pid = getpid(); /* for use with lprm */ 12412111Sralph setpgrp(0, pid); 12516762Sralph signal(SIGHUP, abortpr); 12616762Sralph signal(SIGINT, abortpr); 12716762Sralph signal(SIGQUIT, abortpr); 12816762Sralph signal(SIGTERM, abortpr); 12912111Sralph 13039954Smckusick (void) mktemp(tempfile); 13115811Sralph 13212111Sralph /* 13312111Sralph * uses short form file names 13412111Sralph */ 13512111Sralph if (chdir(SD) < 0) { 13616762Sralph syslog(LOG_ERR, "%s: %m", SD); 13712111Sralph exit(1); 13812111Sralph } 13912463Sralph if (stat(LO, &stb) == 0 && (stb.st_mode & 0100)) 14012463Sralph exit(0); /* printing disabled */ 14114150Sralph lfd = open(LO, O_WRONLY|O_CREAT, 0644); 14213169Sralph if (lfd < 0) { 14316762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, LO); 14413169Sralph exit(1); 14513169Sralph } 14613169Sralph if (flock(lfd, LOCK_EX|LOCK_NB) < 0) { 14712111Sralph if (errno == EWOULDBLOCK) /* active deamon present */ 14812111Sralph exit(0); 14916762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, LO); 15012111Sralph exit(1); 15112111Sralph } 15213148Ssam ftruncate(lfd, 0); 15312111Sralph /* 15412111Sralph * write process id for others to know 15512111Sralph */ 15612111Sralph sprintf(line, "%u\n", pid); 15712111Sralph pidoff = i = strlen(line); 15812463Sralph if (write(lfd, line, i) != i) { 15916762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, LO); 16012111Sralph exit(1); 16112111Sralph } 16212111Sralph /* 16312111Sralph * search the spool directory for work and sort by queue order. 16412111Sralph */ 16512111Sralph if ((nitems = getq(&queue)) < 0) { 16616762Sralph syslog(LOG_ERR, "%s: can't scan %s", printer, SD); 16712111Sralph exit(1); 16812111Sralph } 16912463Sralph if (nitems == 0) /* no work to do */ 17012111Sralph exit(0); 17113169Sralph if (stb.st_mode & 01) { /* reset queue flag */ 17213169Sralph if (fchmod(lfd, stb.st_mode & 0776) < 0) 17316762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, LO); 17413169Sralph } 17512463Sralph openpr(); /* open printer or remote */ 17612463Sralph again: 17712111Sralph /* 17812111Sralph * we found something to do now do it -- 17912111Sralph * write the name of the current control file into the lock file 18012111Sralph * so the spool queue program can tell what we're working on 18112111Sralph */ 18212111Sralph for (qp = queue; nitems--; free((char *) q)) { 18312111Sralph q = *qp++; 18412111Sralph if (stat(q->q_name, &stb) < 0) 18512111Sralph continue; 18612463Sralph restart: 187*68972Stef (void) lseek(lfd, pidoff, 0); 18812111Sralph (void) sprintf(line, "%s\n", q->q_name); 18912111Sralph i = strlen(line); 19012111Sralph if (write(lfd, line, i) != i) 19116762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, LO); 19212111Sralph if (!remote) 19312111Sralph i = printit(q->q_name); 19412111Sralph else 19512111Sralph i = sendit(q->q_name); 19612463Sralph /* 19713169Sralph * Check to see if we are supposed to stop printing or 19813169Sralph * if we are to rebuild the queue. 19912463Sralph */ 20013169Sralph if (fstat(lfd, &stb) == 0) { 20116762Sralph /* stop printing before starting next job? */ 20213169Sralph if (stb.st_mode & 0100) 20313169Sralph goto done; 20416762Sralph /* rebuild queue (after lpc topq) */ 20513169Sralph if (stb.st_mode & 01) { 20613169Sralph for (free((char *) q); nitems--; free((char *) q)) 20713169Sralph q = *qp++; 20813169Sralph if (fchmod(lfd, stb.st_mode & 0776) < 0) 20916762Sralph syslog(LOG_WARNING, "%s: %s: %m", 21016762Sralph printer, LO); 21113169Sralph break; 21213169Sralph } 21313169Sralph } 21417463Sralph if (i == OK) /* file ok and printed */ 21514150Sralph count++; 21617463Sralph else if (i == REPRINT) { /* try reprinting the job */ 21716762Sralph syslog(LOG_INFO, "restarting %s", printer); 21812111Sralph if (ofilter > 0) { 21912111Sralph kill(ofilter, SIGCONT); /* to be sure */ 22012111Sralph (void) close(ofd); 22112111Sralph while ((i = wait(0)) > 0 && i != ofilter) 22212111Sralph ; 22312111Sralph ofilter = 0; 22412111Sralph } 22512463Sralph (void) close(pfd); /* close printer */ 22615811Sralph if (ftruncate(lfd, pidoff) < 0) 22716762Sralph syslog(LOG_WARNING, "%s: %s: %m", printer, LO); 22812463Sralph openpr(); /* try to reopen printer */ 22912111Sralph goto restart; 23012111Sralph } 23112111Sralph } 23212111Sralph free((char *) queue); 23312463Sralph /* 23412463Sralph * search the spool directory for more work. 23512463Sralph */ 23612463Sralph if ((nitems = getq(&queue)) < 0) { 23716762Sralph syslog(LOG_ERR, "%s: can't scan %s", printer, SD); 23812463Sralph exit(1); 23912463Sralph } 24012463Sralph if (nitems == 0) { /* no more work to do */ 24112463Sralph done: 24214150Sralph if (count > 0) { /* Files actually printed */ 24314150Sralph if (!SF && !tof) 24414150Sralph (void) write(ofd, FF, strlen(FF)); 24514150Sralph if (TR != NULL) /* output trailer */ 24614150Sralph (void) write(ofd, TR, strlen(TR)); 24714150Sralph } 24839954Smckusick (void) unlink(tempfile); 24912463Sralph exit(0); 25012463Sralph } 25112111Sralph goto again; 25212111Sralph } 25312111Sralph 25412111Sralph char fonts[4][50]; /* fonts for troff */ 25512111Sralph 25637968Sbostic char ifonts[4][40] = { 25737968Sbostic _PATH_VFONTR, 25837968Sbostic _PATH_VFONTI, 25937968Sbostic _PATH_VFONTB, 26037968Sbostic _PATH_VFONTS, 26112111Sralph }; 26212111Sralph 26312111Sralph /* 26412111Sralph * The remaining part is the reading of the control file (cf) 26512111Sralph * and performing the various actions. 26612111Sralph */ 26755474Sbostic static int 26812111Sralph printit(file) 26912111Sralph char *file; 27012111Sralph { 27112111Sralph register int i; 27217463Sralph char *cp; 27317463Sralph int bombed = OK; 27412111Sralph 27512111Sralph /* 27617463Sralph * open control file; ignore if no longer there. 27712111Sralph */ 27812111Sralph if ((cfp = fopen(file, "r")) == NULL) { 27916762Sralph syslog(LOG_INFO, "%s: %s: %m", printer, file); 28017463Sralph return(OK); 28112111Sralph } 28212111Sralph /* 28312111Sralph * Reset troff fonts. 28412111Sralph */ 28512111Sralph for (i = 0; i < 4; i++) 28612111Sralph strcpy(fonts[i], ifonts[i]); 28766833Sbostic sprintf(&width[2], "%d", PW); 28817302Sralph strcpy(indent+2, "0"); 28912111Sralph 29012111Sralph /* 29112111Sralph * read the control file for work to do 29212111Sralph * 29312111Sralph * file format -- first character in the line is a command 29412111Sralph * rest of the line is the argument. 29512111Sralph * valid commands are: 29612111Sralph * 29717463Sralph * S -- "stat info" for symbolic link protection 29812111Sralph * J -- "job name" on banner page 29912111Sralph * C -- "class name" on banner page 30012111Sralph * L -- "literal" user's name to print on banner 30112111Sralph * T -- "title" for pr 30212111Sralph * H -- "host name" of machine where lpr was done 30312111Sralph * P -- "person" user's login name 30412581Sralph * I -- "indent" amount to indent output 30512111Sralph * f -- "file name" name of text file to print 30612111Sralph * l -- "file name" text file with control chars 30712111Sralph * p -- "file name" text file to print with pr(1) 30812111Sralph * t -- "file name" troff(1) file to print 30913233Sralph * n -- "file name" ditroff(1) file to print 31012111Sralph * d -- "file name" dvi file to print 31112111Sralph * g -- "file name" plot(1G) file to print 31212111Sralph * v -- "file name" plain raster file to print 31312111Sralph * c -- "file name" cifplot file to print 31412111Sralph * 1 -- "R font file" for troff 31512111Sralph * 2 -- "I font file" for troff 31612111Sralph * 3 -- "B font file" for troff 31712111Sralph * 4 -- "S font file" for troff 31812111Sralph * N -- "name" of file (used by lpq) 31912111Sralph * U -- "unlink" name of file to remove 32012111Sralph * (after we print it. (Pass 2 only)). 32112111Sralph * M -- "mail" to user when done printing 32212111Sralph * 32312111Sralph * getline reads a line and expands tabs to blanks 32412111Sralph */ 32512111Sralph 32612111Sralph /* pass 1 */ 32712111Sralph 32812111Sralph while (getline(cfp)) 32912111Sralph switch (line[0]) { 33012111Sralph case 'H': 33114150Sralph strcpy(fromhost, line+1); 33212111Sralph if (class[0] == '\0') 33315552Sralph strncpy(class, line+1, sizeof(class)-1); 33412111Sralph continue; 33512111Sralph 33612111Sralph case 'P': 33715552Sralph strncpy(logname, line+1, sizeof(logname)-1); 33812463Sralph if (RS) { /* restricted */ 33955474Sbostic if (getpwnam(logname) == NULL) { 34017463Sralph bombed = NOACCT; 34115811Sralph sendmail(line+1, bombed); 34212463Sralph goto pass2; 34312463Sralph } 34412463Sralph } 34512111Sralph continue; 34612111Sralph 34717463Sralph case 'S': 34817463Sralph cp = line+1; 34917463Sralph i = 0; 35017463Sralph while (*cp >= '0' && *cp <= '9') 35117463Sralph i = i * 10 + (*cp++ - '0'); 35217463Sralph fdev = i; 35317463Sralph cp++; 35417463Sralph i = 0; 35517463Sralph while (*cp >= '0' && *cp <= '9') 35617463Sralph i = i * 10 + (*cp++ - '0'); 35717463Sralph fino = i; 35817463Sralph continue; 35917463Sralph 36012111Sralph case 'J': 36112111Sralph if (line[1] != '\0') 36215552Sralph strncpy(jobname, line+1, sizeof(jobname)-1); 36312111Sralph else 36412111Sralph strcpy(jobname, " "); 36512111Sralph continue; 36612111Sralph 36712111Sralph case 'C': 36812111Sralph if (line[1] != '\0') 36915552Sralph strncpy(class, line+1, sizeof(class)-1); 37012111Sralph else if (class[0] == '\0') 37115811Sralph gethostname(class, sizeof(class)); 37212111Sralph continue; 37312111Sralph 37412111Sralph case 'T': /* header title for pr */ 37515552Sralph strncpy(title, line+1, sizeof(title)-1); 37612111Sralph continue; 37712111Sralph 37812111Sralph case 'L': /* identification line */ 37918127Sralph if (!SH && !HL) 38012111Sralph banner(line+1, jobname); 38112111Sralph continue; 38212111Sralph 38312111Sralph case '1': /* troff fonts */ 38412111Sralph case '2': 38512111Sralph case '3': 38612111Sralph case '4': 38712111Sralph if (line[1] != '\0') 38812111Sralph strcpy(fonts[line[0]-'1'], line+1); 38912111Sralph continue; 39012111Sralph 39112111Sralph case 'W': /* page width */ 39215552Sralph strncpy(width+2, line+1, sizeof(width)-3); 39312111Sralph continue; 39412111Sralph 39512581Sralph case 'I': /* indent amount */ 39615552Sralph strncpy(indent+2, line+1, sizeof(indent)-3); 39712581Sralph continue; 39812581Sralph 39912111Sralph default: /* some file to print */ 40015811Sralph switch (i = print(line[0], line+1)) { 40117463Sralph case ERROR: 40217463Sralph if (bombed == OK) 40317463Sralph bombed = FATALERR; 40415811Sralph break; 40517463Sralph case REPRINT: 40612111Sralph (void) fclose(cfp); 40717463Sralph return(REPRINT); 40817463Sralph case FILTERERR: 40917463Sralph case ACCESS: 41017463Sralph bombed = i; 41115811Sralph sendmail(logname, bombed); 41215811Sralph } 41312111Sralph title[0] = '\0'; 41412111Sralph continue; 41512111Sralph 41612111Sralph case 'N': 41712111Sralph case 'U': 41812111Sralph case 'M': 41912111Sralph continue; 42012111Sralph } 42112111Sralph 42212111Sralph /* pass 2 */ 42312111Sralph 42412463Sralph pass2: 42512111Sralph fseek(cfp, 0L, 0); 42612111Sralph while (getline(cfp)) 42712111Sralph switch (line[0]) { 42818127Sralph case 'L': /* identification line */ 42918127Sralph if (!SH && HL) 43018127Sralph banner(line+1, jobname); 43118127Sralph continue; 43218127Sralph 43312111Sralph case 'M': 43417463Sralph if (bombed < NOACCT) /* already sent if >= NOACCT */ 43515811Sralph sendmail(line+1, bombed); 43612111Sralph continue; 43712111Sralph 43812111Sralph case 'U': 43912111Sralph (void) unlink(line+1); 44012111Sralph } 44112111Sralph /* 44215811Sralph * clean-up in case another control file exists 44312111Sralph */ 44412111Sralph (void) fclose(cfp); 44512111Sralph (void) unlink(file); 44617463Sralph return(bombed == OK ? OK : ERROR); 44712111Sralph } 44812111Sralph 44912111Sralph /* 45012111Sralph * Print a file. 45113233Sralph * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}. 45215811Sralph * Return -1 if a non-recoverable error occured, 45315811Sralph * 2 if the filter detected some errors (but printed the job anyway), 45415811Sralph * 1 if we should try to reprint this job and 45512111Sralph * 0 if all is well. 45612111Sralph * Note: all filters take stdin as the file, stdout as the printer, 45712111Sralph * stderr as the log file, and must not ignore SIGINT. 45812111Sralph */ 45955474Sbostic static int 46012111Sralph print(format, file) 46112111Sralph int format; 46212111Sralph char *file; 46312111Sralph { 46415811Sralph register int n; 46512111Sralph register char *prog; 46615811Sralph int fi, fo; 46739954Smckusick FILE *fp; 46812111Sralph char *av[15], buf[BUFSIZ]; 46912111Sralph int pid, p[2], stopped = 0; 47012111Sralph union wait status; 47117463Sralph struct stat stb; 47212111Sralph 47317463Sralph if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0) 47417463Sralph return(ERROR); 47517463Sralph /* 47617463Sralph * Check to see if data file is a symbolic link. If so, it should 47717463Sralph * still point to the same file or someone is trying to print 47817463Sralph * something he shouldn't. 47917463Sralph */ 48017463Sralph if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 && 48117463Sralph (stb.st_dev != fdev || stb.st_ino != fino)) 48217463Sralph return(ACCESS); 48312111Sralph if (!SF && !tof) { /* start on a fresh page */ 48412111Sralph (void) write(ofd, FF, strlen(FF)); 48512111Sralph tof = 1; 48612111Sralph } 48712111Sralph if (IF == NULL && (format == 'f' || format == 'l')) { 48812111Sralph tof = 0; 48912111Sralph while ((n = read(fi, buf, BUFSIZ)) > 0) 49012111Sralph if (write(ofd, buf, n) != n) { 49112111Sralph (void) close(fi); 49217463Sralph return(REPRINT); 49312111Sralph } 49412111Sralph (void) close(fi); 49517463Sralph return(OK); 49612111Sralph } 49712111Sralph switch (format) { 49812111Sralph case 'p': /* print file using 'pr' */ 49912111Sralph if (IF == NULL) { /* use output filter */ 50037968Sbostic prog = _PATH_PR; 50112111Sralph av[0] = "pr"; 50212111Sralph av[1] = width; 50312111Sralph av[2] = length; 50412111Sralph av[3] = "-h"; 50512111Sralph av[4] = *title ? title : " "; 50612111Sralph av[5] = 0; 50712111Sralph fo = ofd; 50812111Sralph goto start; 50912111Sralph } 51012111Sralph pipe(p); 51112111Sralph if ((prchild = dofork(DORETURN)) == 0) { /* child */ 51212111Sralph dup2(fi, 0); /* file is stdin */ 51312111Sralph dup2(p[1], 1); /* pipe is stdout */ 514*68972Stef closelog(); 51512111Sralph for (n = 3; n < NOFILE; n++) 51612111Sralph (void) close(n); 51737968Sbostic execl(_PATH_PR, "pr", width, length, 51837968Sbostic "-h", *title ? title : " ", 0); 51937968Sbostic syslog(LOG_ERR, "cannot execl %s", _PATH_PR); 52012111Sralph exit(2); 52112111Sralph } 52212111Sralph (void) close(p[1]); /* close output side */ 52312111Sralph (void) close(fi); 52412111Sralph if (prchild < 0) { 52512111Sralph prchild = 0; 52612111Sralph (void) close(p[0]); 52717463Sralph return(ERROR); 52812111Sralph } 52912111Sralph fi = p[0]; /* use pipe for input */ 53012111Sralph case 'f': /* print plain text file */ 53112111Sralph prog = IF; 53212111Sralph av[1] = width; 53312111Sralph av[2] = length; 53412581Sralph av[3] = indent; 53512581Sralph n = 4; 53612111Sralph break; 53712111Sralph case 'l': /* like 'f' but pass control characters */ 53812111Sralph prog = IF; 53914325Sralph av[1] = "-c"; 54012111Sralph av[2] = width; 54112111Sralph av[3] = length; 54212581Sralph av[4] = indent; 54312581Sralph n = 5; 54412111Sralph break; 54512463Sralph case 'r': /* print a fortran text file */ 54612463Sralph prog = RF; 54712463Sralph av[1] = width; 54812463Sralph av[2] = length; 54912463Sralph n = 3; 55012463Sralph break; 55112111Sralph case 't': /* print troff output */ 55213233Sralph case 'n': /* print ditroff output */ 55312463Sralph case 'd': /* print tex output */ 55412111Sralph (void) unlink(".railmag"); 55512463Sralph if ((fo = creat(".railmag", FILMOD)) < 0) { 55616762Sralph syslog(LOG_ERR, "%s: cannot create .railmag", printer); 55712111Sralph (void) unlink(".railmag"); 55812111Sralph } else { 55912111Sralph for (n = 0; n < 4; n++) { 56012111Sralph if (fonts[n][0] != '/') 56154520Sbostic (void) write(fo, _PATH_VFONT, 56254520Sbostic sizeof(_PATH_VFONT) - 1); 56312111Sralph (void) write(fo, fonts[n], strlen(fonts[n])); 56412111Sralph (void) write(fo, "\n", 1); 56512111Sralph } 56612111Sralph (void) close(fo); 56712111Sralph } 56813233Sralph prog = (format == 't') ? TF : (format == 'n') ? NF : DF; 56912463Sralph av[1] = pxwidth; 57012463Sralph av[2] = pxlength; 57112463Sralph n = 3; 57212111Sralph break; 57312111Sralph case 'c': /* print cifplot output */ 57412111Sralph prog = CF; 57512463Sralph av[1] = pxwidth; 57612463Sralph av[2] = pxlength; 57712463Sralph n = 3; 57812111Sralph break; 57912111Sralph case 'g': /* print plot(1G) output */ 58012111Sralph prog = GF; 58112463Sralph av[1] = pxwidth; 58212463Sralph av[2] = pxlength; 58312463Sralph n = 3; 58412111Sralph break; 58512111Sralph case 'v': /* print raster output */ 58612111Sralph prog = VF; 58712463Sralph av[1] = pxwidth; 58812463Sralph av[2] = pxlength; 58912463Sralph n = 3; 59012111Sralph break; 59112111Sralph default: 59212111Sralph (void) close(fi); 59316762Sralph syslog(LOG_ERR, "%s: illegal format character '%c'", 59416762Sralph printer, format); 59517463Sralph return(ERROR); 59612111Sralph } 59712111Sralph if ((av[0] = rindex(prog, '/')) != NULL) 59812111Sralph av[0]++; 59912111Sralph else 60012111Sralph av[0] = prog; 60112111Sralph av[n++] = "-n"; 60212111Sralph av[n++] = logname; 60312111Sralph av[n++] = "-h"; 60414150Sralph av[n++] = fromhost; 60512111Sralph av[n++] = AF; 60612111Sralph av[n] = 0; 60712111Sralph fo = pfd; 60812111Sralph if (ofilter > 0) { /* stop output filter */ 60912111Sralph write(ofd, "\031\1", 2); 61046912Sbostic while ((pid = 61146912Sbostic wait3((int *)&status, WUNTRACED, 0)) > 0 && pid != ofilter) 61212111Sralph ; 61312111Sralph if (status.w_stopval != WSTOPPED) { 61412111Sralph (void) close(fi); 61516762Sralph syslog(LOG_WARNING, "%s: output filter died (%d)", 61616762Sralph printer, status.w_retcode); 61717463Sralph return(REPRINT); 61812111Sralph } 61912111Sralph stopped++; 62012111Sralph } 62112111Sralph start: 62212111Sralph if ((child = dofork(DORETURN)) == 0) { /* child */ 62312111Sralph dup2(fi, 0); 62412111Sralph dup2(fo, 1); 62539954Smckusick n = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, 0664); 62615811Sralph if (n >= 0) 62715811Sralph dup2(n, 2); 628*68972Stef closelog(); 62912111Sralph for (n = 3; n < NOFILE; n++) 63012111Sralph (void) close(n); 63112111Sralph execv(prog, av); 63216762Sralph syslog(LOG_ERR, "cannot execv %s", prog); 63312111Sralph exit(2); 63412111Sralph } 63512111Sralph (void) close(fi); 63612111Sralph if (child < 0) 63712111Sralph status.w_retcode = 100; 63812111Sralph else 63946912Sbostic while ((pid = wait((int *)&status)) > 0 && pid != child) 64012111Sralph ; 64112111Sralph child = 0; 64212111Sralph prchild = 0; 64312111Sralph if (stopped) { /* restart output filter */ 64412111Sralph if (kill(ofilter, SIGCONT) < 0) { 64516762Sralph syslog(LOG_ERR, "cannot restart output filter"); 64612111Sralph exit(1); 64712111Sralph } 64812111Sralph } 64912111Sralph tof = 0; 65039954Smckusick 65139954Smckusick /* Copy filter output to "lf" logfile */ 65239954Smckusick if (fp = fopen(tempfile, "r")) { 65339954Smckusick while (fgets(buf, sizeof(buf), fp)) 65439954Smckusick fputs(buf, stderr); 65556123Selan fclose(fp); 65639954Smckusick } 65739954Smckusick 65815811Sralph if (!WIFEXITED(status)) { 65916762Sralph syslog(LOG_WARNING, "%s: Daemon filter '%c' terminated (%d)", 66016762Sralph printer, format, status.w_termsig); 66117463Sralph return(ERROR); 66217463Sralph } 66317463Sralph switch (status.w_retcode) { 66417463Sralph case 0: 66517463Sralph tof = 1; 66617463Sralph return(OK); 66717463Sralph case 1: 66817463Sralph return(REPRINT); 66917463Sralph default: 67016762Sralph syslog(LOG_WARNING, "%s: Daemon filter '%c' exited (%d)", 67116762Sralph printer, format, status.w_retcode); 67217463Sralph case 2: 67317463Sralph return(ERROR); 67417463Sralph } 67512111Sralph } 67612111Sralph 67712111Sralph /* 67812111Sralph * Send the daemon control file (cf) and any data files. 67912111Sralph * Return -1 if a non-recoverable error occured, 1 if a recoverable error and 68012111Sralph * 0 if all is well. 68112111Sralph */ 68255474Sbostic static int 68312111Sralph sendit(file) 68412111Sralph char *file; 68512111Sralph { 68617463Sralph register int i, err = OK; 68717463Sralph char *cp, last[BUFSIZ]; 68812111Sralph 68912111Sralph /* 69012111Sralph * open control file 69112111Sralph */ 69216762Sralph if ((cfp = fopen(file, "r")) == NULL) 69317463Sralph return(OK); 69412111Sralph /* 69512111Sralph * read the control file for work to do 69612111Sralph * 69712111Sralph * file format -- first character in the line is a command 69812111Sralph * rest of the line is the argument. 69912111Sralph * commands of interest are: 70012111Sralph * 70112111Sralph * a-z -- "file name" name of file to print 70212111Sralph * U -- "unlink" name of file to remove 70312111Sralph * (after we print it. (Pass 2 only)). 70412111Sralph */ 70512111Sralph 70612111Sralph /* 70712111Sralph * pass 1 70812111Sralph */ 70912111Sralph while (getline(cfp)) { 71012111Sralph again: 71117463Sralph if (line[0] == 'S') { 71217463Sralph cp = line+1; 71317463Sralph i = 0; 71417463Sralph while (*cp >= '0' && *cp <= '9') 71517463Sralph i = i * 10 + (*cp++ - '0'); 71617463Sralph fdev = i; 71717463Sralph cp++; 71817463Sralph i = 0; 71917463Sralph while (*cp >= '0' && *cp <= '9') 72017463Sralph i = i * 10 + (*cp++ - '0'); 72117463Sralph fino = i; 72217463Sralph continue; 72317463Sralph } 72412111Sralph if (line[0] >= 'a' && line[0] <= 'z') { 72512111Sralph strcpy(last, line); 72617463Sralph while (i = getline(cfp)) 72712111Sralph if (strcmp(last, line)) 72812111Sralph break; 72917463Sralph switch (sendfile('\3', last+1)) { 73017463Sralph case OK: 73117463Sralph if (i) 73217463Sralph goto again; 73317463Sralph break; 73417463Sralph case REPRINT: 73512111Sralph (void) fclose(cfp); 73617463Sralph return(REPRINT); 73717463Sralph case ACCESS: 73817463Sralph sendmail(logname, ACCESS); 73917463Sralph case ERROR: 74017463Sralph err = ERROR; 74117463Sralph } 74212111Sralph break; 74312111Sralph } 74412111Sralph } 74517463Sralph if (err == OK && sendfile('\2', file) > 0) { 74612111Sralph (void) fclose(cfp); 74717463Sralph return(REPRINT); 74812111Sralph } 74912111Sralph /* 75012111Sralph * pass 2 75112111Sralph */ 75212111Sralph fseek(cfp, 0L, 0); 75312111Sralph while (getline(cfp)) 75412111Sralph if (line[0] == 'U') 75512111Sralph (void) unlink(line+1); 75612111Sralph /* 75717463Sralph * clean-up in case another control file exists 75812111Sralph */ 75912111Sralph (void) fclose(cfp); 76012111Sralph (void) unlink(file); 76117463Sralph return(err); 76212111Sralph } 76312111Sralph 76412111Sralph /* 76512111Sralph * Send a data file to the remote machine and spool it. 76612111Sralph * Return positive if we should try resending. 76712111Sralph */ 76855474Sbostic static int 76912111Sralph sendfile(type, file) 77055474Sbostic int type; 77155474Sbostic char *file; 77212111Sralph { 77312111Sralph register int f, i, amt; 77412111Sralph struct stat stb; 77512111Sralph char buf[BUFSIZ]; 77616762Sralph int sizerr, resp; 77712111Sralph 77817463Sralph if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0) 77917463Sralph return(ERROR); 78017463Sralph /* 78117463Sralph * Check to see if data file is a symbolic link. If so, it should 78217463Sralph * still point to the same file or someone is trying to print something 78317463Sralph * he shouldn't. 78417463Sralph */ 78517463Sralph if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 && 78617463Sralph (stb.st_dev != fdev || stb.st_ino != fino)) 78717463Sralph return(ACCESS); 788*68972Stef (void) sprintf(buf, "%c%ld %s\n", type, (long)stb.st_size, file); 78912111Sralph amt = strlen(buf); 79016762Sralph for (i = 0; ; i++) { 79116762Sralph if (write(pfd, buf, amt) != amt || 79216762Sralph (resp = response()) < 0 || resp == '\1') { 79316762Sralph (void) close(f); 79417463Sralph return(REPRINT); 79516762Sralph } else if (resp == '\0') 79616762Sralph break; 79716762Sralph if (i == 0) 79855474Sbostic pstatus("no space on remote; waiting for queue to drain"); 79916762Sralph if (i == 10) 80024861Seric syslog(LOG_ALERT, "%s: can't send to %s; queue full", 80116762Sralph printer, RM); 80216762Sralph sleep(5 * 60); 80312692Sralph } 80416762Sralph if (i) 80555474Sbostic pstatus("sending to %s", RM); 80612111Sralph sizerr = 0; 80712111Sralph for (i = 0; i < stb.st_size; i += BUFSIZ) { 80812111Sralph amt = BUFSIZ; 80912111Sralph if (i + amt > stb.st_size) 81012111Sralph amt = stb.st_size - i; 81112111Sralph if (sizerr == 0 && read(f, buf, amt) != amt) 81212111Sralph sizerr = 1; 81312692Sralph if (write(pfd, buf, amt) != amt) { 81412692Sralph (void) close(f); 81517463Sralph return(REPRINT); 81612692Sralph } 81712111Sralph } 81855474Sbostic 81955474Sbostic 82055474Sbostic 82155474Sbostic 82212111Sralph (void) close(f); 82312111Sralph if (sizerr) { 82416762Sralph syslog(LOG_INFO, "%s: %s: changed size", printer, file); 82517463Sralph /* tell recvjob to ignore this file */ 82617463Sralph (void) write(pfd, "\1", 1); 82717463Sralph return(ERROR); 82817463Sralph } 82917463Sralph if (write(pfd, "", 1) != 1 || response()) 83017463Sralph return(REPRINT); 83117463Sralph return(OK); 83212111Sralph } 83312111Sralph 83412111Sralph /* 83512111Sralph * Check to make sure there have been no errors and that both programs 83612111Sralph * are in sync with eachother. 83712111Sralph * Return non-zero if the connection was lost. 83812111Sralph */ 83955474Sbostic static char 84016762Sralph response() 84112111Sralph { 84212111Sralph char resp; 84312111Sralph 84416762Sralph if (read(pfd, &resp, 1) != 1) { 84516762Sralph syslog(LOG_INFO, "%s: lost connection", printer); 84616762Sralph return(-1); 84712111Sralph } 84816762Sralph return(resp); 84912111Sralph } 85012111Sralph 85112111Sralph /* 85212111Sralph * Banner printing stuff 85312111Sralph */ 85455474Sbostic static void 85512111Sralph banner(name1, name2) 85612111Sralph char *name1, *name2; 85712111Sralph { 85812111Sralph time_t tvec; 85912111Sralph extern char *ctime(); 86012111Sralph 86112111Sralph time(&tvec); 86212111Sralph if (!SF && !tof) 86312111Sralph (void) write(ofd, FF, strlen(FF)); 86412111Sralph if (SB) { /* short banner only */ 86512111Sralph if (class[0]) { 86612111Sralph (void) write(ofd, class, strlen(class)); 86712111Sralph (void) write(ofd, ":", 1); 86812111Sralph } 86912111Sralph (void) write(ofd, name1, strlen(name1)); 87012111Sralph (void) write(ofd, " Job: ", 7); 87112111Sralph (void) write(ofd, name2, strlen(name2)); 87212111Sralph (void) write(ofd, " Date: ", 8); 87312111Sralph (void) write(ofd, ctime(&tvec), 24); 87412111Sralph (void) write(ofd, "\n", 1); 87512111Sralph } else { /* normal banner */ 87612111Sralph (void) write(ofd, "\n\n\n", 3); 87712111Sralph scan_out(ofd, name1, '\0'); 87812111Sralph (void) write(ofd, "\n\n", 2); 87912111Sralph scan_out(ofd, name2, '\0'); 88012111Sralph if (class[0]) { 88112111Sralph (void) write(ofd,"\n\n\n",3); 88212111Sralph scan_out(ofd, class, '\0'); 88312111Sralph } 88412111Sralph (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15); 88512111Sralph (void) write(ofd, name2, strlen(name2)); 88612111Sralph (void) write(ofd, "\n\t\t\t\t\tDate: ", 12); 88712111Sralph (void) write(ofd, ctime(&tvec), 24); 88812111Sralph (void) write(ofd, "\n", 1); 88912111Sralph } 89012111Sralph if (!SF) 89112111Sralph (void) write(ofd, FF, strlen(FF)); 89212111Sralph tof = 1; 89312111Sralph } 89412111Sralph 89555474Sbostic static char * 89612111Sralph scnline(key, p, c) 89755474Sbostic register int key; 89855474Sbostic register char *p; 89955474Sbostic int c; 90012111Sralph { 90112111Sralph register scnwidth; 90212111Sralph 90312111Sralph for (scnwidth = WIDTH; --scnwidth;) { 90412111Sralph key <<= 1; 90512111Sralph *p++ = key & 0200 ? c : BACKGND; 90612111Sralph } 90712111Sralph return (p); 90812111Sralph } 90912111Sralph 91012111Sralph #define TRC(q) (((q)-' ')&0177) 91112111Sralph 91255474Sbostic static void 91312111Sralph scan_out(scfd, scsp, dlm) 91455474Sbostic int scfd, dlm; 91555474Sbostic char *scsp; 91612111Sralph { 91712111Sralph register char *strp; 91812111Sralph register nchrs, j; 91912111Sralph char outbuf[LINELEN+1], *sp, c, cc; 92012111Sralph int d, scnhgt; 92112111Sralph extern char scnkey[][HEIGHT]; /* in lpdchar.c */ 92212111Sralph 92312111Sralph for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) { 92412111Sralph strp = &outbuf[0]; 92512111Sralph sp = scsp; 92612111Sralph for (nchrs = 0; ; ) { 92712111Sralph d = dropit(c = TRC(cc = *sp++)); 92812111Sralph if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d)) 92912111Sralph for (j = WIDTH; --j;) 93012111Sralph *strp++ = BACKGND; 93112111Sralph else 93212111Sralph strp = scnline(scnkey[c][scnhgt-1-d], strp, cc); 93312111Sralph if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1) 93412111Sralph break; 93512111Sralph *strp++ = BACKGND; 93612111Sralph *strp++ = BACKGND; 93712111Sralph } 93812111Sralph while (*--strp == BACKGND && strp >= outbuf) 93912111Sralph ; 94012111Sralph strp++; 94112111Sralph *strp++ = '\n'; 94212111Sralph (void) write(scfd, outbuf, strp-outbuf); 94312111Sralph } 94412111Sralph } 94512111Sralph 94655474Sbostic static int 94712111Sralph dropit(c) 94855474Sbostic int c; 94912111Sralph { 95012111Sralph switch(c) { 95112111Sralph 95212111Sralph case TRC('_'): 95312111Sralph case TRC(';'): 95412111Sralph case TRC(','): 95512111Sralph case TRC('g'): 95612111Sralph case TRC('j'): 95712111Sralph case TRC('p'): 95812111Sralph case TRC('q'): 95912111Sralph case TRC('y'): 96012111Sralph return (DROP); 96112111Sralph 96212111Sralph default: 96312111Sralph return (0); 96412111Sralph } 96512111Sralph } 96612111Sralph 96712111Sralph /* 96812111Sralph * sendmail --- 96912111Sralph * tell people about job completion 97012111Sralph */ 97155474Sbostic static void 97215811Sralph sendmail(user, bombed) 97315811Sralph char *user; 97412111Sralph int bombed; 97512111Sralph { 97612111Sralph register int i; 97715811Sralph int p[2], s; 97812111Sralph register char *cp; 97912111Sralph char buf[100]; 98015811Sralph struct stat stb; 98115811Sralph FILE *fp; 98212111Sralph 98312111Sralph pipe(p); 98415811Sralph if ((s = dofork(DORETURN)) == 0) { /* child */ 98512111Sralph dup2(p[0], 0); 986*68972Stef closelog(); 98712111Sralph for (i = 3; i < NOFILE; i++) 98812111Sralph (void) close(i); 98937968Sbostic if ((cp = rindex(_PATH_SENDMAIL, '/')) != NULL) 99012111Sralph cp++; 99155474Sbostic else 99237968Sbostic cp = _PATH_SENDMAIL; 99315811Sralph sprintf(buf, "%s@%s", user, fromhost); 99437968Sbostic execl(_PATH_SENDMAIL, cp, buf, 0); 99512111Sralph exit(0); 99615811Sralph } else if (s > 0) { /* parent */ 99712111Sralph dup2(p[1], 1); 99815811Sralph printf("To: %s@%s\n", user, fromhost); 99912111Sralph printf("Subject: printer job\n\n"); 100012111Sralph printf("Your printer job "); 100112111Sralph if (*jobname) 100212111Sralph printf("(%s) ", jobname); 100312463Sralph switch (bombed) { 100417463Sralph case OK: 100512463Sralph printf("\ncompleted successfully\n"); 100612463Sralph break; 100712463Sralph default: 100817463Sralph case FATALERR: 100912463Sralph printf("\ncould not be printed\n"); 101012463Sralph break; 101117463Sralph case NOACCT: 101212463Sralph printf("\ncould not be printed without an account on %s\n", host); 101312463Sralph break; 101417463Sralph case FILTERERR: 101539954Smckusick if (stat(tempfile, &stb) < 0 || stb.st_size == 0 || 101639954Smckusick (fp = fopen(tempfile, "r")) == NULL) { 101715811Sralph printf("\nwas printed but had some errors\n"); 101815811Sralph break; 101915811Sralph } 102015811Sralph printf("\nwas printed but had the following errors:\n"); 102115811Sralph while ((i = getc(fp)) != EOF) 102215811Sralph putchar(i); 102315811Sralph (void) fclose(fp); 102417463Sralph break; 102517463Sralph case ACCESS: 102617463Sralph printf("\nwas not printed because it was not linked to the original file\n"); 102712463Sralph } 102812111Sralph fflush(stdout); 102912111Sralph (void) close(1); 103012111Sralph } 103112111Sralph (void) close(p[0]); 103212111Sralph (void) close(p[1]); 103315811Sralph wait(&s); 103412111Sralph } 103512111Sralph 103612111Sralph /* 103712111Sralph * dofork - fork with retries on failure 103812111Sralph */ 103955474Sbostic static int 104012111Sralph dofork(action) 104112111Sralph int action; 104212111Sralph { 104312111Sralph register int i, pid; 104412111Sralph 104512111Sralph for (i = 0; i < 20; i++) { 104612463Sralph if ((pid = fork()) < 0) { 104712111Sralph sleep((unsigned)(i*i)); 104812463Sralph continue; 104912463Sralph } 105012463Sralph /* 105112463Sralph * Child should run as daemon instead of root 105212463Sralph */ 105312463Sralph if (pid == 0) 105412463Sralph setuid(DU); 105512463Sralph return(pid); 105612111Sralph } 105716762Sralph syslog(LOG_ERR, "can't fork"); 105812111Sralph 105912111Sralph switch (action) { 106012111Sralph case DORETURN: 106112111Sralph return (-1); 106212111Sralph default: 106316762Sralph syslog(LOG_ERR, "bad action (%d) to dofork", action); 106412111Sralph /*FALL THRU*/ 106512111Sralph case DOABORT: 106612111Sralph exit(1); 106712111Sralph } 106812111Sralph /*NOTREACHED*/ 106912111Sralph } 107012111Sralph 107112111Sralph /* 107216762Sralph * Kill child processes to abort current job. 107312111Sralph */ 107455474Sbostic static void 107555474Sbostic abortpr(signo) 107655474Sbostic int signo; 107712111Sralph { 107839954Smckusick (void) unlink(tempfile); 107912111Sralph kill(0, SIGINT); 108012111Sralph if (ofilter > 0) 108112111Sralph kill(ofilter, SIGCONT); 108246912Sbostic while (wait(NULL) > 0) 108312111Sralph ; 108412111Sralph exit(0); 108512111Sralph } 108612111Sralph 108755474Sbostic static void 108812111Sralph init() 108912111Sralph { 109012111Sralph int status; 109138736Stef char *s; 109212111Sralph 109356123Selan if ((status = cgetent(&bp, printcapdb, printer)) == -2) { 109425468Stef syslog(LOG_ERR, "can't open printer description file"); 109525468Stef exit(1); 109656123Selan } else if (status == -1) { 109725468Stef syslog(LOG_ERR, "unknown printer: %s", printer); 109825468Stef exit(1); 109956123Selan } else if (status == -3) 110056123Selan fatal("potential reference loop detected in printcap file"); 110156123Selan 110256123Selan if (cgetstr(bp, "lp", &LP) == -1) 110337968Sbostic LP = _PATH_DEFDEVLP; 110456123Selan if (cgetstr(bp, "rp", &RP) == -1) 110512463Sralph RP = DEFLP; 110656123Selan if (cgetstr(bp, "lo", &LO) == -1) 110712111Sralph LO = DEFLOCK; 110856123Selan if (cgetstr(bp, "st", &ST) == -1) 110912111Sralph ST = DEFSTAT; 111056123Selan if (cgetstr(bp, "lf", &LF) == -1) 111137968Sbostic LF = _PATH_CONSOLE; 111256123Selan if (cgetstr(bp, "sd", &SD) == -1) 111337968Sbostic SD = _PATH_DEFSPOOL; 111456123Selan if (cgetnum(bp, "du", &DU) < 0) 111512111Sralph DU = DEFUID; 111656123Selan if (cgetstr(bp,"ff", &FF) == -1) 111712111Sralph FF = DEFFF; 111856123Selan if (cgetnum(bp, "pw", &PW) < 0) 111912111Sralph PW = DEFWIDTH; 112012111Sralph sprintf(&width[2], "%d", PW); 112156123Selan if (cgetnum(bp, "pl", &PL) < 0) 112212111Sralph PL = DEFLENGTH; 112312111Sralph sprintf(&length[2], "%d", PL); 112456123Selan if (cgetnum(bp,"px", &PX) < 0) 112512463Sralph PX = 0; 112612463Sralph sprintf(&pxwidth[2], "%d", PX); 112756123Selan if (cgetnum(bp, "py", &PY) < 0) 112812463Sralph PY = 0; 112912463Sralph sprintf(&pxlength[2], "%d", PY); 113056123Selan cgetstr(bp, "rm", &RM); 113138736Stef if (s = checkremote()) 113238736Stef syslog(LOG_WARNING, s); 113325468Stef 113456123Selan cgetstr(bp, "af", &AF); 113556123Selan cgetstr(bp, "of", &OF); 113656123Selan cgetstr(bp, "if", &IF); 113756123Selan cgetstr(bp, "rf", &RF); 113856123Selan cgetstr(bp, "tf", &TF); 113956123Selan cgetstr(bp, "nf", &NF); 114056123Selan cgetstr(bp, "df", &DF); 114156123Selan cgetstr(bp, "gf", &GF); 114256123Selan cgetstr(bp, "vf", &VF); 114356123Selan cgetstr(bp, "cf", &CF); 114456123Selan cgetstr(bp, "tr", &TR); 114556123Selan 114656123Selan RS = (cgetcap(bp, "rs", ':') != NULL); 114756123Selan SF = (cgetcap(bp, "sf", ':') != NULL); 114856123Selan SH = (cgetcap(bp, "sh", ':') != NULL); 114956123Selan SB = (cgetcap(bp, "sb", ':') != NULL); 115056123Selan HL = (cgetcap(bp, "hl", ':') != NULL); 115156123Selan RW = (cgetcap(bp, "rw", ':') != NULL); 115256123Selan 115356123Selan cgetnum(bp, "br", &BR); 115456123Selan if (cgetnum(bp, "fc", &FC) < 0) 115512111Sralph FC = 0; 115656123Selan if (cgetnum(bp, "fs", &FS) < 0) 115712111Sralph FS = 0; 115856123Selan if (cgetnum(bp, "xc", &XC) < 0) 115912111Sralph XC = 0; 116056123Selan if (cgetnum(bp, "xs", &XS) < 0) 116112111Sralph XS = 0; 116256123Selan 116356123Selan tof = (cgetcap(bp, "fo", ':') == NULL); 116412111Sralph } 116512111Sralph 116612463Sralph /* 116712463Sralph * Acquire line printer or remote connection. 116812463Sralph */ 116955474Sbostic static void 117012463Sralph openpr() 117112463Sralph { 117212463Sralph register int i, n; 117316762Sralph int resp; 117412463Sralph 117538736Stef if (!sendtorem && *LP) { 117612463Sralph for (i = 1; ; i = i < 32 ? i << 1 : i) { 117713148Ssam pfd = open(LP, RW ? O_RDWR : O_WRONLY); 117812463Sralph if (pfd >= 0) 117912463Sralph break; 118012463Sralph if (errno == ENOENT) { 118116762Sralph syslog(LOG_ERR, "%s: %m", LP); 118212463Sralph exit(1); 118312463Sralph } 118412463Sralph if (i == 1) 118555474Sbostic pstatus("waiting for %s to become ready (offline ?)", printer); 118612463Sralph sleep(i); 118712463Sralph } 118812463Sralph if (isatty(pfd)) 118912463Sralph setty(); 119055474Sbostic pstatus("%s is ready and printing", printer); 119112463Sralph } else if (RM != NULL) { 119216762Sralph for (i = 1; ; i = i < 256 ? i << 1 : i) { 119316762Sralph resp = -1; 119412528Sralph pfd = getport(RM); 119512463Sralph if (pfd >= 0) { 119612463Sralph (void) sprintf(line, "\2%s\n", RP); 119712463Sralph n = strlen(line); 119816762Sralph if (write(pfd, line, n) == n && 119916762Sralph (resp = response()) == '\0') 120012463Sralph break; 120116031Sralph (void) close(pfd); 120212463Sralph } 120316031Sralph if (i == 1) { 120416762Sralph if (resp < 0) 120555474Sbostic pstatus("waiting for %s to come up", RM); 120616762Sralph else { 120755474Sbostic pstatus("waiting for queue to be enabled on %s", RM); 120816762Sralph i = 256; 120916762Sralph } 121016031Sralph } 121112463Sralph sleep(i); 121212463Sralph } 121355474Sbostic pstatus("sending to %s", RM); 121412463Sralph remote = 1; 121512463Sralph } else { 121616762Sralph syslog(LOG_ERR, "%s: no line printer device or host name", 121716762Sralph printer); 121812463Sralph exit(1); 121912463Sralph } 122012463Sralph /* 122112463Sralph * Start up an output filter, if needed. 122212463Sralph */ 122340049Stef if (!remote && OF) { 122412463Sralph int p[2]; 122512463Sralph char *cp; 122612463Sralph 122712463Sralph pipe(p); 122812463Sralph if ((ofilter = dofork(DOABORT)) == 0) { /* child */ 122912463Sralph dup2(p[0], 0); /* pipe is std in */ 123012463Sralph dup2(pfd, 1); /* printer is std out */ 1231*68972Stef closelog(); 123212463Sralph for (i = 3; i < NOFILE; i++) 123312463Sralph (void) close(i); 123412463Sralph if ((cp = rindex(OF, '/')) == NULL) 123512463Sralph cp = OF; 123612463Sralph else 123712463Sralph cp++; 123812463Sralph execl(OF, cp, width, length, 0); 123916762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, OF); 124012463Sralph exit(1); 124112463Sralph } 124212463Sralph (void) close(p[0]); /* close input side */ 124312463Sralph ofd = p[1]; /* use pipe for output */ 124412463Sralph } else { 124512463Sralph ofd = pfd; 124612463Sralph ofilter = 0; 124712463Sralph } 124812463Sralph } 124912463Sralph 125012111Sralph struct bauds { 125112111Sralph int baud; 125212111Sralph int speed; 125312111Sralph } bauds[] = { 125412111Sralph 50, B50, 125512111Sralph 75, B75, 125612111Sralph 110, B110, 125712111Sralph 134, B134, 125812111Sralph 150, B150, 125912111Sralph 200, B200, 126012111Sralph 300, B300, 126112111Sralph 600, B600, 126212111Sralph 1200, B1200, 126312111Sralph 1800, B1800, 126412111Sralph 2400, B2400, 126512111Sralph 4800, B4800, 126612111Sralph 9600, B9600, 126712111Sralph 19200, EXTA, 126812111Sralph 38400, EXTB, 126912111Sralph 0, 0 127012111Sralph }; 127112111Sralph 127212111Sralph /* 127312111Sralph * setup tty lines. 127412111Sralph */ 127555474Sbostic static void 127612111Sralph setty() 127712111Sralph { 127812111Sralph struct sgttyb ttybuf; 127912111Sralph register struct bauds *bp; 128012111Sralph 128112111Sralph if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) { 128216762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer); 128312111Sralph exit(1); 128412111Sralph } 128512111Sralph if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) { 128616762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCGETP): %m", printer); 128712111Sralph exit(1); 128812111Sralph } 128912111Sralph if (BR > 0) { 129012111Sralph for (bp = bauds; bp->baud; bp++) 129112111Sralph if (BR == bp->baud) 129212111Sralph break; 129312111Sralph if (!bp->baud) { 129416762Sralph syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR); 129512111Sralph exit(1); 129612111Sralph } 129712111Sralph ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed; 129812111Sralph } 129913169Sralph ttybuf.sg_flags &= ~FC; 130013169Sralph ttybuf.sg_flags |= FS; 130112111Sralph if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) { 130216762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCSETP): %m", printer); 130312111Sralph exit(1); 130412111Sralph } 130512111Sralph if (XC) { 130612111Sralph if (ioctl(pfd, TIOCLBIC, &XC) < 0) { 130716762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCLBIC): %m", printer); 130812111Sralph exit(1); 130912111Sralph } 131012111Sralph } 131112111Sralph if (XS) { 131212111Sralph if (ioctl(pfd, TIOCLBIS, &XS) < 0) { 131316762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCLBIS): %m", printer); 131412111Sralph exit(1); 131512111Sralph } 131612111Sralph } 131712111Sralph } 131812463Sralph 131955474Sbostic #if __STDC__ 132055474Sbostic #include <stdarg.h> 132155474Sbostic #else 132255474Sbostic #include <varargs.h> 132355474Sbostic #endif 132455474Sbostic 132555474Sbostic void 132655474Sbostic #if __STDC__ 132755474Sbostic pstatus(const char *msg, ...) 132855474Sbostic #else 132955474Sbostic pstatus(msg, va_alist) 133012463Sralph char *msg; 133155474Sbostic va_dcl 133255474Sbostic #endif 133312463Sralph { 133412463Sralph register int fd; 133512463Sralph char buf[BUFSIZ]; 133655474Sbostic va_list ap; 133755474Sbostic #if __STDC__ 133855474Sbostic va_start(ap, msg); 133955474Sbostic #else 134055474Sbostic va_start(ap); 134155474Sbostic #endif 134212463Sralph 134312463Sralph umask(0); 134413148Ssam fd = open(ST, O_WRONLY|O_CREAT, 0664); 134516762Sralph if (fd < 0 || flock(fd, LOCK_EX) < 0) { 134616762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, ST); 134716762Sralph exit(1); 134816762Sralph } 134913148Ssam ftruncate(fd, 0); 135055474Sbostic (void)vsnprintf(buf, sizeof(buf), msg, ap); 135155474Sbostic va_end(ap); 135212463Sralph strcat(buf, "\n"); 135312463Sralph (void) write(fd, buf, strlen(buf)); 135412463Sralph (void) close(fd); 135512463Sralph } 1356