1*13148Ssam /* printjob.c 4.7 83/06/15 */ 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); 47*13148Ssam if (open(LF, O_WRONLY|O_APPEND) < 0) 48*13148Ssam (void) open("/dev/null", O_WRONLY); 4912877Sralph dup(1); 5012463Sralph pid = getpid(); /* for use with lprm */ 5112111Sralph setpgrp(0, pid); 52*13148Ssam 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*13148Ssam lfd = open(LO, O_WRONLY|O_CREAT, 0664); 64*13148Ssam if (lfd < 0 || flock(lfd, LOCK_EX|LOCK_NB) < 0) { 6512111Sralph if (errno == EWOULDBLOCK) /* active deamon present */ 6612111Sralph exit(0); 6712111Sralph log("cannot create %s", LO); 6812111Sralph exit(1); 6912111Sralph } 70*13148Ssam ftruncate(lfd, 0); 7112111Sralph /* 7212111Sralph * write process id for others to know 7312111Sralph */ 7412111Sralph sprintf(line, "%u\n", pid); 7512111Sralph pidoff = i = strlen(line); 7612463Sralph if (write(lfd, line, i) != i) { 7712111Sralph log("cannot write daemon pid"); 7812111Sralph exit(1); 7912111Sralph } 8012111Sralph /* 8112111Sralph * search the spool directory for work and sort by queue order. 8212111Sralph */ 8312111Sralph if ((nitems = getq(&queue)) < 0) { 8412111Sralph log("can't scan spool directory %s", SD); 8512111Sralph exit(1); 8612111Sralph } 8712463Sralph if (nitems == 0) /* no work to do */ 8812111Sralph exit(0); 8912463Sralph openpr(); /* open printer or remote */ 9012463Sralph again: 9112111Sralph /* 9212111Sralph * we found something to do now do it -- 9312111Sralph * write the name of the current control file into the lock file 9412111Sralph * so the spool queue program can tell what we're working on 9512111Sralph */ 9612111Sralph for (qp = queue; nitems--; free((char *) q)) { 9712111Sralph q = *qp++; 9812111Sralph if (stat(q->q_name, &stb) < 0) 9912111Sralph continue; 10012463Sralph restart: 10112111Sralph (void) lseek(lfd, pidoff, 0); 10212111Sralph (void) sprintf(line, "%s\n", q->q_name); 10312111Sralph i = strlen(line); 10412111Sralph if (write(lfd, line, i) != i) 10512111Sralph log("can't write (%d) control file name", errno); 10612111Sralph if (!remote) 10712111Sralph i = printit(q->q_name); 10812111Sralph else 10912111Sralph i = sendit(q->q_name); 11012463Sralph /* 11112463Sralph * Check to see if we are supposed to stop printing. 11212463Sralph */ 11312463Sralph if (stat(LO, &stb) == 0 && (stb.st_mode & 0100)) 11412463Sralph goto done; 11512463Sralph /* 11612463Sralph * Check to see if we should try reprinting the job. 11712463Sralph */ 11812463Sralph if (i > 0) { 11912111Sralph log("restarting"); 12012111Sralph if (ofilter > 0) { 12112111Sralph kill(ofilter, SIGCONT); /* to be sure */ 12212111Sralph (void) close(ofd); 12312111Sralph while ((i = wait(0)) > 0 && i != ofilter) 12412111Sralph ; 12512111Sralph ofilter = 0; 12612111Sralph } 12712463Sralph (void) close(pfd); /* close printer */ 12812463Sralph (void) lseek(lfd, pidoff, 0); 12912463Sralph if (write(lfd, "\n", 1) != 1) 13012463Sralph log("can't write (%d) control file name", errno); 13112463Sralph openpr(); /* try to reopen printer */ 13212111Sralph goto restart; 13312111Sralph } 13412111Sralph } 13512111Sralph free((char *) queue); 13612463Sralph /* 13712463Sralph * search the spool directory for more work. 13812463Sralph */ 13912463Sralph if ((nitems = getq(&queue)) < 0) { 14012463Sralph log("can't scan spool directory %s", SD); 14112463Sralph exit(1); 14212463Sralph } 14312463Sralph if (nitems == 0) { /* no more work to do */ 14412463Sralph done: 14512463Sralph if (!SF && !tof) 14612463Sralph (void) write(ofd, FF, strlen(FF)); 14712463Sralph if (TR != NULL) /* output trailer */ 14812463Sralph (void) write(ofd, TR, strlen(TR)); 14912463Sralph exit(0); 15012463Sralph } 15112111Sralph goto again; 15212111Sralph } 15312111Sralph 15412111Sralph char fonts[4][50]; /* fonts for troff */ 15512111Sralph 15612111Sralph static char ifonts[4][18] = { 15712111Sralph "/usr/lib/vfont/R", 15812111Sralph "/usr/lib/vfont/I", 15912111Sralph "/usr/lib/vfont/B", 16012111Sralph "/usr/lib/vfont/S" 16112111Sralph }; 16212111Sralph 16312111Sralph /* 16412111Sralph * The remaining part is the reading of the control file (cf) 16512111Sralph * and performing the various actions. 16612111Sralph * Returns 0 if everthing was OK, 1 if we should try to reprint the job and 16712111Sralph * -1 if a non-recoverable error occured. 16812111Sralph */ 16912877Sralph static 17012111Sralph printit(file) 17112111Sralph char *file; 17212111Sralph { 17312111Sralph register int i; 17412111Sralph int bombed = 0; 17512111Sralph 17612111Sralph /* 17712111Sralph * open control file 17812111Sralph */ 17912111Sralph if ((cfp = fopen(file, "r")) == NULL) { 18012111Sralph log("control file (%s) open failure <errno = %d>", file, errno); 18112111Sralph return(0); 18212111Sralph } 18312111Sralph /* 18412111Sralph * Reset troff fonts. 18512111Sralph */ 18612111Sralph for (i = 0; i < 4; i++) 18712111Sralph strcpy(fonts[i], ifonts[i]); 18812111Sralph 18912111Sralph /* 19012111Sralph * read the control file for work to do 19112111Sralph * 19212111Sralph * file format -- first character in the line is a command 19312111Sralph * rest of the line is the argument. 19412111Sralph * valid commands are: 19512111Sralph * 19612111Sralph * J -- "job name" on banner page 19712111Sralph * C -- "class name" on banner page 19812111Sralph * L -- "literal" user's name to print on banner 19912111Sralph * T -- "title" for pr 20012111Sralph * H -- "host name" of machine where lpr was done 20112111Sralph * P -- "person" user's login name 20212581Sralph * I -- "indent" amount to indent output 20312111Sralph * f -- "file name" name of text file to print 20412111Sralph * l -- "file name" text file with control chars 20512111Sralph * p -- "file name" text file to print with pr(1) 20612111Sralph * t -- "file name" troff(1) file to print 20712111Sralph * d -- "file name" dvi file to print 20812111Sralph * g -- "file name" plot(1G) file to print 20912111Sralph * v -- "file name" plain raster file to print 21012111Sralph * c -- "file name" cifplot file to print 21112111Sralph * 1 -- "R font file" for troff 21212111Sralph * 2 -- "I font file" for troff 21312111Sralph * 3 -- "B font file" for troff 21412111Sralph * 4 -- "S font file" for troff 21512111Sralph * N -- "name" of file (used by lpq) 21612111Sralph * U -- "unlink" name of file to remove 21712111Sralph * (after we print it. (Pass 2 only)). 21812111Sralph * M -- "mail" to user when done printing 21912111Sralph * 22012111Sralph * getline reads a line and expands tabs to blanks 22112111Sralph */ 22212111Sralph 22312111Sralph /* pass 1 */ 22412111Sralph 22512111Sralph while (getline(cfp)) 22612111Sralph switch (line[0]) { 22712111Sralph case 'H': 22812111Sralph strcpy(host, line+1); 22912111Sralph if (class[0] == '\0') 23012111Sralph strcpy(class, line+1); 23112111Sralph continue; 23212111Sralph 23312111Sralph case 'P': 23412111Sralph strcpy(logname, line+1); 23512463Sralph if (RS) { /* restricted */ 23612463Sralph if (getpwnam(logname) == (struct passwd *)0) { 23712463Sralph bombed = 2; 23812463Sralph sendmail(bombed); 23912463Sralph goto pass2; 24012463Sralph } 24112463Sralph } 24212111Sralph continue; 24312111Sralph 24412111Sralph case 'J': 24512111Sralph if (line[1] != '\0') 24612111Sralph strcpy(jobname, line+1); 24712111Sralph else 24812111Sralph strcpy(jobname, " "); 24912111Sralph continue; 25012111Sralph 25112111Sralph case 'C': 25212111Sralph if (line[1] != '\0') 25312111Sralph strcpy(class, line+1); 25412111Sralph else if (class[0] == '\0') 25512111Sralph gethostname(class, sizeof (class)); 25612111Sralph continue; 25712111Sralph 25812111Sralph case 'T': /* header title for pr */ 25912111Sralph strcpy(title, line+1); 26012111Sralph continue; 26112111Sralph 26212111Sralph case 'L': /* identification line */ 26312111Sralph if (!SH) 26412111Sralph banner(line+1, jobname); 26512111Sralph continue; 26612111Sralph 26712111Sralph case '1': /* troff fonts */ 26812111Sralph case '2': 26912111Sralph case '3': 27012111Sralph case '4': 27112111Sralph if (line[1] != '\0') 27212111Sralph strcpy(fonts[line[0]-'1'], line+1); 27312111Sralph continue; 27412111Sralph 27512111Sralph case 'W': /* page width */ 27612111Sralph strcpy(width+2, line+1); 27712111Sralph continue; 27812111Sralph 27912581Sralph case 'I': /* indent amount */ 28012581Sralph strcpy(indent+2, line+1); 28112581Sralph continue; 28212581Sralph 28312111Sralph default: /* some file to print */ 28412111Sralph if ((i = print(line[0], line+1)) > 0) { 28512111Sralph (void) fclose(cfp); 28612111Sralph return(1); 28712111Sralph } else if (i < 0) 28812111Sralph bombed = 1; 28912111Sralph title[0] = '\0'; 29012111Sralph continue; 29112111Sralph 29212111Sralph case 'N': 29312111Sralph case 'U': 29412111Sralph case 'M': 29512111Sralph continue; 29612111Sralph } 29712111Sralph 29812111Sralph /* pass 2 */ 29912111Sralph 30012463Sralph pass2: 30112111Sralph fseek(cfp, 0L, 0); 30212111Sralph while (getline(cfp)) 30312111Sralph switch (line[0]) { 30412111Sralph case 'M': 30512463Sralph if (bombed != 2) /* already sent if 2 */ 30612463Sralph sendmail(bombed); 30712111Sralph continue; 30812111Sralph 30912111Sralph case 'U': 31012111Sralph (void) unlink(line+1); 31112111Sralph } 31212111Sralph /* 31312111Sralph * clean-up incase another control file exists 31412111Sralph */ 31512111Sralph (void) fclose(cfp); 31612111Sralph (void) unlink(file); 31712111Sralph return(0); 31812111Sralph } 31912111Sralph 32012111Sralph /* 32112111Sralph * Print a file. 32212111Sralph * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, TF, CF, VF}. 32312111Sralph * Return -1 if a non-recoverable error occured, 1 if a recoverable error and 32412111Sralph * 0 if all is well. 32512111Sralph * Note: all filters take stdin as the file, stdout as the printer, 32612111Sralph * stderr as the log file, and must not ignore SIGINT. 32712111Sralph */ 32812877Sralph static 32912111Sralph print(format, file) 33012111Sralph int format; 33112111Sralph char *file; 33212111Sralph { 33312111Sralph register int n, fi, fo; 33412111Sralph register char *prog; 33512111Sralph char *av[15], buf[BUFSIZ]; 33612111Sralph int pid, p[2], stopped = 0; 33712111Sralph union wait status; 33812111Sralph 339*13148Ssam if ((fi = open(file, O_RDONLY)) < 0) { 34012111Sralph log("%s: open failure <errno = %d>", file, errno); 34112111Sralph return(-1); 34212111Sralph } 34312111Sralph if (!SF && !tof) { /* start on a fresh page */ 34412111Sralph (void) write(ofd, FF, strlen(FF)); 34512111Sralph tof = 1; 34612111Sralph } 34712111Sralph if (IF == NULL && (format == 'f' || format == 'l')) { 34812111Sralph tof = 0; 34912111Sralph while ((n = read(fi, buf, BUFSIZ)) > 0) 35012111Sralph if (write(ofd, buf, n) != n) { 35112111Sralph (void) close(fi); 35212111Sralph return(1); 35312111Sralph } 35412111Sralph (void) close(fi); 35512111Sralph return(0); 35612111Sralph } 35712111Sralph switch (format) { 35812111Sralph case 'p': /* print file using 'pr' */ 35912111Sralph if (IF == NULL) { /* use output filter */ 36012111Sralph prog = PR; 36112111Sralph av[0] = "pr"; 36212111Sralph av[1] = width; 36312111Sralph av[2] = length; 36412111Sralph av[3] = "-h"; 36512111Sralph av[4] = *title ? title : " "; 36612111Sralph av[5] = 0; 36712111Sralph fo = ofd; 36812111Sralph goto start; 36912111Sralph } 37012111Sralph pipe(p); 37112111Sralph if ((prchild = dofork(DORETURN)) == 0) { /* child */ 37212111Sralph dup2(fi, 0); /* file is stdin */ 37312111Sralph dup2(p[1], 1); /* pipe is stdout */ 37412111Sralph for (n = 3; n < NOFILE; n++) 37512111Sralph (void) close(n); 37612111Sralph execl(PR, "pr", width, length, "-h", *title ? title : " ", 0); 37712111Sralph log("cannot execl %s", PR); 37812111Sralph exit(2); 37912111Sralph } 38012111Sralph (void) close(p[1]); /* close output side */ 38112111Sralph (void) close(fi); 38212111Sralph if (prchild < 0) { 38312111Sralph prchild = 0; 38412111Sralph (void) close(p[0]); 38512111Sralph return(-1); 38612111Sralph } 38712111Sralph fi = p[0]; /* use pipe for input */ 38812111Sralph case 'f': /* print plain text file */ 38912111Sralph prog = IF; 39012111Sralph av[1] = width; 39112111Sralph av[2] = length; 39212581Sralph av[3] = indent; 39312581Sralph n = 4; 39412111Sralph break; 39512111Sralph case 'l': /* like 'f' but pass control characters */ 39612111Sralph prog = IF; 39712111Sralph av[1] = "-l"; 39812111Sralph av[2] = width; 39912111Sralph av[3] = length; 40012581Sralph av[4] = indent; 40112581Sralph n = 5; 40212111Sralph break; 40312463Sralph case 'r': /* print a fortran text file */ 40412463Sralph prog = RF; 40512463Sralph av[1] = width; 40612463Sralph av[2] = length; 40712463Sralph n = 3; 40812463Sralph break; 40912111Sralph case 't': /* print troff output */ 41012463Sralph case 'd': /* print tex output */ 41112111Sralph (void) unlink(".railmag"); 41212463Sralph if ((fo = creat(".railmag", FILMOD)) < 0) { 41312111Sralph log("cannot create .railmag"); 41412111Sralph (void) unlink(".railmag"); 41512111Sralph } else { 41612111Sralph for (n = 0; n < 4; n++) { 41712111Sralph if (fonts[n][0] != '/') 41812111Sralph (void) write(fo, "/usr/lib/vfont/", 15); 41912111Sralph (void) write(fo, fonts[n], strlen(fonts[n])); 42012111Sralph (void) write(fo, "\n", 1); 42112111Sralph } 42212111Sralph (void) close(fo); 42312111Sralph } 42412111Sralph prog = (format == 't') ? TF : DF; 42512463Sralph av[1] = pxwidth; 42612463Sralph av[2] = pxlength; 42712463Sralph n = 3; 42812111Sralph break; 42912111Sralph case 'c': /* print cifplot output */ 43012111Sralph prog = CF; 43112463Sralph av[1] = pxwidth; 43212463Sralph av[2] = pxlength; 43312463Sralph n = 3; 43412111Sralph break; 43512111Sralph case 'g': /* print plot(1G) output */ 43612111Sralph prog = GF; 43712463Sralph av[1] = pxwidth; 43812463Sralph av[2] = pxlength; 43912463Sralph n = 3; 44012111Sralph break; 44112111Sralph case 'v': /* print raster output */ 44212111Sralph prog = VF; 44312463Sralph av[1] = pxwidth; 44412463Sralph av[2] = pxlength; 44512463Sralph n = 3; 44612111Sralph break; 44712111Sralph default: 44812111Sralph (void) close(fi); 44912111Sralph log("illegal format character '%c'", format); 45012111Sralph return(-1); 45112111Sralph } 45212111Sralph if ((av[0] = rindex(prog, '/')) != NULL) 45312111Sralph av[0]++; 45412111Sralph else 45512111Sralph av[0] = prog; 45612111Sralph av[n++] = "-n"; 45712111Sralph av[n++] = logname; 45812111Sralph av[n++] = "-h"; 45912111Sralph av[n++] = host; 46012111Sralph av[n++] = AF; 46112111Sralph av[n] = 0; 46212111Sralph fo = pfd; 46312111Sralph if (ofilter > 0) { /* stop output filter */ 46412111Sralph write(ofd, "\031\1", 2); 46512111Sralph while ((pid = wait3(&status, WUNTRACED, 0)) > 0 && pid != ofilter) 46612111Sralph ; 46712111Sralph if (status.w_stopval != WSTOPPED) { 46812111Sralph (void) close(fi); 46912111Sralph log("output filter died (%d)", status.w_retcode); 47012111Sralph return(1); 47112111Sralph } 47212111Sralph stopped++; 47312111Sralph } 47412111Sralph start: 47512111Sralph if ((child = dofork(DORETURN)) == 0) { /* child */ 47612111Sralph dup2(fi, 0); 47712111Sralph dup2(fo, 1); 47812111Sralph for (n = 3; n < NOFILE; n++) 47912111Sralph (void) close(n); 48012111Sralph execv(prog, av); 48112111Sralph log("cannot execl %s", prog); 48212111Sralph exit(2); 48312111Sralph } 48412111Sralph (void) close(fi); 48512111Sralph if (child < 0) 48612111Sralph status.w_retcode = 100; 48712111Sralph else 48812111Sralph while ((pid = wait(&status)) > 0 && pid != child) 48912111Sralph ; 49012111Sralph child = 0; 49112111Sralph prchild = 0; 49212111Sralph if (stopped) { /* restart output filter */ 49312111Sralph if (kill(ofilter, SIGCONT) < 0) { 49412111Sralph log("cannot restart output filter"); 49512111Sralph exit(1); 49612111Sralph } 49712111Sralph } 49812111Sralph tof = 0; 49912111Sralph if (!WIFEXITED(status) || status.w_retcode > 1) { 50012111Sralph log("Daemon Filter '%c' Malfunction (%d)", format, status.w_retcode); 50112111Sralph return(-1); 50212111Sralph } else if (status.w_retcode == 1) 50312111Sralph return(1); 50412111Sralph tof = 1; 50512111Sralph return(0); 50612111Sralph } 50712111Sralph 50812111Sralph /* 50912111Sralph * Send the daemon control file (cf) and any data files. 51012111Sralph * Return -1 if a non-recoverable error occured, 1 if a recoverable error and 51112111Sralph * 0 if all is well. 51212111Sralph */ 51312877Sralph static 51412111Sralph sendit(file) 51512111Sralph char *file; 51612111Sralph { 51712111Sralph register int linelen, err = 0; 51812111Sralph char last[132]; 51912111Sralph 52012111Sralph /* 52112111Sralph * open control file 52212111Sralph */ 52312111Sralph if ((cfp = fopen(file, "r")) == NULL) { 52412111Sralph log("control file (%s) open failure <errno = %d>", file, errno); 52512111Sralph return(0); 52612111Sralph } 52712111Sralph /* 52812111Sralph * read the control file for work to do 52912111Sralph * 53012111Sralph * file format -- first character in the line is a command 53112111Sralph * rest of the line is the argument. 53212111Sralph * commands of interest are: 53312111Sralph * 53412111Sralph * a-z -- "file name" name of file to print 53512111Sralph * U -- "unlink" name of file to remove 53612111Sralph * (after we print it. (Pass 2 only)). 53712111Sralph */ 53812111Sralph 53912111Sralph /* 54012111Sralph * pass 1 54112111Sralph */ 54212111Sralph while (getline(cfp)) { 54312111Sralph again: 54412111Sralph if (line[0] >= 'a' && line[0] <= 'z') { 54512111Sralph strcpy(last, line); 54612111Sralph while (linelen = getline(cfp)) 54712111Sralph if (strcmp(last, line)) 54812111Sralph break; 54912111Sralph if ((err = sendfile('\3', last+1)) > 0) { 55012111Sralph (void) fclose(cfp); 55112111Sralph return(1); 55212111Sralph } else if (err) 55312111Sralph break; 55412111Sralph if (linelen) 55512111Sralph goto again; 55612111Sralph break; 55712111Sralph } 55812111Sralph } 55912111Sralph if (!err && sendfile('\2', file) > 0) { 56012111Sralph (void) fclose(cfp); 56112111Sralph return(1); 56212111Sralph } 56312111Sralph /* 56412111Sralph * pass 2 56512111Sralph */ 56612111Sralph fseek(cfp, 0L, 0); 56712111Sralph while (getline(cfp)) 56812111Sralph if (line[0] == 'U') 56912111Sralph (void) unlink(line+1); 57012111Sralph /* 57112111Sralph * clean-up incase another control file exists 57212111Sralph */ 57312111Sralph (void) fclose(cfp); 57412111Sralph (void) unlink(file); 57512111Sralph return(0); 57612111Sralph } 57712111Sralph 57812111Sralph /* 57912111Sralph * Send a data file to the remote machine and spool it. 58012111Sralph * Return positive if we should try resending. 58112111Sralph */ 58212877Sralph static 58312111Sralph sendfile(type, file) 58412111Sralph char type, *file; 58512111Sralph { 58612111Sralph register int f, i, amt; 58712111Sralph struct stat stb; 58812111Sralph char buf[BUFSIZ]; 58912111Sralph int sizerr; 59012111Sralph 591*13148Ssam if ((f = open(file, O_RDONLY)) < 0 || fstat(f, &stb) < 0) { 59212111Sralph log("file (%s) open failure <errno = %d>", file, errno); 59312111Sralph return(-1); 59412111Sralph } 59512111Sralph (void) sprintf(buf, "%c%d %s\n", type, stb.st_size, file); 59612111Sralph amt = strlen(buf); 59712692Sralph if (write(pfd, buf, amt) != amt) { 59812692Sralph (void) close(f); 59912111Sralph return(1); 60012692Sralph } 60112692Sralph if (noresponse()) { 60212692Sralph (void) close(f); 60312111Sralph return(1); 60412692Sralph } 60512111Sralph sizerr = 0; 60612111Sralph for (i = 0; i < stb.st_size; i += BUFSIZ) { 60712111Sralph amt = BUFSIZ; 60812111Sralph if (i + amt > stb.st_size) 60912111Sralph amt = stb.st_size - i; 61012111Sralph if (sizerr == 0 && read(f, buf, amt) != amt) 61112111Sralph sizerr = 1; 61212692Sralph if (write(pfd, buf, amt) != amt) { 61312692Sralph (void) close(f); 61412111Sralph return(1); 61512692Sralph } 61612111Sralph } 61712111Sralph (void) close(f); 61812111Sralph if (sizerr) { 61912111Sralph log("%s: changed size", file); 62012111Sralph (void) write(pfd, "\1", 1); /* tell recvjob to ignore this file */ 62112111Sralph return(-1); 62212111Sralph } 62312111Sralph if (write(pfd, "", 1) != 1) 62412111Sralph return(1); 62512111Sralph if (noresponse()) 62612111Sralph return(1); 62712111Sralph return(0); 62812111Sralph } 62912111Sralph 63012111Sralph /* 63112111Sralph * Check to make sure there have been no errors and that both programs 63212111Sralph * are in sync with eachother. 63312111Sralph * Return non-zero if the connection was lost. 63412111Sralph */ 63512111Sralph static 63612111Sralph noresponse() 63712111Sralph { 63812111Sralph char resp; 63912111Sralph 64012111Sralph if (read(pfd, &resp, 1) != 1 || resp != '\0') { 64112111Sralph log("lost connection or error in recvjob"); 64212111Sralph return(1); 64312111Sralph } 64412111Sralph return(0); 64512111Sralph } 64612111Sralph 64712111Sralph /* 64812111Sralph * Banner printing stuff 64912111Sralph */ 65012877Sralph static 65112111Sralph banner(name1, name2) 65212111Sralph char *name1, *name2; 65312111Sralph { 65412111Sralph time_t tvec; 65512111Sralph extern char *ctime(); 65612111Sralph 65712111Sralph time(&tvec); 65812111Sralph if (!SF && !tof) 65912111Sralph (void) write(ofd, FF, strlen(FF)); 66012111Sralph if (SB) { /* short banner only */ 66112111Sralph if (class[0]) { 66212111Sralph (void) write(ofd, class, strlen(class)); 66312111Sralph (void) write(ofd, ":", 1); 66412111Sralph } 66512111Sralph (void) write(ofd, name1, strlen(name1)); 66612111Sralph (void) write(ofd, " Job: ", 7); 66712111Sralph (void) write(ofd, name2, strlen(name2)); 66812111Sralph (void) write(ofd, " Date: ", 8); 66912111Sralph (void) write(ofd, ctime(&tvec), 24); 67012111Sralph (void) write(ofd, "\n", 1); 67112111Sralph } else { /* normal banner */ 67212111Sralph (void) write(ofd, "\n\n\n", 3); 67312111Sralph scan_out(ofd, name1, '\0'); 67412111Sralph (void) write(ofd, "\n\n", 2); 67512111Sralph scan_out(ofd, name2, '\0'); 67612111Sralph if (class[0]) { 67712111Sralph (void) write(ofd,"\n\n\n",3); 67812111Sralph scan_out(ofd, class, '\0'); 67912111Sralph } 68012111Sralph (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15); 68112111Sralph (void) write(ofd, name2, strlen(name2)); 68212111Sralph (void) write(ofd, "\n\t\t\t\t\tDate: ", 12); 68312111Sralph (void) write(ofd, ctime(&tvec), 24); 68412111Sralph (void) write(ofd, "\n", 1); 68512111Sralph } 68612111Sralph if (!SF) 68712111Sralph (void) write(ofd, FF, strlen(FF)); 68812111Sralph tof = 1; 68912111Sralph } 69012111Sralph 69112877Sralph static char * 69212111Sralph scnline(key, p, c) 69312111Sralph register char key, *p; 69412111Sralph char c; 69512111Sralph { 69612111Sralph register scnwidth; 69712111Sralph 69812111Sralph for (scnwidth = WIDTH; --scnwidth;) { 69912111Sralph key <<= 1; 70012111Sralph *p++ = key & 0200 ? c : BACKGND; 70112111Sralph } 70212111Sralph return (p); 70312111Sralph } 70412111Sralph 70512111Sralph #define TRC(q) (((q)-' ')&0177) 70612111Sralph 70712877Sralph static 70812111Sralph scan_out(scfd, scsp, dlm) 70912111Sralph int scfd; 71012111Sralph char *scsp, dlm; 71112111Sralph { 71212111Sralph register char *strp; 71312111Sralph register nchrs, j; 71412111Sralph char outbuf[LINELEN+1], *sp, c, cc; 71512111Sralph int d, scnhgt; 71612111Sralph extern char scnkey[][HEIGHT]; /* in lpdchar.c */ 71712111Sralph 71812111Sralph for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) { 71912111Sralph strp = &outbuf[0]; 72012111Sralph sp = scsp; 72112111Sralph for (nchrs = 0; ; ) { 72212111Sralph d = dropit(c = TRC(cc = *sp++)); 72312111Sralph if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d)) 72412111Sralph for (j = WIDTH; --j;) 72512111Sralph *strp++ = BACKGND; 72612111Sralph else 72712111Sralph strp = scnline(scnkey[c][scnhgt-1-d], strp, cc); 72812111Sralph if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1) 72912111Sralph break; 73012111Sralph *strp++ = BACKGND; 73112111Sralph *strp++ = BACKGND; 73212111Sralph } 73312111Sralph while (*--strp == BACKGND && strp >= outbuf) 73412111Sralph ; 73512111Sralph strp++; 73612111Sralph *strp++ = '\n'; 73712111Sralph (void) write(scfd, outbuf, strp-outbuf); 73812111Sralph } 73912111Sralph } 74012111Sralph 74112877Sralph static 74212111Sralph dropit(c) 74312111Sralph char c; 74412111Sralph { 74512111Sralph switch(c) { 74612111Sralph 74712111Sralph case TRC('_'): 74812111Sralph case TRC(';'): 74912111Sralph case TRC(','): 75012111Sralph case TRC('g'): 75112111Sralph case TRC('j'): 75212111Sralph case TRC('p'): 75312111Sralph case TRC('q'): 75412111Sralph case TRC('y'): 75512111Sralph return (DROP); 75612111Sralph 75712111Sralph default: 75812111Sralph return (0); 75912111Sralph } 76012111Sralph } 76112111Sralph 76212111Sralph /* 76312111Sralph * sendmail --- 76412111Sralph * tell people about job completion 76512111Sralph */ 76612877Sralph static 76712111Sralph sendmail(bombed) 76812111Sralph int bombed; 76912111Sralph { 77012111Sralph static int p[2]; 77112111Sralph register int i; 77212111Sralph int stat; 77312111Sralph register char *cp; 77412111Sralph char buf[100]; 77512111Sralph 77612111Sralph pipe(p); 77712111Sralph if ((stat = dofork(DORETURN)) == 0) { /* child */ 77812111Sralph dup2(p[0], 0); 77912111Sralph for (i = 3; i < NOFILE; i++) 78012111Sralph (void) close(i); 78112111Sralph if ((cp = rindex(MAIL, '/')) != NULL) 78212111Sralph cp++; 78312111Sralph else 78412111Sralph cp = MAIL; 78512111Sralph sprintf(buf, "%s@%s", line+1, host); 78612111Sralph execl(MAIL, cp, buf, 0); 78712111Sralph exit(0); 78812111Sralph } else if (stat > 0) { /* parent */ 78912111Sralph dup2(p[1], 1); 79012111Sralph printf("To: %s\n", line+1); 79112111Sralph printf("Subject: printer job\n\n"); 79212111Sralph printf("Your printer job "); 79312111Sralph if (*jobname) 79412111Sralph printf("(%s) ", jobname); 79512463Sralph switch (bombed) { 79612463Sralph case 0: 79712463Sralph printf("\ncompleted successfully\n"); 79812463Sralph break; 79912463Sralph default: 80012463Sralph case 1: 80112463Sralph printf("\ncould not be printed\n"); 80212463Sralph break; 80312463Sralph case 2: 80412463Sralph printf("\ncould not be printed without an account on %s\n", host); 80512463Sralph break; 80612463Sralph } 80712111Sralph fflush(stdout); 80812111Sralph (void) close(1); 80912111Sralph } 81012111Sralph (void) close(p[0]); 81112111Sralph (void) close(p[1]); 81212111Sralph wait(&stat); 81312111Sralph } 81412111Sralph 81512111Sralph /* 81612111Sralph * dofork - fork with retries on failure 81712111Sralph */ 81812877Sralph static 81912111Sralph dofork(action) 82012111Sralph int action; 82112111Sralph { 82212111Sralph register int i, pid; 82312111Sralph 82412111Sralph for (i = 0; i < 20; i++) { 82512463Sralph if ((pid = fork()) < 0) { 82612111Sralph sleep((unsigned)(i*i)); 82712463Sralph continue; 82812463Sralph } 82912463Sralph /* 83012463Sralph * Child should run as daemon instead of root 83112463Sralph */ 83212463Sralph if (pid == 0) 83312463Sralph setuid(DU); 83412463Sralph return(pid); 83512111Sralph } 83612111Sralph log("can't fork"); 83712111Sralph 83812111Sralph switch (action) { 83912111Sralph case DORETURN: 84012111Sralph return (-1); 84112111Sralph default: 84212111Sralph log("bad action (%d) to dofork", action); 84312111Sralph /*FALL THRU*/ 84412111Sralph case DOABORT: 84512111Sralph exit(1); 84612111Sralph } 84712111Sralph /*NOTREACHED*/ 84812111Sralph } 84912111Sralph 85012111Sralph /* 85112111Sralph * Cleanup child processes when a SIGINT is caught. 85212111Sralph */ 85312877Sralph static 85412111Sralph onintr() 85512111Sralph { 85612111Sralph kill(0, SIGINT); 85712111Sralph if (ofilter > 0) 85812111Sralph kill(ofilter, SIGCONT); 85912111Sralph while (wait(0) > 0) 86012111Sralph ; 86112111Sralph exit(0); 86212111Sralph } 86312111Sralph 86412877Sralph static 86512111Sralph init() 86612111Sralph { 86712111Sralph int status; 86812111Sralph 86912111Sralph if ((status = pgetent(line, printer)) < 0) { 87012111Sralph log("can't open printer description file"); 87112111Sralph exit(1); 87212111Sralph } else if (status == 0) { 87312111Sralph log("unknown printer"); 87412111Sralph exit(1); 87512111Sralph } 87612111Sralph if ((LP = pgetstr("lp", &bp)) == NULL) 87712111Sralph LP = DEFDEVLP; 87812111Sralph if ((RP = pgetstr("rp", &bp)) == NULL) 87912463Sralph RP = DEFLP; 88012111Sralph if ((LO = pgetstr("lo", &bp)) == NULL) 88112111Sralph LO = DEFLOCK; 88212111Sralph if ((ST = pgetstr("st", &bp)) == NULL) 88312111Sralph ST = DEFSTAT; 88412111Sralph if ((LF = pgetstr("lf", &bp)) == NULL) 88512111Sralph LF = DEFLOGF; 88612111Sralph if ((SD = pgetstr("sd", &bp)) == NULL) 88712111Sralph SD = DEFSPOOL; 88812111Sralph if ((DU = pgetnum("du")) < 0) 88912111Sralph DU = DEFUID; 89012111Sralph if ((FF = pgetstr("ff", &bp)) == NULL) 89112111Sralph FF = DEFFF; 89212111Sralph if ((PW = pgetnum("pw")) < 0) 89312111Sralph PW = DEFWIDTH; 89412111Sralph sprintf(&width[2], "%d", PW); 89512111Sralph if ((PL = pgetnum("pl")) < 0) 89612111Sralph PL = DEFLENGTH; 89712111Sralph sprintf(&length[2], "%d", PL); 89812463Sralph if ((PX = pgetnum("px")) < 0) 89912463Sralph PX = 0; 90012463Sralph sprintf(&pxwidth[2], "%d", PX); 90112463Sralph if ((PY = pgetnum("py")) < 0) 90212463Sralph PY = 0; 90312463Sralph sprintf(&pxlength[2], "%d", PY); 90412111Sralph RM = pgetstr("rm", &bp); 90512111Sralph AF = pgetstr("af", &bp); 90612111Sralph OF = pgetstr("of", &bp); 90712111Sralph IF = pgetstr("if", &bp); 90812463Sralph RF = pgetstr("rf", &bp); 90912111Sralph TF = pgetstr("tf", &bp); 91012111Sralph DF = pgetstr("df", &bp); 91112111Sralph GF = pgetstr("gf", &bp); 91212111Sralph VF = pgetstr("vf", &bp); 91312111Sralph CF = pgetstr("cf", &bp); 91412111Sralph TR = pgetstr("tr", &bp); 91512463Sralph RS = pgetflag("rs"); 91612111Sralph SF = pgetflag("sf"); 91712111Sralph SH = pgetflag("sh"); 91812111Sralph SB = pgetflag("sb"); 91912111Sralph RW = pgetflag("rw"); 92012111Sralph BR = pgetnum("br"); 92112111Sralph if ((FC = pgetnum("fc")) < 0) 92212111Sralph FC = 0; 92312111Sralph if ((FS = pgetnum("fs")) < 0) 92412111Sralph FS = 0; 92512111Sralph if ((XC = pgetnum("xc")) < 0) 92612111Sralph XC = 0; 92712111Sralph if ((XS = pgetnum("xs")) < 0) 92812111Sralph XS = 0; 92912581Sralph tof = !pgetflag("fo"); 93012111Sralph } 93112111Sralph 93212463Sralph /* 93312463Sralph * Acquire line printer or remote connection. 93412463Sralph */ 93512877Sralph static 93612463Sralph openpr() 93712463Sralph { 93812463Sralph register int i, n; 93912463Sralph 94012463Sralph if (*LP) { 94112463Sralph for (i = 1; ; i = i < 32 ? i << 1 : i) { 942*13148Ssam pfd = open(LP, RW ? O_RDWR : O_WRONLY); 94312463Sralph if (pfd >= 0) 94412463Sralph break; 94512463Sralph if (errno == ENOENT) { 94612463Sralph log("cannot open %s", LP); 94712463Sralph exit(1); 94812463Sralph } 94912463Sralph if (i == 1) 95012463Sralph status("waiting for %s to become ready (offline ?)", printer); 95112463Sralph sleep(i); 95212463Sralph } 95312463Sralph if (isatty(pfd)) 95412463Sralph setty(); 95512463Sralph status("%s is ready and printing", printer); 95612463Sralph } else if (RM != NULL) { 95712463Sralph for (i = 1; ; i = i < 512 ? i << 1 : i) { 95812528Sralph pfd = getport(RM); 95912463Sralph if (pfd >= 0) { 96012463Sralph (void) sprintf(line, "\2%s\n", RP); 96112463Sralph n = strlen(line); 96212463Sralph if (write(pfd, line, n) != n) 96312463Sralph break; 96412463Sralph if (noresponse()) 96512463Sralph (void) close(pfd); 96612463Sralph else 96712463Sralph break; 96812463Sralph } 96912463Sralph if (i == 1) 97012463Sralph status("waiting for %s to come up", RM); 97112463Sralph sleep(i); 97212463Sralph } 97312463Sralph status("sending to %s", RM); 97412463Sralph remote = 1; 97512463Sralph } else { 97612463Sralph log("no line printer device or remote machine name"); 97712463Sralph exit(1); 97812463Sralph } 97912463Sralph /* 98012463Sralph * Start up an output filter, if needed. 98112463Sralph */ 98212463Sralph if (OF) { 98312463Sralph int p[2]; 98412463Sralph char *cp; 98512463Sralph 98612463Sralph pipe(p); 98712463Sralph if ((ofilter = dofork(DOABORT)) == 0) { /* child */ 98812463Sralph dup2(p[0], 0); /* pipe is std in */ 98912463Sralph dup2(pfd, 1); /* printer is std out */ 99012463Sralph for (i = 3; i < NOFILE; i++) 99112463Sralph (void) close(i); 99212463Sralph if ((cp = rindex(OF, '/')) == NULL) 99312463Sralph cp = OF; 99412463Sralph else 99512463Sralph cp++; 99612463Sralph execl(OF, cp, width, length, 0); 99712463Sralph log("can't execl output filter %s", OF); 99812463Sralph exit(1); 99912463Sralph } 100012463Sralph (void) close(p[0]); /* close input side */ 100112463Sralph ofd = p[1]; /* use pipe for output */ 100212463Sralph } else { 100312463Sralph ofd = pfd; 100412463Sralph ofilter = 0; 100512463Sralph } 100612463Sralph } 100712463Sralph 100812111Sralph struct bauds { 100912111Sralph int baud; 101012111Sralph int speed; 101112111Sralph } bauds[] = { 101212111Sralph 50, B50, 101312111Sralph 75, B75, 101412111Sralph 110, B110, 101512111Sralph 134, B134, 101612111Sralph 150, B150, 101712111Sralph 200, B200, 101812111Sralph 300, B300, 101912111Sralph 600, B600, 102012111Sralph 1200, B1200, 102112111Sralph 1800, B1800, 102212111Sralph 2400, B2400, 102312111Sralph 4800, B4800, 102412111Sralph 9600, B9600, 102512111Sralph 19200, EXTA, 102612111Sralph 38400, EXTB, 102712111Sralph 0, 0 102812111Sralph }; 102912111Sralph 103012111Sralph /* 103112111Sralph * setup tty lines. 103212111Sralph */ 103312877Sralph static 103412111Sralph setty() 103512111Sralph { 103612111Sralph struct sgttyb ttybuf; 103712111Sralph register struct bauds *bp; 103812111Sralph 103912111Sralph if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) { 104012111Sralph log("cannot set exclusive-use"); 104112111Sralph exit(1); 104212111Sralph } 104312111Sralph if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) { 104412111Sralph log("cannot get tty parameters"); 104512111Sralph exit(1); 104612111Sralph } 104712111Sralph if (BR > 0) { 104812111Sralph for (bp = bauds; bp->baud; bp++) 104912111Sralph if (BR == bp->baud) 105012111Sralph break; 105112111Sralph if (!bp->baud) { 105212111Sralph log("illegal baud rate %d", BR); 105312111Sralph exit(1); 105412111Sralph } 105512111Sralph ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed; 105612111Sralph } 105712111Sralph if (FC) 105812111Sralph ttybuf.sg_flags &= ~FC; 105912111Sralph if (FS) 106012111Sralph ttybuf.sg_flags |= FS; 106112111Sralph if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) { 106212111Sralph log("cannot set tty parameters"); 106312111Sralph exit(1); 106412111Sralph } 106512111Sralph if (XC) { 106612111Sralph if (ioctl(pfd, TIOCLBIC, &XC) < 0) { 106712111Sralph log("cannot set local tty parameters"); 106812111Sralph exit(1); 106912111Sralph } 107012111Sralph } 107112111Sralph if (XS) { 107212111Sralph if (ioctl(pfd, TIOCLBIS, &XS) < 0) { 107312111Sralph log("cannot set local tty parameters"); 107412111Sralph exit(1); 107512111Sralph } 107612111Sralph } 107712111Sralph } 107812463Sralph 107912463Sralph /*VARARGS1*/ 108012463Sralph static 108112463Sralph status(msg, a1, a2, a3) 108212463Sralph char *msg; 108312463Sralph { 108412463Sralph register int fd; 108512463Sralph char buf[BUFSIZ]; 108612463Sralph 108712463Sralph umask(0); 1088*13148Ssam fd = open(ST, O_WRONLY|O_CREAT, 0664); 1089*13148Ssam if (fd < 0 || flock(fd, LOCK_EX) < 0) 109012463Sralph fatal("cannot create status file"); 1091*13148Ssam ftruncate(fd, 0); 109212463Sralph sprintf(buf, msg, a1, a2, a3); 109312463Sralph strcat(buf, "\n"); 109412463Sralph (void) write(fd, buf, strlen(buf)); 109512463Sralph (void) close(fd); 109612463Sralph } 1097