113954Ssam #ifndef lint 2*15811Sralph static char sccsid[] = "@(#)printjob.c 4.16 (Berkeley) 01/05/84"; 313954Ssam #endif 413954Ssam 512111Sralph /* 612111Sralph * printjob -- print jobs in the queue. 712111Sralph * 812111Sralph * NOTE: the lock file is used to pass information to lpq and lprm. 912111Sralph * it does not need to be removed because file locks are dynamic. 1012111Sralph */ 1112111Sralph 1212111Sralph #include "lp.h" 1312111Sralph 1412877Sralph #define DORETURN 0 /* absorb fork error */ 1512877Sralph #define DOABORT 1 /* abort if dofork fails */ 1612111Sralph 1712877Sralph static char title[80]; /* ``pr'' title */ 1812877Sralph static FILE *cfp; /* control file */ 1912877Sralph static int pfd; /* printer file descriptor */ 2012877Sralph static int ofd; /* output filter file descriptor */ 2112877Sralph static int lfd; /* lock file descriptor */ 2212877Sralph static int pid; /* pid of lpd process */ 2312877Sralph static int prchild; /* id of pr process */ 2412877Sralph static int child; /* id of any filters */ 2512877Sralph static int ofilter; /* id of output filter, if any */ 2612877Sralph static int tof; /* true if at top of form */ 2714150Sralph static int count; /* Number of files actually printed */ 2812877Sralph static int remote; /* true if sending files to remote */ 2912111Sralph 3014150Sralph static char fromhost[32]; /* user's host machine */ 3112877Sralph static char logname[32]; /* user's login name */ 3215552Sralph static char jobname[100]; /* job or file name */ 3312877Sralph static char class[32]; /* classification field */ 3412877Sralph static char width[10] = "-w"; /* page width in characters */ 3512877Sralph static char length[10] = "-l"; /* page length in lines */ 3612877Sralph static char pxwidth[10] = "-x"; /* page width in pixels */ 3712877Sralph static char pxlength[10] = "-y"; /* page length in pixels */ 3812877Sralph static char indent[10] = "-i0"; /* indentation size in characters */ 39*15811Sralph static char tmpfile[] = "errsXXXXXX"; /* file name for filter output */ 4012111Sralph 4112111Sralph printjob() 4212111Sralph { 4312111Sralph struct stat stb; 4412111Sralph register struct queue *q, **qp; 4512111Sralph struct queue **queue; 4612111Sralph register int i, nitems; 4712111Sralph long pidoff; 4812111Sralph extern int onintr(); 4912111Sralph 5012111Sralph init(); /* set up capabilities */ 5113442Sralph (void) write(1, "", 1); /* ack that daemon is started */ 5212877Sralph (void) close(1); /* set up log file */ 5312877Sralph (void) close(2); 5413148Ssam if (open(LF, O_WRONLY|O_APPEND) < 0) 5513148Ssam (void) open("/dev/null", O_WRONLY); 5612877Sralph dup(1); 5712463Sralph pid = getpid(); /* for use with lprm */ 5812111Sralph setpgrp(0, pid); 5914709Sralph signal(SIGHUP, onintr); 6013148Ssam signal(SIGINT, onintr); 6114709Sralph signal(SIGQUIT, onintr); 6214709Sralph signal(SIGTERM, onintr); 6312111Sralph 64*15811Sralph (void) mktemp(tmpfile); 65*15811Sralph 6612111Sralph /* 6712111Sralph * uses short form file names 6812111Sralph */ 6912111Sralph if (chdir(SD) < 0) { 7012111Sralph log("cannot chdir to %s", SD); 7112111Sralph exit(1); 7212111Sralph } 7312463Sralph if (stat(LO, &stb) == 0 && (stb.st_mode & 0100)) 7412463Sralph exit(0); /* printing disabled */ 7514150Sralph lfd = open(LO, O_WRONLY|O_CREAT, 0644); 7613169Sralph if (lfd < 0) { 7713169Sralph log("cannot create %s", LO); 7813169Sralph exit(1); 7913169Sralph } 8013169Sralph if (flock(lfd, LOCK_EX|LOCK_NB) < 0) { 8112111Sralph if (errno == EWOULDBLOCK) /* active deamon present */ 8212111Sralph exit(0); 8313169Sralph log("cannot lock %s", LO); 8412111Sralph exit(1); 8512111Sralph } 8613148Ssam ftruncate(lfd, 0); 8712111Sralph /* 8812111Sralph * write process id for others to know 8912111Sralph */ 9012111Sralph sprintf(line, "%u\n", pid); 9112111Sralph pidoff = i = strlen(line); 9212463Sralph if (write(lfd, line, i) != i) { 9312111Sralph log("cannot write daemon pid"); 9412111Sralph exit(1); 9512111Sralph } 9612111Sralph /* 9712111Sralph * search the spool directory for work and sort by queue order. 9812111Sralph */ 9912111Sralph if ((nitems = getq(&queue)) < 0) { 10012111Sralph log("can't scan spool directory %s", SD); 10112111Sralph exit(1); 10212111Sralph } 10312463Sralph if (nitems == 0) /* no work to do */ 10412111Sralph exit(0); 10513169Sralph if (stb.st_mode & 01) { /* reset queue flag */ 10613169Sralph if (fchmod(lfd, stb.st_mode & 0776) < 0) 10713169Sralph log("cannot chmod %s", LO); 10813169Sralph } 10912463Sralph openpr(); /* open printer or remote */ 11012463Sralph again: 11112111Sralph /* 11212111Sralph * we found something to do now do it -- 11312111Sralph * write the name of the current control file into the lock file 11412111Sralph * so the spool queue program can tell what we're working on 11512111Sralph */ 11612111Sralph for (qp = queue; nitems--; free((char *) q)) { 11712111Sralph q = *qp++; 11812111Sralph if (stat(q->q_name, &stb) < 0) 11912111Sralph continue; 12012463Sralph restart: 12112111Sralph (void) lseek(lfd, pidoff, 0); 12212111Sralph (void) sprintf(line, "%s\n", q->q_name); 12312111Sralph i = strlen(line); 12412111Sralph if (write(lfd, line, i) != i) 12512111Sralph log("can't write (%d) control file name", errno); 12612111Sralph if (!remote) 12712111Sralph i = printit(q->q_name); 12812111Sralph else 12912111Sralph i = sendit(q->q_name); 13012463Sralph /* 13113169Sralph * Check to see if we are supposed to stop printing or 13213169Sralph * if we are to rebuild the queue. 13312463Sralph */ 13413169Sralph if (fstat(lfd, &stb) == 0) { 13513169Sralph if (stb.st_mode & 0100) 13613169Sralph goto done; 13713169Sralph if (stb.st_mode & 01) { 13813169Sralph for (free((char *) q); nitems--; free((char *) q)) 13913169Sralph q = *qp++; 14013169Sralph if (fchmod(lfd, stb.st_mode & 0776) < 0) 14113169Sralph log("cannot chmod %s", LO); 14213169Sralph break; 14313169Sralph } 14413169Sralph } 14514150Sralph if (i == 0) /* file ok and printed */ 14614150Sralph count++; 14714150Sralph else if (i > 0) { /* try reprinting the job */ 14812111Sralph log("restarting"); 14912111Sralph if (ofilter > 0) { 15012111Sralph kill(ofilter, SIGCONT); /* to be sure */ 15112111Sralph (void) close(ofd); 15212111Sralph while ((i = wait(0)) > 0 && i != ofilter) 15312111Sralph ; 15412111Sralph ofilter = 0; 15512111Sralph } 15612463Sralph (void) close(pfd); /* close printer */ 157*15811Sralph if (ftruncate(lfd, pidoff) < 0) 158*15811Sralph log("can't truncate lock file (%d)", errno); 15912463Sralph openpr(); /* try to reopen printer */ 16012111Sralph goto restart; 16112111Sralph } 16212111Sralph } 16312111Sralph free((char *) queue); 16412463Sralph /* 16512463Sralph * search the spool directory for more work. 16612463Sralph */ 16712463Sralph if ((nitems = getq(&queue)) < 0) { 16812463Sralph log("can't scan spool directory %s", SD); 16912463Sralph exit(1); 17012463Sralph } 17112463Sralph if (nitems == 0) { /* no more work to do */ 17212463Sralph done: 17314150Sralph if (count > 0) { /* Files actually printed */ 17414150Sralph if (!SF && !tof) 17514150Sralph (void) write(ofd, FF, strlen(FF)); 17614150Sralph if (TR != NULL) /* output trailer */ 17714150Sralph (void) write(ofd, TR, strlen(TR)); 17814150Sralph } 179*15811Sralph (void) unlink(tmpfile); 18012463Sralph exit(0); 18112463Sralph } 18212111Sralph goto again; 18312111Sralph } 18412111Sralph 18512111Sralph char fonts[4][50]; /* fonts for troff */ 18612111Sralph 18712111Sralph static char ifonts[4][18] = { 18812111Sralph "/usr/lib/vfont/R", 18912111Sralph "/usr/lib/vfont/I", 19012111Sralph "/usr/lib/vfont/B", 19112111Sralph "/usr/lib/vfont/S" 19212111Sralph }; 19312111Sralph 19412111Sralph /* 19512111Sralph * The remaining part is the reading of the control file (cf) 19612111Sralph * and performing the various actions. 19712111Sralph * Returns 0 if everthing was OK, 1 if we should try to reprint the job and 19812111Sralph * -1 if a non-recoverable error occured. 19912111Sralph */ 20012877Sralph static 20112111Sralph printit(file) 20212111Sralph char *file; 20312111Sralph { 20412111Sralph register int i; 20512111Sralph int bombed = 0; 20612111Sralph 20712111Sralph /* 20812111Sralph * open control file 20912111Sralph */ 21012111Sralph if ((cfp = fopen(file, "r")) == NULL) { 21112111Sralph log("control file (%s) open failure <errno = %d>", file, errno); 21212111Sralph return(0); 21312111Sralph } 21412111Sralph /* 21512111Sralph * Reset troff fonts. 21612111Sralph */ 21712111Sralph for (i = 0; i < 4; i++) 21812111Sralph strcpy(fonts[i], ifonts[i]); 21912111Sralph 22012111Sralph /* 22112111Sralph * read the control file for work to do 22212111Sralph * 22312111Sralph * file format -- first character in the line is a command 22412111Sralph * rest of the line is the argument. 22512111Sralph * valid commands are: 22612111Sralph * 22712111Sralph * J -- "job name" on banner page 22812111Sralph * C -- "class name" on banner page 22912111Sralph * L -- "literal" user's name to print on banner 23012111Sralph * T -- "title" for pr 23112111Sralph * H -- "host name" of machine where lpr was done 23212111Sralph * P -- "person" user's login name 23312581Sralph * I -- "indent" amount to indent output 23412111Sralph * f -- "file name" name of text file to print 23512111Sralph * l -- "file name" text file with control chars 23612111Sralph * p -- "file name" text file to print with pr(1) 23712111Sralph * t -- "file name" troff(1) file to print 23813233Sralph * n -- "file name" ditroff(1) file to print 23912111Sralph * d -- "file name" dvi file to print 24012111Sralph * g -- "file name" plot(1G) file to print 24112111Sralph * v -- "file name" plain raster file to print 24212111Sralph * c -- "file name" cifplot file to print 24312111Sralph * 1 -- "R font file" for troff 24412111Sralph * 2 -- "I font file" for troff 24512111Sralph * 3 -- "B font file" for troff 24612111Sralph * 4 -- "S font file" for troff 24712111Sralph * N -- "name" of file (used by lpq) 24812111Sralph * U -- "unlink" name of file to remove 24912111Sralph * (after we print it. (Pass 2 only)). 25012111Sralph * M -- "mail" to user when done printing 25112111Sralph * 25212111Sralph * getline reads a line and expands tabs to blanks 25312111Sralph */ 25412111Sralph 25512111Sralph /* pass 1 */ 25612111Sralph 25712111Sralph while (getline(cfp)) 25812111Sralph switch (line[0]) { 25912111Sralph case 'H': 26014150Sralph strcpy(fromhost, line+1); 26112111Sralph if (class[0] == '\0') 26215552Sralph strncpy(class, line+1, sizeof(class)-1); 26312111Sralph continue; 26412111Sralph 26512111Sralph case 'P': 26615552Sralph strncpy(logname, line+1, sizeof(logname)-1); 26712463Sralph if (RS) { /* restricted */ 26812463Sralph if (getpwnam(logname) == (struct passwd *)0) { 26912463Sralph bombed = 2; 270*15811Sralph sendmail(line+1, bombed); 27112463Sralph goto pass2; 27212463Sralph } 27312463Sralph } 27412111Sralph continue; 27512111Sralph 27612111Sralph case 'J': 27712111Sralph if (line[1] != '\0') 27815552Sralph strncpy(jobname, line+1, sizeof(jobname)-1); 27912111Sralph else 28012111Sralph strcpy(jobname, " "); 28112111Sralph continue; 28212111Sralph 28312111Sralph case 'C': 28412111Sralph if (line[1] != '\0') 28515552Sralph strncpy(class, line+1, sizeof(class)-1); 28612111Sralph else if (class[0] == '\0') 287*15811Sralph gethostname(class, sizeof(class)); 28812111Sralph continue; 28912111Sralph 29012111Sralph case 'T': /* header title for pr */ 29115552Sralph strncpy(title, line+1, sizeof(title)-1); 29212111Sralph continue; 29312111Sralph 29412111Sralph case 'L': /* identification line */ 29512111Sralph if (!SH) 29612111Sralph banner(line+1, jobname); 29712111Sralph continue; 29812111Sralph 29912111Sralph case '1': /* troff fonts */ 30012111Sralph case '2': 30112111Sralph case '3': 30212111Sralph case '4': 30312111Sralph if (line[1] != '\0') 30412111Sralph strcpy(fonts[line[0]-'1'], line+1); 30512111Sralph continue; 30612111Sralph 30712111Sralph case 'W': /* page width */ 30815552Sralph strncpy(width+2, line+1, sizeof(width)-3); 30912111Sralph continue; 31012111Sralph 31112581Sralph case 'I': /* indent amount */ 31215552Sralph strncpy(indent+2, line+1, sizeof(indent)-3); 31312581Sralph continue; 31412581Sralph 31512111Sralph default: /* some file to print */ 316*15811Sralph switch (i = print(line[0], line+1)) { 317*15811Sralph case -1: 318*15811Sralph if (!bombed) 319*15811Sralph bombed = 1; 320*15811Sralph break; 321*15811Sralph case 1: 32212111Sralph (void) fclose(cfp); 32312111Sralph return(1); 324*15811Sralph case 2: 325*15811Sralph bombed = 3; 326*15811Sralph sendmail(logname, bombed); 327*15811Sralph } 32812111Sralph title[0] = '\0'; 32912111Sralph continue; 33012111Sralph 33112111Sralph case 'N': 33212111Sralph case 'U': 33312111Sralph case 'M': 33412111Sralph continue; 33512111Sralph } 33612111Sralph 33712111Sralph /* pass 2 */ 33812111Sralph 33912463Sralph pass2: 34012111Sralph fseek(cfp, 0L, 0); 34112111Sralph while (getline(cfp)) 34212111Sralph switch (line[0]) { 34312111Sralph case 'M': 344*15811Sralph if (bombed < 2) /* already sent if >= 2 */ 345*15811Sralph sendmail(line+1, bombed); 34612111Sralph continue; 34712111Sralph 34812111Sralph case 'U': 34912111Sralph (void) unlink(line+1); 35012111Sralph } 35112111Sralph /* 352*15811Sralph * clean-up in case another control file exists 35312111Sralph */ 35412111Sralph (void) fclose(cfp); 35512111Sralph (void) unlink(file); 35614150Sralph return(bombed ? -1 : 0); 35712111Sralph } 35812111Sralph 35912111Sralph /* 36012111Sralph * Print a file. 36113233Sralph * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}. 362*15811Sralph * Return -1 if a non-recoverable error occured, 363*15811Sralph * 2 if the filter detected some errors (but printed the job anyway), 364*15811Sralph * 1 if we should try to reprint this job and 36512111Sralph * 0 if all is well. 36612111Sralph * Note: all filters take stdin as the file, stdout as the printer, 36712111Sralph * stderr as the log file, and must not ignore SIGINT. 36812111Sralph */ 36912877Sralph static 37012111Sralph print(format, file) 37112111Sralph int format; 37212111Sralph char *file; 37312111Sralph { 374*15811Sralph register int n; 37512111Sralph register char *prog; 376*15811Sralph int fi, fo; 37712111Sralph char *av[15], buf[BUFSIZ]; 37812111Sralph int pid, p[2], stopped = 0; 37912111Sralph union wait status; 38012111Sralph 38113148Ssam if ((fi = open(file, O_RDONLY)) < 0) { 38212111Sralph log("%s: open failure <errno = %d>", file, errno); 38312111Sralph return(-1); 38412111Sralph } 38512111Sralph if (!SF && !tof) { /* start on a fresh page */ 38612111Sralph (void) write(ofd, FF, strlen(FF)); 38712111Sralph tof = 1; 38812111Sralph } 38912111Sralph if (IF == NULL && (format == 'f' || format == 'l')) { 39012111Sralph tof = 0; 39112111Sralph while ((n = read(fi, buf, BUFSIZ)) > 0) 39212111Sralph if (write(ofd, buf, n) != n) { 39312111Sralph (void) close(fi); 39412111Sralph return(1); 39512111Sralph } 39612111Sralph (void) close(fi); 39712111Sralph return(0); 39812111Sralph } 39912111Sralph switch (format) { 40012111Sralph case 'p': /* print file using 'pr' */ 40112111Sralph if (IF == NULL) { /* use output filter */ 40212111Sralph prog = PR; 40312111Sralph av[0] = "pr"; 40412111Sralph av[1] = width; 40512111Sralph av[2] = length; 40612111Sralph av[3] = "-h"; 40712111Sralph av[4] = *title ? title : " "; 40812111Sralph av[5] = 0; 40912111Sralph fo = ofd; 41012111Sralph goto start; 41112111Sralph } 41212111Sralph pipe(p); 41312111Sralph if ((prchild = dofork(DORETURN)) == 0) { /* child */ 41412111Sralph dup2(fi, 0); /* file is stdin */ 41512111Sralph dup2(p[1], 1); /* pipe is stdout */ 41612111Sralph for (n = 3; n < NOFILE; n++) 41712111Sralph (void) close(n); 41812111Sralph execl(PR, "pr", width, length, "-h", *title ? title : " ", 0); 41912111Sralph log("cannot execl %s", PR); 42012111Sralph exit(2); 42112111Sralph } 42212111Sralph (void) close(p[1]); /* close output side */ 42312111Sralph (void) close(fi); 42412111Sralph if (prchild < 0) { 42512111Sralph prchild = 0; 42612111Sralph (void) close(p[0]); 42712111Sralph return(-1); 42812111Sralph } 42912111Sralph fi = p[0]; /* use pipe for input */ 43012111Sralph case 'f': /* print plain text file */ 43112111Sralph prog = IF; 43212111Sralph av[1] = width; 43312111Sralph av[2] = length; 43412581Sralph av[3] = indent; 43512581Sralph n = 4; 43612111Sralph break; 43712111Sralph case 'l': /* like 'f' but pass control characters */ 43812111Sralph prog = IF; 43914325Sralph av[1] = "-c"; 44012111Sralph av[2] = width; 44112111Sralph av[3] = length; 44212581Sralph av[4] = indent; 44312581Sralph n = 5; 44412111Sralph break; 44512463Sralph case 'r': /* print a fortran text file */ 44612463Sralph prog = RF; 44712463Sralph av[1] = width; 44812463Sralph av[2] = length; 44912463Sralph n = 3; 45012463Sralph break; 45112111Sralph case 't': /* print troff output */ 45213233Sralph case 'n': /* print ditroff output */ 45312463Sralph case 'd': /* print tex output */ 45412111Sralph (void) unlink(".railmag"); 45512463Sralph if ((fo = creat(".railmag", FILMOD)) < 0) { 45612111Sralph log("cannot create .railmag"); 45712111Sralph (void) unlink(".railmag"); 45812111Sralph } else { 45912111Sralph for (n = 0; n < 4; n++) { 46012111Sralph if (fonts[n][0] != '/') 46112111Sralph (void) write(fo, "/usr/lib/vfont/", 15); 46212111Sralph (void) write(fo, fonts[n], strlen(fonts[n])); 46312111Sralph (void) write(fo, "\n", 1); 46412111Sralph } 46512111Sralph (void) close(fo); 46612111Sralph } 46713233Sralph prog = (format == 't') ? TF : (format == 'n') ? NF : DF; 46812463Sralph av[1] = pxwidth; 46912463Sralph av[2] = pxlength; 47012463Sralph n = 3; 47112111Sralph break; 47212111Sralph case 'c': /* print cifplot output */ 47312111Sralph prog = CF; 47412463Sralph av[1] = pxwidth; 47512463Sralph av[2] = pxlength; 47612463Sralph n = 3; 47712111Sralph break; 47812111Sralph case 'g': /* print plot(1G) output */ 47912111Sralph prog = GF; 48012463Sralph av[1] = pxwidth; 48112463Sralph av[2] = pxlength; 48212463Sralph n = 3; 48312111Sralph break; 48412111Sralph case 'v': /* print raster output */ 48512111Sralph prog = VF; 48612463Sralph av[1] = pxwidth; 48712463Sralph av[2] = pxlength; 48812463Sralph n = 3; 48912111Sralph break; 49012111Sralph default: 49112111Sralph (void) close(fi); 49212111Sralph log("illegal format character '%c'", format); 49312111Sralph return(-1); 49412111Sralph } 49512111Sralph if ((av[0] = rindex(prog, '/')) != NULL) 49612111Sralph av[0]++; 49712111Sralph else 49812111Sralph av[0] = prog; 49912111Sralph av[n++] = "-n"; 50012111Sralph av[n++] = logname; 50112111Sralph av[n++] = "-h"; 50214150Sralph av[n++] = fromhost; 50312111Sralph av[n++] = AF; 50412111Sralph av[n] = 0; 50512111Sralph fo = pfd; 50612111Sralph if (ofilter > 0) { /* stop output filter */ 50712111Sralph write(ofd, "\031\1", 2); 50812111Sralph while ((pid = wait3(&status, WUNTRACED, 0)) > 0 && pid != ofilter) 50912111Sralph ; 51012111Sralph if (status.w_stopval != WSTOPPED) { 51112111Sralph (void) close(fi); 51212111Sralph log("output filter died (%d)", status.w_retcode); 51312111Sralph return(1); 51412111Sralph } 51512111Sralph stopped++; 51612111Sralph } 51712111Sralph start: 51812111Sralph if ((child = dofork(DORETURN)) == 0) { /* child */ 51912111Sralph dup2(fi, 0); 52012111Sralph dup2(fo, 1); 521*15811Sralph n = open(tmpfile, O_WRONLY|O_CREAT, 0664); 522*15811Sralph if (n >= 0) 523*15811Sralph dup2(n, 2); 52412111Sralph for (n = 3; n < NOFILE; n++) 52512111Sralph (void) close(n); 52612111Sralph execv(prog, av); 52712111Sralph log("cannot execl %s", prog); 52812111Sralph exit(2); 52912111Sralph } 53012111Sralph (void) close(fi); 53112111Sralph if (child < 0) 53212111Sralph status.w_retcode = 100; 53312111Sralph else 53412111Sralph while ((pid = wait(&status)) > 0 && pid != child) 53512111Sralph ; 53612111Sralph child = 0; 53712111Sralph prchild = 0; 53812111Sralph if (stopped) { /* restart output filter */ 53912111Sralph if (kill(ofilter, SIGCONT) < 0) { 54012111Sralph log("cannot restart output filter"); 54112111Sralph exit(1); 54212111Sralph } 54312111Sralph } 54412111Sralph tof = 0; 545*15811Sralph if (!WIFEXITED(status)) { 546*15811Sralph log("Daemon filter '%c' terminated (%d)", format, status.w_termsig); 54712111Sralph return(-1); 548*15811Sralph } else if (status.w_retcode > 2) { 549*15811Sralph log("Daemon filter '%c' exited (%d)", format, status.w_retcode); 550*15811Sralph return(-1); 551*15811Sralph } else if (status.w_retcode == 0) 552*15811Sralph tof = 1; 553*15811Sralph return(status.w_retcode); 55412111Sralph } 55512111Sralph 55612111Sralph /* 55712111Sralph * Send the daemon control file (cf) and any data files. 55812111Sralph * Return -1 if a non-recoverable error occured, 1 if a recoverable error and 55912111Sralph * 0 if all is well. 56012111Sralph */ 56112877Sralph static 56212111Sralph sendit(file) 56312111Sralph char *file; 56412111Sralph { 56512111Sralph register int linelen, err = 0; 56612111Sralph char last[132]; 56712111Sralph 56812111Sralph /* 56912111Sralph * open control file 57012111Sralph */ 57112111Sralph if ((cfp = fopen(file, "r")) == NULL) { 57212111Sralph log("control file (%s) open failure <errno = %d>", file, errno); 57312111Sralph return(0); 57412111Sralph } 57512111Sralph /* 57612111Sralph * read the control file for work to do 57712111Sralph * 57812111Sralph * file format -- first character in the line is a command 57912111Sralph * rest of the line is the argument. 58012111Sralph * commands of interest are: 58112111Sralph * 58212111Sralph * a-z -- "file name" name of file to print 58312111Sralph * U -- "unlink" name of file to remove 58412111Sralph * (after we print it. (Pass 2 only)). 58512111Sralph */ 58612111Sralph 58712111Sralph /* 58812111Sralph * pass 1 58912111Sralph */ 59012111Sralph while (getline(cfp)) { 59112111Sralph again: 59212111Sralph if (line[0] >= 'a' && line[0] <= 'z') { 59312111Sralph strcpy(last, line); 59412111Sralph while (linelen = getline(cfp)) 59512111Sralph if (strcmp(last, line)) 59612111Sralph break; 59712111Sralph if ((err = sendfile('\3', last+1)) > 0) { 59812111Sralph (void) fclose(cfp); 59912111Sralph return(1); 60012111Sralph } else if (err) 60112111Sralph break; 60212111Sralph if (linelen) 60312111Sralph goto again; 60412111Sralph break; 60512111Sralph } 60612111Sralph } 60712111Sralph if (!err && sendfile('\2', file) > 0) { 60812111Sralph (void) fclose(cfp); 60912111Sralph return(1); 61012111Sralph } 61112111Sralph /* 61212111Sralph * pass 2 61312111Sralph */ 61412111Sralph fseek(cfp, 0L, 0); 61512111Sralph while (getline(cfp)) 61612111Sralph if (line[0] == 'U') 61712111Sralph (void) unlink(line+1); 61812111Sralph /* 61912111Sralph * clean-up incase another control file exists 62012111Sralph */ 62112111Sralph (void) fclose(cfp); 62212111Sralph (void) unlink(file); 62312111Sralph return(0); 62412111Sralph } 62512111Sralph 62612111Sralph /* 62712111Sralph * Send a data file to the remote machine and spool it. 62812111Sralph * Return positive if we should try resending. 62912111Sralph */ 63012877Sralph static 63112111Sralph sendfile(type, file) 63212111Sralph char type, *file; 63312111Sralph { 63412111Sralph register int f, i, amt; 63512111Sralph struct stat stb; 63612111Sralph char buf[BUFSIZ]; 63712111Sralph int sizerr; 63812111Sralph 63913148Ssam if ((f = open(file, O_RDONLY)) < 0 || fstat(f, &stb) < 0) { 64012111Sralph log("file (%s) open failure <errno = %d>", file, errno); 64112111Sralph return(-1); 64212111Sralph } 64312111Sralph (void) sprintf(buf, "%c%d %s\n", type, stb.st_size, file); 64412111Sralph amt = strlen(buf); 64512692Sralph if (write(pfd, buf, amt) != amt) { 64612692Sralph (void) close(f); 64712111Sralph return(1); 64812692Sralph } 64912692Sralph if (noresponse()) { 65012692Sralph (void) close(f); 65112111Sralph return(1); 65212692Sralph } 65312111Sralph sizerr = 0; 65412111Sralph for (i = 0; i < stb.st_size; i += BUFSIZ) { 65512111Sralph amt = BUFSIZ; 65612111Sralph if (i + amt > stb.st_size) 65712111Sralph amt = stb.st_size - i; 65812111Sralph if (sizerr == 0 && read(f, buf, amt) != amt) 65912111Sralph sizerr = 1; 66012692Sralph if (write(pfd, buf, amt) != amt) { 66112692Sralph (void) close(f); 66212111Sralph return(1); 66312692Sralph } 66412111Sralph } 66512111Sralph (void) close(f); 66612111Sralph if (sizerr) { 66712111Sralph log("%s: changed size", file); 66812111Sralph (void) write(pfd, "\1", 1); /* tell recvjob to ignore this file */ 66912111Sralph return(-1); 67012111Sralph } 67112111Sralph if (write(pfd, "", 1) != 1) 67212111Sralph return(1); 67312111Sralph if (noresponse()) 67412111Sralph return(1); 67512111Sralph return(0); 67612111Sralph } 67712111Sralph 67812111Sralph /* 67912111Sralph * Check to make sure there have been no errors and that both programs 68012111Sralph * are in sync with eachother. 68112111Sralph * Return non-zero if the connection was lost. 68212111Sralph */ 68312111Sralph static 68412111Sralph noresponse() 68512111Sralph { 68612111Sralph char resp; 68712111Sralph 68812111Sralph if (read(pfd, &resp, 1) != 1 || resp != '\0') { 68912111Sralph log("lost connection or error in recvjob"); 69012111Sralph return(1); 69112111Sralph } 69212111Sralph return(0); 69312111Sralph } 69412111Sralph 69512111Sralph /* 69612111Sralph * Banner printing stuff 69712111Sralph */ 69812877Sralph static 69912111Sralph banner(name1, name2) 70012111Sralph char *name1, *name2; 70112111Sralph { 70212111Sralph time_t tvec; 70312111Sralph extern char *ctime(); 70412111Sralph 70512111Sralph time(&tvec); 70612111Sralph if (!SF && !tof) 70712111Sralph (void) write(ofd, FF, strlen(FF)); 70812111Sralph if (SB) { /* short banner only */ 70912111Sralph if (class[0]) { 71012111Sralph (void) write(ofd, class, strlen(class)); 71112111Sralph (void) write(ofd, ":", 1); 71212111Sralph } 71312111Sralph (void) write(ofd, name1, strlen(name1)); 71412111Sralph (void) write(ofd, " Job: ", 7); 71512111Sralph (void) write(ofd, name2, strlen(name2)); 71612111Sralph (void) write(ofd, " Date: ", 8); 71712111Sralph (void) write(ofd, ctime(&tvec), 24); 71812111Sralph (void) write(ofd, "\n", 1); 71912111Sralph } else { /* normal banner */ 72012111Sralph (void) write(ofd, "\n\n\n", 3); 72112111Sralph scan_out(ofd, name1, '\0'); 72212111Sralph (void) write(ofd, "\n\n", 2); 72312111Sralph scan_out(ofd, name2, '\0'); 72412111Sralph if (class[0]) { 72512111Sralph (void) write(ofd,"\n\n\n",3); 72612111Sralph scan_out(ofd, class, '\0'); 72712111Sralph } 72812111Sralph (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15); 72912111Sralph (void) write(ofd, name2, strlen(name2)); 73012111Sralph (void) write(ofd, "\n\t\t\t\t\tDate: ", 12); 73112111Sralph (void) write(ofd, ctime(&tvec), 24); 73212111Sralph (void) write(ofd, "\n", 1); 73312111Sralph } 73412111Sralph if (!SF) 73512111Sralph (void) write(ofd, FF, strlen(FF)); 73612111Sralph tof = 1; 73712111Sralph } 73812111Sralph 73912877Sralph static char * 74012111Sralph scnline(key, p, c) 74112111Sralph register char key, *p; 74212111Sralph char c; 74312111Sralph { 74412111Sralph register scnwidth; 74512111Sralph 74612111Sralph for (scnwidth = WIDTH; --scnwidth;) { 74712111Sralph key <<= 1; 74812111Sralph *p++ = key & 0200 ? c : BACKGND; 74912111Sralph } 75012111Sralph return (p); 75112111Sralph } 75212111Sralph 75312111Sralph #define TRC(q) (((q)-' ')&0177) 75412111Sralph 75512877Sralph static 75612111Sralph scan_out(scfd, scsp, dlm) 75712111Sralph int scfd; 75812111Sralph char *scsp, dlm; 75912111Sralph { 76012111Sralph register char *strp; 76112111Sralph register nchrs, j; 76212111Sralph char outbuf[LINELEN+1], *sp, c, cc; 76312111Sralph int d, scnhgt; 76412111Sralph extern char scnkey[][HEIGHT]; /* in lpdchar.c */ 76512111Sralph 76612111Sralph for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) { 76712111Sralph strp = &outbuf[0]; 76812111Sralph sp = scsp; 76912111Sralph for (nchrs = 0; ; ) { 77012111Sralph d = dropit(c = TRC(cc = *sp++)); 77112111Sralph if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d)) 77212111Sralph for (j = WIDTH; --j;) 77312111Sralph *strp++ = BACKGND; 77412111Sralph else 77512111Sralph strp = scnline(scnkey[c][scnhgt-1-d], strp, cc); 77612111Sralph if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1) 77712111Sralph break; 77812111Sralph *strp++ = BACKGND; 77912111Sralph *strp++ = BACKGND; 78012111Sralph } 78112111Sralph while (*--strp == BACKGND && strp >= outbuf) 78212111Sralph ; 78312111Sralph strp++; 78412111Sralph *strp++ = '\n'; 78512111Sralph (void) write(scfd, outbuf, strp-outbuf); 78612111Sralph } 78712111Sralph } 78812111Sralph 78912877Sralph static 79012111Sralph dropit(c) 79112111Sralph char c; 79212111Sralph { 79312111Sralph switch(c) { 79412111Sralph 79512111Sralph case TRC('_'): 79612111Sralph case TRC(';'): 79712111Sralph case TRC(','): 79812111Sralph case TRC('g'): 79912111Sralph case TRC('j'): 80012111Sralph case TRC('p'): 80112111Sralph case TRC('q'): 80212111Sralph case TRC('y'): 80312111Sralph return (DROP); 80412111Sralph 80512111Sralph default: 80612111Sralph return (0); 80712111Sralph } 80812111Sralph } 80912111Sralph 81012111Sralph /* 81112111Sralph * sendmail --- 81212111Sralph * tell people about job completion 81312111Sralph */ 81412877Sralph static 815*15811Sralph sendmail(user, bombed) 816*15811Sralph char *user; 81712111Sralph int bombed; 81812111Sralph { 81912111Sralph register int i; 820*15811Sralph int p[2], s; 82112111Sralph register char *cp; 82212111Sralph char buf[100]; 823*15811Sralph struct stat stb; 824*15811Sralph FILE *fp; 82512111Sralph 82612111Sralph pipe(p); 827*15811Sralph if ((s = dofork(DORETURN)) == 0) { /* child */ 82812111Sralph dup2(p[0], 0); 82912111Sralph for (i = 3; i < NOFILE; i++) 83012111Sralph (void) close(i); 83112111Sralph if ((cp = rindex(MAIL, '/')) != NULL) 83212111Sralph cp++; 83312111Sralph else 83412111Sralph cp = MAIL; 835*15811Sralph sprintf(buf, "%s@%s", user, fromhost); 83612111Sralph execl(MAIL, cp, buf, 0); 83712111Sralph exit(0); 838*15811Sralph } else if (s > 0) { /* parent */ 83912111Sralph dup2(p[1], 1); 840*15811Sralph printf("To: %s@%s\n", user, fromhost); 84112111Sralph printf("Subject: printer job\n\n"); 84212111Sralph printf("Your printer job "); 84312111Sralph if (*jobname) 84412111Sralph printf("(%s) ", jobname); 84512463Sralph switch (bombed) { 84612463Sralph case 0: 84712463Sralph printf("\ncompleted successfully\n"); 84812463Sralph break; 84912463Sralph default: 85012463Sralph case 1: 85112463Sralph printf("\ncould not be printed\n"); 85212463Sralph break; 85312463Sralph case 2: 85412463Sralph printf("\ncould not be printed without an account on %s\n", host); 85512463Sralph break; 856*15811Sralph case 3: 857*15811Sralph if (stat(tmpfile, &stb) < 0 || stb.st_size == 0 || 858*15811Sralph (fp = fopen(tmpfile, "r")) == NULL) { 859*15811Sralph printf("\nwas printed but had some errors\n"); 860*15811Sralph break; 861*15811Sralph } 862*15811Sralph printf("\nwas printed but had the following errors:\n"); 863*15811Sralph while ((i = getc(fp)) != EOF) 864*15811Sralph putchar(i); 865*15811Sralph (void) fclose(fp); 86612463Sralph } 86712111Sralph fflush(stdout); 86812111Sralph (void) close(1); 86912111Sralph } 87012111Sralph (void) close(p[0]); 87112111Sralph (void) close(p[1]); 872*15811Sralph wait(&s); 87312111Sralph } 87412111Sralph 87512111Sralph /* 87612111Sralph * dofork - fork with retries on failure 87712111Sralph */ 87812877Sralph static 87912111Sralph dofork(action) 88012111Sralph int action; 88112111Sralph { 88212111Sralph register int i, pid; 88312111Sralph 88412111Sralph for (i = 0; i < 20; i++) { 88512463Sralph if ((pid = fork()) < 0) { 88612111Sralph sleep((unsigned)(i*i)); 88712463Sralph continue; 88812463Sralph } 88912463Sralph /* 89012463Sralph * Child should run as daemon instead of root 89112463Sralph */ 89212463Sralph if (pid == 0) 89312463Sralph setuid(DU); 89412463Sralph return(pid); 89512111Sralph } 89612111Sralph log("can't fork"); 89712111Sralph 89812111Sralph switch (action) { 89912111Sralph case DORETURN: 90012111Sralph return (-1); 90112111Sralph default: 90212111Sralph log("bad action (%d) to dofork", action); 90312111Sralph /*FALL THRU*/ 90412111Sralph case DOABORT: 90512111Sralph exit(1); 90612111Sralph } 90712111Sralph /*NOTREACHED*/ 90812111Sralph } 90912111Sralph 91012111Sralph /* 91114709Sralph * Cleanup child processes when a signal is caught. 91212111Sralph */ 91312877Sralph static 91412111Sralph onintr() 91512111Sralph { 916*15811Sralph (void) unlink(tmpfile); 91712111Sralph kill(0, SIGINT); 91812111Sralph if (ofilter > 0) 91912111Sralph kill(ofilter, SIGCONT); 92012111Sralph while (wait(0) > 0) 92112111Sralph ; 92212111Sralph exit(0); 92312111Sralph } 92412111Sralph 92512877Sralph static 92612111Sralph init() 92712111Sralph { 92812111Sralph int status; 92912111Sralph 93013169Sralph if ((status = pgetent(line, printer)) < 0) 93113169Sralph fatal("can't open printer description file"); 93213169Sralph else if (status == 0) 93313169Sralph fatal("unknown printer"); 93412111Sralph if ((LP = pgetstr("lp", &bp)) == NULL) 93512111Sralph LP = DEFDEVLP; 93612111Sralph if ((RP = pgetstr("rp", &bp)) == NULL) 93712463Sralph RP = DEFLP; 93812111Sralph if ((LO = pgetstr("lo", &bp)) == NULL) 93912111Sralph LO = DEFLOCK; 94012111Sralph if ((ST = pgetstr("st", &bp)) == NULL) 94112111Sralph ST = DEFSTAT; 94212111Sralph if ((LF = pgetstr("lf", &bp)) == NULL) 94312111Sralph LF = DEFLOGF; 94412111Sralph if ((SD = pgetstr("sd", &bp)) == NULL) 94512111Sralph SD = DEFSPOOL; 94612111Sralph if ((DU = pgetnum("du")) < 0) 94712111Sralph DU = DEFUID; 94812111Sralph if ((FF = pgetstr("ff", &bp)) == NULL) 94912111Sralph FF = DEFFF; 95012111Sralph if ((PW = pgetnum("pw")) < 0) 95112111Sralph PW = DEFWIDTH; 95212111Sralph sprintf(&width[2], "%d", PW); 95312111Sralph if ((PL = pgetnum("pl")) < 0) 95412111Sralph PL = DEFLENGTH; 95512111Sralph sprintf(&length[2], "%d", PL); 95612463Sralph if ((PX = pgetnum("px")) < 0) 95712463Sralph PX = 0; 95812463Sralph sprintf(&pxwidth[2], "%d", PX); 95912463Sralph if ((PY = pgetnum("py")) < 0) 96012463Sralph PY = 0; 96112463Sralph sprintf(&pxlength[2], "%d", PY); 96212111Sralph RM = pgetstr("rm", &bp); 96312111Sralph AF = pgetstr("af", &bp); 96412111Sralph OF = pgetstr("of", &bp); 96512111Sralph IF = pgetstr("if", &bp); 96612463Sralph RF = pgetstr("rf", &bp); 96712111Sralph TF = pgetstr("tf", &bp); 96813233Sralph NF = pgetstr("nf", &bp); 96912111Sralph DF = pgetstr("df", &bp); 97012111Sralph GF = pgetstr("gf", &bp); 97112111Sralph VF = pgetstr("vf", &bp); 97212111Sralph CF = pgetstr("cf", &bp); 97312111Sralph TR = pgetstr("tr", &bp); 97412463Sralph RS = pgetflag("rs"); 97512111Sralph SF = pgetflag("sf"); 97612111Sralph SH = pgetflag("sh"); 97712111Sralph SB = pgetflag("sb"); 97812111Sralph RW = pgetflag("rw"); 97912111Sralph BR = pgetnum("br"); 98012111Sralph if ((FC = pgetnum("fc")) < 0) 98112111Sralph FC = 0; 98212111Sralph if ((FS = pgetnum("fs")) < 0) 98312111Sralph FS = 0; 98412111Sralph if ((XC = pgetnum("xc")) < 0) 98512111Sralph XC = 0; 98612111Sralph if ((XS = pgetnum("xs")) < 0) 98712111Sralph XS = 0; 98812581Sralph tof = !pgetflag("fo"); 98912111Sralph } 99012111Sralph 99112463Sralph /* 99212463Sralph * Acquire line printer or remote connection. 99312463Sralph */ 99412877Sralph static 99512463Sralph openpr() 99612463Sralph { 99712463Sralph register int i, n; 99812463Sralph 99912463Sralph if (*LP) { 100012463Sralph for (i = 1; ; i = i < 32 ? i << 1 : i) { 100113148Ssam pfd = open(LP, RW ? O_RDWR : O_WRONLY); 100212463Sralph if (pfd >= 0) 100312463Sralph break; 100412463Sralph if (errno == ENOENT) { 100512463Sralph log("cannot open %s", LP); 100612463Sralph exit(1); 100712463Sralph } 100812463Sralph if (i == 1) 100912463Sralph status("waiting for %s to become ready (offline ?)", printer); 101012463Sralph sleep(i); 101112463Sralph } 101212463Sralph if (isatty(pfd)) 101312463Sralph setty(); 101412463Sralph status("%s is ready and printing", printer); 101512463Sralph } else if (RM != NULL) { 101612463Sralph for (i = 1; ; i = i < 512 ? i << 1 : i) { 101712528Sralph pfd = getport(RM); 101812463Sralph if (pfd >= 0) { 101912463Sralph (void) sprintf(line, "\2%s\n", RP); 102012463Sralph n = strlen(line); 102112463Sralph if (write(pfd, line, n) != n) 102212463Sralph break; 102312463Sralph if (noresponse()) 102412463Sralph (void) close(pfd); 102512463Sralph else 102612463Sralph break; 102712463Sralph } 102812463Sralph if (i == 1) 102912463Sralph status("waiting for %s to come up", RM); 103012463Sralph sleep(i); 103112463Sralph } 103212463Sralph status("sending to %s", RM); 103312463Sralph remote = 1; 103412463Sralph } else { 103512463Sralph log("no line printer device or remote machine name"); 103612463Sralph exit(1); 103712463Sralph } 103812463Sralph /* 103912463Sralph * Start up an output filter, if needed. 104012463Sralph */ 104112463Sralph if (OF) { 104212463Sralph int p[2]; 104312463Sralph char *cp; 104412463Sralph 104512463Sralph pipe(p); 104612463Sralph if ((ofilter = dofork(DOABORT)) == 0) { /* child */ 104712463Sralph dup2(p[0], 0); /* pipe is std in */ 104812463Sralph dup2(pfd, 1); /* printer is std out */ 104912463Sralph for (i = 3; i < NOFILE; i++) 105012463Sralph (void) close(i); 105112463Sralph if ((cp = rindex(OF, '/')) == NULL) 105212463Sralph cp = OF; 105312463Sralph else 105412463Sralph cp++; 105512463Sralph execl(OF, cp, width, length, 0); 105612463Sralph log("can't execl output filter %s", OF); 105712463Sralph exit(1); 105812463Sralph } 105912463Sralph (void) close(p[0]); /* close input side */ 106012463Sralph ofd = p[1]; /* use pipe for output */ 106112463Sralph } else { 106212463Sralph ofd = pfd; 106312463Sralph ofilter = 0; 106412463Sralph } 106512463Sralph } 106612463Sralph 106712111Sralph struct bauds { 106812111Sralph int baud; 106912111Sralph int speed; 107012111Sralph } bauds[] = { 107112111Sralph 50, B50, 107212111Sralph 75, B75, 107312111Sralph 110, B110, 107412111Sralph 134, B134, 107512111Sralph 150, B150, 107612111Sralph 200, B200, 107712111Sralph 300, B300, 107812111Sralph 600, B600, 107912111Sralph 1200, B1200, 108012111Sralph 1800, B1800, 108112111Sralph 2400, B2400, 108212111Sralph 4800, B4800, 108312111Sralph 9600, B9600, 108412111Sralph 19200, EXTA, 108512111Sralph 38400, EXTB, 108612111Sralph 0, 0 108712111Sralph }; 108812111Sralph 108912111Sralph /* 109012111Sralph * setup tty lines. 109112111Sralph */ 109212877Sralph static 109312111Sralph setty() 109412111Sralph { 109512111Sralph struct sgttyb ttybuf; 109612111Sralph register struct bauds *bp; 109712111Sralph 109812111Sralph if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) { 109912111Sralph log("cannot set exclusive-use"); 110012111Sralph exit(1); 110112111Sralph } 110212111Sralph if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) { 110312111Sralph log("cannot get tty parameters"); 110412111Sralph exit(1); 110512111Sralph } 110612111Sralph if (BR > 0) { 110712111Sralph for (bp = bauds; bp->baud; bp++) 110812111Sralph if (BR == bp->baud) 110912111Sralph break; 111012111Sralph if (!bp->baud) { 111112111Sralph log("illegal baud rate %d", BR); 111212111Sralph exit(1); 111312111Sralph } 111412111Sralph ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed; 111512111Sralph } 111613169Sralph ttybuf.sg_flags &= ~FC; 111713169Sralph ttybuf.sg_flags |= FS; 111812111Sralph if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) { 111912111Sralph log("cannot set tty parameters"); 112012111Sralph exit(1); 112112111Sralph } 112212111Sralph if (XC) { 112312111Sralph if (ioctl(pfd, TIOCLBIC, &XC) < 0) { 112412111Sralph log("cannot set local tty parameters"); 112512111Sralph exit(1); 112612111Sralph } 112712111Sralph } 112812111Sralph if (XS) { 112912111Sralph if (ioctl(pfd, TIOCLBIS, &XS) < 0) { 113012111Sralph log("cannot set local tty parameters"); 113112111Sralph exit(1); 113212111Sralph } 113312111Sralph } 113412111Sralph } 113512463Sralph 113612463Sralph /*VARARGS1*/ 113712463Sralph static 113812463Sralph status(msg, a1, a2, a3) 113912463Sralph char *msg; 114012463Sralph { 114112463Sralph register int fd; 114212463Sralph char buf[BUFSIZ]; 114312463Sralph 114412463Sralph umask(0); 114513148Ssam fd = open(ST, O_WRONLY|O_CREAT, 0664); 114613148Ssam if (fd < 0 || flock(fd, LOCK_EX) < 0) 114712463Sralph fatal("cannot create status file"); 114813148Ssam ftruncate(fd, 0); 114912463Sralph sprintf(buf, msg, a1, a2, a3); 115012463Sralph strcat(buf, "\n"); 115112463Sralph (void) write(fd, buf, strlen(buf)); 115212463Sralph (void) close(fd); 115312463Sralph } 1154