1: /*	lpr.c	4.3	81/05/19	*/
   2: /*
   3:  *      lpr -- off line print
   4:  *              also known as print
   5:  */
   6: 
   7: #include    <sys/types.h>
   8: #include    <sys/stat.h>
   9: #include    <signal.h>
  10: #include    <pwd.h>
  11: #include    <stdio.h>
  12: #include    <ctype.h>
  13: #include    "lp.local.h"
  14: #include    <whoami.h>
  15: 
  16: /*
  17:  * Multiple printer scheme using info from printer data base:
  18:  *
  19:  *	DN		daemon to invoke to print stuff
  20:  *	SD		directory used as spool queue
  21:  *
  22:  * daemon identifies what printer it should use (in the case of the
  23:  *  same code being shared) by inspecting its argv[1].
  24:  */
  25: char    *tfname;        /* tmp copy of df before linking */
  26: char    *cfname;        /* copy files */
  27: char    *lfname;        /* linked files */
  28: char    *dfname;        /* daemon files, linked from tf's */
  29: 
  30: int nact;           /* number of jobs to act on */
  31: int tff;            /* daemon file descriptor */
  32: int     mailflg;        /* send mail */
  33: int jflag;          /* job name specified */
  34: int qflg;           /* q job, but don't exec daemon */
  35: int prflag;         /* ``pr'' files */
  36: char    *person;        /* user name */
  37: int inchar;         /* location to increment char in file names */
  38: int     ncopies = 1;        /* # of copies to make */
  39: int iflag;          /* indentation wanted */
  40: int indent;         /* amount to indent */
  41: char    *daemname;      /* path name to daemon program */
  42: char    *DN;            /* daemon name */
  43: char    *SD;            /* spooling directory */
  44: char    *LP;            /* line printer device */
  45: int     MX;         /* max size in BUFSIZ blocks of a print file */
  46: int hdr = 1;        /* 1 =>'s default header */
  47: int     user;           /* user id */
  48: int spgroup;        /* daemon's group for creating spool files */
  49: char    *title;         /* pr'ing title */
  50: char    hostname[32];       /* name of local host */
  51: char    *class = hostname;  /* class title on header page */
  52: char    *jobname;       /* job name on header page */
  53: char    *name;          /* program name */
  54: char    *printer;       /* printer name */
  55: 
  56: char    *pgetstr();
  57: char    *mktmp();
  58: char    *malloc();
  59: char    *getenv();
  60: char    *rindex();
  61: 
  62: main(argc, argv)
  63: int argc;
  64: char *argv[];
  65: {
  66:     register char *arg;
  67:     int i, c, f, flag, out();
  68:     char *sp;
  69:     struct stat sbuf;
  70: 
  71:     /*
  72: 	 * Strategy to maintain protected spooling area:
  73: 	 *	1. Spooling area is writable only by daemon and spooling group
  74: 	 *	2. lpr runs setuid root and setgrp spooling group; it uses
  75: 	 *	   root to access any file it wants (verifying things before
  76: 	 *	   with an access call) and group id to know how it should
  77: 	 *	   set up ownership of files in spooling area.
  78: 	 *	3. Files in spooling area are owned by printer and spooling
  79: 	 *	   group, with mode 660.
  80: 	 *	4. lpd runs setuid daemon and setgrp spooling group to
  81: 	 *	   access files and printer.  Users can't get to anything
  82: 	 *	   w/o help of lpq and lprm programs.
  83: 	 */
  84:     user = getuid();
  85:     spgroup = getegid();
  86:     if(signal(SIGHUP, SIG_IGN) != SIG_IGN)
  87:         signal(SIGHUP, out);
  88:     if(signal(SIGINT, SIG_IGN) != SIG_IGN)
  89:         signal(SIGINT, out);
  90:     if(signal(SIGQUIT, SIG_IGN) != SIG_IGN)
  91:         signal(SIGQUIT, out);
  92:     if(signal(SIGTERM, SIG_IGN) != SIG_IGN)
  93:         signal(SIGTERM, out);
  94:     flag = 0;
  95:     if ((printer = getenv("PRINTER")) == NULL)
  96:         printer = DEFLP;
  97:     name = argv[0];
  98:     gethostname(hostname, sizeof (hostname));
  99: 
 100:     while (argc>1 && (arg = argv[1])[0]=='-') {
 101:         switch (arg[1]) {
 102: 
 103:         case 'c':       /* force copy of files */
 104:             flag = '+';
 105:             break;
 106: 
 107:         case 'C':       /* classification spec */
 108:             hdr++;
 109:             if (arg[2])
 110:                 class = &arg[2];
 111:             else if (argc >= 2) {
 112:                 ++argv;
 113:                 arg = argv[1];
 114:                 argc--;
 115:                 class = arg;
 116:             }
 117:             break;
 118: 
 119:         case 'r':       /* remove file when done */
 120:             flag = '-';
 121:             break;
 122: 
 123:         case 'm':       /* send mail when done */
 124:             mailflg++;
 125:             break;
 126: 
 127:         case 'q':       /* just q job */
 128:             qflg++;
 129:             break;
 130: 
 131:         case 'J':       /* job spec */
 132:             jflag++, hdr++;
 133:             if (arg[2]) {
 134:                 jobname = &arg[2];
 135:                 break;
 136:             }
 137:             if (argc>=2) {
 138:                 ++argv;
 139:                 arg = argv[1];
 140:                 jobname = &arg[0];
 141:                 argc--;
 142:             }
 143:             break;
 144: 
 145:         case 'i':       /* indent output */
 146:             iflag++;
 147:             indent = arg[2] ? atoi(&arg[2]) : 8;
 148:             break;
 149: 
 150:         case 'p':       /* use pr to print files */
 151:             prflag++;
 152:             break;
 153: 
 154:         case 'h':       /* pr's title line */
 155:             if (arg[2])
 156:                 title = &arg[2];
 157:             else if (argc >= 2) {
 158:                 ++argv;
 159:                 arg = argv[1];
 160:                 argc--;
 161:                 title = arg;
 162:             }
 163:             break;
 164: 
 165:         case 'P':       /* specifiy printer name */
 166:             printer = &arg[2];
 167:             break;
 168: 
 169:         case 'H':       /* toggle want of header page */
 170:             hdr = !hdr;
 171:             break;
 172: 
 173:         default:        /* n copies ? */
 174:             if (isdigit(arg[1]))
 175:                 ncopies = atoi(&arg[1]);
 176:         }
 177:         argc--;
 178:         argv++;
 179:     }
 180:     if (!chkprinter(printer)) {
 181:         fprintf(stderr, "%s: no entry for default printer %s\n", name,
 182:             printer);
 183:         exit(2);
 184:     }
 185:     i = getpid();
 186:     f = strlen(SD)+11;
 187:     tfname = mktmp("tf", i, f);
 188:     cfname = mktmp("cf", i, f);
 189:     lfname = mktmp("lf", i, f);
 190:     dfname = mktmp("df", i, f);
 191:     inchar = f-7;
 192:     tff = nfile(tfname);
 193:     if (jflag == 0) {
 194:         if(argc == 1)
 195:             jobname = &dfname[f-10];
 196:         else
 197:             jobname = argv[1];
 198:     }
 199:     ident();
 200: 
 201:     if(argc == 1)
 202:         copy(0, " ");
 203:     else while(--argc) {
 204:         if(test(arg = *++argv) == -1)   /* file reasonable */
 205:             continue;
 206: 
 207:         if (flag == '+')        /* force copy flag */
 208:             goto cf;
 209:         if (stat(arg, &sbuf) < 0) {
 210:             printf("lpr:");
 211:             perror(arg);
 212:             continue;
 213:         }
 214:         if((sbuf.st_mode&04) == 0)
 215:             goto cf;
 216:         if(*arg == '/' && flag != '-') {
 217:             for(i=0;i<ncopies;i++) {
 218:                 if (prflag) {
 219:                     if (title)
 220:                         card('H', title);
 221:                     card('R', arg);
 222:                 } else
 223:                     card('F', arg);
 224:                 card('N', arg);
 225:             }
 226:             nact++;
 227:             continue;
 228:         }
 229:         if(link(arg, lfname) < 0)
 230:             goto cf;
 231:         for(i=0;i<ncopies;i++) {
 232:             if (prflag) {
 233:                 card('H', title ? title : arg);
 234:                 card('R', lfname);
 235:             } else
 236:                 card('F', lfname);
 237:             card('N', arg);
 238:         }
 239:         card('U', lfname);
 240:         lfname[inchar]++;
 241:         nact++;
 242:         goto df;
 243: 
 244:     cf:
 245:         if((f = open(arg, 0)) < 0) {
 246:             printf("%s: cannot open %s\n", name, arg);
 247:             continue;
 248:         }
 249:         copy(f, arg);
 250:         close(f);
 251: 
 252:     df:
 253:         if(flag == '-' && unlink(arg))
 254:             printf("%s: cannot remove %s\n", name, arg);
 255:     }
 256: 
 257:     if(nact) {
 258:         tfname[inchar]--;
 259:         if(link(tfname, dfname) < 0) {
 260:             printf("%s: cannot rename %s\n", name, dfname);
 261:             tfname[inchar]++;
 262:             out();
 263:         }
 264:         unlink(tfname);
 265:         if (qflg)       /* just q things up */
 266:             exit(0);
 267:         if (stat(LP, &sbuf) >= 0 && (sbuf.st_mode&0777) == 0) {
 268:             printf("job queued, but printer down\n");
 269:             exit(0);
 270:         }
 271:         for(f = 0; f < NOFILE; close(f++))
 272:             ;
 273:         open("/dev/tty", 0);
 274:         open("/dev/tty", 1);
 275:         dup2(1, 2);
 276:         execl(DN, rindex(DN, '/') ? rindex(DN, '/')+1 : DN, printer, 0);
 277:         dfname[inchar]++;
 278:     }
 279:     out();
 280: }
 281: 
 282: copy(f, n)
 283: int f;
 284: char n[];
 285: {
 286:     int ff, i, nr, nc;
 287:     char buf[BUFSIZ];
 288: 
 289:     for(i=0;i<ncopies;i++) {
 290:         if (prflag) {
 291:             card('H', title ? title : n);
 292:             card('R', cfname);
 293:         } else
 294:             card('F', cfname);
 295:         card('N', n);
 296:     }
 297:     card('U', cfname);
 298:     ff = nfile(cfname);
 299:     nr = nc = 0;
 300:     while((i = read(f, buf, BUFSIZ)) > 0) {
 301:         if (write(ff, buf, i) != i) {
 302:             printf("%s: %s: temp file write error\n", name, n);
 303:             break;
 304:         }
 305:         nc += i;
 306:         if(nc >= BUFSIZ) {
 307:             nc -= BUFSIZ;
 308:             if(nr++ > MX) {
 309:                 printf("%s: %s: copy file is too large\n", name, n);
 310:                 break;
 311:             }
 312:         }
 313:     }
 314:     close(ff);
 315:     nact++;
 316: }
 317: 
 318: card(c, p2)
 319: register char c, *p2;
 320: {
 321:     char buf[BUFSIZ];
 322:     register char *p1 = buf;
 323:     int col = 0;
 324: 
 325:     *p1++ = c;
 326:     while((c = *p2++) != '\0') {
 327:         *p1++ = c;
 328:         col++;
 329:     }
 330:     *p1++ = '\n';
 331:     write(tff, buf, col+2);
 332: }
 333: 
 334: ident()
 335: {
 336:     extern char *getlogin();
 337:     extern struct passwd *getpwuid();
 338:     struct passwd *pw;
 339:     extern char *itoa();
 340: 
 341:     if ((person = getlogin()) == NULL) {
 342:         if ((pw = getpwuid(user)) == NULL)
 343:             person = "Unknown User";
 344:         else
 345:             person = pw->pw_name;
 346:     }
 347: 
 348:     card('J',jobname);
 349:     card('C',class);
 350:     card('L', person);
 351:     if (iflag)
 352:         card('I', itoa(indent));
 353:     if (mailflg)
 354:         card('M', person);
 355: }
 356: 
 357: nfile(n)
 358: char *n;
 359: {
 360:     register f;
 361:     int oldumask = umask(022);      /* should hold signals */
 362: 
 363:     f = creat(n, FILMOD);
 364:     (void) umask(oldumask);
 365:     if (f < 0) {
 366:         printf("%s: cannot create %s\n", name, n);
 367:         out();
 368:     }
 369:     if (chown(n, user, spgroup) < 0) {
 370:         unlink(n);
 371:         printf("%s: cannot chown %s\n", name, n);
 372:         out();
 373:     }
 374:     n[inchar]++;
 375:     return(f);
 376: }
 377: 
 378: out()
 379: {
 380:     register i;
 381: 
 382:     signal(SIGHUP, SIG_IGN);
 383:     signal(SIGINT, SIG_IGN);
 384:     signal(SIGQUIT, SIG_IGN);
 385:     signal(SIGTERM, SIG_IGN);
 386:     i = inchar;
 387:     if (tfname)
 388:         while(tfname[i] != 'A') {
 389:             tfname[i]--;
 390:             unlink(tfname);
 391:         }
 392:     if (cfname)
 393:         while(cfname[i] != 'A') {
 394:             cfname[i]--;
 395:             unlink(cfname);
 396:         }
 397:     if (lfname)
 398:         while(lfname[i] != 'A') {
 399:             lfname[i]--;
 400:             unlink(lfname);
 401:         }
 402:     if (dfname)
 403:         while(dfname[i] != 'A') {
 404:             dfname[i]--;
 405:             unlink(dfname);
 406:         }
 407:     exit();
 408: }
 409: 
 410: test(file)
 411: char *file;
 412: {
 413:     struct exec buf;
 414:     struct stat mbuf;
 415:     int fd;
 416: 
 417:     if (access(file, 4) < 0) {
 418:         printf("%s: cannot access %s\n", name, file);
 419:         return(-1);
 420:     }
 421:     if(stat(file, &mbuf) < 0) {
 422:         printf("%s: cannot stat %s\n", name, file);
 423:         return (-1);
 424:     }
 425:     if ((mbuf.st_mode&S_IFMT) == S_IFDIR) {
 426:         printf("%s: %s is a directory\n", name, file);
 427:         return(-1);
 428:     }
 429: 
 430:     if((fd = open(file, 0)) < 0) {
 431:         printf("%s: cannot open %s\n", name, file);
 432:         return(-1);
 433:     }
 434:     if (read(fd, &buf, sizeof(buf)) == sizeof(buf))
 435:         switch(buf.a_magic) {
 436:         case A_MAGIC1:
 437:         case A_MAGIC2:
 438:         case A_MAGIC3:
 439: #ifdef A_MAGIC4
 440:         case A_MAGIC4:
 441: #endif
 442:             printf("%s: %s is an executable program", name, file);
 443:             goto error1;
 444: 
 445:         case ARMAG:
 446:             printf("%s: %s is an archive file", name, file);
 447:             goto error1;
 448:         }
 449: 
 450:     close(fd);
 451:     return(0);
 452: error1:
 453:     printf(" and is unprintable\n");
 454:     close(fd);
 455:     return(-1);
 456: }
 457: 
 458: /*
 459:  * itoa - integer to string conversion
 460:  */
 461: char *
 462: itoa(i)
 463: register int i;
 464: {
 465:     static char b[10] = "########";
 466:     register char *p;
 467: 
 468:     p = &b[8];
 469:     do
 470:         *p-- = i%10 + '0';
 471:     while (i /= 10);
 472:     return(++p);
 473: }
 474: 
 475: /*
 476:  * Perform lookup for printer name or abbreviation --
 477:  *   return pointer to daemon structure
 478:  */
 479: chkprinter(s)
 480: register char *s;
 481: {
 482:     static char buf[BUFSIZ/2];
 483:     char b[BUFSIZ];
 484:     int stat;
 485:     char *bp = buf;
 486: 
 487:     if ((stat = pgetent(b, s)) < 0) {
 488:         fprintf(stderr, "%s: can't open printer description file\n", name);
 489:         exit(3);
 490:     } else if (stat == 0)
 491:         return(NULL);
 492:     if ((DN = pgetstr("dn", &bp)) == NULL)
 493:         DN = DEFDAEMON;
 494:     if ((LP = pgetstr("lp", &bp)) == NULL)
 495:         LP = DEFDEVLP;
 496:     if ((SD = pgetstr("sd", &bp)) == NULL)
 497:         SD = DEFSPOOL;
 498:     if ((MX = pgetnum("mx")) < 0)
 499:         MX = DEFMX;
 500:     return(1);
 501: }
 502: 
 503: /*
 504:  * Make a temp file
 505:  */
 506: char *
 507: mktmp(id, pid, n)
 508: char *id;
 509: {
 510:     register char *s;
 511: 
 512:     if ((s = malloc(n)) == NULL) {
 513:         fprintf(stderr, "%s: out of memory\n", name);
 514:         exit(1);
 515:     }
 516:     sprintf(s, "%s/%sA%05d", SD, id, pid);
 517:     return(s);
 518: }

