122437Sdist /* 2*56251Selan * Copyright (c) 1983 The Regents of the University of California. 334203Sbostic * All rights reserved. 434203Sbostic * 556123Selan * 6*56251Selan * %sccs.include.redist.c% 722437Sdist */ 822437Sdist 913954Ssam #ifndef lint 10*56251Selan char copyright[] = 11*56251Selan "@(#) Copyright (c) 1983 The Regents of the University of California.\n\ 12*56251Selan All rights reserved.\n"; 1334203Sbostic #endif /* not lint */ 1413954Ssam 15*56251Selan #ifndef lint 16*56251Selan static char sccsid[] = "@(#)printjob.c 5.17 (Berkeley) 09/15/92"; 17*56251Selan #endif /* not lint */ 18*56251Selan 19*56251Selan 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; 11212111Sralph long 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: 18755474Sbostic (void) lseek(lfd, (off_t)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]); 28717339Sralph strcpy(width+2, "0"); 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 */ 51412111Sralph for (n = 3; n < NOFILE; n++) 51512111Sralph (void) close(n); 51637968Sbostic execl(_PATH_PR, "pr", width, length, 51737968Sbostic "-h", *title ? title : " ", 0); 51837968Sbostic syslog(LOG_ERR, "cannot execl %s", _PATH_PR); 51912111Sralph exit(2); 52012111Sralph } 52112111Sralph (void) close(p[1]); /* close output side */ 52212111Sralph (void) close(fi); 52312111Sralph if (prchild < 0) { 52412111Sralph prchild = 0; 52512111Sralph (void) close(p[0]); 52617463Sralph return(ERROR); 52712111Sralph } 52812111Sralph fi = p[0]; /* use pipe for input */ 52912111Sralph case 'f': /* print plain text file */ 53012111Sralph prog = IF; 53112111Sralph av[1] = width; 53212111Sralph av[2] = length; 53312581Sralph av[3] = indent; 53412581Sralph n = 4; 53512111Sralph break; 53612111Sralph case 'l': /* like 'f' but pass control characters */ 53712111Sralph prog = IF; 53814325Sralph av[1] = "-c"; 53912111Sralph av[2] = width; 54012111Sralph av[3] = length; 54112581Sralph av[4] = indent; 54212581Sralph n = 5; 54312111Sralph break; 54412463Sralph case 'r': /* print a fortran text file */ 54512463Sralph prog = RF; 54612463Sralph av[1] = width; 54712463Sralph av[2] = length; 54812463Sralph n = 3; 54912463Sralph break; 55012111Sralph case 't': /* print troff output */ 55113233Sralph case 'n': /* print ditroff output */ 55212463Sralph case 'd': /* print tex output */ 55312111Sralph (void) unlink(".railmag"); 55412463Sralph if ((fo = creat(".railmag", FILMOD)) < 0) { 55516762Sralph syslog(LOG_ERR, "%s: cannot create .railmag", printer); 55612111Sralph (void) unlink(".railmag"); 55712111Sralph } else { 55812111Sralph for (n = 0; n < 4; n++) { 55912111Sralph if (fonts[n][0] != '/') 56054520Sbostic (void) write(fo, _PATH_VFONT, 56154520Sbostic sizeof(_PATH_VFONT) - 1); 56212111Sralph (void) write(fo, fonts[n], strlen(fonts[n])); 56312111Sralph (void) write(fo, "\n", 1); 56412111Sralph } 56512111Sralph (void) close(fo); 56612111Sralph } 56713233Sralph prog = (format == 't') ? TF : (format == 'n') ? NF : DF; 56812463Sralph av[1] = pxwidth; 56912463Sralph av[2] = pxlength; 57012463Sralph n = 3; 57112111Sralph break; 57212111Sralph case 'c': /* print cifplot output */ 57312111Sralph prog = CF; 57412463Sralph av[1] = pxwidth; 57512463Sralph av[2] = pxlength; 57612463Sralph n = 3; 57712111Sralph break; 57812111Sralph case 'g': /* print plot(1G) output */ 57912111Sralph prog = GF; 58012463Sralph av[1] = pxwidth; 58112463Sralph av[2] = pxlength; 58212463Sralph n = 3; 58312111Sralph break; 58412111Sralph case 'v': /* print raster output */ 58512111Sralph prog = VF; 58612463Sralph av[1] = pxwidth; 58712463Sralph av[2] = pxlength; 58812463Sralph n = 3; 58912111Sralph break; 59012111Sralph default: 59112111Sralph (void) close(fi); 59216762Sralph syslog(LOG_ERR, "%s: illegal format character '%c'", 59316762Sralph printer, format); 59417463Sralph return(ERROR); 59512111Sralph } 59612111Sralph if ((av[0] = rindex(prog, '/')) != NULL) 59712111Sralph av[0]++; 59812111Sralph else 59912111Sralph av[0] = prog; 60012111Sralph av[n++] = "-n"; 60112111Sralph av[n++] = logname; 60212111Sralph av[n++] = "-h"; 60314150Sralph av[n++] = fromhost; 60412111Sralph av[n++] = AF; 60512111Sralph av[n] = 0; 60612111Sralph fo = pfd; 60712111Sralph if (ofilter > 0) { /* stop output filter */ 60812111Sralph write(ofd, "\031\1", 2); 60946912Sbostic while ((pid = 61046912Sbostic wait3((int *)&status, WUNTRACED, 0)) > 0 && pid != ofilter) 61112111Sralph ; 61212111Sralph if (status.w_stopval != WSTOPPED) { 61312111Sralph (void) close(fi); 61416762Sralph syslog(LOG_WARNING, "%s: output filter died (%d)", 61516762Sralph printer, status.w_retcode); 61617463Sralph return(REPRINT); 61712111Sralph } 61812111Sralph stopped++; 61912111Sralph } 62012111Sralph start: 62112111Sralph if ((child = dofork(DORETURN)) == 0) { /* child */ 62212111Sralph dup2(fi, 0); 62312111Sralph dup2(fo, 1); 62439954Smckusick n = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, 0664); 62515811Sralph if (n >= 0) 62615811Sralph dup2(n, 2); 62712111Sralph for (n = 3; n < NOFILE; n++) 62812111Sralph (void) close(n); 62912111Sralph execv(prog, av); 63016762Sralph syslog(LOG_ERR, "cannot execv %s", prog); 63112111Sralph exit(2); 63212111Sralph } 63312111Sralph (void) close(fi); 63412111Sralph if (child < 0) 63512111Sralph status.w_retcode = 100; 63612111Sralph else 63746912Sbostic while ((pid = wait((int *)&status)) > 0 && pid != child) 63812111Sralph ; 63912111Sralph child = 0; 64012111Sralph prchild = 0; 64112111Sralph if (stopped) { /* restart output filter */ 64212111Sralph if (kill(ofilter, SIGCONT) < 0) { 64316762Sralph syslog(LOG_ERR, "cannot restart output filter"); 64412111Sralph exit(1); 64512111Sralph } 64612111Sralph } 64712111Sralph tof = 0; 64839954Smckusick 64939954Smckusick /* Copy filter output to "lf" logfile */ 65039954Smckusick if (fp = fopen(tempfile, "r")) { 65139954Smckusick while (fgets(buf, sizeof(buf), fp)) 65239954Smckusick fputs(buf, stderr); 65356123Selan fclose(fp); 65439954Smckusick } 65539954Smckusick 65615811Sralph if (!WIFEXITED(status)) { 65716762Sralph syslog(LOG_WARNING, "%s: Daemon filter '%c' terminated (%d)", 65816762Sralph printer, format, status.w_termsig); 65917463Sralph return(ERROR); 66017463Sralph } 66117463Sralph switch (status.w_retcode) { 66217463Sralph case 0: 66317463Sralph tof = 1; 66417463Sralph return(OK); 66517463Sralph case 1: 66617463Sralph return(REPRINT); 66717463Sralph default: 66816762Sralph syslog(LOG_WARNING, "%s: Daemon filter '%c' exited (%d)", 66916762Sralph printer, format, status.w_retcode); 67017463Sralph case 2: 67117463Sralph return(ERROR); 67217463Sralph } 67312111Sralph } 67412111Sralph 67512111Sralph /* 67612111Sralph * Send the daemon control file (cf) and any data files. 67712111Sralph * Return -1 if a non-recoverable error occured, 1 if a recoverable error and 67812111Sralph * 0 if all is well. 67912111Sralph */ 68055474Sbostic static int 68112111Sralph sendit(file) 68212111Sralph char *file; 68312111Sralph { 68417463Sralph register int i, err = OK; 68517463Sralph char *cp, last[BUFSIZ]; 68612111Sralph 68712111Sralph /* 68812111Sralph * open control file 68912111Sralph */ 69016762Sralph if ((cfp = fopen(file, "r")) == NULL) 69117463Sralph return(OK); 69212111Sralph /* 69312111Sralph * read the control file for work to do 69412111Sralph * 69512111Sralph * file format -- first character in the line is a command 69612111Sralph * rest of the line is the argument. 69712111Sralph * commands of interest are: 69812111Sralph * 69912111Sralph * a-z -- "file name" name of file to print 70012111Sralph * U -- "unlink" name of file to remove 70112111Sralph * (after we print it. (Pass 2 only)). 70212111Sralph */ 70312111Sralph 70412111Sralph /* 70512111Sralph * pass 1 70612111Sralph */ 70712111Sralph while (getline(cfp)) { 70812111Sralph again: 70917463Sralph if (line[0] == 'S') { 71017463Sralph cp = line+1; 71117463Sralph i = 0; 71217463Sralph while (*cp >= '0' && *cp <= '9') 71317463Sralph i = i * 10 + (*cp++ - '0'); 71417463Sralph fdev = i; 71517463Sralph cp++; 71617463Sralph i = 0; 71717463Sralph while (*cp >= '0' && *cp <= '9') 71817463Sralph i = i * 10 + (*cp++ - '0'); 71917463Sralph fino = i; 72017463Sralph continue; 72117463Sralph } 72212111Sralph if (line[0] >= 'a' && line[0] <= 'z') { 72312111Sralph strcpy(last, line); 72417463Sralph while (i = getline(cfp)) 72512111Sralph if (strcmp(last, line)) 72612111Sralph break; 72717463Sralph switch (sendfile('\3', last+1)) { 72817463Sralph case OK: 72917463Sralph if (i) 73017463Sralph goto again; 73117463Sralph break; 73217463Sralph case REPRINT: 73312111Sralph (void) fclose(cfp); 73417463Sralph return(REPRINT); 73517463Sralph case ACCESS: 73617463Sralph sendmail(logname, ACCESS); 73717463Sralph case ERROR: 73817463Sralph err = ERROR; 73917463Sralph } 74012111Sralph break; 74112111Sralph } 74212111Sralph } 74317463Sralph if (err == OK && sendfile('\2', file) > 0) { 74412111Sralph (void) fclose(cfp); 74517463Sralph return(REPRINT); 74612111Sralph } 74712111Sralph /* 74812111Sralph * pass 2 74912111Sralph */ 75012111Sralph fseek(cfp, 0L, 0); 75112111Sralph while (getline(cfp)) 75212111Sralph if (line[0] == 'U') 75312111Sralph (void) unlink(line+1); 75412111Sralph /* 75517463Sralph * clean-up in case another control file exists 75612111Sralph */ 75712111Sralph (void) fclose(cfp); 75812111Sralph (void) unlink(file); 75917463Sralph return(err); 76012111Sralph } 76112111Sralph 76212111Sralph /* 76312111Sralph * Send a data file to the remote machine and spool it. 76412111Sralph * Return positive if we should try resending. 76512111Sralph */ 76655474Sbostic static int 76712111Sralph sendfile(type, file) 76855474Sbostic int type; 76955474Sbostic char *file; 77012111Sralph { 77112111Sralph register int f, i, amt; 77212111Sralph struct stat stb; 77312111Sralph char buf[BUFSIZ]; 77416762Sralph int sizerr, resp; 77512111Sralph 77617463Sralph if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0) 77717463Sralph return(ERROR); 77817463Sralph /* 77917463Sralph * Check to see if data file is a symbolic link. If so, it should 78017463Sralph * still point to the same file or someone is trying to print something 78117463Sralph * he shouldn't. 78217463Sralph */ 78317463Sralph if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 && 78417463Sralph (stb.st_dev != fdev || stb.st_ino != fino)) 78517463Sralph return(ACCESS); 78655474Sbostic (void) sprintf(buf, "%c%qd %s\n", type, stb.st_size, file); 78712111Sralph amt = strlen(buf); 78816762Sralph for (i = 0; ; i++) { 78916762Sralph if (write(pfd, buf, amt) != amt || 79016762Sralph (resp = response()) < 0 || resp == '\1') { 79116762Sralph (void) close(f); 79217463Sralph return(REPRINT); 79316762Sralph } else if (resp == '\0') 79416762Sralph break; 79516762Sralph if (i == 0) 79655474Sbostic pstatus("no space on remote; waiting for queue to drain"); 79716762Sralph if (i == 10) 79824861Seric syslog(LOG_ALERT, "%s: can't send to %s; queue full", 79916762Sralph printer, RM); 80016762Sralph sleep(5 * 60); 80112692Sralph } 80216762Sralph if (i) 80355474Sbostic pstatus("sending to %s", RM); 80412111Sralph sizerr = 0; 80512111Sralph for (i = 0; i < stb.st_size; i += BUFSIZ) { 80612111Sralph amt = BUFSIZ; 80712111Sralph if (i + amt > stb.st_size) 80812111Sralph amt = stb.st_size - i; 80912111Sralph if (sizerr == 0 && read(f, buf, amt) != amt) 81012111Sralph sizerr = 1; 81112692Sralph if (write(pfd, buf, amt) != amt) { 81212692Sralph (void) close(f); 81317463Sralph return(REPRINT); 81412692Sralph } 81512111Sralph } 81655474Sbostic 81755474Sbostic 81855474Sbostic 81955474Sbostic 82012111Sralph (void) close(f); 82112111Sralph if (sizerr) { 82216762Sralph syslog(LOG_INFO, "%s: %s: changed size", printer, file); 82317463Sralph /* tell recvjob to ignore this file */ 82417463Sralph (void) write(pfd, "\1", 1); 82517463Sralph return(ERROR); 82617463Sralph } 82717463Sralph if (write(pfd, "", 1) != 1 || response()) 82817463Sralph return(REPRINT); 82917463Sralph return(OK); 83012111Sralph } 83112111Sralph 83212111Sralph /* 83312111Sralph * Check to make sure there have been no errors and that both programs 83412111Sralph * are in sync with eachother. 83512111Sralph * Return non-zero if the connection was lost. 83612111Sralph */ 83755474Sbostic static char 83816762Sralph response() 83912111Sralph { 84012111Sralph char resp; 84112111Sralph 84216762Sralph if (read(pfd, &resp, 1) != 1) { 84316762Sralph syslog(LOG_INFO, "%s: lost connection", printer); 84416762Sralph return(-1); 84512111Sralph } 84616762Sralph return(resp); 84712111Sralph } 84812111Sralph 84912111Sralph /* 85012111Sralph * Banner printing stuff 85112111Sralph */ 85255474Sbostic static void 85312111Sralph banner(name1, name2) 85412111Sralph char *name1, *name2; 85512111Sralph { 85612111Sralph time_t tvec; 85712111Sralph extern char *ctime(); 85812111Sralph 85912111Sralph time(&tvec); 86012111Sralph if (!SF && !tof) 86112111Sralph (void) write(ofd, FF, strlen(FF)); 86212111Sralph if (SB) { /* short banner only */ 86312111Sralph if (class[0]) { 86412111Sralph (void) write(ofd, class, strlen(class)); 86512111Sralph (void) write(ofd, ":", 1); 86612111Sralph } 86712111Sralph (void) write(ofd, name1, strlen(name1)); 86812111Sralph (void) write(ofd, " Job: ", 7); 86912111Sralph (void) write(ofd, name2, strlen(name2)); 87012111Sralph (void) write(ofd, " Date: ", 8); 87112111Sralph (void) write(ofd, ctime(&tvec), 24); 87212111Sralph (void) write(ofd, "\n", 1); 87312111Sralph } else { /* normal banner */ 87412111Sralph (void) write(ofd, "\n\n\n", 3); 87512111Sralph scan_out(ofd, name1, '\0'); 87612111Sralph (void) write(ofd, "\n\n", 2); 87712111Sralph scan_out(ofd, name2, '\0'); 87812111Sralph if (class[0]) { 87912111Sralph (void) write(ofd,"\n\n\n",3); 88012111Sralph scan_out(ofd, class, '\0'); 88112111Sralph } 88212111Sralph (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15); 88312111Sralph (void) write(ofd, name2, strlen(name2)); 88412111Sralph (void) write(ofd, "\n\t\t\t\t\tDate: ", 12); 88512111Sralph (void) write(ofd, ctime(&tvec), 24); 88612111Sralph (void) write(ofd, "\n", 1); 88712111Sralph } 88812111Sralph if (!SF) 88912111Sralph (void) write(ofd, FF, strlen(FF)); 89012111Sralph tof = 1; 89112111Sralph } 89212111Sralph 89355474Sbostic static char * 89412111Sralph scnline(key, p, c) 89555474Sbostic register int key; 89655474Sbostic register char *p; 89755474Sbostic int c; 89812111Sralph { 89912111Sralph register scnwidth; 90012111Sralph 90112111Sralph for (scnwidth = WIDTH; --scnwidth;) { 90212111Sralph key <<= 1; 90312111Sralph *p++ = key & 0200 ? c : BACKGND; 90412111Sralph } 90512111Sralph return (p); 90612111Sralph } 90712111Sralph 90812111Sralph #define TRC(q) (((q)-' ')&0177) 90912111Sralph 91055474Sbostic static void 91112111Sralph scan_out(scfd, scsp, dlm) 91255474Sbostic int scfd, dlm; 91355474Sbostic char *scsp; 91412111Sralph { 91512111Sralph register char *strp; 91612111Sralph register nchrs, j; 91712111Sralph char outbuf[LINELEN+1], *sp, c, cc; 91812111Sralph int d, scnhgt; 91912111Sralph extern char scnkey[][HEIGHT]; /* in lpdchar.c */ 92012111Sralph 92112111Sralph for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) { 92212111Sralph strp = &outbuf[0]; 92312111Sralph sp = scsp; 92412111Sralph for (nchrs = 0; ; ) { 92512111Sralph d = dropit(c = TRC(cc = *sp++)); 92612111Sralph if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d)) 92712111Sralph for (j = WIDTH; --j;) 92812111Sralph *strp++ = BACKGND; 92912111Sralph else 93012111Sralph strp = scnline(scnkey[c][scnhgt-1-d], strp, cc); 93112111Sralph if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1) 93212111Sralph break; 93312111Sralph *strp++ = BACKGND; 93412111Sralph *strp++ = BACKGND; 93512111Sralph } 93612111Sralph while (*--strp == BACKGND && strp >= outbuf) 93712111Sralph ; 93812111Sralph strp++; 93912111Sralph *strp++ = '\n'; 94012111Sralph (void) write(scfd, outbuf, strp-outbuf); 94112111Sralph } 94212111Sralph } 94312111Sralph 94455474Sbostic static int 94512111Sralph dropit(c) 94655474Sbostic int c; 94712111Sralph { 94812111Sralph switch(c) { 94912111Sralph 95012111Sralph case TRC('_'): 95112111Sralph case TRC(';'): 95212111Sralph case TRC(','): 95312111Sralph case TRC('g'): 95412111Sralph case TRC('j'): 95512111Sralph case TRC('p'): 95612111Sralph case TRC('q'): 95712111Sralph case TRC('y'): 95812111Sralph return (DROP); 95912111Sralph 96012111Sralph default: 96112111Sralph return (0); 96212111Sralph } 96312111Sralph } 96412111Sralph 96512111Sralph /* 96612111Sralph * sendmail --- 96712111Sralph * tell people about job completion 96812111Sralph */ 96955474Sbostic static void 97015811Sralph sendmail(user, bombed) 97115811Sralph char *user; 97212111Sralph int bombed; 97312111Sralph { 97412111Sralph register int i; 97515811Sralph int p[2], s; 97612111Sralph register char *cp; 97712111Sralph char buf[100]; 97815811Sralph struct stat stb; 97915811Sralph FILE *fp; 98012111Sralph 98112111Sralph pipe(p); 98215811Sralph if ((s = dofork(DORETURN)) == 0) { /* child */ 98312111Sralph dup2(p[0], 0); 98412111Sralph for (i = 3; i < NOFILE; i++) 98512111Sralph (void) close(i); 98637968Sbostic if ((cp = rindex(_PATH_SENDMAIL, '/')) != NULL) 98712111Sralph cp++; 98855474Sbostic else 98937968Sbostic cp = _PATH_SENDMAIL; 99015811Sralph sprintf(buf, "%s@%s", user, fromhost); 99137968Sbostic execl(_PATH_SENDMAIL, cp, buf, 0); 99212111Sralph exit(0); 99315811Sralph } else if (s > 0) { /* parent */ 99412111Sralph dup2(p[1], 1); 99515811Sralph printf("To: %s@%s\n", user, fromhost); 99612111Sralph printf("Subject: printer job\n\n"); 99712111Sralph printf("Your printer job "); 99812111Sralph if (*jobname) 99912111Sralph printf("(%s) ", jobname); 100012463Sralph switch (bombed) { 100117463Sralph case OK: 100212463Sralph printf("\ncompleted successfully\n"); 100312463Sralph break; 100412463Sralph default: 100517463Sralph case FATALERR: 100612463Sralph printf("\ncould not be printed\n"); 100712463Sralph break; 100817463Sralph case NOACCT: 100912463Sralph printf("\ncould not be printed without an account on %s\n", host); 101012463Sralph break; 101117463Sralph case FILTERERR: 101239954Smckusick if (stat(tempfile, &stb) < 0 || stb.st_size == 0 || 101339954Smckusick (fp = fopen(tempfile, "r")) == NULL) { 101415811Sralph printf("\nwas printed but had some errors\n"); 101515811Sralph break; 101615811Sralph } 101715811Sralph printf("\nwas printed but had the following errors:\n"); 101815811Sralph while ((i = getc(fp)) != EOF) 101915811Sralph putchar(i); 102015811Sralph (void) fclose(fp); 102117463Sralph break; 102217463Sralph case ACCESS: 102317463Sralph printf("\nwas not printed because it was not linked to the original file\n"); 102412463Sralph } 102512111Sralph fflush(stdout); 102612111Sralph (void) close(1); 102712111Sralph } 102812111Sralph (void) close(p[0]); 102912111Sralph (void) close(p[1]); 103015811Sralph wait(&s); 103112111Sralph } 103212111Sralph 103312111Sralph /* 103412111Sralph * dofork - fork with retries on failure 103512111Sralph */ 103655474Sbostic static int 103712111Sralph dofork(action) 103812111Sralph int action; 103912111Sralph { 104012111Sralph register int i, pid; 104112111Sralph 104212111Sralph for (i = 0; i < 20; i++) { 104312463Sralph if ((pid = fork()) < 0) { 104412111Sralph sleep((unsigned)(i*i)); 104512463Sralph continue; 104612463Sralph } 104712463Sralph /* 104812463Sralph * Child should run as daemon instead of root 104912463Sralph */ 105012463Sralph if (pid == 0) 105112463Sralph setuid(DU); 105212463Sralph return(pid); 105312111Sralph } 105416762Sralph syslog(LOG_ERR, "can't fork"); 105512111Sralph 105612111Sralph switch (action) { 105712111Sralph case DORETURN: 105812111Sralph return (-1); 105912111Sralph default: 106016762Sralph syslog(LOG_ERR, "bad action (%d) to dofork", action); 106112111Sralph /*FALL THRU*/ 106212111Sralph case DOABORT: 106312111Sralph exit(1); 106412111Sralph } 106512111Sralph /*NOTREACHED*/ 106612111Sralph } 106712111Sralph 106812111Sralph /* 106916762Sralph * Kill child processes to abort current job. 107012111Sralph */ 107155474Sbostic static void 107255474Sbostic abortpr(signo) 107355474Sbostic int signo; 107412111Sralph { 107539954Smckusick (void) unlink(tempfile); 107612111Sralph kill(0, SIGINT); 107712111Sralph if (ofilter > 0) 107812111Sralph kill(ofilter, SIGCONT); 107946912Sbostic while (wait(NULL) > 0) 108012111Sralph ; 108112111Sralph exit(0); 108212111Sralph } 108312111Sralph 108455474Sbostic static void 108512111Sralph init() 108612111Sralph { 108712111Sralph int status; 108838736Stef char *s; 108912111Sralph 109056123Selan if ((status = cgetent(&bp, printcapdb, printer)) == -2) { 109125468Stef syslog(LOG_ERR, "can't open printer description file"); 109225468Stef exit(1); 109356123Selan } else if (status == -1) { 109425468Stef syslog(LOG_ERR, "unknown printer: %s", printer); 109525468Stef exit(1); 109656123Selan } else if (status == -3) 109756123Selan fatal("potential reference loop detected in printcap file"); 109856123Selan 109956123Selan if (cgetstr(bp, "lp", &LP) == -1) 110037968Sbostic LP = _PATH_DEFDEVLP; 110156123Selan if (cgetstr(bp, "rp", &RP) == -1) 110212463Sralph RP = DEFLP; 110356123Selan if (cgetstr(bp, "lo", &LO) == -1) 110412111Sralph LO = DEFLOCK; 110556123Selan if (cgetstr(bp, "st", &ST) == -1) 110612111Sralph ST = DEFSTAT; 110756123Selan if (cgetstr(bp, "lf", &LF) == -1) 110837968Sbostic LF = _PATH_CONSOLE; 110956123Selan if (cgetstr(bp, "sd", &SD) == -1) 111037968Sbostic SD = _PATH_DEFSPOOL; 111156123Selan if (cgetnum(bp, "du", &DU) < 0) 111212111Sralph DU = DEFUID; 111356123Selan if (cgetstr(bp,"ff", &FF) == -1) 111412111Sralph FF = DEFFF; 111556123Selan if (cgetnum(bp, "pw", &PW) < 0) 111612111Sralph PW = DEFWIDTH; 111712111Sralph sprintf(&width[2], "%d", PW); 111856123Selan if (cgetnum(bp, "pl", &PL) < 0) 111912111Sralph PL = DEFLENGTH; 112012111Sralph sprintf(&length[2], "%d", PL); 112156123Selan if (cgetnum(bp,"px", &PX) < 0) 112212463Sralph PX = 0; 112312463Sralph sprintf(&pxwidth[2], "%d", PX); 112456123Selan if (cgetnum(bp, "py", &PY) < 0) 112512463Sralph PY = 0; 112612463Sralph sprintf(&pxlength[2], "%d", PY); 112756123Selan cgetstr(bp, "rm", &RM); 112838736Stef if (s = checkremote()) 112938736Stef syslog(LOG_WARNING, s); 113025468Stef 113156123Selan cgetstr(bp, "af", &AF); 113256123Selan cgetstr(bp, "of", &OF); 113356123Selan cgetstr(bp, "if", &IF); 113456123Selan cgetstr(bp, "rf", &RF); 113556123Selan cgetstr(bp, "tf", &TF); 113656123Selan cgetstr(bp, "nf", &NF); 113756123Selan cgetstr(bp, "df", &DF); 113856123Selan cgetstr(bp, "gf", &GF); 113956123Selan cgetstr(bp, "vf", &VF); 114056123Selan cgetstr(bp, "cf", &CF); 114156123Selan cgetstr(bp, "tr", &TR); 114256123Selan 114356123Selan RS = (cgetcap(bp, "rs", ':') != NULL); 114456123Selan SF = (cgetcap(bp, "sf", ':') != NULL); 114556123Selan SH = (cgetcap(bp, "sh", ':') != NULL); 114656123Selan SB = (cgetcap(bp, "sb", ':') != NULL); 114756123Selan HL = (cgetcap(bp, "hl", ':') != NULL); 114856123Selan RW = (cgetcap(bp, "rw", ':') != NULL); 114956123Selan 115056123Selan cgetnum(bp, "br", &BR); 115156123Selan if (cgetnum(bp, "fc", &FC) < 0) 115212111Sralph FC = 0; 115356123Selan if (cgetnum(bp, "fs", &FS) < 0) 115412111Sralph FS = 0; 115556123Selan if (cgetnum(bp, "xc", &XC) < 0) 115612111Sralph XC = 0; 115756123Selan if (cgetnum(bp, "xs", &XS) < 0) 115812111Sralph XS = 0; 115956123Selan 116056123Selan tof = (cgetcap(bp, "fo", ':') == NULL); 116112111Sralph } 116212111Sralph 116312463Sralph /* 116412463Sralph * Acquire line printer or remote connection. 116512463Sralph */ 116655474Sbostic static void 116712463Sralph openpr() 116812463Sralph { 116912463Sralph register int i, n; 117016762Sralph int resp; 117112463Sralph 117238736Stef if (!sendtorem && *LP) { 117312463Sralph for (i = 1; ; i = i < 32 ? i << 1 : i) { 117413148Ssam pfd = open(LP, RW ? O_RDWR : O_WRONLY); 117512463Sralph if (pfd >= 0) 117612463Sralph break; 117712463Sralph if (errno == ENOENT) { 117816762Sralph syslog(LOG_ERR, "%s: %m", LP); 117912463Sralph exit(1); 118012463Sralph } 118112463Sralph if (i == 1) 118255474Sbostic pstatus("waiting for %s to become ready (offline ?)", printer); 118312463Sralph sleep(i); 118412463Sralph } 118512463Sralph if (isatty(pfd)) 118612463Sralph setty(); 118755474Sbostic pstatus("%s is ready and printing", printer); 118812463Sralph } else if (RM != NULL) { 118916762Sralph for (i = 1; ; i = i < 256 ? i << 1 : i) { 119016762Sralph resp = -1; 119112528Sralph pfd = getport(RM); 119212463Sralph if (pfd >= 0) { 119312463Sralph (void) sprintf(line, "\2%s\n", RP); 119412463Sralph n = strlen(line); 119516762Sralph if (write(pfd, line, n) == n && 119616762Sralph (resp = response()) == '\0') 119712463Sralph break; 119816031Sralph (void) close(pfd); 119912463Sralph } 120016031Sralph if (i == 1) { 120116762Sralph if (resp < 0) 120255474Sbostic pstatus("waiting for %s to come up", RM); 120316762Sralph else { 120455474Sbostic pstatus("waiting for queue to be enabled on %s", RM); 120516762Sralph i = 256; 120616762Sralph } 120716031Sralph } 120812463Sralph sleep(i); 120912463Sralph } 121055474Sbostic pstatus("sending to %s", RM); 121112463Sralph remote = 1; 121212463Sralph } else { 121316762Sralph syslog(LOG_ERR, "%s: no line printer device or host name", 121416762Sralph printer); 121512463Sralph exit(1); 121612463Sralph } 121712463Sralph /* 121812463Sralph * Start up an output filter, if needed. 121912463Sralph */ 122040049Stef if (!remote && OF) { 122112463Sralph int p[2]; 122212463Sralph char *cp; 122312463Sralph 122412463Sralph pipe(p); 122512463Sralph if ((ofilter = dofork(DOABORT)) == 0) { /* child */ 122612463Sralph dup2(p[0], 0); /* pipe is std in */ 122712463Sralph dup2(pfd, 1); /* printer is std out */ 122812463Sralph for (i = 3; i < NOFILE; i++) 122912463Sralph (void) close(i); 123012463Sralph if ((cp = rindex(OF, '/')) == NULL) 123112463Sralph cp = OF; 123212463Sralph else 123312463Sralph cp++; 123412463Sralph execl(OF, cp, width, length, 0); 123516762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, OF); 123612463Sralph exit(1); 123712463Sralph } 123812463Sralph (void) close(p[0]); /* close input side */ 123912463Sralph ofd = p[1]; /* use pipe for output */ 124012463Sralph } else { 124112463Sralph ofd = pfd; 124212463Sralph ofilter = 0; 124312463Sralph } 124412463Sralph } 124512463Sralph 124612111Sralph struct bauds { 124712111Sralph int baud; 124812111Sralph int speed; 124912111Sralph } bauds[] = { 125012111Sralph 50, B50, 125112111Sralph 75, B75, 125212111Sralph 110, B110, 125312111Sralph 134, B134, 125412111Sralph 150, B150, 125512111Sralph 200, B200, 125612111Sralph 300, B300, 125712111Sralph 600, B600, 125812111Sralph 1200, B1200, 125912111Sralph 1800, B1800, 126012111Sralph 2400, B2400, 126112111Sralph 4800, B4800, 126212111Sralph 9600, B9600, 126312111Sralph 19200, EXTA, 126412111Sralph 38400, EXTB, 126512111Sralph 0, 0 126612111Sralph }; 126712111Sralph 126812111Sralph /* 126912111Sralph * setup tty lines. 127012111Sralph */ 127155474Sbostic static void 127212111Sralph setty() 127312111Sralph { 127412111Sralph struct sgttyb ttybuf; 127512111Sralph register struct bauds *bp; 127612111Sralph 127712111Sralph if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) { 127816762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer); 127912111Sralph exit(1); 128012111Sralph } 128112111Sralph if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) { 128216762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCGETP): %m", printer); 128312111Sralph exit(1); 128412111Sralph } 128512111Sralph if (BR > 0) { 128612111Sralph for (bp = bauds; bp->baud; bp++) 128712111Sralph if (BR == bp->baud) 128812111Sralph break; 128912111Sralph if (!bp->baud) { 129016762Sralph syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR); 129112111Sralph exit(1); 129212111Sralph } 129312111Sralph ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed; 129412111Sralph } 129513169Sralph ttybuf.sg_flags &= ~FC; 129613169Sralph ttybuf.sg_flags |= FS; 129712111Sralph if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) { 129816762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCSETP): %m", printer); 129912111Sralph exit(1); 130012111Sralph } 130112111Sralph if (XC) { 130212111Sralph if (ioctl(pfd, TIOCLBIC, &XC) < 0) { 130316762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCLBIC): %m", printer); 130412111Sralph exit(1); 130512111Sralph } 130612111Sralph } 130712111Sralph if (XS) { 130812111Sralph if (ioctl(pfd, TIOCLBIS, &XS) < 0) { 130916762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCLBIS): %m", printer); 131012111Sralph exit(1); 131112111Sralph } 131212111Sralph } 131312111Sralph } 131412463Sralph 131555474Sbostic #if __STDC__ 131655474Sbostic #include <stdarg.h> 131755474Sbostic #else 131855474Sbostic #include <varargs.h> 131955474Sbostic #endif 132055474Sbostic 132155474Sbostic void 132255474Sbostic #if __STDC__ 132355474Sbostic pstatus(const char *msg, ...) 132455474Sbostic #else 132555474Sbostic pstatus(msg, va_alist) 132612463Sralph char *msg; 132755474Sbostic va_dcl 132855474Sbostic #endif 132912463Sralph { 133012463Sralph register int fd; 133112463Sralph char buf[BUFSIZ]; 133255474Sbostic va_list ap; 133355474Sbostic #if __STDC__ 133455474Sbostic va_start(ap, msg); 133555474Sbostic #else 133655474Sbostic va_start(ap); 133755474Sbostic #endif 133812463Sralph 133912463Sralph umask(0); 134013148Ssam fd = open(ST, O_WRONLY|O_CREAT, 0664); 134116762Sralph if (fd < 0 || flock(fd, LOCK_EX) < 0) { 134216762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, ST); 134316762Sralph exit(1); 134416762Sralph } 134513148Ssam ftruncate(fd, 0); 134655474Sbostic (void)vsnprintf(buf, sizeof(buf), msg, ap); 134755474Sbostic va_end(ap); 134812463Sralph strcat(buf, "\n"); 134912463Sralph (void) write(fd, buf, strlen(buf)); 135012463Sralph (void) close(fd); 135112463Sralph } 1352