122437Sdist /* 222437Sdist * Copyright (c) 1983 Regents of the University of California. 322437Sdist * All rights reserved. The Berkeley software License Agreement 422437Sdist * specifies the terms and conditions for redistribution. 522437Sdist */ 622437Sdist 713954Ssam #ifndef lint 825468Stef static char sccsid[] = "@(#)printjob.c 5.2 (Berkeley) 9/17/85"; 922437Sdist #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 */ 71*25496Seric (void) close(2); /* set up log file */ 72*25496Seric if (open(LF, O_WRONLY|O_APPEND, 0664) < 0) { 73*25496Seric syslog(LOG_ERR, "%s: %m", LF); 74*25496Seric (void) open("/dev/null", O_WRONLY); 75*25496Seric } 7616762Sralph setgid(getegid()); 7712463Sralph pid = getpid(); /* for use with lprm */ 7812111Sralph setpgrp(0, pid); 7916762Sralph signal(SIGHUP, abortpr); 8016762Sralph signal(SIGINT, abortpr); 8116762Sralph signal(SIGQUIT, abortpr); 8216762Sralph signal(SIGTERM, abortpr); 8312111Sralph 8415811Sralph (void) mktemp(tmpfile); 8515811Sralph 8612111Sralph /* 8712111Sralph * uses short form file names 8812111Sralph */ 8912111Sralph if (chdir(SD) < 0) { 9016762Sralph syslog(LOG_ERR, "%s: %m", SD); 9112111Sralph exit(1); 9212111Sralph } 9312463Sralph if (stat(LO, &stb) == 0 && (stb.st_mode & 0100)) 9412463Sralph exit(0); /* printing disabled */ 9514150Sralph lfd = open(LO, O_WRONLY|O_CREAT, 0644); 9613169Sralph if (lfd < 0) { 9716762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, LO); 9813169Sralph exit(1); 9913169Sralph } 10013169Sralph if (flock(lfd, LOCK_EX|LOCK_NB) < 0) { 10112111Sralph if (errno == EWOULDBLOCK) /* active deamon present */ 10212111Sralph exit(0); 10316762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, LO); 10412111Sralph exit(1); 10512111Sralph } 10613148Ssam ftruncate(lfd, 0); 10712111Sralph /* 10812111Sralph * write process id for others to know 10912111Sralph */ 11012111Sralph sprintf(line, "%u\n", pid); 11112111Sralph pidoff = i = strlen(line); 11212463Sralph if (write(lfd, line, i) != i) { 11316762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, LO); 11412111Sralph exit(1); 11512111Sralph } 11612111Sralph /* 11712111Sralph * search the spool directory for work and sort by queue order. 11812111Sralph */ 11912111Sralph if ((nitems = getq(&queue)) < 0) { 12016762Sralph syslog(LOG_ERR, "%s: can't scan %s", printer, SD); 12112111Sralph exit(1); 12212111Sralph } 12312463Sralph if (nitems == 0) /* no work to do */ 12412111Sralph exit(0); 12513169Sralph if (stb.st_mode & 01) { /* reset queue flag */ 12613169Sralph if (fchmod(lfd, stb.st_mode & 0776) < 0) 12716762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, LO); 12813169Sralph } 12912463Sralph openpr(); /* open printer or remote */ 13012463Sralph again: 13112111Sralph /* 13212111Sralph * we found something to do now do it -- 13312111Sralph * write the name of the current control file into the lock file 13412111Sralph * so the spool queue program can tell what we're working on 13512111Sralph */ 13612111Sralph for (qp = queue; nitems--; free((char *) q)) { 13712111Sralph q = *qp++; 13812111Sralph if (stat(q->q_name, &stb) < 0) 13912111Sralph continue; 14012463Sralph restart: 14112111Sralph (void) lseek(lfd, pidoff, 0); 14212111Sralph (void) sprintf(line, "%s\n", q->q_name); 14312111Sralph i = strlen(line); 14412111Sralph if (write(lfd, line, i) != i) 14516762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, LO); 14612111Sralph if (!remote) 14712111Sralph i = printit(q->q_name); 14812111Sralph else 14912111Sralph i = sendit(q->q_name); 15012463Sralph /* 15113169Sralph * Check to see if we are supposed to stop printing or 15213169Sralph * if we are to rebuild the queue. 15312463Sralph */ 15413169Sralph if (fstat(lfd, &stb) == 0) { 15516762Sralph /* stop printing before starting next job? */ 15613169Sralph if (stb.st_mode & 0100) 15713169Sralph goto done; 15816762Sralph /* rebuild queue (after lpc topq) */ 15913169Sralph if (stb.st_mode & 01) { 16013169Sralph for (free((char *) q); nitems--; free((char *) q)) 16113169Sralph q = *qp++; 16213169Sralph if (fchmod(lfd, stb.st_mode & 0776) < 0) 16316762Sralph syslog(LOG_WARNING, "%s: %s: %m", 16416762Sralph printer, LO); 16513169Sralph break; 16613169Sralph } 16713169Sralph } 16817463Sralph if (i == OK) /* file ok and printed */ 16914150Sralph count++; 17017463Sralph else if (i == REPRINT) { /* try reprinting the job */ 17116762Sralph syslog(LOG_INFO, "restarting %s", printer); 17212111Sralph if (ofilter > 0) { 17312111Sralph kill(ofilter, SIGCONT); /* to be sure */ 17412111Sralph (void) close(ofd); 17512111Sralph while ((i = wait(0)) > 0 && i != ofilter) 17612111Sralph ; 17712111Sralph ofilter = 0; 17812111Sralph } 17912463Sralph (void) close(pfd); /* close printer */ 18015811Sralph if (ftruncate(lfd, pidoff) < 0) 18116762Sralph syslog(LOG_WARNING, "%s: %s: %m", printer, LO); 18212463Sralph openpr(); /* try to reopen printer */ 18312111Sralph goto restart; 18412111Sralph } 18512111Sralph } 18612111Sralph free((char *) queue); 18712463Sralph /* 18812463Sralph * search the spool directory for more work. 18912463Sralph */ 19012463Sralph if ((nitems = getq(&queue)) < 0) { 19116762Sralph syslog(LOG_ERR, "%s: can't scan %s", printer, SD); 19212463Sralph exit(1); 19312463Sralph } 19412463Sralph if (nitems == 0) { /* no more work to do */ 19512463Sralph done: 19614150Sralph if (count > 0) { /* Files actually printed */ 19714150Sralph if (!SF && !tof) 19814150Sralph (void) write(ofd, FF, strlen(FF)); 19914150Sralph if (TR != NULL) /* output trailer */ 20014150Sralph (void) write(ofd, TR, strlen(TR)); 20114150Sralph } 20215811Sralph (void) unlink(tmpfile); 20312463Sralph exit(0); 20412463Sralph } 20512111Sralph goto again; 20612111Sralph } 20712111Sralph 20812111Sralph char fonts[4][50]; /* fonts for troff */ 20912111Sralph 21016762Sralph char ifonts[4][18] = { 21112111Sralph "/usr/lib/vfont/R", 21212111Sralph "/usr/lib/vfont/I", 21312111Sralph "/usr/lib/vfont/B", 21412111Sralph "/usr/lib/vfont/S" 21512111Sralph }; 21612111Sralph 21712111Sralph /* 21812111Sralph * The remaining part is the reading of the control file (cf) 21912111Sralph * and performing the various actions. 22012111Sralph */ 22112111Sralph printit(file) 22212111Sralph char *file; 22312111Sralph { 22412111Sralph register int i; 22517463Sralph char *cp; 22617463Sralph int bombed = OK; 22712111Sralph 22812111Sralph /* 22917463Sralph * open control file; ignore if no longer there. 23012111Sralph */ 23112111Sralph if ((cfp = fopen(file, "r")) == NULL) { 23216762Sralph syslog(LOG_INFO, "%s: %s: %m", printer, file); 23317463Sralph return(OK); 23412111Sralph } 23512111Sralph /* 23612111Sralph * Reset troff fonts. 23712111Sralph */ 23812111Sralph for (i = 0; i < 4; i++) 23912111Sralph strcpy(fonts[i], ifonts[i]); 24017339Sralph strcpy(width+2, "0"); 24117302Sralph strcpy(indent+2, "0"); 24212111Sralph 24312111Sralph /* 24412111Sralph * read the control file for work to do 24512111Sralph * 24612111Sralph * file format -- first character in the line is a command 24712111Sralph * rest of the line is the argument. 24812111Sralph * valid commands are: 24912111Sralph * 25017463Sralph * S -- "stat info" for symbolic link protection 25112111Sralph * J -- "job name" on banner page 25212111Sralph * C -- "class name" on banner page 25312111Sralph * L -- "literal" user's name to print on banner 25412111Sralph * T -- "title" for pr 25512111Sralph * H -- "host name" of machine where lpr was done 25612111Sralph * P -- "person" user's login name 25712581Sralph * I -- "indent" amount to indent output 25812111Sralph * f -- "file name" name of text file to print 25912111Sralph * l -- "file name" text file with control chars 26012111Sralph * p -- "file name" text file to print with pr(1) 26112111Sralph * t -- "file name" troff(1) file to print 26213233Sralph * n -- "file name" ditroff(1) file to print 26312111Sralph * d -- "file name" dvi file to print 26412111Sralph * g -- "file name" plot(1G) file to print 26512111Sralph * v -- "file name" plain raster file to print 26612111Sralph * c -- "file name" cifplot file to print 26712111Sralph * 1 -- "R font file" for troff 26812111Sralph * 2 -- "I font file" for troff 26912111Sralph * 3 -- "B font file" for troff 27012111Sralph * 4 -- "S font file" for troff 27112111Sralph * N -- "name" of file (used by lpq) 27212111Sralph * U -- "unlink" name of file to remove 27312111Sralph * (after we print it. (Pass 2 only)). 27412111Sralph * M -- "mail" to user when done printing 27512111Sralph * 27612111Sralph * getline reads a line and expands tabs to blanks 27712111Sralph */ 27812111Sralph 27912111Sralph /* pass 1 */ 28012111Sralph 28112111Sralph while (getline(cfp)) 28212111Sralph switch (line[0]) { 28312111Sralph case 'H': 28414150Sralph strcpy(fromhost, line+1); 28512111Sralph if (class[0] == '\0') 28615552Sralph strncpy(class, line+1, sizeof(class)-1); 28712111Sralph continue; 28812111Sralph 28912111Sralph case 'P': 29015552Sralph strncpy(logname, line+1, sizeof(logname)-1); 29112463Sralph if (RS) { /* restricted */ 29212463Sralph if (getpwnam(logname) == (struct passwd *)0) { 29317463Sralph bombed = NOACCT; 29415811Sralph sendmail(line+1, bombed); 29512463Sralph goto pass2; 29612463Sralph } 29712463Sralph } 29812111Sralph continue; 29912111Sralph 30017463Sralph case 'S': 30117463Sralph cp = line+1; 30217463Sralph i = 0; 30317463Sralph while (*cp >= '0' && *cp <= '9') 30417463Sralph i = i * 10 + (*cp++ - '0'); 30517463Sralph fdev = i; 30617463Sralph cp++; 30717463Sralph i = 0; 30817463Sralph while (*cp >= '0' && *cp <= '9') 30917463Sralph i = i * 10 + (*cp++ - '0'); 31017463Sralph fino = i; 31117463Sralph continue; 31217463Sralph 31312111Sralph case 'J': 31412111Sralph if (line[1] != '\0') 31515552Sralph strncpy(jobname, line+1, sizeof(jobname)-1); 31612111Sralph else 31712111Sralph strcpy(jobname, " "); 31812111Sralph continue; 31912111Sralph 32012111Sralph case 'C': 32112111Sralph if (line[1] != '\0') 32215552Sralph strncpy(class, line+1, sizeof(class)-1); 32312111Sralph else if (class[0] == '\0') 32415811Sralph gethostname(class, sizeof(class)); 32512111Sralph continue; 32612111Sralph 32712111Sralph case 'T': /* header title for pr */ 32815552Sralph strncpy(title, line+1, sizeof(title)-1); 32912111Sralph continue; 33012111Sralph 33112111Sralph case 'L': /* identification line */ 33218127Sralph if (!SH && !HL) 33312111Sralph banner(line+1, jobname); 33412111Sralph continue; 33512111Sralph 33612111Sralph case '1': /* troff fonts */ 33712111Sralph case '2': 33812111Sralph case '3': 33912111Sralph case '4': 34012111Sralph if (line[1] != '\0') 34112111Sralph strcpy(fonts[line[0]-'1'], line+1); 34212111Sralph continue; 34312111Sralph 34412111Sralph case 'W': /* page width */ 34515552Sralph strncpy(width+2, line+1, sizeof(width)-3); 34612111Sralph continue; 34712111Sralph 34812581Sralph case 'I': /* indent amount */ 34915552Sralph strncpy(indent+2, line+1, sizeof(indent)-3); 35012581Sralph continue; 35112581Sralph 35212111Sralph default: /* some file to print */ 35315811Sralph switch (i = print(line[0], line+1)) { 35417463Sralph case ERROR: 35517463Sralph if (bombed == OK) 35617463Sralph bombed = FATALERR; 35715811Sralph break; 35817463Sralph case REPRINT: 35912111Sralph (void) fclose(cfp); 36017463Sralph return(REPRINT); 36117463Sralph case FILTERERR: 36217463Sralph case ACCESS: 36317463Sralph bombed = i; 36415811Sralph sendmail(logname, bombed); 36515811Sralph } 36612111Sralph title[0] = '\0'; 36712111Sralph continue; 36812111Sralph 36912111Sralph case 'N': 37012111Sralph case 'U': 37112111Sralph case 'M': 37212111Sralph continue; 37312111Sralph } 37412111Sralph 37512111Sralph /* pass 2 */ 37612111Sralph 37712463Sralph pass2: 37812111Sralph fseek(cfp, 0L, 0); 37912111Sralph while (getline(cfp)) 38012111Sralph switch (line[0]) { 38118127Sralph case 'L': /* identification line */ 38218127Sralph if (!SH && HL) 38318127Sralph banner(line+1, jobname); 38418127Sralph continue; 38518127Sralph 38612111Sralph case 'M': 38717463Sralph if (bombed < NOACCT) /* already sent if >= NOACCT */ 38815811Sralph sendmail(line+1, bombed); 38912111Sralph continue; 39012111Sralph 39112111Sralph case 'U': 39212111Sralph (void) unlink(line+1); 39312111Sralph } 39412111Sralph /* 39515811Sralph * clean-up in case another control file exists 39612111Sralph */ 39712111Sralph (void) fclose(cfp); 39812111Sralph (void) unlink(file); 39917463Sralph return(bombed == OK ? OK : ERROR); 40012111Sralph } 40112111Sralph 40212111Sralph /* 40312111Sralph * Print a file. 40413233Sralph * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}. 40515811Sralph * Return -1 if a non-recoverable error occured, 40615811Sralph * 2 if the filter detected some errors (but printed the job anyway), 40715811Sralph * 1 if we should try to reprint this job and 40812111Sralph * 0 if all is well. 40912111Sralph * Note: all filters take stdin as the file, stdout as the printer, 41012111Sralph * stderr as the log file, and must not ignore SIGINT. 41112111Sralph */ 41212111Sralph print(format, file) 41312111Sralph int format; 41412111Sralph char *file; 41512111Sralph { 41615811Sralph register int n; 41712111Sralph register char *prog; 41815811Sralph int fi, fo; 41912111Sralph char *av[15], buf[BUFSIZ]; 42012111Sralph int pid, p[2], stopped = 0; 42112111Sralph union wait status; 42217463Sralph struct stat stb; 42312111Sralph 42417463Sralph if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0) 42517463Sralph return(ERROR); 42617463Sralph /* 42717463Sralph * Check to see if data file is a symbolic link. If so, it should 42817463Sralph * still point to the same file or someone is trying to print 42917463Sralph * something he shouldn't. 43017463Sralph */ 43117463Sralph if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 && 43217463Sralph (stb.st_dev != fdev || stb.st_ino != fino)) 43317463Sralph return(ACCESS); 43412111Sralph if (!SF && !tof) { /* start on a fresh page */ 43512111Sralph (void) write(ofd, FF, strlen(FF)); 43612111Sralph tof = 1; 43712111Sralph } 43812111Sralph if (IF == NULL && (format == 'f' || format == 'l')) { 43912111Sralph tof = 0; 44012111Sralph while ((n = read(fi, buf, BUFSIZ)) > 0) 44112111Sralph if (write(ofd, buf, n) != n) { 44212111Sralph (void) close(fi); 44317463Sralph return(REPRINT); 44412111Sralph } 44512111Sralph (void) close(fi); 44617463Sralph return(OK); 44712111Sralph } 44812111Sralph switch (format) { 44912111Sralph case 'p': /* print file using 'pr' */ 45012111Sralph if (IF == NULL) { /* use output filter */ 45112111Sralph prog = PR; 45212111Sralph av[0] = "pr"; 45312111Sralph av[1] = width; 45412111Sralph av[2] = length; 45512111Sralph av[3] = "-h"; 45612111Sralph av[4] = *title ? title : " "; 45712111Sralph av[5] = 0; 45812111Sralph fo = ofd; 45912111Sralph goto start; 46012111Sralph } 46112111Sralph pipe(p); 46212111Sralph if ((prchild = dofork(DORETURN)) == 0) { /* child */ 46312111Sralph dup2(fi, 0); /* file is stdin */ 46412111Sralph dup2(p[1], 1); /* pipe is stdout */ 46512111Sralph for (n = 3; n < NOFILE; n++) 46612111Sralph (void) close(n); 46712111Sralph execl(PR, "pr", width, length, "-h", *title ? title : " ", 0); 46816762Sralph syslog(LOG_ERR, "cannot execl %s", PR); 46912111Sralph exit(2); 47012111Sralph } 47112111Sralph (void) close(p[1]); /* close output side */ 47212111Sralph (void) close(fi); 47312111Sralph if (prchild < 0) { 47412111Sralph prchild = 0; 47512111Sralph (void) close(p[0]); 47617463Sralph return(ERROR); 47712111Sralph } 47812111Sralph fi = p[0]; /* use pipe for input */ 47912111Sralph case 'f': /* print plain text file */ 48012111Sralph prog = IF; 48112111Sralph av[1] = width; 48212111Sralph av[2] = length; 48312581Sralph av[3] = indent; 48412581Sralph n = 4; 48512111Sralph break; 48612111Sralph case 'l': /* like 'f' but pass control characters */ 48712111Sralph prog = IF; 48814325Sralph av[1] = "-c"; 48912111Sralph av[2] = width; 49012111Sralph av[3] = length; 49112581Sralph av[4] = indent; 49212581Sralph n = 5; 49312111Sralph break; 49412463Sralph case 'r': /* print a fortran text file */ 49512463Sralph prog = RF; 49612463Sralph av[1] = width; 49712463Sralph av[2] = length; 49812463Sralph n = 3; 49912463Sralph break; 50012111Sralph case 't': /* print troff output */ 50113233Sralph case 'n': /* print ditroff output */ 50212463Sralph case 'd': /* print tex output */ 50312111Sralph (void) unlink(".railmag"); 50412463Sralph if ((fo = creat(".railmag", FILMOD)) < 0) { 50516762Sralph syslog(LOG_ERR, "%s: cannot create .railmag", printer); 50612111Sralph (void) unlink(".railmag"); 50712111Sralph } else { 50812111Sralph for (n = 0; n < 4; n++) { 50912111Sralph if (fonts[n][0] != '/') 51012111Sralph (void) write(fo, "/usr/lib/vfont/", 15); 51112111Sralph (void) write(fo, fonts[n], strlen(fonts[n])); 51212111Sralph (void) write(fo, "\n", 1); 51312111Sralph } 51412111Sralph (void) close(fo); 51512111Sralph } 51613233Sralph prog = (format == 't') ? TF : (format == 'n') ? NF : DF; 51712463Sralph av[1] = pxwidth; 51812463Sralph av[2] = pxlength; 51912463Sralph n = 3; 52012111Sralph break; 52112111Sralph case 'c': /* print cifplot output */ 52212111Sralph prog = CF; 52312463Sralph av[1] = pxwidth; 52412463Sralph av[2] = pxlength; 52512463Sralph n = 3; 52612111Sralph break; 52712111Sralph case 'g': /* print plot(1G) output */ 52812111Sralph prog = GF; 52912463Sralph av[1] = pxwidth; 53012463Sralph av[2] = pxlength; 53112463Sralph n = 3; 53212111Sralph break; 53312111Sralph case 'v': /* print raster output */ 53412111Sralph prog = VF; 53512463Sralph av[1] = pxwidth; 53612463Sralph av[2] = pxlength; 53712463Sralph n = 3; 53812111Sralph break; 53912111Sralph default: 54012111Sralph (void) close(fi); 54116762Sralph syslog(LOG_ERR, "%s: illegal format character '%c'", 54216762Sralph printer, format); 54317463Sralph return(ERROR); 54412111Sralph } 54512111Sralph if ((av[0] = rindex(prog, '/')) != NULL) 54612111Sralph av[0]++; 54712111Sralph else 54812111Sralph av[0] = prog; 54912111Sralph av[n++] = "-n"; 55012111Sralph av[n++] = logname; 55112111Sralph av[n++] = "-h"; 55214150Sralph av[n++] = fromhost; 55312111Sralph av[n++] = AF; 55412111Sralph av[n] = 0; 55512111Sralph fo = pfd; 55612111Sralph if (ofilter > 0) { /* stop output filter */ 55712111Sralph write(ofd, "\031\1", 2); 55812111Sralph while ((pid = wait3(&status, WUNTRACED, 0)) > 0 && pid != ofilter) 55912111Sralph ; 56012111Sralph if (status.w_stopval != WSTOPPED) { 56112111Sralph (void) close(fi); 56216762Sralph syslog(LOG_WARNING, "%s: output filter died (%d)", 56316762Sralph printer, status.w_retcode); 56417463Sralph return(REPRINT); 56512111Sralph } 56612111Sralph stopped++; 56712111Sralph } 56812111Sralph start: 56912111Sralph if ((child = dofork(DORETURN)) == 0) { /* child */ 57012111Sralph dup2(fi, 0); 57112111Sralph dup2(fo, 1); 57217304Sralph n = open(tmpfile, O_WRONLY|O_CREAT|O_TRUNC, 0664); 57315811Sralph if (n >= 0) 57415811Sralph dup2(n, 2); 57512111Sralph for (n = 3; n < NOFILE; n++) 57612111Sralph (void) close(n); 57712111Sralph execv(prog, av); 57816762Sralph syslog(LOG_ERR, "cannot execv %s", prog); 57912111Sralph exit(2); 58012111Sralph } 58112111Sralph (void) close(fi); 58212111Sralph if (child < 0) 58312111Sralph status.w_retcode = 100; 58412111Sralph else 58512111Sralph while ((pid = wait(&status)) > 0 && pid != child) 58612111Sralph ; 58712111Sralph child = 0; 58812111Sralph prchild = 0; 58912111Sralph if (stopped) { /* restart output filter */ 59012111Sralph if (kill(ofilter, SIGCONT) < 0) { 59116762Sralph syslog(LOG_ERR, "cannot restart output filter"); 59212111Sralph exit(1); 59312111Sralph } 59412111Sralph } 59512111Sralph tof = 0; 59615811Sralph if (!WIFEXITED(status)) { 59716762Sralph syslog(LOG_WARNING, "%s: Daemon filter '%c' terminated (%d)", 59816762Sralph printer, format, status.w_termsig); 59917463Sralph return(ERROR); 60017463Sralph } 60117463Sralph switch (status.w_retcode) { 60217463Sralph case 0: 60317463Sralph tof = 1; 60417463Sralph return(OK); 60517463Sralph case 1: 60617463Sralph return(REPRINT); 60717463Sralph default: 60816762Sralph syslog(LOG_WARNING, "%s: Daemon filter '%c' exited (%d)", 60916762Sralph printer, format, status.w_retcode); 61017463Sralph case 2: 61117463Sralph return(ERROR); 61217463Sralph } 61312111Sralph } 61412111Sralph 61512111Sralph /* 61612111Sralph * Send the daemon control file (cf) and any data files. 61712111Sralph * Return -1 if a non-recoverable error occured, 1 if a recoverable error and 61812111Sralph * 0 if all is well. 61912111Sralph */ 62012111Sralph sendit(file) 62112111Sralph char *file; 62212111Sralph { 62317463Sralph register int i, err = OK; 62417463Sralph char *cp, last[BUFSIZ]; 62512111Sralph 62612111Sralph /* 62712111Sralph * open control file 62812111Sralph */ 62916762Sralph if ((cfp = fopen(file, "r")) == NULL) 63017463Sralph return(OK); 63112111Sralph /* 63212111Sralph * read the control file for work to do 63312111Sralph * 63412111Sralph * file format -- first character in the line is a command 63512111Sralph * rest of the line is the argument. 63612111Sralph * commands of interest are: 63712111Sralph * 63812111Sralph * a-z -- "file name" name of file to print 63912111Sralph * U -- "unlink" name of file to remove 64012111Sralph * (after we print it. (Pass 2 only)). 64112111Sralph */ 64212111Sralph 64312111Sralph /* 64412111Sralph * pass 1 64512111Sralph */ 64612111Sralph while (getline(cfp)) { 64712111Sralph again: 64817463Sralph if (line[0] == 'S') { 64917463Sralph cp = line+1; 65017463Sralph i = 0; 65117463Sralph while (*cp >= '0' && *cp <= '9') 65217463Sralph i = i * 10 + (*cp++ - '0'); 65317463Sralph fdev = i; 65417463Sralph cp++; 65517463Sralph i = 0; 65617463Sralph while (*cp >= '0' && *cp <= '9') 65717463Sralph i = i * 10 + (*cp++ - '0'); 65817463Sralph fino = i; 65917463Sralph continue; 66017463Sralph } 66112111Sralph if (line[0] >= 'a' && line[0] <= 'z') { 66212111Sralph strcpy(last, line); 66317463Sralph while (i = getline(cfp)) 66412111Sralph if (strcmp(last, line)) 66512111Sralph break; 66617463Sralph switch (sendfile('\3', last+1)) { 66717463Sralph case OK: 66817463Sralph if (i) 66917463Sralph goto again; 67017463Sralph break; 67117463Sralph case REPRINT: 67212111Sralph (void) fclose(cfp); 67317463Sralph return(REPRINT); 67417463Sralph case ACCESS: 67517463Sralph sendmail(logname, ACCESS); 67617463Sralph case ERROR: 67717463Sralph err = ERROR; 67817463Sralph } 67912111Sralph break; 68012111Sralph } 68112111Sralph } 68217463Sralph if (err == OK && sendfile('\2', file) > 0) { 68312111Sralph (void) fclose(cfp); 68417463Sralph return(REPRINT); 68512111Sralph } 68612111Sralph /* 68712111Sralph * pass 2 68812111Sralph */ 68912111Sralph fseek(cfp, 0L, 0); 69012111Sralph while (getline(cfp)) 69112111Sralph if (line[0] == 'U') 69212111Sralph (void) unlink(line+1); 69312111Sralph /* 69417463Sralph * clean-up in case another control file exists 69512111Sralph */ 69612111Sralph (void) fclose(cfp); 69712111Sralph (void) unlink(file); 69817463Sralph return(err); 69912111Sralph } 70012111Sralph 70112111Sralph /* 70212111Sralph * Send a data file to the remote machine and spool it. 70312111Sralph * Return positive if we should try resending. 70412111Sralph */ 70512111Sralph sendfile(type, file) 70612111Sralph char type, *file; 70712111Sralph { 70812111Sralph register int f, i, amt; 70912111Sralph struct stat stb; 71012111Sralph char buf[BUFSIZ]; 71116762Sralph int sizerr, resp; 71212111Sralph 71317463Sralph if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0) 71417463Sralph return(ERROR); 71517463Sralph /* 71617463Sralph * Check to see if data file is a symbolic link. If so, it should 71717463Sralph * still point to the same file or someone is trying to print something 71817463Sralph * he shouldn't. 71917463Sralph */ 72017463Sralph if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 && 72117463Sralph (stb.st_dev != fdev || stb.st_ino != fino)) 72217463Sralph return(ACCESS); 72312111Sralph (void) sprintf(buf, "%c%d %s\n", type, stb.st_size, file); 72412111Sralph amt = strlen(buf); 72516762Sralph for (i = 0; ; i++) { 72616762Sralph if (write(pfd, buf, amt) != amt || 72716762Sralph (resp = response()) < 0 || resp == '\1') { 72816762Sralph (void) close(f); 72917463Sralph return(REPRINT); 73016762Sralph } else if (resp == '\0') 73116762Sralph break; 73216762Sralph if (i == 0) 73316762Sralph status("no space on remote; waiting for queue to drain"); 73416762Sralph if (i == 10) 73524861Seric syslog(LOG_ALERT, "%s: can't send to %s; queue full", 73616762Sralph printer, RM); 73716762Sralph sleep(5 * 60); 73812692Sralph } 73916762Sralph if (i) 74016762Sralph status("sending to %s", RM); 74112111Sralph sizerr = 0; 74212111Sralph for (i = 0; i < stb.st_size; i += BUFSIZ) { 74312111Sralph amt = BUFSIZ; 74412111Sralph if (i + amt > stb.st_size) 74512111Sralph amt = stb.st_size - i; 74612111Sralph if (sizerr == 0 && read(f, buf, amt) != amt) 74712111Sralph sizerr = 1; 74812692Sralph if (write(pfd, buf, amt) != amt) { 74912692Sralph (void) close(f); 75017463Sralph return(REPRINT); 75112692Sralph } 75212111Sralph } 75312111Sralph (void) close(f); 75412111Sralph if (sizerr) { 75516762Sralph syslog(LOG_INFO, "%s: %s: changed size", printer, file); 75617463Sralph /* tell recvjob to ignore this file */ 75717463Sralph (void) write(pfd, "\1", 1); 75817463Sralph return(ERROR); 75917463Sralph } 76017463Sralph if (write(pfd, "", 1) != 1 || response()) 76117463Sralph return(REPRINT); 76217463Sralph return(OK); 76312111Sralph } 76412111Sralph 76512111Sralph /* 76612111Sralph * Check to make sure there have been no errors and that both programs 76712111Sralph * are in sync with eachother. 76812111Sralph * Return non-zero if the connection was lost. 76912111Sralph */ 77016762Sralph response() 77112111Sralph { 77212111Sralph char resp; 77312111Sralph 77416762Sralph if (read(pfd, &resp, 1) != 1) { 77516762Sralph syslog(LOG_INFO, "%s: lost connection", printer); 77616762Sralph return(-1); 77712111Sralph } 77816762Sralph return(resp); 77912111Sralph } 78012111Sralph 78112111Sralph /* 78212111Sralph * Banner printing stuff 78312111Sralph */ 78412111Sralph banner(name1, name2) 78512111Sralph char *name1, *name2; 78612111Sralph { 78712111Sralph time_t tvec; 78812111Sralph extern char *ctime(); 78912111Sralph 79012111Sralph time(&tvec); 79112111Sralph if (!SF && !tof) 79212111Sralph (void) write(ofd, FF, strlen(FF)); 79312111Sralph if (SB) { /* short banner only */ 79412111Sralph if (class[0]) { 79512111Sralph (void) write(ofd, class, strlen(class)); 79612111Sralph (void) write(ofd, ":", 1); 79712111Sralph } 79812111Sralph (void) write(ofd, name1, strlen(name1)); 79912111Sralph (void) write(ofd, " Job: ", 7); 80012111Sralph (void) write(ofd, name2, strlen(name2)); 80112111Sralph (void) write(ofd, " Date: ", 8); 80212111Sralph (void) write(ofd, ctime(&tvec), 24); 80312111Sralph (void) write(ofd, "\n", 1); 80412111Sralph } else { /* normal banner */ 80512111Sralph (void) write(ofd, "\n\n\n", 3); 80612111Sralph scan_out(ofd, name1, '\0'); 80712111Sralph (void) write(ofd, "\n\n", 2); 80812111Sralph scan_out(ofd, name2, '\0'); 80912111Sralph if (class[0]) { 81012111Sralph (void) write(ofd,"\n\n\n",3); 81112111Sralph scan_out(ofd, class, '\0'); 81212111Sralph } 81312111Sralph (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15); 81412111Sralph (void) write(ofd, name2, strlen(name2)); 81512111Sralph (void) write(ofd, "\n\t\t\t\t\tDate: ", 12); 81612111Sralph (void) write(ofd, ctime(&tvec), 24); 81712111Sralph (void) write(ofd, "\n", 1); 81812111Sralph } 81912111Sralph if (!SF) 82012111Sralph (void) write(ofd, FF, strlen(FF)); 82112111Sralph tof = 1; 82212111Sralph } 82312111Sralph 82416762Sralph char * 82512111Sralph scnline(key, p, c) 82612111Sralph register char key, *p; 82712111Sralph char c; 82812111Sralph { 82912111Sralph register scnwidth; 83012111Sralph 83112111Sralph for (scnwidth = WIDTH; --scnwidth;) { 83212111Sralph key <<= 1; 83312111Sralph *p++ = key & 0200 ? c : BACKGND; 83412111Sralph } 83512111Sralph return (p); 83612111Sralph } 83712111Sralph 83812111Sralph #define TRC(q) (((q)-' ')&0177) 83912111Sralph 84012111Sralph scan_out(scfd, scsp, dlm) 84112111Sralph int scfd; 84212111Sralph char *scsp, dlm; 84312111Sralph { 84412111Sralph register char *strp; 84512111Sralph register nchrs, j; 84612111Sralph char outbuf[LINELEN+1], *sp, c, cc; 84712111Sralph int d, scnhgt; 84812111Sralph extern char scnkey[][HEIGHT]; /* in lpdchar.c */ 84912111Sralph 85012111Sralph for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) { 85112111Sralph strp = &outbuf[0]; 85212111Sralph sp = scsp; 85312111Sralph for (nchrs = 0; ; ) { 85412111Sralph d = dropit(c = TRC(cc = *sp++)); 85512111Sralph if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d)) 85612111Sralph for (j = WIDTH; --j;) 85712111Sralph *strp++ = BACKGND; 85812111Sralph else 85912111Sralph strp = scnline(scnkey[c][scnhgt-1-d], strp, cc); 86012111Sralph if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1) 86112111Sralph break; 86212111Sralph *strp++ = BACKGND; 86312111Sralph *strp++ = BACKGND; 86412111Sralph } 86512111Sralph while (*--strp == BACKGND && strp >= outbuf) 86612111Sralph ; 86712111Sralph strp++; 86812111Sralph *strp++ = '\n'; 86912111Sralph (void) write(scfd, outbuf, strp-outbuf); 87012111Sralph } 87112111Sralph } 87212111Sralph 87312111Sralph dropit(c) 87412111Sralph char c; 87512111Sralph { 87612111Sralph switch(c) { 87712111Sralph 87812111Sralph case TRC('_'): 87912111Sralph case TRC(';'): 88012111Sralph case TRC(','): 88112111Sralph case TRC('g'): 88212111Sralph case TRC('j'): 88312111Sralph case TRC('p'): 88412111Sralph case TRC('q'): 88512111Sralph case TRC('y'): 88612111Sralph return (DROP); 88712111Sralph 88812111Sralph default: 88912111Sralph return (0); 89012111Sralph } 89112111Sralph } 89212111Sralph 89312111Sralph /* 89412111Sralph * sendmail --- 89512111Sralph * tell people about job completion 89612111Sralph */ 89715811Sralph sendmail(user, bombed) 89815811Sralph char *user; 89912111Sralph int bombed; 90012111Sralph { 90112111Sralph register int i; 90215811Sralph int p[2], s; 90312111Sralph register char *cp; 90412111Sralph char buf[100]; 90515811Sralph struct stat stb; 90615811Sralph FILE *fp; 90712111Sralph 90812111Sralph pipe(p); 90915811Sralph if ((s = dofork(DORETURN)) == 0) { /* child */ 91012111Sralph dup2(p[0], 0); 91112111Sralph for (i = 3; i < NOFILE; i++) 91212111Sralph (void) close(i); 91312111Sralph if ((cp = rindex(MAIL, '/')) != NULL) 91412111Sralph cp++; 91512111Sralph else 91612111Sralph cp = MAIL; 91715811Sralph sprintf(buf, "%s@%s", user, fromhost); 91812111Sralph execl(MAIL, cp, buf, 0); 91912111Sralph exit(0); 92015811Sralph } else if (s > 0) { /* parent */ 92112111Sralph dup2(p[1], 1); 92215811Sralph printf("To: %s@%s\n", user, fromhost); 92312111Sralph printf("Subject: printer job\n\n"); 92412111Sralph printf("Your printer job "); 92512111Sralph if (*jobname) 92612111Sralph printf("(%s) ", jobname); 92712463Sralph switch (bombed) { 92817463Sralph case OK: 92912463Sralph printf("\ncompleted successfully\n"); 93012463Sralph break; 93112463Sralph default: 93217463Sralph case FATALERR: 93312463Sralph printf("\ncould not be printed\n"); 93412463Sralph break; 93517463Sralph case NOACCT: 93612463Sralph printf("\ncould not be printed without an account on %s\n", host); 93712463Sralph break; 93817463Sralph case FILTERERR: 93915811Sralph if (stat(tmpfile, &stb) < 0 || stb.st_size == 0 || 94015811Sralph (fp = fopen(tmpfile, "r")) == NULL) { 94115811Sralph printf("\nwas printed but had some errors\n"); 94215811Sralph break; 94315811Sralph } 94415811Sralph printf("\nwas printed but had the following errors:\n"); 94515811Sralph while ((i = getc(fp)) != EOF) 94615811Sralph putchar(i); 94715811Sralph (void) fclose(fp); 94817463Sralph break; 94917463Sralph case ACCESS: 95017463Sralph printf("\nwas not printed because it was not linked to the original file\n"); 95112463Sralph } 95212111Sralph fflush(stdout); 95312111Sralph (void) close(1); 95412111Sralph } 95512111Sralph (void) close(p[0]); 95612111Sralph (void) close(p[1]); 95715811Sralph wait(&s); 95812111Sralph } 95912111Sralph 96012111Sralph /* 96112111Sralph * dofork - fork with retries on failure 96212111Sralph */ 96312111Sralph dofork(action) 96412111Sralph int action; 96512111Sralph { 96612111Sralph register int i, pid; 96712111Sralph 96812111Sralph for (i = 0; i < 20; i++) { 96912463Sralph if ((pid = fork()) < 0) { 97012111Sralph sleep((unsigned)(i*i)); 97112463Sralph continue; 97212463Sralph } 97312463Sralph /* 97412463Sralph * Child should run as daemon instead of root 97512463Sralph */ 97612463Sralph if (pid == 0) 97712463Sralph setuid(DU); 97812463Sralph return(pid); 97912111Sralph } 98016762Sralph syslog(LOG_ERR, "can't fork"); 98112111Sralph 98212111Sralph switch (action) { 98312111Sralph case DORETURN: 98412111Sralph return (-1); 98512111Sralph default: 98616762Sralph syslog(LOG_ERR, "bad action (%d) to dofork", action); 98712111Sralph /*FALL THRU*/ 98812111Sralph case DOABORT: 98912111Sralph exit(1); 99012111Sralph } 99112111Sralph /*NOTREACHED*/ 99212111Sralph } 99312111Sralph 99412111Sralph /* 99516762Sralph * Kill child processes to abort current job. 99612111Sralph */ 99716762Sralph abortpr() 99812111Sralph { 99915811Sralph (void) unlink(tmpfile); 100012111Sralph kill(0, SIGINT); 100112111Sralph if (ofilter > 0) 100212111Sralph kill(ofilter, SIGCONT); 100312111Sralph while (wait(0) > 0) 100412111Sralph ; 100512111Sralph exit(0); 100612111Sralph } 100712111Sralph 100812111Sralph init() 100912111Sralph { 101012111Sralph int status; 101112111Sralph 101225468Stef if ((status = pgetent(line, printer)) < 0) { 101325468Stef syslog(LOG_ERR, "can't open printer description file"); 101425468Stef exit(1); 101525468Stef } else if (status == 0) { 101625468Stef syslog(LOG_ERR, "unknown printer: %s", printer); 101725468Stef exit(1); 101825468Stef } 101912111Sralph if ((LP = pgetstr("lp", &bp)) == NULL) 102012111Sralph LP = DEFDEVLP; 102112111Sralph if ((RP = pgetstr("rp", &bp)) == NULL) 102212463Sralph RP = DEFLP; 102312111Sralph if ((LO = pgetstr("lo", &bp)) == NULL) 102412111Sralph LO = DEFLOCK; 102512111Sralph if ((ST = pgetstr("st", &bp)) == NULL) 102612111Sralph ST = DEFSTAT; 102712111Sralph if ((LF = pgetstr("lf", &bp)) == NULL) 102812111Sralph LF = DEFLOGF; 102912111Sralph if ((SD = pgetstr("sd", &bp)) == NULL) 103012111Sralph SD = DEFSPOOL; 103112111Sralph if ((DU = pgetnum("du")) < 0) 103212111Sralph DU = DEFUID; 103312111Sralph if ((FF = pgetstr("ff", &bp)) == NULL) 103412111Sralph FF = DEFFF; 103512111Sralph if ((PW = pgetnum("pw")) < 0) 103612111Sralph PW = DEFWIDTH; 103712111Sralph sprintf(&width[2], "%d", PW); 103812111Sralph if ((PL = pgetnum("pl")) < 0) 103912111Sralph PL = DEFLENGTH; 104012111Sralph sprintf(&length[2], "%d", PL); 104112463Sralph if ((PX = pgetnum("px")) < 0) 104212463Sralph PX = 0; 104312463Sralph sprintf(&pxwidth[2], "%d", PX); 104412463Sralph if ((PY = pgetnum("py")) < 0) 104512463Sralph PY = 0; 104612463Sralph sprintf(&pxlength[2], "%d", PY); 104712111Sralph RM = pgetstr("rm", &bp); 104825468Stef /* 104925468Stef * Figure out whether the local machine is the same as the remote 105025468Stef * machine entry (if it exists). If not, then ignore the local 105125468Stef * queue information. 105225468Stef */ 105325468Stef if (RM != (char *) NULL) { 105425468Stef char name[256]; 105525468Stef struct hostent *hp; 105625468Stef 105725468Stef /* get the standard network name of the local host */ 105825468Stef gethostname(name, sizeof(name)); 105925468Stef name[sizeof(name)-1] = '\0'; 106025468Stef hp = gethostbyname(name); 106125468Stef if (hp == (struct hostent *) NULL) { 106225468Stef syslog(LOG_ERR, 106325468Stef "unable to get network name for local machine %s", 106425468Stef name); 106525468Stef goto localcheck_done; 106625468Stef } else strcpy(name, hp->h_name); 106725468Stef 106825468Stef /* get the standard network name of RM */ 106925468Stef hp = gethostbyname(RM); 107025468Stef if (hp == (struct hostent *) NULL) { 107125468Stef syslog(LOG_ERR, 107225468Stef "unable to get hostname for remote machine %s", RM); 107325468Stef goto localcheck_done; 107425468Stef } 107525468Stef 107625468Stef /* if printer is not on local machine, ignore LP */ 107725468Stef if (strcmp(name, hp->h_name) != 0) *LP = '\0'; 107825468Stef } 107925468Stef localcheck_done: 108025468Stef 108112111Sralph AF = pgetstr("af", &bp); 108212111Sralph OF = pgetstr("of", &bp); 108312111Sralph IF = pgetstr("if", &bp); 108412463Sralph RF = pgetstr("rf", &bp); 108512111Sralph TF = pgetstr("tf", &bp); 108613233Sralph NF = pgetstr("nf", &bp); 108712111Sralph DF = pgetstr("df", &bp); 108812111Sralph GF = pgetstr("gf", &bp); 108912111Sralph VF = pgetstr("vf", &bp); 109012111Sralph CF = pgetstr("cf", &bp); 109112111Sralph TR = pgetstr("tr", &bp); 109212463Sralph RS = pgetflag("rs"); 109312111Sralph SF = pgetflag("sf"); 109412111Sralph SH = pgetflag("sh"); 109512111Sralph SB = pgetflag("sb"); 109618127Sralph HL = pgetflag("hl"); 109712111Sralph RW = pgetflag("rw"); 109812111Sralph BR = pgetnum("br"); 109912111Sralph if ((FC = pgetnum("fc")) < 0) 110012111Sralph FC = 0; 110112111Sralph if ((FS = pgetnum("fs")) < 0) 110212111Sralph FS = 0; 110312111Sralph if ((XC = pgetnum("xc")) < 0) 110412111Sralph XC = 0; 110512111Sralph if ((XS = pgetnum("xs")) < 0) 110612111Sralph XS = 0; 110712581Sralph tof = !pgetflag("fo"); 110812111Sralph } 110912111Sralph 111012463Sralph /* 111112463Sralph * Acquire line printer or remote connection. 111212463Sralph */ 111312463Sralph openpr() 111412463Sralph { 111512463Sralph register int i, n; 111616762Sralph int resp; 111712463Sralph 111812463Sralph if (*LP) { 111912463Sralph for (i = 1; ; i = i < 32 ? i << 1 : i) { 112013148Ssam pfd = open(LP, RW ? O_RDWR : O_WRONLY); 112112463Sralph if (pfd >= 0) 112212463Sralph break; 112312463Sralph if (errno == ENOENT) { 112416762Sralph syslog(LOG_ERR, "%s: %m", LP); 112512463Sralph exit(1); 112612463Sralph } 112712463Sralph if (i == 1) 112812463Sralph status("waiting for %s to become ready (offline ?)", printer); 112912463Sralph sleep(i); 113012463Sralph } 113112463Sralph if (isatty(pfd)) 113212463Sralph setty(); 113312463Sralph status("%s is ready and printing", printer); 113412463Sralph } else if (RM != NULL) { 113516762Sralph for (i = 1; ; i = i < 256 ? i << 1 : i) { 113616762Sralph resp = -1; 113712528Sralph pfd = getport(RM); 113812463Sralph if (pfd >= 0) { 113912463Sralph (void) sprintf(line, "\2%s\n", RP); 114012463Sralph n = strlen(line); 114116762Sralph if (write(pfd, line, n) == n && 114216762Sralph (resp = response()) == '\0') 114312463Sralph break; 114416031Sralph (void) close(pfd); 114512463Sralph } 114616031Sralph if (i == 1) { 114716762Sralph if (resp < 0) 114816031Sralph status("waiting for %s to come up", RM); 114916762Sralph else { 115016031Sralph status("waiting for queue to be enabled on %s", RM); 115116762Sralph i = 256; 115216762Sralph } 115316031Sralph } 115412463Sralph sleep(i); 115512463Sralph } 115612463Sralph status("sending to %s", RM); 115712463Sralph remote = 1; 115812463Sralph } else { 115916762Sralph syslog(LOG_ERR, "%s: no line printer device or host name", 116016762Sralph printer); 116112463Sralph exit(1); 116212463Sralph } 116312463Sralph /* 116412463Sralph * Start up an output filter, if needed. 116512463Sralph */ 116612463Sralph if (OF) { 116712463Sralph int p[2]; 116812463Sralph char *cp; 116912463Sralph 117012463Sralph pipe(p); 117112463Sralph if ((ofilter = dofork(DOABORT)) == 0) { /* child */ 117212463Sralph dup2(p[0], 0); /* pipe is std in */ 117312463Sralph dup2(pfd, 1); /* printer is std out */ 117412463Sralph for (i = 3; i < NOFILE; i++) 117512463Sralph (void) close(i); 117612463Sralph if ((cp = rindex(OF, '/')) == NULL) 117712463Sralph cp = OF; 117812463Sralph else 117912463Sralph cp++; 118012463Sralph execl(OF, cp, width, length, 0); 118116762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, OF); 118212463Sralph exit(1); 118312463Sralph } 118412463Sralph (void) close(p[0]); /* close input side */ 118512463Sralph ofd = p[1]; /* use pipe for output */ 118612463Sralph } else { 118712463Sralph ofd = pfd; 118812463Sralph ofilter = 0; 118912463Sralph } 119012463Sralph } 119112463Sralph 119212111Sralph struct bauds { 119312111Sralph int baud; 119412111Sralph int speed; 119512111Sralph } bauds[] = { 119612111Sralph 50, B50, 119712111Sralph 75, B75, 119812111Sralph 110, B110, 119912111Sralph 134, B134, 120012111Sralph 150, B150, 120112111Sralph 200, B200, 120212111Sralph 300, B300, 120312111Sralph 600, B600, 120412111Sralph 1200, B1200, 120512111Sralph 1800, B1800, 120612111Sralph 2400, B2400, 120712111Sralph 4800, B4800, 120812111Sralph 9600, B9600, 120912111Sralph 19200, EXTA, 121012111Sralph 38400, EXTB, 121112111Sralph 0, 0 121212111Sralph }; 121312111Sralph 121412111Sralph /* 121512111Sralph * setup tty lines. 121612111Sralph */ 121712111Sralph setty() 121812111Sralph { 121912111Sralph struct sgttyb ttybuf; 122012111Sralph register struct bauds *bp; 122112111Sralph 122212111Sralph if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) { 122316762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer); 122412111Sralph exit(1); 122512111Sralph } 122612111Sralph if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) { 122716762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCGETP): %m", printer); 122812111Sralph exit(1); 122912111Sralph } 123012111Sralph if (BR > 0) { 123112111Sralph for (bp = bauds; bp->baud; bp++) 123212111Sralph if (BR == bp->baud) 123312111Sralph break; 123412111Sralph if (!bp->baud) { 123516762Sralph syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR); 123612111Sralph exit(1); 123712111Sralph } 123812111Sralph ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed; 123912111Sralph } 124013169Sralph ttybuf.sg_flags &= ~FC; 124113169Sralph ttybuf.sg_flags |= FS; 124212111Sralph if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) { 124316762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCSETP): %m", printer); 124412111Sralph exit(1); 124512111Sralph } 124617168Sralph if (XC || XS) { 124717168Sralph int ldisc = NTTYDISC; 124817168Sralph 124917168Sralph if (ioctl(pfd, TIOCSETD, &ldisc) < 0) { 125017168Sralph syslog(LOG_ERR, "%s: ioctl(TIOCSETD): %m", printer); 125117168Sralph exit(1); 125217168Sralph } 125317168Sralph } 125412111Sralph if (XC) { 125512111Sralph if (ioctl(pfd, TIOCLBIC, &XC) < 0) { 125616762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCLBIC): %m", printer); 125712111Sralph exit(1); 125812111Sralph } 125912111Sralph } 126012111Sralph if (XS) { 126112111Sralph if (ioctl(pfd, TIOCLBIS, &XS) < 0) { 126216762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCLBIS): %m", printer); 126312111Sralph exit(1); 126412111Sralph } 126512111Sralph } 126612111Sralph } 126712463Sralph 126812463Sralph /*VARARGS1*/ 126912463Sralph status(msg, a1, a2, a3) 127012463Sralph char *msg; 127112463Sralph { 127212463Sralph register int fd; 127312463Sralph char buf[BUFSIZ]; 127412463Sralph 127512463Sralph umask(0); 127613148Ssam fd = open(ST, O_WRONLY|O_CREAT, 0664); 127716762Sralph if (fd < 0 || flock(fd, LOCK_EX) < 0) { 127816762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, ST); 127916762Sralph exit(1); 128016762Sralph } 128113148Ssam ftruncate(fd, 0); 128212463Sralph sprintf(buf, msg, a1, a2, a3); 128312463Sralph strcat(buf, "\n"); 128412463Sralph (void) write(fd, buf, strlen(buf)); 128512463Sralph (void) close(fd); 128612463Sralph } 1287