Defined functions

card defined in line 318; used 19 times
chkprinter defined in line 479; used 1 times
copy defined in line 282; used 2 times
ident defined in line 334; used 1 times
itoa defined in line 461; used 2 times
main defined in line 62; never used
mktmp defined in line 506; used 5 times
nfile defined in line 357; used 2 times
out defined in line 378; used 9 times
test defined in line 410; used 1 times

Defined variables

DN defined in line 42; used 6 times
LP defined in line 44; used 3 times
MX defined in line 45; used 3 times
SD defined in line 43; used 4 times
cfname defined in line 26; used 9 times
class defined in line 51; used 3 times
daemname defined in line 41; never used
dfname defined in line 28; used 9 times
hdr defined in line 46; used 4 times
hostname defined in line 50; used 3 times
iflag defined in line 39; used 2 times
inchar defined in line 37; used 7 times
indent defined in line 40; used 2 times
jflag defined in line 33; used 2 times
jobname defined in line 52; used 5 times
lfname defined in line 27; used 10 times
mailflg defined in line 32; used 2 times
nact defined in line 30; used 4 times
name defined in line 53; used 17 times
ncopies defined in line 38; used 4 times
person defined in line 36; used 5 times
prflag defined in line 35; used 4 times
printer defined in line 54; used 6 times
qflg defined in line 34; used 2 times
spgroup defined in line 48; used 2 times
tff defined in line 31; used 2 times
tfname defined in line 25; used 10 times
title defined in line 49; used 8 times
user defined in line 47; used 3 times
Last modified: 1983-12-09
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1209
Valid CSS Valid XHTML 1.0 Strict