122437Sdist /* 222437Sdist * Copyright (c) 1983 Regents of the University of California. 334203Sbostic * All rights reserved. 434203Sbostic * 534203Sbostic * Redistribution and use in source and binary forms are permitted 634936Sbostic * provided that the above copyright notice and this paragraph are 734936Sbostic * duplicated in all such forms and that any documentation, 834936Sbostic * advertising materials, and other materials related to such 934936Sbostic * distribution and use acknowledge that the software was developed 1034936Sbostic * by the University of California, Berkeley. The name of the 1134936Sbostic * University may not be used to endorse or promote products derived 1234936Sbostic * from this software without specific prior written permission. 1334936Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1434936Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1534936Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1622437Sdist */ 1722437Sdist 1813954Ssam #ifndef lint 19*39954Smckusick static char sccsid[] = "@(#)printjob.c 5.10 (Berkeley) 01/30/90"; 2034203Sbostic #endif /* not lint */ 2113954Ssam 2212111Sralph /* 2312111Sralph * printjob -- print jobs in the queue. 2412111Sralph * 2512111Sralph * NOTE: the lock file is used to pass information to lpq and lprm. 2612111Sralph * it does not need to be removed because file locks are dynamic. 2712111Sralph */ 2812111Sralph 2912111Sralph #include "lp.h" 3037968Sbostic #include "pathnames.h" 3112111Sralph 3216762Sralph #define DORETURN 0 /* absorb fork error */ 3316762Sralph #define DOABORT 1 /* abort if dofork fails */ 3412111Sralph 3517463Sralph /* 3617463Sralph * Error tokens 3717463Sralph */ 3817463Sralph #define REPRINT -2 3917463Sralph #define ERROR -1 4017463Sralph #define OK 0 4117463Sralph #define FATALERR 1 4217463Sralph #define NOACCT 2 4317463Sralph #define FILTERERR 3 4417463Sralph #define ACCESS 4 4517463Sralph 4616762Sralph char title[80]; /* ``pr'' title */ 4716762Sralph FILE *cfp; /* control file */ 4816762Sralph int pfd; /* printer file descriptor */ 4916762Sralph int ofd; /* output filter file descriptor */ 5016762Sralph int lfd; /* lock file descriptor */ 5116762Sralph int pid; /* pid of lpd process */ 5216762Sralph int prchild; /* id of pr process */ 5316762Sralph int child; /* id of any filters */ 5416762Sralph int ofilter; /* id of output filter, if any */ 5516762Sralph int tof; /* true if at top of form */ 5616762Sralph int remote; /* true if sending files to remote */ 5717463Sralph dev_t fdev; /* device of file pointed to by symlink */ 5817463Sralph ino_t fino; /* inode of file pointed to by symlink */ 5912111Sralph 6016762Sralph char fromhost[32]; /* user's host machine */ 6116762Sralph char logname[32]; /* user's login name */ 6216762Sralph char jobname[100]; /* job or file name */ 6316762Sralph char class[32]; /* classification field */ 6416762Sralph char width[10] = "-w"; /* page width in characters */ 6516762Sralph char length[10] = "-l"; /* page length in lines */ 6616762Sralph char pxwidth[10] = "-x"; /* page width in pixels */ 6716762Sralph char pxlength[10] = "-y"; /* page length in pixels */ 6816762Sralph char indent[10] = "-i0"; /* indentation size in characters */ 69*39954Smckusick char tempfile[] = "errsXXXXXX"; /* file name for filter output */ 7012111Sralph 7112111Sralph printjob() 7212111Sralph { 7312111Sralph struct stat stb; 7412111Sralph register struct queue *q, **qp; 7512111Sralph struct queue **queue; 7612111Sralph register int i, nitems; 7712111Sralph long pidoff; 7816762Sralph int count = 0; 7916762Sralph extern int abortpr(); 8012111Sralph 8112111Sralph init(); /* set up capabilities */ 8213442Sralph (void) write(1, "", 1); /* ack that daemon is started */ 8325496Seric (void) close(2); /* set up log file */ 8425496Seric if (open(LF, O_WRONLY|O_APPEND, 0664) < 0) { 8525496Seric syslog(LOG_ERR, "%s: %m", LF); 8637968Sbostic (void) open(_PATH_DEVNULL, O_WRONLY); 8725496Seric } 8816762Sralph setgid(getegid()); 8912463Sralph pid = getpid(); /* for use with lprm */ 9012111Sralph setpgrp(0, pid); 9116762Sralph signal(SIGHUP, abortpr); 9216762Sralph signal(SIGINT, abortpr); 9316762Sralph signal(SIGQUIT, abortpr); 9416762Sralph signal(SIGTERM, abortpr); 9512111Sralph 96*39954Smckusick (void) mktemp(tempfile); 9715811Sralph 9812111Sralph /* 9912111Sralph * uses short form file names 10012111Sralph */ 10112111Sralph if (chdir(SD) < 0) { 10216762Sralph syslog(LOG_ERR, "%s: %m", SD); 10312111Sralph exit(1); 10412111Sralph } 10512463Sralph if (stat(LO, &stb) == 0 && (stb.st_mode & 0100)) 10612463Sralph exit(0); /* printing disabled */ 10714150Sralph lfd = open(LO, O_WRONLY|O_CREAT, 0644); 10813169Sralph if (lfd < 0) { 10916762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, LO); 11013169Sralph exit(1); 11113169Sralph } 11213169Sralph if (flock(lfd, LOCK_EX|LOCK_NB) < 0) { 11312111Sralph if (errno == EWOULDBLOCK) /* active deamon present */ 11412111Sralph exit(0); 11516762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, LO); 11612111Sralph exit(1); 11712111Sralph } 11813148Ssam ftruncate(lfd, 0); 11912111Sralph /* 12012111Sralph * write process id for others to know 12112111Sralph */ 12212111Sralph sprintf(line, "%u\n", pid); 12312111Sralph pidoff = i = strlen(line); 12412463Sralph if (write(lfd, line, i) != i) { 12516762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, LO); 12612111Sralph exit(1); 12712111Sralph } 12812111Sralph /* 12912111Sralph * search the spool directory for work and sort by queue order. 13012111Sralph */ 13112111Sralph if ((nitems = getq(&queue)) < 0) { 13216762Sralph syslog(LOG_ERR, "%s: can't scan %s", printer, SD); 13312111Sralph exit(1); 13412111Sralph } 13512463Sralph if (nitems == 0) /* no work to do */ 13612111Sralph exit(0); 13713169Sralph if (stb.st_mode & 01) { /* reset queue flag */ 13813169Sralph if (fchmod(lfd, stb.st_mode & 0776) < 0) 13916762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, LO); 14013169Sralph } 14112463Sralph openpr(); /* open printer or remote */ 14212463Sralph again: 14312111Sralph /* 14412111Sralph * we found something to do now do it -- 14512111Sralph * write the name of the current control file into the lock file 14612111Sralph * so the spool queue program can tell what we're working on 14712111Sralph */ 14812111Sralph for (qp = queue; nitems--; free((char *) q)) { 14912111Sralph q = *qp++; 15012111Sralph if (stat(q->q_name, &stb) < 0) 15112111Sralph continue; 15212463Sralph restart: 15312111Sralph (void) lseek(lfd, pidoff, 0); 15412111Sralph (void) sprintf(line, "%s\n", q->q_name); 15512111Sralph i = strlen(line); 15612111Sralph if (write(lfd, line, i) != i) 15716762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, LO); 15812111Sralph if (!remote) 15912111Sralph i = printit(q->q_name); 16012111Sralph else 16112111Sralph i = sendit(q->q_name); 16212463Sralph /* 16313169Sralph * Check to see if we are supposed to stop printing or 16413169Sralph * if we are to rebuild the queue. 16512463Sralph */ 16613169Sralph if (fstat(lfd, &stb) == 0) { 16716762Sralph /* stop printing before starting next job? */ 16813169Sralph if (stb.st_mode & 0100) 16913169Sralph goto done; 17016762Sralph /* rebuild queue (after lpc topq) */ 17113169Sralph if (stb.st_mode & 01) { 17213169Sralph for (free((char *) q); nitems--; free((char *) q)) 17313169Sralph q = *qp++; 17413169Sralph if (fchmod(lfd, stb.st_mode & 0776) < 0) 17516762Sralph syslog(LOG_WARNING, "%s: %s: %m", 17616762Sralph printer, LO); 17713169Sralph break; 17813169Sralph } 17913169Sralph } 18017463Sralph if (i == OK) /* file ok and printed */ 18114150Sralph count++; 18217463Sralph else if (i == REPRINT) { /* try reprinting the job */ 18316762Sralph syslog(LOG_INFO, "restarting %s", printer); 18412111Sralph if (ofilter > 0) { 18512111Sralph kill(ofilter, SIGCONT); /* to be sure */ 18612111Sralph (void) close(ofd); 18712111Sralph while ((i = wait(0)) > 0 && i != ofilter) 18812111Sralph ; 18912111Sralph ofilter = 0; 19012111Sralph } 19112463Sralph (void) close(pfd); /* close printer */ 19215811Sralph if (ftruncate(lfd, pidoff) < 0) 19316762Sralph syslog(LOG_WARNING, "%s: %s: %m", printer, LO); 19412463Sralph openpr(); /* try to reopen printer */ 19512111Sralph goto restart; 19612111Sralph } 19712111Sralph } 19812111Sralph free((char *) queue); 19912463Sralph /* 20012463Sralph * search the spool directory for more work. 20112463Sralph */ 20212463Sralph if ((nitems = getq(&queue)) < 0) { 20316762Sralph syslog(LOG_ERR, "%s: can't scan %s", printer, SD); 20412463Sralph exit(1); 20512463Sralph } 20612463Sralph if (nitems == 0) { /* no more work to do */ 20712463Sralph done: 20814150Sralph if (count > 0) { /* Files actually printed */ 20914150Sralph if (!SF && !tof) 21014150Sralph (void) write(ofd, FF, strlen(FF)); 21114150Sralph if (TR != NULL) /* output trailer */ 21214150Sralph (void) write(ofd, TR, strlen(TR)); 21314150Sralph } 214*39954Smckusick (void) unlink(tempfile); 21512463Sralph exit(0); 21612463Sralph } 21712111Sralph goto again; 21812111Sralph } 21912111Sralph 22012111Sralph char fonts[4][50]; /* fonts for troff */ 22112111Sralph 22237968Sbostic char ifonts[4][40] = { 22337968Sbostic _PATH_VFONTR, 22437968Sbostic _PATH_VFONTI, 22537968Sbostic _PATH_VFONTB, 22637968Sbostic _PATH_VFONTS, 22712111Sralph }; 22812111Sralph 22912111Sralph /* 23012111Sralph * The remaining part is the reading of the control file (cf) 23112111Sralph * and performing the various actions. 23212111Sralph */ 23312111Sralph printit(file) 23412111Sralph char *file; 23512111Sralph { 23612111Sralph register int i; 23717463Sralph char *cp; 23817463Sralph int bombed = OK; 23912111Sralph 24012111Sralph /* 24117463Sralph * open control file; ignore if no longer there. 24212111Sralph */ 24312111Sralph if ((cfp = fopen(file, "r")) == NULL) { 24416762Sralph syslog(LOG_INFO, "%s: %s: %m", printer, file); 24517463Sralph return(OK); 24612111Sralph } 24712111Sralph /* 24812111Sralph * Reset troff fonts. 24912111Sralph */ 25012111Sralph for (i = 0; i < 4; i++) 25112111Sralph strcpy(fonts[i], ifonts[i]); 25217339Sralph strcpy(width+2, "0"); 25317302Sralph strcpy(indent+2, "0"); 25412111Sralph 25512111Sralph /* 25612111Sralph * read the control file for work to do 25712111Sralph * 25812111Sralph * file format -- first character in the line is a command 25912111Sralph * rest of the line is the argument. 26012111Sralph * valid commands are: 26112111Sralph * 26217463Sralph * S -- "stat info" for symbolic link protection 26312111Sralph * J -- "job name" on banner page 26412111Sralph * C -- "class name" on banner page 26512111Sralph * L -- "literal" user's name to print on banner 26612111Sralph * T -- "title" for pr 26712111Sralph * H -- "host name" of machine where lpr was done 26812111Sralph * P -- "person" user's login name 26912581Sralph * I -- "indent" amount to indent output 27012111Sralph * f -- "file name" name of text file to print 27112111Sralph * l -- "file name" text file with control chars 27212111Sralph * p -- "file name" text file to print with pr(1) 27312111Sralph * t -- "file name" troff(1) file to print 27413233Sralph * n -- "file name" ditroff(1) file to print 27512111Sralph * d -- "file name" dvi file to print 27612111Sralph * g -- "file name" plot(1G) file to print 27712111Sralph * v -- "file name" plain raster file to print 27812111Sralph * c -- "file name" cifplot file to print 27912111Sralph * 1 -- "R font file" for troff 28012111Sralph * 2 -- "I font file" for troff 28112111Sralph * 3 -- "B font file" for troff 28212111Sralph * 4 -- "S font file" for troff 28312111Sralph * N -- "name" of file (used by lpq) 28412111Sralph * U -- "unlink" name of file to remove 28512111Sralph * (after we print it. (Pass 2 only)). 28612111Sralph * M -- "mail" to user when done printing 28712111Sralph * 28812111Sralph * getline reads a line and expands tabs to blanks 28912111Sralph */ 29012111Sralph 29112111Sralph /* pass 1 */ 29212111Sralph 29312111Sralph while (getline(cfp)) 29412111Sralph switch (line[0]) { 29512111Sralph case 'H': 29614150Sralph strcpy(fromhost, line+1); 29712111Sralph if (class[0] == '\0') 29815552Sralph strncpy(class, line+1, sizeof(class)-1); 29912111Sralph continue; 30012111Sralph 30112111Sralph case 'P': 30215552Sralph strncpy(logname, line+1, sizeof(logname)-1); 30312463Sralph if (RS) { /* restricted */ 30412463Sralph if (getpwnam(logname) == (struct passwd *)0) { 30517463Sralph bombed = NOACCT; 30615811Sralph sendmail(line+1, bombed); 30712463Sralph goto pass2; 30812463Sralph } 30912463Sralph } 31012111Sralph continue; 31112111Sralph 31217463Sralph case 'S': 31317463Sralph cp = line+1; 31417463Sralph i = 0; 31517463Sralph while (*cp >= '0' && *cp <= '9') 31617463Sralph i = i * 10 + (*cp++ - '0'); 31717463Sralph fdev = i; 31817463Sralph cp++; 31917463Sralph i = 0; 32017463Sralph while (*cp >= '0' && *cp <= '9') 32117463Sralph i = i * 10 + (*cp++ - '0'); 32217463Sralph fino = i; 32317463Sralph continue; 32417463Sralph 32512111Sralph case 'J': 32612111Sralph if (line[1] != '\0') 32715552Sralph strncpy(jobname, line+1, sizeof(jobname)-1); 32812111Sralph else 32912111Sralph strcpy(jobname, " "); 33012111Sralph continue; 33112111Sralph 33212111Sralph case 'C': 33312111Sralph if (line[1] != '\0') 33415552Sralph strncpy(class, line+1, sizeof(class)-1); 33512111Sralph else if (class[0] == '\0') 33615811Sralph gethostname(class, sizeof(class)); 33712111Sralph continue; 33812111Sralph 33912111Sralph case 'T': /* header title for pr */ 34015552Sralph strncpy(title, line+1, sizeof(title)-1); 34112111Sralph continue; 34212111Sralph 34312111Sralph case 'L': /* identification line */ 34418127Sralph if (!SH && !HL) 34512111Sralph banner(line+1, jobname); 34612111Sralph continue; 34712111Sralph 34812111Sralph case '1': /* troff fonts */ 34912111Sralph case '2': 35012111Sralph case '3': 35112111Sralph case '4': 35212111Sralph if (line[1] != '\0') 35312111Sralph strcpy(fonts[line[0]-'1'], line+1); 35412111Sralph continue; 35512111Sralph 35612111Sralph case 'W': /* page width */ 35715552Sralph strncpy(width+2, line+1, sizeof(width)-3); 35812111Sralph continue; 35912111Sralph 36012581Sralph case 'I': /* indent amount */ 36115552Sralph strncpy(indent+2, line+1, sizeof(indent)-3); 36212581Sralph continue; 36312581Sralph 36412111Sralph default: /* some file to print */ 36515811Sralph switch (i = print(line[0], line+1)) { 36617463Sralph case ERROR: 36717463Sralph if (bombed == OK) 36817463Sralph bombed = FATALERR; 36915811Sralph break; 37017463Sralph case REPRINT: 37112111Sralph (void) fclose(cfp); 37217463Sralph return(REPRINT); 37317463Sralph case FILTERERR: 37417463Sralph case ACCESS: 37517463Sralph bombed = i; 37615811Sralph sendmail(logname, bombed); 37715811Sralph } 37812111Sralph title[0] = '\0'; 37912111Sralph continue; 38012111Sralph 38112111Sralph case 'N': 38212111Sralph case 'U': 38312111Sralph case 'M': 38412111Sralph continue; 38512111Sralph } 38612111Sralph 38712111Sralph /* pass 2 */ 38812111Sralph 38912463Sralph pass2: 39012111Sralph fseek(cfp, 0L, 0); 39112111Sralph while (getline(cfp)) 39212111Sralph switch (line[0]) { 39318127Sralph case 'L': /* identification line */ 39418127Sralph if (!SH && HL) 39518127Sralph banner(line+1, jobname); 39618127Sralph continue; 39718127Sralph 39812111Sralph case 'M': 39917463Sralph if (bombed < NOACCT) /* already sent if >= NOACCT */ 40015811Sralph sendmail(line+1, bombed); 40112111Sralph continue; 40212111Sralph 40312111Sralph case 'U': 40412111Sralph (void) unlink(line+1); 40512111Sralph } 40612111Sralph /* 40715811Sralph * clean-up in case another control file exists 40812111Sralph */ 40912111Sralph (void) fclose(cfp); 41012111Sralph (void) unlink(file); 41117463Sralph return(bombed == OK ? OK : ERROR); 41212111Sralph } 41312111Sralph 41412111Sralph /* 41512111Sralph * Print a file. 41613233Sralph * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}. 41715811Sralph * Return -1 if a non-recoverable error occured, 41815811Sralph * 2 if the filter detected some errors (but printed the job anyway), 41915811Sralph * 1 if we should try to reprint this job and 42012111Sralph * 0 if all is well. 42112111Sralph * Note: all filters take stdin as the file, stdout as the printer, 42212111Sralph * stderr as the log file, and must not ignore SIGINT. 42312111Sralph */ 42412111Sralph print(format, file) 42512111Sralph int format; 42612111Sralph char *file; 42712111Sralph { 42815811Sralph register int n; 42912111Sralph register char *prog; 43015811Sralph int fi, fo; 431*39954Smckusick FILE *fp; 43212111Sralph char *av[15], buf[BUFSIZ]; 43312111Sralph int pid, p[2], stopped = 0; 43412111Sralph union wait status; 43517463Sralph struct stat stb; 43612111Sralph 43717463Sralph if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0) 43817463Sralph return(ERROR); 43917463Sralph /* 44017463Sralph * Check to see if data file is a symbolic link. If so, it should 44117463Sralph * still point to the same file or someone is trying to print 44217463Sralph * something he shouldn't. 44317463Sralph */ 44417463Sralph if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 && 44517463Sralph (stb.st_dev != fdev || stb.st_ino != fino)) 44617463Sralph return(ACCESS); 44712111Sralph if (!SF && !tof) { /* start on a fresh page */ 44812111Sralph (void) write(ofd, FF, strlen(FF)); 44912111Sralph tof = 1; 45012111Sralph } 45112111Sralph if (IF == NULL && (format == 'f' || format == 'l')) { 45212111Sralph tof = 0; 45312111Sralph while ((n = read(fi, buf, BUFSIZ)) > 0) 45412111Sralph if (write(ofd, buf, n) != n) { 45512111Sralph (void) close(fi); 45617463Sralph return(REPRINT); 45712111Sralph } 45812111Sralph (void) close(fi); 45917463Sralph return(OK); 46012111Sralph } 46112111Sralph switch (format) { 46212111Sralph case 'p': /* print file using 'pr' */ 46312111Sralph if (IF == NULL) { /* use output filter */ 46437968Sbostic prog = _PATH_PR; 46512111Sralph av[0] = "pr"; 46612111Sralph av[1] = width; 46712111Sralph av[2] = length; 46812111Sralph av[3] = "-h"; 46912111Sralph av[4] = *title ? title : " "; 47012111Sralph av[5] = 0; 47112111Sralph fo = ofd; 47212111Sralph goto start; 47312111Sralph } 47412111Sralph pipe(p); 47512111Sralph if ((prchild = dofork(DORETURN)) == 0) { /* child */ 47612111Sralph dup2(fi, 0); /* file is stdin */ 47712111Sralph dup2(p[1], 1); /* pipe is stdout */ 47812111Sralph for (n = 3; n < NOFILE; n++) 47912111Sralph (void) close(n); 48037968Sbostic execl(_PATH_PR, "pr", width, length, 48137968Sbostic "-h", *title ? title : " ", 0); 48237968Sbostic syslog(LOG_ERR, "cannot execl %s", _PATH_PR); 48312111Sralph exit(2); 48412111Sralph } 48512111Sralph (void) close(p[1]); /* close output side */ 48612111Sralph (void) close(fi); 48712111Sralph if (prchild < 0) { 48812111Sralph prchild = 0; 48912111Sralph (void) close(p[0]); 49017463Sralph return(ERROR); 49112111Sralph } 49212111Sralph fi = p[0]; /* use pipe for input */ 49312111Sralph case 'f': /* print plain text file */ 49412111Sralph prog = IF; 49512111Sralph av[1] = width; 49612111Sralph av[2] = length; 49712581Sralph av[3] = indent; 49812581Sralph n = 4; 49912111Sralph break; 50012111Sralph case 'l': /* like 'f' but pass control characters */ 50112111Sralph prog = IF; 50214325Sralph av[1] = "-c"; 50312111Sralph av[2] = width; 50412111Sralph av[3] = length; 50512581Sralph av[4] = indent; 50612581Sralph n = 5; 50712111Sralph break; 50812463Sralph case 'r': /* print a fortran text file */ 50912463Sralph prog = RF; 51012463Sralph av[1] = width; 51112463Sralph av[2] = length; 51212463Sralph n = 3; 51312463Sralph break; 51412111Sralph case 't': /* print troff output */ 51513233Sralph case 'n': /* print ditroff output */ 51612463Sralph case 'd': /* print tex output */ 51712111Sralph (void) unlink(".railmag"); 51812463Sralph if ((fo = creat(".railmag", FILMOD)) < 0) { 51916762Sralph syslog(LOG_ERR, "%s: cannot create .railmag", printer); 52012111Sralph (void) unlink(".railmag"); 52112111Sralph } else { 52212111Sralph for (n = 0; n < 4; n++) { 52312111Sralph if (fonts[n][0] != '/') 52437968Sbostic (void) write(fo, _PATH_VFONT, 15); 52512111Sralph (void) write(fo, fonts[n], strlen(fonts[n])); 52612111Sralph (void) write(fo, "\n", 1); 52712111Sralph } 52812111Sralph (void) close(fo); 52912111Sralph } 53013233Sralph prog = (format == 't') ? TF : (format == 'n') ? NF : DF; 53112463Sralph av[1] = pxwidth; 53212463Sralph av[2] = pxlength; 53312463Sralph n = 3; 53412111Sralph break; 53512111Sralph case 'c': /* print cifplot output */ 53612111Sralph prog = CF; 53712463Sralph av[1] = pxwidth; 53812463Sralph av[2] = pxlength; 53912463Sralph n = 3; 54012111Sralph break; 54112111Sralph case 'g': /* print plot(1G) output */ 54212111Sralph prog = GF; 54312463Sralph av[1] = pxwidth; 54412463Sralph av[2] = pxlength; 54512463Sralph n = 3; 54612111Sralph break; 54712111Sralph case 'v': /* print raster output */ 54812111Sralph prog = VF; 54912463Sralph av[1] = pxwidth; 55012463Sralph av[2] = pxlength; 55112463Sralph n = 3; 55212111Sralph break; 55312111Sralph default: 55412111Sralph (void) close(fi); 55516762Sralph syslog(LOG_ERR, "%s: illegal format character '%c'", 55616762Sralph printer, format); 55717463Sralph return(ERROR); 55812111Sralph } 55912111Sralph if ((av[0] = rindex(prog, '/')) != NULL) 56012111Sralph av[0]++; 56112111Sralph else 56212111Sralph av[0] = prog; 56312111Sralph av[n++] = "-n"; 56412111Sralph av[n++] = logname; 56512111Sralph av[n++] = "-h"; 56614150Sralph av[n++] = fromhost; 56712111Sralph av[n++] = AF; 56812111Sralph av[n] = 0; 56912111Sralph fo = pfd; 57012111Sralph if (ofilter > 0) { /* stop output filter */ 57112111Sralph write(ofd, "\031\1", 2); 57212111Sralph while ((pid = wait3(&status, WUNTRACED, 0)) > 0 && pid != ofilter) 57312111Sralph ; 57412111Sralph if (status.w_stopval != WSTOPPED) { 57512111Sralph (void) close(fi); 57616762Sralph syslog(LOG_WARNING, "%s: output filter died (%d)", 57716762Sralph printer, status.w_retcode); 57817463Sralph return(REPRINT); 57912111Sralph } 58012111Sralph stopped++; 58112111Sralph } 58212111Sralph start: 58312111Sralph if ((child = dofork(DORETURN)) == 0) { /* child */ 58412111Sralph dup2(fi, 0); 58512111Sralph dup2(fo, 1); 586*39954Smckusick n = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, 0664); 58715811Sralph if (n >= 0) 58815811Sralph dup2(n, 2); 58912111Sralph for (n = 3; n < NOFILE; n++) 59012111Sralph (void) close(n); 59112111Sralph execv(prog, av); 59216762Sralph syslog(LOG_ERR, "cannot execv %s", prog); 59312111Sralph exit(2); 59412111Sralph } 59512111Sralph (void) close(fi); 59612111Sralph if (child < 0) 59712111Sralph status.w_retcode = 100; 59812111Sralph else 59912111Sralph while ((pid = wait(&status)) > 0 && pid != child) 60012111Sralph ; 60112111Sralph child = 0; 60212111Sralph prchild = 0; 60312111Sralph if (stopped) { /* restart output filter */ 60412111Sralph if (kill(ofilter, SIGCONT) < 0) { 60516762Sralph syslog(LOG_ERR, "cannot restart output filter"); 60612111Sralph exit(1); 60712111Sralph } 60812111Sralph } 60912111Sralph tof = 0; 610*39954Smckusick 611*39954Smckusick /* Copy filter output to "lf" logfile */ 612*39954Smckusick if (fp = fopen(tempfile, "r")) { 613*39954Smckusick char tbuf[512]; 614*39954Smckusick 615*39954Smckusick while (fgets(buf, sizeof(buf), fp)) 616*39954Smckusick fputs(buf, stderr); 617*39954Smckusick close(fp); 618*39954Smckusick } 619*39954Smckusick 62015811Sralph if (!WIFEXITED(status)) { 62116762Sralph syslog(LOG_WARNING, "%s: Daemon filter '%c' terminated (%d)", 62216762Sralph printer, format, status.w_termsig); 62317463Sralph return(ERROR); 62417463Sralph } 62517463Sralph switch (status.w_retcode) { 62617463Sralph case 0: 62717463Sralph tof = 1; 62817463Sralph return(OK); 62917463Sralph case 1: 63017463Sralph return(REPRINT); 63117463Sralph default: 63216762Sralph syslog(LOG_WARNING, "%s: Daemon filter '%c' exited (%d)", 63316762Sralph printer, format, status.w_retcode); 63417463Sralph case 2: 63517463Sralph return(ERROR); 63617463Sralph } 63712111Sralph } 63812111Sralph 63912111Sralph /* 64012111Sralph * Send the daemon control file (cf) and any data files. 64112111Sralph * Return -1 if a non-recoverable error occured, 1 if a recoverable error and 64212111Sralph * 0 if all is well. 64312111Sralph */ 64412111Sralph sendit(file) 64512111Sralph char *file; 64612111Sralph { 64717463Sralph register int i, err = OK; 64817463Sralph char *cp, last[BUFSIZ]; 64912111Sralph 65012111Sralph /* 65112111Sralph * open control file 65212111Sralph */ 65316762Sralph if ((cfp = fopen(file, "r")) == NULL) 65417463Sralph return(OK); 65512111Sralph /* 65612111Sralph * read the control file for work to do 65712111Sralph * 65812111Sralph * file format -- first character in the line is a command 65912111Sralph * rest of the line is the argument. 66012111Sralph * commands of interest are: 66112111Sralph * 66212111Sralph * a-z -- "file name" name of file to print 66312111Sralph * U -- "unlink" name of file to remove 66412111Sralph * (after we print it. (Pass 2 only)). 66512111Sralph */ 66612111Sralph 66712111Sralph /* 66812111Sralph * pass 1 66912111Sralph */ 67012111Sralph while (getline(cfp)) { 67112111Sralph again: 67217463Sralph if (line[0] == 'S') { 67317463Sralph cp = line+1; 67417463Sralph i = 0; 67517463Sralph while (*cp >= '0' && *cp <= '9') 67617463Sralph i = i * 10 + (*cp++ - '0'); 67717463Sralph fdev = i; 67817463Sralph cp++; 67917463Sralph i = 0; 68017463Sralph while (*cp >= '0' && *cp <= '9') 68117463Sralph i = i * 10 + (*cp++ - '0'); 68217463Sralph fino = i; 68317463Sralph continue; 68417463Sralph } 68512111Sralph if (line[0] >= 'a' && line[0] <= 'z') { 68612111Sralph strcpy(last, line); 68717463Sralph while (i = getline(cfp)) 68812111Sralph if (strcmp(last, line)) 68912111Sralph break; 69017463Sralph switch (sendfile('\3', last+1)) { 69117463Sralph case OK: 69217463Sralph if (i) 69317463Sralph goto again; 69417463Sralph break; 69517463Sralph case REPRINT: 69612111Sralph (void) fclose(cfp); 69717463Sralph return(REPRINT); 69817463Sralph case ACCESS: 69917463Sralph sendmail(logname, ACCESS); 70017463Sralph case ERROR: 70117463Sralph err = ERROR; 70217463Sralph } 70312111Sralph break; 70412111Sralph } 70512111Sralph } 70617463Sralph if (err == OK && sendfile('\2', file) > 0) { 70712111Sralph (void) fclose(cfp); 70817463Sralph return(REPRINT); 70912111Sralph } 71012111Sralph /* 71112111Sralph * pass 2 71212111Sralph */ 71312111Sralph fseek(cfp, 0L, 0); 71412111Sralph while (getline(cfp)) 71512111Sralph if (line[0] == 'U') 71612111Sralph (void) unlink(line+1); 71712111Sralph /* 71817463Sralph * clean-up in case another control file exists 71912111Sralph */ 72012111Sralph (void) fclose(cfp); 72112111Sralph (void) unlink(file); 72217463Sralph return(err); 72312111Sralph } 72412111Sralph 72512111Sralph /* 72612111Sralph * Send a data file to the remote machine and spool it. 72712111Sralph * Return positive if we should try resending. 72812111Sralph */ 72912111Sralph sendfile(type, file) 73012111Sralph char type, *file; 73112111Sralph { 73212111Sralph register int f, i, amt; 73312111Sralph struct stat stb; 73412111Sralph char buf[BUFSIZ]; 73516762Sralph int sizerr, resp; 73612111Sralph 73717463Sralph if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0) 73817463Sralph return(ERROR); 73917463Sralph /* 74017463Sralph * Check to see if data file is a symbolic link. If so, it should 74117463Sralph * still point to the same file or someone is trying to print something 74217463Sralph * he shouldn't. 74317463Sralph */ 74417463Sralph if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 && 74517463Sralph (stb.st_dev != fdev || stb.st_ino != fino)) 74617463Sralph return(ACCESS); 74712111Sralph (void) sprintf(buf, "%c%d %s\n", type, stb.st_size, file); 74812111Sralph amt = strlen(buf); 74916762Sralph for (i = 0; ; i++) { 75016762Sralph if (write(pfd, buf, amt) != amt || 75116762Sralph (resp = response()) < 0 || resp == '\1') { 75216762Sralph (void) close(f); 75317463Sralph return(REPRINT); 75416762Sralph } else if (resp == '\0') 75516762Sralph break; 75616762Sralph if (i == 0) 75716762Sralph status("no space on remote; waiting for queue to drain"); 75816762Sralph if (i == 10) 75924861Seric syslog(LOG_ALERT, "%s: can't send to %s; queue full", 76016762Sralph printer, RM); 76116762Sralph sleep(5 * 60); 76212692Sralph } 76316762Sralph if (i) 76416762Sralph status("sending to %s", RM); 76512111Sralph sizerr = 0; 76612111Sralph for (i = 0; i < stb.st_size; i += BUFSIZ) { 76712111Sralph amt = BUFSIZ; 76812111Sralph if (i + amt > stb.st_size) 76912111Sralph amt = stb.st_size - i; 77012111Sralph if (sizerr == 0 && read(f, buf, amt) != amt) 77112111Sralph sizerr = 1; 77212692Sralph if (write(pfd, buf, amt) != amt) { 77312692Sralph (void) close(f); 77417463Sralph return(REPRINT); 77512692Sralph } 77612111Sralph } 77712111Sralph (void) close(f); 77812111Sralph if (sizerr) { 77916762Sralph syslog(LOG_INFO, "%s: %s: changed size", printer, file); 78017463Sralph /* tell recvjob to ignore this file */ 78117463Sralph (void) write(pfd, "\1", 1); 78217463Sralph return(ERROR); 78317463Sralph } 78417463Sralph if (write(pfd, "", 1) != 1 || response()) 78517463Sralph return(REPRINT); 78617463Sralph return(OK); 78712111Sralph } 78812111Sralph 78912111Sralph /* 79012111Sralph * Check to make sure there have been no errors and that both programs 79112111Sralph * are in sync with eachother. 79212111Sralph * Return non-zero if the connection was lost. 79312111Sralph */ 79416762Sralph response() 79512111Sralph { 79612111Sralph char resp; 79712111Sralph 79816762Sralph if (read(pfd, &resp, 1) != 1) { 79916762Sralph syslog(LOG_INFO, "%s: lost connection", printer); 80016762Sralph return(-1); 80112111Sralph } 80216762Sralph return(resp); 80312111Sralph } 80412111Sralph 80512111Sralph /* 80612111Sralph * Banner printing stuff 80712111Sralph */ 80812111Sralph banner(name1, name2) 80912111Sralph char *name1, *name2; 81012111Sralph { 81112111Sralph time_t tvec; 81212111Sralph extern char *ctime(); 81312111Sralph 81412111Sralph time(&tvec); 81512111Sralph if (!SF && !tof) 81612111Sralph (void) write(ofd, FF, strlen(FF)); 81712111Sralph if (SB) { /* short banner only */ 81812111Sralph if (class[0]) { 81912111Sralph (void) write(ofd, class, strlen(class)); 82012111Sralph (void) write(ofd, ":", 1); 82112111Sralph } 82212111Sralph (void) write(ofd, name1, strlen(name1)); 82312111Sralph (void) write(ofd, " Job: ", 7); 82412111Sralph (void) write(ofd, name2, strlen(name2)); 82512111Sralph (void) write(ofd, " Date: ", 8); 82612111Sralph (void) write(ofd, ctime(&tvec), 24); 82712111Sralph (void) write(ofd, "\n", 1); 82812111Sralph } else { /* normal banner */ 82912111Sralph (void) write(ofd, "\n\n\n", 3); 83012111Sralph scan_out(ofd, name1, '\0'); 83112111Sralph (void) write(ofd, "\n\n", 2); 83212111Sralph scan_out(ofd, name2, '\0'); 83312111Sralph if (class[0]) { 83412111Sralph (void) write(ofd,"\n\n\n",3); 83512111Sralph scan_out(ofd, class, '\0'); 83612111Sralph } 83712111Sralph (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15); 83812111Sralph (void) write(ofd, name2, strlen(name2)); 83912111Sralph (void) write(ofd, "\n\t\t\t\t\tDate: ", 12); 84012111Sralph (void) write(ofd, ctime(&tvec), 24); 84112111Sralph (void) write(ofd, "\n", 1); 84212111Sralph } 84312111Sralph if (!SF) 84412111Sralph (void) write(ofd, FF, strlen(FF)); 84512111Sralph tof = 1; 84612111Sralph } 84712111Sralph 84816762Sralph char * 84912111Sralph scnline(key, p, c) 85012111Sralph register char key, *p; 85112111Sralph char c; 85212111Sralph { 85312111Sralph register scnwidth; 85412111Sralph 85512111Sralph for (scnwidth = WIDTH; --scnwidth;) { 85612111Sralph key <<= 1; 85712111Sralph *p++ = key & 0200 ? c : BACKGND; 85812111Sralph } 85912111Sralph return (p); 86012111Sralph } 86112111Sralph 86212111Sralph #define TRC(q) (((q)-' ')&0177) 86312111Sralph 86412111Sralph scan_out(scfd, scsp, dlm) 86512111Sralph int scfd; 86612111Sralph char *scsp, dlm; 86712111Sralph { 86812111Sralph register char *strp; 86912111Sralph register nchrs, j; 87012111Sralph char outbuf[LINELEN+1], *sp, c, cc; 87112111Sralph int d, scnhgt; 87212111Sralph extern char scnkey[][HEIGHT]; /* in lpdchar.c */ 87312111Sralph 87412111Sralph for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) { 87512111Sralph strp = &outbuf[0]; 87612111Sralph sp = scsp; 87712111Sralph for (nchrs = 0; ; ) { 87812111Sralph d = dropit(c = TRC(cc = *sp++)); 87912111Sralph if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d)) 88012111Sralph for (j = WIDTH; --j;) 88112111Sralph *strp++ = BACKGND; 88212111Sralph else 88312111Sralph strp = scnline(scnkey[c][scnhgt-1-d], strp, cc); 88412111Sralph if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1) 88512111Sralph break; 88612111Sralph *strp++ = BACKGND; 88712111Sralph *strp++ = BACKGND; 88812111Sralph } 88912111Sralph while (*--strp == BACKGND && strp >= outbuf) 89012111Sralph ; 89112111Sralph strp++; 89212111Sralph *strp++ = '\n'; 89312111Sralph (void) write(scfd, outbuf, strp-outbuf); 89412111Sralph } 89512111Sralph } 89612111Sralph 89712111Sralph dropit(c) 89812111Sralph char c; 89912111Sralph { 90012111Sralph switch(c) { 90112111Sralph 90212111Sralph case TRC('_'): 90312111Sralph case TRC(';'): 90412111Sralph case TRC(','): 90512111Sralph case TRC('g'): 90612111Sralph case TRC('j'): 90712111Sralph case TRC('p'): 90812111Sralph case TRC('q'): 90912111Sralph case TRC('y'): 91012111Sralph return (DROP); 91112111Sralph 91212111Sralph default: 91312111Sralph return (0); 91412111Sralph } 91512111Sralph } 91612111Sralph 91712111Sralph /* 91812111Sralph * sendmail --- 91912111Sralph * tell people about job completion 92012111Sralph */ 92115811Sralph sendmail(user, bombed) 92215811Sralph char *user; 92312111Sralph int bombed; 92412111Sralph { 92512111Sralph register int i; 92615811Sralph int p[2], s; 92712111Sralph register char *cp; 92812111Sralph char buf[100]; 92915811Sralph struct stat stb; 93015811Sralph FILE *fp; 93112111Sralph 93212111Sralph pipe(p); 93315811Sralph if ((s = dofork(DORETURN)) == 0) { /* child */ 93412111Sralph dup2(p[0], 0); 93512111Sralph for (i = 3; i < NOFILE; i++) 93612111Sralph (void) close(i); 93737968Sbostic if ((cp = rindex(_PATH_SENDMAIL, '/')) != NULL) 93812111Sralph cp++; 93912111Sralph else 94037968Sbostic cp = _PATH_SENDMAIL; 94115811Sralph sprintf(buf, "%s@%s", user, fromhost); 94237968Sbostic execl(_PATH_SENDMAIL, cp, buf, 0); 94312111Sralph exit(0); 94415811Sralph } else if (s > 0) { /* parent */ 94512111Sralph dup2(p[1], 1); 94615811Sralph printf("To: %s@%s\n", user, fromhost); 94712111Sralph printf("Subject: printer job\n\n"); 94812111Sralph printf("Your printer job "); 94912111Sralph if (*jobname) 95012111Sralph printf("(%s) ", jobname); 95112463Sralph switch (bombed) { 95217463Sralph case OK: 95312463Sralph printf("\ncompleted successfully\n"); 95412463Sralph break; 95512463Sralph default: 95617463Sralph case FATALERR: 95712463Sralph printf("\ncould not be printed\n"); 95812463Sralph break; 95917463Sralph case NOACCT: 96012463Sralph printf("\ncould not be printed without an account on %s\n", host); 96112463Sralph break; 96217463Sralph case FILTERERR: 963*39954Smckusick if (stat(tempfile, &stb) < 0 || stb.st_size == 0 || 964*39954Smckusick (fp = fopen(tempfile, "r")) == NULL) { 96515811Sralph printf("\nwas printed but had some errors\n"); 96615811Sralph break; 96715811Sralph } 96815811Sralph printf("\nwas printed but had the following errors:\n"); 96915811Sralph while ((i = getc(fp)) != EOF) 97015811Sralph putchar(i); 97115811Sralph (void) fclose(fp); 97217463Sralph break; 97317463Sralph case ACCESS: 97417463Sralph printf("\nwas not printed because it was not linked to the original file\n"); 97512463Sralph } 97612111Sralph fflush(stdout); 97712111Sralph (void) close(1); 97812111Sralph } 97912111Sralph (void) close(p[0]); 98012111Sralph (void) close(p[1]); 98115811Sralph wait(&s); 98212111Sralph } 98312111Sralph 98412111Sralph /* 98512111Sralph * dofork - fork with retries on failure 98612111Sralph */ 98712111Sralph dofork(action) 98812111Sralph int action; 98912111Sralph { 99012111Sralph register int i, pid; 99112111Sralph 99212111Sralph for (i = 0; i < 20; i++) { 99312463Sralph if ((pid = fork()) < 0) { 99412111Sralph sleep((unsigned)(i*i)); 99512463Sralph continue; 99612463Sralph } 99712463Sralph /* 99812463Sralph * Child should run as daemon instead of root 99912463Sralph */ 100012463Sralph if (pid == 0) 100112463Sralph setuid(DU); 100212463Sralph return(pid); 100312111Sralph } 100416762Sralph syslog(LOG_ERR, "can't fork"); 100512111Sralph 100612111Sralph switch (action) { 100712111Sralph case DORETURN: 100812111Sralph return (-1); 100912111Sralph default: 101016762Sralph syslog(LOG_ERR, "bad action (%d) to dofork", action); 101112111Sralph /*FALL THRU*/ 101212111Sralph case DOABORT: 101312111Sralph exit(1); 101412111Sralph } 101512111Sralph /*NOTREACHED*/ 101612111Sralph } 101712111Sralph 101812111Sralph /* 101916762Sralph * Kill child processes to abort current job. 102012111Sralph */ 102116762Sralph abortpr() 102212111Sralph { 1023*39954Smckusick (void) unlink(tempfile); 102412111Sralph kill(0, SIGINT); 102512111Sralph if (ofilter > 0) 102612111Sralph kill(ofilter, SIGCONT); 102712111Sralph while (wait(0) > 0) 102812111Sralph ; 102912111Sralph exit(0); 103012111Sralph } 103112111Sralph 103212111Sralph init() 103312111Sralph { 103412111Sralph int status; 103538736Stef char *s; 103612111Sralph 103725468Stef if ((status = pgetent(line, printer)) < 0) { 103825468Stef syslog(LOG_ERR, "can't open printer description file"); 103925468Stef exit(1); 104025468Stef } else if (status == 0) { 104125468Stef syslog(LOG_ERR, "unknown printer: %s", printer); 104225468Stef exit(1); 104325468Stef } 104412111Sralph if ((LP = pgetstr("lp", &bp)) == NULL) 104537968Sbostic LP = _PATH_DEFDEVLP; 104612111Sralph if ((RP = pgetstr("rp", &bp)) == NULL) 104712463Sralph RP = DEFLP; 104812111Sralph if ((LO = pgetstr("lo", &bp)) == NULL) 104912111Sralph LO = DEFLOCK; 105012111Sralph if ((ST = pgetstr("st", &bp)) == NULL) 105112111Sralph ST = DEFSTAT; 105212111Sralph if ((LF = pgetstr("lf", &bp)) == NULL) 105337968Sbostic LF = _PATH_CONSOLE; 105412111Sralph if ((SD = pgetstr("sd", &bp)) == NULL) 105537968Sbostic SD = _PATH_DEFSPOOL; 105612111Sralph if ((DU = pgetnum("du")) < 0) 105712111Sralph DU = DEFUID; 105812111Sralph if ((FF = pgetstr("ff", &bp)) == NULL) 105912111Sralph FF = DEFFF; 106012111Sralph if ((PW = pgetnum("pw")) < 0) 106112111Sralph PW = DEFWIDTH; 106212111Sralph sprintf(&width[2], "%d", PW); 106312111Sralph if ((PL = pgetnum("pl")) < 0) 106412111Sralph PL = DEFLENGTH; 106512111Sralph sprintf(&length[2], "%d", PL); 106612463Sralph if ((PX = pgetnum("px")) < 0) 106712463Sralph PX = 0; 106812463Sralph sprintf(&pxwidth[2], "%d", PX); 106912463Sralph if ((PY = pgetnum("py")) < 0) 107012463Sralph PY = 0; 107112463Sralph sprintf(&pxlength[2], "%d", PY); 107212111Sralph RM = pgetstr("rm", &bp); 107338736Stef if (s = checkremote()) 107438736Stef syslog(LOG_WARNING, s); 107525468Stef 107612111Sralph AF = pgetstr("af", &bp); 107712111Sralph OF = pgetstr("of", &bp); 107812111Sralph IF = pgetstr("if", &bp); 107912463Sralph RF = pgetstr("rf", &bp); 108012111Sralph TF = pgetstr("tf", &bp); 108113233Sralph NF = pgetstr("nf", &bp); 108212111Sralph DF = pgetstr("df", &bp); 108312111Sralph GF = pgetstr("gf", &bp); 108412111Sralph VF = pgetstr("vf", &bp); 108512111Sralph CF = pgetstr("cf", &bp); 108612111Sralph TR = pgetstr("tr", &bp); 108712463Sralph RS = pgetflag("rs"); 108812111Sralph SF = pgetflag("sf"); 108912111Sralph SH = pgetflag("sh"); 109012111Sralph SB = pgetflag("sb"); 109118127Sralph HL = pgetflag("hl"); 109212111Sralph RW = pgetflag("rw"); 109312111Sralph BR = pgetnum("br"); 109412111Sralph if ((FC = pgetnum("fc")) < 0) 109512111Sralph FC = 0; 109612111Sralph if ((FS = pgetnum("fs")) < 0) 109712111Sralph FS = 0; 109812111Sralph if ((XC = pgetnum("xc")) < 0) 109912111Sralph XC = 0; 110012111Sralph if ((XS = pgetnum("xs")) < 0) 110112111Sralph XS = 0; 110212581Sralph tof = !pgetflag("fo"); 110312111Sralph } 110412111Sralph 110512463Sralph /* 110612463Sralph * Acquire line printer or remote connection. 110712463Sralph */ 110812463Sralph openpr() 110912463Sralph { 111012463Sralph register int i, n; 111116762Sralph int resp; 111212463Sralph 111338736Stef if (!sendtorem && *LP) { 111412463Sralph for (i = 1; ; i = i < 32 ? i << 1 : i) { 111513148Ssam pfd = open(LP, RW ? O_RDWR : O_WRONLY); 111612463Sralph if (pfd >= 0) 111712463Sralph break; 111812463Sralph if (errno == ENOENT) { 111916762Sralph syslog(LOG_ERR, "%s: %m", LP); 112012463Sralph exit(1); 112112463Sralph } 112212463Sralph if (i == 1) 112312463Sralph status("waiting for %s to become ready (offline ?)", printer); 112412463Sralph sleep(i); 112512463Sralph } 112612463Sralph if (isatty(pfd)) 112712463Sralph setty(); 112812463Sralph status("%s is ready and printing", printer); 112912463Sralph } else if (RM != NULL) { 113016762Sralph for (i = 1; ; i = i < 256 ? i << 1 : i) { 113116762Sralph resp = -1; 113212528Sralph pfd = getport(RM); 113312463Sralph if (pfd >= 0) { 113412463Sralph (void) sprintf(line, "\2%s\n", RP); 113512463Sralph n = strlen(line); 113616762Sralph if (write(pfd, line, n) == n && 113716762Sralph (resp = response()) == '\0') 113812463Sralph break; 113916031Sralph (void) close(pfd); 114012463Sralph } 114116031Sralph if (i == 1) { 114216762Sralph if (resp < 0) 114316031Sralph status("waiting for %s to come up", RM); 114416762Sralph else { 114516031Sralph status("waiting for queue to be enabled on %s", RM); 114616762Sralph i = 256; 114716762Sralph } 114816031Sralph } 114912463Sralph sleep(i); 115012463Sralph } 115112463Sralph status("sending to %s", RM); 115212463Sralph remote = 1; 115312463Sralph } else { 115416762Sralph syslog(LOG_ERR, "%s: no line printer device or host name", 115516762Sralph printer); 115612463Sralph exit(1); 115712463Sralph } 115812463Sralph /* 115912463Sralph * Start up an output filter, if needed. 116012463Sralph */ 116112463Sralph if (OF) { 116212463Sralph int p[2]; 116312463Sralph char *cp; 116412463Sralph 116512463Sralph pipe(p); 116612463Sralph if ((ofilter = dofork(DOABORT)) == 0) { /* child */ 116712463Sralph dup2(p[0], 0); /* pipe is std in */ 116812463Sralph dup2(pfd, 1); /* printer is std out */ 116912463Sralph for (i = 3; i < NOFILE; i++) 117012463Sralph (void) close(i); 117112463Sralph if ((cp = rindex(OF, '/')) == NULL) 117212463Sralph cp = OF; 117312463Sralph else 117412463Sralph cp++; 117512463Sralph execl(OF, cp, width, length, 0); 117616762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, OF); 117712463Sralph exit(1); 117812463Sralph } 117912463Sralph (void) close(p[0]); /* close input side */ 118012463Sralph ofd = p[1]; /* use pipe for output */ 118112463Sralph } else { 118212463Sralph ofd = pfd; 118312463Sralph ofilter = 0; 118412463Sralph } 118512463Sralph } 118612463Sralph 118712111Sralph struct bauds { 118812111Sralph int baud; 118912111Sralph int speed; 119012111Sralph } bauds[] = { 119112111Sralph 50, B50, 119212111Sralph 75, B75, 119312111Sralph 110, B110, 119412111Sralph 134, B134, 119512111Sralph 150, B150, 119612111Sralph 200, B200, 119712111Sralph 300, B300, 119812111Sralph 600, B600, 119912111Sralph 1200, B1200, 120012111Sralph 1800, B1800, 120112111Sralph 2400, B2400, 120212111Sralph 4800, B4800, 120312111Sralph 9600, B9600, 120412111Sralph 19200, EXTA, 120512111Sralph 38400, EXTB, 120612111Sralph 0, 0 120712111Sralph }; 120812111Sralph 120912111Sralph /* 121012111Sralph * setup tty lines. 121112111Sralph */ 121212111Sralph setty() 121312111Sralph { 121412111Sralph struct sgttyb ttybuf; 121512111Sralph register struct bauds *bp; 121612111Sralph 121712111Sralph if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) { 121816762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer); 121912111Sralph exit(1); 122012111Sralph } 122112111Sralph if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) { 122216762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCGETP): %m", printer); 122312111Sralph exit(1); 122412111Sralph } 122512111Sralph if (BR > 0) { 122612111Sralph for (bp = bauds; bp->baud; bp++) 122712111Sralph if (BR == bp->baud) 122812111Sralph break; 122912111Sralph if (!bp->baud) { 123016762Sralph syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR); 123112111Sralph exit(1); 123212111Sralph } 123312111Sralph ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed; 123412111Sralph } 123513169Sralph ttybuf.sg_flags &= ~FC; 123613169Sralph ttybuf.sg_flags |= FS; 123712111Sralph if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) { 123816762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCSETP): %m", printer); 123912111Sralph exit(1); 124012111Sralph } 124112111Sralph if (XC) { 124212111Sralph if (ioctl(pfd, TIOCLBIC, &XC) < 0) { 124316762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCLBIC): %m", printer); 124412111Sralph exit(1); 124512111Sralph } 124612111Sralph } 124712111Sralph if (XS) { 124812111Sralph if (ioctl(pfd, TIOCLBIS, &XS) < 0) { 124916762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCLBIS): %m", printer); 125012111Sralph exit(1); 125112111Sralph } 125212111Sralph } 125312111Sralph } 125412463Sralph 125512463Sralph /*VARARGS1*/ 125612463Sralph status(msg, a1, a2, a3) 125712463Sralph char *msg; 125812463Sralph { 125912463Sralph register int fd; 126012463Sralph char buf[BUFSIZ]; 126112463Sralph 126212463Sralph umask(0); 126313148Ssam fd = open(ST, O_WRONLY|O_CREAT, 0664); 126416762Sralph if (fd < 0 || flock(fd, LOCK_EX) < 0) { 126516762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, ST); 126616762Sralph exit(1); 126716762Sralph } 126813148Ssam ftruncate(fd, 0); 126912463Sralph sprintf(buf, msg, a1, a2, a3); 127012463Sralph strcat(buf, "\n"); 127112463Sralph (void) write(fd, buf, strlen(buf)); 127212463Sralph (void) close(fd); 127312463Sralph } 1274