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: }