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*37968Sbostic static char sccsid[] = "@(#)printjob.c 5.7 (Berkeley) 05/11/89"; 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" 30*37968Sbostic #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 */ 6916762Sralph char tmpfile[] = "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); 86*37968Sbostic (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 9615811Sralph (void) mktemp(tmpfile); 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 } 21415811Sralph (void) unlink(tmpfile); 21512463Sralph exit(0); 21612463Sralph } 21712111Sralph goto again; 21812111Sralph } 21912111Sralph 22012111Sralph char fonts[4][50]; /* fonts for troff */ 22112111Sralph 222*37968Sbostic char ifonts[4][40] = { 223*37968Sbostic _PATH_VFONTR, 224*37968Sbostic _PATH_VFONTI, 225*37968Sbostic _PATH_VFONTB, 226*37968Sbostic _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; 43112111Sralph char *av[15], buf[BUFSIZ]; 43212111Sralph int pid, p[2], stopped = 0; 43312111Sralph union wait status; 43417463Sralph struct stat stb; 43512111Sralph 43617463Sralph if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0) 43717463Sralph return(ERROR); 43817463Sralph /* 43917463Sralph * Check to see if data file is a symbolic link. If so, it should 44017463Sralph * still point to the same file or someone is trying to print 44117463Sralph * something he shouldn't. 44217463Sralph */ 44317463Sralph if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 && 44417463Sralph (stb.st_dev != fdev || stb.st_ino != fino)) 44517463Sralph return(ACCESS); 44612111Sralph if (!SF && !tof) { /* start on a fresh page */ 44712111Sralph (void) write(ofd, FF, strlen(FF)); 44812111Sralph tof = 1; 44912111Sralph } 45012111Sralph if (IF == NULL && (format == 'f' || format == 'l')) { 45112111Sralph tof = 0; 45212111Sralph while ((n = read(fi, buf, BUFSIZ)) > 0) 45312111Sralph if (write(ofd, buf, n) != n) { 45412111Sralph (void) close(fi); 45517463Sralph return(REPRINT); 45612111Sralph } 45712111Sralph (void) close(fi); 45817463Sralph return(OK); 45912111Sralph } 46012111Sralph switch (format) { 46112111Sralph case 'p': /* print file using 'pr' */ 46212111Sralph if (IF == NULL) { /* use output filter */ 463*37968Sbostic prog = _PATH_PR; 46412111Sralph av[0] = "pr"; 46512111Sralph av[1] = width; 46612111Sralph av[2] = length; 46712111Sralph av[3] = "-h"; 46812111Sralph av[4] = *title ? title : " "; 46912111Sralph av[5] = 0; 47012111Sralph fo = ofd; 47112111Sralph goto start; 47212111Sralph } 47312111Sralph pipe(p); 47412111Sralph if ((prchild = dofork(DORETURN)) == 0) { /* child */ 47512111Sralph dup2(fi, 0); /* file is stdin */ 47612111Sralph dup2(p[1], 1); /* pipe is stdout */ 47712111Sralph for (n = 3; n < NOFILE; n++) 47812111Sralph (void) close(n); 479*37968Sbostic execl(_PATH_PR, "pr", width, length, 480*37968Sbostic "-h", *title ? title : " ", 0); 481*37968Sbostic syslog(LOG_ERR, "cannot execl %s", _PATH_PR); 48212111Sralph exit(2); 48312111Sralph } 48412111Sralph (void) close(p[1]); /* close output side */ 48512111Sralph (void) close(fi); 48612111Sralph if (prchild < 0) { 48712111Sralph prchild = 0; 48812111Sralph (void) close(p[0]); 48917463Sralph return(ERROR); 49012111Sralph } 49112111Sralph fi = p[0]; /* use pipe for input */ 49212111Sralph case 'f': /* print plain text file */ 49312111Sralph prog = IF; 49412111Sralph av[1] = width; 49512111Sralph av[2] = length; 49612581Sralph av[3] = indent; 49712581Sralph n = 4; 49812111Sralph break; 49912111Sralph case 'l': /* like 'f' but pass control characters */ 50012111Sralph prog = IF; 50114325Sralph av[1] = "-c"; 50212111Sralph av[2] = width; 50312111Sralph av[3] = length; 50412581Sralph av[4] = indent; 50512581Sralph n = 5; 50612111Sralph break; 50712463Sralph case 'r': /* print a fortran text file */ 50812463Sralph prog = RF; 50912463Sralph av[1] = width; 51012463Sralph av[2] = length; 51112463Sralph n = 3; 51212463Sralph break; 51312111Sralph case 't': /* print troff output */ 51413233Sralph case 'n': /* print ditroff output */ 51512463Sralph case 'd': /* print tex output */ 51612111Sralph (void) unlink(".railmag"); 51712463Sralph if ((fo = creat(".railmag", FILMOD)) < 0) { 51816762Sralph syslog(LOG_ERR, "%s: cannot create .railmag", printer); 51912111Sralph (void) unlink(".railmag"); 52012111Sralph } else { 52112111Sralph for (n = 0; n < 4; n++) { 52212111Sralph if (fonts[n][0] != '/') 523*37968Sbostic (void) write(fo, _PATH_VFONT, 15); 52412111Sralph (void) write(fo, fonts[n], strlen(fonts[n])); 52512111Sralph (void) write(fo, "\n", 1); 52612111Sralph } 52712111Sralph (void) close(fo); 52812111Sralph } 52913233Sralph prog = (format == 't') ? TF : (format == 'n') ? NF : DF; 53012463Sralph av[1] = pxwidth; 53112463Sralph av[2] = pxlength; 53212463Sralph n = 3; 53312111Sralph break; 53412111Sralph case 'c': /* print cifplot output */ 53512111Sralph prog = CF; 53612463Sralph av[1] = pxwidth; 53712463Sralph av[2] = pxlength; 53812463Sralph n = 3; 53912111Sralph break; 54012111Sralph case 'g': /* print plot(1G) output */ 54112111Sralph prog = GF; 54212463Sralph av[1] = pxwidth; 54312463Sralph av[2] = pxlength; 54412463Sralph n = 3; 54512111Sralph break; 54612111Sralph case 'v': /* print raster output */ 54712111Sralph prog = VF; 54812463Sralph av[1] = pxwidth; 54912463Sralph av[2] = pxlength; 55012463Sralph n = 3; 55112111Sralph break; 55212111Sralph default: 55312111Sralph (void) close(fi); 55416762Sralph syslog(LOG_ERR, "%s: illegal format character '%c'", 55516762Sralph printer, format); 55617463Sralph return(ERROR); 55712111Sralph } 55812111Sralph if ((av[0] = rindex(prog, '/')) != NULL) 55912111Sralph av[0]++; 56012111Sralph else 56112111Sralph av[0] = prog; 56212111Sralph av[n++] = "-n"; 56312111Sralph av[n++] = logname; 56412111Sralph av[n++] = "-h"; 56514150Sralph av[n++] = fromhost; 56612111Sralph av[n++] = AF; 56712111Sralph av[n] = 0; 56812111Sralph fo = pfd; 56912111Sralph if (ofilter > 0) { /* stop output filter */ 57012111Sralph write(ofd, "\031\1", 2); 57112111Sralph while ((pid = wait3(&status, WUNTRACED, 0)) > 0 && pid != ofilter) 57212111Sralph ; 57312111Sralph if (status.w_stopval != WSTOPPED) { 57412111Sralph (void) close(fi); 57516762Sralph syslog(LOG_WARNING, "%s: output filter died (%d)", 57616762Sralph printer, status.w_retcode); 57717463Sralph return(REPRINT); 57812111Sralph } 57912111Sralph stopped++; 58012111Sralph } 58112111Sralph start: 58212111Sralph if ((child = dofork(DORETURN)) == 0) { /* child */ 58312111Sralph dup2(fi, 0); 58412111Sralph dup2(fo, 1); 58517304Sralph n = open(tmpfile, O_WRONLY|O_CREAT|O_TRUNC, 0664); 58615811Sralph if (n >= 0) 58715811Sralph dup2(n, 2); 58812111Sralph for (n = 3; n < NOFILE; n++) 58912111Sralph (void) close(n); 59012111Sralph execv(prog, av); 59116762Sralph syslog(LOG_ERR, "cannot execv %s", prog); 59212111Sralph exit(2); 59312111Sralph } 59412111Sralph (void) close(fi); 59512111Sralph if (child < 0) 59612111Sralph status.w_retcode = 100; 59712111Sralph else 59812111Sralph while ((pid = wait(&status)) > 0 && pid != child) 59912111Sralph ; 60012111Sralph child = 0; 60112111Sralph prchild = 0; 60212111Sralph if (stopped) { /* restart output filter */ 60312111Sralph if (kill(ofilter, SIGCONT) < 0) { 60416762Sralph syslog(LOG_ERR, "cannot restart output filter"); 60512111Sralph exit(1); 60612111Sralph } 60712111Sralph } 60812111Sralph tof = 0; 60915811Sralph if (!WIFEXITED(status)) { 61016762Sralph syslog(LOG_WARNING, "%s: Daemon filter '%c' terminated (%d)", 61116762Sralph printer, format, status.w_termsig); 61217463Sralph return(ERROR); 61317463Sralph } 61417463Sralph switch (status.w_retcode) { 61517463Sralph case 0: 61617463Sralph tof = 1; 61717463Sralph return(OK); 61817463Sralph case 1: 61917463Sralph return(REPRINT); 62017463Sralph default: 62116762Sralph syslog(LOG_WARNING, "%s: Daemon filter '%c' exited (%d)", 62216762Sralph printer, format, status.w_retcode); 62317463Sralph case 2: 62417463Sralph return(ERROR); 62517463Sralph } 62612111Sralph } 62712111Sralph 62812111Sralph /* 62912111Sralph * Send the daemon control file (cf) and any data files. 63012111Sralph * Return -1 if a non-recoverable error occured, 1 if a recoverable error and 63112111Sralph * 0 if all is well. 63212111Sralph */ 63312111Sralph sendit(file) 63412111Sralph char *file; 63512111Sralph { 63617463Sralph register int i, err = OK; 63717463Sralph char *cp, last[BUFSIZ]; 63812111Sralph 63912111Sralph /* 64012111Sralph * open control file 64112111Sralph */ 64216762Sralph if ((cfp = fopen(file, "r")) == NULL) 64317463Sralph return(OK); 64412111Sralph /* 64512111Sralph * read the control file for work to do 64612111Sralph * 64712111Sralph * file format -- first character in the line is a command 64812111Sralph * rest of the line is the argument. 64912111Sralph * commands of interest are: 65012111Sralph * 65112111Sralph * a-z -- "file name" name of file to print 65212111Sralph * U -- "unlink" name of file to remove 65312111Sralph * (after we print it. (Pass 2 only)). 65412111Sralph */ 65512111Sralph 65612111Sralph /* 65712111Sralph * pass 1 65812111Sralph */ 65912111Sralph while (getline(cfp)) { 66012111Sralph again: 66117463Sralph if (line[0] == 'S') { 66217463Sralph cp = line+1; 66317463Sralph i = 0; 66417463Sralph while (*cp >= '0' && *cp <= '9') 66517463Sralph i = i * 10 + (*cp++ - '0'); 66617463Sralph fdev = i; 66717463Sralph cp++; 66817463Sralph i = 0; 66917463Sralph while (*cp >= '0' && *cp <= '9') 67017463Sralph i = i * 10 + (*cp++ - '0'); 67117463Sralph fino = i; 67217463Sralph continue; 67317463Sralph } 67412111Sralph if (line[0] >= 'a' && line[0] <= 'z') { 67512111Sralph strcpy(last, line); 67617463Sralph while (i = getline(cfp)) 67712111Sralph if (strcmp(last, line)) 67812111Sralph break; 67917463Sralph switch (sendfile('\3', last+1)) { 68017463Sralph case OK: 68117463Sralph if (i) 68217463Sralph goto again; 68317463Sralph break; 68417463Sralph case REPRINT: 68512111Sralph (void) fclose(cfp); 68617463Sralph return(REPRINT); 68717463Sralph case ACCESS: 68817463Sralph sendmail(logname, ACCESS); 68917463Sralph case ERROR: 69017463Sralph err = ERROR; 69117463Sralph } 69212111Sralph break; 69312111Sralph } 69412111Sralph } 69517463Sralph if (err == OK && sendfile('\2', file) > 0) { 69612111Sralph (void) fclose(cfp); 69717463Sralph return(REPRINT); 69812111Sralph } 69912111Sralph /* 70012111Sralph * pass 2 70112111Sralph */ 70212111Sralph fseek(cfp, 0L, 0); 70312111Sralph while (getline(cfp)) 70412111Sralph if (line[0] == 'U') 70512111Sralph (void) unlink(line+1); 70612111Sralph /* 70717463Sralph * clean-up in case another control file exists 70812111Sralph */ 70912111Sralph (void) fclose(cfp); 71012111Sralph (void) unlink(file); 71117463Sralph return(err); 71212111Sralph } 71312111Sralph 71412111Sralph /* 71512111Sralph * Send a data file to the remote machine and spool it. 71612111Sralph * Return positive if we should try resending. 71712111Sralph */ 71812111Sralph sendfile(type, file) 71912111Sralph char type, *file; 72012111Sralph { 72112111Sralph register int f, i, amt; 72212111Sralph struct stat stb; 72312111Sralph char buf[BUFSIZ]; 72416762Sralph int sizerr, resp; 72512111Sralph 72617463Sralph if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0) 72717463Sralph return(ERROR); 72817463Sralph /* 72917463Sralph * Check to see if data file is a symbolic link. If so, it should 73017463Sralph * still point to the same file or someone is trying to print something 73117463Sralph * he shouldn't. 73217463Sralph */ 73317463Sralph if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 && 73417463Sralph (stb.st_dev != fdev || stb.st_ino != fino)) 73517463Sralph return(ACCESS); 73612111Sralph (void) sprintf(buf, "%c%d %s\n", type, stb.st_size, file); 73712111Sralph amt = strlen(buf); 73816762Sralph for (i = 0; ; i++) { 73916762Sralph if (write(pfd, buf, amt) != amt || 74016762Sralph (resp = response()) < 0 || resp == '\1') { 74116762Sralph (void) close(f); 74217463Sralph return(REPRINT); 74316762Sralph } else if (resp == '\0') 74416762Sralph break; 74516762Sralph if (i == 0) 74616762Sralph status("no space on remote; waiting for queue to drain"); 74716762Sralph if (i == 10) 74824861Seric syslog(LOG_ALERT, "%s: can't send to %s; queue full", 74916762Sralph printer, RM); 75016762Sralph sleep(5 * 60); 75112692Sralph } 75216762Sralph if (i) 75316762Sralph status("sending to %s", RM); 75412111Sralph sizerr = 0; 75512111Sralph for (i = 0; i < stb.st_size; i += BUFSIZ) { 75612111Sralph amt = BUFSIZ; 75712111Sralph if (i + amt > stb.st_size) 75812111Sralph amt = stb.st_size - i; 75912111Sralph if (sizerr == 0 && read(f, buf, amt) != amt) 76012111Sralph sizerr = 1; 76112692Sralph if (write(pfd, buf, amt) != amt) { 76212692Sralph (void) close(f); 76317463Sralph return(REPRINT); 76412692Sralph } 76512111Sralph } 76612111Sralph (void) close(f); 76712111Sralph if (sizerr) { 76816762Sralph syslog(LOG_INFO, "%s: %s: changed size", printer, file); 76917463Sralph /* tell recvjob to ignore this file */ 77017463Sralph (void) write(pfd, "\1", 1); 77117463Sralph return(ERROR); 77217463Sralph } 77317463Sralph if (write(pfd, "", 1) != 1 || response()) 77417463Sralph return(REPRINT); 77517463Sralph return(OK); 77612111Sralph } 77712111Sralph 77812111Sralph /* 77912111Sralph * Check to make sure there have been no errors and that both programs 78012111Sralph * are in sync with eachother. 78112111Sralph * Return non-zero if the connection was lost. 78212111Sralph */ 78316762Sralph response() 78412111Sralph { 78512111Sralph char resp; 78612111Sralph 78716762Sralph if (read(pfd, &resp, 1) != 1) { 78816762Sralph syslog(LOG_INFO, "%s: lost connection", printer); 78916762Sralph return(-1); 79012111Sralph } 79116762Sralph return(resp); 79212111Sralph } 79312111Sralph 79412111Sralph /* 79512111Sralph * Banner printing stuff 79612111Sralph */ 79712111Sralph banner(name1, name2) 79812111Sralph char *name1, *name2; 79912111Sralph { 80012111Sralph time_t tvec; 80112111Sralph extern char *ctime(); 80212111Sralph 80312111Sralph time(&tvec); 80412111Sralph if (!SF && !tof) 80512111Sralph (void) write(ofd, FF, strlen(FF)); 80612111Sralph if (SB) { /* short banner only */ 80712111Sralph if (class[0]) { 80812111Sralph (void) write(ofd, class, strlen(class)); 80912111Sralph (void) write(ofd, ":", 1); 81012111Sralph } 81112111Sralph (void) write(ofd, name1, strlen(name1)); 81212111Sralph (void) write(ofd, " Job: ", 7); 81312111Sralph (void) write(ofd, name2, strlen(name2)); 81412111Sralph (void) write(ofd, " Date: ", 8); 81512111Sralph (void) write(ofd, ctime(&tvec), 24); 81612111Sralph (void) write(ofd, "\n", 1); 81712111Sralph } else { /* normal banner */ 81812111Sralph (void) write(ofd, "\n\n\n", 3); 81912111Sralph scan_out(ofd, name1, '\0'); 82012111Sralph (void) write(ofd, "\n\n", 2); 82112111Sralph scan_out(ofd, name2, '\0'); 82212111Sralph if (class[0]) { 82312111Sralph (void) write(ofd,"\n\n\n",3); 82412111Sralph scan_out(ofd, class, '\0'); 82512111Sralph } 82612111Sralph (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15); 82712111Sralph (void) write(ofd, name2, strlen(name2)); 82812111Sralph (void) write(ofd, "\n\t\t\t\t\tDate: ", 12); 82912111Sralph (void) write(ofd, ctime(&tvec), 24); 83012111Sralph (void) write(ofd, "\n", 1); 83112111Sralph } 83212111Sralph if (!SF) 83312111Sralph (void) write(ofd, FF, strlen(FF)); 83412111Sralph tof = 1; 83512111Sralph } 83612111Sralph 83716762Sralph char * 83812111Sralph scnline(key, p, c) 83912111Sralph register char key, *p; 84012111Sralph char c; 84112111Sralph { 84212111Sralph register scnwidth; 84312111Sralph 84412111Sralph for (scnwidth = WIDTH; --scnwidth;) { 84512111Sralph key <<= 1; 84612111Sralph *p++ = key & 0200 ? c : BACKGND; 84712111Sralph } 84812111Sralph return (p); 84912111Sralph } 85012111Sralph 85112111Sralph #define TRC(q) (((q)-' ')&0177) 85212111Sralph 85312111Sralph scan_out(scfd, scsp, dlm) 85412111Sralph int scfd; 85512111Sralph char *scsp, dlm; 85612111Sralph { 85712111Sralph register char *strp; 85812111Sralph register nchrs, j; 85912111Sralph char outbuf[LINELEN+1], *sp, c, cc; 86012111Sralph int d, scnhgt; 86112111Sralph extern char scnkey[][HEIGHT]; /* in lpdchar.c */ 86212111Sralph 86312111Sralph for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) { 86412111Sralph strp = &outbuf[0]; 86512111Sralph sp = scsp; 86612111Sralph for (nchrs = 0; ; ) { 86712111Sralph d = dropit(c = TRC(cc = *sp++)); 86812111Sralph if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d)) 86912111Sralph for (j = WIDTH; --j;) 87012111Sralph *strp++ = BACKGND; 87112111Sralph else 87212111Sralph strp = scnline(scnkey[c][scnhgt-1-d], strp, cc); 87312111Sralph if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1) 87412111Sralph break; 87512111Sralph *strp++ = BACKGND; 87612111Sralph *strp++ = BACKGND; 87712111Sralph } 87812111Sralph while (*--strp == BACKGND && strp >= outbuf) 87912111Sralph ; 88012111Sralph strp++; 88112111Sralph *strp++ = '\n'; 88212111Sralph (void) write(scfd, outbuf, strp-outbuf); 88312111Sralph } 88412111Sralph } 88512111Sralph 88612111Sralph dropit(c) 88712111Sralph char c; 88812111Sralph { 88912111Sralph switch(c) { 89012111Sralph 89112111Sralph case TRC('_'): 89212111Sralph case TRC(';'): 89312111Sralph case TRC(','): 89412111Sralph case TRC('g'): 89512111Sralph case TRC('j'): 89612111Sralph case TRC('p'): 89712111Sralph case TRC('q'): 89812111Sralph case TRC('y'): 89912111Sralph return (DROP); 90012111Sralph 90112111Sralph default: 90212111Sralph return (0); 90312111Sralph } 90412111Sralph } 90512111Sralph 90612111Sralph /* 90712111Sralph * sendmail --- 90812111Sralph * tell people about job completion 90912111Sralph */ 91015811Sralph sendmail(user, bombed) 91115811Sralph char *user; 91212111Sralph int bombed; 91312111Sralph { 91412111Sralph register int i; 91515811Sralph int p[2], s; 91612111Sralph register char *cp; 91712111Sralph char buf[100]; 91815811Sralph struct stat stb; 91915811Sralph FILE *fp; 92012111Sralph 92112111Sralph pipe(p); 92215811Sralph if ((s = dofork(DORETURN)) == 0) { /* child */ 92312111Sralph dup2(p[0], 0); 92412111Sralph for (i = 3; i < NOFILE; i++) 92512111Sralph (void) close(i); 926*37968Sbostic if ((cp = rindex(_PATH_SENDMAIL, '/')) != NULL) 92712111Sralph cp++; 92812111Sralph else 929*37968Sbostic cp = _PATH_SENDMAIL; 93015811Sralph sprintf(buf, "%s@%s", user, fromhost); 931*37968Sbostic execl(_PATH_SENDMAIL, cp, buf, 0); 93212111Sralph exit(0); 93315811Sralph } else if (s > 0) { /* parent */ 93412111Sralph dup2(p[1], 1); 93515811Sralph printf("To: %s@%s\n", user, fromhost); 93612111Sralph printf("Subject: printer job\n\n"); 93712111Sralph printf("Your printer job "); 93812111Sralph if (*jobname) 93912111Sralph printf("(%s) ", jobname); 94012463Sralph switch (bombed) { 94117463Sralph case OK: 94212463Sralph printf("\ncompleted successfully\n"); 94312463Sralph break; 94412463Sralph default: 94517463Sralph case FATALERR: 94612463Sralph printf("\ncould not be printed\n"); 94712463Sralph break; 94817463Sralph case NOACCT: 94912463Sralph printf("\ncould not be printed without an account on %s\n", host); 95012463Sralph break; 95117463Sralph case FILTERERR: 95215811Sralph if (stat(tmpfile, &stb) < 0 || stb.st_size == 0 || 95315811Sralph (fp = fopen(tmpfile, "r")) == NULL) { 95415811Sralph printf("\nwas printed but had some errors\n"); 95515811Sralph break; 95615811Sralph } 95715811Sralph printf("\nwas printed but had the following errors:\n"); 95815811Sralph while ((i = getc(fp)) != EOF) 95915811Sralph putchar(i); 96015811Sralph (void) fclose(fp); 96117463Sralph break; 96217463Sralph case ACCESS: 96317463Sralph printf("\nwas not printed because it was not linked to the original file\n"); 96412463Sralph } 96512111Sralph fflush(stdout); 96612111Sralph (void) close(1); 96712111Sralph } 96812111Sralph (void) close(p[0]); 96912111Sralph (void) close(p[1]); 97015811Sralph wait(&s); 97112111Sralph } 97212111Sralph 97312111Sralph /* 97412111Sralph * dofork - fork with retries on failure 97512111Sralph */ 97612111Sralph dofork(action) 97712111Sralph int action; 97812111Sralph { 97912111Sralph register int i, pid; 98012111Sralph 98112111Sralph for (i = 0; i < 20; i++) { 98212463Sralph if ((pid = fork()) < 0) { 98312111Sralph sleep((unsigned)(i*i)); 98412463Sralph continue; 98512463Sralph } 98612463Sralph /* 98712463Sralph * Child should run as daemon instead of root 98812463Sralph */ 98912463Sralph if (pid == 0) 99012463Sralph setuid(DU); 99112463Sralph return(pid); 99212111Sralph } 99316762Sralph syslog(LOG_ERR, "can't fork"); 99412111Sralph 99512111Sralph switch (action) { 99612111Sralph case DORETURN: 99712111Sralph return (-1); 99812111Sralph default: 99916762Sralph syslog(LOG_ERR, "bad action (%d) to dofork", action); 100012111Sralph /*FALL THRU*/ 100112111Sralph case DOABORT: 100212111Sralph exit(1); 100312111Sralph } 100412111Sralph /*NOTREACHED*/ 100512111Sralph } 100612111Sralph 100712111Sralph /* 100816762Sralph * Kill child processes to abort current job. 100912111Sralph */ 101016762Sralph abortpr() 101112111Sralph { 101215811Sralph (void) unlink(tmpfile); 101312111Sralph kill(0, SIGINT); 101412111Sralph if (ofilter > 0) 101512111Sralph kill(ofilter, SIGCONT); 101612111Sralph while (wait(0) > 0) 101712111Sralph ; 101812111Sralph exit(0); 101912111Sralph } 102012111Sralph 102112111Sralph init() 102212111Sralph { 102312111Sralph int status; 102412111Sralph 102525468Stef if ((status = pgetent(line, printer)) < 0) { 102625468Stef syslog(LOG_ERR, "can't open printer description file"); 102725468Stef exit(1); 102825468Stef } else if (status == 0) { 102925468Stef syslog(LOG_ERR, "unknown printer: %s", printer); 103025468Stef exit(1); 103125468Stef } 103212111Sralph if ((LP = pgetstr("lp", &bp)) == NULL) 1033*37968Sbostic LP = _PATH_DEFDEVLP; 103412111Sralph if ((RP = pgetstr("rp", &bp)) == NULL) 103512463Sralph RP = DEFLP; 103612111Sralph if ((LO = pgetstr("lo", &bp)) == NULL) 103712111Sralph LO = DEFLOCK; 103812111Sralph if ((ST = pgetstr("st", &bp)) == NULL) 103912111Sralph ST = DEFSTAT; 104012111Sralph if ((LF = pgetstr("lf", &bp)) == NULL) 1041*37968Sbostic LF = _PATH_CONSOLE; 104212111Sralph if ((SD = pgetstr("sd", &bp)) == NULL) 1043*37968Sbostic SD = _PATH_DEFSPOOL; 104412111Sralph if ((DU = pgetnum("du")) < 0) 104512111Sralph DU = DEFUID; 104612111Sralph if ((FF = pgetstr("ff", &bp)) == NULL) 104712111Sralph FF = DEFFF; 104812111Sralph if ((PW = pgetnum("pw")) < 0) 104912111Sralph PW = DEFWIDTH; 105012111Sralph sprintf(&width[2], "%d", PW); 105112111Sralph if ((PL = pgetnum("pl")) < 0) 105212111Sralph PL = DEFLENGTH; 105312111Sralph sprintf(&length[2], "%d", PL); 105412463Sralph if ((PX = pgetnum("px")) < 0) 105512463Sralph PX = 0; 105612463Sralph sprintf(&pxwidth[2], "%d", PX); 105712463Sralph if ((PY = pgetnum("py")) < 0) 105812463Sralph PY = 0; 105912463Sralph sprintf(&pxlength[2], "%d", PY); 106012111Sralph RM = pgetstr("rm", &bp); 106125468Stef /* 106225468Stef * Figure out whether the local machine is the same as the remote 106325468Stef * machine entry (if it exists). If not, then ignore the local 106425468Stef * queue information. 106525468Stef */ 106625468Stef if (RM != (char *) NULL) { 106725468Stef char name[256]; 106825468Stef struct hostent *hp; 106925468Stef 107025468Stef /* get the standard network name of the local host */ 107125468Stef gethostname(name, sizeof(name)); 107225468Stef name[sizeof(name)-1] = '\0'; 107325468Stef hp = gethostbyname(name); 107425468Stef if (hp == (struct hostent *) NULL) { 107525468Stef syslog(LOG_ERR, 107625468Stef "unable to get network name for local machine %s", 107725468Stef name); 107825468Stef goto localcheck_done; 107925468Stef } else strcpy(name, hp->h_name); 108025468Stef 108125468Stef /* get the standard network name of RM */ 108225468Stef hp = gethostbyname(RM); 108325468Stef if (hp == (struct hostent *) NULL) { 108425468Stef syslog(LOG_ERR, 108525468Stef "unable to get hostname for remote machine %s", RM); 108625468Stef goto localcheck_done; 108725468Stef } 108825468Stef 108925468Stef /* if printer is not on local machine, ignore LP */ 109025468Stef if (strcmp(name, hp->h_name) != 0) *LP = '\0'; 109125468Stef } 109225468Stef localcheck_done: 109325468Stef 109412111Sralph AF = pgetstr("af", &bp); 109512111Sralph OF = pgetstr("of", &bp); 109612111Sralph IF = pgetstr("if", &bp); 109712463Sralph RF = pgetstr("rf", &bp); 109812111Sralph TF = pgetstr("tf", &bp); 109913233Sralph NF = pgetstr("nf", &bp); 110012111Sralph DF = pgetstr("df", &bp); 110112111Sralph GF = pgetstr("gf", &bp); 110212111Sralph VF = pgetstr("vf", &bp); 110312111Sralph CF = pgetstr("cf", &bp); 110412111Sralph TR = pgetstr("tr", &bp); 110512463Sralph RS = pgetflag("rs"); 110612111Sralph SF = pgetflag("sf"); 110712111Sralph SH = pgetflag("sh"); 110812111Sralph SB = pgetflag("sb"); 110918127Sralph HL = pgetflag("hl"); 111012111Sralph RW = pgetflag("rw"); 111112111Sralph BR = pgetnum("br"); 111212111Sralph if ((FC = pgetnum("fc")) < 0) 111312111Sralph FC = 0; 111412111Sralph if ((FS = pgetnum("fs")) < 0) 111512111Sralph FS = 0; 111612111Sralph if ((XC = pgetnum("xc")) < 0) 111712111Sralph XC = 0; 111812111Sralph if ((XS = pgetnum("xs")) < 0) 111912111Sralph XS = 0; 112012581Sralph tof = !pgetflag("fo"); 112112111Sralph } 112212111Sralph 112312463Sralph /* 112412463Sralph * Acquire line printer or remote connection. 112512463Sralph */ 112612463Sralph openpr() 112712463Sralph { 112812463Sralph register int i, n; 112916762Sralph int resp; 113012463Sralph 113112463Sralph if (*LP) { 113212463Sralph for (i = 1; ; i = i < 32 ? i << 1 : i) { 113313148Ssam pfd = open(LP, RW ? O_RDWR : O_WRONLY); 113412463Sralph if (pfd >= 0) 113512463Sralph break; 113612463Sralph if (errno == ENOENT) { 113716762Sralph syslog(LOG_ERR, "%s: %m", LP); 113812463Sralph exit(1); 113912463Sralph } 114012463Sralph if (i == 1) 114112463Sralph status("waiting for %s to become ready (offline ?)", printer); 114212463Sralph sleep(i); 114312463Sralph } 114412463Sralph if (isatty(pfd)) 114512463Sralph setty(); 114612463Sralph status("%s is ready and printing", printer); 114712463Sralph } else if (RM != NULL) { 114816762Sralph for (i = 1; ; i = i < 256 ? i << 1 : i) { 114916762Sralph resp = -1; 115012528Sralph pfd = getport(RM); 115112463Sralph if (pfd >= 0) { 115212463Sralph (void) sprintf(line, "\2%s\n", RP); 115312463Sralph n = strlen(line); 115416762Sralph if (write(pfd, line, n) == n && 115516762Sralph (resp = response()) == '\0') 115612463Sralph break; 115716031Sralph (void) close(pfd); 115812463Sralph } 115916031Sralph if (i == 1) { 116016762Sralph if (resp < 0) 116116031Sralph status("waiting for %s to come up", RM); 116216762Sralph else { 116316031Sralph status("waiting for queue to be enabled on %s", RM); 116416762Sralph i = 256; 116516762Sralph } 116616031Sralph } 116712463Sralph sleep(i); 116812463Sralph } 116912463Sralph status("sending to %s", RM); 117012463Sralph remote = 1; 117112463Sralph } else { 117216762Sralph syslog(LOG_ERR, "%s: no line printer device or host name", 117316762Sralph printer); 117412463Sralph exit(1); 117512463Sralph } 117612463Sralph /* 117712463Sralph * Start up an output filter, if needed. 117812463Sralph */ 117912463Sralph if (OF) { 118012463Sralph int p[2]; 118112463Sralph char *cp; 118212463Sralph 118312463Sralph pipe(p); 118412463Sralph if ((ofilter = dofork(DOABORT)) == 0) { /* child */ 118512463Sralph dup2(p[0], 0); /* pipe is std in */ 118612463Sralph dup2(pfd, 1); /* printer is std out */ 118712463Sralph for (i = 3; i < NOFILE; i++) 118812463Sralph (void) close(i); 118912463Sralph if ((cp = rindex(OF, '/')) == NULL) 119012463Sralph cp = OF; 119112463Sralph else 119212463Sralph cp++; 119312463Sralph execl(OF, cp, width, length, 0); 119416762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, OF); 119512463Sralph exit(1); 119612463Sralph } 119712463Sralph (void) close(p[0]); /* close input side */ 119812463Sralph ofd = p[1]; /* use pipe for output */ 119912463Sralph } else { 120012463Sralph ofd = pfd; 120112463Sralph ofilter = 0; 120212463Sralph } 120312463Sralph } 120412463Sralph 120512111Sralph struct bauds { 120612111Sralph int baud; 120712111Sralph int speed; 120812111Sralph } bauds[] = { 120912111Sralph 50, B50, 121012111Sralph 75, B75, 121112111Sralph 110, B110, 121212111Sralph 134, B134, 121312111Sralph 150, B150, 121412111Sralph 200, B200, 121512111Sralph 300, B300, 121612111Sralph 600, B600, 121712111Sralph 1200, B1200, 121812111Sralph 1800, B1800, 121912111Sralph 2400, B2400, 122012111Sralph 4800, B4800, 122112111Sralph 9600, B9600, 122212111Sralph 19200, EXTA, 122312111Sralph 38400, EXTB, 122412111Sralph 0, 0 122512111Sralph }; 122612111Sralph 122712111Sralph /* 122812111Sralph * setup tty lines. 122912111Sralph */ 123012111Sralph setty() 123112111Sralph { 123212111Sralph struct sgttyb ttybuf; 123312111Sralph register struct bauds *bp; 123412111Sralph 123512111Sralph if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) { 123616762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer); 123712111Sralph exit(1); 123812111Sralph } 123912111Sralph if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) { 124016762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCGETP): %m", printer); 124112111Sralph exit(1); 124212111Sralph } 124312111Sralph if (BR > 0) { 124412111Sralph for (bp = bauds; bp->baud; bp++) 124512111Sralph if (BR == bp->baud) 124612111Sralph break; 124712111Sralph if (!bp->baud) { 124816762Sralph syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR); 124912111Sralph exit(1); 125012111Sralph } 125112111Sralph ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed; 125212111Sralph } 125313169Sralph ttybuf.sg_flags &= ~FC; 125413169Sralph ttybuf.sg_flags |= FS; 125512111Sralph if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) { 125616762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCSETP): %m", printer); 125712111Sralph exit(1); 125812111Sralph } 125917168Sralph if (XC || XS) { 126017168Sralph int ldisc = NTTYDISC; 126117168Sralph 126217168Sralph if (ioctl(pfd, TIOCSETD, &ldisc) < 0) { 126317168Sralph syslog(LOG_ERR, "%s: ioctl(TIOCSETD): %m", printer); 126417168Sralph exit(1); 126517168Sralph } 126617168Sralph } 126712111Sralph if (XC) { 126812111Sralph if (ioctl(pfd, TIOCLBIC, &XC) < 0) { 126916762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCLBIC): %m", printer); 127012111Sralph exit(1); 127112111Sralph } 127212111Sralph } 127312111Sralph if (XS) { 127412111Sralph if (ioctl(pfd, TIOCLBIS, &XS) < 0) { 127516762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCLBIS): %m", printer); 127612111Sralph exit(1); 127712111Sralph } 127812111Sralph } 127912111Sralph } 128012463Sralph 128112463Sralph /*VARARGS1*/ 128212463Sralph status(msg, a1, a2, a3) 128312463Sralph char *msg; 128412463Sralph { 128512463Sralph register int fd; 128612463Sralph char buf[BUFSIZ]; 128712463Sralph 128812463Sralph umask(0); 128913148Ssam fd = open(ST, O_WRONLY|O_CREAT, 0664); 129016762Sralph if (fd < 0 || flock(fd, LOCK_EX) < 0) { 129116762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, ST); 129216762Sralph exit(1); 129316762Sralph } 129413148Ssam ftruncate(fd, 0); 129512463Sralph sprintf(buf, msg, a1, a2, a3); 129612463Sralph strcat(buf, "\n"); 129712463Sralph (void) write(fd, buf, strlen(buf)); 129812463Sralph (void) close(fd); 129912463Sralph } 1300