1*13442Sralph /* printjob.c 4.10 83/06/29 */ 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 1112877Sralph #define DORETURN 0 /* absorb fork error */ 1212877Sralph #define DOABORT 1 /* abort if dofork fails */ 1312111Sralph 1412877Sralph static char title[80]; /* ``pr'' title */ 1512877Sralph static FILE *cfp; /* control file */ 1612877Sralph static int pfd; /* printer file descriptor */ 1712877Sralph static int ofd; /* output filter file descriptor */ 1812877Sralph static int lfd; /* lock file descriptor */ 1912877Sralph static int pid; /* pid of lpd process */ 2012877Sralph static int prchild; /* id of pr process */ 2112877Sralph static int child; /* id of any filters */ 2212877Sralph static int ofilter; /* id of output filter, if any */ 2312877Sralph static int tof; /* true if at top of form */ 2412877Sralph static int remote; /* true if sending files to remote */ 2512111Sralph 2612877Sralph static char logname[32]; /* user's login name */ 2712877Sralph static char jobname[32]; /* job or file name */ 2812877Sralph static char class[32]; /* classification field */ 2912877Sralph static char width[10] = "-w"; /* page width in characters */ 3012877Sralph static char length[10] = "-l"; /* page length in lines */ 3112877Sralph static char pxwidth[10] = "-x"; /* page width in pixels */ 3212877Sralph static char pxlength[10] = "-y"; /* page length in pixels */ 3312877Sralph static char indent[10] = "-i0"; /* indentation size in characters */ 3412111Sralph 3512111Sralph printjob() 3612111Sralph { 3712111Sralph struct stat stb; 3812111Sralph register struct queue *q, **qp; 3912111Sralph struct queue **queue; 4012111Sralph register int i, nitems; 4112111Sralph long pidoff; 4212111Sralph extern int onintr(); 4312111Sralph 4412111Sralph init(); /* set up capabilities */ 45*13442Sralph (void) write(1, "", 1); /* ack that daemon is started */ 4612877Sralph (void) close(1); /* set up log file */ 4712877Sralph (void) close(2); 4813148Ssam if (open(LF, O_WRONLY|O_APPEND) < 0) 4913148Ssam (void) open("/dev/null", O_WRONLY); 5012877Sralph dup(1); 5112463Sralph pid = getpid(); /* for use with lprm */ 5212111Sralph setpgrp(0, pid); 5313148Ssam signal(SIGINT, onintr); 5412111Sralph 5512111Sralph /* 5612111Sralph * uses short form file names 5712111Sralph */ 5812111Sralph if (chdir(SD) < 0) { 5912111Sralph log("cannot chdir to %s", SD); 6012111Sralph exit(1); 6112111Sralph } 6212463Sralph if (stat(LO, &stb) == 0 && (stb.st_mode & 0100)) 6312463Sralph exit(0); /* printing disabled */ 6413169Sralph lfd = open(LO, O_WRONLY|O_CREAT|O_TRUNC, 0644); 6513169Sralph if (lfd < 0) { 6613169Sralph log("cannot create %s", LO); 6713169Sralph exit(1); 6813169Sralph } 6913169Sralph if (flock(lfd, LOCK_EX|LOCK_NB) < 0) { 7012111Sralph if (errno == EWOULDBLOCK) /* active deamon present */ 7112111Sralph exit(0); 7213169Sralph log("cannot lock %s", LO); 7312111Sralph exit(1); 7412111Sralph } 7513148Ssam ftruncate(lfd, 0); 7612111Sralph /* 7712111Sralph * write process id for others to know 7812111Sralph */ 7912111Sralph sprintf(line, "%u\n", pid); 8012111Sralph pidoff = i = strlen(line); 8112463Sralph if (write(lfd, line, i) != i) { 8212111Sralph log("cannot write daemon pid"); 8312111Sralph exit(1); 8412111Sralph } 8512111Sralph /* 8612111Sralph * search the spool directory for work and sort by queue order. 8712111Sralph */ 8812111Sralph if ((nitems = getq(&queue)) < 0) { 8912111Sralph log("can't scan spool directory %s", SD); 9012111Sralph exit(1); 9112111Sralph } 9212463Sralph if (nitems == 0) /* no work to do */ 9312111Sralph exit(0); 9413169Sralph if (stb.st_mode & 01) { /* reset queue flag */ 9513169Sralph if (fchmod(lfd, stb.st_mode & 0776) < 0) 9613169Sralph log("cannot chmod %s", LO); 9713169Sralph } 9812463Sralph openpr(); /* open printer or remote */ 9912463Sralph again: 10012111Sralph /* 10112111Sralph * we found something to do now do it -- 10212111Sralph * write the name of the current control file into the lock file 10312111Sralph * so the spool queue program can tell what we're working on 10412111Sralph */ 10512111Sralph for (qp = queue; nitems--; free((char *) q)) { 10612111Sralph q = *qp++; 10712111Sralph if (stat(q->q_name, &stb) < 0) 10812111Sralph continue; 10912463Sralph restart: 11012111Sralph (void) lseek(lfd, pidoff, 0); 11112111Sralph (void) sprintf(line, "%s\n", q->q_name); 11212111Sralph i = strlen(line); 11312111Sralph if (write(lfd, line, i) != i) 11412111Sralph log("can't write (%d) control file name", errno); 11512111Sralph if (!remote) 11612111Sralph i = printit(q->q_name); 11712111Sralph else 11812111Sralph i = sendit(q->q_name); 11912463Sralph /* 12013169Sralph * Check to see if we are supposed to stop printing or 12113169Sralph * if we are to rebuild the queue. 12212463Sralph */ 12313169Sralph if (fstat(lfd, &stb) == 0) { 12413169Sralph if (stb.st_mode & 0100) 12513169Sralph goto done; 12613169Sralph if (stb.st_mode & 01) { 12713169Sralph for (free((char *) q); nitems--; free((char *) q)) 12813169Sralph q = *qp++; 12913169Sralph if (fchmod(lfd, stb.st_mode & 0776) < 0) 13013169Sralph log("cannot chmod %s", LO); 13113169Sralph break; 13213169Sralph } 13313169Sralph } 13412463Sralph /* 13512463Sralph * Check to see if we should try reprinting the job. 13612463Sralph */ 13712463Sralph if (i > 0) { 13812111Sralph log("restarting"); 13912111Sralph if (ofilter > 0) { 14012111Sralph kill(ofilter, SIGCONT); /* to be sure */ 14112111Sralph (void) close(ofd); 14212111Sralph while ((i = wait(0)) > 0 && i != ofilter) 14312111Sralph ; 14412111Sralph ofilter = 0; 14512111Sralph } 14612463Sralph (void) close(pfd); /* close printer */ 14712463Sralph (void) lseek(lfd, pidoff, 0); 14812463Sralph if (write(lfd, "\n", 1) != 1) 14912463Sralph log("can't write (%d) control file name", errno); 15012463Sralph openpr(); /* try to reopen printer */ 15112111Sralph goto restart; 15212111Sralph } 15312111Sralph } 15412111Sralph free((char *) queue); 15512463Sralph /* 15612463Sralph * search the spool directory for more work. 15712463Sralph */ 15812463Sralph if ((nitems = getq(&queue)) < 0) { 15912463Sralph log("can't scan spool directory %s", SD); 16012463Sralph exit(1); 16112463Sralph } 16212463Sralph if (nitems == 0) { /* no more work to do */ 16312463Sralph done: 16412463Sralph if (!SF && !tof) 16512463Sralph (void) write(ofd, FF, strlen(FF)); 16612463Sralph if (TR != NULL) /* output trailer */ 16712463Sralph (void) write(ofd, TR, strlen(TR)); 16812463Sralph exit(0); 16912463Sralph } 17012111Sralph goto again; 17112111Sralph } 17212111Sralph 17312111Sralph char fonts[4][50]; /* fonts for troff */ 17412111Sralph 17512111Sralph static char ifonts[4][18] = { 17612111Sralph "/usr/lib/vfont/R", 17712111Sralph "/usr/lib/vfont/I", 17812111Sralph "/usr/lib/vfont/B", 17912111Sralph "/usr/lib/vfont/S" 18012111Sralph }; 18112111Sralph 18212111Sralph /* 18312111Sralph * The remaining part is the reading of the control file (cf) 18412111Sralph * and performing the various actions. 18512111Sralph * Returns 0 if everthing was OK, 1 if we should try to reprint the job and 18612111Sralph * -1 if a non-recoverable error occured. 18712111Sralph */ 18812877Sralph static 18912111Sralph printit(file) 19012111Sralph char *file; 19112111Sralph { 19212111Sralph register int i; 19312111Sralph int bombed = 0; 19412111Sralph 19512111Sralph /* 19612111Sralph * open control file 19712111Sralph */ 19812111Sralph if ((cfp = fopen(file, "r")) == NULL) { 19912111Sralph log("control file (%s) open failure <errno = %d>", file, errno); 20012111Sralph return(0); 20112111Sralph } 20212111Sralph /* 20312111Sralph * Reset troff fonts. 20412111Sralph */ 20512111Sralph for (i = 0; i < 4; i++) 20612111Sralph strcpy(fonts[i], ifonts[i]); 20712111Sralph 20812111Sralph /* 20912111Sralph * read the control file for work to do 21012111Sralph * 21112111Sralph * file format -- first character in the line is a command 21212111Sralph * rest of the line is the argument. 21312111Sralph * valid commands are: 21412111Sralph * 21512111Sralph * J -- "job name" on banner page 21612111Sralph * C -- "class name" on banner page 21712111Sralph * L -- "literal" user's name to print on banner 21812111Sralph * T -- "title" for pr 21912111Sralph * H -- "host name" of machine where lpr was done 22012111Sralph * P -- "person" user's login name 22112581Sralph * I -- "indent" amount to indent output 22212111Sralph * f -- "file name" name of text file to print 22312111Sralph * l -- "file name" text file with control chars 22412111Sralph * p -- "file name" text file to print with pr(1) 22512111Sralph * t -- "file name" troff(1) file to print 22613233Sralph * n -- "file name" ditroff(1) file to print 22712111Sralph * d -- "file name" dvi file to print 22812111Sralph * g -- "file name" plot(1G) file to print 22912111Sralph * v -- "file name" plain raster file to print 23012111Sralph * c -- "file name" cifplot file to print 23112111Sralph * 1 -- "R font file" for troff 23212111Sralph * 2 -- "I font file" for troff 23312111Sralph * 3 -- "B font file" for troff 23412111Sralph * 4 -- "S font file" for troff 23512111Sralph * N -- "name" of file (used by lpq) 23612111Sralph * U -- "unlink" name of file to remove 23712111Sralph * (after we print it. (Pass 2 only)). 23812111Sralph * M -- "mail" to user when done printing 23912111Sralph * 24012111Sralph * getline reads a line and expands tabs to blanks 24112111Sralph */ 24212111Sralph 24312111Sralph /* pass 1 */ 24412111Sralph 24512111Sralph while (getline(cfp)) 24612111Sralph switch (line[0]) { 24712111Sralph case 'H': 24812111Sralph strcpy(host, line+1); 24912111Sralph if (class[0] == '\0') 25012111Sralph strcpy(class, line+1); 25112111Sralph continue; 25212111Sralph 25312111Sralph case 'P': 25412111Sralph strcpy(logname, line+1); 25512463Sralph if (RS) { /* restricted */ 25612463Sralph if (getpwnam(logname) == (struct passwd *)0) { 25712463Sralph bombed = 2; 25812463Sralph sendmail(bombed); 25912463Sralph goto pass2; 26012463Sralph } 26112463Sralph } 26212111Sralph continue; 26312111Sralph 26412111Sralph case 'J': 26512111Sralph if (line[1] != '\0') 26612111Sralph strcpy(jobname, line+1); 26712111Sralph else 26812111Sralph strcpy(jobname, " "); 26912111Sralph continue; 27012111Sralph 27112111Sralph case 'C': 27212111Sralph if (line[1] != '\0') 27312111Sralph strcpy(class, line+1); 27412111Sralph else if (class[0] == '\0') 27512111Sralph gethostname(class, sizeof (class)); 27612111Sralph continue; 27712111Sralph 27812111Sralph case 'T': /* header title for pr */ 27912111Sralph strcpy(title, line+1); 28012111Sralph continue; 28112111Sralph 28212111Sralph case 'L': /* identification line */ 28312111Sralph if (!SH) 28412111Sralph banner(line+1, jobname); 28512111Sralph continue; 28612111Sralph 28712111Sralph case '1': /* troff fonts */ 28812111Sralph case '2': 28912111Sralph case '3': 29012111Sralph case '4': 29112111Sralph if (line[1] != '\0') 29212111Sralph strcpy(fonts[line[0]-'1'], line+1); 29312111Sralph continue; 29412111Sralph 29512111Sralph case 'W': /* page width */ 29612111Sralph strcpy(width+2, line+1); 29712111Sralph continue; 29812111Sralph 29912581Sralph case 'I': /* indent amount */ 30012581Sralph strcpy(indent+2, line+1); 30112581Sralph continue; 30212581Sralph 30312111Sralph default: /* some file to print */ 30412111Sralph if ((i = print(line[0], line+1)) > 0) { 30512111Sralph (void) fclose(cfp); 30612111Sralph return(1); 30712111Sralph } else if (i < 0) 30812111Sralph bombed = 1; 30912111Sralph title[0] = '\0'; 31012111Sralph continue; 31112111Sralph 31212111Sralph case 'N': 31312111Sralph case 'U': 31412111Sralph case 'M': 31512111Sralph continue; 31612111Sralph } 31712111Sralph 31812111Sralph /* pass 2 */ 31912111Sralph 32012463Sralph pass2: 32112111Sralph fseek(cfp, 0L, 0); 32212111Sralph while (getline(cfp)) 32312111Sralph switch (line[0]) { 32412111Sralph case 'M': 32512463Sralph if (bombed != 2) /* already sent if 2 */ 32612463Sralph sendmail(bombed); 32712111Sralph continue; 32812111Sralph 32912111Sralph case 'U': 33012111Sralph (void) unlink(line+1); 33112111Sralph } 33212111Sralph /* 33312111Sralph * clean-up incase another control file exists 33412111Sralph */ 33512111Sralph (void) fclose(cfp); 33612111Sralph (void) unlink(file); 33712111Sralph return(0); 33812111Sralph } 33912111Sralph 34012111Sralph /* 34112111Sralph * Print a file. 34213233Sralph * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}. 34312111Sralph * Return -1 if a non-recoverable error occured, 1 if a recoverable error and 34412111Sralph * 0 if all is well. 34512111Sralph * Note: all filters take stdin as the file, stdout as the printer, 34612111Sralph * stderr as the log file, and must not ignore SIGINT. 34712111Sralph */ 34812877Sralph static 34912111Sralph print(format, file) 35012111Sralph int format; 35112111Sralph char *file; 35212111Sralph { 35312111Sralph register int n, fi, fo; 35412111Sralph register char *prog; 35512111Sralph char *av[15], buf[BUFSIZ]; 35612111Sralph int pid, p[2], stopped = 0; 35712111Sralph union wait status; 35812111Sralph 35913148Ssam if ((fi = open(file, O_RDONLY)) < 0) { 36012111Sralph log("%s: open failure <errno = %d>", file, errno); 36112111Sralph return(-1); 36212111Sralph } 36312111Sralph if (!SF && !tof) { /* start on a fresh page */ 36412111Sralph (void) write(ofd, FF, strlen(FF)); 36512111Sralph tof = 1; 36612111Sralph } 36712111Sralph if (IF == NULL && (format == 'f' || format == 'l')) { 36812111Sralph tof = 0; 36912111Sralph while ((n = read(fi, buf, BUFSIZ)) > 0) 37012111Sralph if (write(ofd, buf, n) != n) { 37112111Sralph (void) close(fi); 37212111Sralph return(1); 37312111Sralph } 37412111Sralph (void) close(fi); 37512111Sralph return(0); 37612111Sralph } 37712111Sralph switch (format) { 37812111Sralph case 'p': /* print file using 'pr' */ 37912111Sralph if (IF == NULL) { /* use output filter */ 38012111Sralph prog = PR; 38112111Sralph av[0] = "pr"; 38212111Sralph av[1] = width; 38312111Sralph av[2] = length; 38412111Sralph av[3] = "-h"; 38512111Sralph av[4] = *title ? title : " "; 38612111Sralph av[5] = 0; 38712111Sralph fo = ofd; 38812111Sralph goto start; 38912111Sralph } 39012111Sralph pipe(p); 39112111Sralph if ((prchild = dofork(DORETURN)) == 0) { /* child */ 39212111Sralph dup2(fi, 0); /* file is stdin */ 39312111Sralph dup2(p[1], 1); /* pipe is stdout */ 39412111Sralph for (n = 3; n < NOFILE; n++) 39512111Sralph (void) close(n); 39612111Sralph execl(PR, "pr", width, length, "-h", *title ? title : " ", 0); 39712111Sralph log("cannot execl %s", PR); 39812111Sralph exit(2); 39912111Sralph } 40012111Sralph (void) close(p[1]); /* close output side */ 40112111Sralph (void) close(fi); 40212111Sralph if (prchild < 0) { 40312111Sralph prchild = 0; 40412111Sralph (void) close(p[0]); 40512111Sralph return(-1); 40612111Sralph } 40712111Sralph fi = p[0]; /* use pipe for input */ 40812111Sralph case 'f': /* print plain text file */ 40912111Sralph prog = IF; 41012111Sralph av[1] = width; 41112111Sralph av[2] = length; 41212581Sralph av[3] = indent; 41312581Sralph n = 4; 41412111Sralph break; 41512111Sralph case 'l': /* like 'f' but pass control characters */ 41612111Sralph prog = IF; 41712111Sralph av[1] = "-l"; 41812111Sralph av[2] = width; 41912111Sralph av[3] = length; 42012581Sralph av[4] = indent; 42112581Sralph n = 5; 42212111Sralph break; 42312463Sralph case 'r': /* print a fortran text file */ 42412463Sralph prog = RF; 42512463Sralph av[1] = width; 42612463Sralph av[2] = length; 42712463Sralph n = 3; 42812463Sralph break; 42912111Sralph case 't': /* print troff output */ 43013233Sralph case 'n': /* print ditroff output */ 43112463Sralph case 'd': /* print tex output */ 43212111Sralph (void) unlink(".railmag"); 43312463Sralph if ((fo = creat(".railmag", FILMOD)) < 0) { 43412111Sralph log("cannot create .railmag"); 43512111Sralph (void) unlink(".railmag"); 43612111Sralph } else { 43712111Sralph for (n = 0; n < 4; n++) { 43812111Sralph if (fonts[n][0] != '/') 43912111Sralph (void) write(fo, "/usr/lib/vfont/", 15); 44012111Sralph (void) write(fo, fonts[n], strlen(fonts[n])); 44112111Sralph (void) write(fo, "\n", 1); 44212111Sralph } 44312111Sralph (void) close(fo); 44412111Sralph } 44513233Sralph prog = (format == 't') ? TF : (format == 'n') ? NF : DF; 44612463Sralph av[1] = pxwidth; 44712463Sralph av[2] = pxlength; 44812463Sralph n = 3; 44912111Sralph break; 45012111Sralph case 'c': /* print cifplot output */ 45112111Sralph prog = CF; 45212463Sralph av[1] = pxwidth; 45312463Sralph av[2] = pxlength; 45412463Sralph n = 3; 45512111Sralph break; 45612111Sralph case 'g': /* print plot(1G) output */ 45712111Sralph prog = GF; 45812463Sralph av[1] = pxwidth; 45912463Sralph av[2] = pxlength; 46012463Sralph n = 3; 46112111Sralph break; 46212111Sralph case 'v': /* print raster output */ 46312111Sralph prog = VF; 46412463Sralph av[1] = pxwidth; 46512463Sralph av[2] = pxlength; 46612463Sralph n = 3; 46712111Sralph break; 46812111Sralph default: 46912111Sralph (void) close(fi); 47012111Sralph log("illegal format character '%c'", format); 47112111Sralph return(-1); 47212111Sralph } 47312111Sralph if ((av[0] = rindex(prog, '/')) != NULL) 47412111Sralph av[0]++; 47512111Sralph else 47612111Sralph av[0] = prog; 47712111Sralph av[n++] = "-n"; 47812111Sralph av[n++] = logname; 47912111Sralph av[n++] = "-h"; 48012111Sralph av[n++] = host; 48112111Sralph av[n++] = AF; 48212111Sralph av[n] = 0; 48312111Sralph fo = pfd; 48412111Sralph if (ofilter > 0) { /* stop output filter */ 48512111Sralph write(ofd, "\031\1", 2); 48612111Sralph while ((pid = wait3(&status, WUNTRACED, 0)) > 0 && pid != ofilter) 48712111Sralph ; 48812111Sralph if (status.w_stopval != WSTOPPED) { 48912111Sralph (void) close(fi); 49012111Sralph log("output filter died (%d)", status.w_retcode); 49112111Sralph return(1); 49212111Sralph } 49312111Sralph stopped++; 49412111Sralph } 49512111Sralph start: 49612111Sralph if ((child = dofork(DORETURN)) == 0) { /* child */ 49712111Sralph dup2(fi, 0); 49812111Sralph dup2(fo, 1); 49912111Sralph for (n = 3; n < NOFILE; n++) 50012111Sralph (void) close(n); 50112111Sralph execv(prog, av); 50212111Sralph log("cannot execl %s", prog); 50312111Sralph exit(2); 50412111Sralph } 50512111Sralph (void) close(fi); 50612111Sralph if (child < 0) 50712111Sralph status.w_retcode = 100; 50812111Sralph else 50912111Sralph while ((pid = wait(&status)) > 0 && pid != child) 51012111Sralph ; 51112111Sralph child = 0; 51212111Sralph prchild = 0; 51312111Sralph if (stopped) { /* restart output filter */ 51412111Sralph if (kill(ofilter, SIGCONT) < 0) { 51512111Sralph log("cannot restart output filter"); 51612111Sralph exit(1); 51712111Sralph } 51812111Sralph } 51912111Sralph tof = 0; 52012111Sralph if (!WIFEXITED(status) || status.w_retcode > 1) { 52112111Sralph log("Daemon Filter '%c' Malfunction (%d)", format, status.w_retcode); 52212111Sralph return(-1); 52312111Sralph } else if (status.w_retcode == 1) 52412111Sralph return(1); 52512111Sralph tof = 1; 52612111Sralph return(0); 52712111Sralph } 52812111Sralph 52912111Sralph /* 53012111Sralph * Send the daemon control file (cf) and any data files. 53112111Sralph * Return -1 if a non-recoverable error occured, 1 if a recoverable error and 53212111Sralph * 0 if all is well. 53312111Sralph */ 53412877Sralph static 53512111Sralph sendit(file) 53612111Sralph char *file; 53712111Sralph { 53812111Sralph register int linelen, err = 0; 53912111Sralph char last[132]; 54012111Sralph 54112111Sralph /* 54212111Sralph * open control file 54312111Sralph */ 54412111Sralph if ((cfp = fopen(file, "r")) == NULL) { 54512111Sralph log("control file (%s) open failure <errno = %d>", file, errno); 54612111Sralph return(0); 54712111Sralph } 54812111Sralph /* 54912111Sralph * read the control file for work to do 55012111Sralph * 55112111Sralph * file format -- first character in the line is a command 55212111Sralph * rest of the line is the argument. 55312111Sralph * commands of interest are: 55412111Sralph * 55512111Sralph * a-z -- "file name" name of file to print 55612111Sralph * U -- "unlink" name of file to remove 55712111Sralph * (after we print it. (Pass 2 only)). 55812111Sralph */ 55912111Sralph 56012111Sralph /* 56112111Sralph * pass 1 56212111Sralph */ 56312111Sralph while (getline(cfp)) { 56412111Sralph again: 56512111Sralph if (line[0] >= 'a' && line[0] <= 'z') { 56612111Sralph strcpy(last, line); 56712111Sralph while (linelen = getline(cfp)) 56812111Sralph if (strcmp(last, line)) 56912111Sralph break; 57012111Sralph if ((err = sendfile('\3', last+1)) > 0) { 57112111Sralph (void) fclose(cfp); 57212111Sralph return(1); 57312111Sralph } else if (err) 57412111Sralph break; 57512111Sralph if (linelen) 57612111Sralph goto again; 57712111Sralph break; 57812111Sralph } 57912111Sralph } 58012111Sralph if (!err && sendfile('\2', file) > 0) { 58112111Sralph (void) fclose(cfp); 58212111Sralph return(1); 58312111Sralph } 58412111Sralph /* 58512111Sralph * pass 2 58612111Sralph */ 58712111Sralph fseek(cfp, 0L, 0); 58812111Sralph while (getline(cfp)) 58912111Sralph if (line[0] == 'U') 59012111Sralph (void) unlink(line+1); 59112111Sralph /* 59212111Sralph * clean-up incase another control file exists 59312111Sralph */ 59412111Sralph (void) fclose(cfp); 59512111Sralph (void) unlink(file); 59612111Sralph return(0); 59712111Sralph } 59812111Sralph 59912111Sralph /* 60012111Sralph * Send a data file to the remote machine and spool it. 60112111Sralph * Return positive if we should try resending. 60212111Sralph */ 60312877Sralph static 60412111Sralph sendfile(type, file) 60512111Sralph char type, *file; 60612111Sralph { 60712111Sralph register int f, i, amt; 60812111Sralph struct stat stb; 60912111Sralph char buf[BUFSIZ]; 61012111Sralph int sizerr; 61112111Sralph 61213148Ssam if ((f = open(file, O_RDONLY)) < 0 || fstat(f, &stb) < 0) { 61312111Sralph log("file (%s) open failure <errno = %d>", file, errno); 61412111Sralph return(-1); 61512111Sralph } 61612111Sralph (void) sprintf(buf, "%c%d %s\n", type, stb.st_size, file); 61712111Sralph amt = strlen(buf); 61812692Sralph if (write(pfd, buf, amt) != amt) { 61912692Sralph (void) close(f); 62012111Sralph return(1); 62112692Sralph } 62212692Sralph if (noresponse()) { 62312692Sralph (void) close(f); 62412111Sralph return(1); 62512692Sralph } 62612111Sralph sizerr = 0; 62712111Sralph for (i = 0; i < stb.st_size; i += BUFSIZ) { 62812111Sralph amt = BUFSIZ; 62912111Sralph if (i + amt > stb.st_size) 63012111Sralph amt = stb.st_size - i; 63112111Sralph if (sizerr == 0 && read(f, buf, amt) != amt) 63212111Sralph sizerr = 1; 63312692Sralph if (write(pfd, buf, amt) != amt) { 63412692Sralph (void) close(f); 63512111Sralph return(1); 63612692Sralph } 63712111Sralph } 63812111Sralph (void) close(f); 63912111Sralph if (sizerr) { 64012111Sralph log("%s: changed size", file); 64112111Sralph (void) write(pfd, "\1", 1); /* tell recvjob to ignore this file */ 64212111Sralph return(-1); 64312111Sralph } 64412111Sralph if (write(pfd, "", 1) != 1) 64512111Sralph return(1); 64612111Sralph if (noresponse()) 64712111Sralph return(1); 64812111Sralph return(0); 64912111Sralph } 65012111Sralph 65112111Sralph /* 65212111Sralph * Check to make sure there have been no errors and that both programs 65312111Sralph * are in sync with eachother. 65412111Sralph * Return non-zero if the connection was lost. 65512111Sralph */ 65612111Sralph static 65712111Sralph noresponse() 65812111Sralph { 65912111Sralph char resp; 66012111Sralph 66112111Sralph if (read(pfd, &resp, 1) != 1 || resp != '\0') { 66212111Sralph log("lost connection or error in recvjob"); 66312111Sralph return(1); 66412111Sralph } 66512111Sralph return(0); 66612111Sralph } 66712111Sralph 66812111Sralph /* 66912111Sralph * Banner printing stuff 67012111Sralph */ 67112877Sralph static 67212111Sralph banner(name1, name2) 67312111Sralph char *name1, *name2; 67412111Sralph { 67512111Sralph time_t tvec; 67612111Sralph extern char *ctime(); 67712111Sralph 67812111Sralph time(&tvec); 67912111Sralph if (!SF && !tof) 68012111Sralph (void) write(ofd, FF, strlen(FF)); 68112111Sralph if (SB) { /* short banner only */ 68212111Sralph if (class[0]) { 68312111Sralph (void) write(ofd, class, strlen(class)); 68412111Sralph (void) write(ofd, ":", 1); 68512111Sralph } 68612111Sralph (void) write(ofd, name1, strlen(name1)); 68712111Sralph (void) write(ofd, " Job: ", 7); 68812111Sralph (void) write(ofd, name2, strlen(name2)); 68912111Sralph (void) write(ofd, " Date: ", 8); 69012111Sralph (void) write(ofd, ctime(&tvec), 24); 69112111Sralph (void) write(ofd, "\n", 1); 69212111Sralph } else { /* normal banner */ 69312111Sralph (void) write(ofd, "\n\n\n", 3); 69412111Sralph scan_out(ofd, name1, '\0'); 69512111Sralph (void) write(ofd, "\n\n", 2); 69612111Sralph scan_out(ofd, name2, '\0'); 69712111Sralph if (class[0]) { 69812111Sralph (void) write(ofd,"\n\n\n",3); 69912111Sralph scan_out(ofd, class, '\0'); 70012111Sralph } 70112111Sralph (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15); 70212111Sralph (void) write(ofd, name2, strlen(name2)); 70312111Sralph (void) write(ofd, "\n\t\t\t\t\tDate: ", 12); 70412111Sralph (void) write(ofd, ctime(&tvec), 24); 70512111Sralph (void) write(ofd, "\n", 1); 70612111Sralph } 70712111Sralph if (!SF) 70812111Sralph (void) write(ofd, FF, strlen(FF)); 70912111Sralph tof = 1; 71012111Sralph } 71112111Sralph 71212877Sralph static char * 71312111Sralph scnline(key, p, c) 71412111Sralph register char key, *p; 71512111Sralph char c; 71612111Sralph { 71712111Sralph register scnwidth; 71812111Sralph 71912111Sralph for (scnwidth = WIDTH; --scnwidth;) { 72012111Sralph key <<= 1; 72112111Sralph *p++ = key & 0200 ? c : BACKGND; 72212111Sralph } 72312111Sralph return (p); 72412111Sralph } 72512111Sralph 72612111Sralph #define TRC(q) (((q)-' ')&0177) 72712111Sralph 72812877Sralph static 72912111Sralph scan_out(scfd, scsp, dlm) 73012111Sralph int scfd; 73112111Sralph char *scsp, dlm; 73212111Sralph { 73312111Sralph register char *strp; 73412111Sralph register nchrs, j; 73512111Sralph char outbuf[LINELEN+1], *sp, c, cc; 73612111Sralph int d, scnhgt; 73712111Sralph extern char scnkey[][HEIGHT]; /* in lpdchar.c */ 73812111Sralph 73912111Sralph for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) { 74012111Sralph strp = &outbuf[0]; 74112111Sralph sp = scsp; 74212111Sralph for (nchrs = 0; ; ) { 74312111Sralph d = dropit(c = TRC(cc = *sp++)); 74412111Sralph if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d)) 74512111Sralph for (j = WIDTH; --j;) 74612111Sralph *strp++ = BACKGND; 74712111Sralph else 74812111Sralph strp = scnline(scnkey[c][scnhgt-1-d], strp, cc); 74912111Sralph if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1) 75012111Sralph break; 75112111Sralph *strp++ = BACKGND; 75212111Sralph *strp++ = BACKGND; 75312111Sralph } 75412111Sralph while (*--strp == BACKGND && strp >= outbuf) 75512111Sralph ; 75612111Sralph strp++; 75712111Sralph *strp++ = '\n'; 75812111Sralph (void) write(scfd, outbuf, strp-outbuf); 75912111Sralph } 76012111Sralph } 76112111Sralph 76212877Sralph static 76312111Sralph dropit(c) 76412111Sralph char c; 76512111Sralph { 76612111Sralph switch(c) { 76712111Sralph 76812111Sralph case TRC('_'): 76912111Sralph case TRC(';'): 77012111Sralph case TRC(','): 77112111Sralph case TRC('g'): 77212111Sralph case TRC('j'): 77312111Sralph case TRC('p'): 77412111Sralph case TRC('q'): 77512111Sralph case TRC('y'): 77612111Sralph return (DROP); 77712111Sralph 77812111Sralph default: 77912111Sralph return (0); 78012111Sralph } 78112111Sralph } 78212111Sralph 78312111Sralph /* 78412111Sralph * sendmail --- 78512111Sralph * tell people about job completion 78612111Sralph */ 78712877Sralph static 78812111Sralph sendmail(bombed) 78912111Sralph int bombed; 79012111Sralph { 79112111Sralph static int p[2]; 79212111Sralph register int i; 79312111Sralph int stat; 79412111Sralph register char *cp; 79512111Sralph char buf[100]; 79612111Sralph 79712111Sralph pipe(p); 79812111Sralph if ((stat = dofork(DORETURN)) == 0) { /* child */ 79912111Sralph dup2(p[0], 0); 80012111Sralph for (i = 3; i < NOFILE; i++) 80112111Sralph (void) close(i); 80212111Sralph if ((cp = rindex(MAIL, '/')) != NULL) 80312111Sralph cp++; 80412111Sralph else 80512111Sralph cp = MAIL; 80612111Sralph sprintf(buf, "%s@%s", line+1, host); 80712111Sralph execl(MAIL, cp, buf, 0); 80812111Sralph exit(0); 80912111Sralph } else if (stat > 0) { /* parent */ 81012111Sralph dup2(p[1], 1); 81112111Sralph printf("To: %s\n", line+1); 81212111Sralph printf("Subject: printer job\n\n"); 81312111Sralph printf("Your printer job "); 81412111Sralph if (*jobname) 81512111Sralph printf("(%s) ", jobname); 81612463Sralph switch (bombed) { 81712463Sralph case 0: 81812463Sralph printf("\ncompleted successfully\n"); 81912463Sralph break; 82012463Sralph default: 82112463Sralph case 1: 82212463Sralph printf("\ncould not be printed\n"); 82312463Sralph break; 82412463Sralph case 2: 82512463Sralph printf("\ncould not be printed without an account on %s\n", host); 82612463Sralph break; 82712463Sralph } 82812111Sralph fflush(stdout); 82912111Sralph (void) close(1); 83012111Sralph } 83112111Sralph (void) close(p[0]); 83212111Sralph (void) close(p[1]); 83312111Sralph wait(&stat); 83412111Sralph } 83512111Sralph 83612111Sralph /* 83712111Sralph * dofork - fork with retries on failure 83812111Sralph */ 83912877Sralph static 84012111Sralph dofork(action) 84112111Sralph int action; 84212111Sralph { 84312111Sralph register int i, pid; 84412111Sralph 84512111Sralph for (i = 0; i < 20; i++) { 84612463Sralph if ((pid = fork()) < 0) { 84712111Sralph sleep((unsigned)(i*i)); 84812463Sralph continue; 84912463Sralph } 85012463Sralph /* 85112463Sralph * Child should run as daemon instead of root 85212463Sralph */ 85312463Sralph if (pid == 0) 85412463Sralph setuid(DU); 85512463Sralph return(pid); 85612111Sralph } 85712111Sralph log("can't fork"); 85812111Sralph 85912111Sralph switch (action) { 86012111Sralph case DORETURN: 86112111Sralph return (-1); 86212111Sralph default: 86312111Sralph log("bad action (%d) to dofork", action); 86412111Sralph /*FALL THRU*/ 86512111Sralph case DOABORT: 86612111Sralph exit(1); 86712111Sralph } 86812111Sralph /*NOTREACHED*/ 86912111Sralph } 87012111Sralph 87112111Sralph /* 87212111Sralph * Cleanup child processes when a SIGINT is caught. 87312111Sralph */ 87412877Sralph static 87512111Sralph onintr() 87612111Sralph { 87712111Sralph kill(0, SIGINT); 87812111Sralph if (ofilter > 0) 87912111Sralph kill(ofilter, SIGCONT); 88012111Sralph while (wait(0) > 0) 88112111Sralph ; 88212111Sralph exit(0); 88312111Sralph } 88412111Sralph 88512877Sralph static 88612111Sralph init() 88712111Sralph { 88812111Sralph int status; 88912111Sralph 89013169Sralph if ((status = pgetent(line, printer)) < 0) 89113169Sralph fatal("can't open printer description file"); 89213169Sralph else if (status == 0) 89313169Sralph fatal("unknown printer"); 89412111Sralph if ((LP = pgetstr("lp", &bp)) == NULL) 89512111Sralph LP = DEFDEVLP; 89612111Sralph if ((RP = pgetstr("rp", &bp)) == NULL) 89712463Sralph RP = DEFLP; 89812111Sralph if ((LO = pgetstr("lo", &bp)) == NULL) 89912111Sralph LO = DEFLOCK; 90012111Sralph if ((ST = pgetstr("st", &bp)) == NULL) 90112111Sralph ST = DEFSTAT; 90212111Sralph if ((LF = pgetstr("lf", &bp)) == NULL) 90312111Sralph LF = DEFLOGF; 90412111Sralph if ((SD = pgetstr("sd", &bp)) == NULL) 90512111Sralph SD = DEFSPOOL; 90612111Sralph if ((DU = pgetnum("du")) < 0) 90712111Sralph DU = DEFUID; 90812111Sralph if ((FF = pgetstr("ff", &bp)) == NULL) 90912111Sralph FF = DEFFF; 91012111Sralph if ((PW = pgetnum("pw")) < 0) 91112111Sralph PW = DEFWIDTH; 91212111Sralph sprintf(&width[2], "%d", PW); 91312111Sralph if ((PL = pgetnum("pl")) < 0) 91412111Sralph PL = DEFLENGTH; 91512111Sralph sprintf(&length[2], "%d", PL); 91612463Sralph if ((PX = pgetnum("px")) < 0) 91712463Sralph PX = 0; 91812463Sralph sprintf(&pxwidth[2], "%d", PX); 91912463Sralph if ((PY = pgetnum("py")) < 0) 92012463Sralph PY = 0; 92112463Sralph sprintf(&pxlength[2], "%d", PY); 92212111Sralph RM = pgetstr("rm", &bp); 92312111Sralph AF = pgetstr("af", &bp); 92412111Sralph OF = pgetstr("of", &bp); 92512111Sralph IF = pgetstr("if", &bp); 92612463Sralph RF = pgetstr("rf", &bp); 92712111Sralph TF = pgetstr("tf", &bp); 92813233Sralph NF = pgetstr("nf", &bp); 92912111Sralph DF = pgetstr("df", &bp); 93012111Sralph GF = pgetstr("gf", &bp); 93112111Sralph VF = pgetstr("vf", &bp); 93212111Sralph CF = pgetstr("cf", &bp); 93312111Sralph TR = pgetstr("tr", &bp); 93412463Sralph RS = pgetflag("rs"); 93512111Sralph SF = pgetflag("sf"); 93612111Sralph SH = pgetflag("sh"); 93712111Sralph SB = pgetflag("sb"); 93812111Sralph RW = pgetflag("rw"); 93912111Sralph BR = pgetnum("br"); 94012111Sralph if ((FC = pgetnum("fc")) < 0) 94112111Sralph FC = 0; 94212111Sralph if ((FS = pgetnum("fs")) < 0) 94312111Sralph FS = 0; 94412111Sralph if ((XC = pgetnum("xc")) < 0) 94512111Sralph XC = 0; 94612111Sralph if ((XS = pgetnum("xs")) < 0) 94712111Sralph XS = 0; 94812581Sralph tof = !pgetflag("fo"); 94912111Sralph } 95012111Sralph 95112463Sralph /* 95212463Sralph * Acquire line printer or remote connection. 95312463Sralph */ 95412877Sralph static 95512463Sralph openpr() 95612463Sralph { 95712463Sralph register int i, n; 95812463Sralph 95912463Sralph if (*LP) { 96012463Sralph for (i = 1; ; i = i < 32 ? i << 1 : i) { 96113148Ssam pfd = open(LP, RW ? O_RDWR : O_WRONLY); 96212463Sralph if (pfd >= 0) 96312463Sralph break; 96412463Sralph if (errno == ENOENT) { 96512463Sralph log("cannot open %s", LP); 96612463Sralph exit(1); 96712463Sralph } 96812463Sralph if (i == 1) 96912463Sralph status("waiting for %s to become ready (offline ?)", printer); 97012463Sralph sleep(i); 97112463Sralph } 97212463Sralph if (isatty(pfd)) 97312463Sralph setty(); 97412463Sralph status("%s is ready and printing", printer); 97512463Sralph } else if (RM != NULL) { 97612463Sralph for (i = 1; ; i = i < 512 ? i << 1 : i) { 97712528Sralph pfd = getport(RM); 97812463Sralph if (pfd >= 0) { 97912463Sralph (void) sprintf(line, "\2%s\n", RP); 98012463Sralph n = strlen(line); 98112463Sralph if (write(pfd, line, n) != n) 98212463Sralph break; 98312463Sralph if (noresponse()) 98412463Sralph (void) close(pfd); 98512463Sralph else 98612463Sralph break; 98712463Sralph } 98812463Sralph if (i == 1) 98912463Sralph status("waiting for %s to come up", RM); 99012463Sralph sleep(i); 99112463Sralph } 99212463Sralph status("sending to %s", RM); 99312463Sralph remote = 1; 99412463Sralph } else { 99512463Sralph log("no line printer device or remote machine name"); 99612463Sralph exit(1); 99712463Sralph } 99812463Sralph /* 99912463Sralph * Start up an output filter, if needed. 100012463Sralph */ 100112463Sralph if (OF) { 100212463Sralph int p[2]; 100312463Sralph char *cp; 100412463Sralph 100512463Sralph pipe(p); 100612463Sralph if ((ofilter = dofork(DOABORT)) == 0) { /* child */ 100712463Sralph dup2(p[0], 0); /* pipe is std in */ 100812463Sralph dup2(pfd, 1); /* printer is std out */ 100912463Sralph for (i = 3; i < NOFILE; i++) 101012463Sralph (void) close(i); 101112463Sralph if ((cp = rindex(OF, '/')) == NULL) 101212463Sralph cp = OF; 101312463Sralph else 101412463Sralph cp++; 101512463Sralph execl(OF, cp, width, length, 0); 101612463Sralph log("can't execl output filter %s", OF); 101712463Sralph exit(1); 101812463Sralph } 101912463Sralph (void) close(p[0]); /* close input side */ 102012463Sralph ofd = p[1]; /* use pipe for output */ 102112463Sralph } else { 102212463Sralph ofd = pfd; 102312463Sralph ofilter = 0; 102412463Sralph } 102512463Sralph } 102612463Sralph 102712111Sralph struct bauds { 102812111Sralph int baud; 102912111Sralph int speed; 103012111Sralph } bauds[] = { 103112111Sralph 50, B50, 103212111Sralph 75, B75, 103312111Sralph 110, B110, 103412111Sralph 134, B134, 103512111Sralph 150, B150, 103612111Sralph 200, B200, 103712111Sralph 300, B300, 103812111Sralph 600, B600, 103912111Sralph 1200, B1200, 104012111Sralph 1800, B1800, 104112111Sralph 2400, B2400, 104212111Sralph 4800, B4800, 104312111Sralph 9600, B9600, 104412111Sralph 19200, EXTA, 104512111Sralph 38400, EXTB, 104612111Sralph 0, 0 104712111Sralph }; 104812111Sralph 104912111Sralph /* 105012111Sralph * setup tty lines. 105112111Sralph */ 105212877Sralph static 105312111Sralph setty() 105412111Sralph { 105512111Sralph struct sgttyb ttybuf; 105612111Sralph register struct bauds *bp; 105712111Sralph 105812111Sralph if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) { 105912111Sralph log("cannot set exclusive-use"); 106012111Sralph exit(1); 106112111Sralph } 106212111Sralph if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) { 106312111Sralph log("cannot get tty parameters"); 106412111Sralph exit(1); 106512111Sralph } 106612111Sralph if (BR > 0) { 106712111Sralph for (bp = bauds; bp->baud; bp++) 106812111Sralph if (BR == bp->baud) 106912111Sralph break; 107012111Sralph if (!bp->baud) { 107112111Sralph log("illegal baud rate %d", BR); 107212111Sralph exit(1); 107312111Sralph } 107412111Sralph ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed; 107512111Sralph } 107613169Sralph ttybuf.sg_flags &= ~FC; 107713169Sralph ttybuf.sg_flags |= FS; 107812111Sralph if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) { 107912111Sralph log("cannot set tty parameters"); 108012111Sralph exit(1); 108112111Sralph } 108212111Sralph if (XC) { 108312111Sralph if (ioctl(pfd, TIOCLBIC, &XC) < 0) { 108412111Sralph log("cannot set local tty parameters"); 108512111Sralph exit(1); 108612111Sralph } 108712111Sralph } 108812111Sralph if (XS) { 108912111Sralph if (ioctl(pfd, TIOCLBIS, &XS) < 0) { 109012111Sralph log("cannot set local tty parameters"); 109112111Sralph exit(1); 109212111Sralph } 109312111Sralph } 109412111Sralph } 109512463Sralph 109612463Sralph /*VARARGS1*/ 109712463Sralph static 109812463Sralph status(msg, a1, a2, a3) 109912463Sralph char *msg; 110012463Sralph { 110112463Sralph register int fd; 110212463Sralph char buf[BUFSIZ]; 110312463Sralph 110412463Sralph umask(0); 110513148Ssam fd = open(ST, O_WRONLY|O_CREAT, 0664); 110613148Ssam if (fd < 0 || flock(fd, LOCK_EX) < 0) 110712463Sralph fatal("cannot create status file"); 110813148Ssam ftruncate(fd, 0); 110912463Sralph sprintf(buf, msg, a1, a2, a3); 111012463Sralph strcat(buf, "\n"); 111112463Sralph (void) write(fd, buf, strlen(buf)); 111212463Sralph (void) close(fd); 111312463Sralph } 1114