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