1*12581Sralph /* printjob.c 4.4 83/05/19 */ 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 */ 23*12581Sralph 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 */ 34*12581Sralph 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 198*12581Sralph * 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 275*12581Sralph case 'I': /* indent amount */ 276*12581Sralph strcpy(indent+2, line+1); 277*12581Sralph continue; 278*12581Sralph 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; 387*12581Sralph av[3] = indent; 388*12581Sralph 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; 395*12581Sralph av[4] = indent; 396*12581Sralph 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); 59012111Sralph if (write(pfd, buf, amt) != amt) 59112111Sralph return(1); 59212111Sralph if (noresponse()) 59312111Sralph return(1); 59412111Sralph sizerr = 0; 59512111Sralph for (i = 0; i < stb.st_size; i += BUFSIZ) { 59612111Sralph amt = BUFSIZ; 59712111Sralph if (i + amt > stb.st_size) 59812111Sralph amt = stb.st_size - i; 59912111Sralph if (sizerr == 0 && read(f, buf, amt) != amt) 60012111Sralph sizerr = 1; 60112111Sralph if (write(pfd, buf, amt) != amt) 60212111Sralph return(1); 60312111Sralph } 60412111Sralph (void) close(f); 60512111Sralph if (sizerr) { 60612111Sralph log("%s: changed size", file); 60712111Sralph (void) write(pfd, "\1", 1); /* tell recvjob to ignore this file */ 60812111Sralph return(-1); 60912111Sralph } 61012111Sralph if (write(pfd, "", 1) != 1) 61112111Sralph return(1); 61212111Sralph if (noresponse()) 61312111Sralph return(1); 61412111Sralph return(0); 61512111Sralph } 61612111Sralph 61712111Sralph /* 61812111Sralph * Check to make sure there have been no errors and that both programs 61912111Sralph * are in sync with eachother. 62012111Sralph * Return non-zero if the connection was lost. 62112111Sralph */ 62212111Sralph static 62312111Sralph noresponse() 62412111Sralph { 62512111Sralph char resp; 62612111Sralph 62712111Sralph if (read(pfd, &resp, 1) != 1 || resp != '\0') { 62812111Sralph log("lost connection or error in recvjob"); 62912111Sralph return(1); 63012111Sralph } 63112111Sralph return(0); 63212111Sralph } 63312111Sralph 63412111Sralph /* 63512111Sralph * Banner printing stuff 63612111Sralph */ 63712111Sralph banner(name1, name2) 63812111Sralph char *name1, *name2; 63912111Sralph { 64012111Sralph time_t tvec; 64112111Sralph extern char *ctime(); 64212111Sralph 64312111Sralph time(&tvec); 64412111Sralph if (!SF && !tof) 64512111Sralph (void) write(ofd, FF, strlen(FF)); 64612111Sralph if (SB) { /* short banner only */ 64712111Sralph if (class[0]) { 64812111Sralph (void) write(ofd, class, strlen(class)); 64912111Sralph (void) write(ofd, ":", 1); 65012111Sralph } 65112111Sralph (void) write(ofd, name1, strlen(name1)); 65212111Sralph (void) write(ofd, " Job: ", 7); 65312111Sralph (void) write(ofd, name2, strlen(name2)); 65412111Sralph (void) write(ofd, " Date: ", 8); 65512111Sralph (void) write(ofd, ctime(&tvec), 24); 65612111Sralph (void) write(ofd, "\n", 1); 65712111Sralph } else { /* normal banner */ 65812111Sralph (void) write(ofd, "\n\n\n", 3); 65912111Sralph scan_out(ofd, name1, '\0'); 66012111Sralph (void) write(ofd, "\n\n", 2); 66112111Sralph scan_out(ofd, name2, '\0'); 66212111Sralph if (class[0]) { 66312111Sralph (void) write(ofd,"\n\n\n",3); 66412111Sralph scan_out(ofd, class, '\0'); 66512111Sralph } 66612111Sralph (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15); 66712111Sralph (void) write(ofd, name2, strlen(name2)); 66812111Sralph (void) write(ofd, "\n\t\t\t\t\tDate: ", 12); 66912111Sralph (void) write(ofd, ctime(&tvec), 24); 67012111Sralph (void) write(ofd, "\n", 1); 67112111Sralph } 67212111Sralph if (!SF) 67312111Sralph (void) write(ofd, FF, strlen(FF)); 67412111Sralph tof = 1; 67512111Sralph } 67612111Sralph 67712111Sralph char * 67812111Sralph scnline(key, p, c) 67912111Sralph register char key, *p; 68012111Sralph char c; 68112111Sralph { 68212111Sralph register scnwidth; 68312111Sralph 68412111Sralph for (scnwidth = WIDTH; --scnwidth;) { 68512111Sralph key <<= 1; 68612111Sralph *p++ = key & 0200 ? c : BACKGND; 68712111Sralph } 68812111Sralph return (p); 68912111Sralph } 69012111Sralph 69112111Sralph #define TRC(q) (((q)-' ')&0177) 69212111Sralph 69312111Sralph scan_out(scfd, scsp, dlm) 69412111Sralph int scfd; 69512111Sralph char *scsp, dlm; 69612111Sralph { 69712111Sralph register char *strp; 69812111Sralph register nchrs, j; 69912111Sralph char outbuf[LINELEN+1], *sp, c, cc; 70012111Sralph int d, scnhgt; 70112111Sralph extern char scnkey[][HEIGHT]; /* in lpdchar.c */ 70212111Sralph 70312111Sralph for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) { 70412111Sralph strp = &outbuf[0]; 70512111Sralph sp = scsp; 70612111Sralph for (nchrs = 0; ; ) { 70712111Sralph d = dropit(c = TRC(cc = *sp++)); 70812111Sralph if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d)) 70912111Sralph for (j = WIDTH; --j;) 71012111Sralph *strp++ = BACKGND; 71112111Sralph else 71212111Sralph strp = scnline(scnkey[c][scnhgt-1-d], strp, cc); 71312111Sralph if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1) 71412111Sralph break; 71512111Sralph *strp++ = BACKGND; 71612111Sralph *strp++ = BACKGND; 71712111Sralph } 71812111Sralph while (*--strp == BACKGND && strp >= outbuf) 71912111Sralph ; 72012111Sralph strp++; 72112111Sralph *strp++ = '\n'; 72212111Sralph (void) write(scfd, outbuf, strp-outbuf); 72312111Sralph } 72412111Sralph } 72512111Sralph 72612111Sralph dropit(c) 72712111Sralph char c; 72812111Sralph { 72912111Sralph switch(c) { 73012111Sralph 73112111Sralph case TRC('_'): 73212111Sralph case TRC(';'): 73312111Sralph case TRC(','): 73412111Sralph case TRC('g'): 73512111Sralph case TRC('j'): 73612111Sralph case TRC('p'): 73712111Sralph case TRC('q'): 73812111Sralph case TRC('y'): 73912111Sralph return (DROP); 74012111Sralph 74112111Sralph default: 74212111Sralph return (0); 74312111Sralph } 74412111Sralph } 74512111Sralph 74612111Sralph /* 74712111Sralph * sendmail --- 74812111Sralph * tell people about job completion 74912111Sralph */ 75012111Sralph sendmail(bombed) 75112111Sralph int bombed; 75212111Sralph { 75312111Sralph static int p[2]; 75412111Sralph register int i; 75512111Sralph int stat; 75612111Sralph register char *cp; 75712111Sralph char buf[100]; 75812111Sralph 75912111Sralph pipe(p); 76012111Sralph if ((stat = dofork(DORETURN)) == 0) { /* child */ 76112111Sralph dup2(p[0], 0); 76212111Sralph for (i = 3; i < NOFILE; i++) 76312111Sralph (void) close(i); 76412111Sralph if ((cp = rindex(MAIL, '/')) != NULL) 76512111Sralph cp++; 76612111Sralph else 76712111Sralph cp = MAIL; 76812111Sralph sprintf(buf, "%s@%s", line+1, host); 76912111Sralph execl(MAIL, cp, buf, 0); 77012111Sralph exit(0); 77112111Sralph } else if (stat > 0) { /* parent */ 77212111Sralph dup2(p[1], 1); 77312111Sralph printf("To: %s\n", line+1); 77412111Sralph printf("Subject: printer job\n\n"); 77512111Sralph printf("Your printer job "); 77612111Sralph if (*jobname) 77712111Sralph printf("(%s) ", jobname); 77812463Sralph switch (bombed) { 77912463Sralph case 0: 78012463Sralph printf("\ncompleted successfully\n"); 78112463Sralph break; 78212463Sralph default: 78312463Sralph case 1: 78412463Sralph printf("\ncould not be printed\n"); 78512463Sralph break; 78612463Sralph case 2: 78712463Sralph printf("\ncould not be printed without an account on %s\n", host); 78812463Sralph break; 78912463Sralph } 79012111Sralph fflush(stdout); 79112111Sralph (void) close(1); 79212111Sralph } 79312111Sralph (void) close(p[0]); 79412111Sralph (void) close(p[1]); 79512111Sralph wait(&stat); 79612111Sralph } 79712111Sralph 79812111Sralph /* 79912111Sralph * dofork - fork with retries on failure 80012111Sralph */ 80112111Sralph dofork(action) 80212111Sralph int action; 80312111Sralph { 80412111Sralph register int i, pid; 80512111Sralph 80612111Sralph for (i = 0; i < 20; i++) { 80712463Sralph if ((pid = fork()) < 0) { 80812111Sralph sleep((unsigned)(i*i)); 80912463Sralph continue; 81012463Sralph } 81112463Sralph /* 81212463Sralph * Child should run as daemon instead of root 81312463Sralph */ 81412463Sralph if (pid == 0) 81512463Sralph setuid(DU); 81612463Sralph return(pid); 81712111Sralph } 81812111Sralph log("can't fork"); 81912111Sralph 82012111Sralph switch (action) { 82112111Sralph case DORETURN: 82212111Sralph return (-1); 82312111Sralph default: 82412111Sralph log("bad action (%d) to dofork", action); 82512111Sralph /*FALL THRU*/ 82612111Sralph case DOABORT: 82712111Sralph exit(1); 82812111Sralph } 82912111Sralph /*NOTREACHED*/ 83012111Sralph } 83112111Sralph 83212111Sralph /* 83312111Sralph * Cleanup child processes when a SIGINT is caught. 83412111Sralph */ 83512111Sralph onintr() 83612111Sralph { 83712111Sralph kill(0, SIGINT); 83812111Sralph if (ofilter > 0) 83912111Sralph kill(ofilter, SIGCONT); 84012111Sralph while (wait(0) > 0) 84112111Sralph ; 84212111Sralph exit(0); 84312111Sralph } 84412111Sralph 84512111Sralph init() 84612111Sralph { 84712111Sralph int status; 84812111Sralph 84912111Sralph if ((status = pgetent(line, printer)) < 0) { 85012111Sralph log("can't open printer description file"); 85112111Sralph exit(1); 85212111Sralph } else if (status == 0) { 85312111Sralph log("unknown printer"); 85412111Sralph exit(1); 85512111Sralph } 85612111Sralph if ((LP = pgetstr("lp", &bp)) == NULL) 85712111Sralph LP = DEFDEVLP; 85812111Sralph if ((RP = pgetstr("rp", &bp)) == NULL) 85912463Sralph RP = DEFLP; 86012111Sralph if ((LO = pgetstr("lo", &bp)) == NULL) 86112111Sralph LO = DEFLOCK; 86212111Sralph if ((ST = pgetstr("st", &bp)) == NULL) 86312111Sralph ST = DEFSTAT; 86412111Sralph if ((LF = pgetstr("lf", &bp)) == NULL) 86512111Sralph LF = DEFLOGF; 86612111Sralph if ((SD = pgetstr("sd", &bp)) == NULL) 86712111Sralph SD = DEFSPOOL; 86812111Sralph if ((DU = pgetnum("du")) < 0) 86912111Sralph DU = DEFUID; 87012111Sralph if ((FF = pgetstr("ff", &bp)) == NULL) 87112111Sralph FF = DEFFF; 87212111Sralph if ((PW = pgetnum("pw")) < 0) 87312111Sralph PW = DEFWIDTH; 87412111Sralph sprintf(&width[2], "%d", PW); 87512111Sralph if ((PL = pgetnum("pl")) < 0) 87612111Sralph PL = DEFLENGTH; 87712111Sralph sprintf(&length[2], "%d", PL); 87812463Sralph if ((PX = pgetnum("px")) < 0) 87912463Sralph PX = 0; 88012463Sralph sprintf(&pxwidth[2], "%d", PX); 88112463Sralph if ((PY = pgetnum("py")) < 0) 88212463Sralph PY = 0; 88312463Sralph sprintf(&pxlength[2], "%d", PY); 88412111Sralph RM = pgetstr("rm", &bp); 88512111Sralph AF = pgetstr("af", &bp); 88612111Sralph OF = pgetstr("of", &bp); 88712111Sralph IF = pgetstr("if", &bp); 88812463Sralph RF = pgetstr("rf", &bp); 88912111Sralph TF = pgetstr("tf", &bp); 89012111Sralph DF = pgetstr("df", &bp); 89112111Sralph GF = pgetstr("gf", &bp); 89212111Sralph VF = pgetstr("vf", &bp); 89312111Sralph CF = pgetstr("cf", &bp); 89412111Sralph TR = pgetstr("tr", &bp); 89512463Sralph RS = pgetflag("rs"); 89612111Sralph SF = pgetflag("sf"); 89712111Sralph SH = pgetflag("sh"); 89812111Sralph SB = pgetflag("sb"); 89912111Sralph RW = pgetflag("rw"); 90012111Sralph BR = pgetnum("br"); 90112111Sralph if ((FC = pgetnum("fc")) < 0) 90212111Sralph FC = 0; 90312111Sralph if ((FS = pgetnum("fs")) < 0) 90412111Sralph FS = 0; 90512111Sralph if ((XC = pgetnum("xc")) < 0) 90612111Sralph XC = 0; 90712111Sralph if ((XS = pgetnum("xs")) < 0) 90812111Sralph XS = 0; 909*12581Sralph tof = !pgetflag("fo"); 91012111Sralph } 91112111Sralph 91212463Sralph /* 91312463Sralph * Acquire line printer or remote connection. 91412463Sralph */ 91512463Sralph openpr() 91612463Sralph { 91712463Sralph register int i, n; 91812463Sralph 91912463Sralph if (*LP) { 92012463Sralph for (i = 1; ; i = i < 32 ? i << 1 : i) { 92112463Sralph pfd = open(LP, RW ? FRDWR : FWRONLY, 0); 92212463Sralph if (pfd >= 0) 92312463Sralph break; 92412463Sralph if (errno == ENOENT) { 92512463Sralph log("cannot open %s", LP); 92612463Sralph exit(1); 92712463Sralph } 92812463Sralph if (i == 1) 92912463Sralph status("waiting for %s to become ready (offline ?)", printer); 93012463Sralph sleep(i); 93112463Sralph } 93212463Sralph if (isatty(pfd)) 93312463Sralph setty(); 93412463Sralph status("%s is ready and printing", printer); 93512463Sralph } else if (RM != NULL) { 93612463Sralph for (i = 1; ; i = i < 512 ? i << 1 : i) { 93712528Sralph pfd = getport(RM); 93812463Sralph if (pfd >= 0) { 93912463Sralph (void) sprintf(line, "\2%s\n", RP); 94012463Sralph n = strlen(line); 94112463Sralph if (write(pfd, line, n) != n) 94212463Sralph break; 94312463Sralph if (noresponse()) 94412463Sralph (void) close(pfd); 94512463Sralph else 94612463Sralph break; 94712463Sralph } 94812463Sralph if (i == 1) 94912463Sralph status("waiting for %s to come up", RM); 95012463Sralph sleep(i); 95112463Sralph } 95212463Sralph status("sending to %s", RM); 95312463Sralph remote = 1; 95412463Sralph } else { 95512463Sralph log("no line printer device or remote machine name"); 95612463Sralph exit(1); 95712463Sralph } 95812463Sralph /* 95912463Sralph * Start up an output filter, if needed. 96012463Sralph */ 96112463Sralph if (OF) { 96212463Sralph int p[2]; 96312463Sralph char *cp; 96412463Sralph 96512463Sralph pipe(p); 96612463Sralph if ((ofilter = dofork(DOABORT)) == 0) { /* child */ 96712463Sralph dup2(p[0], 0); /* pipe is std in */ 96812463Sralph dup2(pfd, 1); /* printer is std out */ 96912463Sralph for (i = 3; i < NOFILE; i++) 97012463Sralph (void) close(i); 97112463Sralph if ((cp = rindex(OF, '/')) == NULL) 97212463Sralph cp = OF; 97312463Sralph else 97412463Sralph cp++; 97512463Sralph execl(OF, cp, width, length, 0); 97612463Sralph log("can't execl output filter %s", OF); 97712463Sralph exit(1); 97812463Sralph } 97912463Sralph (void) close(p[0]); /* close input side */ 98012463Sralph ofd = p[1]; /* use pipe for output */ 98112463Sralph } else { 98212463Sralph ofd = pfd; 98312463Sralph ofilter = 0; 98412463Sralph } 98512463Sralph } 98612463Sralph 98712111Sralph struct bauds { 98812111Sralph int baud; 98912111Sralph int speed; 99012111Sralph } bauds[] = { 99112111Sralph 50, B50, 99212111Sralph 75, B75, 99312111Sralph 110, B110, 99412111Sralph 134, B134, 99512111Sralph 150, B150, 99612111Sralph 200, B200, 99712111Sralph 300, B300, 99812111Sralph 600, B600, 99912111Sralph 1200, B1200, 100012111Sralph 1800, B1800, 100112111Sralph 2400, B2400, 100212111Sralph 4800, B4800, 100312111Sralph 9600, B9600, 100412111Sralph 19200, EXTA, 100512111Sralph 38400, EXTB, 100612111Sralph 0, 0 100712111Sralph }; 100812111Sralph 100912111Sralph /* 101012111Sralph * setup tty lines. 101112111Sralph */ 101212111Sralph setty() 101312111Sralph { 101412111Sralph struct sgttyb ttybuf; 101512111Sralph register struct bauds *bp; 101612111Sralph 101712111Sralph if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) { 101812111Sralph log("cannot set exclusive-use"); 101912111Sralph exit(1); 102012111Sralph } 102112111Sralph if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) { 102212111Sralph log("cannot get tty parameters"); 102312111Sralph exit(1); 102412111Sralph } 102512111Sralph if (BR > 0) { 102612111Sralph for (bp = bauds; bp->baud; bp++) 102712111Sralph if (BR == bp->baud) 102812111Sralph break; 102912111Sralph if (!bp->baud) { 103012111Sralph log("illegal baud rate %d", BR); 103112111Sralph exit(1); 103212111Sralph } 103312111Sralph ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed; 103412111Sralph } 103512111Sralph if (FC) 103612111Sralph ttybuf.sg_flags &= ~FC; 103712111Sralph if (FS) 103812111Sralph ttybuf.sg_flags |= FS; 103912111Sralph if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) { 104012111Sralph log("cannot set tty parameters"); 104112111Sralph exit(1); 104212111Sralph } 104312111Sralph if (XC) { 104412111Sralph if (ioctl(pfd, TIOCLBIC, &XC) < 0) { 104512111Sralph log("cannot set local tty parameters"); 104612111Sralph exit(1); 104712111Sralph } 104812111Sralph } 104912111Sralph if (XS) { 105012111Sralph if (ioctl(pfd, TIOCLBIS, &XS) < 0) { 105112111Sralph log("cannot set local tty parameters"); 105212111Sralph exit(1); 105312111Sralph } 105412111Sralph } 105512111Sralph } 105612463Sralph 105712463Sralph /*VARARGS1*/ 105812463Sralph static 105912463Sralph status(msg, a1, a2, a3) 106012463Sralph char *msg; 106112463Sralph { 106212463Sralph register int fd; 106312463Sralph char buf[BUFSIZ]; 106412463Sralph 106512463Sralph umask(0); 106612463Sralph if ((fd = open(ST, FWRONLY|FCREATE|FTRUNCATE|FEXLOCK, 0664)) < 0) 106712463Sralph fatal("cannot create status file"); 106812463Sralph sprintf(buf, msg, a1, a2, a3); 106912463Sralph strcat(buf, "\n"); 107012463Sralph (void) write(fd, buf, strlen(buf)); 107112463Sralph (void) close(fd); 107212463Sralph } 1073