1*13954Ssam #ifndef lint 2*13954Ssam static char sccsid[] = "@(#)printjob.c 4.11 (Berkeley) 07/17/83"; 3*13954Ssam #endif 4*13954Ssam 512111Sralph /* 612111Sralph * printjob -- print jobs in the queue. 712111Sralph * 812111Sralph * NOTE: the lock file is used to pass information to lpq and lprm. 912111Sralph * it does not need to be removed because file locks are dynamic. 1012111Sralph */ 1112111Sralph 1212111Sralph #include "lp.h" 1312111Sralph 1412877Sralph #define DORETURN 0 /* absorb fork error */ 1512877Sralph #define DOABORT 1 /* abort if dofork fails */ 1612111Sralph 1712877Sralph static char title[80]; /* ``pr'' title */ 1812877Sralph static FILE *cfp; /* control file */ 1912877Sralph static int pfd; /* printer file descriptor */ 2012877Sralph static int ofd; /* output filter file descriptor */ 2112877Sralph static int lfd; /* lock file descriptor */ 2212877Sralph static int pid; /* pid of lpd process */ 2312877Sralph static int prchild; /* id of pr process */ 2412877Sralph static int child; /* id of any filters */ 2512877Sralph static int ofilter; /* id of output filter, if any */ 2612877Sralph static int tof; /* true if at top of form */ 2712877Sralph static int remote; /* true if sending files to remote */ 2812111Sralph 2912877Sralph static char logname[32]; /* user's login name */ 3012877Sralph static char jobname[32]; /* job or file name */ 3112877Sralph static char class[32]; /* classification field */ 3212877Sralph static char width[10] = "-w"; /* page width in characters */ 3312877Sralph static char length[10] = "-l"; /* page length in lines */ 3412877Sralph static char pxwidth[10] = "-x"; /* page width in pixels */ 3512877Sralph static char pxlength[10] = "-y"; /* page length in pixels */ 3612877Sralph static char indent[10] = "-i0"; /* indentation size in characters */ 3712111Sralph 3812111Sralph printjob() 3912111Sralph { 4012111Sralph struct stat stb; 4112111Sralph register struct queue *q, **qp; 4212111Sralph struct queue **queue; 4312111Sralph register int i, nitems; 4412111Sralph long pidoff; 4512111Sralph extern int onintr(); 4612111Sralph 4712111Sralph init(); /* set up capabilities */ 4813442Sralph (void) write(1, "", 1); /* ack that daemon is started */ 4912877Sralph (void) close(1); /* set up log file */ 5012877Sralph (void) close(2); 5113148Ssam if (open(LF, O_WRONLY|O_APPEND) < 0) 5213148Ssam (void) open("/dev/null", O_WRONLY); 5312877Sralph dup(1); 5412463Sralph pid = getpid(); /* for use with lprm */ 5512111Sralph setpgrp(0, pid); 5613148Ssam signal(SIGINT, onintr); 5712111Sralph 5812111Sralph /* 5912111Sralph * uses short form file names 6012111Sralph */ 6112111Sralph if (chdir(SD) < 0) { 6212111Sralph log("cannot chdir to %s", SD); 6312111Sralph exit(1); 6412111Sralph } 6512463Sralph if (stat(LO, &stb) == 0 && (stb.st_mode & 0100)) 6612463Sralph exit(0); /* printing disabled */ 6713169Sralph lfd = open(LO, O_WRONLY|O_CREAT|O_TRUNC, 0644); 6813169Sralph if (lfd < 0) { 6913169Sralph log("cannot create %s", LO); 7013169Sralph exit(1); 7113169Sralph } 7213169Sralph if (flock(lfd, LOCK_EX|LOCK_NB) < 0) { 7312111Sralph if (errno == EWOULDBLOCK) /* active deamon present */ 7412111Sralph exit(0); 7513169Sralph log("cannot lock %s", LO); 7612111Sralph exit(1); 7712111Sralph } 7813148Ssam ftruncate(lfd, 0); 7912111Sralph /* 8012111Sralph * write process id for others to know 8112111Sralph */ 8212111Sralph sprintf(line, "%u\n", pid); 8312111Sralph pidoff = i = strlen(line); 8412463Sralph if (write(lfd, line, i) != i) { 8512111Sralph log("cannot write daemon pid"); 8612111Sralph exit(1); 8712111Sralph } 8812111Sralph /* 8912111Sralph * search the spool directory for work and sort by queue order. 9012111Sralph */ 9112111Sralph if ((nitems = getq(&queue)) < 0) { 9212111Sralph log("can't scan spool directory %s", SD); 9312111Sralph exit(1); 9412111Sralph } 9512463Sralph if (nitems == 0) /* no work to do */ 9612111Sralph exit(0); 9713169Sralph if (stb.st_mode & 01) { /* reset queue flag */ 9813169Sralph if (fchmod(lfd, stb.st_mode & 0776) < 0) 9913169Sralph log("cannot chmod %s", LO); 10013169Sralph } 10112463Sralph openpr(); /* open printer or remote */ 10212463Sralph again: 10312111Sralph /* 10412111Sralph * we found something to do now do it -- 10512111Sralph * write the name of the current control file into the lock file 10612111Sralph * so the spool queue program can tell what we're working on 10712111Sralph */ 10812111Sralph for (qp = queue; nitems--; free((char *) q)) { 10912111Sralph q = *qp++; 11012111Sralph if (stat(q->q_name, &stb) < 0) 11112111Sralph continue; 11212463Sralph restart: 11312111Sralph (void) lseek(lfd, pidoff, 0); 11412111Sralph (void) sprintf(line, "%s\n", q->q_name); 11512111Sralph i = strlen(line); 11612111Sralph if (write(lfd, line, i) != i) 11712111Sralph log("can't write (%d) control file name", errno); 11812111Sralph if (!remote) 11912111Sralph i = printit(q->q_name); 12012111Sralph else 12112111Sralph i = sendit(q->q_name); 12212463Sralph /* 12313169Sralph * Check to see if we are supposed to stop printing or 12413169Sralph * if we are to rebuild the queue. 12512463Sralph */ 12613169Sralph if (fstat(lfd, &stb) == 0) { 12713169Sralph if (stb.st_mode & 0100) 12813169Sralph goto done; 12913169Sralph if (stb.st_mode & 01) { 13013169Sralph for (free((char *) q); nitems--; free((char *) q)) 13113169Sralph q = *qp++; 13213169Sralph if (fchmod(lfd, stb.st_mode & 0776) < 0) 13313169Sralph log("cannot chmod %s", LO); 13413169Sralph break; 13513169Sralph } 13613169Sralph } 13712463Sralph /* 13812463Sralph * Check to see if we should try reprinting the job. 13912463Sralph */ 14012463Sralph if (i > 0) { 14112111Sralph log("restarting"); 14212111Sralph if (ofilter > 0) { 14312111Sralph kill(ofilter, SIGCONT); /* to be sure */ 14412111Sralph (void) close(ofd); 14512111Sralph while ((i = wait(0)) > 0 && i != ofilter) 14612111Sralph ; 14712111Sralph ofilter = 0; 14812111Sralph } 14912463Sralph (void) close(pfd); /* close printer */ 15012463Sralph (void) lseek(lfd, pidoff, 0); 15112463Sralph if (write(lfd, "\n", 1) != 1) 15212463Sralph log("can't write (%d) control file name", errno); 15312463Sralph openpr(); /* try to reopen printer */ 15412111Sralph goto restart; 15512111Sralph } 15612111Sralph } 15712111Sralph free((char *) queue); 15812463Sralph /* 15912463Sralph * search the spool directory for more work. 16012463Sralph */ 16112463Sralph if ((nitems = getq(&queue)) < 0) { 16212463Sralph log("can't scan spool directory %s", SD); 16312463Sralph exit(1); 16412463Sralph } 16512463Sralph if (nitems == 0) { /* no more work to do */ 16612463Sralph done: 16712463Sralph if (!SF && !tof) 16812463Sralph (void) write(ofd, FF, strlen(FF)); 16912463Sralph if (TR != NULL) /* output trailer */ 17012463Sralph (void) write(ofd, TR, strlen(TR)); 17112463Sralph exit(0); 17212463Sralph } 17312111Sralph goto again; 17412111Sralph } 17512111Sralph 17612111Sralph char fonts[4][50]; /* fonts for troff */ 17712111Sralph 17812111Sralph static char ifonts[4][18] = { 17912111Sralph "/usr/lib/vfont/R", 18012111Sralph "/usr/lib/vfont/I", 18112111Sralph "/usr/lib/vfont/B", 18212111Sralph "/usr/lib/vfont/S" 18312111Sralph }; 18412111Sralph 18512111Sralph /* 18612111Sralph * The remaining part is the reading of the control file (cf) 18712111Sralph * and performing the various actions. 18812111Sralph * Returns 0 if everthing was OK, 1 if we should try to reprint the job and 18912111Sralph * -1 if a non-recoverable error occured. 19012111Sralph */ 19112877Sralph static 19212111Sralph printit(file) 19312111Sralph char *file; 19412111Sralph { 19512111Sralph register int i; 19612111Sralph int bombed = 0; 19712111Sralph 19812111Sralph /* 19912111Sralph * open control file 20012111Sralph */ 20112111Sralph if ((cfp = fopen(file, "r")) == NULL) { 20212111Sralph log("control file (%s) open failure <errno = %d>", file, errno); 20312111Sralph return(0); 20412111Sralph } 20512111Sralph /* 20612111Sralph * Reset troff fonts. 20712111Sralph */ 20812111Sralph for (i = 0; i < 4; i++) 20912111Sralph strcpy(fonts[i], ifonts[i]); 21012111Sralph 21112111Sralph /* 21212111Sralph * read the control file for work to do 21312111Sralph * 21412111Sralph * file format -- first character in the line is a command 21512111Sralph * rest of the line is the argument. 21612111Sralph * valid commands are: 21712111Sralph * 21812111Sralph * J -- "job name" on banner page 21912111Sralph * C -- "class name" on banner page 22012111Sralph * L -- "literal" user's name to print on banner 22112111Sralph * T -- "title" for pr 22212111Sralph * H -- "host name" of machine where lpr was done 22312111Sralph * P -- "person" user's login name 22412581Sralph * I -- "indent" amount to indent output 22512111Sralph * f -- "file name" name of text file to print 22612111Sralph * l -- "file name" text file with control chars 22712111Sralph * p -- "file name" text file to print with pr(1) 22812111Sralph * t -- "file name" troff(1) file to print 22913233Sralph * n -- "file name" ditroff(1) file to print 23012111Sralph * d -- "file name" dvi file to print 23112111Sralph * g -- "file name" plot(1G) file to print 23212111Sralph * v -- "file name" plain raster file to print 23312111Sralph * c -- "file name" cifplot file to print 23412111Sralph * 1 -- "R font file" for troff 23512111Sralph * 2 -- "I font file" for troff 23612111Sralph * 3 -- "B font file" for troff 23712111Sralph * 4 -- "S font file" for troff 23812111Sralph * N -- "name" of file (used by lpq) 23912111Sralph * U -- "unlink" name of file to remove 24012111Sralph * (after we print it. (Pass 2 only)). 24112111Sralph * M -- "mail" to user when done printing 24212111Sralph * 24312111Sralph * getline reads a line and expands tabs to blanks 24412111Sralph */ 24512111Sralph 24612111Sralph /* pass 1 */ 24712111Sralph 24812111Sralph while (getline(cfp)) 24912111Sralph switch (line[0]) { 25012111Sralph case 'H': 25112111Sralph strcpy(host, line+1); 25212111Sralph if (class[0] == '\0') 25312111Sralph strcpy(class, line+1); 25412111Sralph continue; 25512111Sralph 25612111Sralph case 'P': 25712111Sralph strcpy(logname, line+1); 25812463Sralph if (RS) { /* restricted */ 25912463Sralph if (getpwnam(logname) == (struct passwd *)0) { 26012463Sralph bombed = 2; 26112463Sralph sendmail(bombed); 26212463Sralph goto pass2; 26312463Sralph } 26412463Sralph } 26512111Sralph continue; 26612111Sralph 26712111Sralph case 'J': 26812111Sralph if (line[1] != '\0') 26912111Sralph strcpy(jobname, line+1); 27012111Sralph else 27112111Sralph strcpy(jobname, " "); 27212111Sralph continue; 27312111Sralph 27412111Sralph case 'C': 27512111Sralph if (line[1] != '\0') 27612111Sralph strcpy(class, line+1); 27712111Sralph else if (class[0] == '\0') 27812111Sralph gethostname(class, sizeof (class)); 27912111Sralph continue; 28012111Sralph 28112111Sralph case 'T': /* header title for pr */ 28212111Sralph strcpy(title, line+1); 28312111Sralph continue; 28412111Sralph 28512111Sralph case 'L': /* identification line */ 28612111Sralph if (!SH) 28712111Sralph banner(line+1, jobname); 28812111Sralph continue; 28912111Sralph 29012111Sralph case '1': /* troff fonts */ 29112111Sralph case '2': 29212111Sralph case '3': 29312111Sralph case '4': 29412111Sralph if (line[1] != '\0') 29512111Sralph strcpy(fonts[line[0]-'1'], line+1); 29612111Sralph continue; 29712111Sralph 29812111Sralph case 'W': /* page width */ 29912111Sralph strcpy(width+2, line+1); 30012111Sralph continue; 30112111Sralph 30212581Sralph case 'I': /* indent amount */ 30312581Sralph strcpy(indent+2, line+1); 30412581Sralph continue; 30512581Sralph 30612111Sralph default: /* some file to print */ 30712111Sralph if ((i = print(line[0], line+1)) > 0) { 30812111Sralph (void) fclose(cfp); 30912111Sralph return(1); 31012111Sralph } else if (i < 0) 31112111Sralph bombed = 1; 31212111Sralph title[0] = '\0'; 31312111Sralph continue; 31412111Sralph 31512111Sralph case 'N': 31612111Sralph case 'U': 31712111Sralph case 'M': 31812111Sralph continue; 31912111Sralph } 32012111Sralph 32112111Sralph /* pass 2 */ 32212111Sralph 32312463Sralph pass2: 32412111Sralph fseek(cfp, 0L, 0); 32512111Sralph while (getline(cfp)) 32612111Sralph switch (line[0]) { 32712111Sralph case 'M': 32812463Sralph if (bombed != 2) /* already sent if 2 */ 32912463Sralph sendmail(bombed); 33012111Sralph continue; 33112111Sralph 33212111Sralph case 'U': 33312111Sralph (void) unlink(line+1); 33412111Sralph } 33512111Sralph /* 33612111Sralph * clean-up incase another control file exists 33712111Sralph */ 33812111Sralph (void) fclose(cfp); 33912111Sralph (void) unlink(file); 34012111Sralph return(0); 34112111Sralph } 34212111Sralph 34312111Sralph /* 34412111Sralph * Print a file. 34513233Sralph * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}. 34612111Sralph * Return -1 if a non-recoverable error occured, 1 if a recoverable error and 34712111Sralph * 0 if all is well. 34812111Sralph * Note: all filters take stdin as the file, stdout as the printer, 34912111Sralph * stderr as the log file, and must not ignore SIGINT. 35012111Sralph */ 35112877Sralph static 35212111Sralph print(format, file) 35312111Sralph int format; 35412111Sralph char *file; 35512111Sralph { 35612111Sralph register int n, fi, fo; 35712111Sralph register char *prog; 35812111Sralph char *av[15], buf[BUFSIZ]; 35912111Sralph int pid, p[2], stopped = 0; 36012111Sralph union wait status; 36112111Sralph 36213148Ssam if ((fi = open(file, O_RDONLY)) < 0) { 36312111Sralph log("%s: open failure <errno = %d>", file, errno); 36412111Sralph return(-1); 36512111Sralph } 36612111Sralph if (!SF && !tof) { /* start on a fresh page */ 36712111Sralph (void) write(ofd, FF, strlen(FF)); 36812111Sralph tof = 1; 36912111Sralph } 37012111Sralph if (IF == NULL && (format == 'f' || format == 'l')) { 37112111Sralph tof = 0; 37212111Sralph while ((n = read(fi, buf, BUFSIZ)) > 0) 37312111Sralph if (write(ofd, buf, n) != n) { 37412111Sralph (void) close(fi); 37512111Sralph return(1); 37612111Sralph } 37712111Sralph (void) close(fi); 37812111Sralph return(0); 37912111Sralph } 38012111Sralph switch (format) { 38112111Sralph case 'p': /* print file using 'pr' */ 38212111Sralph if (IF == NULL) { /* use output filter */ 38312111Sralph prog = PR; 38412111Sralph av[0] = "pr"; 38512111Sralph av[1] = width; 38612111Sralph av[2] = length; 38712111Sralph av[3] = "-h"; 38812111Sralph av[4] = *title ? title : " "; 38912111Sralph av[5] = 0; 39012111Sralph fo = ofd; 39112111Sralph goto start; 39212111Sralph } 39312111Sralph pipe(p); 39412111Sralph if ((prchild = dofork(DORETURN)) == 0) { /* child */ 39512111Sralph dup2(fi, 0); /* file is stdin */ 39612111Sralph dup2(p[1], 1); /* pipe is stdout */ 39712111Sralph for (n = 3; n < NOFILE; n++) 39812111Sralph (void) close(n); 39912111Sralph execl(PR, "pr", width, length, "-h", *title ? title : " ", 0); 40012111Sralph log("cannot execl %s", PR); 40112111Sralph exit(2); 40212111Sralph } 40312111Sralph (void) close(p[1]); /* close output side */ 40412111Sralph (void) close(fi); 40512111Sralph if (prchild < 0) { 40612111Sralph prchild = 0; 40712111Sralph (void) close(p[0]); 40812111Sralph return(-1); 40912111Sralph } 41012111Sralph fi = p[0]; /* use pipe for input */ 41112111Sralph case 'f': /* print plain text file */ 41212111Sralph prog = IF; 41312111Sralph av[1] = width; 41412111Sralph av[2] = length; 41512581Sralph av[3] = indent; 41612581Sralph n = 4; 41712111Sralph break; 41812111Sralph case 'l': /* like 'f' but pass control characters */ 41912111Sralph prog = IF; 42012111Sralph av[1] = "-l"; 42112111Sralph av[2] = width; 42212111Sralph av[3] = length; 42312581Sralph av[4] = indent; 42412581Sralph n = 5; 42512111Sralph break; 42612463Sralph case 'r': /* print a fortran text file */ 42712463Sralph prog = RF; 42812463Sralph av[1] = width; 42912463Sralph av[2] = length; 43012463Sralph n = 3; 43112463Sralph break; 43212111Sralph case 't': /* print troff output */ 43313233Sralph case 'n': /* print ditroff output */ 43412463Sralph case 'd': /* print tex output */ 43512111Sralph (void) unlink(".railmag"); 43612463Sralph if ((fo = creat(".railmag", FILMOD)) < 0) { 43712111Sralph log("cannot create .railmag"); 43812111Sralph (void) unlink(".railmag"); 43912111Sralph } else { 44012111Sralph for (n = 0; n < 4; n++) { 44112111Sralph if (fonts[n][0] != '/') 44212111Sralph (void) write(fo, "/usr/lib/vfont/", 15); 44312111Sralph (void) write(fo, fonts[n], strlen(fonts[n])); 44412111Sralph (void) write(fo, "\n", 1); 44512111Sralph } 44612111Sralph (void) close(fo); 44712111Sralph } 44813233Sralph prog = (format == 't') ? TF : (format == 'n') ? NF : DF; 44912463Sralph av[1] = pxwidth; 45012463Sralph av[2] = pxlength; 45112463Sralph n = 3; 45212111Sralph break; 45312111Sralph case 'c': /* print cifplot output */ 45412111Sralph prog = CF; 45512463Sralph av[1] = pxwidth; 45612463Sralph av[2] = pxlength; 45712463Sralph n = 3; 45812111Sralph break; 45912111Sralph case 'g': /* print plot(1G) output */ 46012111Sralph prog = GF; 46112463Sralph av[1] = pxwidth; 46212463Sralph av[2] = pxlength; 46312463Sralph n = 3; 46412111Sralph break; 46512111Sralph case 'v': /* print raster output */ 46612111Sralph prog = VF; 46712463Sralph av[1] = pxwidth; 46812463Sralph av[2] = pxlength; 46912463Sralph n = 3; 47012111Sralph break; 47112111Sralph default: 47212111Sralph (void) close(fi); 47312111Sralph log("illegal format character '%c'", format); 47412111Sralph return(-1); 47512111Sralph } 47612111Sralph if ((av[0] = rindex(prog, '/')) != NULL) 47712111Sralph av[0]++; 47812111Sralph else 47912111Sralph av[0] = prog; 48012111Sralph av[n++] = "-n"; 48112111Sralph av[n++] = logname; 48212111Sralph av[n++] = "-h"; 48312111Sralph av[n++] = host; 48412111Sralph av[n++] = AF; 48512111Sralph av[n] = 0; 48612111Sralph fo = pfd; 48712111Sralph if (ofilter > 0) { /* stop output filter */ 48812111Sralph write(ofd, "\031\1", 2); 48912111Sralph while ((pid = wait3(&status, WUNTRACED, 0)) > 0 && pid != ofilter) 49012111Sralph ; 49112111Sralph if (status.w_stopval != WSTOPPED) { 49212111Sralph (void) close(fi); 49312111Sralph log("output filter died (%d)", status.w_retcode); 49412111Sralph return(1); 49512111Sralph } 49612111Sralph stopped++; 49712111Sralph } 49812111Sralph start: 49912111Sralph if ((child = dofork(DORETURN)) == 0) { /* child */ 50012111Sralph dup2(fi, 0); 50112111Sralph dup2(fo, 1); 50212111Sralph for (n = 3; n < NOFILE; n++) 50312111Sralph (void) close(n); 50412111Sralph execv(prog, av); 50512111Sralph log("cannot execl %s", prog); 50612111Sralph exit(2); 50712111Sralph } 50812111Sralph (void) close(fi); 50912111Sralph if (child < 0) 51012111Sralph status.w_retcode = 100; 51112111Sralph else 51212111Sralph while ((pid = wait(&status)) > 0 && pid != child) 51312111Sralph ; 51412111Sralph child = 0; 51512111Sralph prchild = 0; 51612111Sralph if (stopped) { /* restart output filter */ 51712111Sralph if (kill(ofilter, SIGCONT) < 0) { 51812111Sralph log("cannot restart output filter"); 51912111Sralph exit(1); 52012111Sralph } 52112111Sralph } 52212111Sralph tof = 0; 52312111Sralph if (!WIFEXITED(status) || status.w_retcode > 1) { 52412111Sralph log("Daemon Filter '%c' Malfunction (%d)", format, status.w_retcode); 52512111Sralph return(-1); 52612111Sralph } else if (status.w_retcode == 1) 52712111Sralph return(1); 52812111Sralph tof = 1; 52912111Sralph return(0); 53012111Sralph } 53112111Sralph 53212111Sralph /* 53312111Sralph * Send the daemon control file (cf) and any data files. 53412111Sralph * Return -1 if a non-recoverable error occured, 1 if a recoverable error and 53512111Sralph * 0 if all is well. 53612111Sralph */ 53712877Sralph static 53812111Sralph sendit(file) 53912111Sralph char *file; 54012111Sralph { 54112111Sralph register int linelen, err = 0; 54212111Sralph char last[132]; 54312111Sralph 54412111Sralph /* 54512111Sralph * open control file 54612111Sralph */ 54712111Sralph if ((cfp = fopen(file, "r")) == NULL) { 54812111Sralph log("control file (%s) open failure <errno = %d>", file, errno); 54912111Sralph return(0); 55012111Sralph } 55112111Sralph /* 55212111Sralph * read the control file for work to do 55312111Sralph * 55412111Sralph * file format -- first character in the line is a command 55512111Sralph * rest of the line is the argument. 55612111Sralph * commands of interest are: 55712111Sralph * 55812111Sralph * a-z -- "file name" name of file to print 55912111Sralph * U -- "unlink" name of file to remove 56012111Sralph * (after we print it. (Pass 2 only)). 56112111Sralph */ 56212111Sralph 56312111Sralph /* 56412111Sralph * pass 1 56512111Sralph */ 56612111Sralph while (getline(cfp)) { 56712111Sralph again: 56812111Sralph if (line[0] >= 'a' && line[0] <= 'z') { 56912111Sralph strcpy(last, line); 57012111Sralph while (linelen = getline(cfp)) 57112111Sralph if (strcmp(last, line)) 57212111Sralph break; 57312111Sralph if ((err = sendfile('\3', last+1)) > 0) { 57412111Sralph (void) fclose(cfp); 57512111Sralph return(1); 57612111Sralph } else if (err) 57712111Sralph break; 57812111Sralph if (linelen) 57912111Sralph goto again; 58012111Sralph break; 58112111Sralph } 58212111Sralph } 58312111Sralph if (!err && sendfile('\2', file) > 0) { 58412111Sralph (void) fclose(cfp); 58512111Sralph return(1); 58612111Sralph } 58712111Sralph /* 58812111Sralph * pass 2 58912111Sralph */ 59012111Sralph fseek(cfp, 0L, 0); 59112111Sralph while (getline(cfp)) 59212111Sralph if (line[0] == 'U') 59312111Sralph (void) unlink(line+1); 59412111Sralph /* 59512111Sralph * clean-up incase another control file exists 59612111Sralph */ 59712111Sralph (void) fclose(cfp); 59812111Sralph (void) unlink(file); 59912111Sralph return(0); 60012111Sralph } 60112111Sralph 60212111Sralph /* 60312111Sralph * Send a data file to the remote machine and spool it. 60412111Sralph * Return positive if we should try resending. 60512111Sralph */ 60612877Sralph static 60712111Sralph sendfile(type, file) 60812111Sralph char type, *file; 60912111Sralph { 61012111Sralph register int f, i, amt; 61112111Sralph struct stat stb; 61212111Sralph char buf[BUFSIZ]; 61312111Sralph int sizerr; 61412111Sralph 61513148Ssam if ((f = open(file, O_RDONLY)) < 0 || fstat(f, &stb) < 0) { 61612111Sralph log("file (%s) open failure <errno = %d>", file, errno); 61712111Sralph return(-1); 61812111Sralph } 61912111Sralph (void) sprintf(buf, "%c%d %s\n", type, stb.st_size, file); 62012111Sralph amt = strlen(buf); 62112692Sralph if (write(pfd, buf, amt) != amt) { 62212692Sralph (void) close(f); 62312111Sralph return(1); 62412692Sralph } 62512692Sralph if (noresponse()) { 62612692Sralph (void) close(f); 62712111Sralph return(1); 62812692Sralph } 62912111Sralph sizerr = 0; 63012111Sralph for (i = 0; i < stb.st_size; i += BUFSIZ) { 63112111Sralph amt = BUFSIZ; 63212111Sralph if (i + amt > stb.st_size) 63312111Sralph amt = stb.st_size - i; 63412111Sralph if (sizerr == 0 && read(f, buf, amt) != amt) 63512111Sralph sizerr = 1; 63612692Sralph if (write(pfd, buf, amt) != amt) { 63712692Sralph (void) close(f); 63812111Sralph return(1); 63912692Sralph } 64012111Sralph } 64112111Sralph (void) close(f); 64212111Sralph if (sizerr) { 64312111Sralph log("%s: changed size", file); 64412111Sralph (void) write(pfd, "\1", 1); /* tell recvjob to ignore this file */ 64512111Sralph return(-1); 64612111Sralph } 64712111Sralph if (write(pfd, "", 1) != 1) 64812111Sralph return(1); 64912111Sralph if (noresponse()) 65012111Sralph return(1); 65112111Sralph return(0); 65212111Sralph } 65312111Sralph 65412111Sralph /* 65512111Sralph * Check to make sure there have been no errors and that both programs 65612111Sralph * are in sync with eachother. 65712111Sralph * Return non-zero if the connection was lost. 65812111Sralph */ 65912111Sralph static 66012111Sralph noresponse() 66112111Sralph { 66212111Sralph char resp; 66312111Sralph 66412111Sralph if (read(pfd, &resp, 1) != 1 || resp != '\0') { 66512111Sralph log("lost connection or error in recvjob"); 66612111Sralph return(1); 66712111Sralph } 66812111Sralph return(0); 66912111Sralph } 67012111Sralph 67112111Sralph /* 67212111Sralph * Banner printing stuff 67312111Sralph */ 67412877Sralph static 67512111Sralph banner(name1, name2) 67612111Sralph char *name1, *name2; 67712111Sralph { 67812111Sralph time_t tvec; 67912111Sralph extern char *ctime(); 68012111Sralph 68112111Sralph time(&tvec); 68212111Sralph if (!SF && !tof) 68312111Sralph (void) write(ofd, FF, strlen(FF)); 68412111Sralph if (SB) { /* short banner only */ 68512111Sralph if (class[0]) { 68612111Sralph (void) write(ofd, class, strlen(class)); 68712111Sralph (void) write(ofd, ":", 1); 68812111Sralph } 68912111Sralph (void) write(ofd, name1, strlen(name1)); 69012111Sralph (void) write(ofd, " Job: ", 7); 69112111Sralph (void) write(ofd, name2, strlen(name2)); 69212111Sralph (void) write(ofd, " Date: ", 8); 69312111Sralph (void) write(ofd, ctime(&tvec), 24); 69412111Sralph (void) write(ofd, "\n", 1); 69512111Sralph } else { /* normal banner */ 69612111Sralph (void) write(ofd, "\n\n\n", 3); 69712111Sralph scan_out(ofd, name1, '\0'); 69812111Sralph (void) write(ofd, "\n\n", 2); 69912111Sralph scan_out(ofd, name2, '\0'); 70012111Sralph if (class[0]) { 70112111Sralph (void) write(ofd,"\n\n\n",3); 70212111Sralph scan_out(ofd, class, '\0'); 70312111Sralph } 70412111Sralph (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15); 70512111Sralph (void) write(ofd, name2, strlen(name2)); 70612111Sralph (void) write(ofd, "\n\t\t\t\t\tDate: ", 12); 70712111Sralph (void) write(ofd, ctime(&tvec), 24); 70812111Sralph (void) write(ofd, "\n", 1); 70912111Sralph } 71012111Sralph if (!SF) 71112111Sralph (void) write(ofd, FF, strlen(FF)); 71212111Sralph tof = 1; 71312111Sralph } 71412111Sralph 71512877Sralph static char * 71612111Sralph scnline(key, p, c) 71712111Sralph register char key, *p; 71812111Sralph char c; 71912111Sralph { 72012111Sralph register scnwidth; 72112111Sralph 72212111Sralph for (scnwidth = WIDTH; --scnwidth;) { 72312111Sralph key <<= 1; 72412111Sralph *p++ = key & 0200 ? c : BACKGND; 72512111Sralph } 72612111Sralph return (p); 72712111Sralph } 72812111Sralph 72912111Sralph #define TRC(q) (((q)-' ')&0177) 73012111Sralph 73112877Sralph static 73212111Sralph scan_out(scfd, scsp, dlm) 73312111Sralph int scfd; 73412111Sralph char *scsp, dlm; 73512111Sralph { 73612111Sralph register char *strp; 73712111Sralph register nchrs, j; 73812111Sralph char outbuf[LINELEN+1], *sp, c, cc; 73912111Sralph int d, scnhgt; 74012111Sralph extern char scnkey[][HEIGHT]; /* in lpdchar.c */ 74112111Sralph 74212111Sralph for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) { 74312111Sralph strp = &outbuf[0]; 74412111Sralph sp = scsp; 74512111Sralph for (nchrs = 0; ; ) { 74612111Sralph d = dropit(c = TRC(cc = *sp++)); 74712111Sralph if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d)) 74812111Sralph for (j = WIDTH; --j;) 74912111Sralph *strp++ = BACKGND; 75012111Sralph else 75112111Sralph strp = scnline(scnkey[c][scnhgt-1-d], strp, cc); 75212111Sralph if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1) 75312111Sralph break; 75412111Sralph *strp++ = BACKGND; 75512111Sralph *strp++ = BACKGND; 75612111Sralph } 75712111Sralph while (*--strp == BACKGND && strp >= outbuf) 75812111Sralph ; 75912111Sralph strp++; 76012111Sralph *strp++ = '\n'; 76112111Sralph (void) write(scfd, outbuf, strp-outbuf); 76212111Sralph } 76312111Sralph } 76412111Sralph 76512877Sralph static 76612111Sralph dropit(c) 76712111Sralph char c; 76812111Sralph { 76912111Sralph switch(c) { 77012111Sralph 77112111Sralph case TRC('_'): 77212111Sralph case TRC(';'): 77312111Sralph case TRC(','): 77412111Sralph case TRC('g'): 77512111Sralph case TRC('j'): 77612111Sralph case TRC('p'): 77712111Sralph case TRC('q'): 77812111Sralph case TRC('y'): 77912111Sralph return (DROP); 78012111Sralph 78112111Sralph default: 78212111Sralph return (0); 78312111Sralph } 78412111Sralph } 78512111Sralph 78612111Sralph /* 78712111Sralph * sendmail --- 78812111Sralph * tell people about job completion 78912111Sralph */ 79012877Sralph static 79112111Sralph sendmail(bombed) 79212111Sralph int bombed; 79312111Sralph { 79412111Sralph static int p[2]; 79512111Sralph register int i; 79612111Sralph int stat; 79712111Sralph register char *cp; 79812111Sralph char buf[100]; 79912111Sralph 80012111Sralph pipe(p); 80112111Sralph if ((stat = dofork(DORETURN)) == 0) { /* child */ 80212111Sralph dup2(p[0], 0); 80312111Sralph for (i = 3; i < NOFILE; i++) 80412111Sralph (void) close(i); 80512111Sralph if ((cp = rindex(MAIL, '/')) != NULL) 80612111Sralph cp++; 80712111Sralph else 80812111Sralph cp = MAIL; 80912111Sralph sprintf(buf, "%s@%s", line+1, host); 81012111Sralph execl(MAIL, cp, buf, 0); 81112111Sralph exit(0); 81212111Sralph } else if (stat > 0) { /* parent */ 81312111Sralph dup2(p[1], 1); 81412111Sralph printf("To: %s\n", line+1); 81512111Sralph printf("Subject: printer job\n\n"); 81612111Sralph printf("Your printer job "); 81712111Sralph if (*jobname) 81812111Sralph printf("(%s) ", jobname); 81912463Sralph switch (bombed) { 82012463Sralph case 0: 82112463Sralph printf("\ncompleted successfully\n"); 82212463Sralph break; 82312463Sralph default: 82412463Sralph case 1: 82512463Sralph printf("\ncould not be printed\n"); 82612463Sralph break; 82712463Sralph case 2: 82812463Sralph printf("\ncould not be printed without an account on %s\n", host); 82912463Sralph break; 83012463Sralph } 83112111Sralph fflush(stdout); 83212111Sralph (void) close(1); 83312111Sralph } 83412111Sralph (void) close(p[0]); 83512111Sralph (void) close(p[1]); 83612111Sralph wait(&stat); 83712111Sralph } 83812111Sralph 83912111Sralph /* 84012111Sralph * dofork - fork with retries on failure 84112111Sralph */ 84212877Sralph static 84312111Sralph dofork(action) 84412111Sralph int action; 84512111Sralph { 84612111Sralph register int i, pid; 84712111Sralph 84812111Sralph for (i = 0; i < 20; i++) { 84912463Sralph if ((pid = fork()) < 0) { 85012111Sralph sleep((unsigned)(i*i)); 85112463Sralph continue; 85212463Sralph } 85312463Sralph /* 85412463Sralph * Child should run as daemon instead of root 85512463Sralph */ 85612463Sralph if (pid == 0) 85712463Sralph setuid(DU); 85812463Sralph return(pid); 85912111Sralph } 86012111Sralph log("can't fork"); 86112111Sralph 86212111Sralph switch (action) { 86312111Sralph case DORETURN: 86412111Sralph return (-1); 86512111Sralph default: 86612111Sralph log("bad action (%d) to dofork", action); 86712111Sralph /*FALL THRU*/ 86812111Sralph case DOABORT: 86912111Sralph exit(1); 87012111Sralph } 87112111Sralph /*NOTREACHED*/ 87212111Sralph } 87312111Sralph 87412111Sralph /* 87512111Sralph * Cleanup child processes when a SIGINT is caught. 87612111Sralph */ 87712877Sralph static 87812111Sralph onintr() 87912111Sralph { 88012111Sralph kill(0, SIGINT); 88112111Sralph if (ofilter > 0) 88212111Sralph kill(ofilter, SIGCONT); 88312111Sralph while (wait(0) > 0) 88412111Sralph ; 88512111Sralph exit(0); 88612111Sralph } 88712111Sralph 88812877Sralph static 88912111Sralph init() 89012111Sralph { 89112111Sralph int status; 89212111Sralph 89313169Sralph if ((status = pgetent(line, printer)) < 0) 89413169Sralph fatal("can't open printer description file"); 89513169Sralph else if (status == 0) 89613169Sralph fatal("unknown printer"); 89712111Sralph if ((LP = pgetstr("lp", &bp)) == NULL) 89812111Sralph LP = DEFDEVLP; 89912111Sralph if ((RP = pgetstr("rp", &bp)) == NULL) 90012463Sralph RP = DEFLP; 90112111Sralph if ((LO = pgetstr("lo", &bp)) == NULL) 90212111Sralph LO = DEFLOCK; 90312111Sralph if ((ST = pgetstr("st", &bp)) == NULL) 90412111Sralph ST = DEFSTAT; 90512111Sralph if ((LF = pgetstr("lf", &bp)) == NULL) 90612111Sralph LF = DEFLOGF; 90712111Sralph if ((SD = pgetstr("sd", &bp)) == NULL) 90812111Sralph SD = DEFSPOOL; 90912111Sralph if ((DU = pgetnum("du")) < 0) 91012111Sralph DU = DEFUID; 91112111Sralph if ((FF = pgetstr("ff", &bp)) == NULL) 91212111Sralph FF = DEFFF; 91312111Sralph if ((PW = pgetnum("pw")) < 0) 91412111Sralph PW = DEFWIDTH; 91512111Sralph sprintf(&width[2], "%d", PW); 91612111Sralph if ((PL = pgetnum("pl")) < 0) 91712111Sralph PL = DEFLENGTH; 91812111Sralph sprintf(&length[2], "%d", PL); 91912463Sralph if ((PX = pgetnum("px")) < 0) 92012463Sralph PX = 0; 92112463Sralph sprintf(&pxwidth[2], "%d", PX); 92212463Sralph if ((PY = pgetnum("py")) < 0) 92312463Sralph PY = 0; 92412463Sralph sprintf(&pxlength[2], "%d", PY); 92512111Sralph RM = pgetstr("rm", &bp); 92612111Sralph AF = pgetstr("af", &bp); 92712111Sralph OF = pgetstr("of", &bp); 92812111Sralph IF = pgetstr("if", &bp); 92912463Sralph RF = pgetstr("rf", &bp); 93012111Sralph TF = pgetstr("tf", &bp); 93113233Sralph NF = pgetstr("nf", &bp); 93212111Sralph DF = pgetstr("df", &bp); 93312111Sralph GF = pgetstr("gf", &bp); 93412111Sralph VF = pgetstr("vf", &bp); 93512111Sralph CF = pgetstr("cf", &bp); 93612111Sralph TR = pgetstr("tr", &bp); 93712463Sralph RS = pgetflag("rs"); 93812111Sralph SF = pgetflag("sf"); 93912111Sralph SH = pgetflag("sh"); 94012111Sralph SB = pgetflag("sb"); 94112111Sralph RW = pgetflag("rw"); 94212111Sralph BR = pgetnum("br"); 94312111Sralph if ((FC = pgetnum("fc")) < 0) 94412111Sralph FC = 0; 94512111Sralph if ((FS = pgetnum("fs")) < 0) 94612111Sralph FS = 0; 94712111Sralph if ((XC = pgetnum("xc")) < 0) 94812111Sralph XC = 0; 94912111Sralph if ((XS = pgetnum("xs")) < 0) 95012111Sralph XS = 0; 95112581Sralph tof = !pgetflag("fo"); 95212111Sralph } 95312111Sralph 95412463Sralph /* 95512463Sralph * Acquire line printer or remote connection. 95612463Sralph */ 95712877Sralph static 95812463Sralph openpr() 95912463Sralph { 96012463Sralph register int i, n; 96112463Sralph 96212463Sralph if (*LP) { 96312463Sralph for (i = 1; ; i = i < 32 ? i << 1 : i) { 96413148Ssam pfd = open(LP, RW ? O_RDWR : O_WRONLY); 96512463Sralph if (pfd >= 0) 96612463Sralph break; 96712463Sralph if (errno == ENOENT) { 96812463Sralph log("cannot open %s", LP); 96912463Sralph exit(1); 97012463Sralph } 97112463Sralph if (i == 1) 97212463Sralph status("waiting for %s to become ready (offline ?)", printer); 97312463Sralph sleep(i); 97412463Sralph } 97512463Sralph if (isatty(pfd)) 97612463Sralph setty(); 97712463Sralph status("%s is ready and printing", printer); 97812463Sralph } else if (RM != NULL) { 97912463Sralph for (i = 1; ; i = i < 512 ? i << 1 : i) { 98012528Sralph pfd = getport(RM); 98112463Sralph if (pfd >= 0) { 98212463Sralph (void) sprintf(line, "\2%s\n", RP); 98312463Sralph n = strlen(line); 98412463Sralph if (write(pfd, line, n) != n) 98512463Sralph break; 98612463Sralph if (noresponse()) 98712463Sralph (void) close(pfd); 98812463Sralph else 98912463Sralph break; 99012463Sralph } 99112463Sralph if (i == 1) 99212463Sralph status("waiting for %s to come up", RM); 99312463Sralph sleep(i); 99412463Sralph } 99512463Sralph status("sending to %s", RM); 99612463Sralph remote = 1; 99712463Sralph } else { 99812463Sralph log("no line printer device or remote machine name"); 99912463Sralph exit(1); 100012463Sralph } 100112463Sralph /* 100212463Sralph * Start up an output filter, if needed. 100312463Sralph */ 100412463Sralph if (OF) { 100512463Sralph int p[2]; 100612463Sralph char *cp; 100712463Sralph 100812463Sralph pipe(p); 100912463Sralph if ((ofilter = dofork(DOABORT)) == 0) { /* child */ 101012463Sralph dup2(p[0], 0); /* pipe is std in */ 101112463Sralph dup2(pfd, 1); /* printer is std out */ 101212463Sralph for (i = 3; i < NOFILE; i++) 101312463Sralph (void) close(i); 101412463Sralph if ((cp = rindex(OF, '/')) == NULL) 101512463Sralph cp = OF; 101612463Sralph else 101712463Sralph cp++; 101812463Sralph execl(OF, cp, width, length, 0); 101912463Sralph log("can't execl output filter %s", OF); 102012463Sralph exit(1); 102112463Sralph } 102212463Sralph (void) close(p[0]); /* close input side */ 102312463Sralph ofd = p[1]; /* use pipe for output */ 102412463Sralph } else { 102512463Sralph ofd = pfd; 102612463Sralph ofilter = 0; 102712463Sralph } 102812463Sralph } 102912463Sralph 103012111Sralph struct bauds { 103112111Sralph int baud; 103212111Sralph int speed; 103312111Sralph } bauds[] = { 103412111Sralph 50, B50, 103512111Sralph 75, B75, 103612111Sralph 110, B110, 103712111Sralph 134, B134, 103812111Sralph 150, B150, 103912111Sralph 200, B200, 104012111Sralph 300, B300, 104112111Sralph 600, B600, 104212111Sralph 1200, B1200, 104312111Sralph 1800, B1800, 104412111Sralph 2400, B2400, 104512111Sralph 4800, B4800, 104612111Sralph 9600, B9600, 104712111Sralph 19200, EXTA, 104812111Sralph 38400, EXTB, 104912111Sralph 0, 0 105012111Sralph }; 105112111Sralph 105212111Sralph /* 105312111Sralph * setup tty lines. 105412111Sralph */ 105512877Sralph static 105612111Sralph setty() 105712111Sralph { 105812111Sralph struct sgttyb ttybuf; 105912111Sralph register struct bauds *bp; 106012111Sralph 106112111Sralph if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) { 106212111Sralph log("cannot set exclusive-use"); 106312111Sralph exit(1); 106412111Sralph } 106512111Sralph if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) { 106612111Sralph log("cannot get tty parameters"); 106712111Sralph exit(1); 106812111Sralph } 106912111Sralph if (BR > 0) { 107012111Sralph for (bp = bauds; bp->baud; bp++) 107112111Sralph if (BR == bp->baud) 107212111Sralph break; 107312111Sralph if (!bp->baud) { 107412111Sralph log("illegal baud rate %d", BR); 107512111Sralph exit(1); 107612111Sralph } 107712111Sralph ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed; 107812111Sralph } 107913169Sralph ttybuf.sg_flags &= ~FC; 108013169Sralph ttybuf.sg_flags |= FS; 108112111Sralph if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) { 108212111Sralph log("cannot set tty parameters"); 108312111Sralph exit(1); 108412111Sralph } 108512111Sralph if (XC) { 108612111Sralph if (ioctl(pfd, TIOCLBIC, &XC) < 0) { 108712111Sralph log("cannot set local tty parameters"); 108812111Sralph exit(1); 108912111Sralph } 109012111Sralph } 109112111Sralph if (XS) { 109212111Sralph if (ioctl(pfd, TIOCLBIS, &XS) < 0) { 109312111Sralph log("cannot set local tty parameters"); 109412111Sralph exit(1); 109512111Sralph } 109612111Sralph } 109712111Sralph } 109812463Sralph 109912463Sralph /*VARARGS1*/ 110012463Sralph static 110112463Sralph status(msg, a1, a2, a3) 110212463Sralph char *msg; 110312463Sralph { 110412463Sralph register int fd; 110512463Sralph char buf[BUFSIZ]; 110612463Sralph 110712463Sralph umask(0); 110813148Ssam fd = open(ST, O_WRONLY|O_CREAT, 0664); 110913148Ssam if (fd < 0 || flock(fd, LOCK_EX) < 0) 111012463Sralph fatal("cannot create status file"); 111113148Ssam ftruncate(fd, 0); 111212463Sralph sprintf(buf, msg, a1, a2, a3); 111312463Sralph strcat(buf, "\n"); 111412463Sralph (void) write(fd, buf, strlen(buf)); 111512463Sralph (void) close(fd); 111612463Sralph } 1117