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 6*34936Sbostic * provided that the above copyright notice and this paragraph are 7*34936Sbostic * duplicated in all such forms and that any documentation, 8*34936Sbostic * advertising materials, and other materials related to such 9*34936Sbostic * distribution and use acknowledge that the software was developed 10*34936Sbostic * by the University of California, Berkeley. The name of the 11*34936Sbostic * University may not be used to endorse or promote products derived 12*34936Sbostic * from this software without specific prior written permission. 13*34936Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14*34936Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15*34936Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1622437Sdist */ 1722437Sdist 1813954Ssam #ifndef lint 19*34936Sbostic static char sccsid[] = "@(#)printjob.c 5.6 (Berkeley) 06/30/88"; 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" 3012111Sralph 3116762Sralph #define DORETURN 0 /* absorb fork error */ 3216762Sralph #define DOABORT 1 /* abort if dofork fails */ 3312111Sralph 3417463Sralph /* 3517463Sralph * Error tokens 3617463Sralph */ 3717463Sralph #define REPRINT -2 3817463Sralph #define ERROR -1 3917463Sralph #define OK 0 4017463Sralph #define FATALERR 1 4117463Sralph #define NOACCT 2 4217463Sralph #define FILTERERR 3 4317463Sralph #define ACCESS 4 4417463Sralph 4516762Sralph char title[80]; /* ``pr'' title */ 4616762Sralph FILE *cfp; /* control file */ 4716762Sralph int pfd; /* printer file descriptor */ 4816762Sralph int ofd; /* output filter file descriptor */ 4916762Sralph int lfd; /* lock file descriptor */ 5016762Sralph int pid; /* pid of lpd process */ 5116762Sralph int prchild; /* id of pr process */ 5216762Sralph int child; /* id of any filters */ 5316762Sralph int ofilter; /* id of output filter, if any */ 5416762Sralph int tof; /* true if at top of form */ 5516762Sralph int remote; /* true if sending files to remote */ 5617463Sralph dev_t fdev; /* device of file pointed to by symlink */ 5717463Sralph ino_t fino; /* inode of file pointed to by symlink */ 5812111Sralph 5916762Sralph char fromhost[32]; /* user's host machine */ 6016762Sralph char logname[32]; /* user's login name */ 6116762Sralph char jobname[100]; /* job or file name */ 6216762Sralph char class[32]; /* classification field */ 6316762Sralph char width[10] = "-w"; /* page width in characters */ 6416762Sralph char length[10] = "-l"; /* page length in lines */ 6516762Sralph char pxwidth[10] = "-x"; /* page width in pixels */ 6616762Sralph char pxlength[10] = "-y"; /* page length in pixels */ 6716762Sralph char indent[10] = "-i0"; /* indentation size in characters */ 6816762Sralph char tmpfile[] = "errsXXXXXX"; /* file name for filter output */ 6912111Sralph 7012111Sralph printjob() 7112111Sralph { 7212111Sralph struct stat stb; 7312111Sralph register struct queue *q, **qp; 7412111Sralph struct queue **queue; 7512111Sralph register int i, nitems; 7612111Sralph long pidoff; 7716762Sralph int count = 0; 7816762Sralph extern int abortpr(); 7912111Sralph 8012111Sralph init(); /* set up capabilities */ 8113442Sralph (void) write(1, "", 1); /* ack that daemon is started */ 8225496Seric (void) close(2); /* set up log file */ 8325496Seric if (open(LF, O_WRONLY|O_APPEND, 0664) < 0) { 8425496Seric syslog(LOG_ERR, "%s: %m", LF); 8525496Seric (void) open("/dev/null", O_WRONLY); 8625496Seric } 8716762Sralph setgid(getegid()); 8812463Sralph pid = getpid(); /* for use with lprm */ 8912111Sralph setpgrp(0, pid); 9016762Sralph signal(SIGHUP, abortpr); 9116762Sralph signal(SIGINT, abortpr); 9216762Sralph signal(SIGQUIT, abortpr); 9316762Sralph signal(SIGTERM, abortpr); 9412111Sralph 9515811Sralph (void) mktemp(tmpfile); 9615811Sralph 9712111Sralph /* 9812111Sralph * uses short form file names 9912111Sralph */ 10012111Sralph if (chdir(SD) < 0) { 10116762Sralph syslog(LOG_ERR, "%s: %m", SD); 10212111Sralph exit(1); 10312111Sralph } 10412463Sralph if (stat(LO, &stb) == 0 && (stb.st_mode & 0100)) 10512463Sralph exit(0); /* printing disabled */ 10614150Sralph lfd = open(LO, O_WRONLY|O_CREAT, 0644); 10713169Sralph if (lfd < 0) { 10816762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, LO); 10913169Sralph exit(1); 11013169Sralph } 11113169Sralph if (flock(lfd, LOCK_EX|LOCK_NB) < 0) { 11212111Sralph if (errno == EWOULDBLOCK) /* active deamon present */ 11312111Sralph exit(0); 11416762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, LO); 11512111Sralph exit(1); 11612111Sralph } 11713148Ssam ftruncate(lfd, 0); 11812111Sralph /* 11912111Sralph * write process id for others to know 12012111Sralph */ 12112111Sralph sprintf(line, "%u\n", pid); 12212111Sralph pidoff = i = strlen(line); 12312463Sralph if (write(lfd, line, i) != i) { 12416762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, LO); 12512111Sralph exit(1); 12612111Sralph } 12712111Sralph /* 12812111Sralph * search the spool directory for work and sort by queue order. 12912111Sralph */ 13012111Sralph if ((nitems = getq(&queue)) < 0) { 13116762Sralph syslog(LOG_ERR, "%s: can't scan %s", printer, SD); 13212111Sralph exit(1); 13312111Sralph } 13412463Sralph if (nitems == 0) /* no work to do */ 13512111Sralph exit(0); 13613169Sralph if (stb.st_mode & 01) { /* reset queue flag */ 13713169Sralph if (fchmod(lfd, stb.st_mode & 0776) < 0) 13816762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, LO); 13913169Sralph } 14012463Sralph openpr(); /* open printer or remote */ 14112463Sralph again: 14212111Sralph /* 14312111Sralph * we found something to do now do it -- 14412111Sralph * write the name of the current control file into the lock file 14512111Sralph * so the spool queue program can tell what we're working on 14612111Sralph */ 14712111Sralph for (qp = queue; nitems--; free((char *) q)) { 14812111Sralph q = *qp++; 14912111Sralph if (stat(q->q_name, &stb) < 0) 15012111Sralph continue; 15112463Sralph restart: 15212111Sralph (void) lseek(lfd, pidoff, 0); 15312111Sralph (void) sprintf(line, "%s\n", q->q_name); 15412111Sralph i = strlen(line); 15512111Sralph if (write(lfd, line, i) != i) 15616762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, LO); 15712111Sralph if (!remote) 15812111Sralph i = printit(q->q_name); 15912111Sralph else 16012111Sralph i = sendit(q->q_name); 16112463Sralph /* 16213169Sralph * Check to see if we are supposed to stop printing or 16313169Sralph * if we are to rebuild the queue. 16412463Sralph */ 16513169Sralph if (fstat(lfd, &stb) == 0) { 16616762Sralph /* stop printing before starting next job? */ 16713169Sralph if (stb.st_mode & 0100) 16813169Sralph goto done; 16916762Sralph /* rebuild queue (after lpc topq) */ 17013169Sralph if (stb.st_mode & 01) { 17113169Sralph for (free((char *) q); nitems--; free((char *) q)) 17213169Sralph q = *qp++; 17313169Sralph if (fchmod(lfd, stb.st_mode & 0776) < 0) 17416762Sralph syslog(LOG_WARNING, "%s: %s: %m", 17516762Sralph printer, LO); 17613169Sralph break; 17713169Sralph } 17813169Sralph } 17917463Sralph if (i == OK) /* file ok and printed */ 18014150Sralph count++; 18117463Sralph else if (i == REPRINT) { /* try reprinting the job */ 18216762Sralph syslog(LOG_INFO, "restarting %s", printer); 18312111Sralph if (ofilter > 0) { 18412111Sralph kill(ofilter, SIGCONT); /* to be sure */ 18512111Sralph (void) close(ofd); 18612111Sralph while ((i = wait(0)) > 0 && i != ofilter) 18712111Sralph ; 18812111Sralph ofilter = 0; 18912111Sralph } 19012463Sralph (void) close(pfd); /* close printer */ 19115811Sralph if (ftruncate(lfd, pidoff) < 0) 19216762Sralph syslog(LOG_WARNING, "%s: %s: %m", printer, LO); 19312463Sralph openpr(); /* try to reopen printer */ 19412111Sralph goto restart; 19512111Sralph } 19612111Sralph } 19712111Sralph free((char *) queue); 19812463Sralph /* 19912463Sralph * search the spool directory for more work. 20012463Sralph */ 20112463Sralph if ((nitems = getq(&queue)) < 0) { 20216762Sralph syslog(LOG_ERR, "%s: can't scan %s", printer, SD); 20312463Sralph exit(1); 20412463Sralph } 20512463Sralph if (nitems == 0) { /* no more work to do */ 20612463Sralph done: 20714150Sralph if (count > 0) { /* Files actually printed */ 20814150Sralph if (!SF && !tof) 20914150Sralph (void) write(ofd, FF, strlen(FF)); 21014150Sralph if (TR != NULL) /* output trailer */ 21114150Sralph (void) write(ofd, TR, strlen(TR)); 21214150Sralph } 21315811Sralph (void) unlink(tmpfile); 21412463Sralph exit(0); 21512463Sralph } 21612111Sralph goto again; 21712111Sralph } 21812111Sralph 21912111Sralph char fonts[4][50]; /* fonts for troff */ 22012111Sralph 22116762Sralph char ifonts[4][18] = { 22212111Sralph "/usr/lib/vfont/R", 22312111Sralph "/usr/lib/vfont/I", 22412111Sralph "/usr/lib/vfont/B", 22512111Sralph "/usr/lib/vfont/S" 22612111Sralph }; 22712111Sralph 22812111Sralph /* 22912111Sralph * The remaining part is the reading of the control file (cf) 23012111Sralph * and performing the various actions. 23112111Sralph */ 23212111Sralph printit(file) 23312111Sralph char *file; 23412111Sralph { 23512111Sralph register int i; 23617463Sralph char *cp; 23717463Sralph int bombed = OK; 23812111Sralph 23912111Sralph /* 24017463Sralph * open control file; ignore if no longer there. 24112111Sralph */ 24212111Sralph if ((cfp = fopen(file, "r")) == NULL) { 24316762Sralph syslog(LOG_INFO, "%s: %s: %m", printer, file); 24417463Sralph return(OK); 24512111Sralph } 24612111Sralph /* 24712111Sralph * Reset troff fonts. 24812111Sralph */ 24912111Sralph for (i = 0; i < 4; i++) 25012111Sralph strcpy(fonts[i], ifonts[i]); 25117339Sralph strcpy(width+2, "0"); 25217302Sralph strcpy(indent+2, "0"); 25312111Sralph 25412111Sralph /* 25512111Sralph * read the control file for work to do 25612111Sralph * 25712111Sralph * file format -- first character in the line is a command 25812111Sralph * rest of the line is the argument. 25912111Sralph * valid commands are: 26012111Sralph * 26117463Sralph * S -- "stat info" for symbolic link protection 26212111Sralph * J -- "job name" on banner page 26312111Sralph * C -- "class name" on banner page 26412111Sralph * L -- "literal" user's name to print on banner 26512111Sralph * T -- "title" for pr 26612111Sralph * H -- "host name" of machine where lpr was done 26712111Sralph * P -- "person" user's login name 26812581Sralph * I -- "indent" amount to indent output 26912111Sralph * f -- "file name" name of text file to print 27012111Sralph * l -- "file name" text file with control chars 27112111Sralph * p -- "file name" text file to print with pr(1) 27212111Sralph * t -- "file name" troff(1) file to print 27313233Sralph * n -- "file name" ditroff(1) file to print 27412111Sralph * d -- "file name" dvi file to print 27512111Sralph * g -- "file name" plot(1G) file to print 27612111Sralph * v -- "file name" plain raster file to print 27712111Sralph * c -- "file name" cifplot file to print 27812111Sralph * 1 -- "R font file" for troff 27912111Sralph * 2 -- "I font file" for troff 28012111Sralph * 3 -- "B font file" for troff 28112111Sralph * 4 -- "S font file" for troff 28212111Sralph * N -- "name" of file (used by lpq) 28312111Sralph * U -- "unlink" name of file to remove 28412111Sralph * (after we print it. (Pass 2 only)). 28512111Sralph * M -- "mail" to user when done printing 28612111Sralph * 28712111Sralph * getline reads a line and expands tabs to blanks 28812111Sralph */ 28912111Sralph 29012111Sralph /* pass 1 */ 29112111Sralph 29212111Sralph while (getline(cfp)) 29312111Sralph switch (line[0]) { 29412111Sralph case 'H': 29514150Sralph strcpy(fromhost, line+1); 29612111Sralph if (class[0] == '\0') 29715552Sralph strncpy(class, line+1, sizeof(class)-1); 29812111Sralph continue; 29912111Sralph 30012111Sralph case 'P': 30115552Sralph strncpy(logname, line+1, sizeof(logname)-1); 30212463Sralph if (RS) { /* restricted */ 30312463Sralph if (getpwnam(logname) == (struct passwd *)0) { 30417463Sralph bombed = NOACCT; 30515811Sralph sendmail(line+1, bombed); 30612463Sralph goto pass2; 30712463Sralph } 30812463Sralph } 30912111Sralph continue; 31012111Sralph 31117463Sralph case 'S': 31217463Sralph cp = line+1; 31317463Sralph i = 0; 31417463Sralph while (*cp >= '0' && *cp <= '9') 31517463Sralph i = i * 10 + (*cp++ - '0'); 31617463Sralph fdev = i; 31717463Sralph cp++; 31817463Sralph i = 0; 31917463Sralph while (*cp >= '0' && *cp <= '9') 32017463Sralph i = i * 10 + (*cp++ - '0'); 32117463Sralph fino = i; 32217463Sralph continue; 32317463Sralph 32412111Sralph case 'J': 32512111Sralph if (line[1] != '\0') 32615552Sralph strncpy(jobname, line+1, sizeof(jobname)-1); 32712111Sralph else 32812111Sralph strcpy(jobname, " "); 32912111Sralph continue; 33012111Sralph 33112111Sralph case 'C': 33212111Sralph if (line[1] != '\0') 33315552Sralph strncpy(class, line+1, sizeof(class)-1); 33412111Sralph else if (class[0] == '\0') 33515811Sralph gethostname(class, sizeof(class)); 33612111Sralph continue; 33712111Sralph 33812111Sralph case 'T': /* header title for pr */ 33915552Sralph strncpy(title, line+1, sizeof(title)-1); 34012111Sralph continue; 34112111Sralph 34212111Sralph case 'L': /* identification line */ 34318127Sralph if (!SH && !HL) 34412111Sralph banner(line+1, jobname); 34512111Sralph continue; 34612111Sralph 34712111Sralph case '1': /* troff fonts */ 34812111Sralph case '2': 34912111Sralph case '3': 35012111Sralph case '4': 35112111Sralph if (line[1] != '\0') 35212111Sralph strcpy(fonts[line[0]-'1'], line+1); 35312111Sralph continue; 35412111Sralph 35512111Sralph case 'W': /* page width */ 35615552Sralph strncpy(width+2, line+1, sizeof(width)-3); 35712111Sralph continue; 35812111Sralph 35912581Sralph case 'I': /* indent amount */ 36015552Sralph strncpy(indent+2, line+1, sizeof(indent)-3); 36112581Sralph continue; 36212581Sralph 36312111Sralph default: /* some file to print */ 36415811Sralph switch (i = print(line[0], line+1)) { 36517463Sralph case ERROR: 36617463Sralph if (bombed == OK) 36717463Sralph bombed = FATALERR; 36815811Sralph break; 36917463Sralph case REPRINT: 37012111Sralph (void) fclose(cfp); 37117463Sralph return(REPRINT); 37217463Sralph case FILTERERR: 37317463Sralph case ACCESS: 37417463Sralph bombed = i; 37515811Sralph sendmail(logname, bombed); 37615811Sralph } 37712111Sralph title[0] = '\0'; 37812111Sralph continue; 37912111Sralph 38012111Sralph case 'N': 38112111Sralph case 'U': 38212111Sralph case 'M': 38312111Sralph continue; 38412111Sralph } 38512111Sralph 38612111Sralph /* pass 2 */ 38712111Sralph 38812463Sralph pass2: 38912111Sralph fseek(cfp, 0L, 0); 39012111Sralph while (getline(cfp)) 39112111Sralph switch (line[0]) { 39218127Sralph case 'L': /* identification line */ 39318127Sralph if (!SH && HL) 39418127Sralph banner(line+1, jobname); 39518127Sralph continue; 39618127Sralph 39712111Sralph case 'M': 39817463Sralph if (bombed < NOACCT) /* already sent if >= NOACCT */ 39915811Sralph sendmail(line+1, bombed); 40012111Sralph continue; 40112111Sralph 40212111Sralph case 'U': 40312111Sralph (void) unlink(line+1); 40412111Sralph } 40512111Sralph /* 40615811Sralph * clean-up in case another control file exists 40712111Sralph */ 40812111Sralph (void) fclose(cfp); 40912111Sralph (void) unlink(file); 41017463Sralph return(bombed == OK ? OK : ERROR); 41112111Sralph } 41212111Sralph 41312111Sralph /* 41412111Sralph * Print a file. 41513233Sralph * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}. 41615811Sralph * Return -1 if a non-recoverable error occured, 41715811Sralph * 2 if the filter detected some errors (but printed the job anyway), 41815811Sralph * 1 if we should try to reprint this job and 41912111Sralph * 0 if all is well. 42012111Sralph * Note: all filters take stdin as the file, stdout as the printer, 42112111Sralph * stderr as the log file, and must not ignore SIGINT. 42212111Sralph */ 42312111Sralph print(format, file) 42412111Sralph int format; 42512111Sralph char *file; 42612111Sralph { 42715811Sralph register int n; 42812111Sralph register char *prog; 42915811Sralph int fi, fo; 43012111Sralph char *av[15], buf[BUFSIZ]; 43112111Sralph int pid, p[2], stopped = 0; 43212111Sralph union wait status; 43317463Sralph struct stat stb; 43412111Sralph 43517463Sralph if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0) 43617463Sralph return(ERROR); 43717463Sralph /* 43817463Sralph * Check to see if data file is a symbolic link. If so, it should 43917463Sralph * still point to the same file or someone is trying to print 44017463Sralph * something he shouldn't. 44117463Sralph */ 44217463Sralph if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 && 44317463Sralph (stb.st_dev != fdev || stb.st_ino != fino)) 44417463Sralph return(ACCESS); 44512111Sralph if (!SF && !tof) { /* start on a fresh page */ 44612111Sralph (void) write(ofd, FF, strlen(FF)); 44712111Sralph tof = 1; 44812111Sralph } 44912111Sralph if (IF == NULL && (format == 'f' || format == 'l')) { 45012111Sralph tof = 0; 45112111Sralph while ((n = read(fi, buf, BUFSIZ)) > 0) 45212111Sralph if (write(ofd, buf, n) != n) { 45312111Sralph (void) close(fi); 45417463Sralph return(REPRINT); 45512111Sralph } 45612111Sralph (void) close(fi); 45717463Sralph return(OK); 45812111Sralph } 45912111Sralph switch (format) { 46012111Sralph case 'p': /* print file using 'pr' */ 46112111Sralph if (IF == NULL) { /* use output filter */ 46212111Sralph prog = PR; 46312111Sralph av[0] = "pr"; 46412111Sralph av[1] = width; 46512111Sralph av[2] = length; 46612111Sralph av[3] = "-h"; 46712111Sralph av[4] = *title ? title : " "; 46812111Sralph av[5] = 0; 46912111Sralph fo = ofd; 47012111Sralph goto start; 47112111Sralph } 47212111Sralph pipe(p); 47312111Sralph if ((prchild = dofork(DORETURN)) == 0) { /* child */ 47412111Sralph dup2(fi, 0); /* file is stdin */ 47512111Sralph dup2(p[1], 1); /* pipe is stdout */ 47612111Sralph for (n = 3; n < NOFILE; n++) 47712111Sralph (void) close(n); 47812111Sralph execl(PR, "pr", width, length, "-h", *title ? title : " ", 0); 47916762Sralph syslog(LOG_ERR, "cannot execl %s", PR); 48012111Sralph exit(2); 48112111Sralph } 48212111Sralph (void) close(p[1]); /* close output side */ 48312111Sralph (void) close(fi); 48412111Sralph if (prchild < 0) { 48512111Sralph prchild = 0; 48612111Sralph (void) close(p[0]); 48717463Sralph return(ERROR); 48812111Sralph } 48912111Sralph fi = p[0]; /* use pipe for input */ 49012111Sralph case 'f': /* print plain text file */ 49112111Sralph prog = IF; 49212111Sralph av[1] = width; 49312111Sralph av[2] = length; 49412581Sralph av[3] = indent; 49512581Sralph n = 4; 49612111Sralph break; 49712111Sralph case 'l': /* like 'f' but pass control characters */ 49812111Sralph prog = IF; 49914325Sralph av[1] = "-c"; 50012111Sralph av[2] = width; 50112111Sralph av[3] = length; 50212581Sralph av[4] = indent; 50312581Sralph n = 5; 50412111Sralph break; 50512463Sralph case 'r': /* print a fortran text file */ 50612463Sralph prog = RF; 50712463Sralph av[1] = width; 50812463Sralph av[2] = length; 50912463Sralph n = 3; 51012463Sralph break; 51112111Sralph case 't': /* print troff output */ 51213233Sralph case 'n': /* print ditroff output */ 51312463Sralph case 'd': /* print tex output */ 51412111Sralph (void) unlink(".railmag"); 51512463Sralph if ((fo = creat(".railmag", FILMOD)) < 0) { 51616762Sralph syslog(LOG_ERR, "%s: cannot create .railmag", printer); 51712111Sralph (void) unlink(".railmag"); 51812111Sralph } else { 51912111Sralph for (n = 0; n < 4; n++) { 52012111Sralph if (fonts[n][0] != '/') 52112111Sralph (void) write(fo, "/usr/lib/vfont/", 15); 52212111Sralph (void) write(fo, fonts[n], strlen(fonts[n])); 52312111Sralph (void) write(fo, "\n", 1); 52412111Sralph } 52512111Sralph (void) close(fo); 52612111Sralph } 52713233Sralph prog = (format == 't') ? TF : (format == 'n') ? NF : DF; 52812463Sralph av[1] = pxwidth; 52912463Sralph av[2] = pxlength; 53012463Sralph n = 3; 53112111Sralph break; 53212111Sralph case 'c': /* print cifplot output */ 53312111Sralph prog = CF; 53412463Sralph av[1] = pxwidth; 53512463Sralph av[2] = pxlength; 53612463Sralph n = 3; 53712111Sralph break; 53812111Sralph case 'g': /* print plot(1G) output */ 53912111Sralph prog = GF; 54012463Sralph av[1] = pxwidth; 54112463Sralph av[2] = pxlength; 54212463Sralph n = 3; 54312111Sralph break; 54412111Sralph case 'v': /* print raster output */ 54512111Sralph prog = VF; 54612463Sralph av[1] = pxwidth; 54712463Sralph av[2] = pxlength; 54812463Sralph n = 3; 54912111Sralph break; 55012111Sralph default: 55112111Sralph (void) close(fi); 55216762Sralph syslog(LOG_ERR, "%s: illegal format character '%c'", 55316762Sralph printer, format); 55417463Sralph return(ERROR); 55512111Sralph } 55612111Sralph if ((av[0] = rindex(prog, '/')) != NULL) 55712111Sralph av[0]++; 55812111Sralph else 55912111Sralph av[0] = prog; 56012111Sralph av[n++] = "-n"; 56112111Sralph av[n++] = logname; 56212111Sralph av[n++] = "-h"; 56314150Sralph av[n++] = fromhost; 56412111Sralph av[n++] = AF; 56512111Sralph av[n] = 0; 56612111Sralph fo = pfd; 56712111Sralph if (ofilter > 0) { /* stop output filter */ 56812111Sralph write(ofd, "\031\1", 2); 56912111Sralph while ((pid = wait3(&status, WUNTRACED, 0)) > 0 && pid != ofilter) 57012111Sralph ; 57112111Sralph if (status.w_stopval != WSTOPPED) { 57212111Sralph (void) close(fi); 57316762Sralph syslog(LOG_WARNING, "%s: output filter died (%d)", 57416762Sralph printer, status.w_retcode); 57517463Sralph return(REPRINT); 57612111Sralph } 57712111Sralph stopped++; 57812111Sralph } 57912111Sralph start: 58012111Sralph if ((child = dofork(DORETURN)) == 0) { /* child */ 58112111Sralph dup2(fi, 0); 58212111Sralph dup2(fo, 1); 58317304Sralph n = open(tmpfile, O_WRONLY|O_CREAT|O_TRUNC, 0664); 58415811Sralph if (n >= 0) 58515811Sralph dup2(n, 2); 58612111Sralph for (n = 3; n < NOFILE; n++) 58712111Sralph (void) close(n); 58812111Sralph execv(prog, av); 58916762Sralph syslog(LOG_ERR, "cannot execv %s", prog); 59012111Sralph exit(2); 59112111Sralph } 59212111Sralph (void) close(fi); 59312111Sralph if (child < 0) 59412111Sralph status.w_retcode = 100; 59512111Sralph else 59612111Sralph while ((pid = wait(&status)) > 0 && pid != child) 59712111Sralph ; 59812111Sralph child = 0; 59912111Sralph prchild = 0; 60012111Sralph if (stopped) { /* restart output filter */ 60112111Sralph if (kill(ofilter, SIGCONT) < 0) { 60216762Sralph syslog(LOG_ERR, "cannot restart output filter"); 60312111Sralph exit(1); 60412111Sralph } 60512111Sralph } 60612111Sralph tof = 0; 60715811Sralph if (!WIFEXITED(status)) { 60816762Sralph syslog(LOG_WARNING, "%s: Daemon filter '%c' terminated (%d)", 60916762Sralph printer, format, status.w_termsig); 61017463Sralph return(ERROR); 61117463Sralph } 61217463Sralph switch (status.w_retcode) { 61317463Sralph case 0: 61417463Sralph tof = 1; 61517463Sralph return(OK); 61617463Sralph case 1: 61717463Sralph return(REPRINT); 61817463Sralph default: 61916762Sralph syslog(LOG_WARNING, "%s: Daemon filter '%c' exited (%d)", 62016762Sralph printer, format, status.w_retcode); 62117463Sralph case 2: 62217463Sralph return(ERROR); 62317463Sralph } 62412111Sralph } 62512111Sralph 62612111Sralph /* 62712111Sralph * Send the daemon control file (cf) and any data files. 62812111Sralph * Return -1 if a non-recoverable error occured, 1 if a recoverable error and 62912111Sralph * 0 if all is well. 63012111Sralph */ 63112111Sralph sendit(file) 63212111Sralph char *file; 63312111Sralph { 63417463Sralph register int i, err = OK; 63517463Sralph char *cp, last[BUFSIZ]; 63612111Sralph 63712111Sralph /* 63812111Sralph * open control file 63912111Sralph */ 64016762Sralph if ((cfp = fopen(file, "r")) == NULL) 64117463Sralph return(OK); 64212111Sralph /* 64312111Sralph * read the control file for work to do 64412111Sralph * 64512111Sralph * file format -- first character in the line is a command 64612111Sralph * rest of the line is the argument. 64712111Sralph * commands of interest are: 64812111Sralph * 64912111Sralph * a-z -- "file name" name of file to print 65012111Sralph * U -- "unlink" name of file to remove 65112111Sralph * (after we print it. (Pass 2 only)). 65212111Sralph */ 65312111Sralph 65412111Sralph /* 65512111Sralph * pass 1 65612111Sralph */ 65712111Sralph while (getline(cfp)) { 65812111Sralph again: 65917463Sralph if (line[0] == 'S') { 66017463Sralph cp = line+1; 66117463Sralph i = 0; 66217463Sralph while (*cp >= '0' && *cp <= '9') 66317463Sralph i = i * 10 + (*cp++ - '0'); 66417463Sralph fdev = i; 66517463Sralph cp++; 66617463Sralph i = 0; 66717463Sralph while (*cp >= '0' && *cp <= '9') 66817463Sralph i = i * 10 + (*cp++ - '0'); 66917463Sralph fino = i; 67017463Sralph continue; 67117463Sralph } 67212111Sralph if (line[0] >= 'a' && line[0] <= 'z') { 67312111Sralph strcpy(last, line); 67417463Sralph while (i = getline(cfp)) 67512111Sralph if (strcmp(last, line)) 67612111Sralph break; 67717463Sralph switch (sendfile('\3', last+1)) { 67817463Sralph case OK: 67917463Sralph if (i) 68017463Sralph goto again; 68117463Sralph break; 68217463Sralph case REPRINT: 68312111Sralph (void) fclose(cfp); 68417463Sralph return(REPRINT); 68517463Sralph case ACCESS: 68617463Sralph sendmail(logname, ACCESS); 68717463Sralph case ERROR: 68817463Sralph err = ERROR; 68917463Sralph } 69012111Sralph break; 69112111Sralph } 69212111Sralph } 69317463Sralph if (err == OK && sendfile('\2', file) > 0) { 69412111Sralph (void) fclose(cfp); 69517463Sralph return(REPRINT); 69612111Sralph } 69712111Sralph /* 69812111Sralph * pass 2 69912111Sralph */ 70012111Sralph fseek(cfp, 0L, 0); 70112111Sralph while (getline(cfp)) 70212111Sralph if (line[0] == 'U') 70312111Sralph (void) unlink(line+1); 70412111Sralph /* 70517463Sralph * clean-up in case another control file exists 70612111Sralph */ 70712111Sralph (void) fclose(cfp); 70812111Sralph (void) unlink(file); 70917463Sralph return(err); 71012111Sralph } 71112111Sralph 71212111Sralph /* 71312111Sralph * Send a data file to the remote machine and spool it. 71412111Sralph * Return positive if we should try resending. 71512111Sralph */ 71612111Sralph sendfile(type, file) 71712111Sralph char type, *file; 71812111Sralph { 71912111Sralph register int f, i, amt; 72012111Sralph struct stat stb; 72112111Sralph char buf[BUFSIZ]; 72216762Sralph int sizerr, resp; 72312111Sralph 72417463Sralph if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0) 72517463Sralph return(ERROR); 72617463Sralph /* 72717463Sralph * Check to see if data file is a symbolic link. If so, it should 72817463Sralph * still point to the same file or someone is trying to print something 72917463Sralph * he shouldn't. 73017463Sralph */ 73117463Sralph if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 && 73217463Sralph (stb.st_dev != fdev || stb.st_ino != fino)) 73317463Sralph return(ACCESS); 73412111Sralph (void) sprintf(buf, "%c%d %s\n", type, stb.st_size, file); 73512111Sralph amt = strlen(buf); 73616762Sralph for (i = 0; ; i++) { 73716762Sralph if (write(pfd, buf, amt) != amt || 73816762Sralph (resp = response()) < 0 || resp == '\1') { 73916762Sralph (void) close(f); 74017463Sralph return(REPRINT); 74116762Sralph } else if (resp == '\0') 74216762Sralph break; 74316762Sralph if (i == 0) 74416762Sralph status("no space on remote; waiting for queue to drain"); 74516762Sralph if (i == 10) 74624861Seric syslog(LOG_ALERT, "%s: can't send to %s; queue full", 74716762Sralph printer, RM); 74816762Sralph sleep(5 * 60); 74912692Sralph } 75016762Sralph if (i) 75116762Sralph status("sending to %s", RM); 75212111Sralph sizerr = 0; 75312111Sralph for (i = 0; i < stb.st_size; i += BUFSIZ) { 75412111Sralph amt = BUFSIZ; 75512111Sralph if (i + amt > stb.st_size) 75612111Sralph amt = stb.st_size - i; 75712111Sralph if (sizerr == 0 && read(f, buf, amt) != amt) 75812111Sralph sizerr = 1; 75912692Sralph if (write(pfd, buf, amt) != amt) { 76012692Sralph (void) close(f); 76117463Sralph return(REPRINT); 76212692Sralph } 76312111Sralph } 76412111Sralph (void) close(f); 76512111Sralph if (sizerr) { 76616762Sralph syslog(LOG_INFO, "%s: %s: changed size", printer, file); 76717463Sralph /* tell recvjob to ignore this file */ 76817463Sralph (void) write(pfd, "\1", 1); 76917463Sralph return(ERROR); 77017463Sralph } 77117463Sralph if (write(pfd, "", 1) != 1 || response()) 77217463Sralph return(REPRINT); 77317463Sralph return(OK); 77412111Sralph } 77512111Sralph 77612111Sralph /* 77712111Sralph * Check to make sure there have been no errors and that both programs 77812111Sralph * are in sync with eachother. 77912111Sralph * Return non-zero if the connection was lost. 78012111Sralph */ 78116762Sralph response() 78212111Sralph { 78312111Sralph char resp; 78412111Sralph 78516762Sralph if (read(pfd, &resp, 1) != 1) { 78616762Sralph syslog(LOG_INFO, "%s: lost connection", printer); 78716762Sralph return(-1); 78812111Sralph } 78916762Sralph return(resp); 79012111Sralph } 79112111Sralph 79212111Sralph /* 79312111Sralph * Banner printing stuff 79412111Sralph */ 79512111Sralph banner(name1, name2) 79612111Sralph char *name1, *name2; 79712111Sralph { 79812111Sralph time_t tvec; 79912111Sralph extern char *ctime(); 80012111Sralph 80112111Sralph time(&tvec); 80212111Sralph if (!SF && !tof) 80312111Sralph (void) write(ofd, FF, strlen(FF)); 80412111Sralph if (SB) { /* short banner only */ 80512111Sralph if (class[0]) { 80612111Sralph (void) write(ofd, class, strlen(class)); 80712111Sralph (void) write(ofd, ":", 1); 80812111Sralph } 80912111Sralph (void) write(ofd, name1, strlen(name1)); 81012111Sralph (void) write(ofd, " Job: ", 7); 81112111Sralph (void) write(ofd, name2, strlen(name2)); 81212111Sralph (void) write(ofd, " Date: ", 8); 81312111Sralph (void) write(ofd, ctime(&tvec), 24); 81412111Sralph (void) write(ofd, "\n", 1); 81512111Sralph } else { /* normal banner */ 81612111Sralph (void) write(ofd, "\n\n\n", 3); 81712111Sralph scan_out(ofd, name1, '\0'); 81812111Sralph (void) write(ofd, "\n\n", 2); 81912111Sralph scan_out(ofd, name2, '\0'); 82012111Sralph if (class[0]) { 82112111Sralph (void) write(ofd,"\n\n\n",3); 82212111Sralph scan_out(ofd, class, '\0'); 82312111Sralph } 82412111Sralph (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15); 82512111Sralph (void) write(ofd, name2, strlen(name2)); 82612111Sralph (void) write(ofd, "\n\t\t\t\t\tDate: ", 12); 82712111Sralph (void) write(ofd, ctime(&tvec), 24); 82812111Sralph (void) write(ofd, "\n", 1); 82912111Sralph } 83012111Sralph if (!SF) 83112111Sralph (void) write(ofd, FF, strlen(FF)); 83212111Sralph tof = 1; 83312111Sralph } 83412111Sralph 83516762Sralph char * 83612111Sralph scnline(key, p, c) 83712111Sralph register char key, *p; 83812111Sralph char c; 83912111Sralph { 84012111Sralph register scnwidth; 84112111Sralph 84212111Sralph for (scnwidth = WIDTH; --scnwidth;) { 84312111Sralph key <<= 1; 84412111Sralph *p++ = key & 0200 ? c : BACKGND; 84512111Sralph } 84612111Sralph return (p); 84712111Sralph } 84812111Sralph 84912111Sralph #define TRC(q) (((q)-' ')&0177) 85012111Sralph 85112111Sralph scan_out(scfd, scsp, dlm) 85212111Sralph int scfd; 85312111Sralph char *scsp, dlm; 85412111Sralph { 85512111Sralph register char *strp; 85612111Sralph register nchrs, j; 85712111Sralph char outbuf[LINELEN+1], *sp, c, cc; 85812111Sralph int d, scnhgt; 85912111Sralph extern char scnkey[][HEIGHT]; /* in lpdchar.c */ 86012111Sralph 86112111Sralph for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) { 86212111Sralph strp = &outbuf[0]; 86312111Sralph sp = scsp; 86412111Sralph for (nchrs = 0; ; ) { 86512111Sralph d = dropit(c = TRC(cc = *sp++)); 86612111Sralph if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d)) 86712111Sralph for (j = WIDTH; --j;) 86812111Sralph *strp++ = BACKGND; 86912111Sralph else 87012111Sralph strp = scnline(scnkey[c][scnhgt-1-d], strp, cc); 87112111Sralph if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1) 87212111Sralph break; 87312111Sralph *strp++ = BACKGND; 87412111Sralph *strp++ = BACKGND; 87512111Sralph } 87612111Sralph while (*--strp == BACKGND && strp >= outbuf) 87712111Sralph ; 87812111Sralph strp++; 87912111Sralph *strp++ = '\n'; 88012111Sralph (void) write(scfd, outbuf, strp-outbuf); 88112111Sralph } 88212111Sralph } 88312111Sralph 88412111Sralph dropit(c) 88512111Sralph char c; 88612111Sralph { 88712111Sralph switch(c) { 88812111Sralph 88912111Sralph case TRC('_'): 89012111Sralph case TRC(';'): 89112111Sralph case TRC(','): 89212111Sralph case TRC('g'): 89312111Sralph case TRC('j'): 89412111Sralph case TRC('p'): 89512111Sralph case TRC('q'): 89612111Sralph case TRC('y'): 89712111Sralph return (DROP); 89812111Sralph 89912111Sralph default: 90012111Sralph return (0); 90112111Sralph } 90212111Sralph } 90312111Sralph 90412111Sralph /* 90512111Sralph * sendmail --- 90612111Sralph * tell people about job completion 90712111Sralph */ 90815811Sralph sendmail(user, bombed) 90915811Sralph char *user; 91012111Sralph int bombed; 91112111Sralph { 91212111Sralph register int i; 91315811Sralph int p[2], s; 91412111Sralph register char *cp; 91512111Sralph char buf[100]; 91615811Sralph struct stat stb; 91715811Sralph FILE *fp; 91812111Sralph 91912111Sralph pipe(p); 92015811Sralph if ((s = dofork(DORETURN)) == 0) { /* child */ 92112111Sralph dup2(p[0], 0); 92212111Sralph for (i = 3; i < NOFILE; i++) 92312111Sralph (void) close(i); 92412111Sralph if ((cp = rindex(MAIL, '/')) != NULL) 92512111Sralph cp++; 92612111Sralph else 92712111Sralph cp = MAIL; 92815811Sralph sprintf(buf, "%s@%s", user, fromhost); 92912111Sralph execl(MAIL, cp, buf, 0); 93012111Sralph exit(0); 93115811Sralph } else if (s > 0) { /* parent */ 93212111Sralph dup2(p[1], 1); 93315811Sralph printf("To: %s@%s\n", user, fromhost); 93412111Sralph printf("Subject: printer job\n\n"); 93512111Sralph printf("Your printer job "); 93612111Sralph if (*jobname) 93712111Sralph printf("(%s) ", jobname); 93812463Sralph switch (bombed) { 93917463Sralph case OK: 94012463Sralph printf("\ncompleted successfully\n"); 94112463Sralph break; 94212463Sralph default: 94317463Sralph case FATALERR: 94412463Sralph printf("\ncould not be printed\n"); 94512463Sralph break; 94617463Sralph case NOACCT: 94712463Sralph printf("\ncould not be printed without an account on %s\n", host); 94812463Sralph break; 94917463Sralph case FILTERERR: 95015811Sralph if (stat(tmpfile, &stb) < 0 || stb.st_size == 0 || 95115811Sralph (fp = fopen(tmpfile, "r")) == NULL) { 95215811Sralph printf("\nwas printed but had some errors\n"); 95315811Sralph break; 95415811Sralph } 95515811Sralph printf("\nwas printed but had the following errors:\n"); 95615811Sralph while ((i = getc(fp)) != EOF) 95715811Sralph putchar(i); 95815811Sralph (void) fclose(fp); 95917463Sralph break; 96017463Sralph case ACCESS: 96117463Sralph printf("\nwas not printed because it was not linked to the original file\n"); 96212463Sralph } 96312111Sralph fflush(stdout); 96412111Sralph (void) close(1); 96512111Sralph } 96612111Sralph (void) close(p[0]); 96712111Sralph (void) close(p[1]); 96815811Sralph wait(&s); 96912111Sralph } 97012111Sralph 97112111Sralph /* 97212111Sralph * dofork - fork with retries on failure 97312111Sralph */ 97412111Sralph dofork(action) 97512111Sralph int action; 97612111Sralph { 97712111Sralph register int i, pid; 97812111Sralph 97912111Sralph for (i = 0; i < 20; i++) { 98012463Sralph if ((pid = fork()) < 0) { 98112111Sralph sleep((unsigned)(i*i)); 98212463Sralph continue; 98312463Sralph } 98412463Sralph /* 98512463Sralph * Child should run as daemon instead of root 98612463Sralph */ 98712463Sralph if (pid == 0) 98812463Sralph setuid(DU); 98912463Sralph return(pid); 99012111Sralph } 99116762Sralph syslog(LOG_ERR, "can't fork"); 99212111Sralph 99312111Sralph switch (action) { 99412111Sralph case DORETURN: 99512111Sralph return (-1); 99612111Sralph default: 99716762Sralph syslog(LOG_ERR, "bad action (%d) to dofork", action); 99812111Sralph /*FALL THRU*/ 99912111Sralph case DOABORT: 100012111Sralph exit(1); 100112111Sralph } 100212111Sralph /*NOTREACHED*/ 100312111Sralph } 100412111Sralph 100512111Sralph /* 100616762Sralph * Kill child processes to abort current job. 100712111Sralph */ 100816762Sralph abortpr() 100912111Sralph { 101015811Sralph (void) unlink(tmpfile); 101112111Sralph kill(0, SIGINT); 101212111Sralph if (ofilter > 0) 101312111Sralph kill(ofilter, SIGCONT); 101412111Sralph while (wait(0) > 0) 101512111Sralph ; 101612111Sralph exit(0); 101712111Sralph } 101812111Sralph 101912111Sralph init() 102012111Sralph { 102112111Sralph int status; 102212111Sralph 102325468Stef if ((status = pgetent(line, printer)) < 0) { 102425468Stef syslog(LOG_ERR, "can't open printer description file"); 102525468Stef exit(1); 102625468Stef } else if (status == 0) { 102725468Stef syslog(LOG_ERR, "unknown printer: %s", printer); 102825468Stef exit(1); 102925468Stef } 103012111Sralph if ((LP = pgetstr("lp", &bp)) == NULL) 103112111Sralph LP = DEFDEVLP; 103212111Sralph if ((RP = pgetstr("rp", &bp)) == NULL) 103312463Sralph RP = DEFLP; 103412111Sralph if ((LO = pgetstr("lo", &bp)) == NULL) 103512111Sralph LO = DEFLOCK; 103612111Sralph if ((ST = pgetstr("st", &bp)) == NULL) 103712111Sralph ST = DEFSTAT; 103812111Sralph if ((LF = pgetstr("lf", &bp)) == NULL) 103912111Sralph LF = DEFLOGF; 104012111Sralph if ((SD = pgetstr("sd", &bp)) == NULL) 104112111Sralph SD = DEFSPOOL; 104212111Sralph if ((DU = pgetnum("du")) < 0) 104312111Sralph DU = DEFUID; 104412111Sralph if ((FF = pgetstr("ff", &bp)) == NULL) 104512111Sralph FF = DEFFF; 104612111Sralph if ((PW = pgetnum("pw")) < 0) 104712111Sralph PW = DEFWIDTH; 104812111Sralph sprintf(&width[2], "%d", PW); 104912111Sralph if ((PL = pgetnum("pl")) < 0) 105012111Sralph PL = DEFLENGTH; 105112111Sralph sprintf(&length[2], "%d", PL); 105212463Sralph if ((PX = pgetnum("px")) < 0) 105312463Sralph PX = 0; 105412463Sralph sprintf(&pxwidth[2], "%d", PX); 105512463Sralph if ((PY = pgetnum("py")) < 0) 105612463Sralph PY = 0; 105712463Sralph sprintf(&pxlength[2], "%d", PY); 105812111Sralph RM = pgetstr("rm", &bp); 105925468Stef /* 106025468Stef * Figure out whether the local machine is the same as the remote 106125468Stef * machine entry (if it exists). If not, then ignore the local 106225468Stef * queue information. 106325468Stef */ 106425468Stef if (RM != (char *) NULL) { 106525468Stef char name[256]; 106625468Stef struct hostent *hp; 106725468Stef 106825468Stef /* get the standard network name of the local host */ 106925468Stef gethostname(name, sizeof(name)); 107025468Stef name[sizeof(name)-1] = '\0'; 107125468Stef hp = gethostbyname(name); 107225468Stef if (hp == (struct hostent *) NULL) { 107325468Stef syslog(LOG_ERR, 107425468Stef "unable to get network name for local machine %s", 107525468Stef name); 107625468Stef goto localcheck_done; 107725468Stef } else strcpy(name, hp->h_name); 107825468Stef 107925468Stef /* get the standard network name of RM */ 108025468Stef hp = gethostbyname(RM); 108125468Stef if (hp == (struct hostent *) NULL) { 108225468Stef syslog(LOG_ERR, 108325468Stef "unable to get hostname for remote machine %s", RM); 108425468Stef goto localcheck_done; 108525468Stef } 108625468Stef 108725468Stef /* if printer is not on local machine, ignore LP */ 108825468Stef if (strcmp(name, hp->h_name) != 0) *LP = '\0'; 108925468Stef } 109025468Stef localcheck_done: 109125468Stef 109212111Sralph AF = pgetstr("af", &bp); 109312111Sralph OF = pgetstr("of", &bp); 109412111Sralph IF = pgetstr("if", &bp); 109512463Sralph RF = pgetstr("rf", &bp); 109612111Sralph TF = pgetstr("tf", &bp); 109713233Sralph NF = pgetstr("nf", &bp); 109812111Sralph DF = pgetstr("df", &bp); 109912111Sralph GF = pgetstr("gf", &bp); 110012111Sralph VF = pgetstr("vf", &bp); 110112111Sralph CF = pgetstr("cf", &bp); 110212111Sralph TR = pgetstr("tr", &bp); 110312463Sralph RS = pgetflag("rs"); 110412111Sralph SF = pgetflag("sf"); 110512111Sralph SH = pgetflag("sh"); 110612111Sralph SB = pgetflag("sb"); 110718127Sralph HL = pgetflag("hl"); 110812111Sralph RW = pgetflag("rw"); 110912111Sralph BR = pgetnum("br"); 111012111Sralph if ((FC = pgetnum("fc")) < 0) 111112111Sralph FC = 0; 111212111Sralph if ((FS = pgetnum("fs")) < 0) 111312111Sralph FS = 0; 111412111Sralph if ((XC = pgetnum("xc")) < 0) 111512111Sralph XC = 0; 111612111Sralph if ((XS = pgetnum("xs")) < 0) 111712111Sralph XS = 0; 111812581Sralph tof = !pgetflag("fo"); 111912111Sralph } 112012111Sralph 112112463Sralph /* 112212463Sralph * Acquire line printer or remote connection. 112312463Sralph */ 112412463Sralph openpr() 112512463Sralph { 112612463Sralph register int i, n; 112716762Sralph int resp; 112812463Sralph 112912463Sralph if (*LP) { 113012463Sralph for (i = 1; ; i = i < 32 ? i << 1 : i) { 113113148Ssam pfd = open(LP, RW ? O_RDWR : O_WRONLY); 113212463Sralph if (pfd >= 0) 113312463Sralph break; 113412463Sralph if (errno == ENOENT) { 113516762Sralph syslog(LOG_ERR, "%s: %m", LP); 113612463Sralph exit(1); 113712463Sralph } 113812463Sralph if (i == 1) 113912463Sralph status("waiting for %s to become ready (offline ?)", printer); 114012463Sralph sleep(i); 114112463Sralph } 114212463Sralph if (isatty(pfd)) 114312463Sralph setty(); 114412463Sralph status("%s is ready and printing", printer); 114512463Sralph } else if (RM != NULL) { 114616762Sralph for (i = 1; ; i = i < 256 ? i << 1 : i) { 114716762Sralph resp = -1; 114812528Sralph pfd = getport(RM); 114912463Sralph if (pfd >= 0) { 115012463Sralph (void) sprintf(line, "\2%s\n", RP); 115112463Sralph n = strlen(line); 115216762Sralph if (write(pfd, line, n) == n && 115316762Sralph (resp = response()) == '\0') 115412463Sralph break; 115516031Sralph (void) close(pfd); 115612463Sralph } 115716031Sralph if (i == 1) { 115816762Sralph if (resp < 0) 115916031Sralph status("waiting for %s to come up", RM); 116016762Sralph else { 116116031Sralph status("waiting for queue to be enabled on %s", RM); 116216762Sralph i = 256; 116316762Sralph } 116416031Sralph } 116512463Sralph sleep(i); 116612463Sralph } 116712463Sralph status("sending to %s", RM); 116812463Sralph remote = 1; 116912463Sralph } else { 117016762Sralph syslog(LOG_ERR, "%s: no line printer device or host name", 117116762Sralph printer); 117212463Sralph exit(1); 117312463Sralph } 117412463Sralph /* 117512463Sralph * Start up an output filter, if needed. 117612463Sralph */ 117712463Sralph if (OF) { 117812463Sralph int p[2]; 117912463Sralph char *cp; 118012463Sralph 118112463Sralph pipe(p); 118212463Sralph if ((ofilter = dofork(DOABORT)) == 0) { /* child */ 118312463Sralph dup2(p[0], 0); /* pipe is std in */ 118412463Sralph dup2(pfd, 1); /* printer is std out */ 118512463Sralph for (i = 3; i < NOFILE; i++) 118612463Sralph (void) close(i); 118712463Sralph if ((cp = rindex(OF, '/')) == NULL) 118812463Sralph cp = OF; 118912463Sralph else 119012463Sralph cp++; 119112463Sralph execl(OF, cp, width, length, 0); 119216762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, OF); 119312463Sralph exit(1); 119412463Sralph } 119512463Sralph (void) close(p[0]); /* close input side */ 119612463Sralph ofd = p[1]; /* use pipe for output */ 119712463Sralph } else { 119812463Sralph ofd = pfd; 119912463Sralph ofilter = 0; 120012463Sralph } 120112463Sralph } 120212463Sralph 120312111Sralph struct bauds { 120412111Sralph int baud; 120512111Sralph int speed; 120612111Sralph } bauds[] = { 120712111Sralph 50, B50, 120812111Sralph 75, B75, 120912111Sralph 110, B110, 121012111Sralph 134, B134, 121112111Sralph 150, B150, 121212111Sralph 200, B200, 121312111Sralph 300, B300, 121412111Sralph 600, B600, 121512111Sralph 1200, B1200, 121612111Sralph 1800, B1800, 121712111Sralph 2400, B2400, 121812111Sralph 4800, B4800, 121912111Sralph 9600, B9600, 122012111Sralph 19200, EXTA, 122112111Sralph 38400, EXTB, 122212111Sralph 0, 0 122312111Sralph }; 122412111Sralph 122512111Sralph /* 122612111Sralph * setup tty lines. 122712111Sralph */ 122812111Sralph setty() 122912111Sralph { 123012111Sralph struct sgttyb ttybuf; 123112111Sralph register struct bauds *bp; 123212111Sralph 123312111Sralph if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) { 123416762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer); 123512111Sralph exit(1); 123612111Sralph } 123712111Sralph if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) { 123816762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCGETP): %m", printer); 123912111Sralph exit(1); 124012111Sralph } 124112111Sralph if (BR > 0) { 124212111Sralph for (bp = bauds; bp->baud; bp++) 124312111Sralph if (BR == bp->baud) 124412111Sralph break; 124512111Sralph if (!bp->baud) { 124616762Sralph syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR); 124712111Sralph exit(1); 124812111Sralph } 124912111Sralph ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed; 125012111Sralph } 125113169Sralph ttybuf.sg_flags &= ~FC; 125213169Sralph ttybuf.sg_flags |= FS; 125312111Sralph if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) { 125416762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCSETP): %m", printer); 125512111Sralph exit(1); 125612111Sralph } 125717168Sralph if (XC || XS) { 125817168Sralph int ldisc = NTTYDISC; 125917168Sralph 126017168Sralph if (ioctl(pfd, TIOCSETD, &ldisc) < 0) { 126117168Sralph syslog(LOG_ERR, "%s: ioctl(TIOCSETD): %m", printer); 126217168Sralph exit(1); 126317168Sralph } 126417168Sralph } 126512111Sralph if (XC) { 126612111Sralph if (ioctl(pfd, TIOCLBIC, &XC) < 0) { 126716762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCLBIC): %m", printer); 126812111Sralph exit(1); 126912111Sralph } 127012111Sralph } 127112111Sralph if (XS) { 127212111Sralph if (ioctl(pfd, TIOCLBIS, &XS) < 0) { 127316762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCLBIS): %m", printer); 127412111Sralph exit(1); 127512111Sralph } 127612111Sralph } 127712111Sralph } 127812463Sralph 127912463Sralph /*VARARGS1*/ 128012463Sralph status(msg, a1, a2, a3) 128112463Sralph char *msg; 128212463Sralph { 128312463Sralph register int fd; 128412463Sralph char buf[BUFSIZ]; 128512463Sralph 128612463Sralph umask(0); 128713148Ssam fd = open(ST, O_WRONLY|O_CREAT, 0664); 128816762Sralph if (fd < 0 || flock(fd, LOCK_EX) < 0) { 128916762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, ST); 129016762Sralph exit(1); 129116762Sralph } 129213148Ssam ftruncate(fd, 0); 129312463Sralph sprintf(buf, msg, a1, a2, a3); 129412463Sralph strcat(buf, "\n"); 129512463Sralph (void) write(fd, buf, strlen(buf)); 129612463Sralph (void) close(fd); 129712463Sralph } 1298