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