1*22437Sdist /* 2*22437Sdist * Copyright (c) 1983 Regents of the University of California. 3*22437Sdist * All rights reserved. The Berkeley software License Agreement 4*22437Sdist * specifies the terms and conditions for redistribution. 5*22437Sdist */ 6*22437Sdist 713954Ssam #ifndef lint 8*22437Sdist static char sccsid[] = "@(#)printjob.c 5.1 (Berkeley) 06/06/85"; 9*22437Sdist #endif not lint 1013954Ssam 1112111Sralph /* 1212111Sralph * printjob -- print jobs in the queue. 1312111Sralph * 1412111Sralph * NOTE: the lock file is used to pass information to lpq and lprm. 1512111Sralph * it does not need to be removed because file locks are dynamic. 1612111Sralph */ 1712111Sralph 1812111Sralph #include "lp.h" 1912111Sralph 2016762Sralph #define DORETURN 0 /* absorb fork error */ 2116762Sralph #define DOABORT 1 /* abort if dofork fails */ 2212111Sralph 2317463Sralph /* 2417463Sralph * Error tokens 2517463Sralph */ 2617463Sralph #define REPRINT -2 2717463Sralph #define ERROR -1 2817463Sralph #define OK 0 2917463Sralph #define FATALERR 1 3017463Sralph #define NOACCT 2 3117463Sralph #define FILTERERR 3 3217463Sralph #define ACCESS 4 3317463Sralph 3416762Sralph char title[80]; /* ``pr'' title */ 3516762Sralph FILE *cfp; /* control file */ 3616762Sralph int pfd; /* printer file descriptor */ 3716762Sralph int ofd; /* output filter file descriptor */ 3816762Sralph int lfd; /* lock file descriptor */ 3916762Sralph int pid; /* pid of lpd process */ 4016762Sralph int prchild; /* id of pr process */ 4116762Sralph int child; /* id of any filters */ 4216762Sralph int ofilter; /* id of output filter, if any */ 4316762Sralph int tof; /* true if at top of form */ 4416762Sralph int remote; /* true if sending files to remote */ 4517463Sralph dev_t fdev; /* device of file pointed to by symlink */ 4617463Sralph ino_t fino; /* inode of file pointed to by symlink */ 4712111Sralph 4816762Sralph char fromhost[32]; /* user's host machine */ 4916762Sralph char logname[32]; /* user's login name */ 5016762Sralph char jobname[100]; /* job or file name */ 5116762Sralph char class[32]; /* classification field */ 5216762Sralph char width[10] = "-w"; /* page width in characters */ 5316762Sralph char length[10] = "-l"; /* page length in lines */ 5416762Sralph char pxwidth[10] = "-x"; /* page width in pixels */ 5516762Sralph char pxlength[10] = "-y"; /* page length in pixels */ 5616762Sralph char indent[10] = "-i0"; /* indentation size in characters */ 5716762Sralph char tmpfile[] = "errsXXXXXX"; /* file name for filter output */ 5812111Sralph 5912111Sralph printjob() 6012111Sralph { 6112111Sralph struct stat stb; 6212111Sralph register struct queue *q, **qp; 6312111Sralph struct queue **queue; 6412111Sralph register int i, nitems; 6512111Sralph long pidoff; 6616762Sralph int count = 0; 6716762Sralph extern int abortpr(); 6812111Sralph 6912111Sralph init(); /* set up capabilities */ 7013442Sralph (void) write(1, "", 1); /* ack that daemon is started */ 7116762Sralph setgid(getegid()); 7212463Sralph pid = getpid(); /* for use with lprm */ 7312111Sralph setpgrp(0, pid); 7416762Sralph signal(SIGHUP, abortpr); 7516762Sralph signal(SIGINT, abortpr); 7616762Sralph signal(SIGQUIT, abortpr); 7716762Sralph signal(SIGTERM, abortpr); 7812111Sralph 7915811Sralph (void) mktemp(tmpfile); 8015811Sralph 8112111Sralph /* 8212111Sralph * uses short form file names 8312111Sralph */ 8412111Sralph if (chdir(SD) < 0) { 8516762Sralph syslog(LOG_ERR, "%s: %m", SD); 8612111Sralph exit(1); 8712111Sralph } 8812463Sralph if (stat(LO, &stb) == 0 && (stb.st_mode & 0100)) 8912463Sralph exit(0); /* printing disabled */ 9014150Sralph lfd = open(LO, O_WRONLY|O_CREAT, 0644); 9113169Sralph if (lfd < 0) { 9216762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, LO); 9313169Sralph exit(1); 9413169Sralph } 9513169Sralph if (flock(lfd, LOCK_EX|LOCK_NB) < 0) { 9612111Sralph if (errno == EWOULDBLOCK) /* active deamon present */ 9712111Sralph exit(0); 9816762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, LO); 9912111Sralph exit(1); 10012111Sralph } 10113148Ssam ftruncate(lfd, 0); 10212111Sralph /* 10312111Sralph * write process id for others to know 10412111Sralph */ 10512111Sralph sprintf(line, "%u\n", pid); 10612111Sralph pidoff = i = strlen(line); 10712463Sralph if (write(lfd, line, i) != i) { 10816762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, LO); 10912111Sralph exit(1); 11012111Sralph } 11112111Sralph /* 11212111Sralph * search the spool directory for work and sort by queue order. 11312111Sralph */ 11412111Sralph if ((nitems = getq(&queue)) < 0) { 11516762Sralph syslog(LOG_ERR, "%s: can't scan %s", printer, SD); 11612111Sralph exit(1); 11712111Sralph } 11812463Sralph if (nitems == 0) /* no work to do */ 11912111Sralph exit(0); 12013169Sralph if (stb.st_mode & 01) { /* reset queue flag */ 12113169Sralph if (fchmod(lfd, stb.st_mode & 0776) < 0) 12216762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, LO); 12313169Sralph } 12412463Sralph openpr(); /* open printer or remote */ 12512463Sralph again: 12612111Sralph /* 12712111Sralph * we found something to do now do it -- 12812111Sralph * write the name of the current control file into the lock file 12912111Sralph * so the spool queue program can tell what we're working on 13012111Sralph */ 13112111Sralph for (qp = queue; nitems--; free((char *) q)) { 13212111Sralph q = *qp++; 13312111Sralph if (stat(q->q_name, &stb) < 0) 13412111Sralph continue; 13512463Sralph restart: 13612111Sralph (void) lseek(lfd, pidoff, 0); 13712111Sralph (void) sprintf(line, "%s\n", q->q_name); 13812111Sralph i = strlen(line); 13912111Sralph if (write(lfd, line, i) != i) 14016762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, LO); 14112111Sralph if (!remote) 14212111Sralph i = printit(q->q_name); 14312111Sralph else 14412111Sralph i = sendit(q->q_name); 14512463Sralph /* 14613169Sralph * Check to see if we are supposed to stop printing or 14713169Sralph * if we are to rebuild the queue. 14812463Sralph */ 14913169Sralph if (fstat(lfd, &stb) == 0) { 15016762Sralph /* stop printing before starting next job? */ 15113169Sralph if (stb.st_mode & 0100) 15213169Sralph goto done; 15316762Sralph /* rebuild queue (after lpc topq) */ 15413169Sralph if (stb.st_mode & 01) { 15513169Sralph for (free((char *) q); nitems--; free((char *) q)) 15613169Sralph q = *qp++; 15713169Sralph if (fchmod(lfd, stb.st_mode & 0776) < 0) 15816762Sralph syslog(LOG_WARNING, "%s: %s: %m", 15916762Sralph printer, LO); 16013169Sralph break; 16113169Sralph } 16213169Sralph } 16317463Sralph if (i == OK) /* file ok and printed */ 16414150Sralph count++; 16517463Sralph else if (i == REPRINT) { /* try reprinting the job */ 16616762Sralph syslog(LOG_INFO, "restarting %s", printer); 16712111Sralph if (ofilter > 0) { 16812111Sralph kill(ofilter, SIGCONT); /* to be sure */ 16912111Sralph (void) close(ofd); 17012111Sralph while ((i = wait(0)) > 0 && i != ofilter) 17112111Sralph ; 17212111Sralph ofilter = 0; 17312111Sralph } 17412463Sralph (void) close(pfd); /* close printer */ 17515811Sralph if (ftruncate(lfd, pidoff) < 0) 17616762Sralph syslog(LOG_WARNING, "%s: %s: %m", printer, LO); 17712463Sralph openpr(); /* try to reopen printer */ 17812111Sralph goto restart; 17912111Sralph } 18012111Sralph } 18112111Sralph free((char *) queue); 18212463Sralph /* 18312463Sralph * search the spool directory for more work. 18412463Sralph */ 18512463Sralph if ((nitems = getq(&queue)) < 0) { 18616762Sralph syslog(LOG_ERR, "%s: can't scan %s", printer, SD); 18712463Sralph exit(1); 18812463Sralph } 18912463Sralph if (nitems == 0) { /* no more work to do */ 19012463Sralph done: 19114150Sralph if (count > 0) { /* Files actually printed */ 19214150Sralph if (!SF && !tof) 19314150Sralph (void) write(ofd, FF, strlen(FF)); 19414150Sralph if (TR != NULL) /* output trailer */ 19514150Sralph (void) write(ofd, TR, strlen(TR)); 19614150Sralph } 19715811Sralph (void) unlink(tmpfile); 19812463Sralph exit(0); 19912463Sralph } 20012111Sralph goto again; 20112111Sralph } 20212111Sralph 20312111Sralph char fonts[4][50]; /* fonts for troff */ 20412111Sralph 20516762Sralph char ifonts[4][18] = { 20612111Sralph "/usr/lib/vfont/R", 20712111Sralph "/usr/lib/vfont/I", 20812111Sralph "/usr/lib/vfont/B", 20912111Sralph "/usr/lib/vfont/S" 21012111Sralph }; 21112111Sralph 21212111Sralph /* 21312111Sralph * The remaining part is the reading of the control file (cf) 21412111Sralph * and performing the various actions. 21512111Sralph */ 21612111Sralph printit(file) 21712111Sralph char *file; 21812111Sralph { 21912111Sralph register int i; 22017463Sralph char *cp; 22117463Sralph int bombed = OK; 22212111Sralph 22312111Sralph /* 22417463Sralph * open control file; ignore if no longer there. 22512111Sralph */ 22612111Sralph if ((cfp = fopen(file, "r")) == NULL) { 22716762Sralph syslog(LOG_INFO, "%s: %s: %m", printer, file); 22817463Sralph return(OK); 22912111Sralph } 23012111Sralph /* 23112111Sralph * Reset troff fonts. 23212111Sralph */ 23312111Sralph for (i = 0; i < 4; i++) 23412111Sralph strcpy(fonts[i], ifonts[i]); 23517339Sralph strcpy(width+2, "0"); 23617302Sralph strcpy(indent+2, "0"); 23712111Sralph 23812111Sralph /* 23912111Sralph * read the control file for work to do 24012111Sralph * 24112111Sralph * file format -- first character in the line is a command 24212111Sralph * rest of the line is the argument. 24312111Sralph * valid commands are: 24412111Sralph * 24517463Sralph * S -- "stat info" for symbolic link protection 24612111Sralph * J -- "job name" on banner page 24712111Sralph * C -- "class name" on banner page 24812111Sralph * L -- "literal" user's name to print on banner 24912111Sralph * T -- "title" for pr 25012111Sralph * H -- "host name" of machine where lpr was done 25112111Sralph * P -- "person" user's login name 25212581Sralph * I -- "indent" amount to indent output 25312111Sralph * f -- "file name" name of text file to print 25412111Sralph * l -- "file name" text file with control chars 25512111Sralph * p -- "file name" text file to print with pr(1) 25612111Sralph * t -- "file name" troff(1) file to print 25713233Sralph * n -- "file name" ditroff(1) file to print 25812111Sralph * d -- "file name" dvi file to print 25912111Sralph * g -- "file name" plot(1G) file to print 26012111Sralph * v -- "file name" plain raster file to print 26112111Sralph * c -- "file name" cifplot file to print 26212111Sralph * 1 -- "R font file" for troff 26312111Sralph * 2 -- "I font file" for troff 26412111Sralph * 3 -- "B font file" for troff 26512111Sralph * 4 -- "S font file" for troff 26612111Sralph * N -- "name" of file (used by lpq) 26712111Sralph * U -- "unlink" name of file to remove 26812111Sralph * (after we print it. (Pass 2 only)). 26912111Sralph * M -- "mail" to user when done printing 27012111Sralph * 27112111Sralph * getline reads a line and expands tabs to blanks 27212111Sralph */ 27312111Sralph 27412111Sralph /* pass 1 */ 27512111Sralph 27612111Sralph while (getline(cfp)) 27712111Sralph switch (line[0]) { 27812111Sralph case 'H': 27914150Sralph strcpy(fromhost, line+1); 28012111Sralph if (class[0] == '\0') 28115552Sralph strncpy(class, line+1, sizeof(class)-1); 28212111Sralph continue; 28312111Sralph 28412111Sralph case 'P': 28515552Sralph strncpy(logname, line+1, sizeof(logname)-1); 28612463Sralph if (RS) { /* restricted */ 28712463Sralph if (getpwnam(logname) == (struct passwd *)0) { 28817463Sralph bombed = NOACCT; 28915811Sralph sendmail(line+1, bombed); 29012463Sralph goto pass2; 29112463Sralph } 29212463Sralph } 29312111Sralph continue; 29412111Sralph 29517463Sralph case 'S': 29617463Sralph cp = line+1; 29717463Sralph i = 0; 29817463Sralph while (*cp >= '0' && *cp <= '9') 29917463Sralph i = i * 10 + (*cp++ - '0'); 30017463Sralph fdev = i; 30117463Sralph cp++; 30217463Sralph i = 0; 30317463Sralph while (*cp >= '0' && *cp <= '9') 30417463Sralph i = i * 10 + (*cp++ - '0'); 30517463Sralph fino = i; 30617463Sralph continue; 30717463Sralph 30812111Sralph case 'J': 30912111Sralph if (line[1] != '\0') 31015552Sralph strncpy(jobname, line+1, sizeof(jobname)-1); 31112111Sralph else 31212111Sralph strcpy(jobname, " "); 31312111Sralph continue; 31412111Sralph 31512111Sralph case 'C': 31612111Sralph if (line[1] != '\0') 31715552Sralph strncpy(class, line+1, sizeof(class)-1); 31812111Sralph else if (class[0] == '\0') 31915811Sralph gethostname(class, sizeof(class)); 32012111Sralph continue; 32112111Sralph 32212111Sralph case 'T': /* header title for pr */ 32315552Sralph strncpy(title, line+1, sizeof(title)-1); 32412111Sralph continue; 32512111Sralph 32612111Sralph case 'L': /* identification line */ 32718127Sralph if (!SH && !HL) 32812111Sralph banner(line+1, jobname); 32912111Sralph continue; 33012111Sralph 33112111Sralph case '1': /* troff fonts */ 33212111Sralph case '2': 33312111Sralph case '3': 33412111Sralph case '4': 33512111Sralph if (line[1] != '\0') 33612111Sralph strcpy(fonts[line[0]-'1'], line+1); 33712111Sralph continue; 33812111Sralph 33912111Sralph case 'W': /* page width */ 34015552Sralph strncpy(width+2, line+1, sizeof(width)-3); 34112111Sralph continue; 34212111Sralph 34312581Sralph case 'I': /* indent amount */ 34415552Sralph strncpy(indent+2, line+1, sizeof(indent)-3); 34512581Sralph continue; 34612581Sralph 34712111Sralph default: /* some file to print */ 34815811Sralph switch (i = print(line[0], line+1)) { 34917463Sralph case ERROR: 35017463Sralph if (bombed == OK) 35117463Sralph bombed = FATALERR; 35215811Sralph break; 35317463Sralph case REPRINT: 35412111Sralph (void) fclose(cfp); 35517463Sralph return(REPRINT); 35617463Sralph case FILTERERR: 35717463Sralph case ACCESS: 35817463Sralph bombed = i; 35915811Sralph sendmail(logname, bombed); 36015811Sralph } 36112111Sralph title[0] = '\0'; 36212111Sralph continue; 36312111Sralph 36412111Sralph case 'N': 36512111Sralph case 'U': 36612111Sralph case 'M': 36712111Sralph continue; 36812111Sralph } 36912111Sralph 37012111Sralph /* pass 2 */ 37112111Sralph 37212463Sralph pass2: 37312111Sralph fseek(cfp, 0L, 0); 37412111Sralph while (getline(cfp)) 37512111Sralph switch (line[0]) { 37618127Sralph case 'L': /* identification line */ 37718127Sralph if (!SH && HL) 37818127Sralph banner(line+1, jobname); 37918127Sralph continue; 38018127Sralph 38112111Sralph case 'M': 38217463Sralph if (bombed < NOACCT) /* already sent if >= NOACCT */ 38315811Sralph sendmail(line+1, bombed); 38412111Sralph continue; 38512111Sralph 38612111Sralph case 'U': 38712111Sralph (void) unlink(line+1); 38812111Sralph } 38912111Sralph /* 39015811Sralph * clean-up in case another control file exists 39112111Sralph */ 39212111Sralph (void) fclose(cfp); 39312111Sralph (void) unlink(file); 39417463Sralph return(bombed == OK ? OK : ERROR); 39512111Sralph } 39612111Sralph 39712111Sralph /* 39812111Sralph * Print a file. 39913233Sralph * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}. 40015811Sralph * Return -1 if a non-recoverable error occured, 40115811Sralph * 2 if the filter detected some errors (but printed the job anyway), 40215811Sralph * 1 if we should try to reprint this job and 40312111Sralph * 0 if all is well. 40412111Sralph * Note: all filters take stdin as the file, stdout as the printer, 40512111Sralph * stderr as the log file, and must not ignore SIGINT. 40612111Sralph */ 40712111Sralph print(format, file) 40812111Sralph int format; 40912111Sralph char *file; 41012111Sralph { 41115811Sralph register int n; 41212111Sralph register char *prog; 41315811Sralph int fi, fo; 41412111Sralph char *av[15], buf[BUFSIZ]; 41512111Sralph int pid, p[2], stopped = 0; 41612111Sralph union wait status; 41717463Sralph struct stat stb; 41812111Sralph 41917463Sralph if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0) 42017463Sralph return(ERROR); 42117463Sralph /* 42217463Sralph * Check to see if data file is a symbolic link. If so, it should 42317463Sralph * still point to the same file or someone is trying to print 42417463Sralph * something he shouldn't. 42517463Sralph */ 42617463Sralph if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 && 42717463Sralph (stb.st_dev != fdev || stb.st_ino != fino)) 42817463Sralph return(ACCESS); 42912111Sralph if (!SF && !tof) { /* start on a fresh page */ 43012111Sralph (void) write(ofd, FF, strlen(FF)); 43112111Sralph tof = 1; 43212111Sralph } 43312111Sralph if (IF == NULL && (format == 'f' || format == 'l')) { 43412111Sralph tof = 0; 43512111Sralph while ((n = read(fi, buf, BUFSIZ)) > 0) 43612111Sralph if (write(ofd, buf, n) != n) { 43712111Sralph (void) close(fi); 43817463Sralph return(REPRINT); 43912111Sralph } 44012111Sralph (void) close(fi); 44117463Sralph return(OK); 44212111Sralph } 44312111Sralph switch (format) { 44412111Sralph case 'p': /* print file using 'pr' */ 44512111Sralph if (IF == NULL) { /* use output filter */ 44612111Sralph prog = PR; 44712111Sralph av[0] = "pr"; 44812111Sralph av[1] = width; 44912111Sralph av[2] = length; 45012111Sralph av[3] = "-h"; 45112111Sralph av[4] = *title ? title : " "; 45212111Sralph av[5] = 0; 45312111Sralph fo = ofd; 45412111Sralph goto start; 45512111Sralph } 45612111Sralph pipe(p); 45712111Sralph if ((prchild = dofork(DORETURN)) == 0) { /* child */ 45812111Sralph dup2(fi, 0); /* file is stdin */ 45912111Sralph dup2(p[1], 1); /* pipe is stdout */ 46012111Sralph for (n = 3; n < NOFILE; n++) 46112111Sralph (void) close(n); 46212111Sralph execl(PR, "pr", width, length, "-h", *title ? title : " ", 0); 46316762Sralph syslog(LOG_ERR, "cannot execl %s", PR); 46412111Sralph exit(2); 46512111Sralph } 46612111Sralph (void) close(p[1]); /* close output side */ 46712111Sralph (void) close(fi); 46812111Sralph if (prchild < 0) { 46912111Sralph prchild = 0; 47012111Sralph (void) close(p[0]); 47117463Sralph return(ERROR); 47212111Sralph } 47312111Sralph fi = p[0]; /* use pipe for input */ 47412111Sralph case 'f': /* print plain text file */ 47512111Sralph prog = IF; 47612111Sralph av[1] = width; 47712111Sralph av[2] = length; 47812581Sralph av[3] = indent; 47912581Sralph n = 4; 48012111Sralph break; 48112111Sralph case 'l': /* like 'f' but pass control characters */ 48212111Sralph prog = IF; 48314325Sralph av[1] = "-c"; 48412111Sralph av[2] = width; 48512111Sralph av[3] = length; 48612581Sralph av[4] = indent; 48712581Sralph n = 5; 48812111Sralph break; 48912463Sralph case 'r': /* print a fortran text file */ 49012463Sralph prog = RF; 49112463Sralph av[1] = width; 49212463Sralph av[2] = length; 49312463Sralph n = 3; 49412463Sralph break; 49512111Sralph case 't': /* print troff output */ 49613233Sralph case 'n': /* print ditroff output */ 49712463Sralph case 'd': /* print tex output */ 49812111Sralph (void) unlink(".railmag"); 49912463Sralph if ((fo = creat(".railmag", FILMOD)) < 0) { 50016762Sralph syslog(LOG_ERR, "%s: cannot create .railmag", printer); 50112111Sralph (void) unlink(".railmag"); 50212111Sralph } else { 50312111Sralph for (n = 0; n < 4; n++) { 50412111Sralph if (fonts[n][0] != '/') 50512111Sralph (void) write(fo, "/usr/lib/vfont/", 15); 50612111Sralph (void) write(fo, fonts[n], strlen(fonts[n])); 50712111Sralph (void) write(fo, "\n", 1); 50812111Sralph } 50912111Sralph (void) close(fo); 51012111Sralph } 51113233Sralph prog = (format == 't') ? TF : (format == 'n') ? NF : DF; 51212463Sralph av[1] = pxwidth; 51312463Sralph av[2] = pxlength; 51412463Sralph n = 3; 51512111Sralph break; 51612111Sralph case 'c': /* print cifplot output */ 51712111Sralph prog = CF; 51812463Sralph av[1] = pxwidth; 51912463Sralph av[2] = pxlength; 52012463Sralph n = 3; 52112111Sralph break; 52212111Sralph case 'g': /* print plot(1G) output */ 52312111Sralph prog = GF; 52412463Sralph av[1] = pxwidth; 52512463Sralph av[2] = pxlength; 52612463Sralph n = 3; 52712111Sralph break; 52812111Sralph case 'v': /* print raster output */ 52912111Sralph prog = VF; 53012463Sralph av[1] = pxwidth; 53112463Sralph av[2] = pxlength; 53212463Sralph n = 3; 53312111Sralph break; 53412111Sralph default: 53512111Sralph (void) close(fi); 53616762Sralph syslog(LOG_ERR, "%s: illegal format character '%c'", 53716762Sralph printer, format); 53817463Sralph return(ERROR); 53912111Sralph } 54012111Sralph if ((av[0] = rindex(prog, '/')) != NULL) 54112111Sralph av[0]++; 54212111Sralph else 54312111Sralph av[0] = prog; 54412111Sralph av[n++] = "-n"; 54512111Sralph av[n++] = logname; 54612111Sralph av[n++] = "-h"; 54714150Sralph av[n++] = fromhost; 54812111Sralph av[n++] = AF; 54912111Sralph av[n] = 0; 55012111Sralph fo = pfd; 55112111Sralph if (ofilter > 0) { /* stop output filter */ 55212111Sralph write(ofd, "\031\1", 2); 55312111Sralph while ((pid = wait3(&status, WUNTRACED, 0)) > 0 && pid != ofilter) 55412111Sralph ; 55512111Sralph if (status.w_stopval != WSTOPPED) { 55612111Sralph (void) close(fi); 55716762Sralph syslog(LOG_WARNING, "%s: output filter died (%d)", 55816762Sralph printer, status.w_retcode); 55917463Sralph return(REPRINT); 56012111Sralph } 56112111Sralph stopped++; 56212111Sralph } 56312111Sralph start: 56412111Sralph if ((child = dofork(DORETURN)) == 0) { /* child */ 56512111Sralph dup2(fi, 0); 56612111Sralph dup2(fo, 1); 56717304Sralph n = open(tmpfile, O_WRONLY|O_CREAT|O_TRUNC, 0664); 56815811Sralph if (n >= 0) 56915811Sralph dup2(n, 2); 57012111Sralph for (n = 3; n < NOFILE; n++) 57112111Sralph (void) close(n); 57212111Sralph execv(prog, av); 57316762Sralph syslog(LOG_ERR, "cannot execv %s", prog); 57412111Sralph exit(2); 57512111Sralph } 57612111Sralph (void) close(fi); 57712111Sralph if (child < 0) 57812111Sralph status.w_retcode = 100; 57912111Sralph else 58012111Sralph while ((pid = wait(&status)) > 0 && pid != child) 58112111Sralph ; 58212111Sralph child = 0; 58312111Sralph prchild = 0; 58412111Sralph if (stopped) { /* restart output filter */ 58512111Sralph if (kill(ofilter, SIGCONT) < 0) { 58616762Sralph syslog(LOG_ERR, "cannot restart output filter"); 58712111Sralph exit(1); 58812111Sralph } 58912111Sralph } 59012111Sralph tof = 0; 59115811Sralph if (!WIFEXITED(status)) { 59216762Sralph syslog(LOG_WARNING, "%s: Daemon filter '%c' terminated (%d)", 59316762Sralph printer, format, status.w_termsig); 59417463Sralph return(ERROR); 59517463Sralph } 59617463Sralph switch (status.w_retcode) { 59717463Sralph case 0: 59817463Sralph tof = 1; 59917463Sralph return(OK); 60017463Sralph case 1: 60117463Sralph return(REPRINT); 60217463Sralph default: 60316762Sralph syslog(LOG_WARNING, "%s: Daemon filter '%c' exited (%d)", 60416762Sralph printer, format, status.w_retcode); 60517463Sralph case 2: 60617463Sralph return(ERROR); 60717463Sralph } 60812111Sralph } 60912111Sralph 61012111Sralph /* 61112111Sralph * Send the daemon control file (cf) and any data files. 61212111Sralph * Return -1 if a non-recoverable error occured, 1 if a recoverable error and 61312111Sralph * 0 if all is well. 61412111Sralph */ 61512111Sralph sendit(file) 61612111Sralph char *file; 61712111Sralph { 61817463Sralph register int i, err = OK; 61917463Sralph char *cp, last[BUFSIZ]; 62012111Sralph 62112111Sralph /* 62212111Sralph * open control file 62312111Sralph */ 62416762Sralph if ((cfp = fopen(file, "r")) == NULL) 62517463Sralph return(OK); 62612111Sralph /* 62712111Sralph * read the control file for work to do 62812111Sralph * 62912111Sralph * file format -- first character in the line is a command 63012111Sralph * rest of the line is the argument. 63112111Sralph * commands of interest are: 63212111Sralph * 63312111Sralph * a-z -- "file name" name of file to print 63412111Sralph * U -- "unlink" name of file to remove 63512111Sralph * (after we print it. (Pass 2 only)). 63612111Sralph */ 63712111Sralph 63812111Sralph /* 63912111Sralph * pass 1 64012111Sralph */ 64112111Sralph while (getline(cfp)) { 64212111Sralph again: 64317463Sralph if (line[0] == 'S') { 64417463Sralph cp = line+1; 64517463Sralph i = 0; 64617463Sralph while (*cp >= '0' && *cp <= '9') 64717463Sralph i = i * 10 + (*cp++ - '0'); 64817463Sralph fdev = i; 64917463Sralph cp++; 65017463Sralph i = 0; 65117463Sralph while (*cp >= '0' && *cp <= '9') 65217463Sralph i = i * 10 + (*cp++ - '0'); 65317463Sralph fino = i; 65417463Sralph continue; 65517463Sralph } 65612111Sralph if (line[0] >= 'a' && line[0] <= 'z') { 65712111Sralph strcpy(last, line); 65817463Sralph while (i = getline(cfp)) 65912111Sralph if (strcmp(last, line)) 66012111Sralph break; 66117463Sralph switch (sendfile('\3', last+1)) { 66217463Sralph case OK: 66317463Sralph if (i) 66417463Sralph goto again; 66517463Sralph break; 66617463Sralph case REPRINT: 66712111Sralph (void) fclose(cfp); 66817463Sralph return(REPRINT); 66917463Sralph case ACCESS: 67017463Sralph sendmail(logname, ACCESS); 67117463Sralph case ERROR: 67217463Sralph err = ERROR; 67317463Sralph } 67412111Sralph break; 67512111Sralph } 67612111Sralph } 67717463Sralph if (err == OK && sendfile('\2', file) > 0) { 67812111Sralph (void) fclose(cfp); 67917463Sralph return(REPRINT); 68012111Sralph } 68112111Sralph /* 68212111Sralph * pass 2 68312111Sralph */ 68412111Sralph fseek(cfp, 0L, 0); 68512111Sralph while (getline(cfp)) 68612111Sralph if (line[0] == 'U') 68712111Sralph (void) unlink(line+1); 68812111Sralph /* 68917463Sralph * clean-up in case another control file exists 69012111Sralph */ 69112111Sralph (void) fclose(cfp); 69212111Sralph (void) unlink(file); 69317463Sralph return(err); 69412111Sralph } 69512111Sralph 69612111Sralph /* 69712111Sralph * Send a data file to the remote machine and spool it. 69812111Sralph * Return positive if we should try resending. 69912111Sralph */ 70012111Sralph sendfile(type, file) 70112111Sralph char type, *file; 70212111Sralph { 70312111Sralph register int f, i, amt; 70412111Sralph struct stat stb; 70512111Sralph char buf[BUFSIZ]; 70616762Sralph int sizerr, resp; 70712111Sralph 70817463Sralph if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0) 70917463Sralph return(ERROR); 71017463Sralph /* 71117463Sralph * Check to see if data file is a symbolic link. If so, it should 71217463Sralph * still point to the same file or someone is trying to print something 71317463Sralph * he shouldn't. 71417463Sralph */ 71517463Sralph if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 && 71617463Sralph (stb.st_dev != fdev || stb.st_ino != fino)) 71717463Sralph return(ACCESS); 71812111Sralph (void) sprintf(buf, "%c%d %s\n", type, stb.st_size, file); 71912111Sralph amt = strlen(buf); 72016762Sralph for (i = 0; ; i++) { 72116762Sralph if (write(pfd, buf, amt) != amt || 72216762Sralph (resp = response()) < 0 || resp == '\1') { 72316762Sralph (void) close(f); 72417463Sralph return(REPRINT); 72516762Sralph } else if (resp == '\0') 72616762Sralph break; 72716762Sralph if (i == 0) 72816762Sralph status("no space on remote; waiting for queue to drain"); 72916762Sralph if (i == 10) 73016762Sralph syslog(LOG_SALERT, "%s: can't send to %s; queue full", 73116762Sralph printer, RM); 73216762Sralph sleep(5 * 60); 73312692Sralph } 73416762Sralph if (i) 73516762Sralph status("sending to %s", RM); 73612111Sralph sizerr = 0; 73712111Sralph for (i = 0; i < stb.st_size; i += BUFSIZ) { 73812111Sralph amt = BUFSIZ; 73912111Sralph if (i + amt > stb.st_size) 74012111Sralph amt = stb.st_size - i; 74112111Sralph if (sizerr == 0 && read(f, buf, amt) != amt) 74212111Sralph sizerr = 1; 74312692Sralph if (write(pfd, buf, amt) != amt) { 74412692Sralph (void) close(f); 74517463Sralph return(REPRINT); 74612692Sralph } 74712111Sralph } 74812111Sralph (void) close(f); 74912111Sralph if (sizerr) { 75016762Sralph syslog(LOG_INFO, "%s: %s: changed size", printer, file); 75117463Sralph /* tell recvjob to ignore this file */ 75217463Sralph (void) write(pfd, "\1", 1); 75317463Sralph return(ERROR); 75417463Sralph } 75517463Sralph if (write(pfd, "", 1) != 1 || response()) 75617463Sralph return(REPRINT); 75717463Sralph return(OK); 75812111Sralph } 75912111Sralph 76012111Sralph /* 76112111Sralph * Check to make sure there have been no errors and that both programs 76212111Sralph * are in sync with eachother. 76312111Sralph * Return non-zero if the connection was lost. 76412111Sralph */ 76516762Sralph response() 76612111Sralph { 76712111Sralph char resp; 76812111Sralph 76916762Sralph if (read(pfd, &resp, 1) != 1) { 77016762Sralph syslog(LOG_INFO, "%s: lost connection", printer); 77116762Sralph return(-1); 77212111Sralph } 77316762Sralph return(resp); 77412111Sralph } 77512111Sralph 77612111Sralph /* 77712111Sralph * Banner printing stuff 77812111Sralph */ 77912111Sralph banner(name1, name2) 78012111Sralph char *name1, *name2; 78112111Sralph { 78212111Sralph time_t tvec; 78312111Sralph extern char *ctime(); 78412111Sralph 78512111Sralph time(&tvec); 78612111Sralph if (!SF && !tof) 78712111Sralph (void) write(ofd, FF, strlen(FF)); 78812111Sralph if (SB) { /* short banner only */ 78912111Sralph if (class[0]) { 79012111Sralph (void) write(ofd, class, strlen(class)); 79112111Sralph (void) write(ofd, ":", 1); 79212111Sralph } 79312111Sralph (void) write(ofd, name1, strlen(name1)); 79412111Sralph (void) write(ofd, " Job: ", 7); 79512111Sralph (void) write(ofd, name2, strlen(name2)); 79612111Sralph (void) write(ofd, " Date: ", 8); 79712111Sralph (void) write(ofd, ctime(&tvec), 24); 79812111Sralph (void) write(ofd, "\n", 1); 79912111Sralph } else { /* normal banner */ 80012111Sralph (void) write(ofd, "\n\n\n", 3); 80112111Sralph scan_out(ofd, name1, '\0'); 80212111Sralph (void) write(ofd, "\n\n", 2); 80312111Sralph scan_out(ofd, name2, '\0'); 80412111Sralph if (class[0]) { 80512111Sralph (void) write(ofd,"\n\n\n",3); 80612111Sralph scan_out(ofd, class, '\0'); 80712111Sralph } 80812111Sralph (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15); 80912111Sralph (void) write(ofd, name2, strlen(name2)); 81012111Sralph (void) write(ofd, "\n\t\t\t\t\tDate: ", 12); 81112111Sralph (void) write(ofd, ctime(&tvec), 24); 81212111Sralph (void) write(ofd, "\n", 1); 81312111Sralph } 81412111Sralph if (!SF) 81512111Sralph (void) write(ofd, FF, strlen(FF)); 81612111Sralph tof = 1; 81712111Sralph } 81812111Sralph 81916762Sralph char * 82012111Sralph scnline(key, p, c) 82112111Sralph register char key, *p; 82212111Sralph char c; 82312111Sralph { 82412111Sralph register scnwidth; 82512111Sralph 82612111Sralph for (scnwidth = WIDTH; --scnwidth;) { 82712111Sralph key <<= 1; 82812111Sralph *p++ = key & 0200 ? c : BACKGND; 82912111Sralph } 83012111Sralph return (p); 83112111Sralph } 83212111Sralph 83312111Sralph #define TRC(q) (((q)-' ')&0177) 83412111Sralph 83512111Sralph scan_out(scfd, scsp, dlm) 83612111Sralph int scfd; 83712111Sralph char *scsp, dlm; 83812111Sralph { 83912111Sralph register char *strp; 84012111Sralph register nchrs, j; 84112111Sralph char outbuf[LINELEN+1], *sp, c, cc; 84212111Sralph int d, scnhgt; 84312111Sralph extern char scnkey[][HEIGHT]; /* in lpdchar.c */ 84412111Sralph 84512111Sralph for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) { 84612111Sralph strp = &outbuf[0]; 84712111Sralph sp = scsp; 84812111Sralph for (nchrs = 0; ; ) { 84912111Sralph d = dropit(c = TRC(cc = *sp++)); 85012111Sralph if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d)) 85112111Sralph for (j = WIDTH; --j;) 85212111Sralph *strp++ = BACKGND; 85312111Sralph else 85412111Sralph strp = scnline(scnkey[c][scnhgt-1-d], strp, cc); 85512111Sralph if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1) 85612111Sralph break; 85712111Sralph *strp++ = BACKGND; 85812111Sralph *strp++ = BACKGND; 85912111Sralph } 86012111Sralph while (*--strp == BACKGND && strp >= outbuf) 86112111Sralph ; 86212111Sralph strp++; 86312111Sralph *strp++ = '\n'; 86412111Sralph (void) write(scfd, outbuf, strp-outbuf); 86512111Sralph } 86612111Sralph } 86712111Sralph 86812111Sralph dropit(c) 86912111Sralph char c; 87012111Sralph { 87112111Sralph switch(c) { 87212111Sralph 87312111Sralph case TRC('_'): 87412111Sralph case TRC(';'): 87512111Sralph case TRC(','): 87612111Sralph case TRC('g'): 87712111Sralph case TRC('j'): 87812111Sralph case TRC('p'): 87912111Sralph case TRC('q'): 88012111Sralph case TRC('y'): 88112111Sralph return (DROP); 88212111Sralph 88312111Sralph default: 88412111Sralph return (0); 88512111Sralph } 88612111Sralph } 88712111Sralph 88812111Sralph /* 88912111Sralph * sendmail --- 89012111Sralph * tell people about job completion 89112111Sralph */ 89215811Sralph sendmail(user, bombed) 89315811Sralph char *user; 89412111Sralph int bombed; 89512111Sralph { 89612111Sralph register int i; 89715811Sralph int p[2], s; 89812111Sralph register char *cp; 89912111Sralph char buf[100]; 90015811Sralph struct stat stb; 90115811Sralph FILE *fp; 90212111Sralph 90312111Sralph pipe(p); 90415811Sralph if ((s = dofork(DORETURN)) == 0) { /* child */ 90512111Sralph dup2(p[0], 0); 90612111Sralph for (i = 3; i < NOFILE; i++) 90712111Sralph (void) close(i); 90812111Sralph if ((cp = rindex(MAIL, '/')) != NULL) 90912111Sralph cp++; 91012111Sralph else 91112111Sralph cp = MAIL; 91215811Sralph sprintf(buf, "%s@%s", user, fromhost); 91312111Sralph execl(MAIL, cp, buf, 0); 91412111Sralph exit(0); 91515811Sralph } else if (s > 0) { /* parent */ 91612111Sralph dup2(p[1], 1); 91715811Sralph printf("To: %s@%s\n", user, fromhost); 91812111Sralph printf("Subject: printer job\n\n"); 91912111Sralph printf("Your printer job "); 92012111Sralph if (*jobname) 92112111Sralph printf("(%s) ", jobname); 92212463Sralph switch (bombed) { 92317463Sralph case OK: 92412463Sralph printf("\ncompleted successfully\n"); 92512463Sralph break; 92612463Sralph default: 92717463Sralph case FATALERR: 92812463Sralph printf("\ncould not be printed\n"); 92912463Sralph break; 93017463Sralph case NOACCT: 93112463Sralph printf("\ncould not be printed without an account on %s\n", host); 93212463Sralph break; 93317463Sralph case FILTERERR: 93415811Sralph if (stat(tmpfile, &stb) < 0 || stb.st_size == 0 || 93515811Sralph (fp = fopen(tmpfile, "r")) == NULL) { 93615811Sralph printf("\nwas printed but had some errors\n"); 93715811Sralph break; 93815811Sralph } 93915811Sralph printf("\nwas printed but had the following errors:\n"); 94015811Sralph while ((i = getc(fp)) != EOF) 94115811Sralph putchar(i); 94215811Sralph (void) fclose(fp); 94317463Sralph break; 94417463Sralph case ACCESS: 94517463Sralph printf("\nwas not printed because it was not linked to the original file\n"); 94612463Sralph } 94712111Sralph fflush(stdout); 94812111Sralph (void) close(1); 94912111Sralph } 95012111Sralph (void) close(p[0]); 95112111Sralph (void) close(p[1]); 95215811Sralph wait(&s); 95312111Sralph } 95412111Sralph 95512111Sralph /* 95612111Sralph * dofork - fork with retries on failure 95712111Sralph */ 95812111Sralph dofork(action) 95912111Sralph int action; 96012111Sralph { 96112111Sralph register int i, pid; 96212111Sralph 96312111Sralph for (i = 0; i < 20; i++) { 96412463Sralph if ((pid = fork()) < 0) { 96512111Sralph sleep((unsigned)(i*i)); 96612463Sralph continue; 96712463Sralph } 96812463Sralph /* 96912463Sralph * Child should run as daemon instead of root 97012463Sralph */ 97112463Sralph if (pid == 0) 97212463Sralph setuid(DU); 97312463Sralph return(pid); 97412111Sralph } 97516762Sralph syslog(LOG_ERR, "can't fork"); 97612111Sralph 97712111Sralph switch (action) { 97812111Sralph case DORETURN: 97912111Sralph return (-1); 98012111Sralph default: 98116762Sralph syslog(LOG_ERR, "bad action (%d) to dofork", action); 98212111Sralph /*FALL THRU*/ 98312111Sralph case DOABORT: 98412111Sralph exit(1); 98512111Sralph } 98612111Sralph /*NOTREACHED*/ 98712111Sralph } 98812111Sralph 98912111Sralph /* 99016762Sralph * Kill child processes to abort current job. 99112111Sralph */ 99216762Sralph abortpr() 99312111Sralph { 99415811Sralph (void) unlink(tmpfile); 99512111Sralph kill(0, SIGINT); 99612111Sralph if (ofilter > 0) 99712111Sralph kill(ofilter, SIGCONT); 99812111Sralph while (wait(0) > 0) 99912111Sralph ; 100012111Sralph exit(0); 100112111Sralph } 100212111Sralph 100312111Sralph init() 100412111Sralph { 100512111Sralph int status; 100612111Sralph 100713169Sralph if ((status = pgetent(line, printer)) < 0) 100813169Sralph fatal("can't open printer description file"); 100913169Sralph else if (status == 0) 101013169Sralph fatal("unknown printer"); 101112111Sralph if ((LP = pgetstr("lp", &bp)) == NULL) 101212111Sralph LP = DEFDEVLP; 101312111Sralph if ((RP = pgetstr("rp", &bp)) == NULL) 101412463Sralph RP = DEFLP; 101512111Sralph if ((LO = pgetstr("lo", &bp)) == NULL) 101612111Sralph LO = DEFLOCK; 101712111Sralph if ((ST = pgetstr("st", &bp)) == NULL) 101812111Sralph ST = DEFSTAT; 101912111Sralph if ((LF = pgetstr("lf", &bp)) == NULL) 102012111Sralph LF = DEFLOGF; 102112111Sralph if ((SD = pgetstr("sd", &bp)) == NULL) 102212111Sralph SD = DEFSPOOL; 102312111Sralph if ((DU = pgetnum("du")) < 0) 102412111Sralph DU = DEFUID; 102512111Sralph if ((FF = pgetstr("ff", &bp)) == NULL) 102612111Sralph FF = DEFFF; 102712111Sralph if ((PW = pgetnum("pw")) < 0) 102812111Sralph PW = DEFWIDTH; 102912111Sralph sprintf(&width[2], "%d", PW); 103012111Sralph if ((PL = pgetnum("pl")) < 0) 103112111Sralph PL = DEFLENGTH; 103212111Sralph sprintf(&length[2], "%d", PL); 103312463Sralph if ((PX = pgetnum("px")) < 0) 103412463Sralph PX = 0; 103512463Sralph sprintf(&pxwidth[2], "%d", PX); 103612463Sralph if ((PY = pgetnum("py")) < 0) 103712463Sralph PY = 0; 103812463Sralph sprintf(&pxlength[2], "%d", PY); 103912111Sralph RM = pgetstr("rm", &bp); 104012111Sralph AF = pgetstr("af", &bp); 104112111Sralph OF = pgetstr("of", &bp); 104212111Sralph IF = pgetstr("if", &bp); 104312463Sralph RF = pgetstr("rf", &bp); 104412111Sralph TF = pgetstr("tf", &bp); 104513233Sralph NF = pgetstr("nf", &bp); 104612111Sralph DF = pgetstr("df", &bp); 104712111Sralph GF = pgetstr("gf", &bp); 104812111Sralph VF = pgetstr("vf", &bp); 104912111Sralph CF = pgetstr("cf", &bp); 105012111Sralph TR = pgetstr("tr", &bp); 105112463Sralph RS = pgetflag("rs"); 105212111Sralph SF = pgetflag("sf"); 105312111Sralph SH = pgetflag("sh"); 105412111Sralph SB = pgetflag("sb"); 105518127Sralph HL = pgetflag("hl"); 105612111Sralph RW = pgetflag("rw"); 105712111Sralph BR = pgetnum("br"); 105812111Sralph if ((FC = pgetnum("fc")) < 0) 105912111Sralph FC = 0; 106012111Sralph if ((FS = pgetnum("fs")) < 0) 106112111Sralph FS = 0; 106212111Sralph if ((XC = pgetnum("xc")) < 0) 106312111Sralph XC = 0; 106412111Sralph if ((XS = pgetnum("xs")) < 0) 106512111Sralph XS = 0; 106612581Sralph tof = !pgetflag("fo"); 106712111Sralph } 106812111Sralph 106912463Sralph /* 107012463Sralph * Acquire line printer or remote connection. 107112463Sralph */ 107212463Sralph openpr() 107312463Sralph { 107412463Sralph register int i, n; 107516762Sralph int resp; 107612463Sralph 107712463Sralph if (*LP) { 107812463Sralph for (i = 1; ; i = i < 32 ? i << 1 : i) { 107913148Ssam pfd = open(LP, RW ? O_RDWR : O_WRONLY); 108012463Sralph if (pfd >= 0) 108112463Sralph break; 108212463Sralph if (errno == ENOENT) { 108316762Sralph syslog(LOG_ERR, "%s: %m", LP); 108412463Sralph exit(1); 108512463Sralph } 108612463Sralph if (i == 1) 108712463Sralph status("waiting for %s to become ready (offline ?)", printer); 108812463Sralph sleep(i); 108912463Sralph } 109012463Sralph if (isatty(pfd)) 109112463Sralph setty(); 109212463Sralph status("%s is ready and printing", printer); 109312463Sralph } else if (RM != NULL) { 109416762Sralph for (i = 1; ; i = i < 256 ? i << 1 : i) { 109516762Sralph resp = -1; 109612528Sralph pfd = getport(RM); 109712463Sralph if (pfd >= 0) { 109812463Sralph (void) sprintf(line, "\2%s\n", RP); 109912463Sralph n = strlen(line); 110016762Sralph if (write(pfd, line, n) == n && 110116762Sralph (resp = response()) == '\0') 110212463Sralph break; 110316031Sralph (void) close(pfd); 110412463Sralph } 110516031Sralph if (i == 1) { 110616762Sralph if (resp < 0) 110716031Sralph status("waiting for %s to come up", RM); 110816762Sralph else { 110916031Sralph status("waiting for queue to be enabled on %s", RM); 111016762Sralph i = 256; 111116762Sralph } 111216031Sralph } 111312463Sralph sleep(i); 111412463Sralph } 111512463Sralph status("sending to %s", RM); 111612463Sralph remote = 1; 111712463Sralph } else { 111816762Sralph syslog(LOG_ERR, "%s: no line printer device or host name", 111916762Sralph printer); 112012463Sralph exit(1); 112112463Sralph } 112212463Sralph /* 112312463Sralph * Start up an output filter, if needed. 112412463Sralph */ 112512463Sralph if (OF) { 112612463Sralph int p[2]; 112712463Sralph char *cp; 112812463Sralph 112912463Sralph pipe(p); 113012463Sralph if ((ofilter = dofork(DOABORT)) == 0) { /* child */ 113112463Sralph dup2(p[0], 0); /* pipe is std in */ 113212463Sralph dup2(pfd, 1); /* printer is std out */ 113312463Sralph for (i = 3; i < NOFILE; i++) 113412463Sralph (void) close(i); 113512463Sralph if ((cp = rindex(OF, '/')) == NULL) 113612463Sralph cp = OF; 113712463Sralph else 113812463Sralph cp++; 113912463Sralph execl(OF, cp, width, length, 0); 114016762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, OF); 114112463Sralph exit(1); 114212463Sralph } 114312463Sralph (void) close(p[0]); /* close input side */ 114412463Sralph ofd = p[1]; /* use pipe for output */ 114512463Sralph } else { 114612463Sralph ofd = pfd; 114712463Sralph ofilter = 0; 114812463Sralph } 114912463Sralph } 115012463Sralph 115112111Sralph struct bauds { 115212111Sralph int baud; 115312111Sralph int speed; 115412111Sralph } bauds[] = { 115512111Sralph 50, B50, 115612111Sralph 75, B75, 115712111Sralph 110, B110, 115812111Sralph 134, B134, 115912111Sralph 150, B150, 116012111Sralph 200, B200, 116112111Sralph 300, B300, 116212111Sralph 600, B600, 116312111Sralph 1200, B1200, 116412111Sralph 1800, B1800, 116512111Sralph 2400, B2400, 116612111Sralph 4800, B4800, 116712111Sralph 9600, B9600, 116812111Sralph 19200, EXTA, 116912111Sralph 38400, EXTB, 117012111Sralph 0, 0 117112111Sralph }; 117212111Sralph 117312111Sralph /* 117412111Sralph * setup tty lines. 117512111Sralph */ 117612111Sralph setty() 117712111Sralph { 117812111Sralph struct sgttyb ttybuf; 117912111Sralph register struct bauds *bp; 118012111Sralph 118112111Sralph if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) { 118216762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer); 118312111Sralph exit(1); 118412111Sralph } 118512111Sralph if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) { 118616762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCGETP): %m", printer); 118712111Sralph exit(1); 118812111Sralph } 118912111Sralph if (BR > 0) { 119012111Sralph for (bp = bauds; bp->baud; bp++) 119112111Sralph if (BR == bp->baud) 119212111Sralph break; 119312111Sralph if (!bp->baud) { 119416762Sralph syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR); 119512111Sralph exit(1); 119612111Sralph } 119712111Sralph ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed; 119812111Sralph } 119913169Sralph ttybuf.sg_flags &= ~FC; 120013169Sralph ttybuf.sg_flags |= FS; 120112111Sralph if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) { 120216762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCSETP): %m", printer); 120312111Sralph exit(1); 120412111Sralph } 120517168Sralph if (XC || XS) { 120617168Sralph int ldisc = NTTYDISC; 120717168Sralph 120817168Sralph if (ioctl(pfd, TIOCSETD, &ldisc) < 0) { 120917168Sralph syslog(LOG_ERR, "%s: ioctl(TIOCSETD): %m", printer); 121017168Sralph exit(1); 121117168Sralph } 121217168Sralph } 121312111Sralph if (XC) { 121412111Sralph if (ioctl(pfd, TIOCLBIC, &XC) < 0) { 121516762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCLBIC): %m", printer); 121612111Sralph exit(1); 121712111Sralph } 121812111Sralph } 121912111Sralph if (XS) { 122012111Sralph if (ioctl(pfd, TIOCLBIS, &XS) < 0) { 122116762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCLBIS): %m", printer); 122212111Sralph exit(1); 122312111Sralph } 122412111Sralph } 122512111Sralph } 122612463Sralph 122712463Sralph /*VARARGS1*/ 122812463Sralph status(msg, a1, a2, a3) 122912463Sralph char *msg; 123012463Sralph { 123112463Sralph register int fd; 123212463Sralph char buf[BUFSIZ]; 123312463Sralph 123412463Sralph umask(0); 123513148Ssam fd = open(ST, O_WRONLY|O_CREAT, 0664); 123616762Sralph if (fd < 0 || flock(fd, LOCK_EX) < 0) { 123716762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, ST); 123816762Sralph exit(1); 123916762Sralph } 124013148Ssam ftruncate(fd, 0); 124112463Sralph sprintf(buf, msg, a1, a2, a3); 124212463Sralph strcat(buf, "\n"); 124312463Sralph (void) write(fd, buf, strlen(buf)); 124412463Sralph (void) close(fd); 124512463Sralph } 1246