1*12692Sralph /* printjob.c 4.5 83/05/23 */ 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 */ 2312581Sralph int tof; /* true if at top of form */ 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 */ 3412581Sralph char indent[10] = "-i0"; /* indentation size in characters */ 3512111Sralph 3612111Sralph printjob() 3712111Sralph { 3812111Sralph struct stat stb; 3912111Sralph register struct queue *q, **qp; 4012111Sralph struct queue **queue; 4112111Sralph register int i, nitems; 4212111Sralph long pidoff; 4312111Sralph extern int onintr(); 4412111Sralph 4512111Sralph init(); /* set up capabilities */ 4612111Sralph (void) close(2); /* set up log file */ 4712111Sralph (void) open(LF, FWRONLY|FAPPEND, 0); 4812463Sralph dup2(2, 1); /* closes original connection */ 4912463Sralph pid = getpid(); /* for use with lprm */ 5012111Sralph setpgrp(0, pid); 5112463Sralph sigset(SIGINT, onintr); 5212111Sralph 5312111Sralph /* 5412111Sralph * uses short form file names 5512111Sralph */ 5612111Sralph if (chdir(SD) < 0) { 5712111Sralph log("cannot chdir to %s", SD); 5812111Sralph exit(1); 5912111Sralph } 6012463Sralph if (stat(LO, &stb) == 0 && (stb.st_mode & 0100)) 6112463Sralph exit(0); /* printing disabled */ 6212111Sralph if ((lfd = open(LO, FWRONLY|FCREATE|FTRUNCATE|FEXLOCK|FNBLOCK, 0664)) < 0) { 6312111Sralph if (errno == EWOULDBLOCK) /* active deamon present */ 6412111Sralph exit(0); 6512111Sralph log("cannot create %s", LO); 6612111Sralph exit(1); 6712111Sralph } 6812111Sralph /* 6912111Sralph * write process id for others to know 7012111Sralph */ 7112111Sralph sprintf(line, "%u\n", pid); 7212111Sralph pidoff = i = strlen(line); 7312463Sralph if (write(lfd, line, i) != i) { 7412111Sralph log("cannot write daemon pid"); 7512111Sralph exit(1); 7612111Sralph } 7712111Sralph /* 7812111Sralph * search the spool directory for work and sort by queue order. 7912111Sralph */ 8012111Sralph if ((nitems = getq(&queue)) < 0) { 8112111Sralph log("can't scan spool directory %s", SD); 8212111Sralph exit(1); 8312111Sralph } 8412463Sralph if (nitems == 0) /* no work to do */ 8512111Sralph exit(0); 8612463Sralph openpr(); /* open printer or remote */ 8712463Sralph again: 8812111Sralph /* 8912111Sralph * we found something to do now do it -- 9012111Sralph * write the name of the current control file into the lock file 9112111Sralph * so the spool queue program can tell what we're working on 9212111Sralph */ 9312111Sralph for (qp = queue; nitems--; free((char *) q)) { 9412111Sralph q = *qp++; 9512111Sralph if (stat(q->q_name, &stb) < 0) 9612111Sralph continue; 9712463Sralph restart: 9812111Sralph (void) lseek(lfd, pidoff, 0); 9912111Sralph (void) sprintf(line, "%s\n", q->q_name); 10012111Sralph i = strlen(line); 10112111Sralph if (write(lfd, line, i) != i) 10212111Sralph log("can't write (%d) control file name", errno); 10312111Sralph if (!remote) 10412111Sralph i = printit(q->q_name); 10512111Sralph else 10612111Sralph i = sendit(q->q_name); 10712463Sralph /* 10812463Sralph * Check to see if we are supposed to stop printing. 10912463Sralph */ 11012463Sralph if (stat(LO, &stb) == 0 && (stb.st_mode & 0100)) 11112463Sralph goto done; 11212463Sralph /* 11312463Sralph * Check to see if we should try reprinting the job. 11412463Sralph */ 11512463Sralph if (i > 0) { 11612111Sralph log("restarting"); 11712111Sralph if (ofilter > 0) { 11812111Sralph kill(ofilter, SIGCONT); /* to be sure */ 11912111Sralph (void) close(ofd); 12012111Sralph while ((i = wait(0)) > 0 && i != ofilter) 12112111Sralph ; 12212111Sralph ofilter = 0; 12312111Sralph } 12412463Sralph (void) close(pfd); /* close printer */ 12512463Sralph (void) lseek(lfd, pidoff, 0); 12612463Sralph if (write(lfd, "\n", 1) != 1) 12712463Sralph log("can't write (%d) control file name", errno); 12812463Sralph openpr(); /* try to reopen printer */ 12912111Sralph goto restart; 13012111Sralph } 13112111Sralph } 13212111Sralph free((char *) queue); 13312463Sralph /* 13412463Sralph * search the spool directory for more work. 13512463Sralph */ 13612463Sralph if ((nitems = getq(&queue)) < 0) { 13712463Sralph log("can't scan spool directory %s", SD); 13812463Sralph exit(1); 13912463Sralph } 14012463Sralph if (nitems == 0) { /* no more work to do */ 14112463Sralph done: 14212463Sralph if (!SF && !tof) 14312463Sralph (void) write(ofd, FF, strlen(FF)); 14412463Sralph if (TR != NULL) /* output trailer */ 14512463Sralph (void) write(ofd, TR, strlen(TR)); 14612463Sralph exit(0); 14712463Sralph } 14812111Sralph goto again; 14912111Sralph } 15012111Sralph 15112111Sralph char fonts[4][50]; /* fonts for troff */ 15212111Sralph 15312111Sralph static char ifonts[4][18] = { 15412111Sralph "/usr/lib/vfont/R", 15512111Sralph "/usr/lib/vfont/I", 15612111Sralph "/usr/lib/vfont/B", 15712111Sralph "/usr/lib/vfont/S" 15812111Sralph }; 15912111Sralph 16012111Sralph /* 16112111Sralph * The remaining part is the reading of the control file (cf) 16212111Sralph * and performing the various actions. 16312111Sralph * Returns 0 if everthing was OK, 1 if we should try to reprint the job and 16412111Sralph * -1 if a non-recoverable error occured. 16512111Sralph */ 16612111Sralph printit(file) 16712111Sralph char *file; 16812111Sralph { 16912111Sralph register int i; 17012111Sralph int bombed = 0; 17112111Sralph 17212111Sralph /* 17312111Sralph * open control file 17412111Sralph */ 17512111Sralph if ((cfp = fopen(file, "r")) == NULL) { 17612111Sralph log("control file (%s) open failure <errno = %d>", file, errno); 17712111Sralph return(0); 17812111Sralph } 17912111Sralph /* 18012111Sralph * Reset troff fonts. 18112111Sralph */ 18212111Sralph for (i = 0; i < 4; i++) 18312111Sralph strcpy(fonts[i], ifonts[i]); 18412111Sralph 18512111Sralph /* 18612111Sralph * read the control file for work to do 18712111Sralph * 18812111Sralph * file format -- first character in the line is a command 18912111Sralph * rest of the line is the argument. 19012111Sralph * valid commands are: 19112111Sralph * 19212111Sralph * J -- "job name" on banner page 19312111Sralph * C -- "class name" on banner page 19412111Sralph * L -- "literal" user's name to print on banner 19512111Sralph * T -- "title" for pr 19612111Sralph * H -- "host name" of machine where lpr was done 19712111Sralph * P -- "person" user's login name 19812581Sralph * I -- "indent" amount to indent output 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 27512581Sralph case 'I': /* indent amount */ 27612581Sralph strcpy(indent+2, line+1); 27712581Sralph continue; 27812581Sralph 27912111Sralph default: /* some file to print */ 28012111Sralph if ((i = print(line[0], line+1)) > 0) { 28112111Sralph (void) fclose(cfp); 28212111Sralph return(1); 28312111Sralph } else if (i < 0) 28412111Sralph bombed = 1; 28512111Sralph title[0] = '\0'; 28612111Sralph continue; 28712111Sralph 28812111Sralph case 'N': 28912111Sralph case 'U': 29012111Sralph case 'M': 29112111Sralph continue; 29212111Sralph } 29312111Sralph 29412111Sralph /* pass 2 */ 29512111Sralph 29612463Sralph pass2: 29712111Sralph fseek(cfp, 0L, 0); 29812111Sralph while (getline(cfp)) 29912111Sralph switch (line[0]) { 30012111Sralph case 'M': 30112463Sralph if (bombed != 2) /* already sent if 2 */ 30212463Sralph sendmail(bombed); 30312111Sralph continue; 30412111Sralph 30512111Sralph case 'U': 30612111Sralph (void) unlink(line+1); 30712111Sralph } 30812111Sralph /* 30912111Sralph * clean-up incase another control file exists 31012111Sralph */ 31112111Sralph (void) fclose(cfp); 31212111Sralph (void) unlink(file); 31312111Sralph return(0); 31412111Sralph } 31512111Sralph 31612111Sralph /* 31712111Sralph * Print a file. 31812111Sralph * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, TF, CF, VF}. 31912111Sralph * Return -1 if a non-recoverable error occured, 1 if a recoverable error and 32012111Sralph * 0 if all is well. 32112111Sralph * Note: all filters take stdin as the file, stdout as the printer, 32212111Sralph * stderr as the log file, and must not ignore SIGINT. 32312111Sralph */ 32412111Sralph print(format, file) 32512111Sralph int format; 32612111Sralph char *file; 32712111Sralph { 32812111Sralph register int n, fi, fo; 32912111Sralph register char *prog; 33012111Sralph char *av[15], buf[BUFSIZ]; 33112111Sralph int pid, p[2], stopped = 0; 33212111Sralph union wait status; 33312111Sralph 33412111Sralph if ((fi = open(file, FRDONLY, 0)) < 0) { 33512111Sralph log("%s: open failure <errno = %d>", file, errno); 33612111Sralph return(-1); 33712111Sralph } 33812111Sralph if (!SF && !tof) { /* start on a fresh page */ 33912111Sralph (void) write(ofd, FF, strlen(FF)); 34012111Sralph tof = 1; 34112111Sralph } 34212111Sralph if (IF == NULL && (format == 'f' || format == 'l')) { 34312111Sralph tof = 0; 34412111Sralph while ((n = read(fi, buf, BUFSIZ)) > 0) 34512111Sralph if (write(ofd, buf, n) != n) { 34612111Sralph (void) close(fi); 34712111Sralph return(1); 34812111Sralph } 34912111Sralph (void) close(fi); 35012111Sralph return(0); 35112111Sralph } 35212111Sralph switch (format) { 35312111Sralph case 'p': /* print file using 'pr' */ 35412111Sralph if (IF == NULL) { /* use output filter */ 35512111Sralph prog = PR; 35612111Sralph av[0] = "pr"; 35712111Sralph av[1] = width; 35812111Sralph av[2] = length; 35912111Sralph av[3] = "-h"; 36012111Sralph av[4] = *title ? title : " "; 36112111Sralph av[5] = 0; 36212111Sralph fo = ofd; 36312111Sralph goto start; 36412111Sralph } 36512111Sralph pipe(p); 36612111Sralph if ((prchild = dofork(DORETURN)) == 0) { /* child */ 36712111Sralph dup2(fi, 0); /* file is stdin */ 36812111Sralph dup2(p[1], 1); /* pipe is stdout */ 36912111Sralph for (n = 3; n < NOFILE; n++) 37012111Sralph (void) close(n); 37112111Sralph execl(PR, "pr", width, length, "-h", *title ? title : " ", 0); 37212111Sralph log("cannot execl %s", PR); 37312111Sralph exit(2); 37412111Sralph } 37512111Sralph (void) close(p[1]); /* close output side */ 37612111Sralph (void) close(fi); 37712111Sralph if (prchild < 0) { 37812111Sralph prchild = 0; 37912111Sralph (void) close(p[0]); 38012111Sralph return(-1); 38112111Sralph } 38212111Sralph fi = p[0]; /* use pipe for input */ 38312111Sralph case 'f': /* print plain text file */ 38412111Sralph prog = IF; 38512111Sralph av[1] = width; 38612111Sralph av[2] = length; 38712581Sralph av[3] = indent; 38812581Sralph n = 4; 38912111Sralph break; 39012111Sralph case 'l': /* like 'f' but pass control characters */ 39112111Sralph prog = IF; 39212111Sralph av[1] = "-l"; 39312111Sralph av[2] = width; 39412111Sralph av[3] = length; 39512581Sralph av[4] = indent; 39612581Sralph n = 5; 39712111Sralph break; 39812463Sralph case 'r': /* print a fortran text file */ 39912463Sralph prog = RF; 40012463Sralph av[1] = width; 40112463Sralph av[2] = length; 40212463Sralph n = 3; 40312463Sralph break; 40412111Sralph case 't': /* print troff output */ 40512463Sralph case 'd': /* print tex output */ 40612111Sralph (void) unlink(".railmag"); 40712463Sralph if ((fo = creat(".railmag", FILMOD)) < 0) { 40812111Sralph log("cannot create .railmag"); 40912111Sralph (void) unlink(".railmag"); 41012111Sralph } else { 41112111Sralph for (n = 0; n < 4; n++) { 41212111Sralph if (fonts[n][0] != '/') 41312111Sralph (void) write(fo, "/usr/lib/vfont/", 15); 41412111Sralph (void) write(fo, fonts[n], strlen(fonts[n])); 41512111Sralph (void) write(fo, "\n", 1); 41612111Sralph } 41712111Sralph (void) close(fo); 41812111Sralph } 41912111Sralph prog = (format == 't') ? TF : DF; 42012463Sralph av[1] = pxwidth; 42112463Sralph av[2] = pxlength; 42212463Sralph n = 3; 42312111Sralph break; 42412111Sralph case 'c': /* print cifplot output */ 42512111Sralph prog = CF; 42612463Sralph av[1] = pxwidth; 42712463Sralph av[2] = pxlength; 42812463Sralph n = 3; 42912111Sralph break; 43012111Sralph case 'g': /* print plot(1G) output */ 43112111Sralph prog = GF; 43212463Sralph av[1] = pxwidth; 43312463Sralph av[2] = pxlength; 43412463Sralph n = 3; 43512111Sralph break; 43612111Sralph case 'v': /* print raster output */ 43712111Sralph prog = VF; 43812463Sralph av[1] = pxwidth; 43912463Sralph av[2] = pxlength; 44012463Sralph n = 3; 44112111Sralph break; 44212111Sralph default: 44312111Sralph (void) close(fi); 44412111Sralph log("illegal format character '%c'", format); 44512111Sralph return(-1); 44612111Sralph } 44712111Sralph if ((av[0] = rindex(prog, '/')) != NULL) 44812111Sralph av[0]++; 44912111Sralph else 45012111Sralph av[0] = prog; 45112111Sralph av[n++] = "-n"; 45212111Sralph av[n++] = logname; 45312111Sralph av[n++] = "-h"; 45412111Sralph av[n++] = host; 45512111Sralph av[n++] = AF; 45612111Sralph av[n] = 0; 45712111Sralph fo = pfd; 45812111Sralph if (ofilter > 0) { /* stop output filter */ 45912111Sralph write(ofd, "\031\1", 2); 46012111Sralph while ((pid = wait3(&status, WUNTRACED, 0)) > 0 && pid != ofilter) 46112111Sralph ; 46212111Sralph if (status.w_stopval != WSTOPPED) { 46312111Sralph (void) close(fi); 46412111Sralph log("output filter died (%d)", status.w_retcode); 46512111Sralph return(1); 46612111Sralph } 46712111Sralph stopped++; 46812111Sralph } 46912111Sralph start: 47012111Sralph if ((child = dofork(DORETURN)) == 0) { /* child */ 47112111Sralph dup2(fi, 0); 47212111Sralph dup2(fo, 1); 47312111Sralph for (n = 3; n < NOFILE; n++) 47412111Sralph (void) close(n); 47512111Sralph execv(prog, av); 47612111Sralph log("cannot execl %s", prog); 47712111Sralph exit(2); 47812111Sralph } 47912111Sralph (void) close(fi); 48012111Sralph if (child < 0) 48112111Sralph status.w_retcode = 100; 48212111Sralph else 48312111Sralph while ((pid = wait(&status)) > 0 && pid != child) 48412111Sralph ; 48512111Sralph child = 0; 48612111Sralph prchild = 0; 48712111Sralph if (stopped) { /* restart output filter */ 48812111Sralph if (kill(ofilter, SIGCONT) < 0) { 48912111Sralph log("cannot restart output filter"); 49012111Sralph exit(1); 49112111Sralph } 49212111Sralph } 49312111Sralph tof = 0; 49412111Sralph if (!WIFEXITED(status) || status.w_retcode > 1) { 49512111Sralph log("Daemon Filter '%c' Malfunction (%d)", format, status.w_retcode); 49612111Sralph return(-1); 49712111Sralph } else if (status.w_retcode == 1) 49812111Sralph return(1); 49912111Sralph tof = 1; 50012111Sralph return(0); 50112111Sralph } 50212111Sralph 50312111Sralph /* 50412111Sralph * Send the daemon control file (cf) and any data files. 50512111Sralph * Return -1 if a non-recoverable error occured, 1 if a recoverable error and 50612111Sralph * 0 if all is well. 50712111Sralph */ 50812111Sralph sendit(file) 50912111Sralph char *file; 51012111Sralph { 51112111Sralph register int linelen, err = 0; 51212111Sralph char last[132]; 51312111Sralph 51412111Sralph /* 51512111Sralph * open control file 51612111Sralph */ 51712111Sralph if ((cfp = fopen(file, "r")) == NULL) { 51812111Sralph log("control file (%s) open failure <errno = %d>", file, errno); 51912111Sralph return(0); 52012111Sralph } 52112111Sralph /* 52212111Sralph * read the control file for work to do 52312111Sralph * 52412111Sralph * file format -- first character in the line is a command 52512111Sralph * rest of the line is the argument. 52612111Sralph * commands of interest are: 52712111Sralph * 52812111Sralph * a-z -- "file name" name of file to print 52912111Sralph * U -- "unlink" name of file to remove 53012111Sralph * (after we print it. (Pass 2 only)). 53112111Sralph */ 53212111Sralph 53312111Sralph /* 53412111Sralph * pass 1 53512111Sralph */ 53612111Sralph while (getline(cfp)) { 53712111Sralph again: 53812111Sralph if (line[0] >= 'a' && line[0] <= 'z') { 53912111Sralph strcpy(last, line); 54012111Sralph while (linelen = getline(cfp)) 54112111Sralph if (strcmp(last, line)) 54212111Sralph break; 54312111Sralph if ((err = sendfile('\3', last+1)) > 0) { 54412111Sralph (void) fclose(cfp); 54512111Sralph return(1); 54612111Sralph } else if (err) 54712111Sralph break; 54812111Sralph if (linelen) 54912111Sralph goto again; 55012111Sralph break; 55112111Sralph } 55212111Sralph } 55312111Sralph if (!err && sendfile('\2', file) > 0) { 55412111Sralph (void) fclose(cfp); 55512111Sralph return(1); 55612111Sralph } 55712111Sralph /* 55812111Sralph * pass 2 55912111Sralph */ 56012111Sralph fseek(cfp, 0L, 0); 56112111Sralph while (getline(cfp)) 56212111Sralph if (line[0] == 'U') 56312111Sralph (void) unlink(line+1); 56412111Sralph /* 56512111Sralph * clean-up incase another control file exists 56612111Sralph */ 56712111Sralph (void) fclose(cfp); 56812111Sralph (void) unlink(file); 56912111Sralph return(0); 57012111Sralph } 57112111Sralph 57212111Sralph /* 57312111Sralph * Send a data file to the remote machine and spool it. 57412111Sralph * Return positive if we should try resending. 57512111Sralph */ 57612111Sralph sendfile(type, file) 57712111Sralph char type, *file; 57812111Sralph { 57912111Sralph register int f, i, amt; 58012111Sralph struct stat stb; 58112111Sralph char buf[BUFSIZ]; 58212111Sralph int sizerr; 58312111Sralph 58412111Sralph if ((f = open(file, FRDONLY, 0)) < 0 || fstat(f, &stb) < 0) { 58512111Sralph log("file (%s) open failure <errno = %d>", file, errno); 58612111Sralph return(-1); 58712111Sralph } 58812111Sralph (void) sprintf(buf, "%c%d %s\n", type, stb.st_size, file); 58912111Sralph amt = strlen(buf); 590*12692Sralph if (write(pfd, buf, amt) != amt) { 591*12692Sralph (void) close(f); 59212111Sralph return(1); 593*12692Sralph } 594*12692Sralph if (noresponse()) { 595*12692Sralph (void) close(f); 59612111Sralph return(1); 597*12692Sralph } 59812111Sralph sizerr = 0; 59912111Sralph for (i = 0; i < stb.st_size; i += BUFSIZ) { 60012111Sralph amt = BUFSIZ; 60112111Sralph if (i + amt > stb.st_size) 60212111Sralph amt = stb.st_size - i; 60312111Sralph if (sizerr == 0 && read(f, buf, amt) != amt) 60412111Sralph sizerr = 1; 605*12692Sralph if (write(pfd, buf, amt) != amt) { 606*12692Sralph (void) close(f); 60712111Sralph return(1); 608*12692Sralph } 60912111Sralph } 61012111Sralph (void) close(f); 61112111Sralph if (sizerr) { 61212111Sralph log("%s: changed size", file); 61312111Sralph (void) write(pfd, "\1", 1); /* tell recvjob to ignore this file */ 61412111Sralph return(-1); 61512111Sralph } 61612111Sralph if (write(pfd, "", 1) != 1) 61712111Sralph return(1); 61812111Sralph if (noresponse()) 61912111Sralph return(1); 62012111Sralph return(0); 62112111Sralph } 62212111Sralph 62312111Sralph /* 62412111Sralph * Check to make sure there have been no errors and that both programs 62512111Sralph * are in sync with eachother. 62612111Sralph * Return non-zero if the connection was lost. 62712111Sralph */ 62812111Sralph static 62912111Sralph noresponse() 63012111Sralph { 63112111Sralph char resp; 63212111Sralph 63312111Sralph if (read(pfd, &resp, 1) != 1 || resp != '\0') { 63412111Sralph log("lost connection or error in recvjob"); 63512111Sralph return(1); 63612111Sralph } 63712111Sralph return(0); 63812111Sralph } 63912111Sralph 64012111Sralph /* 64112111Sralph * Banner printing stuff 64212111Sralph */ 64312111Sralph banner(name1, name2) 64412111Sralph char *name1, *name2; 64512111Sralph { 64612111Sralph time_t tvec; 64712111Sralph extern char *ctime(); 64812111Sralph 64912111Sralph time(&tvec); 65012111Sralph if (!SF && !tof) 65112111Sralph (void) write(ofd, FF, strlen(FF)); 65212111Sralph if (SB) { /* short banner only */ 65312111Sralph if (class[0]) { 65412111Sralph (void) write(ofd, class, strlen(class)); 65512111Sralph (void) write(ofd, ":", 1); 65612111Sralph } 65712111Sralph (void) write(ofd, name1, strlen(name1)); 65812111Sralph (void) write(ofd, " Job: ", 7); 65912111Sralph (void) write(ofd, name2, strlen(name2)); 66012111Sralph (void) write(ofd, " Date: ", 8); 66112111Sralph (void) write(ofd, ctime(&tvec), 24); 66212111Sralph (void) write(ofd, "\n", 1); 66312111Sralph } else { /* normal banner */ 66412111Sralph (void) write(ofd, "\n\n\n", 3); 66512111Sralph scan_out(ofd, name1, '\0'); 66612111Sralph (void) write(ofd, "\n\n", 2); 66712111Sralph scan_out(ofd, name2, '\0'); 66812111Sralph if (class[0]) { 66912111Sralph (void) write(ofd,"\n\n\n",3); 67012111Sralph scan_out(ofd, class, '\0'); 67112111Sralph } 67212111Sralph (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15); 67312111Sralph (void) write(ofd, name2, strlen(name2)); 67412111Sralph (void) write(ofd, "\n\t\t\t\t\tDate: ", 12); 67512111Sralph (void) write(ofd, ctime(&tvec), 24); 67612111Sralph (void) write(ofd, "\n", 1); 67712111Sralph } 67812111Sralph if (!SF) 67912111Sralph (void) write(ofd, FF, strlen(FF)); 68012111Sralph tof = 1; 68112111Sralph } 68212111Sralph 68312111Sralph char * 68412111Sralph scnline(key, p, c) 68512111Sralph register char key, *p; 68612111Sralph char c; 68712111Sralph { 68812111Sralph register scnwidth; 68912111Sralph 69012111Sralph for (scnwidth = WIDTH; --scnwidth;) { 69112111Sralph key <<= 1; 69212111Sralph *p++ = key & 0200 ? c : BACKGND; 69312111Sralph } 69412111Sralph return (p); 69512111Sralph } 69612111Sralph 69712111Sralph #define TRC(q) (((q)-' ')&0177) 69812111Sralph 69912111Sralph scan_out(scfd, scsp, dlm) 70012111Sralph int scfd; 70112111Sralph char *scsp, dlm; 70212111Sralph { 70312111Sralph register char *strp; 70412111Sralph register nchrs, j; 70512111Sralph char outbuf[LINELEN+1], *sp, c, cc; 70612111Sralph int d, scnhgt; 70712111Sralph extern char scnkey[][HEIGHT]; /* in lpdchar.c */ 70812111Sralph 70912111Sralph for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) { 71012111Sralph strp = &outbuf[0]; 71112111Sralph sp = scsp; 71212111Sralph for (nchrs = 0; ; ) { 71312111Sralph d = dropit(c = TRC(cc = *sp++)); 71412111Sralph if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d)) 71512111Sralph for (j = WIDTH; --j;) 71612111Sralph *strp++ = BACKGND; 71712111Sralph else 71812111Sralph strp = scnline(scnkey[c][scnhgt-1-d], strp, cc); 71912111Sralph if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1) 72012111Sralph break; 72112111Sralph *strp++ = BACKGND; 72212111Sralph *strp++ = BACKGND; 72312111Sralph } 72412111Sralph while (*--strp == BACKGND && strp >= outbuf) 72512111Sralph ; 72612111Sralph strp++; 72712111Sralph *strp++ = '\n'; 72812111Sralph (void) write(scfd, outbuf, strp-outbuf); 72912111Sralph } 73012111Sralph } 73112111Sralph 73212111Sralph dropit(c) 73312111Sralph char c; 73412111Sralph { 73512111Sralph switch(c) { 73612111Sralph 73712111Sralph case TRC('_'): 73812111Sralph case TRC(';'): 73912111Sralph case TRC(','): 74012111Sralph case TRC('g'): 74112111Sralph case TRC('j'): 74212111Sralph case TRC('p'): 74312111Sralph case TRC('q'): 74412111Sralph case TRC('y'): 74512111Sralph return (DROP); 74612111Sralph 74712111Sralph default: 74812111Sralph return (0); 74912111Sralph } 75012111Sralph } 75112111Sralph 75212111Sralph /* 75312111Sralph * sendmail --- 75412111Sralph * tell people about job completion 75512111Sralph */ 75612111Sralph sendmail(bombed) 75712111Sralph int bombed; 75812111Sralph { 75912111Sralph static int p[2]; 76012111Sralph register int i; 76112111Sralph int stat; 76212111Sralph register char *cp; 76312111Sralph char buf[100]; 76412111Sralph 76512111Sralph pipe(p); 76612111Sralph if ((stat = dofork(DORETURN)) == 0) { /* child */ 76712111Sralph dup2(p[0], 0); 76812111Sralph for (i = 3; i < NOFILE; i++) 76912111Sralph (void) close(i); 77012111Sralph if ((cp = rindex(MAIL, '/')) != NULL) 77112111Sralph cp++; 77212111Sralph else 77312111Sralph cp = MAIL; 77412111Sralph sprintf(buf, "%s@%s", line+1, host); 77512111Sralph execl(MAIL, cp, buf, 0); 77612111Sralph exit(0); 77712111Sralph } else if (stat > 0) { /* parent */ 77812111Sralph dup2(p[1], 1); 77912111Sralph printf("To: %s\n", line+1); 78012111Sralph printf("Subject: printer job\n\n"); 78112111Sralph printf("Your printer job "); 78212111Sralph if (*jobname) 78312111Sralph printf("(%s) ", jobname); 78412463Sralph switch (bombed) { 78512463Sralph case 0: 78612463Sralph printf("\ncompleted successfully\n"); 78712463Sralph break; 78812463Sralph default: 78912463Sralph case 1: 79012463Sralph printf("\ncould not be printed\n"); 79112463Sralph break; 79212463Sralph case 2: 79312463Sralph printf("\ncould not be printed without an account on %s\n", host); 79412463Sralph break; 79512463Sralph } 79612111Sralph fflush(stdout); 79712111Sralph (void) close(1); 79812111Sralph } 79912111Sralph (void) close(p[0]); 80012111Sralph (void) close(p[1]); 80112111Sralph wait(&stat); 80212111Sralph } 80312111Sralph 80412111Sralph /* 80512111Sralph * dofork - fork with retries on failure 80612111Sralph */ 80712111Sralph dofork(action) 80812111Sralph int action; 80912111Sralph { 81012111Sralph register int i, pid; 81112111Sralph 81212111Sralph for (i = 0; i < 20; i++) { 81312463Sralph if ((pid = fork()) < 0) { 81412111Sralph sleep((unsigned)(i*i)); 81512463Sralph continue; 81612463Sralph } 81712463Sralph /* 81812463Sralph * Child should run as daemon instead of root 81912463Sralph */ 82012463Sralph if (pid == 0) 82112463Sralph setuid(DU); 82212463Sralph return(pid); 82312111Sralph } 82412111Sralph log("can't fork"); 82512111Sralph 82612111Sralph switch (action) { 82712111Sralph case DORETURN: 82812111Sralph return (-1); 82912111Sralph default: 83012111Sralph log("bad action (%d) to dofork", action); 83112111Sralph /*FALL THRU*/ 83212111Sralph case DOABORT: 83312111Sralph exit(1); 83412111Sralph } 83512111Sralph /*NOTREACHED*/ 83612111Sralph } 83712111Sralph 83812111Sralph /* 83912111Sralph * Cleanup child processes when a SIGINT is caught. 84012111Sralph */ 84112111Sralph onintr() 84212111Sralph { 84312111Sralph kill(0, SIGINT); 84412111Sralph if (ofilter > 0) 84512111Sralph kill(ofilter, SIGCONT); 84612111Sralph while (wait(0) > 0) 84712111Sralph ; 84812111Sralph exit(0); 84912111Sralph } 85012111Sralph 85112111Sralph init() 85212111Sralph { 85312111Sralph int status; 85412111Sralph 85512111Sralph if ((status = pgetent(line, printer)) < 0) { 85612111Sralph log("can't open printer description file"); 85712111Sralph exit(1); 85812111Sralph } else if (status == 0) { 85912111Sralph log("unknown printer"); 86012111Sralph exit(1); 86112111Sralph } 86212111Sralph if ((LP = pgetstr("lp", &bp)) == NULL) 86312111Sralph LP = DEFDEVLP; 86412111Sralph if ((RP = pgetstr("rp", &bp)) == NULL) 86512463Sralph RP = DEFLP; 86612111Sralph if ((LO = pgetstr("lo", &bp)) == NULL) 86712111Sralph LO = DEFLOCK; 86812111Sralph if ((ST = pgetstr("st", &bp)) == NULL) 86912111Sralph ST = DEFSTAT; 87012111Sralph if ((LF = pgetstr("lf", &bp)) == NULL) 87112111Sralph LF = DEFLOGF; 87212111Sralph if ((SD = pgetstr("sd", &bp)) == NULL) 87312111Sralph SD = DEFSPOOL; 87412111Sralph if ((DU = pgetnum("du")) < 0) 87512111Sralph DU = DEFUID; 87612111Sralph if ((FF = pgetstr("ff", &bp)) == NULL) 87712111Sralph FF = DEFFF; 87812111Sralph if ((PW = pgetnum("pw")) < 0) 87912111Sralph PW = DEFWIDTH; 88012111Sralph sprintf(&width[2], "%d", PW); 88112111Sralph if ((PL = pgetnum("pl")) < 0) 88212111Sralph PL = DEFLENGTH; 88312111Sralph sprintf(&length[2], "%d", PL); 88412463Sralph if ((PX = pgetnum("px")) < 0) 88512463Sralph PX = 0; 88612463Sralph sprintf(&pxwidth[2], "%d", PX); 88712463Sralph if ((PY = pgetnum("py")) < 0) 88812463Sralph PY = 0; 88912463Sralph sprintf(&pxlength[2], "%d", PY); 89012111Sralph RM = pgetstr("rm", &bp); 89112111Sralph AF = pgetstr("af", &bp); 89212111Sralph OF = pgetstr("of", &bp); 89312111Sralph IF = pgetstr("if", &bp); 89412463Sralph RF = pgetstr("rf", &bp); 89512111Sralph TF = pgetstr("tf", &bp); 89612111Sralph DF = pgetstr("df", &bp); 89712111Sralph GF = pgetstr("gf", &bp); 89812111Sralph VF = pgetstr("vf", &bp); 89912111Sralph CF = pgetstr("cf", &bp); 90012111Sralph TR = pgetstr("tr", &bp); 90112463Sralph RS = pgetflag("rs"); 90212111Sralph SF = pgetflag("sf"); 90312111Sralph SH = pgetflag("sh"); 90412111Sralph SB = pgetflag("sb"); 90512111Sralph RW = pgetflag("rw"); 90612111Sralph BR = pgetnum("br"); 90712111Sralph if ((FC = pgetnum("fc")) < 0) 90812111Sralph FC = 0; 90912111Sralph if ((FS = pgetnum("fs")) < 0) 91012111Sralph FS = 0; 91112111Sralph if ((XC = pgetnum("xc")) < 0) 91212111Sralph XC = 0; 91312111Sralph if ((XS = pgetnum("xs")) < 0) 91412111Sralph XS = 0; 91512581Sralph tof = !pgetflag("fo"); 91612111Sralph } 91712111Sralph 91812463Sralph /* 91912463Sralph * Acquire line printer or remote connection. 92012463Sralph */ 92112463Sralph openpr() 92212463Sralph { 92312463Sralph register int i, n; 92412463Sralph 92512463Sralph if (*LP) { 92612463Sralph for (i = 1; ; i = i < 32 ? i << 1 : i) { 92712463Sralph pfd = open(LP, RW ? FRDWR : FWRONLY, 0); 92812463Sralph if (pfd >= 0) 92912463Sralph break; 93012463Sralph if (errno == ENOENT) { 93112463Sralph log("cannot open %s", LP); 93212463Sralph exit(1); 93312463Sralph } 93412463Sralph if (i == 1) 93512463Sralph status("waiting for %s to become ready (offline ?)", printer); 93612463Sralph sleep(i); 93712463Sralph } 93812463Sralph if (isatty(pfd)) 93912463Sralph setty(); 94012463Sralph status("%s is ready and printing", printer); 94112463Sralph } else if (RM != NULL) { 94212463Sralph for (i = 1; ; i = i < 512 ? i << 1 : i) { 94312528Sralph pfd = getport(RM); 94412463Sralph if (pfd >= 0) { 94512463Sralph (void) sprintf(line, "\2%s\n", RP); 94612463Sralph n = strlen(line); 94712463Sralph if (write(pfd, line, n) != n) 94812463Sralph break; 94912463Sralph if (noresponse()) 95012463Sralph (void) close(pfd); 95112463Sralph else 95212463Sralph break; 95312463Sralph } 95412463Sralph if (i == 1) 95512463Sralph status("waiting for %s to come up", RM); 95612463Sralph sleep(i); 95712463Sralph } 95812463Sralph status("sending to %s", RM); 95912463Sralph remote = 1; 96012463Sralph } else { 96112463Sralph log("no line printer device or remote machine name"); 96212463Sralph exit(1); 96312463Sralph } 96412463Sralph /* 96512463Sralph * Start up an output filter, if needed. 96612463Sralph */ 96712463Sralph if (OF) { 96812463Sralph int p[2]; 96912463Sralph char *cp; 97012463Sralph 97112463Sralph pipe(p); 97212463Sralph if ((ofilter = dofork(DOABORT)) == 0) { /* child */ 97312463Sralph dup2(p[0], 0); /* pipe is std in */ 97412463Sralph dup2(pfd, 1); /* printer is std out */ 97512463Sralph for (i = 3; i < NOFILE; i++) 97612463Sralph (void) close(i); 97712463Sralph if ((cp = rindex(OF, '/')) == NULL) 97812463Sralph cp = OF; 97912463Sralph else 98012463Sralph cp++; 98112463Sralph execl(OF, cp, width, length, 0); 98212463Sralph log("can't execl output filter %s", OF); 98312463Sralph exit(1); 98412463Sralph } 98512463Sralph (void) close(p[0]); /* close input side */ 98612463Sralph ofd = p[1]; /* use pipe for output */ 98712463Sralph } else { 98812463Sralph ofd = pfd; 98912463Sralph ofilter = 0; 99012463Sralph } 99112463Sralph } 99212463Sralph 99312111Sralph struct bauds { 99412111Sralph int baud; 99512111Sralph int speed; 99612111Sralph } bauds[] = { 99712111Sralph 50, B50, 99812111Sralph 75, B75, 99912111Sralph 110, B110, 100012111Sralph 134, B134, 100112111Sralph 150, B150, 100212111Sralph 200, B200, 100312111Sralph 300, B300, 100412111Sralph 600, B600, 100512111Sralph 1200, B1200, 100612111Sralph 1800, B1800, 100712111Sralph 2400, B2400, 100812111Sralph 4800, B4800, 100912111Sralph 9600, B9600, 101012111Sralph 19200, EXTA, 101112111Sralph 38400, EXTB, 101212111Sralph 0, 0 101312111Sralph }; 101412111Sralph 101512111Sralph /* 101612111Sralph * setup tty lines. 101712111Sralph */ 101812111Sralph setty() 101912111Sralph { 102012111Sralph struct sgttyb ttybuf; 102112111Sralph register struct bauds *bp; 102212111Sralph 102312111Sralph if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) { 102412111Sralph log("cannot set exclusive-use"); 102512111Sralph exit(1); 102612111Sralph } 102712111Sralph if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) { 102812111Sralph log("cannot get tty parameters"); 102912111Sralph exit(1); 103012111Sralph } 103112111Sralph if (BR > 0) { 103212111Sralph for (bp = bauds; bp->baud; bp++) 103312111Sralph if (BR == bp->baud) 103412111Sralph break; 103512111Sralph if (!bp->baud) { 103612111Sralph log("illegal baud rate %d", BR); 103712111Sralph exit(1); 103812111Sralph } 103912111Sralph ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed; 104012111Sralph } 104112111Sralph if (FC) 104212111Sralph ttybuf.sg_flags &= ~FC; 104312111Sralph if (FS) 104412111Sralph ttybuf.sg_flags |= FS; 104512111Sralph if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) { 104612111Sralph log("cannot set tty parameters"); 104712111Sralph exit(1); 104812111Sralph } 104912111Sralph if (XC) { 105012111Sralph if (ioctl(pfd, TIOCLBIC, &XC) < 0) { 105112111Sralph log("cannot set local tty parameters"); 105212111Sralph exit(1); 105312111Sralph } 105412111Sralph } 105512111Sralph if (XS) { 105612111Sralph if (ioctl(pfd, TIOCLBIS, &XS) < 0) { 105712111Sralph log("cannot set local tty parameters"); 105812111Sralph exit(1); 105912111Sralph } 106012111Sralph } 106112111Sralph } 106212463Sralph 106312463Sralph /*VARARGS1*/ 106412463Sralph static 106512463Sralph status(msg, a1, a2, a3) 106612463Sralph char *msg; 106712463Sralph { 106812463Sralph register int fd; 106912463Sralph char buf[BUFSIZ]; 107012463Sralph 107112463Sralph umask(0); 107212463Sralph if ((fd = open(ST, FWRONLY|FCREATE|FTRUNCATE|FEXLOCK, 0664)) < 0) 107312463Sralph fatal("cannot create status file"); 107412463Sralph sprintf(buf, msg, a1, a2, a3); 107512463Sralph strcat(buf, "\n"); 107612463Sralph (void) write(fd, buf, strlen(buf)); 107712463Sralph (void) close(fd); 107812463Sralph } 1079