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

Defined functions

card defined in line 421; used 19 times
chkprinter defined in line 586; used 1 times
cleanup defined in line 470; used 11 times
copy defined in line 345; used 2 times
fatal defined in line 670; used 9 times
itoa defined in line 569; used 2 times
linked defined in line 386; used 2 times
main defined in line 75; never used
mktemp defined in line 655; used 5 times
mktemps defined in line 616; used 1 times
nfile defined in line 440; used 2 times
test defined in line 502; used 1 times

Defined variables

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