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