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