122437Sdist /* 222437Sdist * Copyright (c) 1983 Regents of the University of California. 334203Sbostic * All rights reserved. 434203Sbostic * 5*56123Selan * Redistribution and use in source and binary forms, with or without 6*56123Selan * modification, are permitted provided that the following conditions 7*56123Selan * are met: 8*56123Selan * 1. Redistributions of source code must retain the above copyright 9*56123Selan * notice, this list of conditions and the following disclaimer. 10*56123Selan * 2. Redistributions in binary form must reproduce the above copyright 11*56123Selan * notice, this list of conditions and the following disclaimer in the 12*56123Selan * documentation and/or other materials provided with the distribution. 13*56123Selan * 3. All advertising materials mentioning features or use of this software 14*56123Selan * must display the following acknowledgement: 15*56123Selan * This product includes software developed by the University of 16*56123Selan * California, Berkeley and its contributors. 17*56123Selan * 4. Neither the name of the University nor the names of its contributors 18*56123Selan * may be used to endorse or promote products derived from this software 19*56123Selan * without specific prior written permission. 20*56123Selan * 21*56123Selan * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22*56123Selan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23*56123Selan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24*56123Selan * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25*56123Selan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26*56123Selan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27*56123Selan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28*56123Selan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29*56123Selan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30*56123Selan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31*56123Selan * SUCH DAMAGE. 3222437Sdist */ 3322437Sdist 3413954Ssam #ifndef lint 35*56123Selan static char sccsid[] = "@(#)printjob.c 5.16 (Berkeley) 8/6/92"; 3634203Sbostic #endif /* not lint */ 3713954Ssam 3812111Sralph /* 3912111Sralph * printjob -- print jobs in the queue. 4012111Sralph * 4112111Sralph * NOTE: the lock file is used to pass information to lpq and lprm. 4212111Sralph * it does not need to be removed because file locks are dynamic. 4312111Sralph */ 4412111Sralph 4555474Sbostic #include <sys/param.h> 4655474Sbostic #include <sys/wait.h> 4755474Sbostic #include <sys/stat.h> 48*56123Selan #include <sys/types.h> 4955474Sbostic 50*56123Selan #include <pwd.h> 51*56123Selan #include <unistd.h> 5255474Sbostic #include <signal.h> 5355474Sbostic #include <sgtty.h> 5455474Sbostic #include <syslog.h> 5555474Sbostic #include <fcntl.h> 5655474Sbostic #include <dirent.h> 5755474Sbostic #include <errno.h> 5855474Sbostic #include <stdio.h> 5955474Sbostic #include <string.h> 60*56123Selan #include <stdlib.h> 6112111Sralph #include "lp.h" 6255474Sbostic #include "lp.local.h" 6337968Sbostic #include "pathnames.h" 6455474Sbostic #include "extern.h" 6512111Sralph 6616762Sralph #define DORETURN 0 /* absorb fork error */ 6716762Sralph #define DOABORT 1 /* abort if dofork fails */ 6812111Sralph 6917463Sralph /* 7017463Sralph * Error tokens 7117463Sralph */ 7217463Sralph #define REPRINT -2 7317463Sralph #define ERROR -1 7417463Sralph #define OK 0 7517463Sralph #define FATALERR 1 7617463Sralph #define NOACCT 2 7717463Sralph #define FILTERERR 3 7817463Sralph #define ACCESS 4 7917463Sralph 80*56123Selan static dev_t fdev; /* device of file pointed to by symlink */ 81*56123Selan static ino_t fino; /* inode of file pointed to by symlink */ 82*56123Selan static FILE *cfp; /* control file */ 83*56123Selan static int child; /* id of any filters */ 84*56123Selan static int lfd; /* lock file descriptor */ 85*56123Selan static int ofd; /* output filter file descriptor */ 86*56123Selan static int ofilter; /* id of output filter, if any */ 87*56123Selan static int pfd; /* prstatic inter file descriptor */ 88*56123Selan static int pid; /* pid of lpd process */ 89*56123Selan static int prchild; /* id of pr process */ 90*56123Selan static int remote; /* true if sending files to remote */ 91*56123Selan static char title[80]; /* ``pr'' title */ 92*56123Selan static int tof; /* true if at top of form */ 9312111Sralph 94*56123Selan static char class[32]; /* classification field */ 95*56123Selan static char fromhost[32]; /* user's host machine */ 96*56123Selan /* indentation size in static characters */ 97*56123Selan static char indent[10] = "-i0"; 98*56123Selan static char jobname[100]; /* job or file name */ 99*56123Selan static char length[10] = "-l"; /* page length in lines */ 100*56123Selan static char logname[32]; /* user's login name */ 101*56123Selan static char pxlength[10] = "-y"; /* page length in pixels */ 102*56123Selan static char pxwidth[10] = "-x"; /* page width in pixels */ 103*56123Selan static char tempfile[] = "errsXXXXXX"; /* file name for filter output */ 104*56123Selan static char width[10] = "-w"; /* page width in static characters */ 10512111Sralph 10655474Sbostic static void abortpr __P((int)); 10755474Sbostic static void banner __P((char *, char *)); 10855474Sbostic static int dofork __P((int)); 10955474Sbostic static int dropit __P((int)); 11055474Sbostic static void init __P((void)); 11155474Sbostic static void openpr __P((void)); 11255474Sbostic static int print __P((int, char *)); 11355474Sbostic static int printit __P((char *)); 11455474Sbostic static void pstatus __P((const char *, ...)); 11555474Sbostic static char response __P((void)); 11655474Sbostic static void scan_out __P((int, char *, int)); 11755474Sbostic static char *scnline __P((int, char *, int)); 11855474Sbostic static int sendfile __P((int, char *)); 11955474Sbostic static int sendit __P((char *)); 12055474Sbostic static void sendmail __P((char *, int)); 12155474Sbostic static void setty __P((void)); 12255474Sbostic 12355474Sbostic void 12412111Sralph printjob() 12512111Sralph { 12612111Sralph struct stat stb; 12712111Sralph register struct queue *q, **qp; 12812111Sralph struct queue **queue; 12912111Sralph register int i, nitems; 13012111Sralph long pidoff; 13116762Sralph int count = 0; 13212111Sralph 13312111Sralph init(); /* set up capabilities */ 13413442Sralph (void) write(1, "", 1); /* ack that daemon is started */ 13525496Seric (void) close(2); /* set up log file */ 13625496Seric if (open(LF, O_WRONLY|O_APPEND, 0664) < 0) { 13725496Seric syslog(LOG_ERR, "%s: %m", LF); 13837968Sbostic (void) open(_PATH_DEVNULL, O_WRONLY); 13925496Seric } 14016762Sralph setgid(getegid()); 14112463Sralph pid = getpid(); /* for use with lprm */ 14212111Sralph setpgrp(0, pid); 14316762Sralph signal(SIGHUP, abortpr); 14416762Sralph signal(SIGINT, abortpr); 14516762Sralph signal(SIGQUIT, abortpr); 14616762Sralph signal(SIGTERM, abortpr); 14712111Sralph 14839954Smckusick (void) mktemp(tempfile); 14915811Sralph 15012111Sralph /* 15112111Sralph * uses short form file names 15212111Sralph */ 15312111Sralph if (chdir(SD) < 0) { 15416762Sralph syslog(LOG_ERR, "%s: %m", SD); 15512111Sralph exit(1); 15612111Sralph } 15712463Sralph if (stat(LO, &stb) == 0 && (stb.st_mode & 0100)) 15812463Sralph exit(0); /* printing disabled */ 15914150Sralph lfd = open(LO, O_WRONLY|O_CREAT, 0644); 16013169Sralph if (lfd < 0) { 16116762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, LO); 16213169Sralph exit(1); 16313169Sralph } 16413169Sralph if (flock(lfd, LOCK_EX|LOCK_NB) < 0) { 16512111Sralph if (errno == EWOULDBLOCK) /* active deamon present */ 16612111Sralph exit(0); 16716762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, LO); 16812111Sralph exit(1); 16912111Sralph } 17013148Ssam ftruncate(lfd, 0); 17112111Sralph /* 17212111Sralph * write process id for others to know 17312111Sralph */ 17412111Sralph sprintf(line, "%u\n", pid); 17512111Sralph pidoff = i = strlen(line); 17612463Sralph if (write(lfd, line, i) != i) { 17716762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, LO); 17812111Sralph exit(1); 17912111Sralph } 18012111Sralph /* 18112111Sralph * search the spool directory for work and sort by queue order. 18212111Sralph */ 18312111Sralph if ((nitems = getq(&queue)) < 0) { 18416762Sralph syslog(LOG_ERR, "%s: can't scan %s", printer, SD); 18512111Sralph exit(1); 18612111Sralph } 18712463Sralph if (nitems == 0) /* no work to do */ 18812111Sralph exit(0); 18913169Sralph if (stb.st_mode & 01) { /* reset queue flag */ 19013169Sralph if (fchmod(lfd, stb.st_mode & 0776) < 0) 19116762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, LO); 19213169Sralph } 19312463Sralph openpr(); /* open printer or remote */ 19412463Sralph again: 19512111Sralph /* 19612111Sralph * we found something to do now do it -- 19712111Sralph * write the name of the current control file into the lock file 19812111Sralph * so the spool queue program can tell what we're working on 19912111Sralph */ 20012111Sralph for (qp = queue; nitems--; free((char *) q)) { 20112111Sralph q = *qp++; 20212111Sralph if (stat(q->q_name, &stb) < 0) 20312111Sralph continue; 20412463Sralph restart: 20555474Sbostic (void) lseek(lfd, (off_t)pidoff, 0); 20612111Sralph (void) sprintf(line, "%s\n", q->q_name); 20712111Sralph i = strlen(line); 20812111Sralph if (write(lfd, line, i) != i) 20916762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, LO); 21012111Sralph if (!remote) 21112111Sralph i = printit(q->q_name); 21212111Sralph else 21312111Sralph i = sendit(q->q_name); 21412463Sralph /* 21513169Sralph * Check to see if we are supposed to stop printing or 21613169Sralph * if we are to rebuild the queue. 21712463Sralph */ 21813169Sralph if (fstat(lfd, &stb) == 0) { 21916762Sralph /* stop printing before starting next job? */ 22013169Sralph if (stb.st_mode & 0100) 22113169Sralph goto done; 22216762Sralph /* rebuild queue (after lpc topq) */ 22313169Sralph if (stb.st_mode & 01) { 22413169Sralph for (free((char *) q); nitems--; free((char *) q)) 22513169Sralph q = *qp++; 22613169Sralph if (fchmod(lfd, stb.st_mode & 0776) < 0) 22716762Sralph syslog(LOG_WARNING, "%s: %s: %m", 22816762Sralph printer, LO); 22913169Sralph break; 23013169Sralph } 23113169Sralph } 23217463Sralph if (i == OK) /* file ok and printed */ 23314150Sralph count++; 23417463Sralph else if (i == REPRINT) { /* try reprinting the job */ 23516762Sralph syslog(LOG_INFO, "restarting %s", printer); 23612111Sralph if (ofilter > 0) { 23712111Sralph kill(ofilter, SIGCONT); /* to be sure */ 23812111Sralph (void) close(ofd); 23912111Sralph while ((i = wait(0)) > 0 && i != ofilter) 24012111Sralph ; 24112111Sralph ofilter = 0; 24212111Sralph } 24312463Sralph (void) close(pfd); /* close printer */ 24415811Sralph if (ftruncate(lfd, pidoff) < 0) 24516762Sralph syslog(LOG_WARNING, "%s: %s: %m", printer, LO); 24612463Sralph openpr(); /* try to reopen printer */ 24712111Sralph goto restart; 24812111Sralph } 24912111Sralph } 25012111Sralph free((char *) queue); 25112463Sralph /* 25212463Sralph * search the spool directory for more work. 25312463Sralph */ 25412463Sralph if ((nitems = getq(&queue)) < 0) { 25516762Sralph syslog(LOG_ERR, "%s: can't scan %s", printer, SD); 25612463Sralph exit(1); 25712463Sralph } 25812463Sralph if (nitems == 0) { /* no more work to do */ 25912463Sralph done: 26014150Sralph if (count > 0) { /* Files actually printed */ 26114150Sralph if (!SF && !tof) 26214150Sralph (void) write(ofd, FF, strlen(FF)); 26314150Sralph if (TR != NULL) /* output trailer */ 26414150Sralph (void) write(ofd, TR, strlen(TR)); 26514150Sralph } 26639954Smckusick (void) unlink(tempfile); 26712463Sralph exit(0); 26812463Sralph } 26912111Sralph goto again; 27012111Sralph } 27112111Sralph 27212111Sralph char fonts[4][50]; /* fonts for troff */ 27312111Sralph 27437968Sbostic char ifonts[4][40] = { 27537968Sbostic _PATH_VFONTR, 27637968Sbostic _PATH_VFONTI, 27737968Sbostic _PATH_VFONTB, 27837968Sbostic _PATH_VFONTS, 27912111Sralph }; 28012111Sralph 28112111Sralph /* 28212111Sralph * The remaining part is the reading of the control file (cf) 28312111Sralph * and performing the various actions. 28412111Sralph */ 28555474Sbostic static int 28612111Sralph printit(file) 28712111Sralph char *file; 28812111Sralph { 28912111Sralph register int i; 29017463Sralph char *cp; 29117463Sralph int bombed = OK; 29212111Sralph 29312111Sralph /* 29417463Sralph * open control file; ignore if no longer there. 29512111Sralph */ 29612111Sralph if ((cfp = fopen(file, "r")) == NULL) { 29716762Sralph syslog(LOG_INFO, "%s: %s: %m", printer, file); 29817463Sralph return(OK); 29912111Sralph } 30012111Sralph /* 30112111Sralph * Reset troff fonts. 30212111Sralph */ 30312111Sralph for (i = 0; i < 4; i++) 30412111Sralph strcpy(fonts[i], ifonts[i]); 30517339Sralph strcpy(width+2, "0"); 30617302Sralph strcpy(indent+2, "0"); 30712111Sralph 30812111Sralph /* 30912111Sralph * read the control file for work to do 31012111Sralph * 31112111Sralph * file format -- first character in the line is a command 31212111Sralph * rest of the line is the argument. 31312111Sralph * valid commands are: 31412111Sralph * 31517463Sralph * S -- "stat info" for symbolic link protection 31612111Sralph * J -- "job name" on banner page 31712111Sralph * C -- "class name" on banner page 31812111Sralph * L -- "literal" user's name to print on banner 31912111Sralph * T -- "title" for pr 32012111Sralph * H -- "host name" of machine where lpr was done 32112111Sralph * P -- "person" user's login name 32212581Sralph * I -- "indent" amount to indent output 32312111Sralph * f -- "file name" name of text file to print 32412111Sralph * l -- "file name" text file with control chars 32512111Sralph * p -- "file name" text file to print with pr(1) 32612111Sralph * t -- "file name" troff(1) file to print 32713233Sralph * n -- "file name" ditroff(1) file to print 32812111Sralph * d -- "file name" dvi file to print 32912111Sralph * g -- "file name" plot(1G) file to print 33012111Sralph * v -- "file name" plain raster file to print 33112111Sralph * c -- "file name" cifplot file to print 33212111Sralph * 1 -- "R font file" for troff 33312111Sralph * 2 -- "I font file" for troff 33412111Sralph * 3 -- "B font file" for troff 33512111Sralph * 4 -- "S font file" for troff 33612111Sralph * N -- "name" of file (used by lpq) 33712111Sralph * U -- "unlink" name of file to remove 33812111Sralph * (after we print it. (Pass 2 only)). 33912111Sralph * M -- "mail" to user when done printing 34012111Sralph * 34112111Sralph * getline reads a line and expands tabs to blanks 34212111Sralph */ 34312111Sralph 34412111Sralph /* pass 1 */ 34512111Sralph 34612111Sralph while (getline(cfp)) 34712111Sralph switch (line[0]) { 34812111Sralph case 'H': 34914150Sralph strcpy(fromhost, line+1); 35012111Sralph if (class[0] == '\0') 35115552Sralph strncpy(class, line+1, sizeof(class)-1); 35212111Sralph continue; 35312111Sralph 35412111Sralph case 'P': 35515552Sralph strncpy(logname, line+1, sizeof(logname)-1); 35612463Sralph if (RS) { /* restricted */ 35755474Sbostic if (getpwnam(logname) == NULL) { 35817463Sralph bombed = NOACCT; 35915811Sralph sendmail(line+1, bombed); 36012463Sralph goto pass2; 36112463Sralph } 36212463Sralph } 36312111Sralph continue; 36412111Sralph 36517463Sralph case 'S': 36617463Sralph cp = line+1; 36717463Sralph i = 0; 36817463Sralph while (*cp >= '0' && *cp <= '9') 36917463Sralph i = i * 10 + (*cp++ - '0'); 37017463Sralph fdev = i; 37117463Sralph cp++; 37217463Sralph i = 0; 37317463Sralph while (*cp >= '0' && *cp <= '9') 37417463Sralph i = i * 10 + (*cp++ - '0'); 37517463Sralph fino = i; 37617463Sralph continue; 37717463Sralph 37812111Sralph case 'J': 37912111Sralph if (line[1] != '\0') 38015552Sralph strncpy(jobname, line+1, sizeof(jobname)-1); 38112111Sralph else 38212111Sralph strcpy(jobname, " "); 38312111Sralph continue; 38412111Sralph 38512111Sralph case 'C': 38612111Sralph if (line[1] != '\0') 38715552Sralph strncpy(class, line+1, sizeof(class)-1); 38812111Sralph else if (class[0] == '\0') 38915811Sralph gethostname(class, sizeof(class)); 39012111Sralph continue; 39112111Sralph 39212111Sralph case 'T': /* header title for pr */ 39315552Sralph strncpy(title, line+1, sizeof(title)-1); 39412111Sralph continue; 39512111Sralph 39612111Sralph case 'L': /* identification line */ 39718127Sralph if (!SH && !HL) 39812111Sralph banner(line+1, jobname); 39912111Sralph continue; 40012111Sralph 40112111Sralph case '1': /* troff fonts */ 40212111Sralph case '2': 40312111Sralph case '3': 40412111Sralph case '4': 40512111Sralph if (line[1] != '\0') 40612111Sralph strcpy(fonts[line[0]-'1'], line+1); 40712111Sralph continue; 40812111Sralph 40912111Sralph case 'W': /* page width */ 41015552Sralph strncpy(width+2, line+1, sizeof(width)-3); 41112111Sralph continue; 41212111Sralph 41312581Sralph case 'I': /* indent amount */ 41415552Sralph strncpy(indent+2, line+1, sizeof(indent)-3); 41512581Sralph continue; 41612581Sralph 41712111Sralph default: /* some file to print */ 41815811Sralph switch (i = print(line[0], line+1)) { 41917463Sralph case ERROR: 42017463Sralph if (bombed == OK) 42117463Sralph bombed = FATALERR; 42215811Sralph break; 42317463Sralph case REPRINT: 42412111Sralph (void) fclose(cfp); 42517463Sralph return(REPRINT); 42617463Sralph case FILTERERR: 42717463Sralph case ACCESS: 42817463Sralph bombed = i; 42915811Sralph sendmail(logname, bombed); 43015811Sralph } 43112111Sralph title[0] = '\0'; 43212111Sralph continue; 43312111Sralph 43412111Sralph case 'N': 43512111Sralph case 'U': 43612111Sralph case 'M': 43712111Sralph continue; 43812111Sralph } 43912111Sralph 44012111Sralph /* pass 2 */ 44112111Sralph 44212463Sralph pass2: 44312111Sralph fseek(cfp, 0L, 0); 44412111Sralph while (getline(cfp)) 44512111Sralph switch (line[0]) { 44618127Sralph case 'L': /* identification line */ 44718127Sralph if (!SH && HL) 44818127Sralph banner(line+1, jobname); 44918127Sralph continue; 45018127Sralph 45112111Sralph case 'M': 45217463Sralph if (bombed < NOACCT) /* already sent if >= NOACCT */ 45315811Sralph sendmail(line+1, bombed); 45412111Sralph continue; 45512111Sralph 45612111Sralph case 'U': 45712111Sralph (void) unlink(line+1); 45812111Sralph } 45912111Sralph /* 46015811Sralph * clean-up in case another control file exists 46112111Sralph */ 46212111Sralph (void) fclose(cfp); 46312111Sralph (void) unlink(file); 46417463Sralph return(bombed == OK ? OK : ERROR); 46512111Sralph } 46612111Sralph 46712111Sralph /* 46812111Sralph * Print a file. 46913233Sralph * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}. 47015811Sralph * Return -1 if a non-recoverable error occured, 47115811Sralph * 2 if the filter detected some errors (but printed the job anyway), 47215811Sralph * 1 if we should try to reprint this job and 47312111Sralph * 0 if all is well. 47412111Sralph * Note: all filters take stdin as the file, stdout as the printer, 47512111Sralph * stderr as the log file, and must not ignore SIGINT. 47612111Sralph */ 47755474Sbostic static int 47812111Sralph print(format, file) 47912111Sralph int format; 48012111Sralph char *file; 48112111Sralph { 48215811Sralph register int n; 48312111Sralph register char *prog; 48415811Sralph int fi, fo; 48539954Smckusick FILE *fp; 48612111Sralph char *av[15], buf[BUFSIZ]; 48712111Sralph int pid, p[2], stopped = 0; 48812111Sralph union wait status; 48917463Sralph struct stat stb; 49012111Sralph 49117463Sralph if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0) 49217463Sralph return(ERROR); 49317463Sralph /* 49417463Sralph * Check to see if data file is a symbolic link. If so, it should 49517463Sralph * still point to the same file or someone is trying to print 49617463Sralph * something he shouldn't. 49717463Sralph */ 49817463Sralph if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 && 49917463Sralph (stb.st_dev != fdev || stb.st_ino != fino)) 50017463Sralph return(ACCESS); 50112111Sralph if (!SF && !tof) { /* start on a fresh page */ 50212111Sralph (void) write(ofd, FF, strlen(FF)); 50312111Sralph tof = 1; 50412111Sralph } 50512111Sralph if (IF == NULL && (format == 'f' || format == 'l')) { 50612111Sralph tof = 0; 50712111Sralph while ((n = read(fi, buf, BUFSIZ)) > 0) 50812111Sralph if (write(ofd, buf, n) != n) { 50912111Sralph (void) close(fi); 51017463Sralph return(REPRINT); 51112111Sralph } 51212111Sralph (void) close(fi); 51317463Sralph return(OK); 51412111Sralph } 51512111Sralph switch (format) { 51612111Sralph case 'p': /* print file using 'pr' */ 51712111Sralph if (IF == NULL) { /* use output filter */ 51837968Sbostic prog = _PATH_PR; 51912111Sralph av[0] = "pr"; 52012111Sralph av[1] = width; 52112111Sralph av[2] = length; 52212111Sralph av[3] = "-h"; 52312111Sralph av[4] = *title ? title : " "; 52412111Sralph av[5] = 0; 52512111Sralph fo = ofd; 52612111Sralph goto start; 52712111Sralph } 52812111Sralph pipe(p); 52912111Sralph if ((prchild = dofork(DORETURN)) == 0) { /* child */ 53012111Sralph dup2(fi, 0); /* file is stdin */ 53112111Sralph dup2(p[1], 1); /* pipe is stdout */ 53212111Sralph for (n = 3; n < NOFILE; n++) 53312111Sralph (void) close(n); 53437968Sbostic execl(_PATH_PR, "pr", width, length, 53537968Sbostic "-h", *title ? title : " ", 0); 53637968Sbostic syslog(LOG_ERR, "cannot execl %s", _PATH_PR); 53712111Sralph exit(2); 53812111Sralph } 53912111Sralph (void) close(p[1]); /* close output side */ 54012111Sralph (void) close(fi); 54112111Sralph if (prchild < 0) { 54212111Sralph prchild = 0; 54312111Sralph (void) close(p[0]); 54417463Sralph return(ERROR); 54512111Sralph } 54612111Sralph fi = p[0]; /* use pipe for input */ 54712111Sralph case 'f': /* print plain text file */ 54812111Sralph prog = IF; 54912111Sralph av[1] = width; 55012111Sralph av[2] = length; 55112581Sralph av[3] = indent; 55212581Sralph n = 4; 55312111Sralph break; 55412111Sralph case 'l': /* like 'f' but pass control characters */ 55512111Sralph prog = IF; 55614325Sralph av[1] = "-c"; 55712111Sralph av[2] = width; 55812111Sralph av[3] = length; 55912581Sralph av[4] = indent; 56012581Sralph n = 5; 56112111Sralph break; 56212463Sralph case 'r': /* print a fortran text file */ 56312463Sralph prog = RF; 56412463Sralph av[1] = width; 56512463Sralph av[2] = length; 56612463Sralph n = 3; 56712463Sralph break; 56812111Sralph case 't': /* print troff output */ 56913233Sralph case 'n': /* print ditroff output */ 57012463Sralph case 'd': /* print tex output */ 57112111Sralph (void) unlink(".railmag"); 57212463Sralph if ((fo = creat(".railmag", FILMOD)) < 0) { 57316762Sralph syslog(LOG_ERR, "%s: cannot create .railmag", printer); 57412111Sralph (void) unlink(".railmag"); 57512111Sralph } else { 57612111Sralph for (n = 0; n < 4; n++) { 57712111Sralph if (fonts[n][0] != '/') 57854520Sbostic (void) write(fo, _PATH_VFONT, 57954520Sbostic sizeof(_PATH_VFONT) - 1); 58012111Sralph (void) write(fo, fonts[n], strlen(fonts[n])); 58112111Sralph (void) write(fo, "\n", 1); 58212111Sralph } 58312111Sralph (void) close(fo); 58412111Sralph } 58513233Sralph prog = (format == 't') ? TF : (format == 'n') ? NF : DF; 58612463Sralph av[1] = pxwidth; 58712463Sralph av[2] = pxlength; 58812463Sralph n = 3; 58912111Sralph break; 59012111Sralph case 'c': /* print cifplot output */ 59112111Sralph prog = CF; 59212463Sralph av[1] = pxwidth; 59312463Sralph av[2] = pxlength; 59412463Sralph n = 3; 59512111Sralph break; 59612111Sralph case 'g': /* print plot(1G) output */ 59712111Sralph prog = GF; 59812463Sralph av[1] = pxwidth; 59912463Sralph av[2] = pxlength; 60012463Sralph n = 3; 60112111Sralph break; 60212111Sralph case 'v': /* print raster output */ 60312111Sralph prog = VF; 60412463Sralph av[1] = pxwidth; 60512463Sralph av[2] = pxlength; 60612463Sralph n = 3; 60712111Sralph break; 60812111Sralph default: 60912111Sralph (void) close(fi); 61016762Sralph syslog(LOG_ERR, "%s: illegal format character '%c'", 61116762Sralph printer, format); 61217463Sralph return(ERROR); 61312111Sralph } 61412111Sralph if ((av[0] = rindex(prog, '/')) != NULL) 61512111Sralph av[0]++; 61612111Sralph else 61712111Sralph av[0] = prog; 61812111Sralph av[n++] = "-n"; 61912111Sralph av[n++] = logname; 62012111Sralph av[n++] = "-h"; 62114150Sralph av[n++] = fromhost; 62212111Sralph av[n++] = AF; 62312111Sralph av[n] = 0; 62412111Sralph fo = pfd; 62512111Sralph if (ofilter > 0) { /* stop output filter */ 62612111Sralph write(ofd, "\031\1", 2); 62746912Sbostic while ((pid = 62846912Sbostic wait3((int *)&status, WUNTRACED, 0)) > 0 && pid != ofilter) 62912111Sralph ; 63012111Sralph if (status.w_stopval != WSTOPPED) { 63112111Sralph (void) close(fi); 63216762Sralph syslog(LOG_WARNING, "%s: output filter died (%d)", 63316762Sralph printer, status.w_retcode); 63417463Sralph return(REPRINT); 63512111Sralph } 63612111Sralph stopped++; 63712111Sralph } 63812111Sralph start: 63912111Sralph if ((child = dofork(DORETURN)) == 0) { /* child */ 64012111Sralph dup2(fi, 0); 64112111Sralph dup2(fo, 1); 64239954Smckusick n = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, 0664); 64315811Sralph if (n >= 0) 64415811Sralph dup2(n, 2); 64512111Sralph for (n = 3; n < NOFILE; n++) 64612111Sralph (void) close(n); 64712111Sralph execv(prog, av); 64816762Sralph syslog(LOG_ERR, "cannot execv %s", prog); 64912111Sralph exit(2); 65012111Sralph } 65112111Sralph (void) close(fi); 65212111Sralph if (child < 0) 65312111Sralph status.w_retcode = 100; 65412111Sralph else 65546912Sbostic while ((pid = wait((int *)&status)) > 0 && pid != child) 65612111Sralph ; 65712111Sralph child = 0; 65812111Sralph prchild = 0; 65912111Sralph if (stopped) { /* restart output filter */ 66012111Sralph if (kill(ofilter, SIGCONT) < 0) { 66116762Sralph syslog(LOG_ERR, "cannot restart output filter"); 66212111Sralph exit(1); 66312111Sralph } 66412111Sralph } 66512111Sralph tof = 0; 66639954Smckusick 66739954Smckusick /* Copy filter output to "lf" logfile */ 66839954Smckusick if (fp = fopen(tempfile, "r")) { 66939954Smckusick while (fgets(buf, sizeof(buf), fp)) 67039954Smckusick fputs(buf, stderr); 671*56123Selan fclose(fp); 67239954Smckusick } 67339954Smckusick 67415811Sralph if (!WIFEXITED(status)) { 67516762Sralph syslog(LOG_WARNING, "%s: Daemon filter '%c' terminated (%d)", 67616762Sralph printer, format, status.w_termsig); 67717463Sralph return(ERROR); 67817463Sralph } 67917463Sralph switch (status.w_retcode) { 68017463Sralph case 0: 68117463Sralph tof = 1; 68217463Sralph return(OK); 68317463Sralph case 1: 68417463Sralph return(REPRINT); 68517463Sralph default: 68616762Sralph syslog(LOG_WARNING, "%s: Daemon filter '%c' exited (%d)", 68716762Sralph printer, format, status.w_retcode); 68817463Sralph case 2: 68917463Sralph return(ERROR); 69017463Sralph } 69112111Sralph } 69212111Sralph 69312111Sralph /* 69412111Sralph * Send the daemon control file (cf) and any data files. 69512111Sralph * Return -1 if a non-recoverable error occured, 1 if a recoverable error and 69612111Sralph * 0 if all is well. 69712111Sralph */ 69855474Sbostic static int 69912111Sralph sendit(file) 70012111Sralph char *file; 70112111Sralph { 70217463Sralph register int i, err = OK; 70317463Sralph char *cp, last[BUFSIZ]; 70412111Sralph 70512111Sralph /* 70612111Sralph * open control file 70712111Sralph */ 70816762Sralph if ((cfp = fopen(file, "r")) == NULL) 70917463Sralph return(OK); 71012111Sralph /* 71112111Sralph * read the control file for work to do 71212111Sralph * 71312111Sralph * file format -- first character in the line is a command 71412111Sralph * rest of the line is the argument. 71512111Sralph * commands of interest are: 71612111Sralph * 71712111Sralph * a-z -- "file name" name of file to print 71812111Sralph * U -- "unlink" name of file to remove 71912111Sralph * (after we print it. (Pass 2 only)). 72012111Sralph */ 72112111Sralph 72212111Sralph /* 72312111Sralph * pass 1 72412111Sralph */ 72512111Sralph while (getline(cfp)) { 72612111Sralph again: 72717463Sralph if (line[0] == 'S') { 72817463Sralph cp = line+1; 72917463Sralph i = 0; 73017463Sralph while (*cp >= '0' && *cp <= '9') 73117463Sralph i = i * 10 + (*cp++ - '0'); 73217463Sralph fdev = i; 73317463Sralph cp++; 73417463Sralph i = 0; 73517463Sralph while (*cp >= '0' && *cp <= '9') 73617463Sralph i = i * 10 + (*cp++ - '0'); 73717463Sralph fino = i; 73817463Sralph continue; 73917463Sralph } 74012111Sralph if (line[0] >= 'a' && line[0] <= 'z') { 74112111Sralph strcpy(last, line); 74217463Sralph while (i = getline(cfp)) 74312111Sralph if (strcmp(last, line)) 74412111Sralph break; 74517463Sralph switch (sendfile('\3', last+1)) { 74617463Sralph case OK: 74717463Sralph if (i) 74817463Sralph goto again; 74917463Sralph break; 75017463Sralph case REPRINT: 75112111Sralph (void) fclose(cfp); 75217463Sralph return(REPRINT); 75317463Sralph case ACCESS: 75417463Sralph sendmail(logname, ACCESS); 75517463Sralph case ERROR: 75617463Sralph err = ERROR; 75717463Sralph } 75812111Sralph break; 75912111Sralph } 76012111Sralph } 76117463Sralph if (err == OK && sendfile('\2', file) > 0) { 76212111Sralph (void) fclose(cfp); 76317463Sralph return(REPRINT); 76412111Sralph } 76512111Sralph /* 76612111Sralph * pass 2 76712111Sralph */ 76812111Sralph fseek(cfp, 0L, 0); 76912111Sralph while (getline(cfp)) 77012111Sralph if (line[0] == 'U') 77112111Sralph (void) unlink(line+1); 77212111Sralph /* 77317463Sralph * clean-up in case another control file exists 77412111Sralph */ 77512111Sralph (void) fclose(cfp); 77612111Sralph (void) unlink(file); 77717463Sralph return(err); 77812111Sralph } 77912111Sralph 78012111Sralph /* 78112111Sralph * Send a data file to the remote machine and spool it. 78212111Sralph * Return positive if we should try resending. 78312111Sralph */ 78455474Sbostic static int 78512111Sralph sendfile(type, file) 78655474Sbostic int type; 78755474Sbostic char *file; 78812111Sralph { 78912111Sralph register int f, i, amt; 79012111Sralph struct stat stb; 79112111Sralph char buf[BUFSIZ]; 79216762Sralph int sizerr, resp; 79312111Sralph 79417463Sralph if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0) 79517463Sralph return(ERROR); 79617463Sralph /* 79717463Sralph * Check to see if data file is a symbolic link. If so, it should 79817463Sralph * still point to the same file or someone is trying to print something 79917463Sralph * he shouldn't. 80017463Sralph */ 80117463Sralph if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 && 80217463Sralph (stb.st_dev != fdev || stb.st_ino != fino)) 80317463Sralph return(ACCESS); 80455474Sbostic (void) sprintf(buf, "%c%qd %s\n", type, stb.st_size, file); 80512111Sralph amt = strlen(buf); 80616762Sralph for (i = 0; ; i++) { 80716762Sralph if (write(pfd, buf, amt) != amt || 80816762Sralph (resp = response()) < 0 || resp == '\1') { 80916762Sralph (void) close(f); 81017463Sralph return(REPRINT); 81116762Sralph } else if (resp == '\0') 81216762Sralph break; 81316762Sralph if (i == 0) 81455474Sbostic pstatus("no space on remote; waiting for queue to drain"); 81516762Sralph if (i == 10) 81624861Seric syslog(LOG_ALERT, "%s: can't send to %s; queue full", 81716762Sralph printer, RM); 81816762Sralph sleep(5 * 60); 81912692Sralph } 82016762Sralph if (i) 82155474Sbostic pstatus("sending to %s", RM); 82212111Sralph sizerr = 0; 82312111Sralph for (i = 0; i < stb.st_size; i += BUFSIZ) { 82412111Sralph amt = BUFSIZ; 82512111Sralph if (i + amt > stb.st_size) 82612111Sralph amt = stb.st_size - i; 82712111Sralph if (sizerr == 0 && read(f, buf, amt) != amt) 82812111Sralph sizerr = 1; 82912692Sralph if (write(pfd, buf, amt) != amt) { 83012692Sralph (void) close(f); 83117463Sralph return(REPRINT); 83212692Sralph } 83312111Sralph } 83455474Sbostic 83555474Sbostic 83655474Sbostic 83755474Sbostic 83812111Sralph (void) close(f); 83912111Sralph if (sizerr) { 84016762Sralph syslog(LOG_INFO, "%s: %s: changed size", printer, file); 84117463Sralph /* tell recvjob to ignore this file */ 84217463Sralph (void) write(pfd, "\1", 1); 84317463Sralph return(ERROR); 84417463Sralph } 84517463Sralph if (write(pfd, "", 1) != 1 || response()) 84617463Sralph return(REPRINT); 84717463Sralph return(OK); 84812111Sralph } 84912111Sralph 85012111Sralph /* 85112111Sralph * Check to make sure there have been no errors and that both programs 85212111Sralph * are in sync with eachother. 85312111Sralph * Return non-zero if the connection was lost. 85412111Sralph */ 85555474Sbostic static char 85616762Sralph response() 85712111Sralph { 85812111Sralph char resp; 85912111Sralph 86016762Sralph if (read(pfd, &resp, 1) != 1) { 86116762Sralph syslog(LOG_INFO, "%s: lost connection", printer); 86216762Sralph return(-1); 86312111Sralph } 86416762Sralph return(resp); 86512111Sralph } 86612111Sralph 86712111Sralph /* 86812111Sralph * Banner printing stuff 86912111Sralph */ 87055474Sbostic static void 87112111Sralph banner(name1, name2) 87212111Sralph char *name1, *name2; 87312111Sralph { 87412111Sralph time_t tvec; 87512111Sralph extern char *ctime(); 87612111Sralph 87712111Sralph time(&tvec); 87812111Sralph if (!SF && !tof) 87912111Sralph (void) write(ofd, FF, strlen(FF)); 88012111Sralph if (SB) { /* short banner only */ 88112111Sralph if (class[0]) { 88212111Sralph (void) write(ofd, class, strlen(class)); 88312111Sralph (void) write(ofd, ":", 1); 88412111Sralph } 88512111Sralph (void) write(ofd, name1, strlen(name1)); 88612111Sralph (void) write(ofd, " Job: ", 7); 88712111Sralph (void) write(ofd, name2, strlen(name2)); 88812111Sralph (void) write(ofd, " Date: ", 8); 88912111Sralph (void) write(ofd, ctime(&tvec), 24); 89012111Sralph (void) write(ofd, "\n", 1); 89112111Sralph } else { /* normal banner */ 89212111Sralph (void) write(ofd, "\n\n\n", 3); 89312111Sralph scan_out(ofd, name1, '\0'); 89412111Sralph (void) write(ofd, "\n\n", 2); 89512111Sralph scan_out(ofd, name2, '\0'); 89612111Sralph if (class[0]) { 89712111Sralph (void) write(ofd,"\n\n\n",3); 89812111Sralph scan_out(ofd, class, '\0'); 89912111Sralph } 90012111Sralph (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15); 90112111Sralph (void) write(ofd, name2, strlen(name2)); 90212111Sralph (void) write(ofd, "\n\t\t\t\t\tDate: ", 12); 90312111Sralph (void) write(ofd, ctime(&tvec), 24); 90412111Sralph (void) write(ofd, "\n", 1); 90512111Sralph } 90612111Sralph if (!SF) 90712111Sralph (void) write(ofd, FF, strlen(FF)); 90812111Sralph tof = 1; 90912111Sralph } 91012111Sralph 91155474Sbostic static char * 91212111Sralph scnline(key, p, c) 91355474Sbostic register int key; 91455474Sbostic register char *p; 91555474Sbostic int c; 91612111Sralph { 91712111Sralph register scnwidth; 91812111Sralph 91912111Sralph for (scnwidth = WIDTH; --scnwidth;) { 92012111Sralph key <<= 1; 92112111Sralph *p++ = key & 0200 ? c : BACKGND; 92212111Sralph } 92312111Sralph return (p); 92412111Sralph } 92512111Sralph 92612111Sralph #define TRC(q) (((q)-' ')&0177) 92712111Sralph 92855474Sbostic static void 92912111Sralph scan_out(scfd, scsp, dlm) 93055474Sbostic int scfd, dlm; 93155474Sbostic char *scsp; 93212111Sralph { 93312111Sralph register char *strp; 93412111Sralph register nchrs, j; 93512111Sralph char outbuf[LINELEN+1], *sp, c, cc; 93612111Sralph int d, scnhgt; 93712111Sralph extern char scnkey[][HEIGHT]; /* in lpdchar.c */ 93812111Sralph 93912111Sralph for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) { 94012111Sralph strp = &outbuf[0]; 94112111Sralph sp = scsp; 94212111Sralph for (nchrs = 0; ; ) { 94312111Sralph d = dropit(c = TRC(cc = *sp++)); 94412111Sralph if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d)) 94512111Sralph for (j = WIDTH; --j;) 94612111Sralph *strp++ = BACKGND; 94712111Sralph else 94812111Sralph strp = scnline(scnkey[c][scnhgt-1-d], strp, cc); 94912111Sralph if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1) 95012111Sralph break; 95112111Sralph *strp++ = BACKGND; 95212111Sralph *strp++ = BACKGND; 95312111Sralph } 95412111Sralph while (*--strp == BACKGND && strp >= outbuf) 95512111Sralph ; 95612111Sralph strp++; 95712111Sralph *strp++ = '\n'; 95812111Sralph (void) write(scfd, outbuf, strp-outbuf); 95912111Sralph } 96012111Sralph } 96112111Sralph 96255474Sbostic static int 96312111Sralph dropit(c) 96455474Sbostic int c; 96512111Sralph { 96612111Sralph switch(c) { 96712111Sralph 96812111Sralph case TRC('_'): 96912111Sralph case TRC(';'): 97012111Sralph case TRC(','): 97112111Sralph case TRC('g'): 97212111Sralph case TRC('j'): 97312111Sralph case TRC('p'): 97412111Sralph case TRC('q'): 97512111Sralph case TRC('y'): 97612111Sralph return (DROP); 97712111Sralph 97812111Sralph default: 97912111Sralph return (0); 98012111Sralph } 98112111Sralph } 98212111Sralph 98312111Sralph /* 98412111Sralph * sendmail --- 98512111Sralph * tell people about job completion 98612111Sralph */ 98755474Sbostic static void 98815811Sralph sendmail(user, bombed) 98915811Sralph char *user; 99012111Sralph int bombed; 99112111Sralph { 99212111Sralph register int i; 99315811Sralph int p[2], s; 99412111Sralph register char *cp; 99512111Sralph char buf[100]; 99615811Sralph struct stat stb; 99715811Sralph FILE *fp; 99812111Sralph 99912111Sralph pipe(p); 100015811Sralph if ((s = dofork(DORETURN)) == 0) { /* child */ 100112111Sralph dup2(p[0], 0); 100212111Sralph for (i = 3; i < NOFILE; i++) 100312111Sralph (void) close(i); 100437968Sbostic if ((cp = rindex(_PATH_SENDMAIL, '/')) != NULL) 100512111Sralph cp++; 100655474Sbostic else 100737968Sbostic cp = _PATH_SENDMAIL; 100815811Sralph sprintf(buf, "%s@%s", user, fromhost); 100937968Sbostic execl(_PATH_SENDMAIL, cp, buf, 0); 101012111Sralph exit(0); 101115811Sralph } else if (s > 0) { /* parent */ 101212111Sralph dup2(p[1], 1); 101315811Sralph printf("To: %s@%s\n", user, fromhost); 101412111Sralph printf("Subject: printer job\n\n"); 101512111Sralph printf("Your printer job "); 101612111Sralph if (*jobname) 101712111Sralph printf("(%s) ", jobname); 101812463Sralph switch (bombed) { 101917463Sralph case OK: 102012463Sralph printf("\ncompleted successfully\n"); 102112463Sralph break; 102212463Sralph default: 102317463Sralph case FATALERR: 102412463Sralph printf("\ncould not be printed\n"); 102512463Sralph break; 102617463Sralph case NOACCT: 102712463Sralph printf("\ncould not be printed without an account on %s\n", host); 102812463Sralph break; 102917463Sralph case FILTERERR: 103039954Smckusick if (stat(tempfile, &stb) < 0 || stb.st_size == 0 || 103139954Smckusick (fp = fopen(tempfile, "r")) == NULL) { 103215811Sralph printf("\nwas printed but had some errors\n"); 103315811Sralph break; 103415811Sralph } 103515811Sralph printf("\nwas printed but had the following errors:\n"); 103615811Sralph while ((i = getc(fp)) != EOF) 103715811Sralph putchar(i); 103815811Sralph (void) fclose(fp); 103917463Sralph break; 104017463Sralph case ACCESS: 104117463Sralph printf("\nwas not printed because it was not linked to the original file\n"); 104212463Sralph } 104312111Sralph fflush(stdout); 104412111Sralph (void) close(1); 104512111Sralph } 104612111Sralph (void) close(p[0]); 104712111Sralph (void) close(p[1]); 104815811Sralph wait(&s); 104912111Sralph } 105012111Sralph 105112111Sralph /* 105212111Sralph * dofork - fork with retries on failure 105312111Sralph */ 105455474Sbostic static int 105512111Sralph dofork(action) 105612111Sralph int action; 105712111Sralph { 105812111Sralph register int i, pid; 105912111Sralph 106012111Sralph for (i = 0; i < 20; i++) { 106112463Sralph if ((pid = fork()) < 0) { 106212111Sralph sleep((unsigned)(i*i)); 106312463Sralph continue; 106412463Sralph } 106512463Sralph /* 106612463Sralph * Child should run as daemon instead of root 106712463Sralph */ 106812463Sralph if (pid == 0) 106912463Sralph setuid(DU); 107012463Sralph return(pid); 107112111Sralph } 107216762Sralph syslog(LOG_ERR, "can't fork"); 107312111Sralph 107412111Sralph switch (action) { 107512111Sralph case DORETURN: 107612111Sralph return (-1); 107712111Sralph default: 107816762Sralph syslog(LOG_ERR, "bad action (%d) to dofork", action); 107912111Sralph /*FALL THRU*/ 108012111Sralph case DOABORT: 108112111Sralph exit(1); 108212111Sralph } 108312111Sralph /*NOTREACHED*/ 108412111Sralph } 108512111Sralph 108612111Sralph /* 108716762Sralph * Kill child processes to abort current job. 108812111Sralph */ 108955474Sbostic static void 109055474Sbostic abortpr(signo) 109155474Sbostic int signo; 109212111Sralph { 109339954Smckusick (void) unlink(tempfile); 109412111Sralph kill(0, SIGINT); 109512111Sralph if (ofilter > 0) 109612111Sralph kill(ofilter, SIGCONT); 109746912Sbostic while (wait(NULL) > 0) 109812111Sralph ; 109912111Sralph exit(0); 110012111Sralph } 110112111Sralph 110255474Sbostic static void 110312111Sralph init() 110412111Sralph { 110512111Sralph int status; 110638736Stef char *s; 110712111Sralph 1108*56123Selan if ((status = cgetent(&bp, printcapdb, printer)) == -2) { 110925468Stef syslog(LOG_ERR, "can't open printer description file"); 111025468Stef exit(1); 1111*56123Selan } else if (status == -1) { 111225468Stef syslog(LOG_ERR, "unknown printer: %s", printer); 111325468Stef exit(1); 1114*56123Selan } else if (status == -3) 1115*56123Selan fatal("potential reference loop detected in printcap file"); 1116*56123Selan 1117*56123Selan if (cgetstr(bp, "lp", &LP) == -1) 111837968Sbostic LP = _PATH_DEFDEVLP; 1119*56123Selan if (cgetstr(bp, "rp", &RP) == -1) 112012463Sralph RP = DEFLP; 1121*56123Selan if (cgetstr(bp, "lo", &LO) == -1) 112212111Sralph LO = DEFLOCK; 1123*56123Selan if (cgetstr(bp, "st", &ST) == -1) 112412111Sralph ST = DEFSTAT; 1125*56123Selan if (cgetstr(bp, "lf", &LF) == -1) 112637968Sbostic LF = _PATH_CONSOLE; 1127*56123Selan if (cgetstr(bp, "sd", &SD) == -1) 112837968Sbostic SD = _PATH_DEFSPOOL; 1129*56123Selan if (cgetnum(bp, "du", &DU) < 0) 113012111Sralph DU = DEFUID; 1131*56123Selan if (cgetstr(bp,"ff", &FF) == -1) 113212111Sralph FF = DEFFF; 1133*56123Selan if (cgetnum(bp, "pw", &PW) < 0) 113412111Sralph PW = DEFWIDTH; 113512111Sralph sprintf(&width[2], "%d", PW); 1136*56123Selan if (cgetnum(bp, "pl", &PL) < 0) 113712111Sralph PL = DEFLENGTH; 113812111Sralph sprintf(&length[2], "%d", PL); 1139*56123Selan if (cgetnum(bp,"px", &PX) < 0) 114012463Sralph PX = 0; 114112463Sralph sprintf(&pxwidth[2], "%d", PX); 1142*56123Selan if (cgetnum(bp, "py", &PY) < 0) 114312463Sralph PY = 0; 114412463Sralph sprintf(&pxlength[2], "%d", PY); 1145*56123Selan cgetstr(bp, "rm", &RM); 114638736Stef if (s = checkremote()) 114738736Stef syslog(LOG_WARNING, s); 114825468Stef 1149*56123Selan cgetstr(bp, "af", &AF); 1150*56123Selan cgetstr(bp, "of", &OF); 1151*56123Selan cgetstr(bp, "if", &IF); 1152*56123Selan cgetstr(bp, "rf", &RF); 1153*56123Selan cgetstr(bp, "tf", &TF); 1154*56123Selan cgetstr(bp, "nf", &NF); 1155*56123Selan cgetstr(bp, "df", &DF); 1156*56123Selan cgetstr(bp, "gf", &GF); 1157*56123Selan cgetstr(bp, "vf", &VF); 1158*56123Selan cgetstr(bp, "cf", &CF); 1159*56123Selan cgetstr(bp, "tr", &TR); 1160*56123Selan 1161*56123Selan RS = (cgetcap(bp, "rs", ':') != NULL); 1162*56123Selan SF = (cgetcap(bp, "sf", ':') != NULL); 1163*56123Selan SH = (cgetcap(bp, "sh", ':') != NULL); 1164*56123Selan SB = (cgetcap(bp, "sb", ':') != NULL); 1165*56123Selan HL = (cgetcap(bp, "hl", ':') != NULL); 1166*56123Selan RW = (cgetcap(bp, "rw", ':') != NULL); 1167*56123Selan 1168*56123Selan cgetnum(bp, "br", &BR); 1169*56123Selan if (cgetnum(bp, "fc", &FC) < 0) 117012111Sralph FC = 0; 1171*56123Selan if (cgetnum(bp, "fs", &FS) < 0) 117212111Sralph FS = 0; 1173*56123Selan if (cgetnum(bp, "xc", &XC) < 0) 117412111Sralph XC = 0; 1175*56123Selan if (cgetnum(bp, "xs", &XS) < 0) 117612111Sralph XS = 0; 1177*56123Selan 1178*56123Selan tof = (cgetcap(bp, "fo", ':') == NULL); 117912111Sralph } 118012111Sralph 118112463Sralph /* 118212463Sralph * Acquire line printer or remote connection. 118312463Sralph */ 118455474Sbostic static void 118512463Sralph openpr() 118612463Sralph { 118712463Sralph register int i, n; 118816762Sralph int resp; 118912463Sralph 119038736Stef if (!sendtorem && *LP) { 119112463Sralph for (i = 1; ; i = i < 32 ? i << 1 : i) { 119213148Ssam pfd = open(LP, RW ? O_RDWR : O_WRONLY); 119312463Sralph if (pfd >= 0) 119412463Sralph break; 119512463Sralph if (errno == ENOENT) { 119616762Sralph syslog(LOG_ERR, "%s: %m", LP); 119712463Sralph exit(1); 119812463Sralph } 119912463Sralph if (i == 1) 120055474Sbostic pstatus("waiting for %s to become ready (offline ?)", printer); 120112463Sralph sleep(i); 120212463Sralph } 120312463Sralph if (isatty(pfd)) 120412463Sralph setty(); 120555474Sbostic pstatus("%s is ready and printing", printer); 120612463Sralph } else if (RM != NULL) { 120716762Sralph for (i = 1; ; i = i < 256 ? i << 1 : i) { 120816762Sralph resp = -1; 120912528Sralph pfd = getport(RM); 121012463Sralph if (pfd >= 0) { 121112463Sralph (void) sprintf(line, "\2%s\n", RP); 121212463Sralph n = strlen(line); 121316762Sralph if (write(pfd, line, n) == n && 121416762Sralph (resp = response()) == '\0') 121512463Sralph break; 121616031Sralph (void) close(pfd); 121712463Sralph } 121816031Sralph if (i == 1) { 121916762Sralph if (resp < 0) 122055474Sbostic pstatus("waiting for %s to come up", RM); 122116762Sralph else { 122255474Sbostic pstatus("waiting for queue to be enabled on %s", RM); 122316762Sralph i = 256; 122416762Sralph } 122516031Sralph } 122612463Sralph sleep(i); 122712463Sralph } 122855474Sbostic pstatus("sending to %s", RM); 122912463Sralph remote = 1; 123012463Sralph } else { 123116762Sralph syslog(LOG_ERR, "%s: no line printer device or host name", 123216762Sralph printer); 123312463Sralph exit(1); 123412463Sralph } 123512463Sralph /* 123612463Sralph * Start up an output filter, if needed. 123712463Sralph */ 123840049Stef if (!remote && OF) { 123912463Sralph int p[2]; 124012463Sralph char *cp; 124112463Sralph 124212463Sralph pipe(p); 124312463Sralph if ((ofilter = dofork(DOABORT)) == 0) { /* child */ 124412463Sralph dup2(p[0], 0); /* pipe is std in */ 124512463Sralph dup2(pfd, 1); /* printer is std out */ 124612463Sralph for (i = 3; i < NOFILE; i++) 124712463Sralph (void) close(i); 124812463Sralph if ((cp = rindex(OF, '/')) == NULL) 124912463Sralph cp = OF; 125012463Sralph else 125112463Sralph cp++; 125212463Sralph execl(OF, cp, width, length, 0); 125316762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, OF); 125412463Sralph exit(1); 125512463Sralph } 125612463Sralph (void) close(p[0]); /* close input side */ 125712463Sralph ofd = p[1]; /* use pipe for output */ 125812463Sralph } else { 125912463Sralph ofd = pfd; 126012463Sralph ofilter = 0; 126112463Sralph } 126212463Sralph } 126312463Sralph 126412111Sralph struct bauds { 126512111Sralph int baud; 126612111Sralph int speed; 126712111Sralph } bauds[] = { 126812111Sralph 50, B50, 126912111Sralph 75, B75, 127012111Sralph 110, B110, 127112111Sralph 134, B134, 127212111Sralph 150, B150, 127312111Sralph 200, B200, 127412111Sralph 300, B300, 127512111Sralph 600, B600, 127612111Sralph 1200, B1200, 127712111Sralph 1800, B1800, 127812111Sralph 2400, B2400, 127912111Sralph 4800, B4800, 128012111Sralph 9600, B9600, 128112111Sralph 19200, EXTA, 128212111Sralph 38400, EXTB, 128312111Sralph 0, 0 128412111Sralph }; 128512111Sralph 128612111Sralph /* 128712111Sralph * setup tty lines. 128812111Sralph */ 128955474Sbostic static void 129012111Sralph setty() 129112111Sralph { 129212111Sralph struct sgttyb ttybuf; 129312111Sralph register struct bauds *bp; 129412111Sralph 129512111Sralph if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) { 129616762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer); 129712111Sralph exit(1); 129812111Sralph } 129912111Sralph if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) { 130016762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCGETP): %m", printer); 130112111Sralph exit(1); 130212111Sralph } 130312111Sralph if (BR > 0) { 130412111Sralph for (bp = bauds; bp->baud; bp++) 130512111Sralph if (BR == bp->baud) 130612111Sralph break; 130712111Sralph if (!bp->baud) { 130816762Sralph syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR); 130912111Sralph exit(1); 131012111Sralph } 131112111Sralph ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed; 131212111Sralph } 131313169Sralph ttybuf.sg_flags &= ~FC; 131413169Sralph ttybuf.sg_flags |= FS; 131512111Sralph if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) { 131616762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCSETP): %m", printer); 131712111Sralph exit(1); 131812111Sralph } 131912111Sralph if (XC) { 132012111Sralph if (ioctl(pfd, TIOCLBIC, &XC) < 0) { 132116762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCLBIC): %m", printer); 132212111Sralph exit(1); 132312111Sralph } 132412111Sralph } 132512111Sralph if (XS) { 132612111Sralph if (ioctl(pfd, TIOCLBIS, &XS) < 0) { 132716762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCLBIS): %m", printer); 132812111Sralph exit(1); 132912111Sralph } 133012111Sralph } 133112111Sralph } 133212463Sralph 133355474Sbostic #if __STDC__ 133455474Sbostic #include <stdarg.h> 133555474Sbostic #else 133655474Sbostic #include <varargs.h> 133755474Sbostic #endif 133855474Sbostic 133955474Sbostic void 134055474Sbostic #if __STDC__ 134155474Sbostic pstatus(const char *msg, ...) 134255474Sbostic #else 134355474Sbostic pstatus(msg, va_alist) 134412463Sralph char *msg; 134555474Sbostic va_dcl 134655474Sbostic #endif 134712463Sralph { 134812463Sralph register int fd; 134912463Sralph char buf[BUFSIZ]; 135055474Sbostic va_list ap; 135155474Sbostic #if __STDC__ 135255474Sbostic va_start(ap, msg); 135355474Sbostic #else 135455474Sbostic va_start(ap); 135555474Sbostic #endif 135612463Sralph 135712463Sralph umask(0); 135813148Ssam fd = open(ST, O_WRONLY|O_CREAT, 0664); 135916762Sralph if (fd < 0 || flock(fd, LOCK_EX) < 0) { 136016762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, ST); 136116762Sralph exit(1); 136216762Sralph } 136313148Ssam ftruncate(fd, 0); 136455474Sbostic (void)vsnprintf(buf, sizeof(buf), msg, ap); 136555474Sbostic va_end(ap); 136612463Sralph strcat(buf, "\n"); 136712463Sralph (void) write(fd, buf, strlen(buf)); 136812463Sralph (void) close(fd); 136912463Sralph } 1370