113954Ssam #ifndef lint 2*14325Sralph static char sccsid[] = "@(#)printjob.c 4.13 (Berkeley) 08/02/83"; 313954Ssam #endif 413954Ssam 512111Sralph /* 612111Sralph * printjob -- print jobs in the queue. 712111Sralph * 812111Sralph * NOTE: the lock file is used to pass information to lpq and lprm. 912111Sralph * it does not need to be removed because file locks are dynamic. 1012111Sralph */ 1112111Sralph 1212111Sralph #include "lp.h" 1312111Sralph 1412877Sralph #define DORETURN 0 /* absorb fork error */ 1512877Sralph #define DOABORT 1 /* abort if dofork fails */ 1612111Sralph 1712877Sralph static char title[80]; /* ``pr'' title */ 1812877Sralph static FILE *cfp; /* control file */ 1912877Sralph static int pfd; /* printer file descriptor */ 2012877Sralph static int ofd; /* output filter file descriptor */ 2112877Sralph static int lfd; /* lock file descriptor */ 2212877Sralph static int pid; /* pid of lpd process */ 2312877Sralph static int prchild; /* id of pr process */ 2412877Sralph static int child; /* id of any filters */ 2512877Sralph static int ofilter; /* id of output filter, if any */ 2612877Sralph static int tof; /* true if at top of form */ 2714150Sralph static int count; /* Number of files actually printed */ 2812877Sralph static int remote; /* true if sending files to remote */ 2912111Sralph 3014150Sralph static char fromhost[32]; /* user's host machine */ 3112877Sralph static char logname[32]; /* user's login name */ 3212877Sralph static char jobname[32]; /* job or file name */ 3312877Sralph static char class[32]; /* classification field */ 3412877Sralph static char width[10] = "-w"; /* page width in characters */ 3512877Sralph static char length[10] = "-l"; /* page length in lines */ 3612877Sralph static char pxwidth[10] = "-x"; /* page width in pixels */ 3712877Sralph static char pxlength[10] = "-y"; /* page length in pixels */ 3812877Sralph static char indent[10] = "-i0"; /* indentation size in characters */ 3912111Sralph 4012111Sralph printjob() 4112111Sralph { 4212111Sralph struct stat stb; 4312111Sralph register struct queue *q, **qp; 4412111Sralph struct queue **queue; 4512111Sralph register int i, nitems; 4612111Sralph long pidoff; 4712111Sralph extern int onintr(); 4812111Sralph 4912111Sralph init(); /* set up capabilities */ 5013442Sralph (void) write(1, "", 1); /* ack that daemon is started */ 5112877Sralph (void) close(1); /* set up log file */ 5212877Sralph (void) close(2); 5313148Ssam if (open(LF, O_WRONLY|O_APPEND) < 0) 5413148Ssam (void) open("/dev/null", O_WRONLY); 5512877Sralph dup(1); 5612463Sralph pid = getpid(); /* for use with lprm */ 5712111Sralph setpgrp(0, pid); 5813148Ssam signal(SIGINT, onintr); 5912111Sralph 6012111Sralph /* 6112111Sralph * uses short form file names 6212111Sralph */ 6312111Sralph if (chdir(SD) < 0) { 6412111Sralph log("cannot chdir to %s", SD); 6512111Sralph exit(1); 6612111Sralph } 6712463Sralph if (stat(LO, &stb) == 0 && (stb.st_mode & 0100)) 6812463Sralph exit(0); /* printing disabled */ 6914150Sralph lfd = open(LO, O_WRONLY|O_CREAT, 0644); 7013169Sralph if (lfd < 0) { 7113169Sralph log("cannot create %s", LO); 7213169Sralph exit(1); 7313169Sralph } 7413169Sralph if (flock(lfd, LOCK_EX|LOCK_NB) < 0) { 7512111Sralph if (errno == EWOULDBLOCK) /* active deamon present */ 7612111Sralph exit(0); 7713169Sralph log("cannot lock %s", LO); 7812111Sralph exit(1); 7912111Sralph } 8013148Ssam ftruncate(lfd, 0); 8112111Sralph /* 8212111Sralph * write process id for others to know 8312111Sralph */ 8412111Sralph sprintf(line, "%u\n", pid); 8512111Sralph pidoff = i = strlen(line); 8612463Sralph if (write(lfd, line, i) != i) { 8712111Sralph log("cannot write daemon pid"); 8812111Sralph exit(1); 8912111Sralph } 9012111Sralph /* 9112111Sralph * search the spool directory for work and sort by queue order. 9212111Sralph */ 9312111Sralph if ((nitems = getq(&queue)) < 0) { 9412111Sralph log("can't scan spool directory %s", SD); 9512111Sralph exit(1); 9612111Sralph } 9712463Sralph if (nitems == 0) /* no work to do */ 9812111Sralph exit(0); 9913169Sralph if (stb.st_mode & 01) { /* reset queue flag */ 10013169Sralph if (fchmod(lfd, stb.st_mode & 0776) < 0) 10113169Sralph log("cannot chmod %s", LO); 10213169Sralph } 10312463Sralph openpr(); /* open printer or remote */ 10412463Sralph again: 10512111Sralph /* 10612111Sralph * we found something to do now do it -- 10712111Sralph * write the name of the current control file into the lock file 10812111Sralph * so the spool queue program can tell what we're working on 10912111Sralph */ 11012111Sralph for (qp = queue; nitems--; free((char *) q)) { 11112111Sralph q = *qp++; 11212111Sralph if (stat(q->q_name, &stb) < 0) 11312111Sralph continue; 11412463Sralph restart: 11512111Sralph (void) lseek(lfd, pidoff, 0); 11612111Sralph (void) sprintf(line, "%s\n", q->q_name); 11712111Sralph i = strlen(line); 11812111Sralph if (write(lfd, line, i) != i) 11912111Sralph log("can't write (%d) control file name", errno); 12012111Sralph if (!remote) 12112111Sralph i = printit(q->q_name); 12212111Sralph else 12312111Sralph i = sendit(q->q_name); 12412463Sralph /* 12513169Sralph * Check to see if we are supposed to stop printing or 12613169Sralph * if we are to rebuild the queue. 12712463Sralph */ 12813169Sralph if (fstat(lfd, &stb) == 0) { 12913169Sralph if (stb.st_mode & 0100) 13013169Sralph goto done; 13113169Sralph if (stb.st_mode & 01) { 13213169Sralph for (free((char *) q); nitems--; free((char *) q)) 13313169Sralph q = *qp++; 13413169Sralph if (fchmod(lfd, stb.st_mode & 0776) < 0) 13513169Sralph log("cannot chmod %s", LO); 13613169Sralph break; 13713169Sralph } 13813169Sralph } 13914150Sralph if (i == 0) /* file ok and printed */ 14014150Sralph count++; 14114150Sralph else if (i > 0) { /* try reprinting the job */ 14212111Sralph log("restarting"); 14312111Sralph if (ofilter > 0) { 14412111Sralph kill(ofilter, SIGCONT); /* to be sure */ 14512111Sralph (void) close(ofd); 14612111Sralph while ((i = wait(0)) > 0 && i != ofilter) 14712111Sralph ; 14812111Sralph ofilter = 0; 14912111Sralph } 15012463Sralph (void) close(pfd); /* close printer */ 15112463Sralph (void) lseek(lfd, pidoff, 0); 15212463Sralph if (write(lfd, "\n", 1) != 1) 15312463Sralph log("can't write (%d) control file name", errno); 15412463Sralph openpr(); /* try to reopen printer */ 15512111Sralph goto restart; 15612111Sralph } 15712111Sralph } 15812111Sralph free((char *) queue); 15912463Sralph /* 16012463Sralph * search the spool directory for more work. 16112463Sralph */ 16212463Sralph if ((nitems = getq(&queue)) < 0) { 16312463Sralph log("can't scan spool directory %s", SD); 16412463Sralph exit(1); 16512463Sralph } 16612463Sralph if (nitems == 0) { /* no more work to do */ 16712463Sralph done: 16814150Sralph if (count > 0) { /* Files actually printed */ 16914150Sralph if (!SF && !tof) 17014150Sralph (void) write(ofd, FF, strlen(FF)); 17114150Sralph if (TR != NULL) /* output trailer */ 17214150Sralph (void) write(ofd, TR, strlen(TR)); 17314150Sralph } 17412463Sralph exit(0); 17512463Sralph } 17612111Sralph goto again; 17712111Sralph } 17812111Sralph 17912111Sralph char fonts[4][50]; /* fonts for troff */ 18012111Sralph 18112111Sralph static char ifonts[4][18] = { 18212111Sralph "/usr/lib/vfont/R", 18312111Sralph "/usr/lib/vfont/I", 18412111Sralph "/usr/lib/vfont/B", 18512111Sralph "/usr/lib/vfont/S" 18612111Sralph }; 18712111Sralph 18812111Sralph /* 18912111Sralph * The remaining part is the reading of the control file (cf) 19012111Sralph * and performing the various actions. 19112111Sralph * Returns 0 if everthing was OK, 1 if we should try to reprint the job and 19212111Sralph * -1 if a non-recoverable error occured. 19312111Sralph */ 19412877Sralph static 19512111Sralph printit(file) 19612111Sralph char *file; 19712111Sralph { 19812111Sralph register int i; 19912111Sralph int bombed = 0; 20012111Sralph 20112111Sralph /* 20212111Sralph * open control file 20312111Sralph */ 20412111Sralph if ((cfp = fopen(file, "r")) == NULL) { 20512111Sralph log("control file (%s) open failure <errno = %d>", file, errno); 20612111Sralph return(0); 20712111Sralph } 20812111Sralph /* 20912111Sralph * Reset troff fonts. 21012111Sralph */ 21112111Sralph for (i = 0; i < 4; i++) 21212111Sralph strcpy(fonts[i], ifonts[i]); 21312111Sralph 21412111Sralph /* 21512111Sralph * read the control file for work to do 21612111Sralph * 21712111Sralph * file format -- first character in the line is a command 21812111Sralph * rest of the line is the argument. 21912111Sralph * valid commands are: 22012111Sralph * 22112111Sralph * J -- "job name" on banner page 22212111Sralph * C -- "class name" on banner page 22312111Sralph * L -- "literal" user's name to print on banner 22412111Sralph * T -- "title" for pr 22512111Sralph * H -- "host name" of machine where lpr was done 22612111Sralph * P -- "person" user's login name 22712581Sralph * I -- "indent" amount to indent output 22812111Sralph * f -- "file name" name of text file to print 22912111Sralph * l -- "file name" text file with control chars 23012111Sralph * p -- "file name" text file to print with pr(1) 23112111Sralph * t -- "file name" troff(1) file to print 23213233Sralph * n -- "file name" ditroff(1) file to print 23312111Sralph * d -- "file name" dvi file to print 23412111Sralph * g -- "file name" plot(1G) file to print 23512111Sralph * v -- "file name" plain raster file to print 23612111Sralph * c -- "file name" cifplot file to print 23712111Sralph * 1 -- "R font file" for troff 23812111Sralph * 2 -- "I font file" for troff 23912111Sralph * 3 -- "B font file" for troff 24012111Sralph * 4 -- "S font file" for troff 24112111Sralph * N -- "name" of file (used by lpq) 24212111Sralph * U -- "unlink" name of file to remove 24312111Sralph * (after we print it. (Pass 2 only)). 24412111Sralph * M -- "mail" to user when done printing 24512111Sralph * 24612111Sralph * getline reads a line and expands tabs to blanks 24712111Sralph */ 24812111Sralph 24912111Sralph /* pass 1 */ 25012111Sralph 25112111Sralph while (getline(cfp)) 25212111Sralph switch (line[0]) { 25312111Sralph case 'H': 25414150Sralph strcpy(fromhost, line+1); 25512111Sralph if (class[0] == '\0') 25612111Sralph strcpy(class, line+1); 25712111Sralph continue; 25812111Sralph 25912111Sralph case 'P': 26012111Sralph strcpy(logname, line+1); 26112463Sralph if (RS) { /* restricted */ 26212463Sralph if (getpwnam(logname) == (struct passwd *)0) { 26312463Sralph bombed = 2; 26412463Sralph sendmail(bombed); 26512463Sralph goto pass2; 26612463Sralph } 26712463Sralph } 26812111Sralph continue; 26912111Sralph 27012111Sralph case 'J': 27112111Sralph if (line[1] != '\0') 27212111Sralph strcpy(jobname, line+1); 27312111Sralph else 27412111Sralph strcpy(jobname, " "); 27512111Sralph continue; 27612111Sralph 27712111Sralph case 'C': 27812111Sralph if (line[1] != '\0') 27912111Sralph strcpy(class, line+1); 28012111Sralph else if (class[0] == '\0') 28112111Sralph gethostname(class, sizeof (class)); 28212111Sralph continue; 28312111Sralph 28412111Sralph case 'T': /* header title for pr */ 28512111Sralph strcpy(title, line+1); 28612111Sralph continue; 28712111Sralph 28812111Sralph case 'L': /* identification line */ 28912111Sralph if (!SH) 29012111Sralph banner(line+1, jobname); 29112111Sralph continue; 29212111Sralph 29312111Sralph case '1': /* troff fonts */ 29412111Sralph case '2': 29512111Sralph case '3': 29612111Sralph case '4': 29712111Sralph if (line[1] != '\0') 29812111Sralph strcpy(fonts[line[0]-'1'], line+1); 29912111Sralph continue; 30012111Sralph 30112111Sralph case 'W': /* page width */ 30212111Sralph strcpy(width+2, line+1); 30312111Sralph continue; 30412111Sralph 30512581Sralph case 'I': /* indent amount */ 30612581Sralph strcpy(indent+2, line+1); 30712581Sralph continue; 30812581Sralph 30912111Sralph default: /* some file to print */ 31012111Sralph if ((i = print(line[0], line+1)) > 0) { 31112111Sralph (void) fclose(cfp); 31212111Sralph return(1); 31312111Sralph } else if (i < 0) 31412111Sralph bombed = 1; 31512111Sralph title[0] = '\0'; 31612111Sralph continue; 31712111Sralph 31812111Sralph case 'N': 31912111Sralph case 'U': 32012111Sralph case 'M': 32112111Sralph continue; 32212111Sralph } 32312111Sralph 32412111Sralph /* pass 2 */ 32512111Sralph 32612463Sralph pass2: 32712111Sralph fseek(cfp, 0L, 0); 32812111Sralph while (getline(cfp)) 32912111Sralph switch (line[0]) { 33012111Sralph case 'M': 33112463Sralph if (bombed != 2) /* already sent if 2 */ 33212463Sralph sendmail(bombed); 33312111Sralph continue; 33412111Sralph 33512111Sralph case 'U': 33612111Sralph (void) unlink(line+1); 33712111Sralph } 33812111Sralph /* 33912111Sralph * clean-up incase another control file exists 34012111Sralph */ 34112111Sralph (void) fclose(cfp); 34212111Sralph (void) unlink(file); 34314150Sralph return(bombed ? -1 : 0); 34412111Sralph } 34512111Sralph 34612111Sralph /* 34712111Sralph * Print a file. 34813233Sralph * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}. 34912111Sralph * Return -1 if a non-recoverable error occured, 1 if a recoverable error and 35012111Sralph * 0 if all is well. 35112111Sralph * Note: all filters take stdin as the file, stdout as the printer, 35212111Sralph * stderr as the log file, and must not ignore SIGINT. 35312111Sralph */ 35412877Sralph static 35512111Sralph print(format, file) 35612111Sralph int format; 35712111Sralph char *file; 35812111Sralph { 35912111Sralph register int n, fi, fo; 36012111Sralph register char *prog; 36112111Sralph char *av[15], buf[BUFSIZ]; 36212111Sralph int pid, p[2], stopped = 0; 36312111Sralph union wait status; 36412111Sralph 36513148Ssam if ((fi = open(file, O_RDONLY)) < 0) { 36612111Sralph log("%s: open failure <errno = %d>", file, errno); 36712111Sralph return(-1); 36812111Sralph } 36912111Sralph if (!SF && !tof) { /* start on a fresh page */ 37012111Sralph (void) write(ofd, FF, strlen(FF)); 37112111Sralph tof = 1; 37212111Sralph } 37312111Sralph if (IF == NULL && (format == 'f' || format == 'l')) { 37412111Sralph tof = 0; 37512111Sralph while ((n = read(fi, buf, BUFSIZ)) > 0) 37612111Sralph if (write(ofd, buf, n) != n) { 37712111Sralph (void) close(fi); 37812111Sralph return(1); 37912111Sralph } 38012111Sralph (void) close(fi); 38112111Sralph return(0); 38212111Sralph } 38312111Sralph switch (format) { 38412111Sralph case 'p': /* print file using 'pr' */ 38512111Sralph if (IF == NULL) { /* use output filter */ 38612111Sralph prog = PR; 38712111Sralph av[0] = "pr"; 38812111Sralph av[1] = width; 38912111Sralph av[2] = length; 39012111Sralph av[3] = "-h"; 39112111Sralph av[4] = *title ? title : " "; 39212111Sralph av[5] = 0; 39312111Sralph fo = ofd; 39412111Sralph goto start; 39512111Sralph } 39612111Sralph pipe(p); 39712111Sralph if ((prchild = dofork(DORETURN)) == 0) { /* child */ 39812111Sralph dup2(fi, 0); /* file is stdin */ 39912111Sralph dup2(p[1], 1); /* pipe is stdout */ 40012111Sralph for (n = 3; n < NOFILE; n++) 40112111Sralph (void) close(n); 40212111Sralph execl(PR, "pr", width, length, "-h", *title ? title : " ", 0); 40312111Sralph log("cannot execl %s", PR); 40412111Sralph exit(2); 40512111Sralph } 40612111Sralph (void) close(p[1]); /* close output side */ 40712111Sralph (void) close(fi); 40812111Sralph if (prchild < 0) { 40912111Sralph prchild = 0; 41012111Sralph (void) close(p[0]); 41112111Sralph return(-1); 41212111Sralph } 41312111Sralph fi = p[0]; /* use pipe for input */ 41412111Sralph case 'f': /* print plain text file */ 41512111Sralph prog = IF; 41612111Sralph av[1] = width; 41712111Sralph av[2] = length; 41812581Sralph av[3] = indent; 41912581Sralph n = 4; 42012111Sralph break; 42112111Sralph case 'l': /* like 'f' but pass control characters */ 42212111Sralph prog = IF; 423*14325Sralph av[1] = "-c"; 42412111Sralph av[2] = width; 42512111Sralph av[3] = length; 42612581Sralph av[4] = indent; 42712581Sralph n = 5; 42812111Sralph break; 42912463Sralph case 'r': /* print a fortran text file */ 43012463Sralph prog = RF; 43112463Sralph av[1] = width; 43212463Sralph av[2] = length; 43312463Sralph n = 3; 43412463Sralph break; 43512111Sralph case 't': /* print troff output */ 43613233Sralph case 'n': /* print ditroff output */ 43712463Sralph case 'd': /* print tex output */ 43812111Sralph (void) unlink(".railmag"); 43912463Sralph if ((fo = creat(".railmag", FILMOD)) < 0) { 44012111Sralph log("cannot create .railmag"); 44112111Sralph (void) unlink(".railmag"); 44212111Sralph } else { 44312111Sralph for (n = 0; n < 4; n++) { 44412111Sralph if (fonts[n][0] != '/') 44512111Sralph (void) write(fo, "/usr/lib/vfont/", 15); 44612111Sralph (void) write(fo, fonts[n], strlen(fonts[n])); 44712111Sralph (void) write(fo, "\n", 1); 44812111Sralph } 44912111Sralph (void) close(fo); 45012111Sralph } 45113233Sralph prog = (format == 't') ? TF : (format == 'n') ? NF : DF; 45212463Sralph av[1] = pxwidth; 45312463Sralph av[2] = pxlength; 45412463Sralph n = 3; 45512111Sralph break; 45612111Sralph case 'c': /* print cifplot output */ 45712111Sralph prog = CF; 45812463Sralph av[1] = pxwidth; 45912463Sralph av[2] = pxlength; 46012463Sralph n = 3; 46112111Sralph break; 46212111Sralph case 'g': /* print plot(1G) output */ 46312111Sralph prog = GF; 46412463Sralph av[1] = pxwidth; 46512463Sralph av[2] = pxlength; 46612463Sralph n = 3; 46712111Sralph break; 46812111Sralph case 'v': /* print raster output */ 46912111Sralph prog = VF; 47012463Sralph av[1] = pxwidth; 47112463Sralph av[2] = pxlength; 47212463Sralph n = 3; 47312111Sralph break; 47412111Sralph default: 47512111Sralph (void) close(fi); 47612111Sralph log("illegal format character '%c'", format); 47712111Sralph return(-1); 47812111Sralph } 47912111Sralph if ((av[0] = rindex(prog, '/')) != NULL) 48012111Sralph av[0]++; 48112111Sralph else 48212111Sralph av[0] = prog; 48312111Sralph av[n++] = "-n"; 48412111Sralph av[n++] = logname; 48512111Sralph av[n++] = "-h"; 48614150Sralph av[n++] = fromhost; 48712111Sralph av[n++] = AF; 48812111Sralph av[n] = 0; 48912111Sralph fo = pfd; 49012111Sralph if (ofilter > 0) { /* stop output filter */ 49112111Sralph write(ofd, "\031\1", 2); 49212111Sralph while ((pid = wait3(&status, WUNTRACED, 0)) > 0 && pid != ofilter) 49312111Sralph ; 49412111Sralph if (status.w_stopval != WSTOPPED) { 49512111Sralph (void) close(fi); 49612111Sralph log("output filter died (%d)", status.w_retcode); 49712111Sralph return(1); 49812111Sralph } 49912111Sralph stopped++; 50012111Sralph } 50112111Sralph start: 50212111Sralph if ((child = dofork(DORETURN)) == 0) { /* child */ 50312111Sralph dup2(fi, 0); 50412111Sralph dup2(fo, 1); 50512111Sralph for (n = 3; n < NOFILE; n++) 50612111Sralph (void) close(n); 50712111Sralph execv(prog, av); 50812111Sralph log("cannot execl %s", prog); 50912111Sralph exit(2); 51012111Sralph } 51112111Sralph (void) close(fi); 51212111Sralph if (child < 0) 51312111Sralph status.w_retcode = 100; 51412111Sralph else 51512111Sralph while ((pid = wait(&status)) > 0 && pid != child) 51612111Sralph ; 51712111Sralph child = 0; 51812111Sralph prchild = 0; 51912111Sralph if (stopped) { /* restart output filter */ 52012111Sralph if (kill(ofilter, SIGCONT) < 0) { 52112111Sralph log("cannot restart output filter"); 52212111Sralph exit(1); 52312111Sralph } 52412111Sralph } 52512111Sralph tof = 0; 52612111Sralph if (!WIFEXITED(status) || status.w_retcode > 1) { 52712111Sralph log("Daemon Filter '%c' Malfunction (%d)", format, status.w_retcode); 52812111Sralph return(-1); 52912111Sralph } else if (status.w_retcode == 1) 53012111Sralph return(1); 53112111Sralph tof = 1; 53212111Sralph return(0); 53312111Sralph } 53412111Sralph 53512111Sralph /* 53612111Sralph * Send the daemon control file (cf) and any data files. 53712111Sralph * Return -1 if a non-recoverable error occured, 1 if a recoverable error and 53812111Sralph * 0 if all is well. 53912111Sralph */ 54012877Sralph static 54112111Sralph sendit(file) 54212111Sralph char *file; 54312111Sralph { 54412111Sralph register int linelen, err = 0; 54512111Sralph char last[132]; 54612111Sralph 54712111Sralph /* 54812111Sralph * open control file 54912111Sralph */ 55012111Sralph if ((cfp = fopen(file, "r")) == NULL) { 55112111Sralph log("control file (%s) open failure <errno = %d>", file, errno); 55212111Sralph return(0); 55312111Sralph } 55412111Sralph /* 55512111Sralph * read the control file for work to do 55612111Sralph * 55712111Sralph * file format -- first character in the line is a command 55812111Sralph * rest of the line is the argument. 55912111Sralph * commands of interest are: 56012111Sralph * 56112111Sralph * a-z -- "file name" name of file to print 56212111Sralph * U -- "unlink" name of file to remove 56312111Sralph * (after we print it. (Pass 2 only)). 56412111Sralph */ 56512111Sralph 56612111Sralph /* 56712111Sralph * pass 1 56812111Sralph */ 56912111Sralph while (getline(cfp)) { 57012111Sralph again: 57112111Sralph if (line[0] >= 'a' && line[0] <= 'z') { 57212111Sralph strcpy(last, line); 57312111Sralph while (linelen = getline(cfp)) 57412111Sralph if (strcmp(last, line)) 57512111Sralph break; 57612111Sralph if ((err = sendfile('\3', last+1)) > 0) { 57712111Sralph (void) fclose(cfp); 57812111Sralph return(1); 57912111Sralph } else if (err) 58012111Sralph break; 58112111Sralph if (linelen) 58212111Sralph goto again; 58312111Sralph break; 58412111Sralph } 58512111Sralph } 58612111Sralph if (!err && sendfile('\2', file) > 0) { 58712111Sralph (void) fclose(cfp); 58812111Sralph return(1); 58912111Sralph } 59012111Sralph /* 59112111Sralph * pass 2 59212111Sralph */ 59312111Sralph fseek(cfp, 0L, 0); 59412111Sralph while (getline(cfp)) 59512111Sralph if (line[0] == 'U') 59612111Sralph (void) unlink(line+1); 59712111Sralph /* 59812111Sralph * clean-up incase another control file exists 59912111Sralph */ 60012111Sralph (void) fclose(cfp); 60112111Sralph (void) unlink(file); 60212111Sralph return(0); 60312111Sralph } 60412111Sralph 60512111Sralph /* 60612111Sralph * Send a data file to the remote machine and spool it. 60712111Sralph * Return positive if we should try resending. 60812111Sralph */ 60912877Sralph static 61012111Sralph sendfile(type, file) 61112111Sralph char type, *file; 61212111Sralph { 61312111Sralph register int f, i, amt; 61412111Sralph struct stat stb; 61512111Sralph char buf[BUFSIZ]; 61612111Sralph int sizerr; 61712111Sralph 61813148Ssam if ((f = open(file, O_RDONLY)) < 0 || fstat(f, &stb) < 0) { 61912111Sralph log("file (%s) open failure <errno = %d>", file, errno); 62012111Sralph return(-1); 62112111Sralph } 62212111Sralph (void) sprintf(buf, "%c%d %s\n", type, stb.st_size, file); 62312111Sralph amt = strlen(buf); 62412692Sralph if (write(pfd, buf, amt) != amt) { 62512692Sralph (void) close(f); 62612111Sralph return(1); 62712692Sralph } 62812692Sralph if (noresponse()) { 62912692Sralph (void) close(f); 63012111Sralph return(1); 63112692Sralph } 63212111Sralph sizerr = 0; 63312111Sralph for (i = 0; i < stb.st_size; i += BUFSIZ) { 63412111Sralph amt = BUFSIZ; 63512111Sralph if (i + amt > stb.st_size) 63612111Sralph amt = stb.st_size - i; 63712111Sralph if (sizerr == 0 && read(f, buf, amt) != amt) 63812111Sralph sizerr = 1; 63912692Sralph if (write(pfd, buf, amt) != amt) { 64012692Sralph (void) close(f); 64112111Sralph return(1); 64212692Sralph } 64312111Sralph } 64412111Sralph (void) close(f); 64512111Sralph if (sizerr) { 64612111Sralph log("%s: changed size", file); 64712111Sralph (void) write(pfd, "\1", 1); /* tell recvjob to ignore this file */ 64812111Sralph return(-1); 64912111Sralph } 65012111Sralph if (write(pfd, "", 1) != 1) 65112111Sralph return(1); 65212111Sralph if (noresponse()) 65312111Sralph return(1); 65412111Sralph return(0); 65512111Sralph } 65612111Sralph 65712111Sralph /* 65812111Sralph * Check to make sure there have been no errors and that both programs 65912111Sralph * are in sync with eachother. 66012111Sralph * Return non-zero if the connection was lost. 66112111Sralph */ 66212111Sralph static 66312111Sralph noresponse() 66412111Sralph { 66512111Sralph char resp; 66612111Sralph 66712111Sralph if (read(pfd, &resp, 1) != 1 || resp != '\0') { 66812111Sralph log("lost connection or error in recvjob"); 66912111Sralph return(1); 67012111Sralph } 67112111Sralph return(0); 67212111Sralph } 67312111Sralph 67412111Sralph /* 67512111Sralph * Banner printing stuff 67612111Sralph */ 67712877Sralph static 67812111Sralph banner(name1, name2) 67912111Sralph char *name1, *name2; 68012111Sralph { 68112111Sralph time_t tvec; 68212111Sralph extern char *ctime(); 68312111Sralph 68412111Sralph time(&tvec); 68512111Sralph if (!SF && !tof) 68612111Sralph (void) write(ofd, FF, strlen(FF)); 68712111Sralph if (SB) { /* short banner only */ 68812111Sralph if (class[0]) { 68912111Sralph (void) write(ofd, class, strlen(class)); 69012111Sralph (void) write(ofd, ":", 1); 69112111Sralph } 69212111Sralph (void) write(ofd, name1, strlen(name1)); 69312111Sralph (void) write(ofd, " Job: ", 7); 69412111Sralph (void) write(ofd, name2, strlen(name2)); 69512111Sralph (void) write(ofd, " Date: ", 8); 69612111Sralph (void) write(ofd, ctime(&tvec), 24); 69712111Sralph (void) write(ofd, "\n", 1); 69812111Sralph } else { /* normal banner */ 69912111Sralph (void) write(ofd, "\n\n\n", 3); 70012111Sralph scan_out(ofd, name1, '\0'); 70112111Sralph (void) write(ofd, "\n\n", 2); 70212111Sralph scan_out(ofd, name2, '\0'); 70312111Sralph if (class[0]) { 70412111Sralph (void) write(ofd,"\n\n\n",3); 70512111Sralph scan_out(ofd, class, '\0'); 70612111Sralph } 70712111Sralph (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15); 70812111Sralph (void) write(ofd, name2, strlen(name2)); 70912111Sralph (void) write(ofd, "\n\t\t\t\t\tDate: ", 12); 71012111Sralph (void) write(ofd, ctime(&tvec), 24); 71112111Sralph (void) write(ofd, "\n", 1); 71212111Sralph } 71312111Sralph if (!SF) 71412111Sralph (void) write(ofd, FF, strlen(FF)); 71512111Sralph tof = 1; 71612111Sralph } 71712111Sralph 71812877Sralph static char * 71912111Sralph scnline(key, p, c) 72012111Sralph register char key, *p; 72112111Sralph char c; 72212111Sralph { 72312111Sralph register scnwidth; 72412111Sralph 72512111Sralph for (scnwidth = WIDTH; --scnwidth;) { 72612111Sralph key <<= 1; 72712111Sralph *p++ = key & 0200 ? c : BACKGND; 72812111Sralph } 72912111Sralph return (p); 73012111Sralph } 73112111Sralph 73212111Sralph #define TRC(q) (((q)-' ')&0177) 73312111Sralph 73412877Sralph static 73512111Sralph scan_out(scfd, scsp, dlm) 73612111Sralph int scfd; 73712111Sralph char *scsp, dlm; 73812111Sralph { 73912111Sralph register char *strp; 74012111Sralph register nchrs, j; 74112111Sralph char outbuf[LINELEN+1], *sp, c, cc; 74212111Sralph int d, scnhgt; 74312111Sralph extern char scnkey[][HEIGHT]; /* in lpdchar.c */ 74412111Sralph 74512111Sralph for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) { 74612111Sralph strp = &outbuf[0]; 74712111Sralph sp = scsp; 74812111Sralph for (nchrs = 0; ; ) { 74912111Sralph d = dropit(c = TRC(cc = *sp++)); 75012111Sralph if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d)) 75112111Sralph for (j = WIDTH; --j;) 75212111Sralph *strp++ = BACKGND; 75312111Sralph else 75412111Sralph strp = scnline(scnkey[c][scnhgt-1-d], strp, cc); 75512111Sralph if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1) 75612111Sralph break; 75712111Sralph *strp++ = BACKGND; 75812111Sralph *strp++ = BACKGND; 75912111Sralph } 76012111Sralph while (*--strp == BACKGND && strp >= outbuf) 76112111Sralph ; 76212111Sralph strp++; 76312111Sralph *strp++ = '\n'; 76412111Sralph (void) write(scfd, outbuf, strp-outbuf); 76512111Sralph } 76612111Sralph } 76712111Sralph 76812877Sralph static 76912111Sralph dropit(c) 77012111Sralph char c; 77112111Sralph { 77212111Sralph switch(c) { 77312111Sralph 77412111Sralph case TRC('_'): 77512111Sralph case TRC(';'): 77612111Sralph case TRC(','): 77712111Sralph case TRC('g'): 77812111Sralph case TRC('j'): 77912111Sralph case TRC('p'): 78012111Sralph case TRC('q'): 78112111Sralph case TRC('y'): 78212111Sralph return (DROP); 78312111Sralph 78412111Sralph default: 78512111Sralph return (0); 78612111Sralph } 78712111Sralph } 78812111Sralph 78912111Sralph /* 79012111Sralph * sendmail --- 79112111Sralph * tell people about job completion 79212111Sralph */ 79312877Sralph static 79412111Sralph sendmail(bombed) 79512111Sralph int bombed; 79612111Sralph { 79712111Sralph static int p[2]; 79812111Sralph register int i; 79912111Sralph int stat; 80012111Sralph register char *cp; 80112111Sralph char buf[100]; 80212111Sralph 80312111Sralph pipe(p); 80412111Sralph if ((stat = dofork(DORETURN)) == 0) { /* child */ 80512111Sralph dup2(p[0], 0); 80612111Sralph for (i = 3; i < NOFILE; i++) 80712111Sralph (void) close(i); 80812111Sralph if ((cp = rindex(MAIL, '/')) != NULL) 80912111Sralph cp++; 81012111Sralph else 81112111Sralph cp = MAIL; 81214150Sralph sprintf(buf, "%s@%s", line+1, fromhost); 81312111Sralph execl(MAIL, cp, buf, 0); 81412111Sralph exit(0); 81512111Sralph } else if (stat > 0) { /* parent */ 81612111Sralph dup2(p[1], 1); 81714150Sralph printf("To: %s@%s\n", line+1, fromhost); 81812111Sralph printf("Subject: printer job\n\n"); 81912111Sralph printf("Your printer job "); 82012111Sralph if (*jobname) 82112111Sralph printf("(%s) ", jobname); 82212463Sralph switch (bombed) { 82312463Sralph case 0: 82412463Sralph printf("\ncompleted successfully\n"); 82512463Sralph break; 82612463Sralph default: 82712463Sralph case 1: 82812463Sralph printf("\ncould not be printed\n"); 82912463Sralph break; 83012463Sralph case 2: 83112463Sralph printf("\ncould not be printed without an account on %s\n", host); 83212463Sralph break; 83312463Sralph } 83412111Sralph fflush(stdout); 83512111Sralph (void) close(1); 83612111Sralph } 83712111Sralph (void) close(p[0]); 83812111Sralph (void) close(p[1]); 83912111Sralph wait(&stat); 84012111Sralph } 84112111Sralph 84212111Sralph /* 84312111Sralph * dofork - fork with retries on failure 84412111Sralph */ 84512877Sralph static 84612111Sralph dofork(action) 84712111Sralph int action; 84812111Sralph { 84912111Sralph register int i, pid; 85012111Sralph 85112111Sralph for (i = 0; i < 20; i++) { 85212463Sralph if ((pid = fork()) < 0) { 85312111Sralph sleep((unsigned)(i*i)); 85412463Sralph continue; 85512463Sralph } 85612463Sralph /* 85712463Sralph * Child should run as daemon instead of root 85812463Sralph */ 85912463Sralph if (pid == 0) 86012463Sralph setuid(DU); 86112463Sralph return(pid); 86212111Sralph } 86312111Sralph log("can't fork"); 86412111Sralph 86512111Sralph switch (action) { 86612111Sralph case DORETURN: 86712111Sralph return (-1); 86812111Sralph default: 86912111Sralph log("bad action (%d) to dofork", action); 87012111Sralph /*FALL THRU*/ 87112111Sralph case DOABORT: 87212111Sralph exit(1); 87312111Sralph } 87412111Sralph /*NOTREACHED*/ 87512111Sralph } 87612111Sralph 87712111Sralph /* 87812111Sralph * Cleanup child processes when a SIGINT is caught. 87912111Sralph */ 88012877Sralph static 88112111Sralph onintr() 88212111Sralph { 88312111Sralph kill(0, SIGINT); 88412111Sralph if (ofilter > 0) 88512111Sralph kill(ofilter, SIGCONT); 88612111Sralph while (wait(0) > 0) 88712111Sralph ; 88812111Sralph exit(0); 88912111Sralph } 89012111Sralph 89112877Sralph static 89212111Sralph init() 89312111Sralph { 89412111Sralph int status; 89512111Sralph 89613169Sralph if ((status = pgetent(line, printer)) < 0) 89713169Sralph fatal("can't open printer description file"); 89813169Sralph else if (status == 0) 89913169Sralph fatal("unknown printer"); 90012111Sralph if ((LP = pgetstr("lp", &bp)) == NULL) 90112111Sralph LP = DEFDEVLP; 90212111Sralph if ((RP = pgetstr("rp", &bp)) == NULL) 90312463Sralph RP = DEFLP; 90412111Sralph if ((LO = pgetstr("lo", &bp)) == NULL) 90512111Sralph LO = DEFLOCK; 90612111Sralph if ((ST = pgetstr("st", &bp)) == NULL) 90712111Sralph ST = DEFSTAT; 90812111Sralph if ((LF = pgetstr("lf", &bp)) == NULL) 90912111Sralph LF = DEFLOGF; 91012111Sralph if ((SD = pgetstr("sd", &bp)) == NULL) 91112111Sralph SD = DEFSPOOL; 91212111Sralph if ((DU = pgetnum("du")) < 0) 91312111Sralph DU = DEFUID; 91412111Sralph if ((FF = pgetstr("ff", &bp)) == NULL) 91512111Sralph FF = DEFFF; 91612111Sralph if ((PW = pgetnum("pw")) < 0) 91712111Sralph PW = DEFWIDTH; 91812111Sralph sprintf(&width[2], "%d", PW); 91912111Sralph if ((PL = pgetnum("pl")) < 0) 92012111Sralph PL = DEFLENGTH; 92112111Sralph sprintf(&length[2], "%d", PL); 92212463Sralph if ((PX = pgetnum("px")) < 0) 92312463Sralph PX = 0; 92412463Sralph sprintf(&pxwidth[2], "%d", PX); 92512463Sralph if ((PY = pgetnum("py")) < 0) 92612463Sralph PY = 0; 92712463Sralph sprintf(&pxlength[2], "%d", PY); 92812111Sralph RM = pgetstr("rm", &bp); 92912111Sralph AF = pgetstr("af", &bp); 93012111Sralph OF = pgetstr("of", &bp); 93112111Sralph IF = pgetstr("if", &bp); 93212463Sralph RF = pgetstr("rf", &bp); 93312111Sralph TF = pgetstr("tf", &bp); 93413233Sralph NF = pgetstr("nf", &bp); 93512111Sralph DF = pgetstr("df", &bp); 93612111Sralph GF = pgetstr("gf", &bp); 93712111Sralph VF = pgetstr("vf", &bp); 93812111Sralph CF = pgetstr("cf", &bp); 93912111Sralph TR = pgetstr("tr", &bp); 94012463Sralph RS = pgetflag("rs"); 94112111Sralph SF = pgetflag("sf"); 94212111Sralph SH = pgetflag("sh"); 94312111Sralph SB = pgetflag("sb"); 94412111Sralph RW = pgetflag("rw"); 94512111Sralph BR = pgetnum("br"); 94612111Sralph if ((FC = pgetnum("fc")) < 0) 94712111Sralph FC = 0; 94812111Sralph if ((FS = pgetnum("fs")) < 0) 94912111Sralph FS = 0; 95012111Sralph if ((XC = pgetnum("xc")) < 0) 95112111Sralph XC = 0; 95212111Sralph if ((XS = pgetnum("xs")) < 0) 95312111Sralph XS = 0; 95412581Sralph tof = !pgetflag("fo"); 95512111Sralph } 95612111Sralph 95712463Sralph /* 95812463Sralph * Acquire line printer or remote connection. 95912463Sralph */ 96012877Sralph static 96112463Sralph openpr() 96212463Sralph { 96312463Sralph register int i, n; 96412463Sralph 96512463Sralph if (*LP) { 96612463Sralph for (i = 1; ; i = i < 32 ? i << 1 : i) { 96713148Ssam pfd = open(LP, RW ? O_RDWR : O_WRONLY); 96812463Sralph if (pfd >= 0) 96912463Sralph break; 97012463Sralph if (errno == ENOENT) { 97112463Sralph log("cannot open %s", LP); 97212463Sralph exit(1); 97312463Sralph } 97412463Sralph if (i == 1) 97512463Sralph status("waiting for %s to become ready (offline ?)", printer); 97612463Sralph sleep(i); 97712463Sralph } 97812463Sralph if (isatty(pfd)) 97912463Sralph setty(); 98012463Sralph status("%s is ready and printing", printer); 98112463Sralph } else if (RM != NULL) { 98212463Sralph for (i = 1; ; i = i < 512 ? i << 1 : i) { 98312528Sralph pfd = getport(RM); 98412463Sralph if (pfd >= 0) { 98512463Sralph (void) sprintf(line, "\2%s\n", RP); 98612463Sralph n = strlen(line); 98712463Sralph if (write(pfd, line, n) != n) 98812463Sralph break; 98912463Sralph if (noresponse()) 99012463Sralph (void) close(pfd); 99112463Sralph else 99212463Sralph break; 99312463Sralph } 99412463Sralph if (i == 1) 99512463Sralph status("waiting for %s to come up", RM); 99612463Sralph sleep(i); 99712463Sralph } 99812463Sralph status("sending to %s", RM); 99912463Sralph remote = 1; 100012463Sralph } else { 100112463Sralph log("no line printer device or remote machine name"); 100212463Sralph exit(1); 100312463Sralph } 100412463Sralph /* 100512463Sralph * Start up an output filter, if needed. 100612463Sralph */ 100712463Sralph if (OF) { 100812463Sralph int p[2]; 100912463Sralph char *cp; 101012463Sralph 101112463Sralph pipe(p); 101212463Sralph if ((ofilter = dofork(DOABORT)) == 0) { /* child */ 101312463Sralph dup2(p[0], 0); /* pipe is std in */ 101412463Sralph dup2(pfd, 1); /* printer is std out */ 101512463Sralph for (i = 3; i < NOFILE; i++) 101612463Sralph (void) close(i); 101712463Sralph if ((cp = rindex(OF, '/')) == NULL) 101812463Sralph cp = OF; 101912463Sralph else 102012463Sralph cp++; 102112463Sralph execl(OF, cp, width, length, 0); 102212463Sralph log("can't execl output filter %s", OF); 102312463Sralph exit(1); 102412463Sralph } 102512463Sralph (void) close(p[0]); /* close input side */ 102612463Sralph ofd = p[1]; /* use pipe for output */ 102712463Sralph } else { 102812463Sralph ofd = pfd; 102912463Sralph ofilter = 0; 103012463Sralph } 103112463Sralph } 103212463Sralph 103312111Sralph struct bauds { 103412111Sralph int baud; 103512111Sralph int speed; 103612111Sralph } bauds[] = { 103712111Sralph 50, B50, 103812111Sralph 75, B75, 103912111Sralph 110, B110, 104012111Sralph 134, B134, 104112111Sralph 150, B150, 104212111Sralph 200, B200, 104312111Sralph 300, B300, 104412111Sralph 600, B600, 104512111Sralph 1200, B1200, 104612111Sralph 1800, B1800, 104712111Sralph 2400, B2400, 104812111Sralph 4800, B4800, 104912111Sralph 9600, B9600, 105012111Sralph 19200, EXTA, 105112111Sralph 38400, EXTB, 105212111Sralph 0, 0 105312111Sralph }; 105412111Sralph 105512111Sralph /* 105612111Sralph * setup tty lines. 105712111Sralph */ 105812877Sralph static 105912111Sralph setty() 106012111Sralph { 106112111Sralph struct sgttyb ttybuf; 106212111Sralph register struct bauds *bp; 106312111Sralph 106412111Sralph if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) { 106512111Sralph log("cannot set exclusive-use"); 106612111Sralph exit(1); 106712111Sralph } 106812111Sralph if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) { 106912111Sralph log("cannot get tty parameters"); 107012111Sralph exit(1); 107112111Sralph } 107212111Sralph if (BR > 0) { 107312111Sralph for (bp = bauds; bp->baud; bp++) 107412111Sralph if (BR == bp->baud) 107512111Sralph break; 107612111Sralph if (!bp->baud) { 107712111Sralph log("illegal baud rate %d", BR); 107812111Sralph exit(1); 107912111Sralph } 108012111Sralph ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed; 108112111Sralph } 108213169Sralph ttybuf.sg_flags &= ~FC; 108313169Sralph ttybuf.sg_flags |= FS; 108412111Sralph if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) { 108512111Sralph log("cannot set tty parameters"); 108612111Sralph exit(1); 108712111Sralph } 108812111Sralph if (XC) { 108912111Sralph if (ioctl(pfd, TIOCLBIC, &XC) < 0) { 109012111Sralph log("cannot set local tty parameters"); 109112111Sralph exit(1); 109212111Sralph } 109312111Sralph } 109412111Sralph if (XS) { 109512111Sralph if (ioctl(pfd, TIOCLBIS, &XS) < 0) { 109612111Sralph log("cannot set local tty parameters"); 109712111Sralph exit(1); 109812111Sralph } 109912111Sralph } 110012111Sralph } 110112463Sralph 110212463Sralph /*VARARGS1*/ 110312463Sralph static 110412463Sralph status(msg, a1, a2, a3) 110512463Sralph char *msg; 110612463Sralph { 110712463Sralph register int fd; 110812463Sralph char buf[BUFSIZ]; 110912463Sralph 111012463Sralph umask(0); 111113148Ssam fd = open(ST, O_WRONLY|O_CREAT, 0664); 111213148Ssam if (fd < 0 || flock(fd, LOCK_EX) < 0) 111312463Sralph fatal("cannot create status file"); 111413148Ssam ftruncate(fd, 0); 111512463Sralph sprintf(buf, msg, a1, a2, a3); 111612463Sralph strcat(buf, "\n"); 111712463Sralph (void) write(fd, buf, strlen(buf)); 111812463Sralph (void) close(fd); 111912463Sralph } 1120