|
|
1.1 ! root 1: #ifndef lint ! 2: static char sccsid[] = "@(#)lpr.c 4.26 (Berkeley) 9/15/83"; ! 3: #endif ! 4: ! 5: /* ! 6: * lpr -- off line print ! 7: * ! 8: * Allows multiple printers and printers on remote machines by ! 9: * using information from a printer data base. ! 10: */ ! 11: ! 12: #include <stdio.h> ! 13: #include <sys/types.h> ! 14: #include <sys/file.h> ! 15: #include <sys/stat.h> ! 16: #include <pwd.h> ! 17: #include <signal.h> ! 18: #include <ctype.h> ! 19: #include "lp.local.h" ! 20: ! 21: char *tfname; /* tmp copy of cf before linking */ ! 22: char *cfname; /* daemon control files, linked from tf's */ ! 23: char *dfname; /* data files */ ! 24: ! 25: int nact; /* number of jobs to act on */ ! 26: int tfd; /* control file descriptor */ ! 27: int mailflg; /* send mail */ ! 28: int qflag; /* q job, but don't exec daemon */ ! 29: char format = 'f'; /* format char for printing files */ ! 30: int rflag; /* remove files upon completion */ ! 31: int sflag; /* symbolic link flag */ ! 32: int inchar; /* location to increment char in file names */ ! 33: int ncopies = 1; /* # of copies to make */ ! 34: int iflag; /* indentation wanted */ ! 35: int indent; /* amount to indent */ ! 36: int hdr = 1; /* print header or not (default is yes) */ ! 37: int userid; /* user id */ ! 38: char *person; /* user name */ ! 39: char *title; /* pr'ing title */ ! 40: char *fonts[4]; /* troff font names */ ! 41: char *width; /* width for versatec printing */ ! 42: char host[32]; /* host name */ ! 43: char *class = host; /* class title on header page */ ! 44: char *jobname; /* job name on header page */ ! 45: char *name; /* program name */ ! 46: char *printer; /* printer name */ ! 47: char buf[BUFSIZ]; ! 48: ! 49: int MX; /* maximum number of blocks to copy */ ! 50: int MC; /* maximum number of copies allowed */ ! 51: int DU; /* daemon user-id */ ! 52: char *SD; /* spool directory */ ! 53: char *LO; /* lock file name */ ! 54: short SC; /* suppress multiple copies */ ! 55: ! 56: char *getenv(); ! 57: char *rindex(); ! 58: char *linked(); ! 59: int cleanup(); ! 60: ! 61: /*ARGSUSED*/ ! 62: main(argc, argv) ! 63: int argc; ! 64: char *argv[]; ! 65: { ! 66: extern struct passwd *getpwuid(); ! 67: struct passwd *pw; ! 68: extern char *itoa(); ! 69: register char *arg, *cp; ! 70: int i, f; ! 71: struct stat stb; ! 72: ! 73: if (signal(SIGHUP, SIG_IGN) != SIG_IGN) ! 74: signal(SIGHUP, cleanup); ! 75: if (signal(SIGINT, SIG_IGN) != SIG_IGN) ! 76: signal(SIGINT, cleanup); ! 77: if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) ! 78: signal(SIGQUIT, cleanup); ! 79: if (signal(SIGTERM, SIG_IGN) != SIG_IGN) ! 80: signal(SIGTERM, cleanup); ! 81: ! 82: name = argv[0]; ! 83: gethostname(host, sizeof (host)); ! 84: ! 85: while (argc > 1 && argv[1][0] == '-') { ! 86: argc--; ! 87: arg = *++argv; ! 88: switch (arg[1]) { ! 89: ! 90: case 'P': /* specifiy printer name */ ! 91: if (arg[2]) ! 92: printer = &arg[2]; ! 93: else if (argc > 1) { ! 94: argc--; ! 95: printer = *++argv; ! 96: } ! 97: break; ! 98: ! 99: case 'C': /* classification spec */ ! 100: hdr++; ! 101: if (arg[2]) ! 102: class = &arg[2]; ! 103: else if (argc > 1) { ! 104: argc--; ! 105: class = *++argv; ! 106: } ! 107: break; ! 108: ! 109: case 'J': /* job name */ ! 110: hdr++; ! 111: if (arg[2]) ! 112: jobname = &arg[2]; ! 113: else if (argc > 1) { ! 114: argc--; ! 115: jobname = *++argv; ! 116: } ! 117: break; ! 118: ! 119: case 'T': /* pr's title line */ ! 120: if (arg[2]) ! 121: title = &arg[2]; ! 122: else if (argc > 1) { ! 123: argc--; ! 124: title = *++argv; ! 125: } ! 126: break; ! 127: ! 128: case 'l': /* literal output */ ! 129: case 'p': /* print using ``pr'' */ ! 130: case 't': /* print troff output (cat files) */ ! 131: case 'n': /* print ditroff output */ ! 132: case 'd': /* print tex output (dvi files) */ ! 133: case 'g': /* print graph(1G) output */ ! 134: case 'c': /* print cifplot output */ ! 135: case 'v': /* print vplot output */ ! 136: format = arg[1]; ! 137: break; ! 138: ! 139: case 'f': /* print fortran output */ ! 140: format = 'r'; ! 141: break; ! 142: ! 143: case '4': /* troff fonts */ ! 144: case '3': ! 145: case '2': ! 146: case '1': ! 147: if (argc > 1) { ! 148: argc--; ! 149: fonts[arg[1] - '1'] = *++argv; ! 150: } ! 151: break; ! 152: ! 153: case 'w': /* versatec page width */ ! 154: width = arg+2; ! 155: break; ! 156: ! 157: case 'r': /* remove file when done */ ! 158: rflag++; ! 159: break; ! 160: ! 161: case 'm': /* send mail when done */ ! 162: mailflg++; ! 163: break; ! 164: ! 165: case 'h': /* toggle want of header page */ ! 166: hdr = !hdr; ! 167: break; ! 168: ! 169: case 's': /* try to link files */ ! 170: sflag++; ! 171: break; ! 172: ! 173: case 'q': /* just q job */ ! 174: qflag++; ! 175: break; ! 176: ! 177: case 'i': /* indent output */ ! 178: iflag++; ! 179: indent = arg[2] ? atoi(&arg[2]) : 8; ! 180: break; ! 181: ! 182: case '#': /* n copies */ ! 183: if (isdigit(arg[2])) { ! 184: i = atoi(&arg[2]); ! 185: if (i > 0) ! 186: ncopies = i; ! 187: } ! 188: } ! 189: } ! 190: if (printer == NULL && (printer = getenv("PRINTER")) == NULL) ! 191: printer = DEFLP; ! 192: chkprinter(printer); ! 193: if (SC && ncopies > 1) ! 194: fatal("multiple copies are not allowed"); ! 195: if (MC > 0 && ncopies > MC) ! 196: fatal("only %d copies are allowed", MC); ! 197: /* ! 198: * Get the identity of the person doing the lpr using the same ! 199: * algorithm as lprm. ! 200: */ ! 201: userid = getuid(); ! 202: if ((pw = getpwuid(userid)) == NULL) ! 203: fatal("Who are you?"); ! 204: person = pw->pw_name; ! 205: /* ! 206: * Check to make sure queuing is enabled if userid is not root. ! 207: */ ! 208: (void) sprintf(buf, "%s/%s", SD, LO); ! 209: if (userid && stat(buf, &stb) == 0 && (stb.st_mode & 010)) ! 210: fatal("Printer queue is disabled"); ! 211: /* ! 212: * Initialize the control file. ! 213: */ ! 214: mktemps(); ! 215: tfd = nfile(tfname); ! 216: (void) fchown(tfd, DU, -1); /* owned by daemon for protection */ ! 217: card('H', host); ! 218: card('P', person); ! 219: if (hdr) { ! 220: if (jobname == NULL) { ! 221: if (argc == 1) ! 222: jobname = "stdin"; ! 223: else ! 224: jobname = (arg = rindex(argv[1], '/')) ? arg+1 : argv[1]; ! 225: } ! 226: card('J', jobname); ! 227: card('C', class); ! 228: card('L', person); ! 229: } ! 230: if (iflag) ! 231: card('I', itoa(indent)); ! 232: if (mailflg) ! 233: card('M', person); ! 234: if (format == 't' || format == 'n' || format == 'd') ! 235: for (i = 0; i < 4; i++) ! 236: if (fonts[i] != NULL) ! 237: card('1'+i, fonts[i]); ! 238: if (width != NULL) ! 239: card('W', width); ! 240: ! 241: /* ! 242: * Read the files and spool them. ! 243: */ ! 244: if (argc == 1) ! 245: copy(0, " "); ! 246: else while (--argc) { ! 247: if ((f = test(arg = *++argv)) < 0) ! 248: continue; /* file unreasonable */ ! 249: ! 250: if (sflag && (cp = linked(arg)) != NULL) { ! 251: if (format == 'p') ! 252: card('T', title ? title : arg); ! 253: for (i = 0; i < ncopies; i++) ! 254: card(format, &dfname[inchar-2]); ! 255: card('U', &dfname[inchar-2]); ! 256: if (f) ! 257: card('U', cp); ! 258: card('N', arg); ! 259: dfname[inchar]++; ! 260: nact++; ! 261: continue; ! 262: } ! 263: if (sflag) ! 264: printf("%s: %s: not linked, copying instead\n", name, arg); ! 265: if ((i = open(arg, O_RDONLY)) < 0) { ! 266: printf("%s: cannot open %s\n", name, arg); ! 267: continue; ! 268: } ! 269: copy(i, arg); ! 270: (void) close(i); ! 271: if (f && unlink(arg) < 0) ! 272: printf("%s: %s: not removed\n", name, arg); ! 273: } ! 274: ! 275: if (nact) { ! 276: (void) close(tfd); ! 277: tfname[inchar]--; ! 278: /* ! 279: * Touch the control file to fix position in the queue. ! 280: */ ! 281: if ((tfd = open(tfname, O_RDWR)) >= 0) { ! 282: char c; ! 283: ! 284: if (read(tfd, &c, 1) == 1 && lseek(tfd, 0L, 0) == 0 && ! 285: write(tfd, &c, 1) != 1) { ! 286: printf("%s: cannot touch %s\n", name, tfname); ! 287: tfname[inchar]++; ! 288: cleanup(); ! 289: } ! 290: (void) close(tfd); ! 291: } ! 292: if (link(tfname, cfname) < 0) { ! 293: printf("%s: cannot rename %s\n", name, cfname); ! 294: tfname[inchar]++; ! 295: cleanup(); ! 296: } ! 297: unlink(tfname); ! 298: if (qflag) /* just q things up */ ! 299: exit(0); ! 300: if (!startdaemon(printer)) ! 301: printf("jobs queued, but cannot start daemon.\n"); ! 302: exit(0); ! 303: } ! 304: cleanup(); ! 305: /* NOTREACHED */ ! 306: } ! 307: ! 308: /* ! 309: * Create the file n and copy from file descriptor f. ! 310: */ ! 311: copy(f, n) ! 312: int f; ! 313: char n[]; ! 314: { ! 315: register int fd, i, nr, nc; ! 316: ! 317: if (format == 'p') ! 318: card('T', title ? title : n); ! 319: for (i = 0; i < ncopies; i++) ! 320: card(format, &dfname[inchar-2]); ! 321: card('U', &dfname[inchar-2]); ! 322: card('N', n); ! 323: fd = nfile(dfname); ! 324: nr = nc = 0; ! 325: while ((i = read(f, buf, BUFSIZ)) > 0) { ! 326: if (write(fd, buf, i) != i) { ! 327: printf("%s: %s: temp file write error\n", name, n); ! 328: break; ! 329: } ! 330: nc += i; ! 331: if (nc >= BUFSIZ) { ! 332: nc -= BUFSIZ; ! 333: nr++; ! 334: if (MX > 0 && nr > MX) { ! 335: printf("%s: %s: copy file is too large\n", name, n); ! 336: break; ! 337: } ! 338: } ! 339: } ! 340: (void) close(fd); ! 341: if (nc==0 && nr==0) ! 342: printf("%s: %s: empty input file\n", name, f ? n : "stdin"); ! 343: else ! 344: nact++; ! 345: } ! 346: ! 347: /* ! 348: * Try and link the file to dfname. Return a pointer to the full ! 349: * path name if successful. ! 350: */ ! 351: char * ! 352: linked(file) ! 353: register char *file; ! 354: { ! 355: register char *cp; ! 356: static char buf[BUFSIZ]; ! 357: ! 358: if (*file != '/') { ! 359: if (getwd(buf) == NULL) ! 360: return(NULL); ! 361: while (file[0] == '.') { ! 362: switch (file[1]) { ! 363: case '/': ! 364: file += 2; ! 365: continue; ! 366: case '.': ! 367: if (file[2] == '/') { ! 368: if ((cp = rindex(buf, '/')) != NULL) ! 369: *cp = '\0'; ! 370: file += 3; ! 371: continue; ! 372: } ! 373: } ! 374: break; ! 375: } ! 376: strcat(buf, "/"); ! 377: strcat(buf, file); ! 378: file = buf; ! 379: } ! 380: return(symlink(file, dfname) ? NULL : file); ! 381: } ! 382: ! 383: /* ! 384: * Put a line into the control file. ! 385: */ ! 386: card(c, p2) ! 387: register char c, *p2; ! 388: { ! 389: register char *p1 = buf; ! 390: register int len = 2; ! 391: ! 392: *p1++ = c; ! 393: while ((c = *p2++) != '\0') { ! 394: *p1++ = c; ! 395: len++; ! 396: } ! 397: *p1++ = '\n'; ! 398: write(tfd, buf, len); ! 399: } ! 400: ! 401: /* ! 402: * Create a new file in the spool directory. ! 403: */ ! 404: nfile(n) ! 405: char *n; ! 406: { ! 407: register f; ! 408: int oldumask = umask(0); /* should block signals */ ! 409: ! 410: f = creat(n, FILMOD); ! 411: (void) umask(oldumask); ! 412: if (f < 0) { ! 413: printf("%s: cannot create %s\n", name, n); ! 414: cleanup(); ! 415: } ! 416: if (fchown(f, userid, -1) < 0) { ! 417: printf("%s: cannot chown %s\n", name, n); ! 418: cleanup(); ! 419: } ! 420: if (++n[inchar] > 'z') { ! 421: if (++n[inchar-2] == 't') { ! 422: printf("too many files - break up the job\n"); ! 423: cleanup(); ! 424: } ! 425: n[inchar] = 'A'; ! 426: } else if (n[inchar] == '[') ! 427: n[inchar] = 'a'; ! 428: return(f); ! 429: } ! 430: ! 431: /* ! 432: * Cleanup after interrupts and errors. ! 433: */ ! 434: cleanup() ! 435: { ! 436: register i; ! 437: ! 438: signal(SIGHUP, SIG_IGN); ! 439: signal(SIGINT, SIG_IGN); ! 440: signal(SIGQUIT, SIG_IGN); ! 441: signal(SIGTERM, SIG_IGN); ! 442: i = inchar; ! 443: if (tfname) ! 444: do ! 445: unlink(tfname); ! 446: while (tfname[i]-- != 'A'); ! 447: if (cfname) ! 448: do ! 449: unlink(cfname); ! 450: while (cfname[i]-- != 'A'); ! 451: if (dfname) ! 452: do { ! 453: do ! 454: unlink(dfname); ! 455: while (dfname[i]-- != 'A'); ! 456: dfname[i] = 'z'; ! 457: } while (dfname[i-2]-- != 'd'); ! 458: exit(1); ! 459: } ! 460: ! 461: /* ! 462: * Test to see if this is a printable file. ! 463: * Return -1 if it is not, 0 if its printable, and 1 if ! 464: * we should remove it after printing. ! 465: */ ! 466: test(file) ! 467: char *file; ! 468: { ! 469: struct exec execb; ! 470: struct stat statb; ! 471: register int fd; ! 472: register char *cp; ! 473: ! 474: if (access(file, 4) < 0) { ! 475: printf("%s: cannot access %s\n", name, file); ! 476: return(-1); ! 477: } ! 478: if (stat(file, &statb) < 0) { ! 479: printf("%s: cannot stat %s\n", name, file); ! 480: return(-1); ! 481: } ! 482: if ((statb.st_mode & S_IFMT) == S_IFDIR) { ! 483: printf("%s: %s is a directory\n", name, file); ! 484: return(-1); ! 485: } ! 486: if (statb.st_size == 0) { ! 487: printf("%s: %s is an empty file\n", name, file); ! 488: return(-1); ! 489: } ! 490: if ((fd = open(file, O_RDONLY)) < 0) { ! 491: printf("%s: cannot open %s\n", name, file); ! 492: return(-1); ! 493: } ! 494: if (read(fd, &execb, sizeof(execb)) == sizeof(execb)) ! 495: switch(execb.a_magic) { ! 496: case A_MAGIC1: ! 497: case A_MAGIC2: ! 498: case A_MAGIC3: ! 499: #ifdef A_MAGIC4 ! 500: case A_MAGIC4: ! 501: #endif ! 502: printf("%s: %s is an executable program", name, file); ! 503: goto error1; ! 504: ! 505: case ARMAG: ! 506: printf("%s: %s is an archive file", name, file); ! 507: goto error1; ! 508: } ! 509: (void) close(fd); ! 510: if (rflag) { ! 511: if ((cp = rindex(file, '/')) == NULL) { ! 512: if (access(".", 2) == 0) ! 513: return(1); ! 514: } else { ! 515: *cp = '\0'; ! 516: fd = access(file, 2); ! 517: *cp = '/'; ! 518: if (fd == 0) ! 519: return(1); ! 520: } ! 521: printf("%s: %s: is not removable by you\n", name, file); ! 522: } ! 523: return(0); ! 524: ! 525: error1: ! 526: printf(" and is unprintable\n"); ! 527: (void) close(fd); ! 528: return(-1); ! 529: } ! 530: ! 531: /* ! 532: * itoa - integer to string conversion ! 533: */ ! 534: char * ! 535: itoa(i) ! 536: register int i; ! 537: { ! 538: static char b[10] = "########"; ! 539: register char *p; ! 540: ! 541: p = &b[8]; ! 542: do ! 543: *p-- = i%10 + '0'; ! 544: while (i /= 10); ! 545: return(++p); ! 546: } ! 547: ! 548: /* ! 549: * Perform lookup for printer name or abbreviation -- ! 550: */ ! 551: chkprinter(s) ! 552: char *s; ! 553: { ! 554: int status; ! 555: static char pbuf[BUFSIZ/2]; ! 556: char *bp = pbuf; ! 557: extern char *pgetstr(); ! 558: ! 559: if ((status = pgetent(buf, s)) < 0) ! 560: fatal("cannot open printer description file"); ! 561: else if (status == 0) ! 562: fatal("%s: unknown printer", s); ! 563: if ((SD = pgetstr("sd", &bp)) == NULL) ! 564: SD = DEFSPOOL; ! 565: if ((LO = pgetstr("lo", &bp)) == NULL) ! 566: LO = DEFLOCK; ! 567: if ((MX = pgetnum("mx")) < 0) ! 568: MX = DEFMX; ! 569: if ((MC = pgetnum("mc")) < 0) ! 570: MC = DEFMAXCOPIES; ! 571: if ((DU = pgetnum("du")) < 0) ! 572: DU = DEFUID; ! 573: SC = pgetflag("sc"); ! 574: } ! 575: ! 576: /* ! 577: * Make the temp files. ! 578: */ ! 579: mktemps() ! 580: { ! 581: register int c, len, fd, n; ! 582: register char *cp; ! 583: char *mktemp(); ! 584: ! 585: (void) sprintf(buf, "%s/.seq", SD); ! 586: if ((fd = open(buf, O_RDWR|O_CREAT, 0661)) < 0) { ! 587: printf("%s: cannot create %s\n", name, buf); ! 588: exit(1); ! 589: } ! 590: if (flock(fd, LOCK_EX)) { ! 591: printf("%s: cannot lock %s\n", name, buf); ! 592: exit(1); ! 593: } ! 594: n = 0; ! 595: if ((len = read(fd, buf, sizeof(buf))) > 0) { ! 596: for (cp = buf; len--; ) { ! 597: if (*cp < '0' || *cp > '9') ! 598: break; ! 599: n = n * 10 + (*cp++ - '0'); ! 600: } ! 601: } ! 602: len = strlen(SD) + strlen(host) + 8; ! 603: tfname = mktemp("tf", n, len); ! 604: cfname = mktemp("cf", n, len); ! 605: dfname = mktemp("df", n, len); ! 606: inchar = strlen(SD) + 3; ! 607: n = (n + 1) % 1000; ! 608: (void) lseek(fd, 0L, 0); ! 609: sprintf(buf, "%03d\n", n); ! 610: (void) write(fd, buf, strlen(buf)); ! 611: (void) close(fd); /* unlocks as well */ ! 612: } ! 613: ! 614: /* ! 615: * Make a temp file name. ! 616: */ ! 617: char * ! 618: mktemp(id, num, len) ! 619: char *id; ! 620: int num, len; ! 621: { ! 622: register char *s; ! 623: extern char *malloc(); ! 624: ! 625: if ((s = malloc(len)) == NULL) ! 626: fatal("out of memory"); ! 627: (void) sprintf(s, "%s/%sA%03d%s", SD, id, num, host); ! 628: return(s); ! 629: } ! 630: ! 631: /*VARARGS1*/ ! 632: fatal(msg, a1, a2, a3) ! 633: char *msg; ! 634: { ! 635: printf("%s: ", name); ! 636: printf(msg, a1, a2, a3); ! 637: putchar('\n'); ! 638: exit(1); ! 639: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.