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