1*13169Sralph /* printjob.c 4.8 83/06/17 */ 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 */ 63*13169Sralph lfd = open(LO, O_WRONLY|O_CREAT|O_TRUNC, 0644); 64*13169Sralph if (lfd < 0) { 65*13169Sralph log("cannot create %s", LO); 66*13169Sralph exit(1); 67*13169Sralph } 68*13169Sralph if (flock(lfd, LOCK_EX|LOCK_NB) < 0) { 6912111Sralph if (errno == EWOULDBLOCK) /* active deamon present */ 7012111Sralph exit(0); 71*13169Sralph 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); 93*13169Sralph if (stb.st_mode & 01) { /* reset queue flag */ 94*13169Sralph if (fchmod(lfd, stb.st_mode & 0776) < 0) 95*13169Sralph log("cannot chmod %s", LO); 96*13169Sralph } 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 /* 119*13169Sralph * Check to see if we are supposed to stop printing or 120*13169Sralph * if we are to rebuild the queue. 12112463Sralph */ 122*13169Sralph if (fstat(lfd, &stb) == 0) { 123*13169Sralph if (stb.st_mode & 0100) 124*13169Sralph goto done; 125*13169Sralph if (stb.st_mode & 01) { 126*13169Sralph for (free((char *) q); nitems--; free((char *) q)) 127*13169Sralph q = *qp++; 128*13169Sralph if (fchmod(lfd, stb.st_mode & 0776) < 0) 129*13169Sralph log("cannot chmod %s", LO); 130*13169Sralph break; 131*13169Sralph } 132*13169Sralph } 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 22512111Sralph * d -- "file name" dvi file to print 22612111Sralph * g -- "file name" plot(1G) file to print 22712111Sralph * v -- "file name" plain raster file to print 22812111Sralph * c -- "file name" cifplot file to print 22912111Sralph * 1 -- "R font file" for troff 23012111Sralph * 2 -- "I font file" for troff 23112111Sralph * 3 -- "B font file" for troff 23212111Sralph * 4 -- "S font file" for troff 23312111Sralph * N -- "name" of file (used by lpq) 23412111Sralph * U -- "unlink" name of file to remove 23512111Sralph * (after we print it. (Pass 2 only)). 23612111Sralph * M -- "mail" to user when done printing 23712111Sralph * 23812111Sralph * getline reads a line and expands tabs to blanks 23912111Sralph */ 24012111Sralph 24112111Sralph /* pass 1 */ 24212111Sralph 24312111Sralph while (getline(cfp)) 24412111Sralph switch (line[0]) { 24512111Sralph case 'H': 24612111Sralph strcpy(host, line+1); 24712111Sralph if (class[0] == '\0') 24812111Sralph strcpy(class, line+1); 24912111Sralph continue; 25012111Sralph 25112111Sralph case 'P': 25212111Sralph strcpy(logname, line+1); 25312463Sralph if (RS) { /* restricted */ 25412463Sralph if (getpwnam(logname) == (struct passwd *)0) { 25512463Sralph bombed = 2; 25612463Sralph sendmail(bombed); 25712463Sralph goto pass2; 25812463Sralph } 25912463Sralph } 26012111Sralph continue; 26112111Sralph 26212111Sralph case 'J': 26312111Sralph if (line[1] != '\0') 26412111Sralph strcpy(jobname, line+1); 26512111Sralph else 26612111Sralph strcpy(jobname, " "); 26712111Sralph continue; 26812111Sralph 26912111Sralph case 'C': 27012111Sralph if (line[1] != '\0') 27112111Sralph strcpy(class, line+1); 27212111Sralph else if (class[0] == '\0') 27312111Sralph gethostname(class, sizeof (class)); 27412111Sralph continue; 27512111Sralph 27612111Sralph case 'T': /* header title for pr */ 27712111Sralph strcpy(title, line+1); 27812111Sralph continue; 27912111Sralph 28012111Sralph case 'L': /* identification line */ 28112111Sralph if (!SH) 28212111Sralph banner(line+1, jobname); 28312111Sralph continue; 28412111Sralph 28512111Sralph case '1': /* troff fonts */ 28612111Sralph case '2': 28712111Sralph case '3': 28812111Sralph case '4': 28912111Sralph if (line[1] != '\0') 29012111Sralph strcpy(fonts[line[0]-'1'], line+1); 29112111Sralph continue; 29212111Sralph 29312111Sralph case 'W': /* page width */ 29412111Sralph strcpy(width+2, line+1); 29512111Sralph continue; 29612111Sralph 29712581Sralph case 'I': /* indent amount */ 29812581Sralph strcpy(indent+2, line+1); 29912581Sralph continue; 30012581Sralph 30112111Sralph default: /* some file to print */ 30212111Sralph if ((i = print(line[0], line+1)) > 0) { 30312111Sralph (void) fclose(cfp); 30412111Sralph return(1); 30512111Sralph } else if (i < 0) 30612111Sralph bombed = 1; 30712111Sralph title[0] = '\0'; 30812111Sralph continue; 30912111Sralph 31012111Sralph case 'N': 31112111Sralph case 'U': 31212111Sralph case 'M': 31312111Sralph continue; 31412111Sralph } 31512111Sralph 31612111Sralph /* pass 2 */ 31712111Sralph 31812463Sralph pass2: 31912111Sralph fseek(cfp, 0L, 0); 32012111Sralph while (getline(cfp)) 32112111Sralph switch (line[0]) { 32212111Sralph case 'M': 32312463Sralph if (bombed != 2) /* already sent if 2 */ 32412463Sralph sendmail(bombed); 32512111Sralph continue; 32612111Sralph 32712111Sralph case 'U': 32812111Sralph (void) unlink(line+1); 32912111Sralph } 33012111Sralph /* 33112111Sralph * clean-up incase another control file exists 33212111Sralph */ 33312111Sralph (void) fclose(cfp); 33412111Sralph (void) unlink(file); 33512111Sralph return(0); 33612111Sralph } 33712111Sralph 33812111Sralph /* 33912111Sralph * Print a file. 34012111Sralph * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, TF, CF, VF}. 34112111Sralph * Return -1 if a non-recoverable error occured, 1 if a recoverable error and 34212111Sralph * 0 if all is well. 34312111Sralph * Note: all filters take stdin as the file, stdout as the printer, 34412111Sralph * stderr as the log file, and must not ignore SIGINT. 34512111Sralph */ 34612877Sralph static 34712111Sralph print(format, file) 34812111Sralph int format; 34912111Sralph char *file; 35012111Sralph { 35112111Sralph register int n, fi, fo; 35212111Sralph register char *prog; 35312111Sralph char *av[15], buf[BUFSIZ]; 35412111Sralph int pid, p[2], stopped = 0; 35512111Sralph union wait status; 35612111Sralph 35713148Ssam if ((fi = open(file, O_RDONLY)) < 0) { 35812111Sralph log("%s: open failure <errno = %d>", file, errno); 35912111Sralph return(-1); 36012111Sralph } 36112111Sralph if (!SF && !tof) { /* start on a fresh page */ 36212111Sralph (void) write(ofd, FF, strlen(FF)); 36312111Sralph tof = 1; 36412111Sralph } 36512111Sralph if (IF == NULL && (format == 'f' || format == 'l')) { 36612111Sralph tof = 0; 36712111Sralph while ((n = read(fi, buf, BUFSIZ)) > 0) 36812111Sralph if (write(ofd, buf, n) != n) { 36912111Sralph (void) close(fi); 37012111Sralph return(1); 37112111Sralph } 37212111Sralph (void) close(fi); 37312111Sralph return(0); 37412111Sralph } 37512111Sralph switch (format) { 37612111Sralph case 'p': /* print file using 'pr' */ 37712111Sralph if (IF == NULL) { /* use output filter */ 37812111Sralph prog = PR; 37912111Sralph av[0] = "pr"; 38012111Sralph av[1] = width; 38112111Sralph av[2] = length; 38212111Sralph av[3] = "-h"; 38312111Sralph av[4] = *title ? title : " "; 38412111Sralph av[5] = 0; 38512111Sralph fo = ofd; 38612111Sralph goto start; 38712111Sralph } 38812111Sralph pipe(p); 38912111Sralph if ((prchild = dofork(DORETURN)) == 0) { /* child */ 39012111Sralph dup2(fi, 0); /* file is stdin */ 39112111Sralph dup2(p[1], 1); /* pipe is stdout */ 39212111Sralph for (n = 3; n < NOFILE; n++) 39312111Sralph (void) close(n); 39412111Sralph execl(PR, "pr", width, length, "-h", *title ? title : " ", 0); 39512111Sralph log("cannot execl %s", PR); 39612111Sralph exit(2); 39712111Sralph } 39812111Sralph (void) close(p[1]); /* close output side */ 39912111Sralph (void) close(fi); 40012111Sralph if (prchild < 0) { 40112111Sralph prchild = 0; 40212111Sralph (void) close(p[0]); 40312111Sralph return(-1); 40412111Sralph } 40512111Sralph fi = p[0]; /* use pipe for input */ 40612111Sralph case 'f': /* print plain text file */ 40712111Sralph prog = IF; 40812111Sralph av[1] = width; 40912111Sralph av[2] = length; 41012581Sralph av[3] = indent; 41112581Sralph n = 4; 41212111Sralph break; 41312111Sralph case 'l': /* like 'f' but pass control characters */ 41412111Sralph prog = IF; 41512111Sralph av[1] = "-l"; 41612111Sralph av[2] = width; 41712111Sralph av[3] = length; 41812581Sralph av[4] = indent; 41912581Sralph n = 5; 42012111Sralph break; 42112463Sralph case 'r': /* print a fortran text file */ 42212463Sralph prog = RF; 42312463Sralph av[1] = width; 42412463Sralph av[2] = length; 42512463Sralph n = 3; 42612463Sralph break; 42712111Sralph case 't': /* print troff output */ 42812463Sralph case 'd': /* print tex output */ 42912111Sralph (void) unlink(".railmag"); 43012463Sralph if ((fo = creat(".railmag", FILMOD)) < 0) { 43112111Sralph log("cannot create .railmag"); 43212111Sralph (void) unlink(".railmag"); 43312111Sralph } else { 43412111Sralph for (n = 0; n < 4; n++) { 43512111Sralph if (fonts[n][0] != '/') 43612111Sralph (void) write(fo, "/usr/lib/vfont/", 15); 43712111Sralph (void) write(fo, fonts[n], strlen(fonts[n])); 43812111Sralph (void) write(fo, "\n", 1); 43912111Sralph } 44012111Sralph (void) close(fo); 44112111Sralph } 44212111Sralph prog = (format == 't') ? TF : DF; 44312463Sralph av[1] = pxwidth; 44412463Sralph av[2] = pxlength; 44512463Sralph n = 3; 44612111Sralph break; 44712111Sralph case 'c': /* print cifplot output */ 44812111Sralph prog = CF; 44912463Sralph av[1] = pxwidth; 45012463Sralph av[2] = pxlength; 45112463Sralph n = 3; 45212111Sralph break; 45312111Sralph case 'g': /* print plot(1G) output */ 45412111Sralph prog = GF; 45512463Sralph av[1] = pxwidth; 45612463Sralph av[2] = pxlength; 45712463Sralph n = 3; 45812111Sralph break; 45912111Sralph case 'v': /* print raster output */ 46012111Sralph prog = VF; 46112463Sralph av[1] = pxwidth; 46212463Sralph av[2] = pxlength; 46312463Sralph n = 3; 46412111Sralph break; 46512111Sralph default: 46612111Sralph (void) close(fi); 46712111Sralph log("illegal format character '%c'", format); 46812111Sralph return(-1); 46912111Sralph } 47012111Sralph if ((av[0] = rindex(prog, '/')) != NULL) 47112111Sralph av[0]++; 47212111Sralph else 47312111Sralph av[0] = prog; 47412111Sralph av[n++] = "-n"; 47512111Sralph av[n++] = logname; 47612111Sralph av[n++] = "-h"; 47712111Sralph av[n++] = host; 47812111Sralph av[n++] = AF; 47912111Sralph av[n] = 0; 48012111Sralph fo = pfd; 48112111Sralph if (ofilter > 0) { /* stop output filter */ 48212111Sralph write(ofd, "\031\1", 2); 48312111Sralph while ((pid = wait3(&status, WUNTRACED, 0)) > 0 && pid != ofilter) 48412111Sralph ; 48512111Sralph if (status.w_stopval != WSTOPPED) { 48612111Sralph (void) close(fi); 48712111Sralph log("output filter died (%d)", status.w_retcode); 48812111Sralph return(1); 48912111Sralph } 49012111Sralph stopped++; 49112111Sralph } 49212111Sralph start: 49312111Sralph if ((child = dofork(DORETURN)) == 0) { /* child */ 49412111Sralph dup2(fi, 0); 49512111Sralph dup2(fo, 1); 49612111Sralph for (n = 3; n < NOFILE; n++) 49712111Sralph (void) close(n); 49812111Sralph execv(prog, av); 49912111Sralph log("cannot execl %s", prog); 50012111Sralph exit(2); 50112111Sralph } 50212111Sralph (void) close(fi); 50312111Sralph if (child < 0) 50412111Sralph status.w_retcode = 100; 50512111Sralph else 50612111Sralph while ((pid = wait(&status)) > 0 && pid != child) 50712111Sralph ; 50812111Sralph child = 0; 50912111Sralph prchild = 0; 51012111Sralph if (stopped) { /* restart output filter */ 51112111Sralph if (kill(ofilter, SIGCONT) < 0) { 51212111Sralph log("cannot restart output filter"); 51312111Sralph exit(1); 51412111Sralph } 51512111Sralph } 51612111Sralph tof = 0; 51712111Sralph if (!WIFEXITED(status) || status.w_retcode > 1) { 51812111Sralph log("Daemon Filter '%c' Malfunction (%d)", format, status.w_retcode); 51912111Sralph return(-1); 52012111Sralph } else if (status.w_retcode == 1) 52112111Sralph return(1); 52212111Sralph tof = 1; 52312111Sralph return(0); 52412111Sralph } 52512111Sralph 52612111Sralph /* 52712111Sralph * Send the daemon control file (cf) and any data files. 52812111Sralph * Return -1 if a non-recoverable error occured, 1 if a recoverable error and 52912111Sralph * 0 if all is well. 53012111Sralph */ 53112877Sralph static 53212111Sralph sendit(file) 53312111Sralph char *file; 53412111Sralph { 53512111Sralph register int linelen, err = 0; 53612111Sralph char last[132]; 53712111Sralph 53812111Sralph /* 53912111Sralph * open control file 54012111Sralph */ 54112111Sralph if ((cfp = fopen(file, "r")) == NULL) { 54212111Sralph log("control file (%s) open failure <errno = %d>", file, errno); 54312111Sralph return(0); 54412111Sralph } 54512111Sralph /* 54612111Sralph * read the control file for work to do 54712111Sralph * 54812111Sralph * file format -- first character in the line is a command 54912111Sralph * rest of the line is the argument. 55012111Sralph * commands of interest are: 55112111Sralph * 55212111Sralph * a-z -- "file name" name of file to print 55312111Sralph * U -- "unlink" name of file to remove 55412111Sralph * (after we print it. (Pass 2 only)). 55512111Sralph */ 55612111Sralph 55712111Sralph /* 55812111Sralph * pass 1 55912111Sralph */ 56012111Sralph while (getline(cfp)) { 56112111Sralph again: 56212111Sralph if (line[0] >= 'a' && line[0] <= 'z') { 56312111Sralph strcpy(last, line); 56412111Sralph while (linelen = getline(cfp)) 56512111Sralph if (strcmp(last, line)) 56612111Sralph break; 56712111Sralph if ((err = sendfile('\3', last+1)) > 0) { 56812111Sralph (void) fclose(cfp); 56912111Sralph return(1); 57012111Sralph } else if (err) 57112111Sralph break; 57212111Sralph if (linelen) 57312111Sralph goto again; 57412111Sralph break; 57512111Sralph } 57612111Sralph } 57712111Sralph if (!err && sendfile('\2', file) > 0) { 57812111Sralph (void) fclose(cfp); 57912111Sralph return(1); 58012111Sralph } 58112111Sralph /* 58212111Sralph * pass 2 58312111Sralph */ 58412111Sralph fseek(cfp, 0L, 0); 58512111Sralph while (getline(cfp)) 58612111Sralph if (line[0] == 'U') 58712111Sralph (void) unlink(line+1); 58812111Sralph /* 58912111Sralph * clean-up incase another control file exists 59012111Sralph */ 59112111Sralph (void) fclose(cfp); 59212111Sralph (void) unlink(file); 59312111Sralph return(0); 59412111Sralph } 59512111Sralph 59612111Sralph /* 59712111Sralph * Send a data file to the remote machine and spool it. 59812111Sralph * Return positive if we should try resending. 59912111Sralph */ 60012877Sralph static 60112111Sralph sendfile(type, file) 60212111Sralph char type, *file; 60312111Sralph { 60412111Sralph register int f, i, amt; 60512111Sralph struct stat stb; 60612111Sralph char buf[BUFSIZ]; 60712111Sralph int sizerr; 60812111Sralph 60913148Ssam if ((f = open(file, O_RDONLY)) < 0 || fstat(f, &stb) < 0) { 61012111Sralph log("file (%s) open failure <errno = %d>", file, errno); 61112111Sralph return(-1); 61212111Sralph } 61312111Sralph (void) sprintf(buf, "%c%d %s\n", type, stb.st_size, file); 61412111Sralph amt = strlen(buf); 61512692Sralph if (write(pfd, buf, amt) != amt) { 61612692Sralph (void) close(f); 61712111Sralph return(1); 61812692Sralph } 61912692Sralph if (noresponse()) { 62012692Sralph (void) close(f); 62112111Sralph return(1); 62212692Sralph } 62312111Sralph sizerr = 0; 62412111Sralph for (i = 0; i < stb.st_size; i += BUFSIZ) { 62512111Sralph amt = BUFSIZ; 62612111Sralph if (i + amt > stb.st_size) 62712111Sralph amt = stb.st_size - i; 62812111Sralph if (sizerr == 0 && read(f, buf, amt) != amt) 62912111Sralph sizerr = 1; 63012692Sralph if (write(pfd, buf, amt) != amt) { 63112692Sralph (void) close(f); 63212111Sralph return(1); 63312692Sralph } 63412111Sralph } 63512111Sralph (void) close(f); 63612111Sralph if (sizerr) { 63712111Sralph log("%s: changed size", file); 63812111Sralph (void) write(pfd, "\1", 1); /* tell recvjob to ignore this file */ 63912111Sralph return(-1); 64012111Sralph } 64112111Sralph if (write(pfd, "", 1) != 1) 64212111Sralph return(1); 64312111Sralph if (noresponse()) 64412111Sralph return(1); 64512111Sralph return(0); 64612111Sralph } 64712111Sralph 64812111Sralph /* 64912111Sralph * Check to make sure there have been no errors and that both programs 65012111Sralph * are in sync with eachother. 65112111Sralph * Return non-zero if the connection was lost. 65212111Sralph */ 65312111Sralph static 65412111Sralph noresponse() 65512111Sralph { 65612111Sralph char resp; 65712111Sralph 65812111Sralph if (read(pfd, &resp, 1) != 1 || resp != '\0') { 65912111Sralph log("lost connection or error in recvjob"); 66012111Sralph return(1); 66112111Sralph } 66212111Sralph return(0); 66312111Sralph } 66412111Sralph 66512111Sralph /* 66612111Sralph * Banner printing stuff 66712111Sralph */ 66812877Sralph static 66912111Sralph banner(name1, name2) 67012111Sralph char *name1, *name2; 67112111Sralph { 67212111Sralph time_t tvec; 67312111Sralph extern char *ctime(); 67412111Sralph 67512111Sralph time(&tvec); 67612111Sralph if (!SF && !tof) 67712111Sralph (void) write(ofd, FF, strlen(FF)); 67812111Sralph if (SB) { /* short banner only */ 67912111Sralph if (class[0]) { 68012111Sralph (void) write(ofd, class, strlen(class)); 68112111Sralph (void) write(ofd, ":", 1); 68212111Sralph } 68312111Sralph (void) write(ofd, name1, strlen(name1)); 68412111Sralph (void) write(ofd, " Job: ", 7); 68512111Sralph (void) write(ofd, name2, strlen(name2)); 68612111Sralph (void) write(ofd, " Date: ", 8); 68712111Sralph (void) write(ofd, ctime(&tvec), 24); 68812111Sralph (void) write(ofd, "\n", 1); 68912111Sralph } else { /* normal banner */ 69012111Sralph (void) write(ofd, "\n\n\n", 3); 69112111Sralph scan_out(ofd, name1, '\0'); 69212111Sralph (void) write(ofd, "\n\n", 2); 69312111Sralph scan_out(ofd, name2, '\0'); 69412111Sralph if (class[0]) { 69512111Sralph (void) write(ofd,"\n\n\n",3); 69612111Sralph scan_out(ofd, class, '\0'); 69712111Sralph } 69812111Sralph (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15); 69912111Sralph (void) write(ofd, name2, strlen(name2)); 70012111Sralph (void) write(ofd, "\n\t\t\t\t\tDate: ", 12); 70112111Sralph (void) write(ofd, ctime(&tvec), 24); 70212111Sralph (void) write(ofd, "\n", 1); 70312111Sralph } 70412111Sralph if (!SF) 70512111Sralph (void) write(ofd, FF, strlen(FF)); 70612111Sralph tof = 1; 70712111Sralph } 70812111Sralph 70912877Sralph static char * 71012111Sralph scnline(key, p, c) 71112111Sralph register char key, *p; 71212111Sralph char c; 71312111Sralph { 71412111Sralph register scnwidth; 71512111Sralph 71612111Sralph for (scnwidth = WIDTH; --scnwidth;) { 71712111Sralph key <<= 1; 71812111Sralph *p++ = key & 0200 ? c : BACKGND; 71912111Sralph } 72012111Sralph return (p); 72112111Sralph } 72212111Sralph 72312111Sralph #define TRC(q) (((q)-' ')&0177) 72412111Sralph 72512877Sralph static 72612111Sralph scan_out(scfd, scsp, dlm) 72712111Sralph int scfd; 72812111Sralph char *scsp, dlm; 72912111Sralph { 73012111Sralph register char *strp; 73112111Sralph register nchrs, j; 73212111Sralph char outbuf[LINELEN+1], *sp, c, cc; 73312111Sralph int d, scnhgt; 73412111Sralph extern char scnkey[][HEIGHT]; /* in lpdchar.c */ 73512111Sralph 73612111Sralph for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) { 73712111Sralph strp = &outbuf[0]; 73812111Sralph sp = scsp; 73912111Sralph for (nchrs = 0; ; ) { 74012111Sralph d = dropit(c = TRC(cc = *sp++)); 74112111Sralph if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d)) 74212111Sralph for (j = WIDTH; --j;) 74312111Sralph *strp++ = BACKGND; 74412111Sralph else 74512111Sralph strp = scnline(scnkey[c][scnhgt-1-d], strp, cc); 74612111Sralph if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1) 74712111Sralph break; 74812111Sralph *strp++ = BACKGND; 74912111Sralph *strp++ = BACKGND; 75012111Sralph } 75112111Sralph while (*--strp == BACKGND && strp >= outbuf) 75212111Sralph ; 75312111Sralph strp++; 75412111Sralph *strp++ = '\n'; 75512111Sralph (void) write(scfd, outbuf, strp-outbuf); 75612111Sralph } 75712111Sralph } 75812111Sralph 75912877Sralph static 76012111Sralph dropit(c) 76112111Sralph char c; 76212111Sralph { 76312111Sralph switch(c) { 76412111Sralph 76512111Sralph case TRC('_'): 76612111Sralph case TRC(';'): 76712111Sralph case TRC(','): 76812111Sralph case TRC('g'): 76912111Sralph case TRC('j'): 77012111Sralph case TRC('p'): 77112111Sralph case TRC('q'): 77212111Sralph case TRC('y'): 77312111Sralph return (DROP); 77412111Sralph 77512111Sralph default: 77612111Sralph return (0); 77712111Sralph } 77812111Sralph } 77912111Sralph 78012111Sralph /* 78112111Sralph * sendmail --- 78212111Sralph * tell people about job completion 78312111Sralph */ 78412877Sralph static 78512111Sralph sendmail(bombed) 78612111Sralph int bombed; 78712111Sralph { 78812111Sralph static int p[2]; 78912111Sralph register int i; 79012111Sralph int stat; 79112111Sralph register char *cp; 79212111Sralph char buf[100]; 79312111Sralph 79412111Sralph pipe(p); 79512111Sralph if ((stat = dofork(DORETURN)) == 0) { /* child */ 79612111Sralph dup2(p[0], 0); 79712111Sralph for (i = 3; i < NOFILE; i++) 79812111Sralph (void) close(i); 79912111Sralph if ((cp = rindex(MAIL, '/')) != NULL) 80012111Sralph cp++; 80112111Sralph else 80212111Sralph cp = MAIL; 80312111Sralph sprintf(buf, "%s@%s", line+1, host); 80412111Sralph execl(MAIL, cp, buf, 0); 80512111Sralph exit(0); 80612111Sralph } else if (stat > 0) { /* parent */ 80712111Sralph dup2(p[1], 1); 80812111Sralph printf("To: %s\n", line+1); 80912111Sralph printf("Subject: printer job\n\n"); 81012111Sralph printf("Your printer job "); 81112111Sralph if (*jobname) 81212111Sralph printf("(%s) ", jobname); 81312463Sralph switch (bombed) { 81412463Sralph case 0: 81512463Sralph printf("\ncompleted successfully\n"); 81612463Sralph break; 81712463Sralph default: 81812463Sralph case 1: 81912463Sralph printf("\ncould not be printed\n"); 82012463Sralph break; 82112463Sralph case 2: 82212463Sralph printf("\ncould not be printed without an account on %s\n", host); 82312463Sralph break; 82412463Sralph } 82512111Sralph fflush(stdout); 82612111Sralph (void) close(1); 82712111Sralph } 82812111Sralph (void) close(p[0]); 82912111Sralph (void) close(p[1]); 83012111Sralph wait(&stat); 83112111Sralph } 83212111Sralph 83312111Sralph /* 83412111Sralph * dofork - fork with retries on failure 83512111Sralph */ 83612877Sralph static 83712111Sralph dofork(action) 83812111Sralph int action; 83912111Sralph { 84012111Sralph register int i, pid; 84112111Sralph 84212111Sralph for (i = 0; i < 20; i++) { 84312463Sralph if ((pid = fork()) < 0) { 84412111Sralph sleep((unsigned)(i*i)); 84512463Sralph continue; 84612463Sralph } 84712463Sralph /* 84812463Sralph * Child should run as daemon instead of root 84912463Sralph */ 85012463Sralph if (pid == 0) 85112463Sralph setuid(DU); 85212463Sralph return(pid); 85312111Sralph } 85412111Sralph log("can't fork"); 85512111Sralph 85612111Sralph switch (action) { 85712111Sralph case DORETURN: 85812111Sralph return (-1); 85912111Sralph default: 86012111Sralph log("bad action (%d) to dofork", action); 86112111Sralph /*FALL THRU*/ 86212111Sralph case DOABORT: 86312111Sralph exit(1); 86412111Sralph } 86512111Sralph /*NOTREACHED*/ 86612111Sralph } 86712111Sralph 86812111Sralph /* 86912111Sralph * Cleanup child processes when a SIGINT is caught. 87012111Sralph */ 87112877Sralph static 87212111Sralph onintr() 87312111Sralph { 87412111Sralph kill(0, SIGINT); 87512111Sralph if (ofilter > 0) 87612111Sralph kill(ofilter, SIGCONT); 87712111Sralph while (wait(0) > 0) 87812111Sralph ; 87912111Sralph exit(0); 88012111Sralph } 88112111Sralph 88212877Sralph static 88312111Sralph init() 88412111Sralph { 88512111Sralph int status; 88612111Sralph 887*13169Sralph if ((status = pgetent(line, printer)) < 0) 888*13169Sralph fatal("can't open printer description file"); 889*13169Sralph else if (status == 0) 890*13169Sralph fatal("unknown printer"); 89112111Sralph if ((LP = pgetstr("lp", &bp)) == NULL) 89212111Sralph LP = DEFDEVLP; 89312111Sralph if ((RP = pgetstr("rp", &bp)) == NULL) 89412463Sralph RP = DEFLP; 89512111Sralph if ((LO = pgetstr("lo", &bp)) == NULL) 89612111Sralph LO = DEFLOCK; 89712111Sralph if ((ST = pgetstr("st", &bp)) == NULL) 89812111Sralph ST = DEFSTAT; 89912111Sralph if ((LF = pgetstr("lf", &bp)) == NULL) 90012111Sralph LF = DEFLOGF; 90112111Sralph if ((SD = pgetstr("sd", &bp)) == NULL) 90212111Sralph SD = DEFSPOOL; 90312111Sralph if ((DU = pgetnum("du")) < 0) 90412111Sralph DU = DEFUID; 90512111Sralph if ((FF = pgetstr("ff", &bp)) == NULL) 90612111Sralph FF = DEFFF; 90712111Sralph if ((PW = pgetnum("pw")) < 0) 90812111Sralph PW = DEFWIDTH; 90912111Sralph sprintf(&width[2], "%d", PW); 91012111Sralph if ((PL = pgetnum("pl")) < 0) 91112111Sralph PL = DEFLENGTH; 91212111Sralph sprintf(&length[2], "%d", PL); 91312463Sralph if ((PX = pgetnum("px")) < 0) 91412463Sralph PX = 0; 91512463Sralph sprintf(&pxwidth[2], "%d", PX); 91612463Sralph if ((PY = pgetnum("py")) < 0) 91712463Sralph PY = 0; 91812463Sralph sprintf(&pxlength[2], "%d", PY); 91912111Sralph RM = pgetstr("rm", &bp); 92012111Sralph AF = pgetstr("af", &bp); 92112111Sralph OF = pgetstr("of", &bp); 92212111Sralph IF = pgetstr("if", &bp); 92312463Sralph RF = pgetstr("rf", &bp); 92412111Sralph TF = pgetstr("tf", &bp); 92512111Sralph DF = pgetstr("df", &bp); 92612111Sralph GF = pgetstr("gf", &bp); 92712111Sralph VF = pgetstr("vf", &bp); 92812111Sralph CF = pgetstr("cf", &bp); 92912111Sralph TR = pgetstr("tr", &bp); 93012463Sralph RS = pgetflag("rs"); 93112111Sralph SF = pgetflag("sf"); 93212111Sralph SH = pgetflag("sh"); 93312111Sralph SB = pgetflag("sb"); 93412111Sralph RW = pgetflag("rw"); 93512111Sralph BR = pgetnum("br"); 93612111Sralph if ((FC = pgetnum("fc")) < 0) 93712111Sralph FC = 0; 93812111Sralph if ((FS = pgetnum("fs")) < 0) 93912111Sralph FS = 0; 94012111Sralph if ((XC = pgetnum("xc")) < 0) 94112111Sralph XC = 0; 94212111Sralph if ((XS = pgetnum("xs")) < 0) 94312111Sralph XS = 0; 94412581Sralph tof = !pgetflag("fo"); 94512111Sralph } 94612111Sralph 94712463Sralph /* 94812463Sralph * Acquire line printer or remote connection. 94912463Sralph */ 95012877Sralph static 95112463Sralph openpr() 95212463Sralph { 95312463Sralph register int i, n; 95412463Sralph 95512463Sralph if (*LP) { 95612463Sralph for (i = 1; ; i = i < 32 ? i << 1 : i) { 95713148Ssam pfd = open(LP, RW ? O_RDWR : O_WRONLY); 95812463Sralph if (pfd >= 0) 95912463Sralph break; 96012463Sralph if (errno == ENOENT) { 96112463Sralph log("cannot open %s", LP); 96212463Sralph exit(1); 96312463Sralph } 96412463Sralph if (i == 1) 96512463Sralph status("waiting for %s to become ready (offline ?)", printer); 96612463Sralph sleep(i); 96712463Sralph } 96812463Sralph if (isatty(pfd)) 96912463Sralph setty(); 97012463Sralph status("%s is ready and printing", printer); 97112463Sralph } else if (RM != NULL) { 97212463Sralph for (i = 1; ; i = i < 512 ? i << 1 : i) { 97312528Sralph pfd = getport(RM); 97412463Sralph if (pfd >= 0) { 97512463Sralph (void) sprintf(line, "\2%s\n", RP); 97612463Sralph n = strlen(line); 97712463Sralph if (write(pfd, line, n) != n) 97812463Sralph break; 97912463Sralph if (noresponse()) 98012463Sralph (void) close(pfd); 98112463Sralph else 98212463Sralph break; 98312463Sralph } 98412463Sralph if (i == 1) 98512463Sralph status("waiting for %s to come up", RM); 98612463Sralph sleep(i); 98712463Sralph } 98812463Sralph status("sending to %s", RM); 98912463Sralph remote = 1; 99012463Sralph } else { 99112463Sralph log("no line printer device or remote machine name"); 99212463Sralph exit(1); 99312463Sralph } 99412463Sralph /* 99512463Sralph * Start up an output filter, if needed. 99612463Sralph */ 99712463Sralph if (OF) { 99812463Sralph int p[2]; 99912463Sralph char *cp; 100012463Sralph 100112463Sralph pipe(p); 100212463Sralph if ((ofilter = dofork(DOABORT)) == 0) { /* child */ 100312463Sralph dup2(p[0], 0); /* pipe is std in */ 100412463Sralph dup2(pfd, 1); /* printer is std out */ 100512463Sralph for (i = 3; i < NOFILE; i++) 100612463Sralph (void) close(i); 100712463Sralph if ((cp = rindex(OF, '/')) == NULL) 100812463Sralph cp = OF; 100912463Sralph else 101012463Sralph cp++; 101112463Sralph execl(OF, cp, width, length, 0); 101212463Sralph log("can't execl output filter %s", OF); 101312463Sralph exit(1); 101412463Sralph } 101512463Sralph (void) close(p[0]); /* close input side */ 101612463Sralph ofd = p[1]; /* use pipe for output */ 101712463Sralph } else { 101812463Sralph ofd = pfd; 101912463Sralph ofilter = 0; 102012463Sralph } 102112463Sralph } 102212463Sralph 102312111Sralph struct bauds { 102412111Sralph int baud; 102512111Sralph int speed; 102612111Sralph } bauds[] = { 102712111Sralph 50, B50, 102812111Sralph 75, B75, 102912111Sralph 110, B110, 103012111Sralph 134, B134, 103112111Sralph 150, B150, 103212111Sralph 200, B200, 103312111Sralph 300, B300, 103412111Sralph 600, B600, 103512111Sralph 1200, B1200, 103612111Sralph 1800, B1800, 103712111Sralph 2400, B2400, 103812111Sralph 4800, B4800, 103912111Sralph 9600, B9600, 104012111Sralph 19200, EXTA, 104112111Sralph 38400, EXTB, 104212111Sralph 0, 0 104312111Sralph }; 104412111Sralph 104512111Sralph /* 104612111Sralph * setup tty lines. 104712111Sralph */ 104812877Sralph static 104912111Sralph setty() 105012111Sralph { 105112111Sralph struct sgttyb ttybuf; 105212111Sralph register struct bauds *bp; 105312111Sralph 105412111Sralph if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) { 105512111Sralph log("cannot set exclusive-use"); 105612111Sralph exit(1); 105712111Sralph } 105812111Sralph if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) { 105912111Sralph log("cannot get tty parameters"); 106012111Sralph exit(1); 106112111Sralph } 106212111Sralph if (BR > 0) { 106312111Sralph for (bp = bauds; bp->baud; bp++) 106412111Sralph if (BR == bp->baud) 106512111Sralph break; 106612111Sralph if (!bp->baud) { 106712111Sralph log("illegal baud rate %d", BR); 106812111Sralph exit(1); 106912111Sralph } 107012111Sralph ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed; 107112111Sralph } 1072*13169Sralph ttybuf.sg_flags &= ~FC; 1073*13169Sralph ttybuf.sg_flags |= FS; 107412111Sralph if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) { 107512111Sralph log("cannot set tty parameters"); 107612111Sralph exit(1); 107712111Sralph } 107812111Sralph if (XC) { 107912111Sralph if (ioctl(pfd, TIOCLBIC, &XC) < 0) { 108012111Sralph log("cannot set local tty parameters"); 108112111Sralph exit(1); 108212111Sralph } 108312111Sralph } 108412111Sralph if (XS) { 108512111Sralph if (ioctl(pfd, TIOCLBIS, &XS) < 0) { 108612111Sralph log("cannot set local tty parameters"); 108712111Sralph exit(1); 108812111Sralph } 108912111Sralph } 109012111Sralph } 109112463Sralph 109212463Sralph /*VARARGS1*/ 109312463Sralph static 109412463Sralph status(msg, a1, a2, a3) 109512463Sralph char *msg; 109612463Sralph { 109712463Sralph register int fd; 109812463Sralph char buf[BUFSIZ]; 109912463Sralph 110012463Sralph umask(0); 110113148Ssam fd = open(ST, O_WRONLY|O_CREAT, 0664); 110213148Ssam if (fd < 0 || flock(fd, LOCK_EX) < 0) 110312463Sralph fatal("cannot create status file"); 110413148Ssam ftruncate(fd, 0); 110512463Sralph sprintf(buf, msg, a1, a2, a3); 110612463Sralph strcat(buf, "\n"); 110712463Sralph (void) write(fd, buf, strlen(buf)); 110812463Sralph (void) close(fd); 110912463Sralph } 1110