122437Sdist /* 222437Sdist * Copyright (c) 1983 Regents of the University of California. 3*34203Sbostic * All rights reserved. 4*34203Sbostic * 5*34203Sbostic * Redistribution and use in source and binary forms are permitted 6*34203Sbostic * provided that this notice is preserved and that due credit is given 7*34203Sbostic * to the University of California at Berkeley. The name of the University 8*34203Sbostic * may not be used to endorse or promote products derived from this 9*34203Sbostic * software without specific prior written permission. This software 10*34203Sbostic * is provided ``as is'' without express or implied warranty. 1122437Sdist */ 1222437Sdist 1313954Ssam #ifndef lint 14*34203Sbostic static char sccsid[] = "@(#)printjob.c 5.5 (Berkeley) 05/05/88"; 15*34203Sbostic #endif /* not lint */ 1613954Ssam 1712111Sralph /* 1812111Sralph * printjob -- print jobs in the queue. 1912111Sralph * 2012111Sralph * NOTE: the lock file is used to pass information to lpq and lprm. 2112111Sralph * it does not need to be removed because file locks are dynamic. 2212111Sralph */ 2312111Sralph 2412111Sralph #include "lp.h" 2512111Sralph 2616762Sralph #define DORETURN 0 /* absorb fork error */ 2716762Sralph #define DOABORT 1 /* abort if dofork fails */ 2812111Sralph 2917463Sralph /* 3017463Sralph * Error tokens 3117463Sralph */ 3217463Sralph #define REPRINT -2 3317463Sralph #define ERROR -1 3417463Sralph #define OK 0 3517463Sralph #define FATALERR 1 3617463Sralph #define NOACCT 2 3717463Sralph #define FILTERERR 3 3817463Sralph #define ACCESS 4 3917463Sralph 4016762Sralph char title[80]; /* ``pr'' title */ 4116762Sralph FILE *cfp; /* control file */ 4216762Sralph int pfd; /* printer file descriptor */ 4316762Sralph int ofd; /* output filter file descriptor */ 4416762Sralph int lfd; /* lock file descriptor */ 4516762Sralph int pid; /* pid of lpd process */ 4616762Sralph int prchild; /* id of pr process */ 4716762Sralph int child; /* id of any filters */ 4816762Sralph int ofilter; /* id of output filter, if any */ 4916762Sralph int tof; /* true if at top of form */ 5016762Sralph int remote; /* true if sending files to remote */ 5117463Sralph dev_t fdev; /* device of file pointed to by symlink */ 5217463Sralph ino_t fino; /* inode of file pointed to by symlink */ 5312111Sralph 5416762Sralph char fromhost[32]; /* user's host machine */ 5516762Sralph char logname[32]; /* user's login name */ 5616762Sralph char jobname[100]; /* job or file name */ 5716762Sralph char class[32]; /* classification field */ 5816762Sralph char width[10] = "-w"; /* page width in characters */ 5916762Sralph char length[10] = "-l"; /* page length in lines */ 6016762Sralph char pxwidth[10] = "-x"; /* page width in pixels */ 6116762Sralph char pxlength[10] = "-y"; /* page length in pixels */ 6216762Sralph char indent[10] = "-i0"; /* indentation size in characters */ 6316762Sralph char tmpfile[] = "errsXXXXXX"; /* file name for filter output */ 6412111Sralph 6512111Sralph printjob() 6612111Sralph { 6712111Sralph struct stat stb; 6812111Sralph register struct queue *q, **qp; 6912111Sralph struct queue **queue; 7012111Sralph register int i, nitems; 7112111Sralph long pidoff; 7216762Sralph int count = 0; 7316762Sralph extern int abortpr(); 7412111Sralph 7512111Sralph init(); /* set up capabilities */ 7613442Sralph (void) write(1, "", 1); /* ack that daemon is started */ 7725496Seric (void) close(2); /* set up log file */ 7825496Seric if (open(LF, O_WRONLY|O_APPEND, 0664) < 0) { 7925496Seric syslog(LOG_ERR, "%s: %m", LF); 8025496Seric (void) open("/dev/null", O_WRONLY); 8125496Seric } 8216762Sralph setgid(getegid()); 8312463Sralph pid = getpid(); /* for use with lprm */ 8412111Sralph setpgrp(0, pid); 8516762Sralph signal(SIGHUP, abortpr); 8616762Sralph signal(SIGINT, abortpr); 8716762Sralph signal(SIGQUIT, abortpr); 8816762Sralph signal(SIGTERM, abortpr); 8912111Sralph 9015811Sralph (void) mktemp(tmpfile); 9115811Sralph 9212111Sralph /* 9312111Sralph * uses short form file names 9412111Sralph */ 9512111Sralph if (chdir(SD) < 0) { 9616762Sralph syslog(LOG_ERR, "%s: %m", SD); 9712111Sralph exit(1); 9812111Sralph } 9912463Sralph if (stat(LO, &stb) == 0 && (stb.st_mode & 0100)) 10012463Sralph exit(0); /* printing disabled */ 10114150Sralph lfd = open(LO, O_WRONLY|O_CREAT, 0644); 10213169Sralph if (lfd < 0) { 10316762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, LO); 10413169Sralph exit(1); 10513169Sralph } 10613169Sralph if (flock(lfd, LOCK_EX|LOCK_NB) < 0) { 10712111Sralph if (errno == EWOULDBLOCK) /* active deamon present */ 10812111Sralph exit(0); 10916762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, LO); 11012111Sralph exit(1); 11112111Sralph } 11213148Ssam ftruncate(lfd, 0); 11312111Sralph /* 11412111Sralph * write process id for others to know 11512111Sralph */ 11612111Sralph sprintf(line, "%u\n", pid); 11712111Sralph pidoff = i = strlen(line); 11812463Sralph if (write(lfd, line, i) != i) { 11916762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, LO); 12012111Sralph exit(1); 12112111Sralph } 12212111Sralph /* 12312111Sralph * search the spool directory for work and sort by queue order. 12412111Sralph */ 12512111Sralph if ((nitems = getq(&queue)) < 0) { 12616762Sralph syslog(LOG_ERR, "%s: can't scan %s", printer, SD); 12712111Sralph exit(1); 12812111Sralph } 12912463Sralph if (nitems == 0) /* no work to do */ 13012111Sralph exit(0); 13113169Sralph if (stb.st_mode & 01) { /* reset queue flag */ 13213169Sralph if (fchmod(lfd, stb.st_mode & 0776) < 0) 13316762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, LO); 13413169Sralph } 13512463Sralph openpr(); /* open printer or remote */ 13612463Sralph again: 13712111Sralph /* 13812111Sralph * we found something to do now do it -- 13912111Sralph * write the name of the current control file into the lock file 14012111Sralph * so the spool queue program can tell what we're working on 14112111Sralph */ 14212111Sralph for (qp = queue; nitems--; free((char *) q)) { 14312111Sralph q = *qp++; 14412111Sralph if (stat(q->q_name, &stb) < 0) 14512111Sralph continue; 14612463Sralph restart: 14712111Sralph (void) lseek(lfd, pidoff, 0); 14812111Sralph (void) sprintf(line, "%s\n", q->q_name); 14912111Sralph i = strlen(line); 15012111Sralph if (write(lfd, line, i) != i) 15116762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, LO); 15212111Sralph if (!remote) 15312111Sralph i = printit(q->q_name); 15412111Sralph else 15512111Sralph i = sendit(q->q_name); 15612463Sralph /* 15713169Sralph * Check to see if we are supposed to stop printing or 15813169Sralph * if we are to rebuild the queue. 15912463Sralph */ 16013169Sralph if (fstat(lfd, &stb) == 0) { 16116762Sralph /* stop printing before starting next job? */ 16213169Sralph if (stb.st_mode & 0100) 16313169Sralph goto done; 16416762Sralph /* rebuild queue (after lpc topq) */ 16513169Sralph if (stb.st_mode & 01) { 16613169Sralph for (free((char *) q); nitems--; free((char *) q)) 16713169Sralph q = *qp++; 16813169Sralph if (fchmod(lfd, stb.st_mode & 0776) < 0) 16916762Sralph syslog(LOG_WARNING, "%s: %s: %m", 17016762Sralph printer, LO); 17113169Sralph break; 17213169Sralph } 17313169Sralph } 17417463Sralph if (i == OK) /* file ok and printed */ 17514150Sralph count++; 17617463Sralph else if (i == REPRINT) { /* try reprinting the job */ 17716762Sralph syslog(LOG_INFO, "restarting %s", printer); 17812111Sralph if (ofilter > 0) { 17912111Sralph kill(ofilter, SIGCONT); /* to be sure */ 18012111Sralph (void) close(ofd); 18112111Sralph while ((i = wait(0)) > 0 && i != ofilter) 18212111Sralph ; 18312111Sralph ofilter = 0; 18412111Sralph } 18512463Sralph (void) close(pfd); /* close printer */ 18615811Sralph if (ftruncate(lfd, pidoff) < 0) 18716762Sralph syslog(LOG_WARNING, "%s: %s: %m", printer, LO); 18812463Sralph openpr(); /* try to reopen printer */ 18912111Sralph goto restart; 19012111Sralph } 19112111Sralph } 19212111Sralph free((char *) queue); 19312463Sralph /* 19412463Sralph * search the spool directory for more work. 19512463Sralph */ 19612463Sralph if ((nitems = getq(&queue)) < 0) { 19716762Sralph syslog(LOG_ERR, "%s: can't scan %s", printer, SD); 19812463Sralph exit(1); 19912463Sralph } 20012463Sralph if (nitems == 0) { /* no more work to do */ 20112463Sralph done: 20214150Sralph if (count > 0) { /* Files actually printed */ 20314150Sralph if (!SF && !tof) 20414150Sralph (void) write(ofd, FF, strlen(FF)); 20514150Sralph if (TR != NULL) /* output trailer */ 20614150Sralph (void) write(ofd, TR, strlen(TR)); 20714150Sralph } 20815811Sralph (void) unlink(tmpfile); 20912463Sralph exit(0); 21012463Sralph } 21112111Sralph goto again; 21212111Sralph } 21312111Sralph 21412111Sralph char fonts[4][50]; /* fonts for troff */ 21512111Sralph 21616762Sralph char ifonts[4][18] = { 21712111Sralph "/usr/lib/vfont/R", 21812111Sralph "/usr/lib/vfont/I", 21912111Sralph "/usr/lib/vfont/B", 22012111Sralph "/usr/lib/vfont/S" 22112111Sralph }; 22212111Sralph 22312111Sralph /* 22412111Sralph * The remaining part is the reading of the control file (cf) 22512111Sralph * and performing the various actions. 22612111Sralph */ 22712111Sralph printit(file) 22812111Sralph char *file; 22912111Sralph { 23012111Sralph register int i; 23117463Sralph char *cp; 23217463Sralph int bombed = OK; 23312111Sralph 23412111Sralph /* 23517463Sralph * open control file; ignore if no longer there. 23612111Sralph */ 23712111Sralph if ((cfp = fopen(file, "r")) == NULL) { 23816762Sralph syslog(LOG_INFO, "%s: %s: %m", printer, file); 23917463Sralph return(OK); 24012111Sralph } 24112111Sralph /* 24212111Sralph * Reset troff fonts. 24312111Sralph */ 24412111Sralph for (i = 0; i < 4; i++) 24512111Sralph strcpy(fonts[i], ifonts[i]); 24617339Sralph strcpy(width+2, "0"); 24717302Sralph strcpy(indent+2, "0"); 24812111Sralph 24912111Sralph /* 25012111Sralph * read the control file for work to do 25112111Sralph * 25212111Sralph * file format -- first character in the line is a command 25312111Sralph * rest of the line is the argument. 25412111Sralph * valid commands are: 25512111Sralph * 25617463Sralph * S -- "stat info" for symbolic link protection 25712111Sralph * J -- "job name" on banner page 25812111Sralph * C -- "class name" on banner page 25912111Sralph * L -- "literal" user's name to print on banner 26012111Sralph * T -- "title" for pr 26112111Sralph * H -- "host name" of machine where lpr was done 26212111Sralph * P -- "person" user's login name 26312581Sralph * I -- "indent" amount to indent output 26412111Sralph * f -- "file name" name of text file to print 26512111Sralph * l -- "file name" text file with control chars 26612111Sralph * p -- "file name" text file to print with pr(1) 26712111Sralph * t -- "file name" troff(1) file to print 26813233Sralph * n -- "file name" ditroff(1) file to print 26912111Sralph * d -- "file name" dvi file to print 27012111Sralph * g -- "file name" plot(1G) file to print 27112111Sralph * v -- "file name" plain raster file to print 27212111Sralph * c -- "file name" cifplot file to print 27312111Sralph * 1 -- "R font file" for troff 27412111Sralph * 2 -- "I font file" for troff 27512111Sralph * 3 -- "B font file" for troff 27612111Sralph * 4 -- "S font file" for troff 27712111Sralph * N -- "name" of file (used by lpq) 27812111Sralph * U -- "unlink" name of file to remove 27912111Sralph * (after we print it. (Pass 2 only)). 28012111Sralph * M -- "mail" to user when done printing 28112111Sralph * 28212111Sralph * getline reads a line and expands tabs to blanks 28312111Sralph */ 28412111Sralph 28512111Sralph /* pass 1 */ 28612111Sralph 28712111Sralph while (getline(cfp)) 28812111Sralph switch (line[0]) { 28912111Sralph case 'H': 29014150Sralph strcpy(fromhost, line+1); 29112111Sralph if (class[0] == '\0') 29215552Sralph strncpy(class, line+1, sizeof(class)-1); 29312111Sralph continue; 29412111Sralph 29512111Sralph case 'P': 29615552Sralph strncpy(logname, line+1, sizeof(logname)-1); 29712463Sralph if (RS) { /* restricted */ 29812463Sralph if (getpwnam(logname) == (struct passwd *)0) { 29917463Sralph bombed = NOACCT; 30015811Sralph sendmail(line+1, bombed); 30112463Sralph goto pass2; 30212463Sralph } 30312463Sralph } 30412111Sralph continue; 30512111Sralph 30617463Sralph case 'S': 30717463Sralph cp = line+1; 30817463Sralph i = 0; 30917463Sralph while (*cp >= '0' && *cp <= '9') 31017463Sralph i = i * 10 + (*cp++ - '0'); 31117463Sralph fdev = i; 31217463Sralph cp++; 31317463Sralph i = 0; 31417463Sralph while (*cp >= '0' && *cp <= '9') 31517463Sralph i = i * 10 + (*cp++ - '0'); 31617463Sralph fino = i; 31717463Sralph continue; 31817463Sralph 31912111Sralph case 'J': 32012111Sralph if (line[1] != '\0') 32115552Sralph strncpy(jobname, line+1, sizeof(jobname)-1); 32212111Sralph else 32312111Sralph strcpy(jobname, " "); 32412111Sralph continue; 32512111Sralph 32612111Sralph case 'C': 32712111Sralph if (line[1] != '\0') 32815552Sralph strncpy(class, line+1, sizeof(class)-1); 32912111Sralph else if (class[0] == '\0') 33015811Sralph gethostname(class, sizeof(class)); 33112111Sralph continue; 33212111Sralph 33312111Sralph case 'T': /* header title for pr */ 33415552Sralph strncpy(title, line+1, sizeof(title)-1); 33512111Sralph continue; 33612111Sralph 33712111Sralph case 'L': /* identification line */ 33818127Sralph if (!SH && !HL) 33912111Sralph banner(line+1, jobname); 34012111Sralph continue; 34112111Sralph 34212111Sralph case '1': /* troff fonts */ 34312111Sralph case '2': 34412111Sralph case '3': 34512111Sralph case '4': 34612111Sralph if (line[1] != '\0') 34712111Sralph strcpy(fonts[line[0]-'1'], line+1); 34812111Sralph continue; 34912111Sralph 35012111Sralph case 'W': /* page width */ 35115552Sralph strncpy(width+2, line+1, sizeof(width)-3); 35212111Sralph continue; 35312111Sralph 35412581Sralph case 'I': /* indent amount */ 35515552Sralph strncpy(indent+2, line+1, sizeof(indent)-3); 35612581Sralph continue; 35712581Sralph 35812111Sralph default: /* some file to print */ 35915811Sralph switch (i = print(line[0], line+1)) { 36017463Sralph case ERROR: 36117463Sralph if (bombed == OK) 36217463Sralph bombed = FATALERR; 36315811Sralph break; 36417463Sralph case REPRINT: 36512111Sralph (void) fclose(cfp); 36617463Sralph return(REPRINT); 36717463Sralph case FILTERERR: 36817463Sralph case ACCESS: 36917463Sralph bombed = i; 37015811Sralph sendmail(logname, bombed); 37115811Sralph } 37212111Sralph title[0] = '\0'; 37312111Sralph continue; 37412111Sralph 37512111Sralph case 'N': 37612111Sralph case 'U': 37712111Sralph case 'M': 37812111Sralph continue; 37912111Sralph } 38012111Sralph 38112111Sralph /* pass 2 */ 38212111Sralph 38312463Sralph pass2: 38412111Sralph fseek(cfp, 0L, 0); 38512111Sralph while (getline(cfp)) 38612111Sralph switch (line[0]) { 38718127Sralph case 'L': /* identification line */ 38818127Sralph if (!SH && HL) 38918127Sralph banner(line+1, jobname); 39018127Sralph continue; 39118127Sralph 39212111Sralph case 'M': 39317463Sralph if (bombed < NOACCT) /* already sent if >= NOACCT */ 39415811Sralph sendmail(line+1, bombed); 39512111Sralph continue; 39612111Sralph 39712111Sralph case 'U': 39812111Sralph (void) unlink(line+1); 39912111Sralph } 40012111Sralph /* 40115811Sralph * clean-up in case another control file exists 40212111Sralph */ 40312111Sralph (void) fclose(cfp); 40412111Sralph (void) unlink(file); 40517463Sralph return(bombed == OK ? OK : ERROR); 40612111Sralph } 40712111Sralph 40812111Sralph /* 40912111Sralph * Print a file. 41013233Sralph * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}. 41115811Sralph * Return -1 if a non-recoverable error occured, 41215811Sralph * 2 if the filter detected some errors (but printed the job anyway), 41315811Sralph * 1 if we should try to reprint this job and 41412111Sralph * 0 if all is well. 41512111Sralph * Note: all filters take stdin as the file, stdout as the printer, 41612111Sralph * stderr as the log file, and must not ignore SIGINT. 41712111Sralph */ 41812111Sralph print(format, file) 41912111Sralph int format; 42012111Sralph char *file; 42112111Sralph { 42215811Sralph register int n; 42312111Sralph register char *prog; 42415811Sralph int fi, fo; 42512111Sralph char *av[15], buf[BUFSIZ]; 42612111Sralph int pid, p[2], stopped = 0; 42712111Sralph union wait status; 42817463Sralph struct stat stb; 42912111Sralph 43017463Sralph if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0) 43117463Sralph return(ERROR); 43217463Sralph /* 43317463Sralph * Check to see if data file is a symbolic link. If so, it should 43417463Sralph * still point to the same file or someone is trying to print 43517463Sralph * something he shouldn't. 43617463Sralph */ 43717463Sralph if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 && 43817463Sralph (stb.st_dev != fdev || stb.st_ino != fino)) 43917463Sralph return(ACCESS); 44012111Sralph if (!SF && !tof) { /* start on a fresh page */ 44112111Sralph (void) write(ofd, FF, strlen(FF)); 44212111Sralph tof = 1; 44312111Sralph } 44412111Sralph if (IF == NULL && (format == 'f' || format == 'l')) { 44512111Sralph tof = 0; 44612111Sralph while ((n = read(fi, buf, BUFSIZ)) > 0) 44712111Sralph if (write(ofd, buf, n) != n) { 44812111Sralph (void) close(fi); 44917463Sralph return(REPRINT); 45012111Sralph } 45112111Sralph (void) close(fi); 45217463Sralph return(OK); 45312111Sralph } 45412111Sralph switch (format) { 45512111Sralph case 'p': /* print file using 'pr' */ 45612111Sralph if (IF == NULL) { /* use output filter */ 45712111Sralph prog = PR; 45812111Sralph av[0] = "pr"; 45912111Sralph av[1] = width; 46012111Sralph av[2] = length; 46112111Sralph av[3] = "-h"; 46212111Sralph av[4] = *title ? title : " "; 46312111Sralph av[5] = 0; 46412111Sralph fo = ofd; 46512111Sralph goto start; 46612111Sralph } 46712111Sralph pipe(p); 46812111Sralph if ((prchild = dofork(DORETURN)) == 0) { /* child */ 46912111Sralph dup2(fi, 0); /* file is stdin */ 47012111Sralph dup2(p[1], 1); /* pipe is stdout */ 47112111Sralph for (n = 3; n < NOFILE; n++) 47212111Sralph (void) close(n); 47312111Sralph execl(PR, "pr", width, length, "-h", *title ? title : " ", 0); 47416762Sralph syslog(LOG_ERR, "cannot execl %s", PR); 47512111Sralph exit(2); 47612111Sralph } 47712111Sralph (void) close(p[1]); /* close output side */ 47812111Sralph (void) close(fi); 47912111Sralph if (prchild < 0) { 48012111Sralph prchild = 0; 48112111Sralph (void) close(p[0]); 48217463Sralph return(ERROR); 48312111Sralph } 48412111Sralph fi = p[0]; /* use pipe for input */ 48512111Sralph case 'f': /* print plain text file */ 48612111Sralph prog = IF; 48712111Sralph av[1] = width; 48812111Sralph av[2] = length; 48912581Sralph av[3] = indent; 49012581Sralph n = 4; 49112111Sralph break; 49212111Sralph case 'l': /* like 'f' but pass control characters */ 49312111Sralph prog = IF; 49414325Sralph av[1] = "-c"; 49512111Sralph av[2] = width; 49612111Sralph av[3] = length; 49712581Sralph av[4] = indent; 49812581Sralph n = 5; 49912111Sralph break; 50012463Sralph case 'r': /* print a fortran text file */ 50112463Sralph prog = RF; 50212463Sralph av[1] = width; 50312463Sralph av[2] = length; 50412463Sralph n = 3; 50512463Sralph break; 50612111Sralph case 't': /* print troff output */ 50713233Sralph case 'n': /* print ditroff output */ 50812463Sralph case 'd': /* print tex output */ 50912111Sralph (void) unlink(".railmag"); 51012463Sralph if ((fo = creat(".railmag", FILMOD)) < 0) { 51116762Sralph syslog(LOG_ERR, "%s: cannot create .railmag", printer); 51212111Sralph (void) unlink(".railmag"); 51312111Sralph } else { 51412111Sralph for (n = 0; n < 4; n++) { 51512111Sralph if (fonts[n][0] != '/') 51612111Sralph (void) write(fo, "/usr/lib/vfont/", 15); 51712111Sralph (void) write(fo, fonts[n], strlen(fonts[n])); 51812111Sralph (void) write(fo, "\n", 1); 51912111Sralph } 52012111Sralph (void) close(fo); 52112111Sralph } 52213233Sralph prog = (format == 't') ? TF : (format == 'n') ? NF : DF; 52312463Sralph av[1] = pxwidth; 52412463Sralph av[2] = pxlength; 52512463Sralph n = 3; 52612111Sralph break; 52712111Sralph case 'c': /* print cifplot output */ 52812111Sralph prog = CF; 52912463Sralph av[1] = pxwidth; 53012463Sralph av[2] = pxlength; 53112463Sralph n = 3; 53212111Sralph break; 53312111Sralph case 'g': /* print plot(1G) output */ 53412111Sralph prog = GF; 53512463Sralph av[1] = pxwidth; 53612463Sralph av[2] = pxlength; 53712463Sralph n = 3; 53812111Sralph break; 53912111Sralph case 'v': /* print raster output */ 54012111Sralph prog = VF; 54112463Sralph av[1] = pxwidth; 54212463Sralph av[2] = pxlength; 54312463Sralph n = 3; 54412111Sralph break; 54512111Sralph default: 54612111Sralph (void) close(fi); 54716762Sralph syslog(LOG_ERR, "%s: illegal format character '%c'", 54816762Sralph printer, format); 54917463Sralph return(ERROR); 55012111Sralph } 55112111Sralph if ((av[0] = rindex(prog, '/')) != NULL) 55212111Sralph av[0]++; 55312111Sralph else 55412111Sralph av[0] = prog; 55512111Sralph av[n++] = "-n"; 55612111Sralph av[n++] = logname; 55712111Sralph av[n++] = "-h"; 55814150Sralph av[n++] = fromhost; 55912111Sralph av[n++] = AF; 56012111Sralph av[n] = 0; 56112111Sralph fo = pfd; 56212111Sralph if (ofilter > 0) { /* stop output filter */ 56312111Sralph write(ofd, "\031\1", 2); 56412111Sralph while ((pid = wait3(&status, WUNTRACED, 0)) > 0 && pid != ofilter) 56512111Sralph ; 56612111Sralph if (status.w_stopval != WSTOPPED) { 56712111Sralph (void) close(fi); 56816762Sralph syslog(LOG_WARNING, "%s: output filter died (%d)", 56916762Sralph printer, status.w_retcode); 57017463Sralph return(REPRINT); 57112111Sralph } 57212111Sralph stopped++; 57312111Sralph } 57412111Sralph start: 57512111Sralph if ((child = dofork(DORETURN)) == 0) { /* child */ 57612111Sralph dup2(fi, 0); 57712111Sralph dup2(fo, 1); 57817304Sralph n = open(tmpfile, O_WRONLY|O_CREAT|O_TRUNC, 0664); 57915811Sralph if (n >= 0) 58015811Sralph dup2(n, 2); 58112111Sralph for (n = 3; n < NOFILE; n++) 58212111Sralph (void) close(n); 58312111Sralph execv(prog, av); 58416762Sralph syslog(LOG_ERR, "cannot execv %s", prog); 58512111Sralph exit(2); 58612111Sralph } 58712111Sralph (void) close(fi); 58812111Sralph if (child < 0) 58912111Sralph status.w_retcode = 100; 59012111Sralph else 59112111Sralph while ((pid = wait(&status)) > 0 && pid != child) 59212111Sralph ; 59312111Sralph child = 0; 59412111Sralph prchild = 0; 59512111Sralph if (stopped) { /* restart output filter */ 59612111Sralph if (kill(ofilter, SIGCONT) < 0) { 59716762Sralph syslog(LOG_ERR, "cannot restart output filter"); 59812111Sralph exit(1); 59912111Sralph } 60012111Sralph } 60112111Sralph tof = 0; 60215811Sralph if (!WIFEXITED(status)) { 60316762Sralph syslog(LOG_WARNING, "%s: Daemon filter '%c' terminated (%d)", 60416762Sralph printer, format, status.w_termsig); 60517463Sralph return(ERROR); 60617463Sralph } 60717463Sralph switch (status.w_retcode) { 60817463Sralph case 0: 60917463Sralph tof = 1; 61017463Sralph return(OK); 61117463Sralph case 1: 61217463Sralph return(REPRINT); 61317463Sralph default: 61416762Sralph syslog(LOG_WARNING, "%s: Daemon filter '%c' exited (%d)", 61516762Sralph printer, format, status.w_retcode); 61617463Sralph case 2: 61717463Sralph return(ERROR); 61817463Sralph } 61912111Sralph } 62012111Sralph 62112111Sralph /* 62212111Sralph * Send the daemon control file (cf) and any data files. 62312111Sralph * Return -1 if a non-recoverable error occured, 1 if a recoverable error and 62412111Sralph * 0 if all is well. 62512111Sralph */ 62612111Sralph sendit(file) 62712111Sralph char *file; 62812111Sralph { 62917463Sralph register int i, err = OK; 63017463Sralph char *cp, last[BUFSIZ]; 63112111Sralph 63212111Sralph /* 63312111Sralph * open control file 63412111Sralph */ 63516762Sralph if ((cfp = fopen(file, "r")) == NULL) 63617463Sralph return(OK); 63712111Sralph /* 63812111Sralph * read the control file for work to do 63912111Sralph * 64012111Sralph * file format -- first character in the line is a command 64112111Sralph * rest of the line is the argument. 64212111Sralph * commands of interest are: 64312111Sralph * 64412111Sralph * a-z -- "file name" name of file to print 64512111Sralph * U -- "unlink" name of file to remove 64612111Sralph * (after we print it. (Pass 2 only)). 64712111Sralph */ 64812111Sralph 64912111Sralph /* 65012111Sralph * pass 1 65112111Sralph */ 65212111Sralph while (getline(cfp)) { 65312111Sralph again: 65417463Sralph if (line[0] == 'S') { 65517463Sralph cp = line+1; 65617463Sralph i = 0; 65717463Sralph while (*cp >= '0' && *cp <= '9') 65817463Sralph i = i * 10 + (*cp++ - '0'); 65917463Sralph fdev = i; 66017463Sralph cp++; 66117463Sralph i = 0; 66217463Sralph while (*cp >= '0' && *cp <= '9') 66317463Sralph i = i * 10 + (*cp++ - '0'); 66417463Sralph fino = i; 66517463Sralph continue; 66617463Sralph } 66712111Sralph if (line[0] >= 'a' && line[0] <= 'z') { 66812111Sralph strcpy(last, line); 66917463Sralph while (i = getline(cfp)) 67012111Sralph if (strcmp(last, line)) 67112111Sralph break; 67217463Sralph switch (sendfile('\3', last+1)) { 67317463Sralph case OK: 67417463Sralph if (i) 67517463Sralph goto again; 67617463Sralph break; 67717463Sralph case REPRINT: 67812111Sralph (void) fclose(cfp); 67917463Sralph return(REPRINT); 68017463Sralph case ACCESS: 68117463Sralph sendmail(logname, ACCESS); 68217463Sralph case ERROR: 68317463Sralph err = ERROR; 68417463Sralph } 68512111Sralph break; 68612111Sralph } 68712111Sralph } 68817463Sralph if (err == OK && sendfile('\2', file) > 0) { 68912111Sralph (void) fclose(cfp); 69017463Sralph return(REPRINT); 69112111Sralph } 69212111Sralph /* 69312111Sralph * pass 2 69412111Sralph */ 69512111Sralph fseek(cfp, 0L, 0); 69612111Sralph while (getline(cfp)) 69712111Sralph if (line[0] == 'U') 69812111Sralph (void) unlink(line+1); 69912111Sralph /* 70017463Sralph * clean-up in case another control file exists 70112111Sralph */ 70212111Sralph (void) fclose(cfp); 70312111Sralph (void) unlink(file); 70417463Sralph return(err); 70512111Sralph } 70612111Sralph 70712111Sralph /* 70812111Sralph * Send a data file to the remote machine and spool it. 70912111Sralph * Return positive if we should try resending. 71012111Sralph */ 71112111Sralph sendfile(type, file) 71212111Sralph char type, *file; 71312111Sralph { 71412111Sralph register int f, i, amt; 71512111Sralph struct stat stb; 71612111Sralph char buf[BUFSIZ]; 71716762Sralph int sizerr, resp; 71812111Sralph 71917463Sralph if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0) 72017463Sralph return(ERROR); 72117463Sralph /* 72217463Sralph * Check to see if data file is a symbolic link. If so, it should 72317463Sralph * still point to the same file or someone is trying to print something 72417463Sralph * he shouldn't. 72517463Sralph */ 72617463Sralph if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 && 72717463Sralph (stb.st_dev != fdev || stb.st_ino != fino)) 72817463Sralph return(ACCESS); 72912111Sralph (void) sprintf(buf, "%c%d %s\n", type, stb.st_size, file); 73012111Sralph amt = strlen(buf); 73116762Sralph for (i = 0; ; i++) { 73216762Sralph if (write(pfd, buf, amt) != amt || 73316762Sralph (resp = response()) < 0 || resp == '\1') { 73416762Sralph (void) close(f); 73517463Sralph return(REPRINT); 73616762Sralph } else if (resp == '\0') 73716762Sralph break; 73816762Sralph if (i == 0) 73916762Sralph status("no space on remote; waiting for queue to drain"); 74016762Sralph if (i == 10) 74124861Seric syslog(LOG_ALERT, "%s: can't send to %s; queue full", 74216762Sralph printer, RM); 74316762Sralph sleep(5 * 60); 74412692Sralph } 74516762Sralph if (i) 74616762Sralph status("sending to %s", RM); 74712111Sralph sizerr = 0; 74812111Sralph for (i = 0; i < stb.st_size; i += BUFSIZ) { 74912111Sralph amt = BUFSIZ; 75012111Sralph if (i + amt > stb.st_size) 75112111Sralph amt = stb.st_size - i; 75212111Sralph if (sizerr == 0 && read(f, buf, amt) != amt) 75312111Sralph sizerr = 1; 75412692Sralph if (write(pfd, buf, amt) != amt) { 75512692Sralph (void) close(f); 75617463Sralph return(REPRINT); 75712692Sralph } 75812111Sralph } 75912111Sralph (void) close(f); 76012111Sralph if (sizerr) { 76116762Sralph syslog(LOG_INFO, "%s: %s: changed size", printer, file); 76217463Sralph /* tell recvjob to ignore this file */ 76317463Sralph (void) write(pfd, "\1", 1); 76417463Sralph return(ERROR); 76517463Sralph } 76617463Sralph if (write(pfd, "", 1) != 1 || response()) 76717463Sralph return(REPRINT); 76817463Sralph return(OK); 76912111Sralph } 77012111Sralph 77112111Sralph /* 77212111Sralph * Check to make sure there have been no errors and that both programs 77312111Sralph * are in sync with eachother. 77412111Sralph * Return non-zero if the connection was lost. 77512111Sralph */ 77616762Sralph response() 77712111Sralph { 77812111Sralph char resp; 77912111Sralph 78016762Sralph if (read(pfd, &resp, 1) != 1) { 78116762Sralph syslog(LOG_INFO, "%s: lost connection", printer); 78216762Sralph return(-1); 78312111Sralph } 78416762Sralph return(resp); 78512111Sralph } 78612111Sralph 78712111Sralph /* 78812111Sralph * Banner printing stuff 78912111Sralph */ 79012111Sralph banner(name1, name2) 79112111Sralph char *name1, *name2; 79212111Sralph { 79312111Sralph time_t tvec; 79412111Sralph extern char *ctime(); 79512111Sralph 79612111Sralph time(&tvec); 79712111Sralph if (!SF && !tof) 79812111Sralph (void) write(ofd, FF, strlen(FF)); 79912111Sralph if (SB) { /* short banner only */ 80012111Sralph if (class[0]) { 80112111Sralph (void) write(ofd, class, strlen(class)); 80212111Sralph (void) write(ofd, ":", 1); 80312111Sralph } 80412111Sralph (void) write(ofd, name1, strlen(name1)); 80512111Sralph (void) write(ofd, " Job: ", 7); 80612111Sralph (void) write(ofd, name2, strlen(name2)); 80712111Sralph (void) write(ofd, " Date: ", 8); 80812111Sralph (void) write(ofd, ctime(&tvec), 24); 80912111Sralph (void) write(ofd, "\n", 1); 81012111Sralph } else { /* normal banner */ 81112111Sralph (void) write(ofd, "\n\n\n", 3); 81212111Sralph scan_out(ofd, name1, '\0'); 81312111Sralph (void) write(ofd, "\n\n", 2); 81412111Sralph scan_out(ofd, name2, '\0'); 81512111Sralph if (class[0]) { 81612111Sralph (void) write(ofd,"\n\n\n",3); 81712111Sralph scan_out(ofd, class, '\0'); 81812111Sralph } 81912111Sralph (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15); 82012111Sralph (void) write(ofd, name2, strlen(name2)); 82112111Sralph (void) write(ofd, "\n\t\t\t\t\tDate: ", 12); 82212111Sralph (void) write(ofd, ctime(&tvec), 24); 82312111Sralph (void) write(ofd, "\n", 1); 82412111Sralph } 82512111Sralph if (!SF) 82612111Sralph (void) write(ofd, FF, strlen(FF)); 82712111Sralph tof = 1; 82812111Sralph } 82912111Sralph 83016762Sralph char * 83112111Sralph scnline(key, p, c) 83212111Sralph register char key, *p; 83312111Sralph char c; 83412111Sralph { 83512111Sralph register scnwidth; 83612111Sralph 83712111Sralph for (scnwidth = WIDTH; --scnwidth;) { 83812111Sralph key <<= 1; 83912111Sralph *p++ = key & 0200 ? c : BACKGND; 84012111Sralph } 84112111Sralph return (p); 84212111Sralph } 84312111Sralph 84412111Sralph #define TRC(q) (((q)-' ')&0177) 84512111Sralph 84612111Sralph scan_out(scfd, scsp, dlm) 84712111Sralph int scfd; 84812111Sralph char *scsp, dlm; 84912111Sralph { 85012111Sralph register char *strp; 85112111Sralph register nchrs, j; 85212111Sralph char outbuf[LINELEN+1], *sp, c, cc; 85312111Sralph int d, scnhgt; 85412111Sralph extern char scnkey[][HEIGHT]; /* in lpdchar.c */ 85512111Sralph 85612111Sralph for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) { 85712111Sralph strp = &outbuf[0]; 85812111Sralph sp = scsp; 85912111Sralph for (nchrs = 0; ; ) { 86012111Sralph d = dropit(c = TRC(cc = *sp++)); 86112111Sralph if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d)) 86212111Sralph for (j = WIDTH; --j;) 86312111Sralph *strp++ = BACKGND; 86412111Sralph else 86512111Sralph strp = scnline(scnkey[c][scnhgt-1-d], strp, cc); 86612111Sralph if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1) 86712111Sralph break; 86812111Sralph *strp++ = BACKGND; 86912111Sralph *strp++ = BACKGND; 87012111Sralph } 87112111Sralph while (*--strp == BACKGND && strp >= outbuf) 87212111Sralph ; 87312111Sralph strp++; 87412111Sralph *strp++ = '\n'; 87512111Sralph (void) write(scfd, outbuf, strp-outbuf); 87612111Sralph } 87712111Sralph } 87812111Sralph 87912111Sralph dropit(c) 88012111Sralph char c; 88112111Sralph { 88212111Sralph switch(c) { 88312111Sralph 88412111Sralph case TRC('_'): 88512111Sralph case TRC(';'): 88612111Sralph case TRC(','): 88712111Sralph case TRC('g'): 88812111Sralph case TRC('j'): 88912111Sralph case TRC('p'): 89012111Sralph case TRC('q'): 89112111Sralph case TRC('y'): 89212111Sralph return (DROP); 89312111Sralph 89412111Sralph default: 89512111Sralph return (0); 89612111Sralph } 89712111Sralph } 89812111Sralph 89912111Sralph /* 90012111Sralph * sendmail --- 90112111Sralph * tell people about job completion 90212111Sralph */ 90315811Sralph sendmail(user, bombed) 90415811Sralph char *user; 90512111Sralph int bombed; 90612111Sralph { 90712111Sralph register int i; 90815811Sralph int p[2], s; 90912111Sralph register char *cp; 91012111Sralph char buf[100]; 91115811Sralph struct stat stb; 91215811Sralph FILE *fp; 91312111Sralph 91412111Sralph pipe(p); 91515811Sralph if ((s = dofork(DORETURN)) == 0) { /* child */ 91612111Sralph dup2(p[0], 0); 91712111Sralph for (i = 3; i < NOFILE; i++) 91812111Sralph (void) close(i); 91912111Sralph if ((cp = rindex(MAIL, '/')) != NULL) 92012111Sralph cp++; 92112111Sralph else 92212111Sralph cp = MAIL; 92315811Sralph sprintf(buf, "%s@%s", user, fromhost); 92412111Sralph execl(MAIL, cp, buf, 0); 92512111Sralph exit(0); 92615811Sralph } else if (s > 0) { /* parent */ 92712111Sralph dup2(p[1], 1); 92815811Sralph printf("To: %s@%s\n", user, fromhost); 92912111Sralph printf("Subject: printer job\n\n"); 93012111Sralph printf("Your printer job "); 93112111Sralph if (*jobname) 93212111Sralph printf("(%s) ", jobname); 93312463Sralph switch (bombed) { 93417463Sralph case OK: 93512463Sralph printf("\ncompleted successfully\n"); 93612463Sralph break; 93712463Sralph default: 93817463Sralph case FATALERR: 93912463Sralph printf("\ncould not be printed\n"); 94012463Sralph break; 94117463Sralph case NOACCT: 94212463Sralph printf("\ncould not be printed without an account on %s\n", host); 94312463Sralph break; 94417463Sralph case FILTERERR: 94515811Sralph if (stat(tmpfile, &stb) < 0 || stb.st_size == 0 || 94615811Sralph (fp = fopen(tmpfile, "r")) == NULL) { 94715811Sralph printf("\nwas printed but had some errors\n"); 94815811Sralph break; 94915811Sralph } 95015811Sralph printf("\nwas printed but had the following errors:\n"); 95115811Sralph while ((i = getc(fp)) != EOF) 95215811Sralph putchar(i); 95315811Sralph (void) fclose(fp); 95417463Sralph break; 95517463Sralph case ACCESS: 95617463Sralph printf("\nwas not printed because it was not linked to the original file\n"); 95712463Sralph } 95812111Sralph fflush(stdout); 95912111Sralph (void) close(1); 96012111Sralph } 96112111Sralph (void) close(p[0]); 96212111Sralph (void) close(p[1]); 96315811Sralph wait(&s); 96412111Sralph } 96512111Sralph 96612111Sralph /* 96712111Sralph * dofork - fork with retries on failure 96812111Sralph */ 96912111Sralph dofork(action) 97012111Sralph int action; 97112111Sralph { 97212111Sralph register int i, pid; 97312111Sralph 97412111Sralph for (i = 0; i < 20; i++) { 97512463Sralph if ((pid = fork()) < 0) { 97612111Sralph sleep((unsigned)(i*i)); 97712463Sralph continue; 97812463Sralph } 97912463Sralph /* 98012463Sralph * Child should run as daemon instead of root 98112463Sralph */ 98212463Sralph if (pid == 0) 98312463Sralph setuid(DU); 98412463Sralph return(pid); 98512111Sralph } 98616762Sralph syslog(LOG_ERR, "can't fork"); 98712111Sralph 98812111Sralph switch (action) { 98912111Sralph case DORETURN: 99012111Sralph return (-1); 99112111Sralph default: 99216762Sralph syslog(LOG_ERR, "bad action (%d) to dofork", action); 99312111Sralph /*FALL THRU*/ 99412111Sralph case DOABORT: 99512111Sralph exit(1); 99612111Sralph } 99712111Sralph /*NOTREACHED*/ 99812111Sralph } 99912111Sralph 100012111Sralph /* 100116762Sralph * Kill child processes to abort current job. 100212111Sralph */ 100316762Sralph abortpr() 100412111Sralph { 100515811Sralph (void) unlink(tmpfile); 100612111Sralph kill(0, SIGINT); 100712111Sralph if (ofilter > 0) 100812111Sralph kill(ofilter, SIGCONT); 100912111Sralph while (wait(0) > 0) 101012111Sralph ; 101112111Sralph exit(0); 101212111Sralph } 101312111Sralph 101412111Sralph init() 101512111Sralph { 101612111Sralph int status; 101712111Sralph 101825468Stef if ((status = pgetent(line, printer)) < 0) { 101925468Stef syslog(LOG_ERR, "can't open printer description file"); 102025468Stef exit(1); 102125468Stef } else if (status == 0) { 102225468Stef syslog(LOG_ERR, "unknown printer: %s", printer); 102325468Stef exit(1); 102425468Stef } 102512111Sralph if ((LP = pgetstr("lp", &bp)) == NULL) 102612111Sralph LP = DEFDEVLP; 102712111Sralph if ((RP = pgetstr("rp", &bp)) == NULL) 102812463Sralph RP = DEFLP; 102912111Sralph if ((LO = pgetstr("lo", &bp)) == NULL) 103012111Sralph LO = DEFLOCK; 103112111Sralph if ((ST = pgetstr("st", &bp)) == NULL) 103212111Sralph ST = DEFSTAT; 103312111Sralph if ((LF = pgetstr("lf", &bp)) == NULL) 103412111Sralph LF = DEFLOGF; 103512111Sralph if ((SD = pgetstr("sd", &bp)) == NULL) 103612111Sralph SD = DEFSPOOL; 103712111Sralph if ((DU = pgetnum("du")) < 0) 103812111Sralph DU = DEFUID; 103912111Sralph if ((FF = pgetstr("ff", &bp)) == NULL) 104012111Sralph FF = DEFFF; 104112111Sralph if ((PW = pgetnum("pw")) < 0) 104212111Sralph PW = DEFWIDTH; 104312111Sralph sprintf(&width[2], "%d", PW); 104412111Sralph if ((PL = pgetnum("pl")) < 0) 104512111Sralph PL = DEFLENGTH; 104612111Sralph sprintf(&length[2], "%d", PL); 104712463Sralph if ((PX = pgetnum("px")) < 0) 104812463Sralph PX = 0; 104912463Sralph sprintf(&pxwidth[2], "%d", PX); 105012463Sralph if ((PY = pgetnum("py")) < 0) 105112463Sralph PY = 0; 105212463Sralph sprintf(&pxlength[2], "%d", PY); 105312111Sralph RM = pgetstr("rm", &bp); 105425468Stef /* 105525468Stef * Figure out whether the local machine is the same as the remote 105625468Stef * machine entry (if it exists). If not, then ignore the local 105725468Stef * queue information. 105825468Stef */ 105925468Stef if (RM != (char *) NULL) { 106025468Stef char name[256]; 106125468Stef struct hostent *hp; 106225468Stef 106325468Stef /* get the standard network name of the local host */ 106425468Stef gethostname(name, sizeof(name)); 106525468Stef name[sizeof(name)-1] = '\0'; 106625468Stef hp = gethostbyname(name); 106725468Stef if (hp == (struct hostent *) NULL) { 106825468Stef syslog(LOG_ERR, 106925468Stef "unable to get network name for local machine %s", 107025468Stef name); 107125468Stef goto localcheck_done; 107225468Stef } else strcpy(name, hp->h_name); 107325468Stef 107425468Stef /* get the standard network name of RM */ 107525468Stef hp = gethostbyname(RM); 107625468Stef if (hp == (struct hostent *) NULL) { 107725468Stef syslog(LOG_ERR, 107825468Stef "unable to get hostname for remote machine %s", RM); 107925468Stef goto localcheck_done; 108025468Stef } 108125468Stef 108225468Stef /* if printer is not on local machine, ignore LP */ 108325468Stef if (strcmp(name, hp->h_name) != 0) *LP = '\0'; 108425468Stef } 108525468Stef localcheck_done: 108625468Stef 108712111Sralph AF = pgetstr("af", &bp); 108812111Sralph OF = pgetstr("of", &bp); 108912111Sralph IF = pgetstr("if", &bp); 109012463Sralph RF = pgetstr("rf", &bp); 109112111Sralph TF = pgetstr("tf", &bp); 109213233Sralph NF = pgetstr("nf", &bp); 109312111Sralph DF = pgetstr("df", &bp); 109412111Sralph GF = pgetstr("gf", &bp); 109512111Sralph VF = pgetstr("vf", &bp); 109612111Sralph CF = pgetstr("cf", &bp); 109712111Sralph TR = pgetstr("tr", &bp); 109812463Sralph RS = pgetflag("rs"); 109912111Sralph SF = pgetflag("sf"); 110012111Sralph SH = pgetflag("sh"); 110112111Sralph SB = pgetflag("sb"); 110218127Sralph HL = pgetflag("hl"); 110312111Sralph RW = pgetflag("rw"); 110412111Sralph BR = pgetnum("br"); 110512111Sralph if ((FC = pgetnum("fc")) < 0) 110612111Sralph FC = 0; 110712111Sralph if ((FS = pgetnum("fs")) < 0) 110812111Sralph FS = 0; 110912111Sralph if ((XC = pgetnum("xc")) < 0) 111012111Sralph XC = 0; 111112111Sralph if ((XS = pgetnum("xs")) < 0) 111212111Sralph XS = 0; 111312581Sralph tof = !pgetflag("fo"); 111412111Sralph } 111512111Sralph 111612463Sralph /* 111712463Sralph * Acquire line printer or remote connection. 111812463Sralph */ 111912463Sralph openpr() 112012463Sralph { 112112463Sralph register int i, n; 112216762Sralph int resp; 112312463Sralph 112412463Sralph if (*LP) { 112512463Sralph for (i = 1; ; i = i < 32 ? i << 1 : i) { 112613148Ssam pfd = open(LP, RW ? O_RDWR : O_WRONLY); 112712463Sralph if (pfd >= 0) 112812463Sralph break; 112912463Sralph if (errno == ENOENT) { 113016762Sralph syslog(LOG_ERR, "%s: %m", LP); 113112463Sralph exit(1); 113212463Sralph } 113312463Sralph if (i == 1) 113412463Sralph status("waiting for %s to become ready (offline ?)", printer); 113512463Sralph sleep(i); 113612463Sralph } 113712463Sralph if (isatty(pfd)) 113812463Sralph setty(); 113912463Sralph status("%s is ready and printing", printer); 114012463Sralph } else if (RM != NULL) { 114116762Sralph for (i = 1; ; i = i < 256 ? i << 1 : i) { 114216762Sralph resp = -1; 114312528Sralph pfd = getport(RM); 114412463Sralph if (pfd >= 0) { 114512463Sralph (void) sprintf(line, "\2%s\n", RP); 114612463Sralph n = strlen(line); 114716762Sralph if (write(pfd, line, n) == n && 114816762Sralph (resp = response()) == '\0') 114912463Sralph break; 115016031Sralph (void) close(pfd); 115112463Sralph } 115216031Sralph if (i == 1) { 115316762Sralph if (resp < 0) 115416031Sralph status("waiting for %s to come up", RM); 115516762Sralph else { 115616031Sralph status("waiting for queue to be enabled on %s", RM); 115716762Sralph i = 256; 115816762Sralph } 115916031Sralph } 116012463Sralph sleep(i); 116112463Sralph } 116212463Sralph status("sending to %s", RM); 116312463Sralph remote = 1; 116412463Sralph } else { 116516762Sralph syslog(LOG_ERR, "%s: no line printer device or host name", 116616762Sralph printer); 116712463Sralph exit(1); 116812463Sralph } 116912463Sralph /* 117012463Sralph * Start up an output filter, if needed. 117112463Sralph */ 117212463Sralph if (OF) { 117312463Sralph int p[2]; 117412463Sralph char *cp; 117512463Sralph 117612463Sralph pipe(p); 117712463Sralph if ((ofilter = dofork(DOABORT)) == 0) { /* child */ 117812463Sralph dup2(p[0], 0); /* pipe is std in */ 117912463Sralph dup2(pfd, 1); /* printer is std out */ 118012463Sralph for (i = 3; i < NOFILE; i++) 118112463Sralph (void) close(i); 118212463Sralph if ((cp = rindex(OF, '/')) == NULL) 118312463Sralph cp = OF; 118412463Sralph else 118512463Sralph cp++; 118612463Sralph execl(OF, cp, width, length, 0); 118716762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, OF); 118812463Sralph exit(1); 118912463Sralph } 119012463Sralph (void) close(p[0]); /* close input side */ 119112463Sralph ofd = p[1]; /* use pipe for output */ 119212463Sralph } else { 119312463Sralph ofd = pfd; 119412463Sralph ofilter = 0; 119512463Sralph } 119612463Sralph } 119712463Sralph 119812111Sralph struct bauds { 119912111Sralph int baud; 120012111Sralph int speed; 120112111Sralph } bauds[] = { 120212111Sralph 50, B50, 120312111Sralph 75, B75, 120412111Sralph 110, B110, 120512111Sralph 134, B134, 120612111Sralph 150, B150, 120712111Sralph 200, B200, 120812111Sralph 300, B300, 120912111Sralph 600, B600, 121012111Sralph 1200, B1200, 121112111Sralph 1800, B1800, 121212111Sralph 2400, B2400, 121312111Sralph 4800, B4800, 121412111Sralph 9600, B9600, 121512111Sralph 19200, EXTA, 121612111Sralph 38400, EXTB, 121712111Sralph 0, 0 121812111Sralph }; 121912111Sralph 122012111Sralph /* 122112111Sralph * setup tty lines. 122212111Sralph */ 122312111Sralph setty() 122412111Sralph { 122512111Sralph struct sgttyb ttybuf; 122612111Sralph register struct bauds *bp; 122712111Sralph 122812111Sralph if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) { 122916762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer); 123012111Sralph exit(1); 123112111Sralph } 123212111Sralph if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) { 123316762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCGETP): %m", printer); 123412111Sralph exit(1); 123512111Sralph } 123612111Sralph if (BR > 0) { 123712111Sralph for (bp = bauds; bp->baud; bp++) 123812111Sralph if (BR == bp->baud) 123912111Sralph break; 124012111Sralph if (!bp->baud) { 124116762Sralph syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR); 124212111Sralph exit(1); 124312111Sralph } 124412111Sralph ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed; 124512111Sralph } 124613169Sralph ttybuf.sg_flags &= ~FC; 124713169Sralph ttybuf.sg_flags |= FS; 124812111Sralph if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) { 124916762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCSETP): %m", printer); 125012111Sralph exit(1); 125112111Sralph } 125217168Sralph if (XC || XS) { 125317168Sralph int ldisc = NTTYDISC; 125417168Sralph 125517168Sralph if (ioctl(pfd, TIOCSETD, &ldisc) < 0) { 125617168Sralph syslog(LOG_ERR, "%s: ioctl(TIOCSETD): %m", printer); 125717168Sralph exit(1); 125817168Sralph } 125917168Sralph } 126012111Sralph if (XC) { 126112111Sralph if (ioctl(pfd, TIOCLBIC, &XC) < 0) { 126216762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCLBIC): %m", printer); 126312111Sralph exit(1); 126412111Sralph } 126512111Sralph } 126612111Sralph if (XS) { 126712111Sralph if (ioctl(pfd, TIOCLBIS, &XS) < 0) { 126816762Sralph syslog(LOG_ERR, "%s: ioctl(TIOCLBIS): %m", printer); 126912111Sralph exit(1); 127012111Sralph } 127112111Sralph } 127212111Sralph } 127312463Sralph 127412463Sralph /*VARARGS1*/ 127512463Sralph status(msg, a1, a2, a3) 127612463Sralph char *msg; 127712463Sralph { 127812463Sralph register int fd; 127912463Sralph char buf[BUFSIZ]; 128012463Sralph 128112463Sralph umask(0); 128213148Ssam fd = open(ST, O_WRONLY|O_CREAT, 0664); 128316762Sralph if (fd < 0 || flock(fd, LOCK_EX) < 0) { 128416762Sralph syslog(LOG_ERR, "%s: %s: %m", printer, ST); 128516762Sralph exit(1); 128616762Sralph } 128713148Ssam ftruncate(fd, 0); 128812463Sralph sprintf(buf, msg, a1, a2, a3); 128912463Sralph strcat(buf, "\n"); 129012463Sralph (void) write(fd, buf, strlen(buf)); 129112463Sralph (void) close(fd); 129212463Sralph } 1293