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