113954Ssam #ifndef lint 2*15552Sralph static char sccsid[] = "@(#)printjob.c 4.15 (Berkeley) 11/18/83"; 313954Ssam #endif 413954Ssam 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 */ 2714150Sralph static int count; /* Number of files actually printed */ 2812877Sralph static int remote; /* true if sending files to remote */ 2912111Sralph 3014150Sralph static char fromhost[32]; /* user's host machine */ 3112877Sralph static char logname[32]; /* user's login name */ 32*15552Sralph static char jobname[100]; /* job or file name */ 3312877Sralph static char class[32]; /* classification field */ 3412877Sralph static char width[10] = "-w"; /* page width in characters */ 3512877Sralph static char length[10] = "-l"; /* page length in lines */ 3612877Sralph static char pxwidth[10] = "-x"; /* page width in pixels */ 3712877Sralph static char pxlength[10] = "-y"; /* page length in pixels */ 3812877Sralph static char indent[10] = "-i0"; /* indentation size in characters */ 3912111Sralph 4012111Sralph printjob() 4112111Sralph { 4212111Sralph struct stat stb; 4312111Sralph register struct queue *q, **qp; 4412111Sralph struct queue **queue; 4512111Sralph register int i, nitems; 4612111Sralph long pidoff; 4712111Sralph extern int onintr(); 4812111Sralph 4912111Sralph init(); /* set up capabilities */ 5013442Sralph (void) write(1, "", 1); /* ack that daemon is started */ 5112877Sralph (void) close(1); /* set up log file */ 5212877Sralph (void) close(2); 5313148Ssam if (open(LF, O_WRONLY|O_APPEND) < 0) 5413148Ssam (void) open("/dev/null", O_WRONLY); 5512877Sralph dup(1); 5612463Sralph pid = getpid(); /* for use with lprm */ 5712111Sralph setpgrp(0, pid); 5814709Sralph signal(SIGHUP, onintr); 5913148Ssam signal(SIGINT, onintr); 6014709Sralph signal(SIGQUIT, onintr); 6114709Sralph signal(SIGTERM, onintr); 6212111Sralph 6312111Sralph /* 6412111Sralph * uses short form file names 6512111Sralph */ 6612111Sralph if (chdir(SD) < 0) { 6712111Sralph log("cannot chdir to %s", SD); 6812111Sralph exit(1); 6912111Sralph } 7012463Sralph if (stat(LO, &stb) == 0 && (stb.st_mode & 0100)) 7112463Sralph exit(0); /* printing disabled */ 7214150Sralph lfd = open(LO, O_WRONLY|O_CREAT, 0644); 7313169Sralph if (lfd < 0) { 7413169Sralph log("cannot create %s", LO); 7513169Sralph exit(1); 7613169Sralph } 7713169Sralph if (flock(lfd, LOCK_EX|LOCK_NB) < 0) { 7812111Sralph if (errno == EWOULDBLOCK) /* active deamon present */ 7912111Sralph exit(0); 8013169Sralph log("cannot lock %s", LO); 8112111Sralph exit(1); 8212111Sralph } 8313148Ssam ftruncate(lfd, 0); 8412111Sralph /* 8512111Sralph * write process id for others to know 8612111Sralph */ 8712111Sralph sprintf(line, "%u\n", pid); 8812111Sralph pidoff = i = strlen(line); 8912463Sralph if (write(lfd, line, i) != i) { 9012111Sralph log("cannot write daemon pid"); 9112111Sralph exit(1); 9212111Sralph } 9312111Sralph /* 9412111Sralph * search the spool directory for work and sort by queue order. 9512111Sralph */ 9612111Sralph if ((nitems = getq(&queue)) < 0) { 9712111Sralph log("can't scan spool directory %s", SD); 9812111Sralph exit(1); 9912111Sralph } 10012463Sralph if (nitems == 0) /* no work to do */ 10112111Sralph exit(0); 10213169Sralph if (stb.st_mode & 01) { /* reset queue flag */ 10313169Sralph if (fchmod(lfd, stb.st_mode & 0776) < 0) 10413169Sralph log("cannot chmod %s", LO); 10513169Sralph } 10612463Sralph openpr(); /* open printer or remote */ 10712463Sralph again: 10812111Sralph /* 10912111Sralph * we found something to do now do it -- 11012111Sralph * write the name of the current control file into the lock file 11112111Sralph * so the spool queue program can tell what we're working on 11212111Sralph */ 11312111Sralph for (qp = queue; nitems--; free((char *) q)) { 11412111Sralph q = *qp++; 11512111Sralph if (stat(q->q_name, &stb) < 0) 11612111Sralph continue; 11712463Sralph restart: 11812111Sralph (void) lseek(lfd, pidoff, 0); 11912111Sralph (void) sprintf(line, "%s\n", q->q_name); 12012111Sralph i = strlen(line); 12112111Sralph if (write(lfd, line, i) != i) 12212111Sralph log("can't write (%d) control file name", errno); 12312111Sralph if (!remote) 12412111Sralph i = printit(q->q_name); 12512111Sralph else 12612111Sralph i = sendit(q->q_name); 12712463Sralph /* 12813169Sralph * Check to see if we are supposed to stop printing or 12913169Sralph * if we are to rebuild the queue. 13012463Sralph */ 13113169Sralph if (fstat(lfd, &stb) == 0) { 13213169Sralph if (stb.st_mode & 0100) 13313169Sralph goto done; 13413169Sralph if (stb.st_mode & 01) { 13513169Sralph for (free((char *) q); nitems--; free((char *) q)) 13613169Sralph q = *qp++; 13713169Sralph if (fchmod(lfd, stb.st_mode & 0776) < 0) 13813169Sralph log("cannot chmod %s", LO); 13913169Sralph break; 14013169Sralph } 14113169Sralph } 14214150Sralph if (i == 0) /* file ok and printed */ 14314150Sralph count++; 14414150Sralph else if (i > 0) { /* try reprinting the job */ 14512111Sralph log("restarting"); 14612111Sralph if (ofilter > 0) { 14712111Sralph kill(ofilter, SIGCONT); /* to be sure */ 14812111Sralph (void) close(ofd); 14912111Sralph while ((i = wait(0)) > 0 && i != ofilter) 15012111Sralph ; 15112111Sralph ofilter = 0; 15212111Sralph } 15312463Sralph (void) close(pfd); /* close printer */ 15412463Sralph (void) lseek(lfd, pidoff, 0); 15512463Sralph if (write(lfd, "\n", 1) != 1) 15612463Sralph log("can't write (%d) control file name", errno); 15712463Sralph openpr(); /* try to reopen printer */ 15812111Sralph goto restart; 15912111Sralph } 16012111Sralph } 16112111Sralph free((char *) queue); 16212463Sralph /* 16312463Sralph * search the spool directory for more work. 16412463Sralph */ 16512463Sralph if ((nitems = getq(&queue)) < 0) { 16612463Sralph log("can't scan spool directory %s", SD); 16712463Sralph exit(1); 16812463Sralph } 16912463Sralph if (nitems == 0) { /* no more work to do */ 17012463Sralph done: 17114150Sralph if (count > 0) { /* Files actually printed */ 17214150Sralph if (!SF && !tof) 17314150Sralph (void) write(ofd, FF, strlen(FF)); 17414150Sralph if (TR != NULL) /* output trailer */ 17514150Sralph (void) write(ofd, TR, strlen(TR)); 17614150Sralph } 17712463Sralph exit(0); 17812463Sralph } 17912111Sralph goto again; 18012111Sralph } 18112111Sralph 18212111Sralph char fonts[4][50]; /* fonts for troff */ 18312111Sralph 18412111Sralph static char ifonts[4][18] = { 18512111Sralph "/usr/lib/vfont/R", 18612111Sralph "/usr/lib/vfont/I", 18712111Sralph "/usr/lib/vfont/B", 18812111Sralph "/usr/lib/vfont/S" 18912111Sralph }; 19012111Sralph 19112111Sralph /* 19212111Sralph * The remaining part is the reading of the control file (cf) 19312111Sralph * and performing the various actions. 19412111Sralph * Returns 0 if everthing was OK, 1 if we should try to reprint the job and 19512111Sralph * -1 if a non-recoverable error occured. 19612111Sralph */ 19712877Sralph static 19812111Sralph printit(file) 19912111Sralph char *file; 20012111Sralph { 20112111Sralph register int i; 20212111Sralph int bombed = 0; 20312111Sralph 20412111Sralph /* 20512111Sralph * open control file 20612111Sralph */ 20712111Sralph if ((cfp = fopen(file, "r")) == NULL) { 20812111Sralph log("control file (%s) open failure <errno = %d>", file, errno); 20912111Sralph return(0); 21012111Sralph } 21112111Sralph /* 21212111Sralph * Reset troff fonts. 21312111Sralph */ 21412111Sralph for (i = 0; i < 4; i++) 21512111Sralph strcpy(fonts[i], ifonts[i]); 21612111Sralph 21712111Sralph /* 21812111Sralph * read the control file for work to do 21912111Sralph * 22012111Sralph * file format -- first character in the line is a command 22112111Sralph * rest of the line is the argument. 22212111Sralph * valid commands are: 22312111Sralph * 22412111Sralph * J -- "job name" on banner page 22512111Sralph * C -- "class name" on banner page 22612111Sralph * L -- "literal" user's name to print on banner 22712111Sralph * T -- "title" for pr 22812111Sralph * H -- "host name" of machine where lpr was done 22912111Sralph * P -- "person" user's login name 23012581Sralph * I -- "indent" amount to indent output 23112111Sralph * f -- "file name" name of text file to print 23212111Sralph * l -- "file name" text file with control chars 23312111Sralph * p -- "file name" text file to print with pr(1) 23412111Sralph * t -- "file name" troff(1) file to print 23513233Sralph * n -- "file name" ditroff(1) file to print 23612111Sralph * d -- "file name" dvi file to print 23712111Sralph * g -- "file name" plot(1G) file to print 23812111Sralph * v -- "file name" plain raster file to print 23912111Sralph * c -- "file name" cifplot file to print 24012111Sralph * 1 -- "R font file" for troff 24112111Sralph * 2 -- "I font file" for troff 24212111Sralph * 3 -- "B font file" for troff 24312111Sralph * 4 -- "S font file" for troff 24412111Sralph * N -- "name" of file (used by lpq) 24512111Sralph * U -- "unlink" name of file to remove 24612111Sralph * (after we print it. (Pass 2 only)). 24712111Sralph * M -- "mail" to user when done printing 24812111Sralph * 24912111Sralph * getline reads a line and expands tabs to blanks 25012111Sralph */ 25112111Sralph 25212111Sralph /* pass 1 */ 25312111Sralph 25412111Sralph while (getline(cfp)) 25512111Sralph switch (line[0]) { 25612111Sralph case 'H': 25714150Sralph strcpy(fromhost, line+1); 25812111Sralph if (class[0] == '\0') 259*15552Sralph strncpy(class, line+1, sizeof(class)-1); 26012111Sralph continue; 26112111Sralph 26212111Sralph case 'P': 263*15552Sralph strncpy(logname, line+1, sizeof(logname)-1); 26412463Sralph if (RS) { /* restricted */ 26512463Sralph if (getpwnam(logname) == (struct passwd *)0) { 26612463Sralph bombed = 2; 26712463Sralph sendmail(bombed); 26812463Sralph goto pass2; 26912463Sralph } 27012463Sralph } 27112111Sralph continue; 27212111Sralph 27312111Sralph case 'J': 27412111Sralph if (line[1] != '\0') 275*15552Sralph strncpy(jobname, line+1, sizeof(jobname)-1); 27612111Sralph else 27712111Sralph strcpy(jobname, " "); 27812111Sralph continue; 27912111Sralph 28012111Sralph case 'C': 28112111Sralph if (line[1] != '\0') 282*15552Sralph strncpy(class, line+1, sizeof(class)-1); 28312111Sralph else if (class[0] == '\0') 28412111Sralph gethostname(class, sizeof (class)); 28512111Sralph continue; 28612111Sralph 28712111Sralph case 'T': /* header title for pr */ 288*15552Sralph strncpy(title, line+1, sizeof(title)-1); 28912111Sralph continue; 29012111Sralph 29112111Sralph case 'L': /* identification line */ 29212111Sralph if (!SH) 29312111Sralph banner(line+1, jobname); 29412111Sralph continue; 29512111Sralph 29612111Sralph case '1': /* troff fonts */ 29712111Sralph case '2': 29812111Sralph case '3': 29912111Sralph case '4': 30012111Sralph if (line[1] != '\0') 30112111Sralph strcpy(fonts[line[0]-'1'], line+1); 30212111Sralph continue; 30312111Sralph 30412111Sralph case 'W': /* page width */ 305*15552Sralph strncpy(width+2, line+1, sizeof(width)-3); 30612111Sralph continue; 30712111Sralph 30812581Sralph case 'I': /* indent amount */ 309*15552Sralph strncpy(indent+2, line+1, sizeof(indent)-3); 31012581Sralph continue; 31112581Sralph 31212111Sralph default: /* some file to print */ 31312111Sralph if ((i = print(line[0], line+1)) > 0) { 31412111Sralph (void) fclose(cfp); 31512111Sralph return(1); 31612111Sralph } else if (i < 0) 31712111Sralph bombed = 1; 31812111Sralph title[0] = '\0'; 31912111Sralph continue; 32012111Sralph 32112111Sralph case 'N': 32212111Sralph case 'U': 32312111Sralph case 'M': 32412111Sralph continue; 32512111Sralph } 32612111Sralph 32712111Sralph /* pass 2 */ 32812111Sralph 32912463Sralph pass2: 33012111Sralph fseek(cfp, 0L, 0); 33112111Sralph while (getline(cfp)) 33212111Sralph switch (line[0]) { 33312111Sralph case 'M': 33412463Sralph if (bombed != 2) /* already sent if 2 */ 33512463Sralph sendmail(bombed); 33612111Sralph continue; 33712111Sralph 33812111Sralph case 'U': 33912111Sralph (void) unlink(line+1); 34012111Sralph } 34112111Sralph /* 34212111Sralph * clean-up incase another control file exists 34312111Sralph */ 34412111Sralph (void) fclose(cfp); 34512111Sralph (void) unlink(file); 34614150Sralph return(bombed ? -1 : 0); 34712111Sralph } 34812111Sralph 34912111Sralph /* 35012111Sralph * Print a file. 35113233Sralph * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}. 35212111Sralph * Return -1 if a non-recoverable error occured, 1 if a recoverable error and 35312111Sralph * 0 if all is well. 35412111Sralph * Note: all filters take stdin as the file, stdout as the printer, 35512111Sralph * stderr as the log file, and must not ignore SIGINT. 35612111Sralph */ 35712877Sralph static 35812111Sralph print(format, file) 35912111Sralph int format; 36012111Sralph char *file; 36112111Sralph { 36212111Sralph register int n, fi, fo; 36312111Sralph register char *prog; 36412111Sralph char *av[15], buf[BUFSIZ]; 36512111Sralph int pid, p[2], stopped = 0; 36612111Sralph union wait status; 36712111Sralph 36813148Ssam if ((fi = open(file, O_RDONLY)) < 0) { 36912111Sralph log("%s: open failure <errno = %d>", file, errno); 37012111Sralph return(-1); 37112111Sralph } 37212111Sralph if (!SF && !tof) { /* start on a fresh page */ 37312111Sralph (void) write(ofd, FF, strlen(FF)); 37412111Sralph tof = 1; 37512111Sralph } 37612111Sralph if (IF == NULL && (format == 'f' || format == 'l')) { 37712111Sralph tof = 0; 37812111Sralph while ((n = read(fi, buf, BUFSIZ)) > 0) 37912111Sralph if (write(ofd, buf, n) != n) { 38012111Sralph (void) close(fi); 38112111Sralph return(1); 38212111Sralph } 38312111Sralph (void) close(fi); 38412111Sralph return(0); 38512111Sralph } 38612111Sralph switch (format) { 38712111Sralph case 'p': /* print file using 'pr' */ 38812111Sralph if (IF == NULL) { /* use output filter */ 38912111Sralph prog = PR; 39012111Sralph av[0] = "pr"; 39112111Sralph av[1] = width; 39212111Sralph av[2] = length; 39312111Sralph av[3] = "-h"; 39412111Sralph av[4] = *title ? title : " "; 39512111Sralph av[5] = 0; 39612111Sralph fo = ofd; 39712111Sralph goto start; 39812111Sralph } 39912111Sralph pipe(p); 40012111Sralph if ((prchild = dofork(DORETURN)) == 0) { /* child */ 40112111Sralph dup2(fi, 0); /* file is stdin */ 40212111Sralph dup2(p[1], 1); /* pipe is stdout */ 40312111Sralph for (n = 3; n < NOFILE; n++) 40412111Sralph (void) close(n); 40512111Sralph execl(PR, "pr", width, length, "-h", *title ? title : " ", 0); 40612111Sralph log("cannot execl %s", PR); 40712111Sralph exit(2); 40812111Sralph } 40912111Sralph (void) close(p[1]); /* close output side */ 41012111Sralph (void) close(fi); 41112111Sralph if (prchild < 0) { 41212111Sralph prchild = 0; 41312111Sralph (void) close(p[0]); 41412111Sralph return(-1); 41512111Sralph } 41612111Sralph fi = p[0]; /* use pipe for input */ 41712111Sralph case 'f': /* print plain text file */ 41812111Sralph prog = IF; 41912111Sralph av[1] = width; 42012111Sralph av[2] = length; 42112581Sralph av[3] = indent; 42212581Sralph n = 4; 42312111Sralph break; 42412111Sralph case 'l': /* like 'f' but pass control characters */ 42512111Sralph prog = IF; 42614325Sralph av[1] = "-c"; 42712111Sralph av[2] = width; 42812111Sralph av[3] = length; 42912581Sralph av[4] = indent; 43012581Sralph n = 5; 43112111Sralph break; 43212463Sralph case 'r': /* print a fortran text file */ 43312463Sralph prog = RF; 43412463Sralph av[1] = width; 43512463Sralph av[2] = length; 43612463Sralph n = 3; 43712463Sralph break; 43812111Sralph case 't': /* print troff output */ 43913233Sralph case 'n': /* print ditroff output */ 44012463Sralph case 'd': /* print tex output */ 44112111Sralph (void) unlink(".railmag"); 44212463Sralph if ((fo = creat(".railmag", FILMOD)) < 0) { 44312111Sralph log("cannot create .railmag"); 44412111Sralph (void) unlink(".railmag"); 44512111Sralph } else { 44612111Sralph for (n = 0; n < 4; n++) { 44712111Sralph if (fonts[n][0] != '/') 44812111Sralph (void) write(fo, "/usr/lib/vfont/", 15); 44912111Sralph (void) write(fo, fonts[n], strlen(fonts[n])); 45012111Sralph (void) write(fo, "\n", 1); 45112111Sralph } 45212111Sralph (void) close(fo); 45312111Sralph } 45413233Sralph prog = (format == 't') ? TF : (format == 'n') ? NF : DF; 45512463Sralph av[1] = pxwidth; 45612463Sralph av[2] = pxlength; 45712463Sralph n = 3; 45812111Sralph break; 45912111Sralph case 'c': /* print cifplot output */ 46012111Sralph prog = CF; 46112463Sralph av[1] = pxwidth; 46212463Sralph av[2] = pxlength; 46312463Sralph n = 3; 46412111Sralph break; 46512111Sralph case 'g': /* print plot(1G) output */ 46612111Sralph prog = GF; 46712463Sralph av[1] = pxwidth; 46812463Sralph av[2] = pxlength; 46912463Sralph n = 3; 47012111Sralph break; 47112111Sralph case 'v': /* print raster output */ 47212111Sralph prog = VF; 47312463Sralph av[1] = pxwidth; 47412463Sralph av[2] = pxlength; 47512463Sralph n = 3; 47612111Sralph break; 47712111Sralph default: 47812111Sralph (void) close(fi); 47912111Sralph log("illegal format character '%c'", format); 48012111Sralph return(-1); 48112111Sralph } 48212111Sralph if ((av[0] = rindex(prog, '/')) != NULL) 48312111Sralph av[0]++; 48412111Sralph else 48512111Sralph av[0] = prog; 48612111Sralph av[n++] = "-n"; 48712111Sralph av[n++] = logname; 48812111Sralph av[n++] = "-h"; 48914150Sralph av[n++] = fromhost; 49012111Sralph av[n++] = AF; 49112111Sralph av[n] = 0; 49212111Sralph fo = pfd; 49312111Sralph if (ofilter > 0) { /* stop output filter */ 49412111Sralph write(ofd, "\031\1", 2); 49512111Sralph while ((pid = wait3(&status, WUNTRACED, 0)) > 0 && pid != ofilter) 49612111Sralph ; 49712111Sralph if (status.w_stopval != WSTOPPED) { 49812111Sralph (void) close(fi); 49912111Sralph log("output filter died (%d)", status.w_retcode); 50012111Sralph return(1); 50112111Sralph } 50212111Sralph stopped++; 50312111Sralph } 50412111Sralph start: 50512111Sralph if ((child = dofork(DORETURN)) == 0) { /* child */ 50612111Sralph dup2(fi, 0); 50712111Sralph dup2(fo, 1); 50812111Sralph for (n = 3; n < NOFILE; n++) 50912111Sralph (void) close(n); 51012111Sralph execv(prog, av); 51112111Sralph log("cannot execl %s", prog); 51212111Sralph exit(2); 51312111Sralph } 51412111Sralph (void) close(fi); 51512111Sralph if (child < 0) 51612111Sralph status.w_retcode = 100; 51712111Sralph else 51812111Sralph while ((pid = wait(&status)) > 0 && pid != child) 51912111Sralph ; 52012111Sralph child = 0; 52112111Sralph prchild = 0; 52212111Sralph if (stopped) { /* restart output filter */ 52312111Sralph if (kill(ofilter, SIGCONT) < 0) { 52412111Sralph log("cannot restart output filter"); 52512111Sralph exit(1); 52612111Sralph } 52712111Sralph } 52812111Sralph tof = 0; 52912111Sralph if (!WIFEXITED(status) || status.w_retcode > 1) { 53012111Sralph log("Daemon Filter '%c' Malfunction (%d)", format, status.w_retcode); 53112111Sralph return(-1); 53212111Sralph } else if (status.w_retcode == 1) 53312111Sralph return(1); 53412111Sralph tof = 1; 53512111Sralph return(0); 53612111Sralph } 53712111Sralph 53812111Sralph /* 53912111Sralph * Send the daemon control file (cf) and any data files. 54012111Sralph * Return -1 if a non-recoverable error occured, 1 if a recoverable error and 54112111Sralph * 0 if all is well. 54212111Sralph */ 54312877Sralph static 54412111Sralph sendit(file) 54512111Sralph char *file; 54612111Sralph { 54712111Sralph register int linelen, err = 0; 54812111Sralph char last[132]; 54912111Sralph 55012111Sralph /* 55112111Sralph * open control file 55212111Sralph */ 55312111Sralph if ((cfp = fopen(file, "r")) == NULL) { 55412111Sralph log("control file (%s) open failure <errno = %d>", file, errno); 55512111Sralph return(0); 55612111Sralph } 55712111Sralph /* 55812111Sralph * read the control file for work to do 55912111Sralph * 56012111Sralph * file format -- first character in the line is a command 56112111Sralph * rest of the line is the argument. 56212111Sralph * commands of interest are: 56312111Sralph * 56412111Sralph * a-z -- "file name" name of file to print 56512111Sralph * U -- "unlink" name of file to remove 56612111Sralph * (after we print it. (Pass 2 only)). 56712111Sralph */ 56812111Sralph 56912111Sralph /* 57012111Sralph * pass 1 57112111Sralph */ 57212111Sralph while (getline(cfp)) { 57312111Sralph again: 57412111Sralph if (line[0] >= 'a' && line[0] <= 'z') { 57512111Sralph strcpy(last, line); 57612111Sralph while (linelen = getline(cfp)) 57712111Sralph if (strcmp(last, line)) 57812111Sralph break; 57912111Sralph if ((err = sendfile('\3', last+1)) > 0) { 58012111Sralph (void) fclose(cfp); 58112111Sralph return(1); 58212111Sralph } else if (err) 58312111Sralph break; 58412111Sralph if (linelen) 58512111Sralph goto again; 58612111Sralph break; 58712111Sralph } 58812111Sralph } 58912111Sralph if (!err && sendfile('\2', file) > 0) { 59012111Sralph (void) fclose(cfp); 59112111Sralph return(1); 59212111Sralph } 59312111Sralph /* 59412111Sralph * pass 2 59512111Sralph */ 59612111Sralph fseek(cfp, 0L, 0); 59712111Sralph while (getline(cfp)) 59812111Sralph if (line[0] == 'U') 59912111Sralph (void) unlink(line+1); 60012111Sralph /* 60112111Sralph * clean-up incase another control file exists 60212111Sralph */ 60312111Sralph (void) fclose(cfp); 60412111Sralph (void) unlink(file); 60512111Sralph return(0); 60612111Sralph } 60712111Sralph 60812111Sralph /* 60912111Sralph * Send a data file to the remote machine and spool it. 61012111Sralph * Return positive if we should try resending. 61112111Sralph */ 61212877Sralph static 61312111Sralph sendfile(type, file) 61412111Sralph char type, *file; 61512111Sralph { 61612111Sralph register int f, i, amt; 61712111Sralph struct stat stb; 61812111Sralph char buf[BUFSIZ]; 61912111Sralph int sizerr; 62012111Sralph 62113148Ssam if ((f = open(file, O_RDONLY)) < 0 || fstat(f, &stb) < 0) { 62212111Sralph log("file (%s) open failure <errno = %d>", file, errno); 62312111Sralph return(-1); 62412111Sralph } 62512111Sralph (void) sprintf(buf, "%c%d %s\n", type, stb.st_size, file); 62612111Sralph amt = strlen(buf); 62712692Sralph if (write(pfd, buf, amt) != amt) { 62812692Sralph (void) close(f); 62912111Sralph return(1); 63012692Sralph } 63112692Sralph if (noresponse()) { 63212692Sralph (void) close(f); 63312111Sralph return(1); 63412692Sralph } 63512111Sralph sizerr = 0; 63612111Sralph for (i = 0; i < stb.st_size; i += BUFSIZ) { 63712111Sralph amt = BUFSIZ; 63812111Sralph if (i + amt > stb.st_size) 63912111Sralph amt = stb.st_size - i; 64012111Sralph if (sizerr == 0 && read(f, buf, amt) != amt) 64112111Sralph sizerr = 1; 64212692Sralph if (write(pfd, buf, amt) != amt) { 64312692Sralph (void) close(f); 64412111Sralph return(1); 64512692Sralph } 64612111Sralph } 64712111Sralph (void) close(f); 64812111Sralph if (sizerr) { 64912111Sralph log("%s: changed size", file); 65012111Sralph (void) write(pfd, "\1", 1); /* tell recvjob to ignore this file */ 65112111Sralph return(-1); 65212111Sralph } 65312111Sralph if (write(pfd, "", 1) != 1) 65412111Sralph return(1); 65512111Sralph if (noresponse()) 65612111Sralph return(1); 65712111Sralph return(0); 65812111Sralph } 65912111Sralph 66012111Sralph /* 66112111Sralph * Check to make sure there have been no errors and that both programs 66212111Sralph * are in sync with eachother. 66312111Sralph * Return non-zero if the connection was lost. 66412111Sralph */ 66512111Sralph static 66612111Sralph noresponse() 66712111Sralph { 66812111Sralph char resp; 66912111Sralph 67012111Sralph if (read(pfd, &resp, 1) != 1 || resp != '\0') { 67112111Sralph log("lost connection or error in recvjob"); 67212111Sralph return(1); 67312111Sralph } 67412111Sralph return(0); 67512111Sralph } 67612111Sralph 67712111Sralph /* 67812111Sralph * Banner printing stuff 67912111Sralph */ 68012877Sralph static 68112111Sralph banner(name1, name2) 68212111Sralph char *name1, *name2; 68312111Sralph { 68412111Sralph time_t tvec; 68512111Sralph extern char *ctime(); 68612111Sralph 68712111Sralph time(&tvec); 68812111Sralph if (!SF && !tof) 68912111Sralph (void) write(ofd, FF, strlen(FF)); 69012111Sralph if (SB) { /* short banner only */ 69112111Sralph if (class[0]) { 69212111Sralph (void) write(ofd, class, strlen(class)); 69312111Sralph (void) write(ofd, ":", 1); 69412111Sralph } 69512111Sralph (void) write(ofd, name1, strlen(name1)); 69612111Sralph (void) write(ofd, " Job: ", 7); 69712111Sralph (void) write(ofd, name2, strlen(name2)); 69812111Sralph (void) write(ofd, " Date: ", 8); 69912111Sralph (void) write(ofd, ctime(&tvec), 24); 70012111Sralph (void) write(ofd, "\n", 1); 70112111Sralph } else { /* normal banner */ 70212111Sralph (void) write(ofd, "\n\n\n", 3); 70312111Sralph scan_out(ofd, name1, '\0'); 70412111Sralph (void) write(ofd, "\n\n", 2); 70512111Sralph scan_out(ofd, name2, '\0'); 70612111Sralph if (class[0]) { 70712111Sralph (void) write(ofd,"\n\n\n",3); 70812111Sralph scan_out(ofd, class, '\0'); 70912111Sralph } 71012111Sralph (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15); 71112111Sralph (void) write(ofd, name2, strlen(name2)); 71212111Sralph (void) write(ofd, "\n\t\t\t\t\tDate: ", 12); 71312111Sralph (void) write(ofd, ctime(&tvec), 24); 71412111Sralph (void) write(ofd, "\n", 1); 71512111Sralph } 71612111Sralph if (!SF) 71712111Sralph (void) write(ofd, FF, strlen(FF)); 71812111Sralph tof = 1; 71912111Sralph } 72012111Sralph 72112877Sralph static char * 72212111Sralph scnline(key, p, c) 72312111Sralph register char key, *p; 72412111Sralph char c; 72512111Sralph { 72612111Sralph register scnwidth; 72712111Sralph 72812111Sralph for (scnwidth = WIDTH; --scnwidth;) { 72912111Sralph key <<= 1; 73012111Sralph *p++ = key & 0200 ? c : BACKGND; 73112111Sralph } 73212111Sralph return (p); 73312111Sralph } 73412111Sralph 73512111Sralph #define TRC(q) (((q)-' ')&0177) 73612111Sralph 73712877Sralph static 73812111Sralph scan_out(scfd, scsp, dlm) 73912111Sralph int scfd; 74012111Sralph char *scsp, dlm; 74112111Sralph { 74212111Sralph register char *strp; 74312111Sralph register nchrs, j; 74412111Sralph char outbuf[LINELEN+1], *sp, c, cc; 74512111Sralph int d, scnhgt; 74612111Sralph extern char scnkey[][HEIGHT]; /* in lpdchar.c */ 74712111Sralph 74812111Sralph for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) { 74912111Sralph strp = &outbuf[0]; 75012111Sralph sp = scsp; 75112111Sralph for (nchrs = 0; ; ) { 75212111Sralph d = dropit(c = TRC(cc = *sp++)); 75312111Sralph if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d)) 75412111Sralph for (j = WIDTH; --j;) 75512111Sralph *strp++ = BACKGND; 75612111Sralph else 75712111Sralph strp = scnline(scnkey[c][scnhgt-1-d], strp, cc); 75812111Sralph if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1) 75912111Sralph break; 76012111Sralph *strp++ = BACKGND; 76112111Sralph *strp++ = BACKGND; 76212111Sralph } 76312111Sralph while (*--strp == BACKGND && strp >= outbuf) 76412111Sralph ; 76512111Sralph strp++; 76612111Sralph *strp++ = '\n'; 76712111Sralph (void) write(scfd, outbuf, strp-outbuf); 76812111Sralph } 76912111Sralph } 77012111Sralph 77112877Sralph static 77212111Sralph dropit(c) 77312111Sralph char c; 77412111Sralph { 77512111Sralph switch(c) { 77612111Sralph 77712111Sralph case TRC('_'): 77812111Sralph case TRC(';'): 77912111Sralph case TRC(','): 78012111Sralph case TRC('g'): 78112111Sralph case TRC('j'): 78212111Sralph case TRC('p'): 78312111Sralph case TRC('q'): 78412111Sralph case TRC('y'): 78512111Sralph return (DROP); 78612111Sralph 78712111Sralph default: 78812111Sralph return (0); 78912111Sralph } 79012111Sralph } 79112111Sralph 79212111Sralph /* 79312111Sralph * sendmail --- 79412111Sralph * tell people about job completion 79512111Sralph */ 79612877Sralph static 79712111Sralph sendmail(bombed) 79812111Sralph int bombed; 79912111Sralph { 80012111Sralph static int p[2]; 80112111Sralph register int i; 80212111Sralph int stat; 80312111Sralph register char *cp; 80412111Sralph char buf[100]; 80512111Sralph 80612111Sralph pipe(p); 80712111Sralph if ((stat = dofork(DORETURN)) == 0) { /* child */ 80812111Sralph dup2(p[0], 0); 80912111Sralph for (i = 3; i < NOFILE; i++) 81012111Sralph (void) close(i); 81112111Sralph if ((cp = rindex(MAIL, '/')) != NULL) 81212111Sralph cp++; 81312111Sralph else 81412111Sralph cp = MAIL; 81514150Sralph sprintf(buf, "%s@%s", line+1, fromhost); 81612111Sralph execl(MAIL, cp, buf, 0); 81712111Sralph exit(0); 81812111Sralph } else if (stat > 0) { /* parent */ 81912111Sralph dup2(p[1], 1); 82014150Sralph printf("To: %s@%s\n", line+1, fromhost); 82112111Sralph printf("Subject: printer job\n\n"); 82212111Sralph printf("Your printer job "); 82312111Sralph if (*jobname) 82412111Sralph printf("(%s) ", jobname); 82512463Sralph switch (bombed) { 82612463Sralph case 0: 82712463Sralph printf("\ncompleted successfully\n"); 82812463Sralph break; 82912463Sralph default: 83012463Sralph case 1: 83112463Sralph printf("\ncould not be printed\n"); 83212463Sralph break; 83312463Sralph case 2: 83412463Sralph printf("\ncould not be printed without an account on %s\n", host); 83512463Sralph break; 83612463Sralph } 83712111Sralph fflush(stdout); 83812111Sralph (void) close(1); 83912111Sralph } 84012111Sralph (void) close(p[0]); 84112111Sralph (void) close(p[1]); 84212111Sralph wait(&stat); 84312111Sralph } 84412111Sralph 84512111Sralph /* 84612111Sralph * dofork - fork with retries on failure 84712111Sralph */ 84812877Sralph static 84912111Sralph dofork(action) 85012111Sralph int action; 85112111Sralph { 85212111Sralph register int i, pid; 85312111Sralph 85412111Sralph for (i = 0; i < 20; i++) { 85512463Sralph if ((pid = fork()) < 0) { 85612111Sralph sleep((unsigned)(i*i)); 85712463Sralph continue; 85812463Sralph } 85912463Sralph /* 86012463Sralph * Child should run as daemon instead of root 86112463Sralph */ 86212463Sralph if (pid == 0) 86312463Sralph setuid(DU); 86412463Sralph return(pid); 86512111Sralph } 86612111Sralph log("can't fork"); 86712111Sralph 86812111Sralph switch (action) { 86912111Sralph case DORETURN: 87012111Sralph return (-1); 87112111Sralph default: 87212111Sralph log("bad action (%d) to dofork", action); 87312111Sralph /*FALL THRU*/ 87412111Sralph case DOABORT: 87512111Sralph exit(1); 87612111Sralph } 87712111Sralph /*NOTREACHED*/ 87812111Sralph } 87912111Sralph 88012111Sralph /* 88114709Sralph * Cleanup child processes when a signal is caught. 88212111Sralph */ 88312877Sralph static 88412111Sralph onintr() 88512111Sralph { 88612111Sralph kill(0, SIGINT); 88712111Sralph if (ofilter > 0) 88812111Sralph kill(ofilter, SIGCONT); 88912111Sralph while (wait(0) > 0) 89012111Sralph ; 89112111Sralph exit(0); 89212111Sralph } 89312111Sralph 89412877Sralph static 89512111Sralph init() 89612111Sralph { 89712111Sralph int status; 89812111Sralph 89913169Sralph if ((status = pgetent(line, printer)) < 0) 90013169Sralph fatal("can't open printer description file"); 90113169Sralph else if (status == 0) 90213169Sralph fatal("unknown printer"); 90312111Sralph if ((LP = pgetstr("lp", &bp)) == NULL) 90412111Sralph LP = DEFDEVLP; 90512111Sralph if ((RP = pgetstr("rp", &bp)) == NULL) 90612463Sralph RP = DEFLP; 90712111Sralph if ((LO = pgetstr("lo", &bp)) == NULL) 90812111Sralph LO = DEFLOCK; 90912111Sralph if ((ST = pgetstr("st", &bp)) == NULL) 91012111Sralph ST = DEFSTAT; 91112111Sralph if ((LF = pgetstr("lf", &bp)) == NULL) 91212111Sralph LF = DEFLOGF; 91312111Sralph if ((SD = pgetstr("sd", &bp)) == NULL) 91412111Sralph SD = DEFSPOOL; 91512111Sralph if ((DU = pgetnum("du")) < 0) 91612111Sralph DU = DEFUID; 91712111Sralph if ((FF = pgetstr("ff", &bp)) == NULL) 91812111Sralph FF = DEFFF; 91912111Sralph if ((PW = pgetnum("pw")) < 0) 92012111Sralph PW = DEFWIDTH; 92112111Sralph sprintf(&width[2], "%d", PW); 92212111Sralph if ((PL = pgetnum("pl")) < 0) 92312111Sralph PL = DEFLENGTH; 92412111Sralph sprintf(&length[2], "%d", PL); 92512463Sralph if ((PX = pgetnum("px")) < 0) 92612463Sralph PX = 0; 92712463Sralph sprintf(&pxwidth[2], "%d", PX); 92812463Sralph if ((PY = pgetnum("py")) < 0) 92912463Sralph PY = 0; 93012463Sralph sprintf(&pxlength[2], "%d", PY); 93112111Sralph RM = pgetstr("rm", &bp); 93212111Sralph AF = pgetstr("af", &bp); 93312111Sralph OF = pgetstr("of", &bp); 93412111Sralph IF = pgetstr("if", &bp); 93512463Sralph RF = pgetstr("rf", &bp); 93612111Sralph TF = pgetstr("tf", &bp); 93713233Sralph NF = pgetstr("nf", &bp); 93812111Sralph DF = pgetstr("df", &bp); 93912111Sralph GF = pgetstr("gf", &bp); 94012111Sralph VF = pgetstr("vf", &bp); 94112111Sralph CF = pgetstr("cf", &bp); 94212111Sralph TR = pgetstr("tr", &bp); 94312463Sralph RS = pgetflag("rs"); 94412111Sralph SF = pgetflag("sf"); 94512111Sralph SH = pgetflag("sh"); 94612111Sralph SB = pgetflag("sb"); 94712111Sralph RW = pgetflag("rw"); 94812111Sralph BR = pgetnum("br"); 94912111Sralph if ((FC = pgetnum("fc")) < 0) 95012111Sralph FC = 0; 95112111Sralph if ((FS = pgetnum("fs")) < 0) 95212111Sralph FS = 0; 95312111Sralph if ((XC = pgetnum("xc")) < 0) 95412111Sralph XC = 0; 95512111Sralph if ((XS = pgetnum("xs")) < 0) 95612111Sralph XS = 0; 95712581Sralph tof = !pgetflag("fo"); 95812111Sralph } 95912111Sralph 96012463Sralph /* 96112463Sralph * Acquire line printer or remote connection. 96212463Sralph */ 96312877Sralph static 96412463Sralph openpr() 96512463Sralph { 96612463Sralph register int i, n; 96712463Sralph 96812463Sralph if (*LP) { 96912463Sralph for (i = 1; ; i = i < 32 ? i << 1 : i) { 97013148Ssam pfd = open(LP, RW ? O_RDWR : O_WRONLY); 97112463Sralph if (pfd >= 0) 97212463Sralph break; 97312463Sralph if (errno == ENOENT) { 97412463Sralph log("cannot open %s", LP); 97512463Sralph exit(1); 97612463Sralph } 97712463Sralph if (i == 1) 97812463Sralph status("waiting for %s to become ready (offline ?)", printer); 97912463Sralph sleep(i); 98012463Sralph } 98112463Sralph if (isatty(pfd)) 98212463Sralph setty(); 98312463Sralph status("%s is ready and printing", printer); 98412463Sralph } else if (RM != NULL) { 98512463Sralph for (i = 1; ; i = i < 512 ? i << 1 : i) { 98612528Sralph pfd = getport(RM); 98712463Sralph if (pfd >= 0) { 98812463Sralph (void) sprintf(line, "\2%s\n", RP); 98912463Sralph n = strlen(line); 99012463Sralph if (write(pfd, line, n) != n) 99112463Sralph break; 99212463Sralph if (noresponse()) 99312463Sralph (void) close(pfd); 99412463Sralph else 99512463Sralph break; 99612463Sralph } 99712463Sralph if (i == 1) 99812463Sralph status("waiting for %s to come up", RM); 99912463Sralph sleep(i); 100012463Sralph } 100112463Sralph status("sending to %s", RM); 100212463Sralph remote = 1; 100312463Sralph } else { 100412463Sralph log("no line printer device or remote machine name"); 100512463Sralph exit(1); 100612463Sralph } 100712463Sralph /* 100812463Sralph * Start up an output filter, if needed. 100912463Sralph */ 101012463Sralph if (OF) { 101112463Sralph int p[2]; 101212463Sralph char *cp; 101312463Sralph 101412463Sralph pipe(p); 101512463Sralph if ((ofilter = dofork(DOABORT)) == 0) { /* child */ 101612463Sralph dup2(p[0], 0); /* pipe is std in */ 101712463Sralph dup2(pfd, 1); /* printer is std out */ 101812463Sralph for (i = 3; i < NOFILE; i++) 101912463Sralph (void) close(i); 102012463Sralph if ((cp = rindex(OF, '/')) == NULL) 102112463Sralph cp = OF; 102212463Sralph else 102312463Sralph cp++; 102412463Sralph execl(OF, cp, width, length, 0); 102512463Sralph log("can't execl output filter %s", OF); 102612463Sralph exit(1); 102712463Sralph } 102812463Sralph (void) close(p[0]); /* close input side */ 102912463Sralph ofd = p[1]; /* use pipe for output */ 103012463Sralph } else { 103112463Sralph ofd = pfd; 103212463Sralph ofilter = 0; 103312463Sralph } 103412463Sralph } 103512463Sralph 103612111Sralph struct bauds { 103712111Sralph int baud; 103812111Sralph int speed; 103912111Sralph } bauds[] = { 104012111Sralph 50, B50, 104112111Sralph 75, B75, 104212111Sralph 110, B110, 104312111Sralph 134, B134, 104412111Sralph 150, B150, 104512111Sralph 200, B200, 104612111Sralph 300, B300, 104712111Sralph 600, B600, 104812111Sralph 1200, B1200, 104912111Sralph 1800, B1800, 105012111Sralph 2400, B2400, 105112111Sralph 4800, B4800, 105212111Sralph 9600, B9600, 105312111Sralph 19200, EXTA, 105412111Sralph 38400, EXTB, 105512111Sralph 0, 0 105612111Sralph }; 105712111Sralph 105812111Sralph /* 105912111Sralph * setup tty lines. 106012111Sralph */ 106112877Sralph static 106212111Sralph setty() 106312111Sralph { 106412111Sralph struct sgttyb ttybuf; 106512111Sralph register struct bauds *bp; 106612111Sralph 106712111Sralph if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) { 106812111Sralph log("cannot set exclusive-use"); 106912111Sralph exit(1); 107012111Sralph } 107112111Sralph if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) { 107212111Sralph log("cannot get tty parameters"); 107312111Sralph exit(1); 107412111Sralph } 107512111Sralph if (BR > 0) { 107612111Sralph for (bp = bauds; bp->baud; bp++) 107712111Sralph if (BR == bp->baud) 107812111Sralph break; 107912111Sralph if (!bp->baud) { 108012111Sralph log("illegal baud rate %d", BR); 108112111Sralph exit(1); 108212111Sralph } 108312111Sralph ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed; 108412111Sralph } 108513169Sralph ttybuf.sg_flags &= ~FC; 108613169Sralph ttybuf.sg_flags |= FS; 108712111Sralph if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) { 108812111Sralph log("cannot set tty parameters"); 108912111Sralph exit(1); 109012111Sralph } 109112111Sralph if (XC) { 109212111Sralph if (ioctl(pfd, TIOCLBIC, &XC) < 0) { 109312111Sralph log("cannot set local tty parameters"); 109412111Sralph exit(1); 109512111Sralph } 109612111Sralph } 109712111Sralph if (XS) { 109812111Sralph if (ioctl(pfd, TIOCLBIS, &XS) < 0) { 109912111Sralph log("cannot set local tty parameters"); 110012111Sralph exit(1); 110112111Sralph } 110212111Sralph } 110312111Sralph } 110412463Sralph 110512463Sralph /*VARARGS1*/ 110612463Sralph static 110712463Sralph status(msg, a1, a2, a3) 110812463Sralph char *msg; 110912463Sralph { 111012463Sralph register int fd; 111112463Sralph char buf[BUFSIZ]; 111212463Sralph 111312463Sralph umask(0); 111413148Ssam fd = open(ST, O_WRONLY|O_CREAT, 0664); 111513148Ssam if (fd < 0 || flock(fd, LOCK_EX) < 0) 111612463Sralph fatal("cannot create status file"); 111713148Ssam ftruncate(fd, 0); 111812463Sralph sprintf(buf, msg, a1, a2, a3); 111912463Sralph strcat(buf, "\n"); 112012463Sralph (void) write(fd, buf, strlen(buf)); 112112463Sralph (void) close(fd); 112212463Sralph } 1123