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