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