1*12528Sralph /* printjob.c 4.3 83/05/18 */ 212111Sralph /* 312111Sralph * printjob -- print jobs in the queue. 412111Sralph * 512111Sralph * NOTE: the lock file is used to pass information to lpq and lprm. 612111Sralph * it does not need to be removed because file locks are dynamic. 712111Sralph */ 812111Sralph 912111Sralph #include "lp.h" 1012111Sralph 1112111Sralph #define DORETURN 0 /* absorb fork error */ 1212111Sralph #define DOABORT 1 /* abort if dofork fails */ 1312111Sralph 1412111Sralph char title[80]; /* ``pr'' title */ 1512111Sralph FILE *cfp; /* control file */ 1612111Sralph int pfd; /* printer file descriptor */ 1712111Sralph int ofd; /* output filter file descriptor */ 1812111Sralph int lfd; /* lock file descriptor */ 1912111Sralph int pid; /* pid of lpd process */ 2012111Sralph int prchild; /* id of pr process */ 2112111Sralph int child; /* id of any filters */ 2212111Sralph int ofilter; /* id of output filter, if any */ 2312111Sralph int tof = 1; /* top of form; init true if open does ff */ 2412111Sralph int remote; /* non zero if sending files to remote */ 2512111Sralph 2612111Sralph extern banner(); /* big character printer */ 2712111Sralph char logname[32]; /* user's login name */ 2812111Sralph char jobname[32]; /* job or file name */ 2912111Sralph char class[32]; /* classification field */ 3012463Sralph char width[10] = "-w"; /* page width in characters */ 3112463Sralph char length[10] = "-l"; /* page length in lines */ 3212463Sralph char pxwidth[10] = "-x"; /* page width in pixels */ 3312463Sralph char pxlength[10] = "-y"; /* page length in pixels */ 3412111Sralph 3512111Sralph printjob() 3612111Sralph { 3712111Sralph struct stat stb; 3812111Sralph register struct queue *q, **qp; 3912111Sralph struct queue **queue; 4012111Sralph register int i, nitems; 4112111Sralph long pidoff; 4212111Sralph extern int onintr(); 4312111Sralph 4412111Sralph init(); /* set up capabilities */ 4512111Sralph (void) close(2); /* set up log file */ 4612111Sralph (void) open(LF, FWRONLY|FAPPEND, 0); 4712463Sralph dup2(2, 1); /* closes original connection */ 4812463Sralph pid = getpid(); /* for use with lprm */ 4912111Sralph setpgrp(0, pid); 5012463Sralph sigset(SIGINT, onintr); 5112111Sralph 5212111Sralph /* 5312111Sralph * uses short form file names 5412111Sralph */ 5512111Sralph if (chdir(SD) < 0) { 5612111Sralph log("cannot chdir to %s", SD); 5712111Sralph exit(1); 5812111Sralph } 5912463Sralph if (stat(LO, &stb) == 0 && (stb.st_mode & 0100)) 6012463Sralph exit(0); /* printing disabled */ 6112111Sralph if ((lfd = open(LO, FWRONLY|FCREATE|FTRUNCATE|FEXLOCK|FNBLOCK, 0664)) < 0) { 6212111Sralph if (errno == EWOULDBLOCK) /* active deamon present */ 6312111Sralph exit(0); 6412111Sralph log("cannot create %s", LO); 6512111Sralph exit(1); 6612111Sralph } 6712111Sralph /* 6812111Sralph * write process id for others to know 6912111Sralph */ 7012111Sralph sprintf(line, "%u\n", pid); 7112111Sralph pidoff = i = strlen(line); 7212463Sralph if (write(lfd, line, i) != i) { 7312111Sralph log("cannot write daemon pid"); 7412111Sralph exit(1); 7512111Sralph } 7612111Sralph /* 7712111Sralph * search the spool directory for work and sort by queue order. 7812111Sralph */ 7912111Sralph if ((nitems = getq(&queue)) < 0) { 8012111Sralph log("can't scan spool directory %s", SD); 8112111Sralph exit(1); 8212111Sralph } 8312463Sralph if (nitems == 0) /* no work to do */ 8412111Sralph exit(0); 8512463Sralph openpr(); /* open printer or remote */ 8612463Sralph again: 8712111Sralph /* 8812111Sralph * we found something to do now do it -- 8912111Sralph * write the name of the current control file into the lock file 9012111Sralph * so the spool queue program can tell what we're working on 9112111Sralph */ 9212111Sralph for (qp = queue; nitems--; free((char *) q)) { 9312111Sralph q = *qp++; 9412111Sralph if (stat(q->q_name, &stb) < 0) 9512111Sralph continue; 9612463Sralph restart: 9712111Sralph (void) lseek(lfd, pidoff, 0); 9812111Sralph (void) sprintf(line, "%s\n", q->q_name); 9912111Sralph i = strlen(line); 10012111Sralph if (write(lfd, line, i) != i) 10112111Sralph log("can't write (%d) control file name", errno); 10212111Sralph if (!remote) 10312111Sralph i = printit(q->q_name); 10412111Sralph else 10512111Sralph i = sendit(q->q_name); 10612463Sralph /* 10712463Sralph * Check to see if we are supposed to stop printing. 10812463Sralph */ 10912463Sralph if (stat(LO, &stb) == 0 && (stb.st_mode & 0100)) 11012463Sralph goto done; 11112463Sralph /* 11212463Sralph * Check to see if we should try reprinting the job. 11312463Sralph */ 11412463Sralph if (i > 0) { 11512111Sralph log("restarting"); 11612111Sralph if (ofilter > 0) { 11712111Sralph kill(ofilter, SIGCONT); /* to be sure */ 11812111Sralph (void) close(ofd); 11912111Sralph while ((i = wait(0)) > 0 && i != ofilter) 12012111Sralph ; 12112111Sralph ofilter = 0; 12212111Sralph } 12312463Sralph (void) close(pfd); /* close printer */ 12412463Sralph (void) lseek(lfd, pidoff, 0); 12512463Sralph if (write(lfd, "\n", 1) != 1) 12612463Sralph log("can't write (%d) control file name", errno); 12712463Sralph openpr(); /* try to reopen printer */ 12812111Sralph goto restart; 12912111Sralph } 13012111Sralph } 13112111Sralph free((char *) queue); 13212463Sralph /* 13312463Sralph * search the spool directory for more work. 13412463Sralph */ 13512463Sralph if ((nitems = getq(&queue)) < 0) { 13612463Sralph log("can't scan spool directory %s", SD); 13712463Sralph exit(1); 13812463Sralph } 13912463Sralph if (nitems == 0) { /* no more work to do */ 14012463Sralph done: 14112463Sralph if (!SF && !tof) 14212463Sralph (void) write(ofd, FF, strlen(FF)); 14312463Sralph if (TR != NULL) /* output trailer */ 14412463Sralph (void) write(ofd, TR, strlen(TR)); 14512463Sralph exit(0); 14612463Sralph } 14712111Sralph goto again; 14812111Sralph } 14912111Sralph 15012111Sralph char fonts[4][50]; /* fonts for troff */ 15112111Sralph 15212111Sralph static char ifonts[4][18] = { 15312111Sralph "/usr/lib/vfont/R", 15412111Sralph "/usr/lib/vfont/I", 15512111Sralph "/usr/lib/vfont/B", 15612111Sralph "/usr/lib/vfont/S" 15712111Sralph }; 15812111Sralph 15912111Sralph /* 16012111Sralph * The remaining part is the reading of the control file (cf) 16112111Sralph * and performing the various actions. 16212111Sralph * Returns 0 if everthing was OK, 1 if we should try to reprint the job and 16312111Sralph * -1 if a non-recoverable error occured. 16412111Sralph */ 16512111Sralph printit(file) 16612111Sralph char *file; 16712111Sralph { 16812111Sralph register int i; 16912111Sralph int bombed = 0; 17012111Sralph 17112111Sralph /* 17212111Sralph * open control file 17312111Sralph */ 17412111Sralph if ((cfp = fopen(file, "r")) == NULL) { 17512111Sralph log("control file (%s) open failure <errno = %d>", file, errno); 17612111Sralph return(0); 17712111Sralph } 17812111Sralph /* 17912111Sralph * Reset troff fonts. 18012111Sralph */ 18112111Sralph for (i = 0; i < 4; i++) 18212111Sralph strcpy(fonts[i], ifonts[i]); 18312111Sralph 18412111Sralph /* 18512111Sralph * read the control file for work to do 18612111Sralph * 18712111Sralph * file format -- first character in the line is a command 18812111Sralph * rest of the line is the argument. 18912111Sralph * valid commands are: 19012111Sralph * 19112111Sralph * J -- "job name" on banner page 19212111Sralph * C -- "class name" on banner page 19312111Sralph * L -- "literal" user's name to print on banner 19412111Sralph * T -- "title" for pr 19512111Sralph * H -- "host name" of machine where lpr was done 19612111Sralph * P -- "person" user's login name 19712111Sralph * I -- "indent" changes default indents driver 19812111Sralph * must have stty/gtty avaialble 19912111Sralph * f -- "file name" name of text file to print 20012111Sralph * l -- "file name" text file with control chars 20112111Sralph * p -- "file name" text file to print with pr(1) 20212111Sralph * t -- "file name" troff(1) file to print 20312111Sralph * d -- "file name" dvi file to print 20412111Sralph * g -- "file name" plot(1G) file to print 20512111Sralph * v -- "file name" plain raster file to print 20612111Sralph * c -- "file name" cifplot file to print 20712111Sralph * 1 -- "R font file" for troff 20812111Sralph * 2 -- "I font file" for troff 20912111Sralph * 3 -- "B font file" for troff 21012111Sralph * 4 -- "S font file" for troff 21112111Sralph * N -- "name" of file (used by lpq) 21212111Sralph * U -- "unlink" name of file to remove 21312111Sralph * (after we print it. (Pass 2 only)). 21412111Sralph * M -- "mail" to user when done printing 21512111Sralph * 21612111Sralph * getline reads a line and expands tabs to blanks 21712111Sralph */ 21812111Sralph 21912111Sralph /* pass 1 */ 22012111Sralph 22112111Sralph while (getline(cfp)) 22212111Sralph switch (line[0]) { 22312111Sralph case 'H': 22412111Sralph strcpy(host, line+1); 22512111Sralph if (class[0] == '\0') 22612111Sralph strcpy(class, line+1); 22712111Sralph continue; 22812111Sralph 22912111Sralph case 'P': 23012111Sralph strcpy(logname, line+1); 23112463Sralph if (RS) { /* restricted */ 23212463Sralph if (getpwnam(logname) == (struct passwd *)0) { 23312463Sralph bombed = 2; 23412463Sralph sendmail(bombed); 23512463Sralph goto pass2; 23612463Sralph } 23712463Sralph } 23812111Sralph continue; 23912111Sralph 24012111Sralph case 'J': 24112111Sralph if (line[1] != '\0') 24212111Sralph strcpy(jobname, line+1); 24312111Sralph else 24412111Sralph strcpy(jobname, " "); 24512111Sralph continue; 24612111Sralph 24712111Sralph case 'C': 24812111Sralph if (line[1] != '\0') 24912111Sralph strcpy(class, line+1); 25012111Sralph else if (class[0] == '\0') 25112111Sralph gethostname(class, sizeof (class)); 25212111Sralph continue; 25312111Sralph 25412111Sralph case 'T': /* header title for pr */ 25512111Sralph strcpy(title, line+1); 25612111Sralph continue; 25712111Sralph 25812111Sralph case 'L': /* identification line */ 25912111Sralph if (!SH) 26012111Sralph banner(line+1, jobname); 26112111Sralph continue; 26212111Sralph 26312111Sralph case '1': /* troff fonts */ 26412111Sralph case '2': 26512111Sralph case '3': 26612111Sralph case '4': 26712111Sralph if (line[1] != '\0') 26812111Sralph strcpy(fonts[line[0]-'1'], line+1); 26912111Sralph continue; 27012111Sralph 27112111Sralph case 'W': /* page width */ 27212111Sralph strcpy(width+2, line+1); 27312111Sralph continue; 27412111Sralph 27512111Sralph default: /* some file to print */ 27612111Sralph if ((i = print(line[0], line+1)) > 0) { 27712111Sralph (void) fclose(cfp); 27812111Sralph return(1); 27912111Sralph } else if (i < 0) 28012111Sralph bombed = 1; 28112111Sralph title[0] = '\0'; 28212111Sralph continue; 28312111Sralph 28412111Sralph case 'I': 28512111Sralph case 'N': 28612111Sralph case 'U': 28712111Sralph case 'M': 28812111Sralph continue; 28912111Sralph } 29012111Sralph 29112111Sralph /* pass 2 */ 29212111Sralph 29312463Sralph pass2: 29412111Sralph fseek(cfp, 0L, 0); 29512111Sralph while (getline(cfp)) 29612111Sralph switch (line[0]) { 29712111Sralph case 'M': 29812463Sralph if (bombed != 2) /* already sent if 2 */ 29912463Sralph sendmail(bombed); 30012111Sralph continue; 30112111Sralph 30212111Sralph case 'U': 30312111Sralph (void) unlink(line+1); 30412111Sralph } 30512111Sralph /* 30612111Sralph * clean-up incase another control file exists 30712111Sralph */ 30812111Sralph (void) fclose(cfp); 30912111Sralph (void) unlink(file); 31012111Sralph return(0); 31112111Sralph } 31212111Sralph 31312111Sralph /* 31412111Sralph * Print a file. 31512111Sralph * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, TF, CF, VF}. 31612111Sralph * Return -1 if a non-recoverable error occured, 1 if a recoverable error and 31712111Sralph * 0 if all is well. 31812111Sralph * Note: all filters take stdin as the file, stdout as the printer, 31912111Sralph * stderr as the log file, and must not ignore SIGINT. 32012111Sralph */ 32112111Sralph print(format, file) 32212111Sralph int format; 32312111Sralph char *file; 32412111Sralph { 32512111Sralph register int n, fi, fo; 32612111Sralph register char *prog; 32712111Sralph char *av[15], buf[BUFSIZ]; 32812111Sralph int pid, p[2], stopped = 0; 32912111Sralph union wait status; 33012111Sralph 33112111Sralph if ((fi = open(file, FRDONLY, 0)) < 0) { 33212111Sralph log("%s: open failure <errno = %d>", file, errno); 33312111Sralph return(-1); 33412111Sralph } 33512111Sralph if (!SF && !tof) { /* start on a fresh page */ 33612111Sralph (void) write(ofd, FF, strlen(FF)); 33712111Sralph tof = 1; 33812111Sralph } 33912111Sralph if (IF == NULL && (format == 'f' || format == 'l')) { 34012111Sralph tof = 0; 34112111Sralph while ((n = read(fi, buf, BUFSIZ)) > 0) 34212111Sralph if (write(ofd, buf, n) != n) { 34312111Sralph (void) close(fi); 34412111Sralph return(1); 34512111Sralph } 34612111Sralph (void) close(fi); 34712111Sralph return(0); 34812111Sralph } 34912111Sralph switch (format) { 35012111Sralph case 'p': /* print file using 'pr' */ 35112111Sralph if (IF == NULL) { /* use output filter */ 35212111Sralph prog = PR; 35312111Sralph av[0] = "pr"; 35412111Sralph av[1] = width; 35512111Sralph av[2] = length; 35612111Sralph av[3] = "-h"; 35712111Sralph av[4] = *title ? title : " "; 35812111Sralph av[5] = 0; 35912111Sralph fo = ofd; 36012111Sralph goto start; 36112111Sralph } 36212111Sralph pipe(p); 36312111Sralph if ((prchild = dofork(DORETURN)) == 0) { /* child */ 36412111Sralph dup2(fi, 0); /* file is stdin */ 36512111Sralph dup2(p[1], 1); /* pipe is stdout */ 36612111Sralph for (n = 3; n < NOFILE; n++) 36712111Sralph (void) close(n); 36812111Sralph execl(PR, "pr", width, length, "-h", *title ? title : " ", 0); 36912111Sralph log("cannot execl %s", PR); 37012111Sralph exit(2); 37112111Sralph } 37212111Sralph (void) close(p[1]); /* close output side */ 37312111Sralph (void) close(fi); 37412111Sralph if (prchild < 0) { 37512111Sralph prchild = 0; 37612111Sralph (void) close(p[0]); 37712111Sralph return(-1); 37812111Sralph } 37912111Sralph fi = p[0]; /* use pipe for input */ 38012111Sralph case 'f': /* print plain text file */ 38112111Sralph prog = IF; 38212111Sralph av[1] = width; 38312111Sralph av[2] = length; 38412111Sralph n = 3; 38512111Sralph break; 38612111Sralph case 'l': /* like 'f' but pass control characters */ 38712111Sralph prog = IF; 38812111Sralph av[1] = "-l"; 38912111Sralph av[2] = width; 39012111Sralph av[3] = length; 39112111Sralph n = 4; 39212111Sralph break; 39312463Sralph case 'r': /* print a fortran text file */ 39412463Sralph prog = RF; 39512463Sralph av[1] = width; 39612463Sralph av[2] = length; 39712463Sralph n = 3; 39812463Sralph break; 39912111Sralph case 't': /* print troff output */ 40012463Sralph case 'd': /* print tex output */ 40112111Sralph (void) unlink(".railmag"); 40212463Sralph if ((fo = creat(".railmag", FILMOD)) < 0) { 40312111Sralph log("cannot create .railmag"); 40412111Sralph (void) unlink(".railmag"); 40512111Sralph } else { 40612111Sralph for (n = 0; n < 4; n++) { 40712111Sralph if (fonts[n][0] != '/') 40812111Sralph (void) write(fo, "/usr/lib/vfont/", 15); 40912111Sralph (void) write(fo, fonts[n], strlen(fonts[n])); 41012111Sralph (void) write(fo, "\n", 1); 41112111Sralph } 41212111Sralph (void) close(fo); 41312111Sralph } 41412111Sralph prog = (format == 't') ? TF : DF; 41512463Sralph av[1] = pxwidth; 41612463Sralph av[2] = pxlength; 41712463Sralph n = 3; 41812111Sralph break; 41912111Sralph case 'c': /* print cifplot output */ 42012111Sralph prog = CF; 42112463Sralph av[1] = pxwidth; 42212463Sralph av[2] = pxlength; 42312463Sralph n = 3; 42412111Sralph break; 42512111Sralph case 'g': /* print plot(1G) output */ 42612111Sralph prog = GF; 42712463Sralph av[1] = pxwidth; 42812463Sralph av[2] = pxlength; 42912463Sralph n = 3; 43012111Sralph break; 43112111Sralph case 'v': /* print raster output */ 43212111Sralph prog = VF; 43312463Sralph av[1] = pxwidth; 43412463Sralph av[2] = pxlength; 43512463Sralph n = 3; 43612111Sralph break; 43712111Sralph default: 43812111Sralph (void) close(fi); 43912111Sralph log("illegal format character '%c'", format); 44012111Sralph return(-1); 44112111Sralph } 44212111Sralph if ((av[0] = rindex(prog, '/')) != NULL) 44312111Sralph av[0]++; 44412111Sralph else 44512111Sralph av[0] = prog; 44612111Sralph av[n++] = "-n"; 44712111Sralph av[n++] = logname; 44812111Sralph av[n++] = "-h"; 44912111Sralph av[n++] = host; 45012111Sralph av[n++] = AF; 45112111Sralph av[n] = 0; 45212111Sralph fo = pfd; 45312111Sralph if (ofilter > 0) { /* stop output filter */ 45412111Sralph write(ofd, "\031\1", 2); 45512111Sralph while ((pid = wait3(&status, WUNTRACED, 0)) > 0 && pid != ofilter) 45612111Sralph ; 45712111Sralph if (status.w_stopval != WSTOPPED) { 45812111Sralph (void) close(fi); 45912111Sralph log("output filter died (%d)", status.w_retcode); 46012111Sralph return(1); 46112111Sralph } 46212111Sralph stopped++; 46312111Sralph } 46412111Sralph start: 46512111Sralph if ((child = dofork(DORETURN)) == 0) { /* child */ 46612111Sralph dup2(fi, 0); 46712111Sralph dup2(fo, 1); 46812111Sralph for (n = 3; n < NOFILE; n++) 46912111Sralph (void) close(n); 47012111Sralph execv(prog, av); 47112111Sralph log("cannot execl %s", prog); 47212111Sralph exit(2); 47312111Sralph } 47412111Sralph (void) close(fi); 47512111Sralph if (child < 0) 47612111Sralph status.w_retcode = 100; 47712111Sralph else 47812111Sralph while ((pid = wait(&status)) > 0 && pid != child) 47912111Sralph ; 48012111Sralph child = 0; 48112111Sralph prchild = 0; 48212111Sralph if (stopped) { /* restart output filter */ 48312111Sralph if (kill(ofilter, SIGCONT) < 0) { 48412111Sralph log("cannot restart output filter"); 48512111Sralph exit(1); 48612111Sralph } 48712111Sralph } 48812111Sralph tof = 0; 48912111Sralph if (!WIFEXITED(status) || status.w_retcode > 1) { 49012111Sralph log("Daemon Filter '%c' Malfunction (%d)", format, status.w_retcode); 49112111Sralph return(-1); 49212111Sralph } else if (status.w_retcode == 1) 49312111Sralph return(1); 49412111Sralph tof = 1; 49512111Sralph return(0); 49612111Sralph } 49712111Sralph 49812111Sralph /* 49912111Sralph * Send the daemon control file (cf) and any data files. 50012111Sralph * Return -1 if a non-recoverable error occured, 1 if a recoverable error and 50112111Sralph * 0 if all is well. 50212111Sralph */ 50312111Sralph sendit(file) 50412111Sralph char *file; 50512111Sralph { 50612111Sralph register int linelen, err = 0; 50712111Sralph char last[132]; 50812111Sralph 50912111Sralph /* 51012111Sralph * open control file 51112111Sralph */ 51212111Sralph if ((cfp = fopen(file, "r")) == NULL) { 51312111Sralph log("control file (%s) open failure <errno = %d>", file, errno); 51412111Sralph return(0); 51512111Sralph } 51612111Sralph /* 51712111Sralph * read the control file for work to do 51812111Sralph * 51912111Sralph * file format -- first character in the line is a command 52012111Sralph * rest of the line is the argument. 52112111Sralph * commands of interest are: 52212111Sralph * 52312111Sralph * a-z -- "file name" name of file to print 52412111Sralph * U -- "unlink" name of file to remove 52512111Sralph * (after we print it. (Pass 2 only)). 52612111Sralph */ 52712111Sralph 52812111Sralph /* 52912111Sralph * pass 1 53012111Sralph */ 53112111Sralph while (getline(cfp)) { 53212111Sralph again: 53312111Sralph if (line[0] >= 'a' && line[0] <= 'z') { 53412111Sralph strcpy(last, line); 53512111Sralph while (linelen = getline(cfp)) 53612111Sralph if (strcmp(last, line)) 53712111Sralph break; 53812111Sralph if ((err = sendfile('\3', last+1)) > 0) { 53912111Sralph (void) fclose(cfp); 54012111Sralph return(1); 54112111Sralph } else if (err) 54212111Sralph break; 54312111Sralph if (linelen) 54412111Sralph goto again; 54512111Sralph break; 54612111Sralph } 54712111Sralph } 54812111Sralph if (!err && sendfile('\2', file) > 0) { 54912111Sralph (void) fclose(cfp); 55012111Sralph return(1); 55112111Sralph } 55212111Sralph /* 55312111Sralph * pass 2 55412111Sralph */ 55512111Sralph fseek(cfp, 0L, 0); 55612111Sralph while (getline(cfp)) 55712111Sralph if (line[0] == 'U') 55812111Sralph (void) unlink(line+1); 55912111Sralph /* 56012111Sralph * clean-up incase another control file exists 56112111Sralph */ 56212111Sralph (void) fclose(cfp); 56312111Sralph (void) unlink(file); 56412111Sralph return(0); 56512111Sralph } 56612111Sralph 56712111Sralph /* 56812111Sralph * Send a data file to the remote machine and spool it. 56912111Sralph * Return positive if we should try resending. 57012111Sralph */ 57112111Sralph sendfile(type, file) 57212111Sralph char type, *file; 57312111Sralph { 57412111Sralph register int f, i, amt; 57512111Sralph struct stat stb; 57612111Sralph char buf[BUFSIZ]; 57712111Sralph int sizerr; 57812111Sralph 57912111Sralph if ((f = open(file, FRDONLY, 0)) < 0 || fstat(f, &stb) < 0) { 58012111Sralph log("file (%s) open failure <errno = %d>", file, errno); 58112111Sralph return(-1); 58212111Sralph } 58312111Sralph (void) sprintf(buf, "%c%d %s\n", type, stb.st_size, file); 58412111Sralph amt = strlen(buf); 58512111Sralph if (write(pfd, buf, amt) != amt) 58612111Sralph return(1); 58712111Sralph if (noresponse()) 58812111Sralph return(1); 58912111Sralph sizerr = 0; 59012111Sralph for (i = 0; i < stb.st_size; i += BUFSIZ) { 59112111Sralph amt = BUFSIZ; 59212111Sralph if (i + amt > stb.st_size) 59312111Sralph amt = stb.st_size - i; 59412111Sralph if (sizerr == 0 && read(f, buf, amt) != amt) 59512111Sralph sizerr = 1; 59612111Sralph if (write(pfd, buf, amt) != amt) 59712111Sralph return(1); 59812111Sralph } 59912111Sralph (void) close(f); 60012111Sralph if (sizerr) { 60112111Sralph log("%s: changed size", file); 60212111Sralph (void) write(pfd, "\1", 1); /* tell recvjob to ignore this file */ 60312111Sralph return(-1); 60412111Sralph } 60512111Sralph if (write(pfd, "", 1) != 1) 60612111Sralph return(1); 60712111Sralph if (noresponse()) 60812111Sralph return(1); 60912111Sralph return(0); 61012111Sralph } 61112111Sralph 61212111Sralph /* 61312111Sralph * Check to make sure there have been no errors and that both programs 61412111Sralph * are in sync with eachother. 61512111Sralph * Return non-zero if the connection was lost. 61612111Sralph */ 61712111Sralph static 61812111Sralph noresponse() 61912111Sralph { 62012111Sralph char resp; 62112111Sralph 62212111Sralph if (read(pfd, &resp, 1) != 1 || resp != '\0') { 62312111Sralph log("lost connection or error in recvjob"); 62412111Sralph return(1); 62512111Sralph } 62612111Sralph return(0); 62712111Sralph } 62812111Sralph 62912111Sralph /* 63012111Sralph * Banner printing stuff 63112111Sralph */ 63212111Sralph banner(name1, name2) 63312111Sralph char *name1, *name2; 63412111Sralph { 63512111Sralph time_t tvec; 63612111Sralph extern char *ctime(); 63712111Sralph 63812111Sralph time(&tvec); 63912111Sralph if (!SF && !tof) 64012111Sralph (void) write(ofd, FF, strlen(FF)); 64112111Sralph if (SB) { /* short banner only */ 64212111Sralph if (class[0]) { 64312111Sralph (void) write(ofd, class, strlen(class)); 64412111Sralph (void) write(ofd, ":", 1); 64512111Sralph } 64612111Sralph (void) write(ofd, name1, strlen(name1)); 64712111Sralph (void) write(ofd, " Job: ", 7); 64812111Sralph (void) write(ofd, name2, strlen(name2)); 64912111Sralph (void) write(ofd, " Date: ", 8); 65012111Sralph (void) write(ofd, ctime(&tvec), 24); 65112111Sralph (void) write(ofd, "\n", 1); 65212111Sralph } else { /* normal banner */ 65312111Sralph (void) write(ofd, "\n\n\n", 3); 65412111Sralph scan_out(ofd, name1, '\0'); 65512111Sralph (void) write(ofd, "\n\n", 2); 65612111Sralph scan_out(ofd, name2, '\0'); 65712111Sralph if (class[0]) { 65812111Sralph (void) write(ofd,"\n\n\n",3); 65912111Sralph scan_out(ofd, class, '\0'); 66012111Sralph } 66112111Sralph (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15); 66212111Sralph (void) write(ofd, name2, strlen(name2)); 66312111Sralph (void) write(ofd, "\n\t\t\t\t\tDate: ", 12); 66412111Sralph (void) write(ofd, ctime(&tvec), 24); 66512111Sralph (void) write(ofd, "\n", 1); 66612111Sralph } 66712111Sralph if (!SF) 66812111Sralph (void) write(ofd, FF, strlen(FF)); 66912111Sralph tof = 1; 67012111Sralph } 67112111Sralph 67212111Sralph char * 67312111Sralph scnline(key, p, c) 67412111Sralph register char key, *p; 67512111Sralph char c; 67612111Sralph { 67712111Sralph register scnwidth; 67812111Sralph 67912111Sralph for (scnwidth = WIDTH; --scnwidth;) { 68012111Sralph key <<= 1; 68112111Sralph *p++ = key & 0200 ? c : BACKGND; 68212111Sralph } 68312111Sralph return (p); 68412111Sralph } 68512111Sralph 68612111Sralph #define TRC(q) (((q)-' ')&0177) 68712111Sralph 68812111Sralph scan_out(scfd, scsp, dlm) 68912111Sralph int scfd; 69012111Sralph char *scsp, dlm; 69112111Sralph { 69212111Sralph register char *strp; 69312111Sralph register nchrs, j; 69412111Sralph char outbuf[LINELEN+1], *sp, c, cc; 69512111Sralph int d, scnhgt; 69612111Sralph extern char scnkey[][HEIGHT]; /* in lpdchar.c */ 69712111Sralph 69812111Sralph for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) { 69912111Sralph strp = &outbuf[0]; 70012111Sralph sp = scsp; 70112111Sralph for (nchrs = 0; ; ) { 70212111Sralph d = dropit(c = TRC(cc = *sp++)); 70312111Sralph if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d)) 70412111Sralph for (j = WIDTH; --j;) 70512111Sralph *strp++ = BACKGND; 70612111Sralph else 70712111Sralph strp = scnline(scnkey[c][scnhgt-1-d], strp, cc); 70812111Sralph if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1) 70912111Sralph break; 71012111Sralph *strp++ = BACKGND; 71112111Sralph *strp++ = BACKGND; 71212111Sralph } 71312111Sralph while (*--strp == BACKGND && strp >= outbuf) 71412111Sralph ; 71512111Sralph strp++; 71612111Sralph *strp++ = '\n'; 71712111Sralph (void) write(scfd, outbuf, strp-outbuf); 71812111Sralph } 71912111Sralph } 72012111Sralph 72112111Sralph dropit(c) 72212111Sralph char c; 72312111Sralph { 72412111Sralph switch(c) { 72512111Sralph 72612111Sralph case TRC('_'): 72712111Sralph case TRC(';'): 72812111Sralph case TRC(','): 72912111Sralph case TRC('g'): 73012111Sralph case TRC('j'): 73112111Sralph case TRC('p'): 73212111Sralph case TRC('q'): 73312111Sralph case TRC('y'): 73412111Sralph return (DROP); 73512111Sralph 73612111Sralph default: 73712111Sralph return (0); 73812111Sralph } 73912111Sralph } 74012111Sralph 74112111Sralph /* 74212111Sralph * sendmail --- 74312111Sralph * tell people about job completion 74412111Sralph */ 74512111Sralph sendmail(bombed) 74612111Sralph int bombed; 74712111Sralph { 74812111Sralph static int p[2]; 74912111Sralph register int i; 75012111Sralph int stat; 75112111Sralph register char *cp; 75212111Sralph char buf[100]; 75312111Sralph 75412111Sralph pipe(p); 75512111Sralph if ((stat = dofork(DORETURN)) == 0) { /* child */ 75612111Sralph dup2(p[0], 0); 75712111Sralph for (i = 3; i < NOFILE; i++) 75812111Sralph (void) close(i); 75912111Sralph if ((cp = rindex(MAIL, '/')) != NULL) 76012111Sralph cp++; 76112111Sralph else 76212111Sralph cp = MAIL; 76312111Sralph sprintf(buf, "%s@%s", line+1, host); 76412111Sralph execl(MAIL, cp, buf, 0); 76512111Sralph exit(0); 76612111Sralph } else if (stat > 0) { /* parent */ 76712111Sralph dup2(p[1], 1); 76812111Sralph printf("To: %s\n", line+1); 76912111Sralph printf("Subject: printer job\n\n"); 77012111Sralph printf("Your printer job "); 77112111Sralph if (*jobname) 77212111Sralph printf("(%s) ", jobname); 77312463Sralph switch (bombed) { 77412463Sralph case 0: 77512463Sralph printf("\ncompleted successfully\n"); 77612463Sralph break; 77712463Sralph default: 77812463Sralph case 1: 77912463Sralph printf("\ncould not be printed\n"); 78012463Sralph break; 78112463Sralph case 2: 78212463Sralph printf("\ncould not be printed without an account on %s\n", host); 78312463Sralph break; 78412463Sralph } 78512111Sralph fflush(stdout); 78612111Sralph (void) close(1); 78712111Sralph } 78812111Sralph (void) close(p[0]); 78912111Sralph (void) close(p[1]); 79012111Sralph wait(&stat); 79112111Sralph } 79212111Sralph 79312111Sralph /* 79412111Sralph * dofork - fork with retries on failure 79512111Sralph */ 79612111Sralph dofork(action) 79712111Sralph int action; 79812111Sralph { 79912111Sralph register int i, pid; 80012111Sralph 80112111Sralph for (i = 0; i < 20; i++) { 80212463Sralph if ((pid = fork()) < 0) { 80312111Sralph sleep((unsigned)(i*i)); 80412463Sralph continue; 80512463Sralph } 80612463Sralph /* 80712463Sralph * Child should run as daemon instead of root 80812463Sralph */ 80912463Sralph if (pid == 0) 81012463Sralph setuid(DU); 81112463Sralph return(pid); 81212111Sralph } 81312111Sralph log("can't fork"); 81412111Sralph 81512111Sralph switch (action) { 81612111Sralph case DORETURN: 81712111Sralph return (-1); 81812111Sralph default: 81912111Sralph log("bad action (%d) to dofork", action); 82012111Sralph /*FALL THRU*/ 82112111Sralph case DOABORT: 82212111Sralph exit(1); 82312111Sralph } 82412111Sralph /*NOTREACHED*/ 82512111Sralph } 82612111Sralph 82712111Sralph /* 82812111Sralph * Cleanup child processes when a SIGINT is caught. 82912111Sralph */ 83012111Sralph onintr() 83112111Sralph { 83212111Sralph kill(0, SIGINT); 83312111Sralph if (ofilter > 0) 83412111Sralph kill(ofilter, SIGCONT); 83512111Sralph while (wait(0) > 0) 83612111Sralph ; 83712111Sralph exit(0); 83812111Sralph } 83912111Sralph 84012111Sralph init() 84112111Sralph { 84212111Sralph int status; 84312111Sralph 84412111Sralph if ((status = pgetent(line, printer)) < 0) { 84512111Sralph log("can't open printer description file"); 84612111Sralph exit(1); 84712111Sralph } else if (status == 0) { 84812111Sralph log("unknown printer"); 84912111Sralph exit(1); 85012111Sralph } 85112111Sralph if ((LP = pgetstr("lp", &bp)) == NULL) 85212111Sralph LP = DEFDEVLP; 85312111Sralph if ((RP = pgetstr("rp", &bp)) == NULL) 85412463Sralph RP = DEFLP; 85512111Sralph if ((LO = pgetstr("lo", &bp)) == NULL) 85612111Sralph LO = DEFLOCK; 85712111Sralph if ((ST = pgetstr("st", &bp)) == NULL) 85812111Sralph ST = DEFSTAT; 85912111Sralph if ((LF = pgetstr("lf", &bp)) == NULL) 86012111Sralph LF = DEFLOGF; 86112111Sralph if ((SD = pgetstr("sd", &bp)) == NULL) 86212111Sralph SD = DEFSPOOL; 86312111Sralph if ((DU = pgetnum("du")) < 0) 86412111Sralph DU = DEFUID; 86512111Sralph if ((FF = pgetstr("ff", &bp)) == NULL) 86612111Sralph FF = DEFFF; 86712111Sralph if ((PW = pgetnum("pw")) < 0) 86812111Sralph PW = DEFWIDTH; 86912111Sralph sprintf(&width[2], "%d", PW); 87012111Sralph if ((PL = pgetnum("pl")) < 0) 87112111Sralph PL = DEFLENGTH; 87212111Sralph sprintf(&length[2], "%d", PL); 87312463Sralph if ((PX = pgetnum("px")) < 0) 87412463Sralph PX = 0; 87512463Sralph sprintf(&pxwidth[2], "%d", PX); 87612463Sralph if ((PY = pgetnum("py")) < 0) 87712463Sralph PY = 0; 87812463Sralph sprintf(&pxlength[2], "%d", PY); 87912111Sralph RM = pgetstr("rm", &bp); 88012111Sralph AF = pgetstr("af", &bp); 88112111Sralph OF = pgetstr("of", &bp); 88212111Sralph IF = pgetstr("if", &bp); 88312463Sralph RF = pgetstr("rf", &bp); 88412111Sralph TF = pgetstr("tf", &bp); 88512111Sralph DF = pgetstr("df", &bp); 88612111Sralph GF = pgetstr("gf", &bp); 88712111Sralph VF = pgetstr("vf", &bp); 88812111Sralph CF = pgetstr("cf", &bp); 88912111Sralph TR = pgetstr("tr", &bp); 89012463Sralph RS = pgetflag("rs"); 89112111Sralph SF = pgetflag("sf"); 89212111Sralph SH = pgetflag("sh"); 89312111Sralph SB = pgetflag("sb"); 89412111Sralph RW = pgetflag("rw"); 89512111Sralph BR = pgetnum("br"); 89612111Sralph if ((FC = pgetnum("fc")) < 0) 89712111Sralph FC = 0; 89812111Sralph if ((FS = pgetnum("fs")) < 0) 89912111Sralph FS = 0; 90012111Sralph if ((XC = pgetnum("xc")) < 0) 90112111Sralph XC = 0; 90212111Sralph if ((XS = pgetnum("xs")) < 0) 90312111Sralph XS = 0; 90412111Sralph } 90512111Sralph 90612463Sralph /* 90712463Sralph * Acquire line printer or remote connection. 90812463Sralph */ 90912463Sralph openpr() 91012463Sralph { 91112463Sralph register int i, n; 91212463Sralph 91312463Sralph if (*LP) { 91412463Sralph for (i = 1; ; i = i < 32 ? i << 1 : i) { 91512463Sralph pfd = open(LP, RW ? FRDWR : FWRONLY, 0); 91612463Sralph if (pfd >= 0) 91712463Sralph break; 91812463Sralph if (errno == ENOENT) { 91912463Sralph log("cannot open %s", LP); 92012463Sralph exit(1); 92112463Sralph } 92212463Sralph if (i == 1) 92312463Sralph status("waiting for %s to become ready (offline ?)", printer); 92412463Sralph sleep(i); 92512463Sralph } 92612463Sralph if (isatty(pfd)) 92712463Sralph setty(); 92812463Sralph status("%s is ready and printing", printer); 92912463Sralph } else if (RM != NULL) { 93012463Sralph for (i = 1; ; i = i < 512 ? i << 1 : i) { 931*12528Sralph pfd = getport(RM); 93212463Sralph if (pfd >= 0) { 93312463Sralph (void) sprintf(line, "\2%s\n", RP); 93412463Sralph n = strlen(line); 93512463Sralph if (write(pfd, line, n) != n) 93612463Sralph break; 93712463Sralph if (noresponse()) 93812463Sralph (void) close(pfd); 93912463Sralph else 94012463Sralph break; 94112463Sralph } 94212463Sralph if (i == 1) 94312463Sralph status("waiting for %s to come up", RM); 94412463Sralph sleep(i); 94512463Sralph } 94612463Sralph status("sending to %s", RM); 94712463Sralph remote = 1; 94812463Sralph } else { 94912463Sralph log("no line printer device or remote machine name"); 95012463Sralph exit(1); 95112463Sralph } 95212463Sralph /* 95312463Sralph * Start up an output filter, if needed. 95412463Sralph */ 95512463Sralph if (OF) { 95612463Sralph int p[2]; 95712463Sralph char *cp; 95812463Sralph 95912463Sralph pipe(p); 96012463Sralph if ((ofilter = dofork(DOABORT)) == 0) { /* child */ 96112463Sralph dup2(p[0], 0); /* pipe is std in */ 96212463Sralph dup2(pfd, 1); /* printer is std out */ 96312463Sralph for (i = 3; i < NOFILE; i++) 96412463Sralph (void) close(i); 96512463Sralph if ((cp = rindex(OF, '/')) == NULL) 96612463Sralph cp = OF; 96712463Sralph else 96812463Sralph cp++; 96912463Sralph execl(OF, cp, width, length, 0); 97012463Sralph log("can't execl output filter %s", OF); 97112463Sralph exit(1); 97212463Sralph } 97312463Sralph (void) close(p[0]); /* close input side */ 97412463Sralph ofd = p[1]; /* use pipe for output */ 97512463Sralph } else { 97612463Sralph ofd = pfd; 97712463Sralph ofilter = 0; 97812463Sralph } 97912463Sralph } 98012463Sralph 98112111Sralph struct bauds { 98212111Sralph int baud; 98312111Sralph int speed; 98412111Sralph } bauds[] = { 98512111Sralph 50, B50, 98612111Sralph 75, B75, 98712111Sralph 110, B110, 98812111Sralph 134, B134, 98912111Sralph 150, B150, 99012111Sralph 200, B200, 99112111Sralph 300, B300, 99212111Sralph 600, B600, 99312111Sralph 1200, B1200, 99412111Sralph 1800, B1800, 99512111Sralph 2400, B2400, 99612111Sralph 4800, B4800, 99712111Sralph 9600, B9600, 99812111Sralph 19200, EXTA, 99912111Sralph 38400, EXTB, 100012111Sralph 0, 0 100112111Sralph }; 100212111Sralph 100312111Sralph /* 100412111Sralph * setup tty lines. 100512111Sralph */ 100612111Sralph setty() 100712111Sralph { 100812111Sralph struct sgttyb ttybuf; 100912111Sralph register struct bauds *bp; 101012111Sralph 101112111Sralph if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) { 101212111Sralph log("cannot set exclusive-use"); 101312111Sralph exit(1); 101412111Sralph } 101512111Sralph if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) { 101612111Sralph log("cannot get tty parameters"); 101712111Sralph exit(1); 101812111Sralph } 101912111Sralph if (BR > 0) { 102012111Sralph for (bp = bauds; bp->baud; bp++) 102112111Sralph if (BR == bp->baud) 102212111Sralph break; 102312111Sralph if (!bp->baud) { 102412111Sralph log("illegal baud rate %d", BR); 102512111Sralph exit(1); 102612111Sralph } 102712111Sralph ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed; 102812111Sralph } 102912111Sralph if (FC) 103012111Sralph ttybuf.sg_flags &= ~FC; 103112111Sralph if (FS) 103212111Sralph ttybuf.sg_flags |= FS; 103312111Sralph if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) { 103412111Sralph log("cannot set tty parameters"); 103512111Sralph exit(1); 103612111Sralph } 103712111Sralph if (XC) { 103812111Sralph if (ioctl(pfd, TIOCLBIC, &XC) < 0) { 103912111Sralph log("cannot set local tty parameters"); 104012111Sralph exit(1); 104112111Sralph } 104212111Sralph } 104312111Sralph if (XS) { 104412111Sralph if (ioctl(pfd, TIOCLBIS, &XS) < 0) { 104512111Sralph log("cannot set local tty parameters"); 104612111Sralph exit(1); 104712111Sralph } 104812111Sralph } 104912111Sralph } 105012463Sralph 105112463Sralph /*VARARGS1*/ 105212463Sralph static 105312463Sralph status(msg, a1, a2, a3) 105412463Sralph char *msg; 105512463Sralph { 105612463Sralph register int fd; 105712463Sralph char buf[BUFSIZ]; 105812463Sralph 105912463Sralph umask(0); 106012463Sralph if ((fd = open(ST, FWRONLY|FCREATE|FTRUNCATE|FEXLOCK, 0664)) < 0) 106112463Sralph fatal("cannot create status file"); 106212463Sralph sprintf(buf, msg, a1, a2, a3); 106312463Sralph strcat(buf, "\n"); 106412463Sralph (void) write(fd, buf, strlen(buf)); 106512463Sralph (void) close(fd); 106612463Sralph } 1067