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