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