1*12877Sralph /* printjob.c 4.6 83/06/02 */ 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 11*12877Sralph #define DORETURN 0 /* absorb fork error */ 12*12877Sralph #define DOABORT 1 /* abort if dofork fails */ 1312111Sralph 14*12877Sralph static char title[80]; /* ``pr'' title */ 15*12877Sralph static FILE *cfp; /* control file */ 16*12877Sralph static int pfd; /* printer file descriptor */ 17*12877Sralph static int ofd; /* output filter file descriptor */ 18*12877Sralph static int lfd; /* lock file descriptor */ 19*12877Sralph static int pid; /* pid of lpd process */ 20*12877Sralph static int prchild; /* id of pr process */ 21*12877Sralph static int child; /* id of any filters */ 22*12877Sralph static int ofilter; /* id of output filter, if any */ 23*12877Sralph static int tof; /* true if at top of form */ 24*12877Sralph static int remote; /* true if sending files to remote */ 2512111Sralph 26*12877Sralph static char logname[32]; /* user's login name */ 27*12877Sralph static char jobname[32]; /* job or file name */ 28*12877Sralph static char class[32]; /* classification field */ 29*12877Sralph static char width[10] = "-w"; /* page width in characters */ 30*12877Sralph static char length[10] = "-l"; /* page length in lines */ 31*12877Sralph static char pxwidth[10] = "-x"; /* page width in pixels */ 32*12877Sralph static char pxlength[10] = "-y"; /* page length in pixels */ 33*12877Sralph static char indent[10] = "-i0"; /* indentation size in characters */ 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 */ 45*12877Sralph (void) close(1); /* set up log file */ 46*12877Sralph (void) close(2); 47*12877Sralph if (open(LF, FWRONLY|FAPPEND, 0) < 0) 48*12877Sralph (void) open("/dev/null", FWRONLY); 49*12877Sralph dup(1); 5012463Sralph pid = getpid(); /* for use with lprm */ 5112111Sralph setpgrp(0, pid); 5212463Sralph sigset(SIGINT, onintr); 5312111Sralph 5412111Sralph /* 5512111Sralph * uses short form file names 5612111Sralph */ 5712111Sralph if (chdir(SD) < 0) { 5812111Sralph log("cannot chdir to %s", SD); 5912111Sralph exit(1); 6012111Sralph } 6112463Sralph if (stat(LO, &stb) == 0 && (stb.st_mode & 0100)) 6212463Sralph exit(0); /* printing disabled */ 6312111Sralph if ((lfd = open(LO, FWRONLY|FCREATE|FTRUNCATE|FEXLOCK|FNBLOCK, 0664)) < 0) { 6412111Sralph if (errno == EWOULDBLOCK) /* active deamon present */ 6512111Sralph exit(0); 6612111Sralph log("cannot create %s", LO); 6712111Sralph exit(1); 6812111Sralph } 6912111Sralph /* 7012111Sralph * write process id for others to know 7112111Sralph */ 7212111Sralph sprintf(line, "%u\n", pid); 7312111Sralph pidoff = i = strlen(line); 7412463Sralph if (write(lfd, line, i) != i) { 7512111Sralph log("cannot write daemon pid"); 7612111Sralph exit(1); 7712111Sralph } 7812111Sralph /* 7912111Sralph * search the spool directory for work and sort by queue order. 8012111Sralph */ 8112111Sralph if ((nitems = getq(&queue)) < 0) { 8212111Sralph log("can't scan spool directory %s", SD); 8312111Sralph exit(1); 8412111Sralph } 8512463Sralph if (nitems == 0) /* no work to do */ 8612111Sralph exit(0); 8712463Sralph openpr(); /* open printer or remote */ 8812463Sralph again: 8912111Sralph /* 9012111Sralph * we found something to do now do it -- 9112111Sralph * write the name of the current control file into the lock file 9212111Sralph * so the spool queue program can tell what we're working on 9312111Sralph */ 9412111Sralph for (qp = queue; nitems--; free((char *) q)) { 9512111Sralph q = *qp++; 9612111Sralph if (stat(q->q_name, &stb) < 0) 9712111Sralph continue; 9812463Sralph restart: 9912111Sralph (void) lseek(lfd, pidoff, 0); 10012111Sralph (void) sprintf(line, "%s\n", q->q_name); 10112111Sralph i = strlen(line); 10212111Sralph if (write(lfd, line, i) != i) 10312111Sralph log("can't write (%d) control file name", errno); 10412111Sralph if (!remote) 10512111Sralph i = printit(q->q_name); 10612111Sralph else 10712111Sralph i = sendit(q->q_name); 10812463Sralph /* 10912463Sralph * Check to see if we are supposed to stop printing. 11012463Sralph */ 11112463Sralph if (stat(LO, &stb) == 0 && (stb.st_mode & 0100)) 11212463Sralph goto done; 11312463Sralph /* 11412463Sralph * Check to see if we should try reprinting the job. 11512463Sralph */ 11612463Sralph if (i > 0) { 11712111Sralph log("restarting"); 11812111Sralph if (ofilter > 0) { 11912111Sralph kill(ofilter, SIGCONT); /* to be sure */ 12012111Sralph (void) close(ofd); 12112111Sralph while ((i = wait(0)) > 0 && i != ofilter) 12212111Sralph ; 12312111Sralph ofilter = 0; 12412111Sralph } 12512463Sralph (void) close(pfd); /* close printer */ 12612463Sralph (void) lseek(lfd, pidoff, 0); 12712463Sralph if (write(lfd, "\n", 1) != 1) 12812463Sralph log("can't write (%d) control file name", errno); 12912463Sralph openpr(); /* try to reopen printer */ 13012111Sralph goto restart; 13112111Sralph } 13212111Sralph } 13312111Sralph free((char *) queue); 13412463Sralph /* 13512463Sralph * search the spool directory for more work. 13612463Sralph */ 13712463Sralph if ((nitems = getq(&queue)) < 0) { 13812463Sralph log("can't scan spool directory %s", SD); 13912463Sralph exit(1); 14012463Sralph } 14112463Sralph if (nitems == 0) { /* no more work to do */ 14212463Sralph done: 14312463Sralph if (!SF && !tof) 14412463Sralph (void) write(ofd, FF, strlen(FF)); 14512463Sralph if (TR != NULL) /* output trailer */ 14612463Sralph (void) write(ofd, TR, strlen(TR)); 14712463Sralph exit(0); 14812463Sralph } 14912111Sralph goto again; 15012111Sralph } 15112111Sralph 15212111Sralph char fonts[4][50]; /* fonts for troff */ 15312111Sralph 15412111Sralph static char ifonts[4][18] = { 15512111Sralph "/usr/lib/vfont/R", 15612111Sralph "/usr/lib/vfont/I", 15712111Sralph "/usr/lib/vfont/B", 15812111Sralph "/usr/lib/vfont/S" 15912111Sralph }; 16012111Sralph 16112111Sralph /* 16212111Sralph * The remaining part is the reading of the control file (cf) 16312111Sralph * and performing the various actions. 16412111Sralph * Returns 0 if everthing was OK, 1 if we should try to reprint the job and 16512111Sralph * -1 if a non-recoverable error occured. 16612111Sralph */ 167*12877Sralph static 16812111Sralph printit(file) 16912111Sralph char *file; 17012111Sralph { 17112111Sralph register int i; 17212111Sralph int bombed = 0; 17312111Sralph 17412111Sralph /* 17512111Sralph * open control file 17612111Sralph */ 17712111Sralph if ((cfp = fopen(file, "r")) == NULL) { 17812111Sralph log("control file (%s) open failure <errno = %d>", file, errno); 17912111Sralph return(0); 18012111Sralph } 18112111Sralph /* 18212111Sralph * Reset troff fonts. 18312111Sralph */ 18412111Sralph for (i = 0; i < 4; i++) 18512111Sralph strcpy(fonts[i], ifonts[i]); 18612111Sralph 18712111Sralph /* 18812111Sralph * read the control file for work to do 18912111Sralph * 19012111Sralph * file format -- first character in the line is a command 19112111Sralph * rest of the line is the argument. 19212111Sralph * valid commands are: 19312111Sralph * 19412111Sralph * J -- "job name" on banner page 19512111Sralph * C -- "class name" on banner page 19612111Sralph * L -- "literal" user's name to print on banner 19712111Sralph * T -- "title" for pr 19812111Sralph * H -- "host name" of machine where lpr was done 19912111Sralph * P -- "person" user's login name 20012581Sralph * I -- "indent" amount to indent output 20112111Sralph * f -- "file name" name of text file to print 20212111Sralph * l -- "file name" text file with control chars 20312111Sralph * p -- "file name" text file to print with pr(1) 20412111Sralph * t -- "file name" troff(1) file to print 20512111Sralph * d -- "file name" dvi file to print 20612111Sralph * g -- "file name" plot(1G) file to print 20712111Sralph * v -- "file name" plain raster file to print 20812111Sralph * c -- "file name" cifplot file to print 20912111Sralph * 1 -- "R font file" for troff 21012111Sralph * 2 -- "I font file" for troff 21112111Sralph * 3 -- "B font file" for troff 21212111Sralph * 4 -- "S font file" for troff 21312111Sralph * N -- "name" of file (used by lpq) 21412111Sralph * U -- "unlink" name of file to remove 21512111Sralph * (after we print it. (Pass 2 only)). 21612111Sralph * M -- "mail" to user when done printing 21712111Sralph * 21812111Sralph * getline reads a line and expands tabs to blanks 21912111Sralph */ 22012111Sralph 22112111Sralph /* pass 1 */ 22212111Sralph 22312111Sralph while (getline(cfp)) 22412111Sralph switch (line[0]) { 22512111Sralph case 'H': 22612111Sralph strcpy(host, line+1); 22712111Sralph if (class[0] == '\0') 22812111Sralph strcpy(class, line+1); 22912111Sralph continue; 23012111Sralph 23112111Sralph case 'P': 23212111Sralph strcpy(logname, line+1); 23312463Sralph if (RS) { /* restricted */ 23412463Sralph if (getpwnam(logname) == (struct passwd *)0) { 23512463Sralph bombed = 2; 23612463Sralph sendmail(bombed); 23712463Sralph goto pass2; 23812463Sralph } 23912463Sralph } 24012111Sralph continue; 24112111Sralph 24212111Sralph case 'J': 24312111Sralph if (line[1] != '\0') 24412111Sralph strcpy(jobname, line+1); 24512111Sralph else 24612111Sralph strcpy(jobname, " "); 24712111Sralph continue; 24812111Sralph 24912111Sralph case 'C': 25012111Sralph if (line[1] != '\0') 25112111Sralph strcpy(class, line+1); 25212111Sralph else if (class[0] == '\0') 25312111Sralph gethostname(class, sizeof (class)); 25412111Sralph continue; 25512111Sralph 25612111Sralph case 'T': /* header title for pr */ 25712111Sralph strcpy(title, line+1); 25812111Sralph continue; 25912111Sralph 26012111Sralph case 'L': /* identification line */ 26112111Sralph if (!SH) 26212111Sralph banner(line+1, jobname); 26312111Sralph continue; 26412111Sralph 26512111Sralph case '1': /* troff fonts */ 26612111Sralph case '2': 26712111Sralph case '3': 26812111Sralph case '4': 26912111Sralph if (line[1] != '\0') 27012111Sralph strcpy(fonts[line[0]-'1'], line+1); 27112111Sralph continue; 27212111Sralph 27312111Sralph case 'W': /* page width */ 27412111Sralph strcpy(width+2, line+1); 27512111Sralph continue; 27612111Sralph 27712581Sralph case 'I': /* indent amount */ 27812581Sralph strcpy(indent+2, line+1); 27912581Sralph continue; 28012581Sralph 28112111Sralph default: /* some file to print */ 28212111Sralph if ((i = print(line[0], line+1)) > 0) { 28312111Sralph (void) fclose(cfp); 28412111Sralph return(1); 28512111Sralph } else if (i < 0) 28612111Sralph bombed = 1; 28712111Sralph title[0] = '\0'; 28812111Sralph continue; 28912111Sralph 29012111Sralph case 'N': 29112111Sralph case 'U': 29212111Sralph case 'M': 29312111Sralph continue; 29412111Sralph } 29512111Sralph 29612111Sralph /* pass 2 */ 29712111Sralph 29812463Sralph pass2: 29912111Sralph fseek(cfp, 0L, 0); 30012111Sralph while (getline(cfp)) 30112111Sralph switch (line[0]) { 30212111Sralph case 'M': 30312463Sralph if (bombed != 2) /* already sent if 2 */ 30412463Sralph sendmail(bombed); 30512111Sralph continue; 30612111Sralph 30712111Sralph case 'U': 30812111Sralph (void) unlink(line+1); 30912111Sralph } 31012111Sralph /* 31112111Sralph * clean-up incase another control file exists 31212111Sralph */ 31312111Sralph (void) fclose(cfp); 31412111Sralph (void) unlink(file); 31512111Sralph return(0); 31612111Sralph } 31712111Sralph 31812111Sralph /* 31912111Sralph * Print a file. 32012111Sralph * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, TF, CF, VF}. 32112111Sralph * Return -1 if a non-recoverable error occured, 1 if a recoverable error and 32212111Sralph * 0 if all is well. 32312111Sralph * Note: all filters take stdin as the file, stdout as the printer, 32412111Sralph * stderr as the log file, and must not ignore SIGINT. 32512111Sralph */ 326*12877Sralph static 32712111Sralph print(format, file) 32812111Sralph int format; 32912111Sralph char *file; 33012111Sralph { 33112111Sralph register int n, fi, fo; 33212111Sralph register char *prog; 33312111Sralph char *av[15], buf[BUFSIZ]; 33412111Sralph int pid, p[2], stopped = 0; 33512111Sralph union wait status; 33612111Sralph 33712111Sralph if ((fi = open(file, FRDONLY, 0)) < 0) { 33812111Sralph log("%s: open failure <errno = %d>", file, errno); 33912111Sralph return(-1); 34012111Sralph } 34112111Sralph if (!SF && !tof) { /* start on a fresh page */ 34212111Sralph (void) write(ofd, FF, strlen(FF)); 34312111Sralph tof = 1; 34412111Sralph } 34512111Sralph if (IF == NULL && (format == 'f' || format == 'l')) { 34612111Sralph tof = 0; 34712111Sralph while ((n = read(fi, buf, BUFSIZ)) > 0) 34812111Sralph if (write(ofd, buf, n) != n) { 34912111Sralph (void) close(fi); 35012111Sralph return(1); 35112111Sralph } 35212111Sralph (void) close(fi); 35312111Sralph return(0); 35412111Sralph } 35512111Sralph switch (format) { 35612111Sralph case 'p': /* print file using 'pr' */ 35712111Sralph if (IF == NULL) { /* use output filter */ 35812111Sralph prog = PR; 35912111Sralph av[0] = "pr"; 36012111Sralph av[1] = width; 36112111Sralph av[2] = length; 36212111Sralph av[3] = "-h"; 36312111Sralph av[4] = *title ? title : " "; 36412111Sralph av[5] = 0; 36512111Sralph fo = ofd; 36612111Sralph goto start; 36712111Sralph } 36812111Sralph pipe(p); 36912111Sralph if ((prchild = dofork(DORETURN)) == 0) { /* child */ 37012111Sralph dup2(fi, 0); /* file is stdin */ 37112111Sralph dup2(p[1], 1); /* pipe is stdout */ 37212111Sralph for (n = 3; n < NOFILE; n++) 37312111Sralph (void) close(n); 37412111Sralph execl(PR, "pr", width, length, "-h", *title ? title : " ", 0); 37512111Sralph log("cannot execl %s", PR); 37612111Sralph exit(2); 37712111Sralph } 37812111Sralph (void) close(p[1]); /* close output side */ 37912111Sralph (void) close(fi); 38012111Sralph if (prchild < 0) { 38112111Sralph prchild = 0; 38212111Sralph (void) close(p[0]); 38312111Sralph return(-1); 38412111Sralph } 38512111Sralph fi = p[0]; /* use pipe for input */ 38612111Sralph case 'f': /* print plain text file */ 38712111Sralph prog = IF; 38812111Sralph av[1] = width; 38912111Sralph av[2] = length; 39012581Sralph av[3] = indent; 39112581Sralph n = 4; 39212111Sralph break; 39312111Sralph case 'l': /* like 'f' but pass control characters */ 39412111Sralph prog = IF; 39512111Sralph av[1] = "-l"; 39612111Sralph av[2] = width; 39712111Sralph av[3] = length; 39812581Sralph av[4] = indent; 39912581Sralph n = 5; 40012111Sralph break; 40112463Sralph case 'r': /* print a fortran text file */ 40212463Sralph prog = RF; 40312463Sralph av[1] = width; 40412463Sralph av[2] = length; 40512463Sralph n = 3; 40612463Sralph break; 40712111Sralph case 't': /* print troff output */ 40812463Sralph case 'd': /* print tex output */ 40912111Sralph (void) unlink(".railmag"); 41012463Sralph if ((fo = creat(".railmag", FILMOD)) < 0) { 41112111Sralph log("cannot create .railmag"); 41212111Sralph (void) unlink(".railmag"); 41312111Sralph } else { 41412111Sralph for (n = 0; n < 4; n++) { 41512111Sralph if (fonts[n][0] != '/') 41612111Sralph (void) write(fo, "/usr/lib/vfont/", 15); 41712111Sralph (void) write(fo, fonts[n], strlen(fonts[n])); 41812111Sralph (void) write(fo, "\n", 1); 41912111Sralph } 42012111Sralph (void) close(fo); 42112111Sralph } 42212111Sralph prog = (format == 't') ? TF : DF; 42312463Sralph av[1] = pxwidth; 42412463Sralph av[2] = pxlength; 42512463Sralph n = 3; 42612111Sralph break; 42712111Sralph case 'c': /* print cifplot output */ 42812111Sralph prog = CF; 42912463Sralph av[1] = pxwidth; 43012463Sralph av[2] = pxlength; 43112463Sralph n = 3; 43212111Sralph break; 43312111Sralph case 'g': /* print plot(1G) output */ 43412111Sralph prog = GF; 43512463Sralph av[1] = pxwidth; 43612463Sralph av[2] = pxlength; 43712463Sralph n = 3; 43812111Sralph break; 43912111Sralph case 'v': /* print raster output */ 44012111Sralph prog = VF; 44112463Sralph av[1] = pxwidth; 44212463Sralph av[2] = pxlength; 44312463Sralph n = 3; 44412111Sralph break; 44512111Sralph default: 44612111Sralph (void) close(fi); 44712111Sralph log("illegal format character '%c'", format); 44812111Sralph return(-1); 44912111Sralph } 45012111Sralph if ((av[0] = rindex(prog, '/')) != NULL) 45112111Sralph av[0]++; 45212111Sralph else 45312111Sralph av[0] = prog; 45412111Sralph av[n++] = "-n"; 45512111Sralph av[n++] = logname; 45612111Sralph av[n++] = "-h"; 45712111Sralph av[n++] = host; 45812111Sralph av[n++] = AF; 45912111Sralph av[n] = 0; 46012111Sralph fo = pfd; 46112111Sralph if (ofilter > 0) { /* stop output filter */ 46212111Sralph write(ofd, "\031\1", 2); 46312111Sralph while ((pid = wait3(&status, WUNTRACED, 0)) > 0 && pid != ofilter) 46412111Sralph ; 46512111Sralph if (status.w_stopval != WSTOPPED) { 46612111Sralph (void) close(fi); 46712111Sralph log("output filter died (%d)", status.w_retcode); 46812111Sralph return(1); 46912111Sralph } 47012111Sralph stopped++; 47112111Sralph } 47212111Sralph start: 47312111Sralph if ((child = dofork(DORETURN)) == 0) { /* child */ 47412111Sralph dup2(fi, 0); 47512111Sralph dup2(fo, 1); 47612111Sralph for (n = 3; n < NOFILE; n++) 47712111Sralph (void) close(n); 47812111Sralph execv(prog, av); 47912111Sralph log("cannot execl %s", prog); 48012111Sralph exit(2); 48112111Sralph } 48212111Sralph (void) close(fi); 48312111Sralph if (child < 0) 48412111Sralph status.w_retcode = 100; 48512111Sralph else 48612111Sralph while ((pid = wait(&status)) > 0 && pid != child) 48712111Sralph ; 48812111Sralph child = 0; 48912111Sralph prchild = 0; 49012111Sralph if (stopped) { /* restart output filter */ 49112111Sralph if (kill(ofilter, SIGCONT) < 0) { 49212111Sralph log("cannot restart output filter"); 49312111Sralph exit(1); 49412111Sralph } 49512111Sralph } 49612111Sralph tof = 0; 49712111Sralph if (!WIFEXITED(status) || status.w_retcode > 1) { 49812111Sralph log("Daemon Filter '%c' Malfunction (%d)", format, status.w_retcode); 49912111Sralph return(-1); 50012111Sralph } else if (status.w_retcode == 1) 50112111Sralph return(1); 50212111Sralph tof = 1; 50312111Sralph return(0); 50412111Sralph } 50512111Sralph 50612111Sralph /* 50712111Sralph * Send the daemon control file (cf) and any data files. 50812111Sralph * Return -1 if a non-recoverable error occured, 1 if a recoverable error and 50912111Sralph * 0 if all is well. 51012111Sralph */ 511*12877Sralph static 51212111Sralph sendit(file) 51312111Sralph char *file; 51412111Sralph { 51512111Sralph register int linelen, err = 0; 51612111Sralph char last[132]; 51712111Sralph 51812111Sralph /* 51912111Sralph * open control file 52012111Sralph */ 52112111Sralph if ((cfp = fopen(file, "r")) == NULL) { 52212111Sralph log("control file (%s) open failure <errno = %d>", file, errno); 52312111Sralph return(0); 52412111Sralph } 52512111Sralph /* 52612111Sralph * read the control file for work to do 52712111Sralph * 52812111Sralph * file format -- first character in the line is a command 52912111Sralph * rest of the line is the argument. 53012111Sralph * commands of interest are: 53112111Sralph * 53212111Sralph * a-z -- "file name" name of file to print 53312111Sralph * U -- "unlink" name of file to remove 53412111Sralph * (after we print it. (Pass 2 only)). 53512111Sralph */ 53612111Sralph 53712111Sralph /* 53812111Sralph * pass 1 53912111Sralph */ 54012111Sralph while (getline(cfp)) { 54112111Sralph again: 54212111Sralph if (line[0] >= 'a' && line[0] <= 'z') { 54312111Sralph strcpy(last, line); 54412111Sralph while (linelen = getline(cfp)) 54512111Sralph if (strcmp(last, line)) 54612111Sralph break; 54712111Sralph if ((err = sendfile('\3', last+1)) > 0) { 54812111Sralph (void) fclose(cfp); 54912111Sralph return(1); 55012111Sralph } else if (err) 55112111Sralph break; 55212111Sralph if (linelen) 55312111Sralph goto again; 55412111Sralph break; 55512111Sralph } 55612111Sralph } 55712111Sralph if (!err && sendfile('\2', file) > 0) { 55812111Sralph (void) fclose(cfp); 55912111Sralph return(1); 56012111Sralph } 56112111Sralph /* 56212111Sralph * pass 2 56312111Sralph */ 56412111Sralph fseek(cfp, 0L, 0); 56512111Sralph while (getline(cfp)) 56612111Sralph if (line[0] == 'U') 56712111Sralph (void) unlink(line+1); 56812111Sralph /* 56912111Sralph * clean-up incase another control file exists 57012111Sralph */ 57112111Sralph (void) fclose(cfp); 57212111Sralph (void) unlink(file); 57312111Sralph return(0); 57412111Sralph } 57512111Sralph 57612111Sralph /* 57712111Sralph * Send a data file to the remote machine and spool it. 57812111Sralph * Return positive if we should try resending. 57912111Sralph */ 580*12877Sralph static 58112111Sralph sendfile(type, file) 58212111Sralph char type, *file; 58312111Sralph { 58412111Sralph register int f, i, amt; 58512111Sralph struct stat stb; 58612111Sralph char buf[BUFSIZ]; 58712111Sralph int sizerr; 58812111Sralph 58912111Sralph if ((f = open(file, FRDONLY, 0)) < 0 || fstat(f, &stb) < 0) { 59012111Sralph log("file (%s) open failure <errno = %d>", file, errno); 59112111Sralph return(-1); 59212111Sralph } 59312111Sralph (void) sprintf(buf, "%c%d %s\n", type, stb.st_size, file); 59412111Sralph amt = strlen(buf); 59512692Sralph if (write(pfd, buf, amt) != amt) { 59612692Sralph (void) close(f); 59712111Sralph return(1); 59812692Sralph } 59912692Sralph if (noresponse()) { 60012692Sralph (void) close(f); 60112111Sralph return(1); 60212692Sralph } 60312111Sralph sizerr = 0; 60412111Sralph for (i = 0; i < stb.st_size; i += BUFSIZ) { 60512111Sralph amt = BUFSIZ; 60612111Sralph if (i + amt > stb.st_size) 60712111Sralph amt = stb.st_size - i; 60812111Sralph if (sizerr == 0 && read(f, buf, amt) != amt) 60912111Sralph sizerr = 1; 61012692Sralph if (write(pfd, buf, amt) != amt) { 61112692Sralph (void) close(f); 61212111Sralph return(1); 61312692Sralph } 61412111Sralph } 61512111Sralph (void) close(f); 61612111Sralph if (sizerr) { 61712111Sralph log("%s: changed size", file); 61812111Sralph (void) write(pfd, "\1", 1); /* tell recvjob to ignore this file */ 61912111Sralph return(-1); 62012111Sralph } 62112111Sralph if (write(pfd, "", 1) != 1) 62212111Sralph return(1); 62312111Sralph if (noresponse()) 62412111Sralph return(1); 62512111Sralph return(0); 62612111Sralph } 62712111Sralph 62812111Sralph /* 62912111Sralph * Check to make sure there have been no errors and that both programs 63012111Sralph * are in sync with eachother. 63112111Sralph * Return non-zero if the connection was lost. 63212111Sralph */ 63312111Sralph static 63412111Sralph noresponse() 63512111Sralph { 63612111Sralph char resp; 63712111Sralph 63812111Sralph if (read(pfd, &resp, 1) != 1 || resp != '\0') { 63912111Sralph log("lost connection or error in recvjob"); 64012111Sralph return(1); 64112111Sralph } 64212111Sralph return(0); 64312111Sralph } 64412111Sralph 64512111Sralph /* 64612111Sralph * Banner printing stuff 64712111Sralph */ 648*12877Sralph static 64912111Sralph banner(name1, name2) 65012111Sralph char *name1, *name2; 65112111Sralph { 65212111Sralph time_t tvec; 65312111Sralph extern char *ctime(); 65412111Sralph 65512111Sralph time(&tvec); 65612111Sralph if (!SF && !tof) 65712111Sralph (void) write(ofd, FF, strlen(FF)); 65812111Sralph if (SB) { /* short banner only */ 65912111Sralph if (class[0]) { 66012111Sralph (void) write(ofd, class, strlen(class)); 66112111Sralph (void) write(ofd, ":", 1); 66212111Sralph } 66312111Sralph (void) write(ofd, name1, strlen(name1)); 66412111Sralph (void) write(ofd, " Job: ", 7); 66512111Sralph (void) write(ofd, name2, strlen(name2)); 66612111Sralph (void) write(ofd, " Date: ", 8); 66712111Sralph (void) write(ofd, ctime(&tvec), 24); 66812111Sralph (void) write(ofd, "\n", 1); 66912111Sralph } else { /* normal banner */ 67012111Sralph (void) write(ofd, "\n\n\n", 3); 67112111Sralph scan_out(ofd, name1, '\0'); 67212111Sralph (void) write(ofd, "\n\n", 2); 67312111Sralph scan_out(ofd, name2, '\0'); 67412111Sralph if (class[0]) { 67512111Sralph (void) write(ofd,"\n\n\n",3); 67612111Sralph scan_out(ofd, class, '\0'); 67712111Sralph } 67812111Sralph (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15); 67912111Sralph (void) write(ofd, name2, strlen(name2)); 68012111Sralph (void) write(ofd, "\n\t\t\t\t\tDate: ", 12); 68112111Sralph (void) write(ofd, ctime(&tvec), 24); 68212111Sralph (void) write(ofd, "\n", 1); 68312111Sralph } 68412111Sralph if (!SF) 68512111Sralph (void) write(ofd, FF, strlen(FF)); 68612111Sralph tof = 1; 68712111Sralph } 68812111Sralph 689*12877Sralph static char * 69012111Sralph scnline(key, p, c) 69112111Sralph register char key, *p; 69212111Sralph char c; 69312111Sralph { 69412111Sralph register scnwidth; 69512111Sralph 69612111Sralph for (scnwidth = WIDTH; --scnwidth;) { 69712111Sralph key <<= 1; 69812111Sralph *p++ = key & 0200 ? c : BACKGND; 69912111Sralph } 70012111Sralph return (p); 70112111Sralph } 70212111Sralph 70312111Sralph #define TRC(q) (((q)-' ')&0177) 70412111Sralph 705*12877Sralph static 70612111Sralph scan_out(scfd, scsp, dlm) 70712111Sralph int scfd; 70812111Sralph char *scsp, dlm; 70912111Sralph { 71012111Sralph register char *strp; 71112111Sralph register nchrs, j; 71212111Sralph char outbuf[LINELEN+1], *sp, c, cc; 71312111Sralph int d, scnhgt; 71412111Sralph extern char scnkey[][HEIGHT]; /* in lpdchar.c */ 71512111Sralph 71612111Sralph for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) { 71712111Sralph strp = &outbuf[0]; 71812111Sralph sp = scsp; 71912111Sralph for (nchrs = 0; ; ) { 72012111Sralph d = dropit(c = TRC(cc = *sp++)); 72112111Sralph if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d)) 72212111Sralph for (j = WIDTH; --j;) 72312111Sralph *strp++ = BACKGND; 72412111Sralph else 72512111Sralph strp = scnline(scnkey[c][scnhgt-1-d], strp, cc); 72612111Sralph if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1) 72712111Sralph break; 72812111Sralph *strp++ = BACKGND; 72912111Sralph *strp++ = BACKGND; 73012111Sralph } 73112111Sralph while (*--strp == BACKGND && strp >= outbuf) 73212111Sralph ; 73312111Sralph strp++; 73412111Sralph *strp++ = '\n'; 73512111Sralph (void) write(scfd, outbuf, strp-outbuf); 73612111Sralph } 73712111Sralph } 73812111Sralph 739*12877Sralph static 74012111Sralph dropit(c) 74112111Sralph char c; 74212111Sralph { 74312111Sralph switch(c) { 74412111Sralph 74512111Sralph case TRC('_'): 74612111Sralph case TRC(';'): 74712111Sralph case TRC(','): 74812111Sralph case TRC('g'): 74912111Sralph case TRC('j'): 75012111Sralph case TRC('p'): 75112111Sralph case TRC('q'): 75212111Sralph case TRC('y'): 75312111Sralph return (DROP); 75412111Sralph 75512111Sralph default: 75612111Sralph return (0); 75712111Sralph } 75812111Sralph } 75912111Sralph 76012111Sralph /* 76112111Sralph * sendmail --- 76212111Sralph * tell people about job completion 76312111Sralph */ 764*12877Sralph static 76512111Sralph sendmail(bombed) 76612111Sralph int bombed; 76712111Sralph { 76812111Sralph static int p[2]; 76912111Sralph register int i; 77012111Sralph int stat; 77112111Sralph register char *cp; 77212111Sralph char buf[100]; 77312111Sralph 77412111Sralph pipe(p); 77512111Sralph if ((stat = dofork(DORETURN)) == 0) { /* child */ 77612111Sralph dup2(p[0], 0); 77712111Sralph for (i = 3; i < NOFILE; i++) 77812111Sralph (void) close(i); 77912111Sralph if ((cp = rindex(MAIL, '/')) != NULL) 78012111Sralph cp++; 78112111Sralph else 78212111Sralph cp = MAIL; 78312111Sralph sprintf(buf, "%s@%s", line+1, host); 78412111Sralph execl(MAIL, cp, buf, 0); 78512111Sralph exit(0); 78612111Sralph } else if (stat > 0) { /* parent */ 78712111Sralph dup2(p[1], 1); 78812111Sralph printf("To: %s\n", line+1); 78912111Sralph printf("Subject: printer job\n\n"); 79012111Sralph printf("Your printer job "); 79112111Sralph if (*jobname) 79212111Sralph printf("(%s) ", jobname); 79312463Sralph switch (bombed) { 79412463Sralph case 0: 79512463Sralph printf("\ncompleted successfully\n"); 79612463Sralph break; 79712463Sralph default: 79812463Sralph case 1: 79912463Sralph printf("\ncould not be printed\n"); 80012463Sralph break; 80112463Sralph case 2: 80212463Sralph printf("\ncould not be printed without an account on %s\n", host); 80312463Sralph break; 80412463Sralph } 80512111Sralph fflush(stdout); 80612111Sralph (void) close(1); 80712111Sralph } 80812111Sralph (void) close(p[0]); 80912111Sralph (void) close(p[1]); 81012111Sralph wait(&stat); 81112111Sralph } 81212111Sralph 81312111Sralph /* 81412111Sralph * dofork - fork with retries on failure 81512111Sralph */ 816*12877Sralph static 81712111Sralph dofork(action) 81812111Sralph int action; 81912111Sralph { 82012111Sralph register int i, pid; 82112111Sralph 82212111Sralph for (i = 0; i < 20; i++) { 82312463Sralph if ((pid = fork()) < 0) { 82412111Sralph sleep((unsigned)(i*i)); 82512463Sralph continue; 82612463Sralph } 82712463Sralph /* 82812463Sralph * Child should run as daemon instead of root 82912463Sralph */ 83012463Sralph if (pid == 0) 83112463Sralph setuid(DU); 83212463Sralph return(pid); 83312111Sralph } 83412111Sralph log("can't fork"); 83512111Sralph 83612111Sralph switch (action) { 83712111Sralph case DORETURN: 83812111Sralph return (-1); 83912111Sralph default: 84012111Sralph log("bad action (%d) to dofork", action); 84112111Sralph /*FALL THRU*/ 84212111Sralph case DOABORT: 84312111Sralph exit(1); 84412111Sralph } 84512111Sralph /*NOTREACHED*/ 84612111Sralph } 84712111Sralph 84812111Sralph /* 84912111Sralph * Cleanup child processes when a SIGINT is caught. 85012111Sralph */ 851*12877Sralph static 85212111Sralph onintr() 85312111Sralph { 85412111Sralph kill(0, SIGINT); 85512111Sralph if (ofilter > 0) 85612111Sralph kill(ofilter, SIGCONT); 85712111Sralph while (wait(0) > 0) 85812111Sralph ; 85912111Sralph exit(0); 86012111Sralph } 86112111Sralph 862*12877Sralph static 86312111Sralph init() 86412111Sralph { 86512111Sralph int status; 86612111Sralph 86712111Sralph if ((status = pgetent(line, printer)) < 0) { 86812111Sralph log("can't open printer description file"); 86912111Sralph exit(1); 87012111Sralph } else if (status == 0) { 87112111Sralph log("unknown printer"); 87212111Sralph exit(1); 87312111Sralph } 87412111Sralph if ((LP = pgetstr("lp", &bp)) == NULL) 87512111Sralph LP = DEFDEVLP; 87612111Sralph if ((RP = pgetstr("rp", &bp)) == NULL) 87712463Sralph RP = DEFLP; 87812111Sralph if ((LO = pgetstr("lo", &bp)) == NULL) 87912111Sralph LO = DEFLOCK; 88012111Sralph if ((ST = pgetstr("st", &bp)) == NULL) 88112111Sralph ST = DEFSTAT; 88212111Sralph if ((LF = pgetstr("lf", &bp)) == NULL) 88312111Sralph LF = DEFLOGF; 88412111Sralph if ((SD = pgetstr("sd", &bp)) == NULL) 88512111Sralph SD = DEFSPOOL; 88612111Sralph if ((DU = pgetnum("du")) < 0) 88712111Sralph DU = DEFUID; 88812111Sralph if ((FF = pgetstr("ff", &bp)) == NULL) 88912111Sralph FF = DEFFF; 89012111Sralph if ((PW = pgetnum("pw")) < 0) 89112111Sralph PW = DEFWIDTH; 89212111Sralph sprintf(&width[2], "%d", PW); 89312111Sralph if ((PL = pgetnum("pl")) < 0) 89412111Sralph PL = DEFLENGTH; 89512111Sralph sprintf(&length[2], "%d", PL); 89612463Sralph if ((PX = pgetnum("px")) < 0) 89712463Sralph PX = 0; 89812463Sralph sprintf(&pxwidth[2], "%d", PX); 89912463Sralph if ((PY = pgetnum("py")) < 0) 90012463Sralph PY = 0; 90112463Sralph sprintf(&pxlength[2], "%d", PY); 90212111Sralph RM = pgetstr("rm", &bp); 90312111Sralph AF = pgetstr("af", &bp); 90412111Sralph OF = pgetstr("of", &bp); 90512111Sralph IF = pgetstr("if", &bp); 90612463Sralph RF = pgetstr("rf", &bp); 90712111Sralph TF = pgetstr("tf", &bp); 90812111Sralph DF = pgetstr("df", &bp); 90912111Sralph GF = pgetstr("gf", &bp); 91012111Sralph VF = pgetstr("vf", &bp); 91112111Sralph CF = pgetstr("cf", &bp); 91212111Sralph TR = pgetstr("tr", &bp); 91312463Sralph RS = pgetflag("rs"); 91412111Sralph SF = pgetflag("sf"); 91512111Sralph SH = pgetflag("sh"); 91612111Sralph SB = pgetflag("sb"); 91712111Sralph RW = pgetflag("rw"); 91812111Sralph BR = pgetnum("br"); 91912111Sralph if ((FC = pgetnum("fc")) < 0) 92012111Sralph FC = 0; 92112111Sralph if ((FS = pgetnum("fs")) < 0) 92212111Sralph FS = 0; 92312111Sralph if ((XC = pgetnum("xc")) < 0) 92412111Sralph XC = 0; 92512111Sralph if ((XS = pgetnum("xs")) < 0) 92612111Sralph XS = 0; 92712581Sralph tof = !pgetflag("fo"); 92812111Sralph } 92912111Sralph 93012463Sralph /* 93112463Sralph * Acquire line printer or remote connection. 93212463Sralph */ 933*12877Sralph static 93412463Sralph openpr() 93512463Sralph { 93612463Sralph register int i, n; 93712463Sralph 93812463Sralph if (*LP) { 93912463Sralph for (i = 1; ; i = i < 32 ? i << 1 : i) { 94012463Sralph pfd = open(LP, RW ? FRDWR : FWRONLY, 0); 94112463Sralph if (pfd >= 0) 94212463Sralph break; 94312463Sralph if (errno == ENOENT) { 94412463Sralph log("cannot open %s", LP); 94512463Sralph exit(1); 94612463Sralph } 94712463Sralph if (i == 1) 94812463Sralph status("waiting for %s to become ready (offline ?)", printer); 94912463Sralph sleep(i); 95012463Sralph } 95112463Sralph if (isatty(pfd)) 95212463Sralph setty(); 95312463Sralph status("%s is ready and printing", printer); 95412463Sralph } else if (RM != NULL) { 95512463Sralph for (i = 1; ; i = i < 512 ? i << 1 : i) { 95612528Sralph pfd = getport(RM); 95712463Sralph if (pfd >= 0) { 95812463Sralph (void) sprintf(line, "\2%s\n", RP); 95912463Sralph n = strlen(line); 96012463Sralph if (write(pfd, line, n) != n) 96112463Sralph break; 96212463Sralph if (noresponse()) 96312463Sralph (void) close(pfd); 96412463Sralph else 96512463Sralph break; 96612463Sralph } 96712463Sralph if (i == 1) 96812463Sralph status("waiting for %s to come up", RM); 96912463Sralph sleep(i); 97012463Sralph } 97112463Sralph status("sending to %s", RM); 97212463Sralph remote = 1; 97312463Sralph } else { 97412463Sralph log("no line printer device or remote machine name"); 97512463Sralph exit(1); 97612463Sralph } 97712463Sralph /* 97812463Sralph * Start up an output filter, if needed. 97912463Sralph */ 98012463Sralph if (OF) { 98112463Sralph int p[2]; 98212463Sralph char *cp; 98312463Sralph 98412463Sralph pipe(p); 98512463Sralph if ((ofilter = dofork(DOABORT)) == 0) { /* child */ 98612463Sralph dup2(p[0], 0); /* pipe is std in */ 98712463Sralph dup2(pfd, 1); /* printer is std out */ 98812463Sralph for (i = 3; i < NOFILE; i++) 98912463Sralph (void) close(i); 99012463Sralph if ((cp = rindex(OF, '/')) == NULL) 99112463Sralph cp = OF; 99212463Sralph else 99312463Sralph cp++; 99412463Sralph execl(OF, cp, width, length, 0); 99512463Sralph log("can't execl output filter %s", OF); 99612463Sralph exit(1); 99712463Sralph } 99812463Sralph (void) close(p[0]); /* close input side */ 99912463Sralph ofd = p[1]; /* use pipe for output */ 100012463Sralph } else { 100112463Sralph ofd = pfd; 100212463Sralph ofilter = 0; 100312463Sralph } 100412463Sralph } 100512463Sralph 100612111Sralph struct bauds { 100712111Sralph int baud; 100812111Sralph int speed; 100912111Sralph } bauds[] = { 101012111Sralph 50, B50, 101112111Sralph 75, B75, 101212111Sralph 110, B110, 101312111Sralph 134, B134, 101412111Sralph 150, B150, 101512111Sralph 200, B200, 101612111Sralph 300, B300, 101712111Sralph 600, B600, 101812111Sralph 1200, B1200, 101912111Sralph 1800, B1800, 102012111Sralph 2400, B2400, 102112111Sralph 4800, B4800, 102212111Sralph 9600, B9600, 102312111Sralph 19200, EXTA, 102412111Sralph 38400, EXTB, 102512111Sralph 0, 0 102612111Sralph }; 102712111Sralph 102812111Sralph /* 102912111Sralph * setup tty lines. 103012111Sralph */ 1031*12877Sralph static 103212111Sralph setty() 103312111Sralph { 103412111Sralph struct sgttyb ttybuf; 103512111Sralph register struct bauds *bp; 103612111Sralph 103712111Sralph if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) { 103812111Sralph log("cannot set exclusive-use"); 103912111Sralph exit(1); 104012111Sralph } 104112111Sralph if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) { 104212111Sralph log("cannot get tty parameters"); 104312111Sralph exit(1); 104412111Sralph } 104512111Sralph if (BR > 0) { 104612111Sralph for (bp = bauds; bp->baud; bp++) 104712111Sralph if (BR == bp->baud) 104812111Sralph break; 104912111Sralph if (!bp->baud) { 105012111Sralph log("illegal baud rate %d", BR); 105112111Sralph exit(1); 105212111Sralph } 105312111Sralph ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed; 105412111Sralph } 105512111Sralph if (FC) 105612111Sralph ttybuf.sg_flags &= ~FC; 105712111Sralph if (FS) 105812111Sralph ttybuf.sg_flags |= FS; 105912111Sralph if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) { 106012111Sralph log("cannot set tty parameters"); 106112111Sralph exit(1); 106212111Sralph } 106312111Sralph if (XC) { 106412111Sralph if (ioctl(pfd, TIOCLBIC, &XC) < 0) { 106512111Sralph log("cannot set local tty parameters"); 106612111Sralph exit(1); 106712111Sralph } 106812111Sralph } 106912111Sralph if (XS) { 107012111Sralph if (ioctl(pfd, TIOCLBIS, &XS) < 0) { 107112111Sralph log("cannot set local tty parameters"); 107212111Sralph exit(1); 107312111Sralph } 107412111Sralph } 107512111Sralph } 107612463Sralph 107712463Sralph /*VARARGS1*/ 107812463Sralph static 107912463Sralph status(msg, a1, a2, a3) 108012463Sralph char *msg; 108112463Sralph { 108212463Sralph register int fd; 108312463Sralph char buf[BUFSIZ]; 108412463Sralph 108512463Sralph umask(0); 108612463Sralph if ((fd = open(ST, FWRONLY|FCREATE|FTRUNCATE|FEXLOCK, 0664)) < 0) 108712463Sralph fatal("cannot create status file"); 108812463Sralph sprintf(buf, msg, a1, a2, a3); 108912463Sralph strcat(buf, "\n"); 109012463Sralph (void) write(fd, buf, strlen(buf)); 109112463Sralph (void) close(fd); 109212463Sralph } 1093