122437Sdist /* 261845Sbostic * Copyright (c) 1983, 1993 361845Sbostic * The Regents of the University of California. All rights reserved. 434203Sbostic * 556123Selan * 656251Selan * %sccs.include.redist.c% 722437Sdist */ 822437Sdist 913954Ssam #ifndef lint 1061845Sbostic static char copyright[] = 1161845Sbostic "@(#) Copyright (c) 1983, 1993\n\ 1261845Sbostic The Regents of the University of California. All rights reserved.\n"; 1334203Sbostic #endif /* not lint */ 1413954Ssam 1556251Selan #ifndef lint 16*69008Stef static char sccsid[] = "@(#)printjob.c 8.5 (Berkeley) 04/28/95"; 1756251Selan #endif /* not lint */ 1856251Selan 1956251Selan 2012111Sralph /* 2112111Sralph * printjob -- print jobs in the queue. 2212111Sralph * 2312111Sralph * NOTE: the lock file is used to pass information to lpq and lprm. 2412111Sralph * it does not need to be removed because file locks are dynamic. 2512111Sralph */ 2612111Sralph 2755474Sbostic #include <sys/param.h> 2855474Sbostic #include <sys/wait.h> 2955474Sbostic #include <sys/stat.h> 3056123Selan #include <sys/types.h> 3155474Sbostic 3256123Selan #include <pwd.h> 3356123Selan #include <unistd.h> 3455474Sbostic #include <signal.h> 3555474Sbostic #include <sgtty.h> 3655474Sbostic #include <syslog.h> 3755474Sbostic #include <fcntl.h> 3855474Sbostic #include <dirent.h> 3955474Sbostic #include <errno.h> 4055474Sbostic #include <stdio.h> 4155474Sbostic #include <string.h> 4256123Selan #include <stdlib.h> 4312111Sralph #include "lp.h" 4455474Sbostic #include "lp.local.h" 4537968Sbostic #include "pathnames.h" 4655474Sbostic #include "extern.h" 4712111Sralph 4816762Sralph #define DORETURN 0 /* absorb fork error */ 4916762Sralph #define DOABORT 1 /* abort if dofork fails */ 5012111Sralph 5117463Sralph /* 5217463Sralph * Error tokens 5317463Sralph */ 5417463Sralph #define REPRINT -2 5517463Sralph #define ERROR -1 5617463Sralph #define OK 0 5717463Sralph #define FATALERR 1 5817463Sralph #define NOACCT 2 5917463Sralph #define FILTERERR 3 6017463Sralph #define ACCESS 4 6117463Sralph 6256123Selan static dev_t fdev; /* device of file pointed to by symlink */ 6356123Selan static ino_t fino; /* inode of file pointed to by symlink */ 6456123Selan static FILE *cfp; /* control file */ 6556123Selan static int child; /* id of any filters */ 6656123Selan static int lfd; /* lock file descriptor */ 6756123Selan static int ofd; /* output filter file descriptor */ 6856123Selan static int ofilter; /* id of output filter, if any */ 6956123Selan static int pfd; /* prstatic inter file descriptor */ 7056123Selan static int pid; /* pid of lpd process */ 7156123Selan static int prchild; /* id of pr process */ 7256123Selan static char title[80]; /* ``pr'' title */ 7356123Selan static int tof; /* true if at top of form */ 7412111Sralph 7556123Selan static char class[32]; /* classification field */ 7656123Selan static char fromhost[32]; /* user's host machine */ 7756123Selan /* indentation size in static characters */ 7856123Selan static char indent[10] = "-i0"; 7956123Selan static char jobname[100]; /* job or file name */ 8056123Selan static char length[10] = "-l"; /* page length in lines */ 8156123Selan static char logname[32]; /* user's login name */ 8256123Selan static char pxlength[10] = "-y"; /* page length in pixels */ 8356123Selan static char pxwidth[10] = "-x"; /* page width in pixels */ 8456123Selan static char tempfile[] = "errsXXXXXX"; /* file name for filter output */ 8556123Selan static char width[10] = "-w"; /* page width in static characters */ 8612111Sralph 8755474Sbostic static void abortpr __P((int)); 8855474Sbostic static void banner __P((char *, char *)); 8955474Sbostic static int dofork __P((int)); 9055474Sbostic static int dropit __P((int)); 9155474Sbostic static void init __P((void)); 9255474Sbostic static void openpr __P((void)); 93*69008Stef static void opennet __P((char *)); 94*69008Stef static void opentty __P((void)); 95*69008Stef static void openrem __P((void)); 9655474Sbostic static int print __P((int, char *)); 9755474Sbostic static int printit __P((char *)); 9855474Sbostic static void pstatus __P((const char *, ...)); 9955474Sbostic static char response __P((void)); 10055474Sbostic static void scan_out __P((int, char *, int)); 10155474Sbostic static char *scnline __P((int, char *, int)); 10255474Sbostic static int sendfile __P((int, char *)); 10355474Sbostic static int sendit __P((char *)); 10455474Sbostic static void sendmail __P((char *, int)); 10555474Sbostic static void setty __P((void)); 10655474Sbostic 10755474Sbostic void 10812111Sralph printjob() 10912111Sralph { 11012111Sralph struct stat stb; 11112111Sralph register struct queue *q, **qp; 11212111Sralph struct queue **queue; 11312111Sralph register int i, nitems; 11468972Stef off_t pidoff; 11569007Stef int errcnt, count = 0; 11612111Sralph 11712111Sralph init(); /* set up capabilities */ 11813442Sralph (void) write(1, "", 1); /* ack that daemon is started */ 11925496Seric (void) close(2); /* set up log file */ 12025496Seric if (open(LF, O_WRONLY|O_APPEND, 0664) < 0) { 12125496Seric syslog(LOG_ERR, "%s: %m", LF); 12237968Sbostic (void) open(_PATH_DEVNULL, O_WRONLY); 12325496Seric } 12416762Sralph setgid(getegid()); 12512463Sralph pid = getpid(); /* for use with lprm */ 12612111Sralph setpgrp(0, pid); 12716762Sralph signal(SIGHUP, abortpr); 12816762Sralph signal(SIGINT, abortpr); 12916762Sralph signal(SIGQUIT, abortpr); 13016762Sralph signal(SIGTERM, abortpr); 13112111Sralph 13239954Smckusick (void) mktemp(tempfile); 13315811Sralph 13412111Sralph /* 13512111Sralph * uses short form file names 13612111Sralph */ 13712111Sralph if (chdir(SD) < 0) { 13816762Sralph syslog(LOG_ERR, "%s: %m", SD); 13912111Sralph exit(1); 14012111Sralph } 14112463Sralph if (stat(LO, &stb) == 0 && (stb.st_mode & 0100)) 14212463Sralph exit(0); /* printing disabled */ 14314150Sralph lfd = open(LO, O_WRONLY|O_CREAT, 0644); 14413169Sralph if (lfd < 0) { 14516762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, LO); 14613169Sralph exit(1); 14713169Sralph } 14813169Sralph if (flock(lfd, LOCK_EX|LOCK_NB) < 0) { 14912111Sralph if (errno == EWOULDBLOCK) /* active deamon present */ 15012111Sralph exit(0); 15116762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, LO); 15212111Sralph exit(1); 15312111Sralph } 15413148Ssam ftruncate(lfd, 0); 15512111Sralph /* 15612111Sralph * write process id for others to know 15712111Sralph */ 15812111Sralph sprintf(line, "%u\n", pid); 15912111Sralph pidoff = i = strlen(line); 16012463Sralph if (write(lfd, line, i) != i) { 16116762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, LO); 16212111Sralph exit(1); 16312111Sralph } 16412111Sralph /* 16512111Sralph * search the spool directory for work and sort by queue order. 16612111Sralph */ 16712111Sralph if ((nitems = getq(&queue)) < 0) { 16816762Sralph syslog(LOG_ERR, "%s: can't scan %s", printer, SD); 16912111Sralph exit(1); 17012111Sralph } 17112463Sralph if (nitems == 0) /* no work to do */ 17212111Sralph exit(0); 17313169Sralph if (stb.st_mode & 01) { /* reset queue flag */ 17413169Sralph if (fchmod(lfd, stb.st_mode & 0776) < 0) 17516762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, LO); 17613169Sralph } 17712463Sralph openpr(); /* open printer or remote */ 17812463Sralph again: 17912111Sralph /* 18012111Sralph * we found something to do now do it -- 18112111Sralph * write the name of the current control file into the lock file 18212111Sralph * so the spool queue program can tell what we're working on 18312111Sralph */ 18412111Sralph for (qp = queue; nitems--; free((char *) q)) { 18512111Sralph q = *qp++; 18612111Sralph if (stat(q->q_name, &stb) < 0) 18712111Sralph continue; 18869007Stef errcnt = 0; 18912463Sralph restart: 19068972Stef (void) lseek(lfd, pidoff, 0); 19112111Sralph (void) sprintf(line, "%s\n", q->q_name); 19212111Sralph i = strlen(line); 19312111Sralph if (write(lfd, line, i) != i) 19416762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, LO); 19512111Sralph if (!remote) 19612111Sralph i = printit(q->q_name); 19712111Sralph else 19812111Sralph i = sendit(q->q_name); 19912463Sralph /* 20013169Sralph * Check to see if we are supposed to stop printing or 20113169Sralph * if we are to rebuild the queue. 20212463Sralph */ 20313169Sralph if (fstat(lfd, &stb) == 0) { 20416762Sralph /* stop printing before starting next job? */ 20513169Sralph if (stb.st_mode & 0100) 20613169Sralph goto done; 20716762Sralph /* rebuild queue (after lpc topq) */ 20813169Sralph if (stb.st_mode & 01) { 20913169Sralph for (free((char *) q); nitems--; free((char *) q)) 21013169Sralph q = *qp++; 21113169Sralph if (fchmod(lfd, stb.st_mode & 0776) < 0) 21216762Sralph syslog(LOG_WARNING, "%s: %s: %m", 21316762Sralph printer, LO); 21413169Sralph break; 21513169Sralph } 21613169Sralph } 21717463Sralph if (i == OK) /* file ok and printed */ 21814150Sralph count++; 21969007Stef else if (i == REPRINT && ++errcnt < 5) { 22069007Stef /* try reprinting the job */ 22116762Sralph syslog(LOG_INFO, "restarting %s", printer); 22212111Sralph if (ofilter > 0) { 22312111Sralph kill(ofilter, SIGCONT); /* to be sure */ 22412111Sralph (void) close(ofd); 22512111Sralph while ((i = wait(0)) > 0 && i != ofilter) 22612111Sralph ; 22712111Sralph ofilter = 0; 22812111Sralph } 22912463Sralph (void) close(pfd); /* close printer */ 23015811Sralph if (ftruncate(lfd, pidoff) < 0) 23116762Sralph syslog(LOG_WARNING, "%s: %s: %m", printer, LO); 23212463Sralph openpr(); /* try to reopen printer */ 23312111Sralph goto restart; 23469007Stef } else { 23569007Stef syslog(LOG_WARNING, "%s: job could not be %s (%s)", printer, 23669007Stef remote ? "sent to remote host" : "printed", q->q_name); 23769007Stef if (i == REPRINT) { 23869007Stef /* insure we don't attempt this job again */ 23969007Stef (void) unlink(q->q_name); 24069007Stef q->q_name[0] = 'd'; 24169007Stef (void) unlink(q->q_name); 24269007Stef if (logname[0]) 24369007Stef sendmail(logname, FATALERR); 24469007Stef } 24512111Sralph } 24612111Sralph } 24712111Sralph free((char *) queue); 24812463Sralph /* 24912463Sralph * search the spool directory for more work. 25012463Sralph */ 25112463Sralph if ((nitems = getq(&queue)) < 0) { 25216762Sralph syslog(LOG_ERR, "%s: can't scan %s", printer, SD); 25312463Sralph exit(1); 25412463Sralph } 25512463Sralph if (nitems == 0) { /* no more work to do */ 25612463Sralph done: 25714150Sralph if (count > 0) { /* Files actually printed */ 25814150Sralph if (!SF && !tof) 25914150Sralph (void) write(ofd, FF, strlen(FF)); 26014150Sralph if (TR != NULL) /* output trailer */ 26114150Sralph (void) write(ofd, TR, strlen(TR)); 26214150Sralph } 26339954Smckusick (void) unlink(tempfile); 26412463Sralph exit(0); 26512463Sralph } 26612111Sralph goto again; 26712111Sralph } 26812111Sralph 26912111Sralph char fonts[4][50]; /* fonts for troff */ 27012111Sralph 27137968Sbostic char ifonts[4][40] = { 27237968Sbostic _PATH_VFONTR, 27337968Sbostic _PATH_VFONTI, 27437968Sbostic _PATH_VFONTB, 27537968Sbostic _PATH_VFONTS, 27612111Sralph }; 27712111Sralph 27812111Sralph /* 27912111Sralph * The remaining part is the reading of the control file (cf) 28012111Sralph * and performing the various actions. 28112111Sralph */ 28255474Sbostic static int 28312111Sralph printit(file) 28412111Sralph char *file; 28512111Sralph { 28612111Sralph register int i; 28717463Sralph char *cp; 28817463Sralph int bombed = OK; 28912111Sralph 29012111Sralph /* 29117463Sralph * open control file; ignore if no longer there. 29212111Sralph */ 29312111Sralph if ((cfp = fopen(file, "r")) == NULL) { 29416762Sralph syslog(LOG_INFO, "%s: %s: %m", printer, file); 29517463Sralph return(OK); 29612111Sralph } 29712111Sralph /* 29812111Sralph * Reset troff fonts. 29912111Sralph */ 30012111Sralph for (i = 0; i < 4; i++) 30112111Sralph strcpy(fonts[i], ifonts[i]); 30266833Sbostic sprintf(&width[2], "%d", PW); 30317302Sralph strcpy(indent+2, "0"); 30412111Sralph 30512111Sralph /* 30612111Sralph * read the control file for work to do 30712111Sralph * 30812111Sralph * file format -- first character in the line is a command 30912111Sralph * rest of the line is the argument. 31012111Sralph * valid commands are: 31112111Sralph * 31217463Sralph * S -- "stat info" for symbolic link protection 31312111Sralph * J -- "job name" on banner page 31412111Sralph * C -- "class name" on banner page 31512111Sralph * L -- "literal" user's name to print on banner 31612111Sralph * T -- "title" for pr 31712111Sralph * H -- "host name" of machine where lpr was done 31812111Sralph * P -- "person" user's login name 31912581Sralph * I -- "indent" amount to indent output 32069007Stef * R -- laser dpi "resolution" 32112111Sralph * f -- "file name" name of text file to print 32212111Sralph * l -- "file name" text file with control chars 32312111Sralph * p -- "file name" text file to print with pr(1) 32412111Sralph * t -- "file name" troff(1) file to print 32513233Sralph * n -- "file name" ditroff(1) file to print 32612111Sralph * d -- "file name" dvi file to print 32712111Sralph * g -- "file name" plot(1G) file to print 32812111Sralph * v -- "file name" plain raster file to print 32912111Sralph * c -- "file name" cifplot file to print 33012111Sralph * 1 -- "R font file" for troff 33112111Sralph * 2 -- "I font file" for troff 33212111Sralph * 3 -- "B font file" for troff 33312111Sralph * 4 -- "S font file" for troff 33412111Sralph * N -- "name" of file (used by lpq) 33512111Sralph * U -- "unlink" name of file to remove 33612111Sralph * (after we print it. (Pass 2 only)). 33712111Sralph * M -- "mail" to user when done printing 33812111Sralph * 33912111Sralph * getline reads a line and expands tabs to blanks 34012111Sralph */ 34112111Sralph 34212111Sralph /* pass 1 */ 34312111Sralph 34412111Sralph while (getline(cfp)) 34512111Sralph switch (line[0]) { 34612111Sralph case 'H': 34714150Sralph strcpy(fromhost, line+1); 34812111Sralph if (class[0] == '\0') 34915552Sralph strncpy(class, line+1, sizeof(class)-1); 35012111Sralph continue; 35112111Sralph 35212111Sralph case 'P': 35315552Sralph strncpy(logname, line+1, sizeof(logname)-1); 35412463Sralph if (RS) { /* restricted */ 35555474Sbostic if (getpwnam(logname) == NULL) { 35617463Sralph bombed = NOACCT; 35715811Sralph sendmail(line+1, bombed); 35812463Sralph goto pass2; 35912463Sralph } 36012463Sralph } 36112111Sralph continue; 36212111Sralph 36317463Sralph case 'S': 36417463Sralph cp = line+1; 36517463Sralph i = 0; 36617463Sralph while (*cp >= '0' && *cp <= '9') 36717463Sralph i = i * 10 + (*cp++ - '0'); 36817463Sralph fdev = i; 36917463Sralph cp++; 37017463Sralph i = 0; 37117463Sralph while (*cp >= '0' && *cp <= '9') 37217463Sralph i = i * 10 + (*cp++ - '0'); 37317463Sralph fino = i; 37417463Sralph continue; 37517463Sralph 37612111Sralph case 'J': 37712111Sralph if (line[1] != '\0') 37815552Sralph strncpy(jobname, line+1, sizeof(jobname)-1); 37912111Sralph else 38012111Sralph strcpy(jobname, " "); 38112111Sralph continue; 38212111Sralph 38312111Sralph case 'C': 38412111Sralph if (line[1] != '\0') 38515552Sralph strncpy(class, line+1, sizeof(class)-1); 38612111Sralph else if (class[0] == '\0') 38715811Sralph gethostname(class, sizeof(class)); 38812111Sralph continue; 38912111Sralph 39012111Sralph case 'T': /* header title for pr */ 39115552Sralph strncpy(title, line+1, sizeof(title)-1); 39212111Sralph continue; 39312111Sralph 39412111Sralph case 'L': /* identification line */ 39518127Sralph if (!SH && !HL) 39612111Sralph banner(line+1, jobname); 39712111Sralph continue; 39812111Sralph 39912111Sralph case '1': /* troff fonts */ 40012111Sralph case '2': 40112111Sralph case '3': 40212111Sralph case '4': 40312111Sralph if (line[1] != '\0') 40412111Sralph strcpy(fonts[line[0]-'1'], line+1); 40512111Sralph continue; 40612111Sralph 40712111Sralph case 'W': /* page width */ 40815552Sralph strncpy(width+2, line+1, sizeof(width)-3); 40912111Sralph continue; 41012111Sralph 41112581Sralph case 'I': /* indent amount */ 41215552Sralph strncpy(indent+2, line+1, sizeof(indent)-3); 41312581Sralph continue; 41412581Sralph 41512111Sralph default: /* some file to print */ 41615811Sralph switch (i = print(line[0], line+1)) { 41717463Sralph case ERROR: 41817463Sralph if (bombed == OK) 41917463Sralph bombed = FATALERR; 42015811Sralph break; 42117463Sralph case REPRINT: 42212111Sralph (void) fclose(cfp); 42317463Sralph return(REPRINT); 42417463Sralph case FILTERERR: 42517463Sralph case ACCESS: 42617463Sralph bombed = i; 42715811Sralph sendmail(logname, bombed); 42815811Sralph } 42912111Sralph title[0] = '\0'; 43012111Sralph continue; 43112111Sralph 43212111Sralph case 'N': 43312111Sralph case 'U': 43412111Sralph case 'M': 43569007Stef case 'R': 43612111Sralph continue; 43712111Sralph } 43812111Sralph 43912111Sralph /* pass 2 */ 44012111Sralph 44112463Sralph pass2: 44212111Sralph fseek(cfp, 0L, 0); 44312111Sralph while (getline(cfp)) 44412111Sralph switch (line[0]) { 44518127Sralph case 'L': /* identification line */ 44618127Sralph if (!SH && HL) 44718127Sralph banner(line+1, jobname); 44818127Sralph continue; 44918127Sralph 45012111Sralph case 'M': 45117463Sralph if (bombed < NOACCT) /* already sent if >= NOACCT */ 45215811Sralph sendmail(line+1, bombed); 45312111Sralph continue; 45412111Sralph 45512111Sralph case 'U': 45612111Sralph (void) unlink(line+1); 45712111Sralph } 45812111Sralph /* 45915811Sralph * clean-up in case another control file exists 46012111Sralph */ 46112111Sralph (void) fclose(cfp); 46212111Sralph (void) unlink(file); 46317463Sralph return(bombed == OK ? OK : ERROR); 46412111Sralph } 46512111Sralph 46612111Sralph /* 46712111Sralph * Print a file. 46813233Sralph * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}. 46915811Sralph * Return -1 if a non-recoverable error occured, 47015811Sralph * 2 if the filter detected some errors (but printed the job anyway), 47115811Sralph * 1 if we should try to reprint this job and 47212111Sralph * 0 if all is well. 47312111Sralph * Note: all filters take stdin as the file, stdout as the printer, 47412111Sralph * stderr as the log file, and must not ignore SIGINT. 47512111Sralph */ 47655474Sbostic static int 47712111Sralph print(format, file) 47812111Sralph int format; 47912111Sralph char *file; 48012111Sralph { 48115811Sralph register int n; 48212111Sralph register char *prog; 48315811Sralph int fi, fo; 48439954Smckusick FILE *fp; 48512111Sralph char *av[15], buf[BUFSIZ]; 48612111Sralph int pid, p[2], stopped = 0; 48712111Sralph union wait status; 48817463Sralph struct stat stb; 48912111Sralph 49017463Sralph if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0) 49117463Sralph return(ERROR); 49217463Sralph /* 49317463Sralph * Check to see if data file is a symbolic link. If so, it should 49417463Sralph * still point to the same file or someone is trying to print 49517463Sralph * something he shouldn't. 49617463Sralph */ 49717463Sralph if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 && 49817463Sralph (stb.st_dev != fdev || stb.st_ino != fino)) 49917463Sralph return(ACCESS); 50012111Sralph if (!SF && !tof) { /* start on a fresh page */ 50112111Sralph (void) write(ofd, FF, strlen(FF)); 50212111Sralph tof = 1; 50312111Sralph } 50412111Sralph if (IF == NULL && (format == 'f' || format == 'l')) { 50512111Sralph tof = 0; 50612111Sralph while ((n = read(fi, buf, BUFSIZ)) > 0) 50712111Sralph if (write(ofd, buf, n) != n) { 50812111Sralph (void) close(fi); 50917463Sralph return(REPRINT); 51012111Sralph } 51112111Sralph (void) close(fi); 51217463Sralph return(OK); 51312111Sralph } 51412111Sralph switch (format) { 51512111Sralph case 'p': /* print file using 'pr' */ 51612111Sralph if (IF == NULL) { /* use output filter */ 51737968Sbostic prog = _PATH_PR; 51812111Sralph av[0] = "pr"; 51912111Sralph av[1] = width; 52012111Sralph av[2] = length; 52112111Sralph av[3] = "-h"; 52212111Sralph av[4] = *title ? title : " "; 52312111Sralph av[5] = 0; 52412111Sralph fo = ofd; 52512111Sralph goto start; 52612111Sralph } 52712111Sralph pipe(p); 52812111Sralph if ((prchild = dofork(DORETURN)) == 0) { /* child */ 52912111Sralph dup2(fi, 0); /* file is stdin */ 53012111Sralph dup2(p[1], 1); /* pipe is stdout */ 53168972Stef closelog(); 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 } 61469007Stef if (prog == NULL) { 61569007Stef (void) close(fi); 61669007Stef syslog(LOG_ERR, 61769007Stef "%s: no filter found in printcap for format character '%c'", 61869007Stef printer, format); 61969007Stef return(ERROR); 62069007Stef } 62112111Sralph if ((av[0] = rindex(prog, '/')) != NULL) 62212111Sralph av[0]++; 62312111Sralph else 62412111Sralph av[0] = prog; 62512111Sralph av[n++] = "-n"; 62612111Sralph av[n++] = logname; 62712111Sralph av[n++] = "-h"; 62814150Sralph av[n++] = fromhost; 62912111Sralph av[n++] = AF; 63012111Sralph av[n] = 0; 63112111Sralph fo = pfd; 63212111Sralph if (ofilter > 0) { /* stop output filter */ 63312111Sralph write(ofd, "\031\1", 2); 63446912Sbostic while ((pid = 63546912Sbostic wait3((int *)&status, WUNTRACED, 0)) > 0 && pid != ofilter) 63612111Sralph ; 63712111Sralph if (status.w_stopval != WSTOPPED) { 63812111Sralph (void) close(fi); 63969007Stef syslog(LOG_WARNING, 64069007Stef "%s: output filter died (retcode=%d termsig=%d)", 64169007Stef printer, status.w_retcode, status.w_termsig); 64217463Sralph return(REPRINT); 64312111Sralph } 64412111Sralph stopped++; 64512111Sralph } 64612111Sralph start: 64712111Sralph if ((child = dofork(DORETURN)) == 0) { /* child */ 64812111Sralph dup2(fi, 0); 64912111Sralph dup2(fo, 1); 65039954Smckusick n = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, 0664); 65115811Sralph if (n >= 0) 65215811Sralph dup2(n, 2); 65368972Stef closelog(); 65412111Sralph for (n = 3; n < NOFILE; n++) 65512111Sralph (void) close(n); 65612111Sralph execv(prog, av); 65716762Sralph syslog(LOG_ERR, "cannot execv %s", prog); 65812111Sralph exit(2); 65912111Sralph } 66012111Sralph (void) close(fi); 66112111Sralph if (child < 0) 66212111Sralph status.w_retcode = 100; 66312111Sralph else 66446912Sbostic while ((pid = wait((int *)&status)) > 0 && pid != child) 66512111Sralph ; 66612111Sralph child = 0; 66712111Sralph prchild = 0; 66812111Sralph if (stopped) { /* restart output filter */ 66912111Sralph if (kill(ofilter, SIGCONT) < 0) { 67016762Sralph syslog(LOG_ERR, "cannot restart output filter"); 67112111Sralph exit(1); 67212111Sralph } 67312111Sralph } 67412111Sralph tof = 0; 67539954Smckusick 67639954Smckusick /* Copy filter output to "lf" logfile */ 67739954Smckusick if (fp = fopen(tempfile, "r")) { 67839954Smckusick while (fgets(buf, sizeof(buf), fp)) 67939954Smckusick fputs(buf, stderr); 68056123Selan fclose(fp); 68139954Smckusick } 68239954Smckusick 68315811Sralph if (!WIFEXITED(status)) { 68469007Stef syslog(LOG_WARNING, "%s: filter '%c' terminated (termsig=%d)", 68516762Sralph printer, format, status.w_termsig); 68617463Sralph return(ERROR); 68717463Sralph } 68817463Sralph switch (status.w_retcode) { 68917463Sralph case 0: 69017463Sralph tof = 1; 69117463Sralph return(OK); 69217463Sralph case 1: 69317463Sralph return(REPRINT); 69469007Stef case 2: 69569007Stef return(ERROR); 69617463Sralph default: 69769007Stef syslog(LOG_WARNING, "%s: filter '%c' exited (retcode=%d)", 69816762Sralph printer, format, status.w_retcode); 69969007Stef return(FILTERERR); 70017463Sralph } 70112111Sralph } 70212111Sralph 70312111Sralph /* 70412111Sralph * Send the daemon control file (cf) and any data files. 70512111Sralph * Return -1 if a non-recoverable error occured, 1 if a recoverable error and 70612111Sralph * 0 if all is well. 70712111Sralph */ 70855474Sbostic static int 70912111Sralph sendit(file) 71012111Sralph char *file; 71112111Sralph { 71217463Sralph register int i, err = OK; 71317463Sralph char *cp, last[BUFSIZ]; 71412111Sralph 71512111Sralph /* 71612111Sralph * open control file 71712111Sralph */ 71816762Sralph if ((cfp = fopen(file, "r")) == NULL) 71917463Sralph return(OK); 72012111Sralph /* 72112111Sralph * read the control file for work to do 72212111Sralph * 72312111Sralph * file format -- first character in the line is a command 72412111Sralph * rest of the line is the argument. 72512111Sralph * commands of interest are: 72612111Sralph * 72712111Sralph * a-z -- "file name" name of file to print 72812111Sralph * U -- "unlink" name of file to remove 72912111Sralph * (after we print it. (Pass 2 only)). 73012111Sralph */ 73112111Sralph 73212111Sralph /* 73312111Sralph * pass 1 73412111Sralph */ 73512111Sralph while (getline(cfp)) { 73612111Sralph again: 73717463Sralph if (line[0] == 'S') { 73817463Sralph cp = line+1; 73917463Sralph i = 0; 74017463Sralph while (*cp >= '0' && *cp <= '9') 74117463Sralph i = i * 10 + (*cp++ - '0'); 74217463Sralph fdev = i; 74317463Sralph cp++; 74417463Sralph i = 0; 74517463Sralph while (*cp >= '0' && *cp <= '9') 74617463Sralph i = i * 10 + (*cp++ - '0'); 74717463Sralph fino = i; 74817463Sralph continue; 74917463Sralph } 75012111Sralph if (line[0] >= 'a' && line[0] <= 'z') { 75112111Sralph strcpy(last, line); 75217463Sralph while (i = getline(cfp)) 75312111Sralph if (strcmp(last, line)) 75412111Sralph break; 75517463Sralph switch (sendfile('\3', last+1)) { 75617463Sralph case OK: 75717463Sralph if (i) 75817463Sralph goto again; 75917463Sralph break; 76017463Sralph case REPRINT: 76112111Sralph (void) fclose(cfp); 76217463Sralph return(REPRINT); 76317463Sralph case ACCESS: 76417463Sralph sendmail(logname, ACCESS); 76517463Sralph case ERROR: 76617463Sralph err = ERROR; 76717463Sralph } 76812111Sralph break; 76912111Sralph } 77012111Sralph } 77117463Sralph if (err == OK && sendfile('\2', file) > 0) { 77212111Sralph (void) fclose(cfp); 77317463Sralph return(REPRINT); 77412111Sralph } 77512111Sralph /* 77612111Sralph * pass 2 77712111Sralph */ 77812111Sralph fseek(cfp, 0L, 0); 77912111Sralph while (getline(cfp)) 78012111Sralph if (line[0] == 'U') 78112111Sralph (void) unlink(line+1); 78212111Sralph /* 78317463Sralph * clean-up in case another control file exists 78412111Sralph */ 78512111Sralph (void) fclose(cfp); 78612111Sralph (void) unlink(file); 78717463Sralph return(err); 78812111Sralph } 78912111Sralph 79012111Sralph /* 79112111Sralph * Send a data file to the remote machine and spool it. 79212111Sralph * Return positive if we should try resending. 79312111Sralph */ 79455474Sbostic static int 79512111Sralph sendfile(type, file) 79655474Sbostic int type; 79755474Sbostic char *file; 79812111Sralph { 79912111Sralph register int f, i, amt; 80012111Sralph struct stat stb; 80112111Sralph char buf[BUFSIZ]; 80216762Sralph int sizerr, resp; 80312111Sralph 80417463Sralph if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0) 80517463Sralph return(ERROR); 80617463Sralph /* 80717463Sralph * Check to see if data file is a symbolic link. If so, it should 80817463Sralph * still point to the same file or someone is trying to print something 80917463Sralph * he shouldn't. 81017463Sralph */ 81117463Sralph if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 && 81217463Sralph (stb.st_dev != fdev || stb.st_ino != fino)) 81317463Sralph return(ACCESS); 81468972Stef (void) sprintf(buf, "%c%ld %s\n", type, (long)stb.st_size, file); 81512111Sralph amt = strlen(buf); 81616762Sralph for (i = 0; ; i++) { 81716762Sralph if (write(pfd, buf, amt) != amt || 81816762Sralph (resp = response()) < 0 || resp == '\1') { 81916762Sralph (void) close(f); 82017463Sralph return(REPRINT); 82116762Sralph } else if (resp == '\0') 82216762Sralph break; 82316762Sralph if (i == 0) 82455474Sbostic pstatus("no space on remote; waiting for queue to drain"); 82516762Sralph if (i == 10) 82624861Seric syslog(LOG_ALERT, "%s: can't send to %s; queue full", 82716762Sralph printer, RM); 82816762Sralph sleep(5 * 60); 82912692Sralph } 83016762Sralph if (i) 83155474Sbostic pstatus("sending to %s", RM); 83212111Sralph sizerr = 0; 83312111Sralph for (i = 0; i < stb.st_size; i += BUFSIZ) { 83412111Sralph amt = BUFSIZ; 83512111Sralph if (i + amt > stb.st_size) 83612111Sralph amt = stb.st_size - i; 83712111Sralph if (sizerr == 0 && read(f, buf, amt) != amt) 83812111Sralph sizerr = 1; 83912692Sralph if (write(pfd, buf, amt) != amt) { 84012692Sralph (void) close(f); 84117463Sralph return(REPRINT); 84212692Sralph } 84312111Sralph } 84455474Sbostic 84555474Sbostic 84655474Sbostic 84755474Sbostic 84812111Sralph (void) close(f); 84912111Sralph if (sizerr) { 85016762Sralph syslog(LOG_INFO, "%s: %s: changed size", printer, file); 85117463Sralph /* tell recvjob to ignore this file */ 85217463Sralph (void) write(pfd, "\1", 1); 85317463Sralph return(ERROR); 85417463Sralph } 85517463Sralph if (write(pfd, "", 1) != 1 || response()) 85617463Sralph return(REPRINT); 85717463Sralph return(OK); 85812111Sralph } 85912111Sralph 86012111Sralph /* 86112111Sralph * Check to make sure there have been no errors and that both programs 86212111Sralph * are in sync with eachother. 86312111Sralph * Return non-zero if the connection was lost. 86412111Sralph */ 86555474Sbostic static char 86616762Sralph response() 86712111Sralph { 86812111Sralph char resp; 86912111Sralph 87016762Sralph if (read(pfd, &resp, 1) != 1) { 87116762Sralph syslog(LOG_INFO, "%s: lost connection", printer); 87216762Sralph return(-1); 87312111Sralph } 87416762Sralph return(resp); 87512111Sralph } 87612111Sralph 87712111Sralph /* 87812111Sralph * Banner printing stuff 87912111Sralph */ 88055474Sbostic static void 88112111Sralph banner(name1, name2) 88212111Sralph char *name1, *name2; 88312111Sralph { 88412111Sralph time_t tvec; 88512111Sralph extern char *ctime(); 88612111Sralph 88712111Sralph time(&tvec); 88812111Sralph if (!SF && !tof) 88912111Sralph (void) write(ofd, FF, strlen(FF)); 89012111Sralph if (SB) { /* short banner only */ 89112111Sralph if (class[0]) { 89212111Sralph (void) write(ofd, class, strlen(class)); 89312111Sralph (void) write(ofd, ":", 1); 89412111Sralph } 89512111Sralph (void) write(ofd, name1, strlen(name1)); 89612111Sralph (void) write(ofd, " Job: ", 7); 89712111Sralph (void) write(ofd, name2, strlen(name2)); 89812111Sralph (void) write(ofd, " Date: ", 8); 89912111Sralph (void) write(ofd, ctime(&tvec), 24); 90012111Sralph (void) write(ofd, "\n", 1); 90112111Sralph } else { /* normal banner */ 90212111Sralph (void) write(ofd, "\n\n\n", 3); 90312111Sralph scan_out(ofd, name1, '\0'); 90412111Sralph (void) write(ofd, "\n\n", 2); 90512111Sralph scan_out(ofd, name2, '\0'); 90612111Sralph if (class[0]) { 90712111Sralph (void) write(ofd,"\n\n\n",3); 90812111Sralph scan_out(ofd, class, '\0'); 90912111Sralph } 91012111Sralph (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15); 91112111Sralph (void) write(ofd, name2, strlen(name2)); 91212111Sralph (void) write(ofd, "\n\t\t\t\t\tDate: ", 12); 91312111Sralph (void) write(ofd, ctime(&tvec), 24); 91412111Sralph (void) write(ofd, "\n", 1); 91512111Sralph } 91612111Sralph if (!SF) 91712111Sralph (void) write(ofd, FF, strlen(FF)); 91812111Sralph tof = 1; 91912111Sralph } 92012111Sralph 92155474Sbostic static char * 92212111Sralph scnline(key, p, c) 92355474Sbostic register int key; 92455474Sbostic register char *p; 92555474Sbostic int c; 92612111Sralph { 92712111Sralph register scnwidth; 92812111Sralph 92912111Sralph for (scnwidth = WIDTH; --scnwidth;) { 93012111Sralph key <<= 1; 93112111Sralph *p++ = key & 0200 ? c : BACKGND; 93212111Sralph } 93312111Sralph return (p); 93412111Sralph } 93512111Sralph 93612111Sralph #define TRC(q) (((q)-' ')&0177) 93712111Sralph 93855474Sbostic static void 93912111Sralph scan_out(scfd, scsp, dlm) 94055474Sbostic int scfd, dlm; 94155474Sbostic char *scsp; 94212111Sralph { 94312111Sralph register char *strp; 94412111Sralph register nchrs, j; 94512111Sralph char outbuf[LINELEN+1], *sp, c, cc; 94612111Sralph int d, scnhgt; 94712111Sralph extern char scnkey[][HEIGHT]; /* in lpdchar.c */ 94812111Sralph 94912111Sralph for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) { 95012111Sralph strp = &outbuf[0]; 95112111Sralph sp = scsp; 95212111Sralph for (nchrs = 0; ; ) { 95312111Sralph d = dropit(c = TRC(cc = *sp++)); 95412111Sralph if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d)) 95512111Sralph for (j = WIDTH; --j;) 95612111Sralph *strp++ = BACKGND; 95712111Sralph else 95812111Sralph strp = scnline(scnkey[c][scnhgt-1-d], strp, cc); 95912111Sralph if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1) 96012111Sralph break; 96112111Sralph *strp++ = BACKGND; 96212111Sralph *strp++ = BACKGND; 96312111Sralph } 96412111Sralph while (*--strp == BACKGND && strp >= outbuf) 96512111Sralph ; 96612111Sralph strp++; 96712111Sralph *strp++ = '\n'; 96812111Sralph (void) write(scfd, outbuf, strp-outbuf); 96912111Sralph } 97012111Sralph } 97112111Sralph 97255474Sbostic static int 97312111Sralph dropit(c) 97455474Sbostic int c; 97512111Sralph { 97612111Sralph switch(c) { 97712111Sralph 97812111Sralph case TRC('_'): 97912111Sralph case TRC(';'): 98012111Sralph case TRC(','): 98112111Sralph case TRC('g'): 98212111Sralph case TRC('j'): 98312111Sralph case TRC('p'): 98412111Sralph case TRC('q'): 98512111Sralph case TRC('y'): 98612111Sralph return (DROP); 98712111Sralph 98812111Sralph default: 98912111Sralph return (0); 99012111Sralph } 99112111Sralph } 99212111Sralph 99312111Sralph /* 99412111Sralph * sendmail --- 99512111Sralph * tell people about job completion 99612111Sralph */ 99755474Sbostic static void 99815811Sralph sendmail(user, bombed) 99915811Sralph char *user; 100012111Sralph int bombed; 100112111Sralph { 100212111Sralph register int i; 100315811Sralph int p[2], s; 100412111Sralph register char *cp; 100512111Sralph char buf[100]; 100615811Sralph struct stat stb; 100715811Sralph FILE *fp; 100812111Sralph 100912111Sralph pipe(p); 101015811Sralph if ((s = dofork(DORETURN)) == 0) { /* child */ 101112111Sralph dup2(p[0], 0); 101268972Stef closelog(); 101312111Sralph for (i = 3; i < NOFILE; i++) 101412111Sralph (void) close(i); 101537968Sbostic if ((cp = rindex(_PATH_SENDMAIL, '/')) != NULL) 101612111Sralph cp++; 101755474Sbostic else 101837968Sbostic cp = _PATH_SENDMAIL; 101915811Sralph sprintf(buf, "%s@%s", user, fromhost); 102037968Sbostic execl(_PATH_SENDMAIL, cp, buf, 0); 102112111Sralph exit(0); 102215811Sralph } else if (s > 0) { /* parent */ 102312111Sralph dup2(p[1], 1); 102415811Sralph printf("To: %s@%s\n", user, fromhost); 102569007Stef printf("Subject: %s printer job \"%s\"\n", printer, 102669007Stef *jobname ? jobname : "<unknown>"); 102769007Stef printf("Reply-To: root@%s\n\n", host); 102812111Sralph printf("Your printer job "); 102912111Sralph if (*jobname) 103012111Sralph printf("(%s) ", jobname); 103112463Sralph switch (bombed) { 103217463Sralph case OK: 103312463Sralph printf("\ncompleted successfully\n"); 1034*69008Stef cp = "OK"; 103512463Sralph break; 103612463Sralph default: 103717463Sralph case FATALERR: 103812463Sralph printf("\ncould not be printed\n"); 1039*69008Stef cp = "FATALERR"; 104012463Sralph break; 104117463Sralph case NOACCT: 104212463Sralph printf("\ncould not be printed without an account on %s\n", host); 1043*69008Stef cp = "NOACCT"; 104412463Sralph break; 104517463Sralph case FILTERERR: 104639954Smckusick if (stat(tempfile, &stb) < 0 || stb.st_size == 0 || 104739954Smckusick (fp = fopen(tempfile, "r")) == NULL) { 104869007Stef printf("\nhad some errors and may not have printed\n"); 104915811Sralph break; 105015811Sralph } 105169007Stef printf("\nhad the following errors and may not have printed:\n"); 105215811Sralph while ((i = getc(fp)) != EOF) 105315811Sralph putchar(i); 105415811Sralph (void) fclose(fp); 1055*69008Stef cp = "FILTERERR"; 105617463Sralph break; 105717463Sralph case ACCESS: 105817463Sralph printf("\nwas not printed because it was not linked to the original file\n"); 1059*69008Stef cp = "ACCESS"; 106012463Sralph } 106112111Sralph fflush(stdout); 106212111Sralph (void) close(1); 106312111Sralph } 106412111Sralph (void) close(p[0]); 106512111Sralph (void) close(p[1]); 106615811Sralph wait(&s); 1067*69008Stef syslog(LOG_INFO, "mail sent to user %s about job %s on printer %s (%s)", 1068*69008Stef user, *jobname ? jobname : "<unknown>", printer, cp); 106912111Sralph } 107012111Sralph 107112111Sralph /* 107212111Sralph * dofork - fork with retries on failure 107312111Sralph */ 107455474Sbostic static int 107512111Sralph dofork(action) 107612111Sralph int action; 107712111Sralph { 107812111Sralph register int i, pid; 107912111Sralph 108012111Sralph for (i = 0; i < 20; i++) { 108112463Sralph if ((pid = fork()) < 0) { 108212111Sralph sleep((unsigned)(i*i)); 108312463Sralph continue; 108412463Sralph } 108512463Sralph /* 108612463Sralph * Child should run as daemon instead of root 108712463Sralph */ 108812463Sralph if (pid == 0) 108912463Sralph setuid(DU); 109012463Sralph return(pid); 109112111Sralph } 109216762Sralph syslog(LOG_ERR, "can't fork"); 109312111Sralph 109412111Sralph switch (action) { 109512111Sralph case DORETURN: 109612111Sralph return (-1); 109712111Sralph default: 109816762Sralph syslog(LOG_ERR, "bad action (%d) to dofork", action); 109912111Sralph /*FALL THRU*/ 110012111Sralph case DOABORT: 110112111Sralph exit(1); 110212111Sralph } 110312111Sralph /*NOTREACHED*/ 110412111Sralph } 110512111Sralph 110612111Sralph /* 110716762Sralph * Kill child processes to abort current job. 110812111Sralph */ 110955474Sbostic static void 111055474Sbostic abortpr(signo) 111155474Sbostic int signo; 111212111Sralph { 111339954Smckusick (void) unlink(tempfile); 111412111Sralph kill(0, SIGINT); 111512111Sralph if (ofilter > 0) 111612111Sralph kill(ofilter, SIGCONT); 111746912Sbostic while (wait(NULL) > 0) 111812111Sralph ; 111912111Sralph exit(0); 112012111Sralph } 112112111Sralph 112255474Sbostic static void 112312111Sralph init() 112412111Sralph { 112512111Sralph int status; 112638736Stef char *s; 112712111Sralph 112856123Selan if ((status = cgetent(&bp, printcapdb, printer)) == -2) { 112925468Stef syslog(LOG_ERR, "can't open printer description file"); 113025468Stef exit(1); 113156123Selan } else if (status == -1) { 113225468Stef syslog(LOG_ERR, "unknown printer: %s", printer); 113325468Stef exit(1); 113456123Selan } else if (status == -3) 113556123Selan fatal("potential reference loop detected in printcap file"); 113656123Selan 113756123Selan if (cgetstr(bp, "lp", &LP) == -1) 113837968Sbostic LP = _PATH_DEFDEVLP; 113956123Selan if (cgetstr(bp, "rp", &RP) == -1) 114012463Sralph RP = DEFLP; 114156123Selan if (cgetstr(bp, "lo", &LO) == -1) 114212111Sralph LO = DEFLOCK; 114356123Selan if (cgetstr(bp, "st", &ST) == -1) 114412111Sralph ST = DEFSTAT; 114556123Selan if (cgetstr(bp, "lf", &LF) == -1) 114637968Sbostic LF = _PATH_CONSOLE; 114756123Selan if (cgetstr(bp, "sd", &SD) == -1) 114837968Sbostic SD = _PATH_DEFSPOOL; 114956123Selan if (cgetnum(bp, "du", &DU) < 0) 115012111Sralph DU = DEFUID; 115156123Selan if (cgetstr(bp,"ff", &FF) == -1) 115212111Sralph FF = DEFFF; 115356123Selan if (cgetnum(bp, "pw", &PW) < 0) 115412111Sralph PW = DEFWIDTH; 115512111Sralph sprintf(&width[2], "%d", PW); 115656123Selan if (cgetnum(bp, "pl", &PL) < 0) 115712111Sralph PL = DEFLENGTH; 115812111Sralph sprintf(&length[2], "%d", PL); 115956123Selan if (cgetnum(bp,"px", &PX) < 0) 116012463Sralph PX = 0; 116112463Sralph sprintf(&pxwidth[2], "%d", PX); 116256123Selan if (cgetnum(bp, "py", &PY) < 0) 116312463Sralph PY = 0; 116412463Sralph sprintf(&pxlength[2], "%d", PY); 116556123Selan cgetstr(bp, "rm", &RM); 116638736Stef if (s = checkremote()) 116738736Stef syslog(LOG_WARNING, s); 116825468Stef 116956123Selan cgetstr(bp, "af", &AF); 117056123Selan cgetstr(bp, "of", &OF); 117156123Selan cgetstr(bp, "if", &IF); 117256123Selan cgetstr(bp, "rf", &RF); 117356123Selan cgetstr(bp, "tf", &TF); 117456123Selan cgetstr(bp, "nf", &NF); 117556123Selan cgetstr(bp, "df", &DF); 117656123Selan cgetstr(bp, "gf", &GF); 117756123Selan cgetstr(bp, "vf", &VF); 117856123Selan cgetstr(bp, "cf", &CF); 117956123Selan cgetstr(bp, "tr", &TR); 118056123Selan 118156123Selan RS = (cgetcap(bp, "rs", ':') != NULL); 118256123Selan SF = (cgetcap(bp, "sf", ':') != NULL); 118356123Selan SH = (cgetcap(bp, "sh", ':') != NULL); 118456123Selan SB = (cgetcap(bp, "sb", ':') != NULL); 118556123Selan HL = (cgetcap(bp, "hl", ':') != NULL); 118656123Selan RW = (cgetcap(bp, "rw", ':') != NULL); 118756123Selan 118856123Selan cgetnum(bp, "br", &BR); 118956123Selan if (cgetnum(bp, "fc", &FC) < 0) 119012111Sralph FC = 0; 119156123Selan if (cgetnum(bp, "fs", &FS) < 0) 119212111Sralph FS = 0; 119356123Selan if (cgetnum(bp, "xc", &XC) < 0) 119412111Sralph XC = 0; 119556123Selan if (cgetnum(bp, "xs", &XS) < 0) 119612111Sralph XS = 0; 119756123Selan 119856123Selan tof = (cgetcap(bp, "fo", ':') == NULL); 119912111Sralph } 120012111Sralph 120112463Sralph /* 120212463Sralph * Acquire line printer or remote connection. 120312463Sralph */ 120455474Sbostic static void 120512463Sralph openpr() 120612463Sralph { 1207*69008Stef register int i; 1208*69008Stef char *cp; 120912463Sralph 1210*69008Stef if (!remote && *LP) { 1211*69008Stef if (cp = index(LP, '@')) 1212*69008Stef opennet(cp); 1213*69008Stef else 1214*69008Stef opentty(); 1215*69008Stef } else if (remote) { 1216*69008Stef openrem(); 121712463Sralph } else { 121816762Sralph syslog(LOG_ERR, "%s: no line printer device or host name", 121916762Sralph printer); 122012463Sralph exit(1); 122112463Sralph } 1222*69008Stef 122312463Sralph /* 122412463Sralph * Start up an output filter, if needed. 122512463Sralph */ 122640049Stef if (!remote && OF) { 122712463Sralph int p[2]; 122812463Sralph 122912463Sralph pipe(p); 123012463Sralph if ((ofilter = dofork(DOABORT)) == 0) { /* child */ 123112463Sralph dup2(p[0], 0); /* pipe is std in */ 123212463Sralph dup2(pfd, 1); /* printer is std out */ 123368972Stef closelog(); 123412463Sralph for (i = 3; i < NOFILE; i++) 123512463Sralph (void) close(i); 123612463Sralph if ((cp = rindex(OF, '/')) == NULL) 123712463Sralph cp = OF; 123812463Sralph else 123912463Sralph cp++; 124012463Sralph execl(OF, cp, width, length, 0); 124116762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, OF); 124212463Sralph exit(1); 124312463Sralph } 124412463Sralph (void) close(p[0]); /* close input side */ 124512463Sralph ofd = p[1]; /* use pipe for output */ 124612463Sralph } else { 124712463Sralph ofd = pfd; 124812463Sralph ofilter = 0; 124912463Sralph } 125012463Sralph } 125112463Sralph 1252*69008Stef /* 1253*69008Stef * Printer connected directly to the network 1254*69008Stef * or to a terminal server on the net 1255*69008Stef */ 1256*69008Stef static void 1257*69008Stef opennet(cp) 1258*69008Stef char *cp; 1259*69008Stef { 1260*69008Stef register int i; 1261*69008Stef int resp, port; 1262*69008Stef 1263*69008Stef *cp++ = '\0'; 1264*69008Stef port = atoi(cp); 1265*69008Stef if (port <= 0) { 1266*69008Stef syslog(LOG_ERR, "%s: bad port number: %s", printer, cp); 1267*69008Stef exit(1); 1268*69008Stef } 1269*69008Stef 1270*69008Stef for (i = 1; ; i = i < 256 ? i << 1 : i) { 1271*69008Stef resp = -1; 1272*69008Stef pfd = getport(LP, port); 1273*69008Stef if (pfd < 0 && errno == ECONNREFUSED) 1274*69008Stef resp = 1; 1275*69008Stef else if (pfd >= 0) { 1276*69008Stef /* 1277*69008Stef * need to delay a bit for rs232 lines 1278*69008Stef * to stabilize in case printer is 1279*69008Stef * connected via a terminal server 1280*69008Stef */ 1281*69008Stef delay(500); 1282*69008Stef break; 1283*69008Stef } 1284*69008Stef if (i == 1) { 1285*69008Stef if (resp < 0) 1286*69008Stef pstatus("waiting for %s to come up", LP); 1287*69008Stef else 1288*69008Stef pstatus("waiting for access to printer on %s", LP); 1289*69008Stef } 1290*69008Stef sleep(i); 1291*69008Stef } 1292*69008Stef pstatus("sending to %s port %d", LP, port); 1293*69008Stef *(--cp) = '@'; /* restore LP parameter in case we are called again */ 1294*69008Stef } 1295*69008Stef 1296*69008Stef /* 1297*69008Stef * Printer is connected to an RS232 port on this host 1298*69008Stef */ 1299*69008Stef static void 1300*69008Stef opentty() 1301*69008Stef { 1302*69008Stef register int i; 1303*69008Stef int resp, port; 1304*69008Stef 1305*69008Stef for (i = 1; ; i = i < 32 ? i << 1 : i) { 1306*69008Stef pfd = open(LP, RW ? O_RDWR : O_WRONLY); 1307*69008Stef if (pfd >= 0) { 1308*69008Stef delay(500); 1309*69008Stef break; 1310*69008Stef } 1311*69008Stef if (errno == ENOENT) { 1312*69008Stef syslog(LOG_ERR, "%s: %m", LP); 1313*69008Stef exit(1); 1314*69008Stef } 1315*69008Stef if (i == 1) 1316*69008Stef pstatus("waiting for %s to become ready (offline ?)", 1317*69008Stef printer); 1318*69008Stef sleep(i); 1319*69008Stef } 1320*69008Stef if (isatty(pfd)) 1321*69008Stef setty(); 1322*69008Stef pstatus("%s is ready and printing", printer); 1323*69008Stef } 1324*69008Stef 1325*69008Stef /* 1326*69008Stef * Printer is on a remote host 1327*69008Stef */ 1328*69008Stef static void 1329*69008Stef openrem() 1330*69008Stef { 1331*69008Stef register int i, n; 1332*69008Stef int resp, port; 1333*69008Stef 1334*69008Stef for (i = 1; ; i = i < 256 ? i << 1 : i) { 1335*69008Stef resp = -1; 1336*69008Stef pfd = getport(RM, 0); 1337*69008Stef if (pfd >= 0) { 1338*69008Stef (void) sprintf(line, "\2%s\n", RP); 1339*69008Stef n = strlen(line); 1340*69008Stef if (write(pfd, line, n) == n && 1341*69008Stef (resp = response()) == '\0') 1342*69008Stef break; 1343*69008Stef (void) close(pfd); 1344*69008Stef } 1345*69008Stef if (i == 1) { 1346*69008Stef if (resp < 0) 1347*69008Stef pstatus("waiting for %s to come up", RM); 1348*69008Stef else { 1349*69008Stef pstatus("waiting for queue to be enabled on %s", 1350*69008Stef RM); 1351*69008Stef i = 256; 1352*69008Stef } 1353*69008Stef } 1354*69008Stef sleep(i); 1355*69008Stef } 1356*69008Stef pstatus("sending to %s", RM); 1357*69008Stef } 1358*69008Stef 135912111Sralph struct bauds { 136012111Sralph int baud; 136112111Sralph int speed; 136212111Sralph } bauds[] = { 136312111Sralph 50, B50, 136412111Sralph 75, B75, 136512111Sralph 110, B110, 136612111Sralph 134, B134, 136712111Sralph 150, B150, 136812111Sralph 200, B200, 136912111Sralph 300, B300, 137012111Sralph 600, B600, 137112111Sralph 1200, B1200, 137212111Sralph 1800, B1800, 137312111Sralph 2400, B2400, 137412111Sralph 4800, B4800, 137512111Sralph 9600, B9600, 137612111Sralph 19200, EXTA, 137712111Sralph 38400, EXTB, 137812111Sralph 0, 0 137912111Sralph }; 138012111Sralph 138112111Sralph /* 138212111Sralph * setup tty lines. 138312111Sralph */ 138455474Sbostic static void 138512111Sralph setty() 138612111Sralph { 138712111Sralph struct sgttyb ttybuf; 138812111Sralph register struct bauds *bp; 138912111Sralph 139012111Sralph if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) { 139116762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer); 139212111Sralph exit(1); 139312111Sralph } 139412111Sralph if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) { 139516762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCGETP): %m", printer); 139612111Sralph exit(1); 139712111Sralph } 139812111Sralph if (BR > 0) { 139912111Sralph for (bp = bauds; bp->baud; bp++) 140012111Sralph if (BR == bp->baud) 140112111Sralph break; 140212111Sralph if (!bp->baud) { 140316762Sralph syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR); 140412111Sralph exit(1); 140512111Sralph } 140612111Sralph ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed; 140712111Sralph } 140813169Sralph ttybuf.sg_flags &= ~FC; 140913169Sralph ttybuf.sg_flags |= FS; 141012111Sralph if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) { 141116762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCSETP): %m", printer); 141212111Sralph exit(1); 141312111Sralph } 141412111Sralph if (XC) { 141512111Sralph if (ioctl(pfd, TIOCLBIC, &XC) < 0) { 141616762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCLBIC): %m", printer); 141712111Sralph exit(1); 141812111Sralph } 141912111Sralph } 142012111Sralph if (XS) { 142112111Sralph if (ioctl(pfd, TIOCLBIS, &XS) < 0) { 142216762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCLBIS): %m", printer); 142312111Sralph exit(1); 142412111Sralph } 142512111Sralph } 142612111Sralph } 142712463Sralph 142855474Sbostic #if __STDC__ 142955474Sbostic #include <stdarg.h> 143055474Sbostic #else 143155474Sbostic #include <varargs.h> 143255474Sbostic #endif 143355474Sbostic 143455474Sbostic void 143555474Sbostic #if __STDC__ 143655474Sbostic pstatus(const char *msg, ...) 143755474Sbostic #else 143855474Sbostic pstatus(msg, va_alist) 143912463Sralph char *msg; 144055474Sbostic va_dcl 144155474Sbostic #endif 144212463Sralph { 144312463Sralph register int fd; 144412463Sralph char buf[BUFSIZ]; 144555474Sbostic va_list ap; 144655474Sbostic #if __STDC__ 144755474Sbostic va_start(ap, msg); 144855474Sbostic #else 144955474Sbostic va_start(ap); 145055474Sbostic #endif 145112463Sralph 145212463Sralph umask(0); 145313148Ssam fd = open(ST, O_WRONLY|O_CREAT, 0664); 145416762Sralph if (fd < 0 || flock(fd, LOCK_EX) < 0) { 145516762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, ST); 145616762Sralph exit(1); 145716762Sralph } 145813148Ssam ftruncate(fd, 0); 145955474Sbostic (void)vsnprintf(buf, sizeof(buf), msg, ap); 146055474Sbostic va_end(ap); 146112463Sralph strcat(buf, "\n"); 146212463Sralph (void) write(fd, buf, strlen(buf)); 146312463Sralph (void) close(fd); 146412463Sralph } 1465