122437Sdist /* 222437Sdist * Copyright (c) 1983 Regents of the University of California. 334203Sbostic * All rights reserved. 434203Sbostic * 542802Sbostic * %sccs.include.redist.c% 622437Sdist */ 722437Sdist 813954Ssam #ifndef lint 9*54520Sbostic static char sccsid[] = "@(#)printjob.c 5.14 (Berkeley) 06/27/92"; 1034203Sbostic #endif /* not lint */ 1113954Ssam 1212111Sralph /* 1312111Sralph * printjob -- print jobs in the queue. 1412111Sralph * 1512111Sralph * NOTE: the lock file is used to pass information to lpq and lprm. 1612111Sralph * it does not need to be removed because file locks are dynamic. 1712111Sralph */ 1812111Sralph 1912111Sralph #include "lp.h" 2037968Sbostic #include "pathnames.h" 2112111Sralph 2216762Sralph #define DORETURN 0 /* absorb fork error */ 2316762Sralph #define DOABORT 1 /* abort if dofork fails */ 2412111Sralph 2517463Sralph /* 2617463Sralph * Error tokens 2717463Sralph */ 2817463Sralph #define REPRINT -2 2917463Sralph #define ERROR -1 3017463Sralph #define OK 0 3117463Sralph #define FATALERR 1 3217463Sralph #define NOACCT 2 3317463Sralph #define FILTERERR 3 3417463Sralph #define ACCESS 4 3517463Sralph 3616762Sralph char title[80]; /* ``pr'' title */ 3716762Sralph FILE *cfp; /* control file */ 3816762Sralph int pfd; /* printer file descriptor */ 3916762Sralph int ofd; /* output filter file descriptor */ 4016762Sralph int lfd; /* lock file descriptor */ 4116762Sralph int pid; /* pid of lpd process */ 4216762Sralph int prchild; /* id of pr process */ 4316762Sralph int child; /* id of any filters */ 4416762Sralph int ofilter; /* id of output filter, if any */ 4516762Sralph int tof; /* true if at top of form */ 4616762Sralph int remote; /* true if sending files to remote */ 4717463Sralph dev_t fdev; /* device of file pointed to by symlink */ 4817463Sralph ino_t fino; /* inode of file pointed to by symlink */ 4912111Sralph 5016762Sralph char fromhost[32]; /* user's host machine */ 5116762Sralph char logname[32]; /* user's login name */ 5216762Sralph char jobname[100]; /* job or file name */ 5316762Sralph char class[32]; /* classification field */ 5416762Sralph char width[10] = "-w"; /* page width in characters */ 5516762Sralph char length[10] = "-l"; /* page length in lines */ 5616762Sralph char pxwidth[10] = "-x"; /* page width in pixels */ 5716762Sralph char pxlength[10] = "-y"; /* page length in pixels */ 5816762Sralph char indent[10] = "-i0"; /* indentation size in characters */ 5939954Smckusick char tempfile[] = "errsXXXXXX"; /* file name for filter output */ 6012111Sralph 6112111Sralph printjob() 6212111Sralph { 6312111Sralph struct stat stb; 6412111Sralph register struct queue *q, **qp; 6512111Sralph struct queue **queue; 6612111Sralph register int i, nitems; 6712111Sralph long pidoff; 6816762Sralph int count = 0; 6946912Sbostic void abortpr(); 7012111Sralph 7112111Sralph init(); /* set up capabilities */ 7213442Sralph (void) write(1, "", 1); /* ack that daemon is started */ 7325496Seric (void) close(2); /* set up log file */ 7425496Seric if (open(LF, O_WRONLY|O_APPEND, 0664) < 0) { 7525496Seric syslog(LOG_ERR, "%s: %m", LF); 7637968Sbostic (void) open(_PATH_DEVNULL, O_WRONLY); 7725496Seric } 7816762Sralph setgid(getegid()); 7912463Sralph pid = getpid(); /* for use with lprm */ 8012111Sralph setpgrp(0, pid); 8116762Sralph signal(SIGHUP, abortpr); 8216762Sralph signal(SIGINT, abortpr); 8316762Sralph signal(SIGQUIT, abortpr); 8416762Sralph signal(SIGTERM, abortpr); 8512111Sralph 8639954Smckusick (void) mktemp(tempfile); 8715811Sralph 8812111Sralph /* 8912111Sralph * uses short form file names 9012111Sralph */ 9112111Sralph if (chdir(SD) < 0) { 9216762Sralph syslog(LOG_ERR, "%s: %m", SD); 9312111Sralph exit(1); 9412111Sralph } 9512463Sralph if (stat(LO, &stb) == 0 && (stb.st_mode & 0100)) 9612463Sralph exit(0); /* printing disabled */ 9714150Sralph lfd = open(LO, O_WRONLY|O_CREAT, 0644); 9813169Sralph if (lfd < 0) { 9916762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, LO); 10013169Sralph exit(1); 10113169Sralph } 10213169Sralph if (flock(lfd, LOCK_EX|LOCK_NB) < 0) { 10312111Sralph if (errno == EWOULDBLOCK) /* active deamon present */ 10412111Sralph exit(0); 10516762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, LO); 10612111Sralph exit(1); 10712111Sralph } 10813148Ssam ftruncate(lfd, 0); 10912111Sralph /* 11012111Sralph * write process id for others to know 11112111Sralph */ 11212111Sralph sprintf(line, "%u\n", pid); 11312111Sralph pidoff = i = strlen(line); 11412463Sralph if (write(lfd, line, i) != i) { 11516762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, LO); 11612111Sralph exit(1); 11712111Sralph } 11812111Sralph /* 11912111Sralph * search the spool directory for work and sort by queue order. 12012111Sralph */ 12112111Sralph if ((nitems = getq(&queue)) < 0) { 12216762Sralph syslog(LOG_ERR, "%s: can't scan %s", printer, SD); 12312111Sralph exit(1); 12412111Sralph } 12512463Sralph if (nitems == 0) /* no work to do */ 12612111Sralph exit(0); 12713169Sralph if (stb.st_mode & 01) { /* reset queue flag */ 12813169Sralph if (fchmod(lfd, stb.st_mode & 0776) < 0) 12916762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, LO); 13013169Sralph } 13112463Sralph openpr(); /* open printer or remote */ 13212463Sralph again: 13312111Sralph /* 13412111Sralph * we found something to do now do it -- 13512111Sralph * write the name of the current control file into the lock file 13612111Sralph * so the spool queue program can tell what we're working on 13712111Sralph */ 13812111Sralph for (qp = queue; nitems--; free((char *) q)) { 13912111Sralph q = *qp++; 14012111Sralph if (stat(q->q_name, &stb) < 0) 14112111Sralph continue; 14212463Sralph restart: 14312111Sralph (void) lseek(lfd, pidoff, 0); 14412111Sralph (void) sprintf(line, "%s\n", q->q_name); 14512111Sralph i = strlen(line); 14612111Sralph if (write(lfd, line, i) != i) 14716762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, LO); 14812111Sralph if (!remote) 14912111Sralph i = printit(q->q_name); 15012111Sralph else 15112111Sralph i = sendit(q->q_name); 15212463Sralph /* 15313169Sralph * Check to see if we are supposed to stop printing or 15413169Sralph * if we are to rebuild the queue. 15512463Sralph */ 15613169Sralph if (fstat(lfd, &stb) == 0) { 15716762Sralph /* stop printing before starting next job? */ 15813169Sralph if (stb.st_mode & 0100) 15913169Sralph goto done; 16016762Sralph /* rebuild queue (after lpc topq) */ 16113169Sralph if (stb.st_mode & 01) { 16213169Sralph for (free((char *) q); nitems--; free((char *) q)) 16313169Sralph q = *qp++; 16413169Sralph if (fchmod(lfd, stb.st_mode & 0776) < 0) 16516762Sralph syslog(LOG_WARNING, "%s: %s: %m", 16616762Sralph printer, LO); 16713169Sralph break; 16813169Sralph } 16913169Sralph } 17017463Sralph if (i == OK) /* file ok and printed */ 17114150Sralph count++; 17217463Sralph else if (i == REPRINT) { /* try reprinting the job */ 17316762Sralph syslog(LOG_INFO, "restarting %s", printer); 17412111Sralph if (ofilter > 0) { 17512111Sralph kill(ofilter, SIGCONT); /* to be sure */ 17612111Sralph (void) close(ofd); 17712111Sralph while ((i = wait(0)) > 0 && i != ofilter) 17812111Sralph ; 17912111Sralph ofilter = 0; 18012111Sralph } 18112463Sralph (void) close(pfd); /* close printer */ 18215811Sralph if (ftruncate(lfd, pidoff) < 0) 18316762Sralph syslog(LOG_WARNING, "%s: %s: %m", printer, LO); 18412463Sralph openpr(); /* try to reopen printer */ 18512111Sralph goto restart; 18612111Sralph } 18712111Sralph } 18812111Sralph free((char *) queue); 18912463Sralph /* 19012463Sralph * search the spool directory for more work. 19112463Sralph */ 19212463Sralph if ((nitems = getq(&queue)) < 0) { 19316762Sralph syslog(LOG_ERR, "%s: can't scan %s", printer, SD); 19412463Sralph exit(1); 19512463Sralph } 19612463Sralph if (nitems == 0) { /* no more work to do */ 19712463Sralph done: 19814150Sralph if (count > 0) { /* Files actually printed */ 19914150Sralph if (!SF && !tof) 20014150Sralph (void) write(ofd, FF, strlen(FF)); 20114150Sralph if (TR != NULL) /* output trailer */ 20214150Sralph (void) write(ofd, TR, strlen(TR)); 20314150Sralph } 20439954Smckusick (void) unlink(tempfile); 20512463Sralph exit(0); 20612463Sralph } 20712111Sralph goto again; 20812111Sralph } 20912111Sralph 21012111Sralph char fonts[4][50]; /* fonts for troff */ 21112111Sralph 21237968Sbostic char ifonts[4][40] = { 21337968Sbostic _PATH_VFONTR, 21437968Sbostic _PATH_VFONTI, 21537968Sbostic _PATH_VFONTB, 21637968Sbostic _PATH_VFONTS, 21712111Sralph }; 21812111Sralph 21912111Sralph /* 22012111Sralph * The remaining part is the reading of the control file (cf) 22112111Sralph * and performing the various actions. 22212111Sralph */ 22312111Sralph printit(file) 22412111Sralph char *file; 22512111Sralph { 22612111Sralph register int i; 22717463Sralph char *cp; 22817463Sralph int bombed = OK; 22912111Sralph 23012111Sralph /* 23117463Sralph * open control file; ignore if no longer there. 23212111Sralph */ 23312111Sralph if ((cfp = fopen(file, "r")) == NULL) { 23416762Sralph syslog(LOG_INFO, "%s: %s: %m", printer, file); 23517463Sralph return(OK); 23612111Sralph } 23712111Sralph /* 23812111Sralph * Reset troff fonts. 23912111Sralph */ 24012111Sralph for (i = 0; i < 4; i++) 24112111Sralph strcpy(fonts[i], ifonts[i]); 24217339Sralph strcpy(width+2, "0"); 24317302Sralph strcpy(indent+2, "0"); 24412111Sralph 24512111Sralph /* 24612111Sralph * read the control file for work to do 24712111Sralph * 24812111Sralph * file format -- first character in the line is a command 24912111Sralph * rest of the line is the argument. 25012111Sralph * valid commands are: 25112111Sralph * 25217463Sralph * S -- "stat info" for symbolic link protection 25312111Sralph * J -- "job name" on banner page 25412111Sralph * C -- "class name" on banner page 25512111Sralph * L -- "literal" user's name to print on banner 25612111Sralph * T -- "title" for pr 25712111Sralph * H -- "host name" of machine where lpr was done 25812111Sralph * P -- "person" user's login name 25912581Sralph * I -- "indent" amount to indent output 26012111Sralph * f -- "file name" name of text file to print 26112111Sralph * l -- "file name" text file with control chars 26212111Sralph * p -- "file name" text file to print with pr(1) 26312111Sralph * t -- "file name" troff(1) file to print 26413233Sralph * n -- "file name" ditroff(1) file to print 26512111Sralph * d -- "file name" dvi file to print 26612111Sralph * g -- "file name" plot(1G) file to print 26712111Sralph * v -- "file name" plain raster file to print 26812111Sralph * c -- "file name" cifplot file to print 26912111Sralph * 1 -- "R font file" for troff 27012111Sralph * 2 -- "I font file" for troff 27112111Sralph * 3 -- "B font file" for troff 27212111Sralph * 4 -- "S font file" for troff 27312111Sralph * N -- "name" of file (used by lpq) 27412111Sralph * U -- "unlink" name of file to remove 27512111Sralph * (after we print it. (Pass 2 only)). 27612111Sralph * M -- "mail" to user when done printing 27712111Sralph * 27812111Sralph * getline reads a line and expands tabs to blanks 27912111Sralph */ 28012111Sralph 28112111Sralph /* pass 1 */ 28212111Sralph 28312111Sralph while (getline(cfp)) 28412111Sralph switch (line[0]) { 28512111Sralph case 'H': 28614150Sralph strcpy(fromhost, line+1); 28712111Sralph if (class[0] == '\0') 28815552Sralph strncpy(class, line+1, sizeof(class)-1); 28912111Sralph continue; 29012111Sralph 29112111Sralph case 'P': 29215552Sralph strncpy(logname, line+1, sizeof(logname)-1); 29312463Sralph if (RS) { /* restricted */ 29412463Sralph if (getpwnam(logname) == (struct passwd *)0) { 29517463Sralph bombed = NOACCT; 29615811Sralph sendmail(line+1, bombed); 29712463Sralph goto pass2; 29812463Sralph } 29912463Sralph } 30012111Sralph continue; 30112111Sralph 30217463Sralph case 'S': 30317463Sralph cp = line+1; 30417463Sralph i = 0; 30517463Sralph while (*cp >= '0' && *cp <= '9') 30617463Sralph i = i * 10 + (*cp++ - '0'); 30717463Sralph fdev = i; 30817463Sralph cp++; 30917463Sralph i = 0; 31017463Sralph while (*cp >= '0' && *cp <= '9') 31117463Sralph i = i * 10 + (*cp++ - '0'); 31217463Sralph fino = i; 31317463Sralph continue; 31417463Sralph 31512111Sralph case 'J': 31612111Sralph if (line[1] != '\0') 31715552Sralph strncpy(jobname, line+1, sizeof(jobname)-1); 31812111Sralph else 31912111Sralph strcpy(jobname, " "); 32012111Sralph continue; 32112111Sralph 32212111Sralph case 'C': 32312111Sralph if (line[1] != '\0') 32415552Sralph strncpy(class, line+1, sizeof(class)-1); 32512111Sralph else if (class[0] == '\0') 32615811Sralph gethostname(class, sizeof(class)); 32712111Sralph continue; 32812111Sralph 32912111Sralph case 'T': /* header title for pr */ 33015552Sralph strncpy(title, line+1, sizeof(title)-1); 33112111Sralph continue; 33212111Sralph 33312111Sralph case 'L': /* identification line */ 33418127Sralph if (!SH && !HL) 33512111Sralph banner(line+1, jobname); 33612111Sralph continue; 33712111Sralph 33812111Sralph case '1': /* troff fonts */ 33912111Sralph case '2': 34012111Sralph case '3': 34112111Sralph case '4': 34212111Sralph if (line[1] != '\0') 34312111Sralph strcpy(fonts[line[0]-'1'], line+1); 34412111Sralph continue; 34512111Sralph 34612111Sralph case 'W': /* page width */ 34715552Sralph strncpy(width+2, line+1, sizeof(width)-3); 34812111Sralph continue; 34912111Sralph 35012581Sralph case 'I': /* indent amount */ 35115552Sralph strncpy(indent+2, line+1, sizeof(indent)-3); 35212581Sralph continue; 35312581Sralph 35412111Sralph default: /* some file to print */ 35515811Sralph switch (i = print(line[0], line+1)) { 35617463Sralph case ERROR: 35717463Sralph if (bombed == OK) 35817463Sralph bombed = FATALERR; 35915811Sralph break; 36017463Sralph case REPRINT: 36112111Sralph (void) fclose(cfp); 36217463Sralph return(REPRINT); 36317463Sralph case FILTERERR: 36417463Sralph case ACCESS: 36517463Sralph bombed = i; 36615811Sralph sendmail(logname, bombed); 36715811Sralph } 36812111Sralph title[0] = '\0'; 36912111Sralph continue; 37012111Sralph 37112111Sralph case 'N': 37212111Sralph case 'U': 37312111Sralph case 'M': 37412111Sralph continue; 37512111Sralph } 37612111Sralph 37712111Sralph /* pass 2 */ 37812111Sralph 37912463Sralph pass2: 38012111Sralph fseek(cfp, 0L, 0); 38112111Sralph while (getline(cfp)) 38212111Sralph switch (line[0]) { 38318127Sralph case 'L': /* identification line */ 38418127Sralph if (!SH && HL) 38518127Sralph banner(line+1, jobname); 38618127Sralph continue; 38718127Sralph 38812111Sralph case 'M': 38917463Sralph if (bombed < NOACCT) /* already sent if >= NOACCT */ 39015811Sralph sendmail(line+1, bombed); 39112111Sralph continue; 39212111Sralph 39312111Sralph case 'U': 39412111Sralph (void) unlink(line+1); 39512111Sralph } 39612111Sralph /* 39715811Sralph * clean-up in case another control file exists 39812111Sralph */ 39912111Sralph (void) fclose(cfp); 40012111Sralph (void) unlink(file); 40117463Sralph return(bombed == OK ? OK : ERROR); 40212111Sralph } 40312111Sralph 40412111Sralph /* 40512111Sralph * Print a file. 40613233Sralph * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}. 40715811Sralph * Return -1 if a non-recoverable error occured, 40815811Sralph * 2 if the filter detected some errors (but printed the job anyway), 40915811Sralph * 1 if we should try to reprint this job and 41012111Sralph * 0 if all is well. 41112111Sralph * Note: all filters take stdin as the file, stdout as the printer, 41212111Sralph * stderr as the log file, and must not ignore SIGINT. 41312111Sralph */ 41412111Sralph print(format, file) 41512111Sralph int format; 41612111Sralph char *file; 41712111Sralph { 41815811Sralph register int n; 41912111Sralph register char *prog; 42015811Sralph int fi, fo; 42139954Smckusick FILE *fp; 42212111Sralph char *av[15], buf[BUFSIZ]; 42312111Sralph int pid, p[2], stopped = 0; 42412111Sralph union wait status; 42517463Sralph struct stat stb; 42612111Sralph 42717463Sralph if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0) 42817463Sralph return(ERROR); 42917463Sralph /* 43017463Sralph * Check to see if data file is a symbolic link. If so, it should 43117463Sralph * still point to the same file or someone is trying to print 43217463Sralph * something he shouldn't. 43317463Sralph */ 43417463Sralph if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 && 43517463Sralph (stb.st_dev != fdev || stb.st_ino != fino)) 43617463Sralph return(ACCESS); 43712111Sralph if (!SF && !tof) { /* start on a fresh page */ 43812111Sralph (void) write(ofd, FF, strlen(FF)); 43912111Sralph tof = 1; 44012111Sralph } 44112111Sralph if (IF == NULL && (format == 'f' || format == 'l')) { 44212111Sralph tof = 0; 44312111Sralph while ((n = read(fi, buf, BUFSIZ)) > 0) 44412111Sralph if (write(ofd, buf, n) != n) { 44512111Sralph (void) close(fi); 44617463Sralph return(REPRINT); 44712111Sralph } 44812111Sralph (void) close(fi); 44917463Sralph return(OK); 45012111Sralph } 45112111Sralph switch (format) { 45212111Sralph case 'p': /* print file using 'pr' */ 45312111Sralph if (IF == NULL) { /* use output filter */ 45437968Sbostic prog = _PATH_PR; 45512111Sralph av[0] = "pr"; 45612111Sralph av[1] = width; 45712111Sralph av[2] = length; 45812111Sralph av[3] = "-h"; 45912111Sralph av[4] = *title ? title : " "; 46012111Sralph av[5] = 0; 46112111Sralph fo = ofd; 46212111Sralph goto start; 46312111Sralph } 46412111Sralph pipe(p); 46512111Sralph if ((prchild = dofork(DORETURN)) == 0) { /* child */ 46612111Sralph dup2(fi, 0); /* file is stdin */ 46712111Sralph dup2(p[1], 1); /* pipe is stdout */ 46812111Sralph for (n = 3; n < NOFILE; n++) 46912111Sralph (void) close(n); 47037968Sbostic execl(_PATH_PR, "pr", width, length, 47137968Sbostic "-h", *title ? title : " ", 0); 47237968Sbostic syslog(LOG_ERR, "cannot execl %s", _PATH_PR); 47312111Sralph exit(2); 47412111Sralph } 47512111Sralph (void) close(p[1]); /* close output side */ 47612111Sralph (void) close(fi); 47712111Sralph if (prchild < 0) { 47812111Sralph prchild = 0; 47912111Sralph (void) close(p[0]); 48017463Sralph return(ERROR); 48112111Sralph } 48212111Sralph fi = p[0]; /* use pipe for input */ 48312111Sralph case 'f': /* print plain text file */ 48412111Sralph prog = IF; 48512111Sralph av[1] = width; 48612111Sralph av[2] = length; 48712581Sralph av[3] = indent; 48812581Sralph n = 4; 48912111Sralph break; 49012111Sralph case 'l': /* like 'f' but pass control characters */ 49112111Sralph prog = IF; 49214325Sralph av[1] = "-c"; 49312111Sralph av[2] = width; 49412111Sralph av[3] = length; 49512581Sralph av[4] = indent; 49612581Sralph n = 5; 49712111Sralph break; 49812463Sralph case 'r': /* print a fortran text file */ 49912463Sralph prog = RF; 50012463Sralph av[1] = width; 50112463Sralph av[2] = length; 50212463Sralph n = 3; 50312463Sralph break; 50412111Sralph case 't': /* print troff output */ 50513233Sralph case 'n': /* print ditroff output */ 50612463Sralph case 'd': /* print tex output */ 50712111Sralph (void) unlink(".railmag"); 50812463Sralph if ((fo = creat(".railmag", FILMOD)) < 0) { 50916762Sralph syslog(LOG_ERR, "%s: cannot create .railmag", printer); 51012111Sralph (void) unlink(".railmag"); 51112111Sralph } else { 51212111Sralph for (n = 0; n < 4; n++) { 51312111Sralph if (fonts[n][0] != '/') 514*54520Sbostic (void) write(fo, _PATH_VFONT, 515*54520Sbostic sizeof(_PATH_VFONT) - 1); 51612111Sralph (void) write(fo, fonts[n], strlen(fonts[n])); 51712111Sralph (void) write(fo, "\n", 1); 51812111Sralph } 51912111Sralph (void) close(fo); 52012111Sralph } 52113233Sralph prog = (format == 't') ? TF : (format == 'n') ? NF : DF; 52212463Sralph av[1] = pxwidth; 52312463Sralph av[2] = pxlength; 52412463Sralph n = 3; 52512111Sralph break; 52612111Sralph case 'c': /* print cifplot output */ 52712111Sralph prog = CF; 52812463Sralph av[1] = pxwidth; 52912463Sralph av[2] = pxlength; 53012463Sralph n = 3; 53112111Sralph break; 53212111Sralph case 'g': /* print plot(1G) output */ 53312111Sralph prog = GF; 53412463Sralph av[1] = pxwidth; 53512463Sralph av[2] = pxlength; 53612463Sralph n = 3; 53712111Sralph break; 53812111Sralph case 'v': /* print raster output */ 53912111Sralph prog = VF; 54012463Sralph av[1] = pxwidth; 54112463Sralph av[2] = pxlength; 54212463Sralph n = 3; 54312111Sralph break; 54412111Sralph default: 54512111Sralph (void) close(fi); 54616762Sralph syslog(LOG_ERR, "%s: illegal format character '%c'", 54716762Sralph printer, format); 54817463Sralph return(ERROR); 54912111Sralph } 55012111Sralph if ((av[0] = rindex(prog, '/')) != NULL) 55112111Sralph av[0]++; 55212111Sralph else 55312111Sralph av[0] = prog; 55412111Sralph av[n++] = "-n"; 55512111Sralph av[n++] = logname; 55612111Sralph av[n++] = "-h"; 55714150Sralph av[n++] = fromhost; 55812111Sralph av[n++] = AF; 55912111Sralph av[n] = 0; 56012111Sralph fo = pfd; 56112111Sralph if (ofilter > 0) { /* stop output filter */ 56212111Sralph write(ofd, "\031\1", 2); 56346912Sbostic while ((pid = 56446912Sbostic wait3((int *)&status, WUNTRACED, 0)) > 0 && pid != ofilter) 56512111Sralph ; 56612111Sralph if (status.w_stopval != WSTOPPED) { 56712111Sralph (void) close(fi); 56816762Sralph syslog(LOG_WARNING, "%s: output filter died (%d)", 56916762Sralph printer, status.w_retcode); 57017463Sralph return(REPRINT); 57112111Sralph } 57212111Sralph stopped++; 57312111Sralph } 57412111Sralph start: 57512111Sralph if ((child = dofork(DORETURN)) == 0) { /* child */ 57612111Sralph dup2(fi, 0); 57712111Sralph dup2(fo, 1); 57839954Smckusick n = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, 0664); 57915811Sralph if (n >= 0) 58015811Sralph dup2(n, 2); 58112111Sralph for (n = 3; n < NOFILE; n++) 58212111Sralph (void) close(n); 58312111Sralph execv(prog, av); 58416762Sralph syslog(LOG_ERR, "cannot execv %s", prog); 58512111Sralph exit(2); 58612111Sralph } 58712111Sralph (void) close(fi); 58812111Sralph if (child < 0) 58912111Sralph status.w_retcode = 100; 59012111Sralph else 59146912Sbostic while ((pid = wait((int *)&status)) > 0 && pid != child) 59212111Sralph ; 59312111Sralph child = 0; 59412111Sralph prchild = 0; 59512111Sralph if (stopped) { /* restart output filter */ 59612111Sralph if (kill(ofilter, SIGCONT) < 0) { 59716762Sralph syslog(LOG_ERR, "cannot restart output filter"); 59812111Sralph exit(1); 59912111Sralph } 60012111Sralph } 60112111Sralph tof = 0; 60239954Smckusick 60339954Smckusick /* Copy filter output to "lf" logfile */ 60439954Smckusick if (fp = fopen(tempfile, "r")) { 60539954Smckusick char tbuf[512]; 60639954Smckusick 60739954Smckusick while (fgets(buf, sizeof(buf), fp)) 60839954Smckusick fputs(buf, stderr); 60939954Smckusick close(fp); 61039954Smckusick } 61139954Smckusick 61215811Sralph if (!WIFEXITED(status)) { 61316762Sralph syslog(LOG_WARNING, "%s: Daemon filter '%c' terminated (%d)", 61416762Sralph printer, format, status.w_termsig); 61517463Sralph return(ERROR); 61617463Sralph } 61717463Sralph switch (status.w_retcode) { 61817463Sralph case 0: 61917463Sralph tof = 1; 62017463Sralph return(OK); 62117463Sralph case 1: 62217463Sralph return(REPRINT); 62317463Sralph default: 62416762Sralph syslog(LOG_WARNING, "%s: Daemon filter '%c' exited (%d)", 62516762Sralph printer, format, status.w_retcode); 62617463Sralph case 2: 62717463Sralph return(ERROR); 62817463Sralph } 62912111Sralph } 63012111Sralph 63112111Sralph /* 63212111Sralph * Send the daemon control file (cf) and any data files. 63312111Sralph * Return -1 if a non-recoverable error occured, 1 if a recoverable error and 63412111Sralph * 0 if all is well. 63512111Sralph */ 63612111Sralph sendit(file) 63712111Sralph char *file; 63812111Sralph { 63917463Sralph register int i, err = OK; 64017463Sralph char *cp, last[BUFSIZ]; 64112111Sralph 64212111Sralph /* 64312111Sralph * open control file 64412111Sralph */ 64516762Sralph if ((cfp = fopen(file, "r")) == NULL) 64617463Sralph return(OK); 64712111Sralph /* 64812111Sralph * read the control file for work to do 64912111Sralph * 65012111Sralph * file format -- first character in the line is a command 65112111Sralph * rest of the line is the argument. 65212111Sralph * commands of interest are: 65312111Sralph * 65412111Sralph * a-z -- "file name" name of file to print 65512111Sralph * U -- "unlink" name of file to remove 65612111Sralph * (after we print it. (Pass 2 only)). 65712111Sralph */ 65812111Sralph 65912111Sralph /* 66012111Sralph * pass 1 66112111Sralph */ 66212111Sralph while (getline(cfp)) { 66312111Sralph again: 66417463Sralph if (line[0] == 'S') { 66517463Sralph cp = line+1; 66617463Sralph i = 0; 66717463Sralph while (*cp >= '0' && *cp <= '9') 66817463Sralph i = i * 10 + (*cp++ - '0'); 66917463Sralph fdev = i; 67017463Sralph cp++; 67117463Sralph i = 0; 67217463Sralph while (*cp >= '0' && *cp <= '9') 67317463Sralph i = i * 10 + (*cp++ - '0'); 67417463Sralph fino = i; 67517463Sralph continue; 67617463Sralph } 67712111Sralph if (line[0] >= 'a' && line[0] <= 'z') { 67812111Sralph strcpy(last, line); 67917463Sralph while (i = getline(cfp)) 68012111Sralph if (strcmp(last, line)) 68112111Sralph break; 68217463Sralph switch (sendfile('\3', last+1)) { 68317463Sralph case OK: 68417463Sralph if (i) 68517463Sralph goto again; 68617463Sralph break; 68717463Sralph case REPRINT: 68812111Sralph (void) fclose(cfp); 68917463Sralph return(REPRINT); 69017463Sralph case ACCESS: 69117463Sralph sendmail(logname, ACCESS); 69217463Sralph case ERROR: 69317463Sralph err = ERROR; 69417463Sralph } 69512111Sralph break; 69612111Sralph } 69712111Sralph } 69817463Sralph if (err == OK && sendfile('\2', file) > 0) { 69912111Sralph (void) fclose(cfp); 70017463Sralph return(REPRINT); 70112111Sralph } 70212111Sralph /* 70312111Sralph * pass 2 70412111Sralph */ 70512111Sralph fseek(cfp, 0L, 0); 70612111Sralph while (getline(cfp)) 70712111Sralph if (line[0] == 'U') 70812111Sralph (void) unlink(line+1); 70912111Sralph /* 71017463Sralph * clean-up in case another control file exists 71112111Sralph */ 71212111Sralph (void) fclose(cfp); 71312111Sralph (void) unlink(file); 71417463Sralph return(err); 71512111Sralph } 71612111Sralph 71712111Sralph /* 71812111Sralph * Send a data file to the remote machine and spool it. 71912111Sralph * Return positive if we should try resending. 72012111Sralph */ 72112111Sralph sendfile(type, file) 72212111Sralph char type, *file; 72312111Sralph { 72412111Sralph register int f, i, amt; 72512111Sralph struct stat stb; 72612111Sralph char buf[BUFSIZ]; 72716762Sralph int sizerr, resp; 72812111Sralph 72917463Sralph if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0) 73017463Sralph return(ERROR); 73117463Sralph /* 73217463Sralph * Check to see if data file is a symbolic link. If so, it should 73317463Sralph * still point to the same file or someone is trying to print something 73417463Sralph * he shouldn't. 73517463Sralph */ 73617463Sralph if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 && 73717463Sralph (stb.st_dev != fdev || stb.st_ino != fino)) 73817463Sralph return(ACCESS); 73912111Sralph (void) sprintf(buf, "%c%d %s\n", type, stb.st_size, file); 74012111Sralph amt = strlen(buf); 74116762Sralph for (i = 0; ; i++) { 74216762Sralph if (write(pfd, buf, amt) != amt || 74316762Sralph (resp = response()) < 0 || resp == '\1') { 74416762Sralph (void) close(f); 74517463Sralph return(REPRINT); 74616762Sralph } else if (resp == '\0') 74716762Sralph break; 74816762Sralph if (i == 0) 74916762Sralph status("no space on remote; waiting for queue to drain"); 75016762Sralph if (i == 10) 75124861Seric syslog(LOG_ALERT, "%s: can't send to %s; queue full", 75216762Sralph printer, RM); 75316762Sralph sleep(5 * 60); 75412692Sralph } 75516762Sralph if (i) 75616762Sralph status("sending to %s", RM); 75712111Sralph sizerr = 0; 75812111Sralph for (i = 0; i < stb.st_size; i += BUFSIZ) { 75912111Sralph amt = BUFSIZ; 76012111Sralph if (i + amt > stb.st_size) 76112111Sralph amt = stb.st_size - i; 76212111Sralph if (sizerr == 0 && read(f, buf, amt) != amt) 76312111Sralph sizerr = 1; 76412692Sralph if (write(pfd, buf, amt) != amt) { 76512692Sralph (void) close(f); 76617463Sralph return(REPRINT); 76712692Sralph } 76812111Sralph } 76912111Sralph (void) close(f); 77012111Sralph if (sizerr) { 77116762Sralph syslog(LOG_INFO, "%s: %s: changed size", printer, file); 77217463Sralph /* tell recvjob to ignore this file */ 77317463Sralph (void) write(pfd, "\1", 1); 77417463Sralph return(ERROR); 77517463Sralph } 77617463Sralph if (write(pfd, "", 1) != 1 || response()) 77717463Sralph return(REPRINT); 77817463Sralph return(OK); 77912111Sralph } 78012111Sralph 78112111Sralph /* 78212111Sralph * Check to make sure there have been no errors and that both programs 78312111Sralph * are in sync with eachother. 78412111Sralph * Return non-zero if the connection was lost. 78512111Sralph */ 78616762Sralph response() 78712111Sralph { 78812111Sralph char resp; 78912111Sralph 79016762Sralph if (read(pfd, &resp, 1) != 1) { 79116762Sralph syslog(LOG_INFO, "%s: lost connection", printer); 79216762Sralph return(-1); 79312111Sralph } 79416762Sralph return(resp); 79512111Sralph } 79612111Sralph 79712111Sralph /* 79812111Sralph * Banner printing stuff 79912111Sralph */ 80012111Sralph banner(name1, name2) 80112111Sralph char *name1, *name2; 80212111Sralph { 80312111Sralph time_t tvec; 80412111Sralph extern char *ctime(); 80512111Sralph 80612111Sralph time(&tvec); 80712111Sralph if (!SF && !tof) 80812111Sralph (void) write(ofd, FF, strlen(FF)); 80912111Sralph if (SB) { /* short banner only */ 81012111Sralph if (class[0]) { 81112111Sralph (void) write(ofd, class, strlen(class)); 81212111Sralph (void) write(ofd, ":", 1); 81312111Sralph } 81412111Sralph (void) write(ofd, name1, strlen(name1)); 81512111Sralph (void) write(ofd, " Job: ", 7); 81612111Sralph (void) write(ofd, name2, strlen(name2)); 81712111Sralph (void) write(ofd, " Date: ", 8); 81812111Sralph (void) write(ofd, ctime(&tvec), 24); 81912111Sralph (void) write(ofd, "\n", 1); 82012111Sralph } else { /* normal banner */ 82112111Sralph (void) write(ofd, "\n\n\n", 3); 82212111Sralph scan_out(ofd, name1, '\0'); 82312111Sralph (void) write(ofd, "\n\n", 2); 82412111Sralph scan_out(ofd, name2, '\0'); 82512111Sralph if (class[0]) { 82612111Sralph (void) write(ofd,"\n\n\n",3); 82712111Sralph scan_out(ofd, class, '\0'); 82812111Sralph } 82912111Sralph (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15); 83012111Sralph (void) write(ofd, name2, strlen(name2)); 83112111Sralph (void) write(ofd, "\n\t\t\t\t\tDate: ", 12); 83212111Sralph (void) write(ofd, ctime(&tvec), 24); 83312111Sralph (void) write(ofd, "\n", 1); 83412111Sralph } 83512111Sralph if (!SF) 83612111Sralph (void) write(ofd, FF, strlen(FF)); 83712111Sralph tof = 1; 83812111Sralph } 83912111Sralph 84016762Sralph char * 84112111Sralph scnline(key, p, c) 84212111Sralph register char key, *p; 84312111Sralph char c; 84412111Sralph { 84512111Sralph register scnwidth; 84612111Sralph 84712111Sralph for (scnwidth = WIDTH; --scnwidth;) { 84812111Sralph key <<= 1; 84912111Sralph *p++ = key & 0200 ? c : BACKGND; 85012111Sralph } 85112111Sralph return (p); 85212111Sralph } 85312111Sralph 85412111Sralph #define TRC(q) (((q)-' ')&0177) 85512111Sralph 85612111Sralph scan_out(scfd, scsp, dlm) 85712111Sralph int scfd; 85812111Sralph char *scsp, dlm; 85912111Sralph { 86012111Sralph register char *strp; 86112111Sralph register nchrs, j; 86212111Sralph char outbuf[LINELEN+1], *sp, c, cc; 86312111Sralph int d, scnhgt; 86412111Sralph extern char scnkey[][HEIGHT]; /* in lpdchar.c */ 86512111Sralph 86612111Sralph for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) { 86712111Sralph strp = &outbuf[0]; 86812111Sralph sp = scsp; 86912111Sralph for (nchrs = 0; ; ) { 87012111Sralph d = dropit(c = TRC(cc = *sp++)); 87112111Sralph if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d)) 87212111Sralph for (j = WIDTH; --j;) 87312111Sralph *strp++ = BACKGND; 87412111Sralph else 87512111Sralph strp = scnline(scnkey[c][scnhgt-1-d], strp, cc); 87612111Sralph if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1) 87712111Sralph break; 87812111Sralph *strp++ = BACKGND; 87912111Sralph *strp++ = BACKGND; 88012111Sralph } 88112111Sralph while (*--strp == BACKGND && strp >= outbuf) 88212111Sralph ; 88312111Sralph strp++; 88412111Sralph *strp++ = '\n'; 88512111Sralph (void) write(scfd, outbuf, strp-outbuf); 88612111Sralph } 88712111Sralph } 88812111Sralph 88912111Sralph dropit(c) 89012111Sralph char c; 89112111Sralph { 89212111Sralph switch(c) { 89312111Sralph 89412111Sralph case TRC('_'): 89512111Sralph case TRC(';'): 89612111Sralph case TRC(','): 89712111Sralph case TRC('g'): 89812111Sralph case TRC('j'): 89912111Sralph case TRC('p'): 90012111Sralph case TRC('q'): 90112111Sralph case TRC('y'): 90212111Sralph return (DROP); 90312111Sralph 90412111Sralph default: 90512111Sralph return (0); 90612111Sralph } 90712111Sralph } 90812111Sralph 90912111Sralph /* 91012111Sralph * sendmail --- 91112111Sralph * tell people about job completion 91212111Sralph */ 91315811Sralph sendmail(user, bombed) 91415811Sralph char *user; 91512111Sralph int bombed; 91612111Sralph { 91712111Sralph register int i; 91815811Sralph int p[2], s; 91912111Sralph register char *cp; 92012111Sralph char buf[100]; 92115811Sralph struct stat stb; 92215811Sralph FILE *fp; 92312111Sralph 92412111Sralph pipe(p); 92515811Sralph if ((s = dofork(DORETURN)) == 0) { /* child */ 92612111Sralph dup2(p[0], 0); 92712111Sralph for (i = 3; i < NOFILE; i++) 92812111Sralph (void) close(i); 92937968Sbostic if ((cp = rindex(_PATH_SENDMAIL, '/')) != NULL) 93012111Sralph cp++; 93112111Sralph else 93237968Sbostic cp = _PATH_SENDMAIL; 93315811Sralph sprintf(buf, "%s@%s", user, fromhost); 93437968Sbostic execl(_PATH_SENDMAIL, cp, buf, 0); 93512111Sralph exit(0); 93615811Sralph } else if (s > 0) { /* parent */ 93712111Sralph dup2(p[1], 1); 93815811Sralph printf("To: %s@%s\n", user, fromhost); 93912111Sralph printf("Subject: printer job\n\n"); 94012111Sralph printf("Your printer job "); 94112111Sralph if (*jobname) 94212111Sralph printf("(%s) ", jobname); 94312463Sralph switch (bombed) { 94417463Sralph case OK: 94512463Sralph printf("\ncompleted successfully\n"); 94612463Sralph break; 94712463Sralph default: 94817463Sralph case FATALERR: 94912463Sralph printf("\ncould not be printed\n"); 95012463Sralph break; 95117463Sralph case NOACCT: 95212463Sralph printf("\ncould not be printed without an account on %s\n", host); 95312463Sralph break; 95417463Sralph case FILTERERR: 95539954Smckusick if (stat(tempfile, &stb) < 0 || stb.st_size == 0 || 95639954Smckusick (fp = fopen(tempfile, "r")) == NULL) { 95715811Sralph printf("\nwas printed but had some errors\n"); 95815811Sralph break; 95915811Sralph } 96015811Sralph printf("\nwas printed but had the following errors:\n"); 96115811Sralph while ((i = getc(fp)) != EOF) 96215811Sralph putchar(i); 96315811Sralph (void) fclose(fp); 96417463Sralph break; 96517463Sralph case ACCESS: 96617463Sralph printf("\nwas not printed because it was not linked to the original file\n"); 96712463Sralph } 96812111Sralph fflush(stdout); 96912111Sralph (void) close(1); 97012111Sralph } 97112111Sralph (void) close(p[0]); 97212111Sralph (void) close(p[1]); 97315811Sralph wait(&s); 97412111Sralph } 97512111Sralph 97612111Sralph /* 97712111Sralph * dofork - fork with retries on failure 97812111Sralph */ 97912111Sralph dofork(action) 98012111Sralph int action; 98112111Sralph { 98212111Sralph register int i, pid; 98312111Sralph 98412111Sralph for (i = 0; i < 20; i++) { 98512463Sralph if ((pid = fork()) < 0) { 98612111Sralph sleep((unsigned)(i*i)); 98712463Sralph continue; 98812463Sralph } 98912463Sralph /* 99012463Sralph * Child should run as daemon instead of root 99112463Sralph */ 99212463Sralph if (pid == 0) 99312463Sralph setuid(DU); 99412463Sralph return(pid); 99512111Sralph } 99616762Sralph syslog(LOG_ERR, "can't fork"); 99712111Sralph 99812111Sralph switch (action) { 99912111Sralph case DORETURN: 100012111Sralph return (-1); 100112111Sralph default: 100216762Sralph syslog(LOG_ERR, "bad action (%d) to dofork", action); 100312111Sralph /*FALL THRU*/ 100412111Sralph case DOABORT: 100512111Sralph exit(1); 100612111Sralph } 100712111Sralph /*NOTREACHED*/ 100812111Sralph } 100912111Sralph 101012111Sralph /* 101116762Sralph * Kill child processes to abort current job. 101212111Sralph */ 101346912Sbostic void 101416762Sralph abortpr() 101512111Sralph { 101639954Smckusick (void) unlink(tempfile); 101712111Sralph kill(0, SIGINT); 101812111Sralph if (ofilter > 0) 101912111Sralph kill(ofilter, SIGCONT); 102046912Sbostic while (wait(NULL) > 0) 102112111Sralph ; 102212111Sralph exit(0); 102312111Sralph } 102412111Sralph 102512111Sralph init() 102612111Sralph { 102712111Sralph int status; 102838736Stef char *s; 102912111Sralph 103025468Stef if ((status = pgetent(line, printer)) < 0) { 103125468Stef syslog(LOG_ERR, "can't open printer description file"); 103225468Stef exit(1); 103325468Stef } else if (status == 0) { 103425468Stef syslog(LOG_ERR, "unknown printer: %s", printer); 103525468Stef exit(1); 103625468Stef } 103712111Sralph if ((LP = pgetstr("lp", &bp)) == NULL) 103837968Sbostic LP = _PATH_DEFDEVLP; 103912111Sralph if ((RP = pgetstr("rp", &bp)) == NULL) 104012463Sralph RP = DEFLP; 104112111Sralph if ((LO = pgetstr("lo", &bp)) == NULL) 104212111Sralph LO = DEFLOCK; 104312111Sralph if ((ST = pgetstr("st", &bp)) == NULL) 104412111Sralph ST = DEFSTAT; 104512111Sralph if ((LF = pgetstr("lf", &bp)) == NULL) 104637968Sbostic LF = _PATH_CONSOLE; 104712111Sralph if ((SD = pgetstr("sd", &bp)) == NULL) 104837968Sbostic SD = _PATH_DEFSPOOL; 104912111Sralph if ((DU = pgetnum("du")) < 0) 105012111Sralph DU = DEFUID; 105112111Sralph if ((FF = pgetstr("ff", &bp)) == NULL) 105212111Sralph FF = DEFFF; 105312111Sralph if ((PW = pgetnum("pw")) < 0) 105412111Sralph PW = DEFWIDTH; 105512111Sralph sprintf(&width[2], "%d", PW); 105612111Sralph if ((PL = pgetnum("pl")) < 0) 105712111Sralph PL = DEFLENGTH; 105812111Sralph sprintf(&length[2], "%d", PL); 105912463Sralph if ((PX = pgetnum("px")) < 0) 106012463Sralph PX = 0; 106112463Sralph sprintf(&pxwidth[2], "%d", PX); 106212463Sralph if ((PY = pgetnum("py")) < 0) 106312463Sralph PY = 0; 106412463Sralph sprintf(&pxlength[2], "%d", PY); 106512111Sralph RM = pgetstr("rm", &bp); 106638736Stef if (s = checkremote()) 106738736Stef syslog(LOG_WARNING, s); 106825468Stef 106912111Sralph AF = pgetstr("af", &bp); 107012111Sralph OF = pgetstr("of", &bp); 107112111Sralph IF = pgetstr("if", &bp); 107212463Sralph RF = pgetstr("rf", &bp); 107312111Sralph TF = pgetstr("tf", &bp); 107413233Sralph NF = pgetstr("nf", &bp); 107512111Sralph DF = pgetstr("df", &bp); 107612111Sralph GF = pgetstr("gf", &bp); 107712111Sralph VF = pgetstr("vf", &bp); 107812111Sralph CF = pgetstr("cf", &bp); 107912111Sralph TR = pgetstr("tr", &bp); 108012463Sralph RS = pgetflag("rs"); 108112111Sralph SF = pgetflag("sf"); 108212111Sralph SH = pgetflag("sh"); 108312111Sralph SB = pgetflag("sb"); 108418127Sralph HL = pgetflag("hl"); 108512111Sralph RW = pgetflag("rw"); 108612111Sralph BR = pgetnum("br"); 108712111Sralph if ((FC = pgetnum("fc")) < 0) 108812111Sralph FC = 0; 108912111Sralph if ((FS = pgetnum("fs")) < 0) 109012111Sralph FS = 0; 109112111Sralph if ((XC = pgetnum("xc")) < 0) 109212111Sralph XC = 0; 109312111Sralph if ((XS = pgetnum("xs")) < 0) 109412111Sralph XS = 0; 109512581Sralph tof = !pgetflag("fo"); 109612111Sralph } 109712111Sralph 109812463Sralph /* 109912463Sralph * Acquire line printer or remote connection. 110012463Sralph */ 110112463Sralph openpr() 110212463Sralph { 110312463Sralph register int i, n; 110416762Sralph int resp; 110512463Sralph 110638736Stef if (!sendtorem && *LP) { 110712463Sralph for (i = 1; ; i = i < 32 ? i << 1 : i) { 110813148Ssam pfd = open(LP, RW ? O_RDWR : O_WRONLY); 110912463Sralph if (pfd >= 0) 111012463Sralph break; 111112463Sralph if (errno == ENOENT) { 111216762Sralph syslog(LOG_ERR, "%s: %m", LP); 111312463Sralph exit(1); 111412463Sralph } 111512463Sralph if (i == 1) 111612463Sralph status("waiting for %s to become ready (offline ?)", printer); 111712463Sralph sleep(i); 111812463Sralph } 111912463Sralph if (isatty(pfd)) 112012463Sralph setty(); 112112463Sralph status("%s is ready and printing", printer); 112212463Sralph } else if (RM != NULL) { 112316762Sralph for (i = 1; ; i = i < 256 ? i << 1 : i) { 112416762Sralph resp = -1; 112512528Sralph pfd = getport(RM); 112612463Sralph if (pfd >= 0) { 112712463Sralph (void) sprintf(line, "\2%s\n", RP); 112812463Sralph n = strlen(line); 112916762Sralph if (write(pfd, line, n) == n && 113016762Sralph (resp = response()) == '\0') 113112463Sralph break; 113216031Sralph (void) close(pfd); 113312463Sralph } 113416031Sralph if (i == 1) { 113516762Sralph if (resp < 0) 113616031Sralph status("waiting for %s to come up", RM); 113716762Sralph else { 113816031Sralph status("waiting for queue to be enabled on %s", RM); 113916762Sralph i = 256; 114016762Sralph } 114116031Sralph } 114212463Sralph sleep(i); 114312463Sralph } 114412463Sralph status("sending to %s", RM); 114512463Sralph remote = 1; 114612463Sralph } else { 114716762Sralph syslog(LOG_ERR, "%s: no line printer device or host name", 114816762Sralph printer); 114912463Sralph exit(1); 115012463Sralph } 115112463Sralph /* 115212463Sralph * Start up an output filter, if needed. 115312463Sralph */ 115440049Stef if (!remote && OF) { 115512463Sralph int p[2]; 115612463Sralph char *cp; 115712463Sralph 115812463Sralph pipe(p); 115912463Sralph if ((ofilter = dofork(DOABORT)) == 0) { /* child */ 116012463Sralph dup2(p[0], 0); /* pipe is std in */ 116112463Sralph dup2(pfd, 1); /* printer is std out */ 116212463Sralph for (i = 3; i < NOFILE; i++) 116312463Sralph (void) close(i); 116412463Sralph if ((cp = rindex(OF, '/')) == NULL) 116512463Sralph cp = OF; 116612463Sralph else 116712463Sralph cp++; 116812463Sralph execl(OF, cp, width, length, 0); 116916762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, OF); 117012463Sralph exit(1); 117112463Sralph } 117212463Sralph (void) close(p[0]); /* close input side */ 117312463Sralph ofd = p[1]; /* use pipe for output */ 117412463Sralph } else { 117512463Sralph ofd = pfd; 117612463Sralph ofilter = 0; 117712463Sralph } 117812463Sralph } 117912463Sralph 118012111Sralph struct bauds { 118112111Sralph int baud; 118212111Sralph int speed; 118312111Sralph } bauds[] = { 118412111Sralph 50, B50, 118512111Sralph 75, B75, 118612111Sralph 110, B110, 118712111Sralph 134, B134, 118812111Sralph 150, B150, 118912111Sralph 200, B200, 119012111Sralph 300, B300, 119112111Sralph 600, B600, 119212111Sralph 1200, B1200, 119312111Sralph 1800, B1800, 119412111Sralph 2400, B2400, 119512111Sralph 4800, B4800, 119612111Sralph 9600, B9600, 119712111Sralph 19200, EXTA, 119812111Sralph 38400, EXTB, 119912111Sralph 0, 0 120012111Sralph }; 120112111Sralph 120212111Sralph /* 120312111Sralph * setup tty lines. 120412111Sralph */ 120512111Sralph setty() 120612111Sralph { 120712111Sralph struct sgttyb ttybuf; 120812111Sralph register struct bauds *bp; 120912111Sralph 121012111Sralph if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) { 121116762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer); 121212111Sralph exit(1); 121312111Sralph } 121412111Sralph if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) { 121516762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCGETP): %m", printer); 121612111Sralph exit(1); 121712111Sralph } 121812111Sralph if (BR > 0) { 121912111Sralph for (bp = bauds; bp->baud; bp++) 122012111Sralph if (BR == bp->baud) 122112111Sralph break; 122212111Sralph if (!bp->baud) { 122316762Sralph syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR); 122412111Sralph exit(1); 122512111Sralph } 122612111Sralph ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed; 122712111Sralph } 122813169Sralph ttybuf.sg_flags &= ~FC; 122913169Sralph ttybuf.sg_flags |= FS; 123012111Sralph if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) { 123116762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCSETP): %m", printer); 123212111Sralph exit(1); 123312111Sralph } 123412111Sralph if (XC) { 123512111Sralph if (ioctl(pfd, TIOCLBIC, &XC) < 0) { 123616762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCLBIC): %m", printer); 123712111Sralph exit(1); 123812111Sralph } 123912111Sralph } 124012111Sralph if (XS) { 124112111Sralph if (ioctl(pfd, TIOCLBIS, &XS) < 0) { 124216762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCLBIS): %m", printer); 124312111Sralph exit(1); 124412111Sralph } 124512111Sralph } 124612111Sralph } 124712463Sralph 124812463Sralph /*VARARGS1*/ 124912463Sralph status(msg, a1, a2, a3) 125012463Sralph char *msg; 125112463Sralph { 125212463Sralph register int fd; 125312463Sralph char buf[BUFSIZ]; 125412463Sralph 125512463Sralph umask(0); 125613148Ssam fd = open(ST, O_WRONLY|O_CREAT, 0664); 125716762Sralph if (fd < 0 || flock(fd, LOCK_EX) < 0) { 125816762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, ST); 125916762Sralph exit(1); 126016762Sralph } 126113148Ssam ftruncate(fd, 0); 126212463Sralph sprintf(buf, msg, a1, a2, a3); 126312463Sralph strcat(buf, "\n"); 126412463Sralph (void) write(fd, buf, strlen(buf)); 126512463Sralph (void) close(fd); 126612463Sralph } 1267