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

Defined functions

card defined in line 423; used 19 times
chkprinter defined in line 588; used 1 times
copy defined in line 347; used 6 times
fatal defined in line 672; used 9 times
linked defined in line 388; used 2 times
main defined in line 77; never used
mktemp defined in line 657; used 5 times
mktemps defined in line 618; used 1 times
nfile defined in line 442; used 2 times
test defined in line 504; used 5 times

Defined variables

DU defined in line 65; used 3 times
LO defined in line 67; used 3 times
MC defined in line 64; used 5 times
MX defined in line 63; used 4 times
RG defined in line 68; used 3 times
SC defined in line 69; used 2 times
SD defined in line 66; used 7 times
cfname defined in line 36; used 6 times
class defined in line 57; used 3 times
copyright defined in line 8; never used
dfname defined in line 37; used 13 times
fonts defined in line 54; used 3 times
format defined in line 43; used 12 times
hdr defined in line 50; used 5 times
host defined in line 56; used 6 times
iflag defined in line 48; used 2 times
inchar defined in line 46; used 18 times
indent defined in line 49; used 2 times
jobname defined in line 58; used 6 times
mailflg defined in line 41; used 2 times
nact defined in line 39; used 3 times
name defined in line 59; used 22 times
ncopies defined in line 47; used 5 times
person defined in line 52; used 11 times
printer defined in line 60; used 7 times
qflag defined in line 42; used 2 times
rflag defined in line 44; used 2 times
sccsid defined in line 14; never used
sflag defined in line 45; used 3 times
statb defined in line 61; used 5 times
tfd defined in line 40; used 9 times
tfname defined in line 35; used 12 times
title defined in line 53; used 6 times
userid defined in line 51; used 4 times
width defined in line 55; used 3 times
Last modified: 1986-01-11
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2651
Valid CSS Valid XHTML 1.0 Strict