1*12111Sralph /* printjob.c 4.1 83/04/29 */ 2*12111Sralph /* 3*12111Sralph * printjob -- print jobs in the queue. 4*12111Sralph * 5*12111Sralph * NOTE: the lock file is used to pass information to lpq and lprm. 6*12111Sralph * it does not need to be removed because file locks are dynamic. 7*12111Sralph */ 8*12111Sralph 9*12111Sralph #include "lp.h" 10*12111Sralph 11*12111Sralph #define DORETURN 0 /* absorb fork error */ 12*12111Sralph #define DOABORT 1 /* abort if dofork fails */ 13*12111Sralph 14*12111Sralph char title[80]; /* ``pr'' title */ 15*12111Sralph FILE *cfp; /* control file */ 16*12111Sralph int pfd; /* printer file descriptor */ 17*12111Sralph int ofd; /* output filter file descriptor */ 18*12111Sralph int lfd; /* lock file descriptor */ 19*12111Sralph int pid; /* pid of lpd process */ 20*12111Sralph int prchild; /* id of pr process */ 21*12111Sralph int child; /* id of any filters */ 22*12111Sralph int ofilter; /* id of output filter, if any */ 23*12111Sralph int tof = 1; /* top of form; init true if open does ff */ 24*12111Sralph int remote; /* non zero if sending files to remote */ 25*12111Sralph 26*12111Sralph extern banner(); /* big character printer */ 27*12111Sralph char logname[32]; /* user's login name */ 28*12111Sralph char jobname[32]; /* job or file name */ 29*12111Sralph char class[32]; /* classification field */ 30*12111Sralph char width[10] = "-w"; /* page width for `pr' */ 31*12111Sralph char length[10] = "-l"; /* page length for `pr' */ 32*12111Sralph 33*12111Sralph printjob() 34*12111Sralph { 35*12111Sralph struct stat stb; 36*12111Sralph register struct queue *q, **qp; 37*12111Sralph struct queue **queue; 38*12111Sralph register int i, nitems; 39*12111Sralph long pidoff; 40*12111Sralph extern int onintr(); 41*12111Sralph 42*12111Sralph name = "printjob"; 43*12111Sralph init(); /* set up capabilities */ 44*12111Sralph (void) close(2); /* set up log file */ 45*12111Sralph (void) open(LF, FWRONLY|FAPPEND, 0); 46*12111Sralph dup2(2, 1); 47*12111Sralph pid = getpid(); 48*12111Sralph setpgrp(0, pid); 49*12111Sralph sigset(SIGINT, onintr); /* for use with lprm */ 50*12111Sralph 51*12111Sralph /* 52*12111Sralph * uses short form file names 53*12111Sralph */ 54*12111Sralph if (chdir(SD) < 0) { 55*12111Sralph log("cannot chdir to %s", SD); 56*12111Sralph exit(1); 57*12111Sralph } 58*12111Sralph if ((lfd = open(LO, FWRONLY|FCREATE|FTRUNCATE|FEXLOCK|FNBLOCK, 0664)) < 0) { 59*12111Sralph if (errno == EWOULDBLOCK) /* active deamon present */ 60*12111Sralph exit(0); 61*12111Sralph log("cannot create %s", LO); 62*12111Sralph exit(1); 63*12111Sralph } 64*12111Sralph /* 65*12111Sralph * write process id for others to know 66*12111Sralph */ 67*12111Sralph sprintf(line, "%u\n", pid); 68*12111Sralph pidoff = i = strlen(line); 69*12111Sralph if (write(lfd, line, i) != i) 70*12111Sralph log("cannot write daemon pid"); 71*12111Sralph /* 72*12111Sralph * acquire line printer or remote connection 73*12111Sralph */ 74*12111Sralph restart: 75*12111Sralph if (*LP) { 76*12111Sralph for (i = 1; ; i = i < 32 ? i << 1 : i) { 77*12111Sralph pfd = open(LP, RW ? FRDWR : FWRONLY, 0); 78*12111Sralph if (pfd >= 0) 79*12111Sralph break; 80*12111Sralph if (errno == ENOENT) { 81*12111Sralph log("cannot open %s", LP); 82*12111Sralph exit(1); 83*12111Sralph } 84*12111Sralph if (i == 1) 85*12111Sralph status("waiting for %s to become ready (offline ?)", printer); 86*12111Sralph sleep(i); 87*12111Sralph } 88*12111Sralph if (isatty(pfd)) 89*12111Sralph setty(); 90*12111Sralph status("%s is ready and printing", printer); 91*12111Sralph } else if (RM != NULL) { 92*12111Sralph for (i = 1; ; i = i < 512 ? i << 1 : i) { 93*12111Sralph pfd = getport(); 94*12111Sralph if (pfd >= 0) { 95*12111Sralph (void) sprintf(line, "\2%s\n", RP); 96*12111Sralph nitems = strlen(line); 97*12111Sralph if (write(pfd, line, nitems) != nitems) 98*12111Sralph break; 99*12111Sralph if (noresponse()) 100*12111Sralph (void) close(pfd); 101*12111Sralph else 102*12111Sralph break; 103*12111Sralph } 104*12111Sralph if (i == 1) 105*12111Sralph status("waiting for %s to come up", RM); 106*12111Sralph sleep(i); 107*12111Sralph } 108*12111Sralph status("sending to %s", RM); 109*12111Sralph remote = 1; 110*12111Sralph } else { 111*12111Sralph log("no line printer device or remote machine name"); 112*12111Sralph exit(1); 113*12111Sralph } 114*12111Sralph /* 115*12111Sralph * Start running as daemon instead of root 116*12111Sralph */ 117*12111Sralph setuid(DU); 118*12111Sralph /* 119*12111Sralph * Start up an output filter, if needed. 120*12111Sralph */ 121*12111Sralph if (OF) { 122*12111Sralph int p[2]; 123*12111Sralph char *cp; 124*12111Sralph 125*12111Sralph pipe(p); 126*12111Sralph if ((ofilter = dofork(DOABORT)) == 0) { /* child */ 127*12111Sralph dup2(p[0], 0); /* pipe is std in */ 128*12111Sralph dup2(pfd, 1); /* printer is std out */ 129*12111Sralph for (i = 3; i < NOFILE; i++) 130*12111Sralph (void) close(i); 131*12111Sralph if ((cp = rindex(OF, '/')) == NULL) 132*12111Sralph cp = OF; 133*12111Sralph else 134*12111Sralph cp++; 135*12111Sralph execl(OF, cp, 0); 136*12111Sralph log("can't execl output filter %s", OF); 137*12111Sralph exit(1); 138*12111Sralph } 139*12111Sralph (void) close(p[0]); /* close input side */ 140*12111Sralph ofd = p[1]; /* use pipe for output */ 141*12111Sralph } else { 142*12111Sralph ofd = pfd; 143*12111Sralph ofilter = 0; 144*12111Sralph } 145*12111Sralph 146*12111Sralph /* 147*12111Sralph * search the spool directory for work and sort by queue order. 148*12111Sralph */ 149*12111Sralph again: 150*12111Sralph if ((nitems = getq(&queue)) < 0) { 151*12111Sralph log("can't scan spool directory %s", SD); 152*12111Sralph exit(1); 153*12111Sralph } 154*12111Sralph if (nitems == 0) { /* EOF => no work to do */ 155*12111Sralph if (!SF && !tof) 156*12111Sralph (void) write(ofd, FF, strlen(FF)); 157*12111Sralph if (TR != NULL) /* output trailer */ 158*12111Sralph (void) write(ofd, TR, strlen(TR)); 159*12111Sralph exit(0); 160*12111Sralph } 161*12111Sralph 162*12111Sralph /* 163*12111Sralph * we found something to do now do it -- 164*12111Sralph * write the name of the current control file into the lock file 165*12111Sralph * so the spool queue program can tell what we're working on 166*12111Sralph */ 167*12111Sralph for (qp = queue; nitems--; free((char *) q)) { 168*12111Sralph q = *qp++; 169*12111Sralph if (stat(q->q_name, &stb) < 0) 170*12111Sralph continue; 171*12111Sralph (void) lseek(lfd, pidoff, 0); 172*12111Sralph (void) sprintf(line, "%s\n", q->q_name); 173*12111Sralph i = strlen(line); 174*12111Sralph if (write(lfd, line, i) != i) 175*12111Sralph log("can't write (%d) control file name", errno); 176*12111Sralph if (!remote) 177*12111Sralph i = printit(q->q_name); 178*12111Sralph else 179*12111Sralph i = sendit(q->q_name); 180*12111Sralph if (i > 0) { /* restart daemon to reprint job */ 181*12111Sralph log("restarting"); 182*12111Sralph if (ofilter > 0) { 183*12111Sralph kill(ofilter, SIGCONT); /* to be sure */ 184*12111Sralph (void) close(ofd); 185*12111Sralph while ((i = wait(0)) > 0 && i != ofilter) 186*12111Sralph ; 187*12111Sralph ofilter = 0; 188*12111Sralph } 189*12111Sralph (void) close(pfd); 190*12111Sralph free((char *) q); 191*12111Sralph while (nitems--) 192*12111Sralph free((char *) *qp++); 193*12111Sralph free((char *) queue); 194*12111Sralph goto restart; 195*12111Sralph } 196*12111Sralph } 197*12111Sralph free((char *) queue); 198*12111Sralph goto again; 199*12111Sralph } 200*12111Sralph 201*12111Sralph char fonts[4][50]; /* fonts for troff */ 202*12111Sralph 203*12111Sralph static char ifonts[4][18] = { 204*12111Sralph "/usr/lib/vfont/R", 205*12111Sralph "/usr/lib/vfont/I", 206*12111Sralph "/usr/lib/vfont/B", 207*12111Sralph "/usr/lib/vfont/S" 208*12111Sralph }; 209*12111Sralph 210*12111Sralph /* 211*12111Sralph * The remaining part is the reading of the control file (cf) 212*12111Sralph * and performing the various actions. 213*12111Sralph * Returns 0 if everthing was OK, 1 if we should try to reprint the job and 214*12111Sralph * -1 if a non-recoverable error occured. 215*12111Sralph */ 216*12111Sralph printit(file) 217*12111Sralph char *file; 218*12111Sralph { 219*12111Sralph register int i; 220*12111Sralph int bombed = 0; 221*12111Sralph 222*12111Sralph /* 223*12111Sralph * open control file 224*12111Sralph */ 225*12111Sralph if ((cfp = fopen(file, "r")) == NULL) { 226*12111Sralph log("control file (%s) open failure <errno = %d>", file, errno); 227*12111Sralph return(0); 228*12111Sralph } 229*12111Sralph /* 230*12111Sralph * Reset troff fonts. 231*12111Sralph */ 232*12111Sralph for (i = 0; i < 4; i++) 233*12111Sralph strcpy(fonts[i], ifonts[i]); 234*12111Sralph 235*12111Sralph /* 236*12111Sralph * read the control file for work to do 237*12111Sralph * 238*12111Sralph * file format -- first character in the line is a command 239*12111Sralph * rest of the line is the argument. 240*12111Sralph * valid commands are: 241*12111Sralph * 242*12111Sralph * J -- "job name" on banner page 243*12111Sralph * C -- "class name" on banner page 244*12111Sralph * L -- "literal" user's name to print on banner 245*12111Sralph * T -- "title" for pr 246*12111Sralph * H -- "host name" of machine where lpr was done 247*12111Sralph * P -- "person" user's login name 248*12111Sralph * I -- "indent" changes default indents driver 249*12111Sralph * must have stty/gtty avaialble 250*12111Sralph * f -- "file name" name of text file to print 251*12111Sralph * l -- "file name" text file with control chars 252*12111Sralph * p -- "file name" text file to print with pr(1) 253*12111Sralph * t -- "file name" troff(1) file to print 254*12111Sralph * d -- "file name" dvi file to print 255*12111Sralph * g -- "file name" plot(1G) file to print 256*12111Sralph * v -- "file name" plain raster file to print 257*12111Sralph * c -- "file name" cifplot file to print 258*12111Sralph * 1 -- "R font file" for troff 259*12111Sralph * 2 -- "I font file" for troff 260*12111Sralph * 3 -- "B font file" for troff 261*12111Sralph * 4 -- "S font file" for troff 262*12111Sralph * N -- "name" of file (used by lpq) 263*12111Sralph * U -- "unlink" name of file to remove 264*12111Sralph * (after we print it. (Pass 2 only)). 265*12111Sralph * M -- "mail" to user when done printing 266*12111Sralph * 267*12111Sralph * getline reads a line and expands tabs to blanks 268*12111Sralph */ 269*12111Sralph 270*12111Sralph /* pass 1 */ 271*12111Sralph 272*12111Sralph while (getline(cfp)) 273*12111Sralph switch (line[0]) { 274*12111Sralph case 'H': 275*12111Sralph strcpy(host, line+1); 276*12111Sralph if (class[0] == '\0') 277*12111Sralph strcpy(class, line+1); 278*12111Sralph continue; 279*12111Sralph 280*12111Sralph case 'P': 281*12111Sralph strcpy(logname, line+1); 282*12111Sralph continue; 283*12111Sralph 284*12111Sralph case 'J': 285*12111Sralph if (line[1] != '\0') 286*12111Sralph strcpy(jobname, line+1); 287*12111Sralph else 288*12111Sralph strcpy(jobname, " "); 289*12111Sralph continue; 290*12111Sralph 291*12111Sralph case 'C': 292*12111Sralph if (line[1] != '\0') 293*12111Sralph strcpy(class, line+1); 294*12111Sralph else if (class[0] == '\0') 295*12111Sralph gethostname(class, sizeof (class)); 296*12111Sralph continue; 297*12111Sralph 298*12111Sralph case 'T': /* header title for pr */ 299*12111Sralph strcpy(title, line+1); 300*12111Sralph continue; 301*12111Sralph 302*12111Sralph case 'L': /* identification line */ 303*12111Sralph if (!SH) 304*12111Sralph banner(line+1, jobname); 305*12111Sralph continue; 306*12111Sralph 307*12111Sralph case '1': /* troff fonts */ 308*12111Sralph case '2': 309*12111Sralph case '3': 310*12111Sralph case '4': 311*12111Sralph if (line[1] != '\0') 312*12111Sralph strcpy(fonts[line[0]-'1'], line+1); 313*12111Sralph continue; 314*12111Sralph 315*12111Sralph case 'W': /* page width */ 316*12111Sralph strcpy(width+2, line+1); 317*12111Sralph continue; 318*12111Sralph 319*12111Sralph default: /* some file to print */ 320*12111Sralph if ((i = print(line[0], line+1)) > 0) { 321*12111Sralph (void) fclose(cfp); 322*12111Sralph return(1); 323*12111Sralph } else if (i < 0) 324*12111Sralph bombed = 1; 325*12111Sralph title[0] = '\0'; 326*12111Sralph continue; 327*12111Sralph 328*12111Sralph case 'I': 329*12111Sralph case 'N': 330*12111Sralph case 'U': 331*12111Sralph case 'M': 332*12111Sralph continue; 333*12111Sralph } 334*12111Sralph 335*12111Sralph /* pass 2 */ 336*12111Sralph 337*12111Sralph fseek(cfp, 0L, 0); 338*12111Sralph while (getline(cfp)) 339*12111Sralph switch (line[0]) { 340*12111Sralph case 'M': 341*12111Sralph sendmail(bombed); 342*12111Sralph continue; 343*12111Sralph 344*12111Sralph case 'U': 345*12111Sralph (void) unlink(line+1); 346*12111Sralph } 347*12111Sralph /* 348*12111Sralph * clean-up incase another control file exists 349*12111Sralph */ 350*12111Sralph (void) fclose(cfp); 351*12111Sralph (void) unlink(file); 352*12111Sralph return(0); 353*12111Sralph } 354*12111Sralph 355*12111Sralph /* 356*12111Sralph * Print a file. 357*12111Sralph * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, TF, CF, VF}. 358*12111Sralph * Return -1 if a non-recoverable error occured, 1 if a recoverable error and 359*12111Sralph * 0 if all is well. 360*12111Sralph * Note: all filters take stdin as the file, stdout as the printer, 361*12111Sralph * stderr as the log file, and must not ignore SIGINT. 362*12111Sralph */ 363*12111Sralph print(format, file) 364*12111Sralph int format; 365*12111Sralph char *file; 366*12111Sralph { 367*12111Sralph register int n, fi, fo; 368*12111Sralph register char *prog; 369*12111Sralph char *av[15], buf[BUFSIZ]; 370*12111Sralph int pid, p[2], stopped = 0; 371*12111Sralph union wait status; 372*12111Sralph 373*12111Sralph if ((fi = open(file, FRDONLY, 0)) < 0) { 374*12111Sralph log("%s: open failure <errno = %d>", file, errno); 375*12111Sralph return(-1); 376*12111Sralph } 377*12111Sralph if (!SF && !tof) { /* start on a fresh page */ 378*12111Sralph (void) write(ofd, FF, strlen(FF)); 379*12111Sralph tof = 1; 380*12111Sralph } 381*12111Sralph if (IF == NULL && (format == 'f' || format == 'l')) { 382*12111Sralph tof = 0; 383*12111Sralph while ((n = read(fi, buf, BUFSIZ)) > 0) 384*12111Sralph if (write(ofd, buf, n) != n) { 385*12111Sralph (void) close(fi); 386*12111Sralph return(1); 387*12111Sralph } 388*12111Sralph (void) close(fi); 389*12111Sralph return(0); 390*12111Sralph } 391*12111Sralph switch (format) { 392*12111Sralph case 'p': /* print file using 'pr' */ 393*12111Sralph if (IF == NULL) { /* use output filter */ 394*12111Sralph prog = PR; 395*12111Sralph av[0] = "pr"; 396*12111Sralph av[1] = width; 397*12111Sralph av[2] = length; 398*12111Sralph av[3] = "-h"; 399*12111Sralph av[4] = *title ? title : " "; 400*12111Sralph av[5] = 0; 401*12111Sralph fo = ofd; 402*12111Sralph goto start; 403*12111Sralph } 404*12111Sralph pipe(p); 405*12111Sralph if ((prchild = dofork(DORETURN)) == 0) { /* child */ 406*12111Sralph dup2(fi, 0); /* file is stdin */ 407*12111Sralph dup2(p[1], 1); /* pipe is stdout */ 408*12111Sralph for (n = 3; n < NOFILE; n++) 409*12111Sralph (void) close(n); 410*12111Sralph execl(PR, "pr", width, length, "-h", *title ? title : " ", 0); 411*12111Sralph log("cannot execl %s", PR); 412*12111Sralph exit(2); 413*12111Sralph } 414*12111Sralph (void) close(p[1]); /* close output side */ 415*12111Sralph (void) close(fi); 416*12111Sralph if (prchild < 0) { 417*12111Sralph prchild = 0; 418*12111Sralph (void) close(p[0]); 419*12111Sralph return(-1); 420*12111Sralph } 421*12111Sralph fi = p[0]; /* use pipe for input */ 422*12111Sralph case 'f': /* print plain text file */ 423*12111Sralph prog = IF; 424*12111Sralph av[1] = width; 425*12111Sralph av[2] = length; 426*12111Sralph n = 3; 427*12111Sralph break; 428*12111Sralph case 'l': /* like 'f' but pass control characters */ 429*12111Sralph prog = IF; 430*12111Sralph av[1] = "-l"; 431*12111Sralph av[2] = width; 432*12111Sralph av[3] = length; 433*12111Sralph n = 4; 434*12111Sralph break; 435*12111Sralph case 't': /* print troff output */ 436*12111Sralph case 'd': /* print troff output */ 437*12111Sralph (void) unlink(".railmag"); 438*12111Sralph if ((fo = creat(".railmag", 0666)) < 0) { 439*12111Sralph log("cannot create .railmag"); 440*12111Sralph (void) unlink(".railmag"); 441*12111Sralph } else { 442*12111Sralph for (n = 0; n < 4; n++) { 443*12111Sralph if (fonts[n][0] != '/') 444*12111Sralph (void) write(fo, "/usr/lib/vfont/", 15); 445*12111Sralph (void) write(fo, fonts[n], strlen(fonts[n])); 446*12111Sralph (void) write(fo, "\n", 1); 447*12111Sralph } 448*12111Sralph (void) close(fo); 449*12111Sralph } 450*12111Sralph prog = (format == 't') ? TF : DF; 451*12111Sralph n = 1; 452*12111Sralph break; 453*12111Sralph case 'c': /* print cifplot output */ 454*12111Sralph prog = CF; 455*12111Sralph n = 1; 456*12111Sralph break; 457*12111Sralph case 'g': /* print plot(1G) output */ 458*12111Sralph prog = GF; 459*12111Sralph n = 1; 460*12111Sralph break; 461*12111Sralph case 'v': /* print raster output */ 462*12111Sralph prog = VF; 463*12111Sralph n = 1; 464*12111Sralph break; 465*12111Sralph default: 466*12111Sralph (void) close(fi); 467*12111Sralph log("illegal format character '%c'", format); 468*12111Sralph return(-1); 469*12111Sralph } 470*12111Sralph if ((av[0] = rindex(prog, '/')) != NULL) 471*12111Sralph av[0]++; 472*12111Sralph else 473*12111Sralph av[0] = prog; 474*12111Sralph av[n++] = "-n"; 475*12111Sralph av[n++] = logname; 476*12111Sralph av[n++] = "-h"; 477*12111Sralph av[n++] = host; 478*12111Sralph av[n++] = AF; 479*12111Sralph av[n] = 0; 480*12111Sralph fo = pfd; 481*12111Sralph if (ofilter > 0) { /* stop output filter */ 482*12111Sralph write(ofd, "\031\1", 2); 483*12111Sralph while ((pid = wait3(&status, WUNTRACED, 0)) > 0 && pid != ofilter) 484*12111Sralph ; 485*12111Sralph if (status.w_stopval != WSTOPPED) { 486*12111Sralph (void) close(fi); 487*12111Sralph log("output filter died (%d)", status.w_retcode); 488*12111Sralph return(1); 489*12111Sralph } 490*12111Sralph stopped++; 491*12111Sralph } 492*12111Sralph start: 493*12111Sralph if ((child = dofork(DORETURN)) == 0) { /* child */ 494*12111Sralph dup2(fi, 0); 495*12111Sralph dup2(fo, 1); 496*12111Sralph for (n = 3; n < NOFILE; n++) 497*12111Sralph (void) close(n); 498*12111Sralph execv(prog, av); 499*12111Sralph log("cannot execl %s", prog); 500*12111Sralph exit(2); 501*12111Sralph } 502*12111Sralph (void) close(fi); 503*12111Sralph if (child < 0) 504*12111Sralph status.w_retcode = 100; 505*12111Sralph else 506*12111Sralph while ((pid = wait(&status)) > 0 && pid != child) 507*12111Sralph ; 508*12111Sralph child = 0; 509*12111Sralph prchild = 0; 510*12111Sralph if (stopped) { /* restart output filter */ 511*12111Sralph if (kill(ofilter, SIGCONT) < 0) { 512*12111Sralph log("cannot restart output filter"); 513*12111Sralph exit(1); 514*12111Sralph } 515*12111Sralph } 516*12111Sralph tof = 0; 517*12111Sralph if (!WIFEXITED(status) || status.w_retcode > 1) { 518*12111Sralph log("Daemon Filter '%c' Malfunction (%d)", format, status.w_retcode); 519*12111Sralph return(-1); 520*12111Sralph } else if (status.w_retcode == 1) 521*12111Sralph return(1); 522*12111Sralph tof = 1; 523*12111Sralph return(0); 524*12111Sralph } 525*12111Sralph 526*12111Sralph /* 527*12111Sralph * Send the daemon control file (cf) and any data files. 528*12111Sralph * Return -1 if a non-recoverable error occured, 1 if a recoverable error and 529*12111Sralph * 0 if all is well. 530*12111Sralph */ 531*12111Sralph sendit(file) 532*12111Sralph char *file; 533*12111Sralph { 534*12111Sralph register int linelen, err = 0; 535*12111Sralph char last[132]; 536*12111Sralph 537*12111Sralph /* 538*12111Sralph * open control file 539*12111Sralph */ 540*12111Sralph if ((cfp = fopen(file, "r")) == NULL) { 541*12111Sralph log("control file (%s) open failure <errno = %d>", file, errno); 542*12111Sralph return(0); 543*12111Sralph } 544*12111Sralph /* 545*12111Sralph * read the control file for work to do 546*12111Sralph * 547*12111Sralph * file format -- first character in the line is a command 548*12111Sralph * rest of the line is the argument. 549*12111Sralph * commands of interest are: 550*12111Sralph * 551*12111Sralph * a-z -- "file name" name of file to print 552*12111Sralph * U -- "unlink" name of file to remove 553*12111Sralph * (after we print it. (Pass 2 only)). 554*12111Sralph */ 555*12111Sralph 556*12111Sralph /* 557*12111Sralph * pass 1 558*12111Sralph */ 559*12111Sralph while (getline(cfp)) { 560*12111Sralph again: 561*12111Sralph if (line[0] >= 'a' && line[0] <= 'z') { 562*12111Sralph strcpy(last, line); 563*12111Sralph while (linelen = getline(cfp)) 564*12111Sralph if (strcmp(last, line)) 565*12111Sralph break; 566*12111Sralph if ((err = sendfile('\3', last+1)) > 0) { 567*12111Sralph (void) fclose(cfp); 568*12111Sralph return(1); 569*12111Sralph } else if (err) 570*12111Sralph break; 571*12111Sralph if (linelen) 572*12111Sralph goto again; 573*12111Sralph break; 574*12111Sralph } 575*12111Sralph } 576*12111Sralph if (!err && sendfile('\2', file) > 0) { 577*12111Sralph (void) fclose(cfp); 578*12111Sralph return(1); 579*12111Sralph } 580*12111Sralph /* 581*12111Sralph * pass 2 582*12111Sralph */ 583*12111Sralph fseek(cfp, 0L, 0); 584*12111Sralph while (getline(cfp)) 585*12111Sralph if (line[0] == 'U') 586*12111Sralph (void) unlink(line+1); 587*12111Sralph /* 588*12111Sralph * clean-up incase another control file exists 589*12111Sralph */ 590*12111Sralph (void) fclose(cfp); 591*12111Sralph (void) unlink(file); 592*12111Sralph return(0); 593*12111Sralph } 594*12111Sralph 595*12111Sralph /* 596*12111Sralph * Send a data file to the remote machine and spool it. 597*12111Sralph * Return positive if we should try resending. 598*12111Sralph */ 599*12111Sralph sendfile(type, file) 600*12111Sralph char type, *file; 601*12111Sralph { 602*12111Sralph register int f, i, amt; 603*12111Sralph struct stat stb; 604*12111Sralph char buf[BUFSIZ]; 605*12111Sralph int sizerr; 606*12111Sralph 607*12111Sralph if ((f = open(file, FRDONLY, 0)) < 0 || fstat(f, &stb) < 0) { 608*12111Sralph log("file (%s) open failure <errno = %d>", file, errno); 609*12111Sralph return(-1); 610*12111Sralph } 611*12111Sralph (void) sprintf(buf, "%c%d %s\n", type, stb.st_size, file); 612*12111Sralph amt = strlen(buf); 613*12111Sralph if (write(pfd, buf, amt) != amt) 614*12111Sralph return(1); 615*12111Sralph if (noresponse()) 616*12111Sralph return(1); 617*12111Sralph sizerr = 0; 618*12111Sralph for (i = 0; i < stb.st_size; i += BUFSIZ) { 619*12111Sralph amt = BUFSIZ; 620*12111Sralph if (i + amt > stb.st_size) 621*12111Sralph amt = stb.st_size - i; 622*12111Sralph if (sizerr == 0 && read(f, buf, amt) != amt) 623*12111Sralph sizerr = 1; 624*12111Sralph if (write(pfd, buf, amt) != amt) 625*12111Sralph return(1); 626*12111Sralph } 627*12111Sralph (void) close(f); 628*12111Sralph if (sizerr) { 629*12111Sralph log("%s: changed size", file); 630*12111Sralph (void) write(pfd, "\1", 1); /* tell recvjob to ignore this file */ 631*12111Sralph return(-1); 632*12111Sralph } 633*12111Sralph if (write(pfd, "", 1) != 1) 634*12111Sralph return(1); 635*12111Sralph if (noresponse()) 636*12111Sralph return(1); 637*12111Sralph return(0); 638*12111Sralph } 639*12111Sralph 640*12111Sralph /* 641*12111Sralph * Check to make sure there have been no errors and that both programs 642*12111Sralph * are in sync with eachother. 643*12111Sralph * Return non-zero if the connection was lost. 644*12111Sralph */ 645*12111Sralph static 646*12111Sralph noresponse() 647*12111Sralph { 648*12111Sralph char resp; 649*12111Sralph 650*12111Sralph if (read(pfd, &resp, 1) != 1 || resp != '\0') { 651*12111Sralph log("lost connection or error in recvjob"); 652*12111Sralph return(1); 653*12111Sralph } 654*12111Sralph return(0); 655*12111Sralph } 656*12111Sralph 657*12111Sralph /* 658*12111Sralph * Banner printing stuff 659*12111Sralph */ 660*12111Sralph banner(name1, name2) 661*12111Sralph char *name1, *name2; 662*12111Sralph { 663*12111Sralph time_t tvec; 664*12111Sralph extern char *ctime(); 665*12111Sralph 666*12111Sralph time(&tvec); 667*12111Sralph if (!SF && !tof) 668*12111Sralph (void) write(ofd, FF, strlen(FF)); 669*12111Sralph if (SB) { /* short banner only */ 670*12111Sralph if (class[0]) { 671*12111Sralph (void) write(ofd, class, strlen(class)); 672*12111Sralph (void) write(ofd, ":", 1); 673*12111Sralph } 674*12111Sralph (void) write(ofd, name1, strlen(name1)); 675*12111Sralph (void) write(ofd, " Job: ", 7); 676*12111Sralph (void) write(ofd, name2, strlen(name2)); 677*12111Sralph (void) write(ofd, " Date: ", 8); 678*12111Sralph (void) write(ofd, ctime(&tvec), 24); 679*12111Sralph (void) write(ofd, "\n", 1); 680*12111Sralph } else { /* normal banner */ 681*12111Sralph (void) write(ofd, "\n\n\n", 3); 682*12111Sralph scan_out(ofd, name1, '\0'); 683*12111Sralph (void) write(ofd, "\n\n", 2); 684*12111Sralph scan_out(ofd, name2, '\0'); 685*12111Sralph if (class[0]) { 686*12111Sralph (void) write(ofd,"\n\n\n",3); 687*12111Sralph scan_out(ofd, class, '\0'); 688*12111Sralph } 689*12111Sralph (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15); 690*12111Sralph (void) write(ofd, name2, strlen(name2)); 691*12111Sralph (void) write(ofd, "\n\t\t\t\t\tDate: ", 12); 692*12111Sralph (void) write(ofd, ctime(&tvec), 24); 693*12111Sralph (void) write(ofd, "\n", 1); 694*12111Sralph } 695*12111Sralph if (!SF) 696*12111Sralph (void) write(ofd, FF, strlen(FF)); 697*12111Sralph tof = 1; 698*12111Sralph } 699*12111Sralph 700*12111Sralph char * 701*12111Sralph scnline(key, p, c) 702*12111Sralph register char key, *p; 703*12111Sralph char c; 704*12111Sralph { 705*12111Sralph register scnwidth; 706*12111Sralph 707*12111Sralph for (scnwidth = WIDTH; --scnwidth;) { 708*12111Sralph key <<= 1; 709*12111Sralph *p++ = key & 0200 ? c : BACKGND; 710*12111Sralph } 711*12111Sralph return (p); 712*12111Sralph } 713*12111Sralph 714*12111Sralph #define TRC(q) (((q)-' ')&0177) 715*12111Sralph 716*12111Sralph scan_out(scfd, scsp, dlm) 717*12111Sralph int scfd; 718*12111Sralph char *scsp, dlm; 719*12111Sralph { 720*12111Sralph register char *strp; 721*12111Sralph register nchrs, j; 722*12111Sralph char outbuf[LINELEN+1], *sp, c, cc; 723*12111Sralph int d, scnhgt; 724*12111Sralph extern char scnkey[][HEIGHT]; /* in lpdchar.c */ 725*12111Sralph 726*12111Sralph for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) { 727*12111Sralph strp = &outbuf[0]; 728*12111Sralph sp = scsp; 729*12111Sralph for (nchrs = 0; ; ) { 730*12111Sralph d = dropit(c = TRC(cc = *sp++)); 731*12111Sralph if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d)) 732*12111Sralph for (j = WIDTH; --j;) 733*12111Sralph *strp++ = BACKGND; 734*12111Sralph else 735*12111Sralph strp = scnline(scnkey[c][scnhgt-1-d], strp, cc); 736*12111Sralph if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1) 737*12111Sralph break; 738*12111Sralph *strp++ = BACKGND; 739*12111Sralph *strp++ = BACKGND; 740*12111Sralph } 741*12111Sralph while (*--strp == BACKGND && strp >= outbuf) 742*12111Sralph ; 743*12111Sralph strp++; 744*12111Sralph *strp++ = '\n'; 745*12111Sralph (void) write(scfd, outbuf, strp-outbuf); 746*12111Sralph } 747*12111Sralph } 748*12111Sralph 749*12111Sralph dropit(c) 750*12111Sralph char c; 751*12111Sralph { 752*12111Sralph switch(c) { 753*12111Sralph 754*12111Sralph case TRC('_'): 755*12111Sralph case TRC(';'): 756*12111Sralph case TRC(','): 757*12111Sralph case TRC('g'): 758*12111Sralph case TRC('j'): 759*12111Sralph case TRC('p'): 760*12111Sralph case TRC('q'): 761*12111Sralph case TRC('y'): 762*12111Sralph return (DROP); 763*12111Sralph 764*12111Sralph default: 765*12111Sralph return (0); 766*12111Sralph } 767*12111Sralph } 768*12111Sralph 769*12111Sralph /* 770*12111Sralph * sendmail --- 771*12111Sralph * tell people about job completion 772*12111Sralph */ 773*12111Sralph sendmail(bombed) 774*12111Sralph int bombed; 775*12111Sralph { 776*12111Sralph static int p[2]; 777*12111Sralph register int i; 778*12111Sralph int stat; 779*12111Sralph register char *cp; 780*12111Sralph char buf[100]; 781*12111Sralph 782*12111Sralph pipe(p); 783*12111Sralph if ((stat = dofork(DORETURN)) == 0) { /* child */ 784*12111Sralph dup2(p[0], 0); 785*12111Sralph for (i = 3; i < NOFILE; i++) 786*12111Sralph (void) close(i); 787*12111Sralph if ((cp = rindex(MAIL, '/')) != NULL) 788*12111Sralph cp++; 789*12111Sralph else 790*12111Sralph cp = MAIL; 791*12111Sralph sprintf(buf, "%s@%s", line+1, host); 792*12111Sralph execl(MAIL, cp, buf, 0); 793*12111Sralph exit(0); 794*12111Sralph } else if (stat > 0) { /* parent */ 795*12111Sralph dup2(p[1], 1); 796*12111Sralph printf("To: %s\n", line+1); 797*12111Sralph printf("Subject: printer job\n\n"); 798*12111Sralph printf("Your printer job "); 799*12111Sralph if (*jobname) 800*12111Sralph printf("(%s) ", jobname); 801*12111Sralph if (bombed) 802*12111Sralph printf("bombed\n"); 803*12111Sralph else 804*12111Sralph printf("is done\n"); 805*12111Sralph fflush(stdout); 806*12111Sralph (void) close(1); 807*12111Sralph } 808*12111Sralph (void) close(p[0]); 809*12111Sralph (void) close(p[1]); 810*12111Sralph wait(&stat); 811*12111Sralph } 812*12111Sralph 813*12111Sralph /* 814*12111Sralph * dofork - fork with retries on failure 815*12111Sralph */ 816*12111Sralph dofork(action) 817*12111Sralph int action; 818*12111Sralph { 819*12111Sralph register int i, pid; 820*12111Sralph 821*12111Sralph for (i = 0; i < 20; i++) { 822*12111Sralph if ((pid = fork()) < 0) 823*12111Sralph sleep((unsigned)(i*i)); 824*12111Sralph else 825*12111Sralph return(pid); 826*12111Sralph } 827*12111Sralph log("can't fork"); 828*12111Sralph 829*12111Sralph switch (action) { 830*12111Sralph case DORETURN: 831*12111Sralph return (-1); 832*12111Sralph default: 833*12111Sralph log("bad action (%d) to dofork", action); 834*12111Sralph /*FALL THRU*/ 835*12111Sralph case DOABORT: 836*12111Sralph exit(1); 837*12111Sralph } 838*12111Sralph /*NOTREACHED*/ 839*12111Sralph } 840*12111Sralph 841*12111Sralph /* 842*12111Sralph * Cleanup child processes when a SIGINT is caught. 843*12111Sralph */ 844*12111Sralph onintr() 845*12111Sralph { 846*12111Sralph kill(0, SIGINT); 847*12111Sralph if (ofilter > 0) 848*12111Sralph kill(ofilter, SIGCONT); 849*12111Sralph while (wait(0) > 0) 850*12111Sralph ; 851*12111Sralph exit(0); 852*12111Sralph } 853*12111Sralph 854*12111Sralph init() 855*12111Sralph { 856*12111Sralph int status; 857*12111Sralph 858*12111Sralph if ((status = pgetent(line, printer)) < 0) { 859*12111Sralph log("can't open printer description file"); 860*12111Sralph exit(1); 861*12111Sralph } else if (status == 0) { 862*12111Sralph log("unknown printer"); 863*12111Sralph exit(1); 864*12111Sralph } 865*12111Sralph if ((LP = pgetstr("lp", &bp)) == NULL) 866*12111Sralph LP = DEFDEVLP; 867*12111Sralph if ((RP = pgetstr("rp", &bp)) == NULL) 868*12111Sralph RP = printer; 869*12111Sralph if ((LO = pgetstr("lo", &bp)) == NULL) 870*12111Sralph LO = DEFLOCK; 871*12111Sralph if ((ST = pgetstr("st", &bp)) == NULL) 872*12111Sralph ST = DEFSTAT; 873*12111Sralph if ((LF = pgetstr("lf", &bp)) == NULL) 874*12111Sralph LF = DEFLOGF; 875*12111Sralph if ((SD = pgetstr("sd", &bp)) == NULL) 876*12111Sralph SD = DEFSPOOL; 877*12111Sralph if ((DU = pgetnum("du")) < 0) 878*12111Sralph DU = DEFUID; 879*12111Sralph if ((FF = pgetstr("ff", &bp)) == NULL) 880*12111Sralph FF = DEFFF; 881*12111Sralph if ((PW = pgetnum("pw")) < 0) 882*12111Sralph PW = DEFWIDTH; 883*12111Sralph sprintf(&width[2], "%d", PW); 884*12111Sralph if ((PL = pgetnum("pl")) < 0) 885*12111Sralph PL = DEFLENGTH; 886*12111Sralph sprintf(&length[2], "%d", PL); 887*12111Sralph RM = pgetstr("rm", &bp); 888*12111Sralph AF = pgetstr("af", &bp); 889*12111Sralph OF = pgetstr("of", &bp); 890*12111Sralph IF = pgetstr("if", &bp); 891*12111Sralph TF = pgetstr("tf", &bp); 892*12111Sralph DF = pgetstr("df", &bp); 893*12111Sralph GF = pgetstr("gf", &bp); 894*12111Sralph VF = pgetstr("vf", &bp); 895*12111Sralph CF = pgetstr("cf", &bp); 896*12111Sralph TR = pgetstr("tr", &bp); 897*12111Sralph SF = pgetflag("sf"); 898*12111Sralph SH = pgetflag("sh"); 899*12111Sralph SB = pgetflag("sb"); 900*12111Sralph RW = pgetflag("rw"); 901*12111Sralph BR = pgetnum("br"); 902*12111Sralph if ((FC = pgetnum("fc")) < 0) 903*12111Sralph FC = 0; 904*12111Sralph if ((FS = pgetnum("fs")) < 0) 905*12111Sralph FS = 0; 906*12111Sralph if ((XC = pgetnum("xc")) < 0) 907*12111Sralph XC = 0; 908*12111Sralph if ((XS = pgetnum("xs")) < 0) 909*12111Sralph XS = 0; 910*12111Sralph } 911*12111Sralph 912*12111Sralph struct bauds { 913*12111Sralph int baud; 914*12111Sralph int speed; 915*12111Sralph } bauds[] = { 916*12111Sralph 50, B50, 917*12111Sralph 75, B75, 918*12111Sralph 110, B110, 919*12111Sralph 134, B134, 920*12111Sralph 150, B150, 921*12111Sralph 200, B200, 922*12111Sralph 300, B300, 923*12111Sralph 600, B600, 924*12111Sralph 1200, B1200, 925*12111Sralph 1800, B1800, 926*12111Sralph 2400, B2400, 927*12111Sralph 4800, B4800, 928*12111Sralph 9600, B9600, 929*12111Sralph 19200, EXTA, 930*12111Sralph 38400, EXTB, 931*12111Sralph 0, 0 932*12111Sralph }; 933*12111Sralph 934*12111Sralph /* 935*12111Sralph * setup tty lines. 936*12111Sralph */ 937*12111Sralph setty() 938*12111Sralph { 939*12111Sralph struct sgttyb ttybuf; 940*12111Sralph register struct bauds *bp; 941*12111Sralph 942*12111Sralph if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) { 943*12111Sralph log("cannot set exclusive-use"); 944*12111Sralph exit(1); 945*12111Sralph } 946*12111Sralph if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) { 947*12111Sralph log("cannot get tty parameters"); 948*12111Sralph exit(1); 949*12111Sralph } 950*12111Sralph if (BR > 0) { 951*12111Sralph for (bp = bauds; bp->baud; bp++) 952*12111Sralph if (BR == bp->baud) 953*12111Sralph break; 954*12111Sralph if (!bp->baud) { 955*12111Sralph log("illegal baud rate %d", BR); 956*12111Sralph exit(1); 957*12111Sralph } 958*12111Sralph ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed; 959*12111Sralph } 960*12111Sralph if (FC) 961*12111Sralph ttybuf.sg_flags &= ~FC; 962*12111Sralph if (FS) 963*12111Sralph ttybuf.sg_flags |= FS; 964*12111Sralph if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) { 965*12111Sralph log("cannot set tty parameters"); 966*12111Sralph exit(1); 967*12111Sralph } 968*12111Sralph if (XC) { 969*12111Sralph if (ioctl(pfd, TIOCLBIC, &XC) < 0) { 970*12111Sralph log("cannot set local tty parameters"); 971*12111Sralph exit(1); 972*12111Sralph } 973*12111Sralph } 974*12111Sralph if (XS) { 975*12111Sralph if (ioctl(pfd, TIOCLBIS, &XS) < 0) { 976*12111Sralph log("cannot set local tty parameters"); 977*12111Sralph exit(1); 978*12111Sralph } 979*12111Sralph } 980*12111Sralph } 981