1: /*	%M%	%I%	%E%	*/
   2: /*
   3:  * Spool Queue examination program
   4:  *
   5:  * lpq [+[n]] [-Pprinter] [users...]
   6:  *
   7:  * + =>'s continually scan q until empty
   8:  * -P used to identify printer as per lpr/lpd
   9:  */
  10: 
  11: #include    <stdio.h>
  12: #include    <sys/types.h>
  13: #include    <sys/dir.h>
  14: #include    <pwd.h>
  15: #include    <sgtty.h>
  16: #include    <sys/stat.h>
  17: #include    <ctype.h>
  18: #include    "lp.local.h"
  19: 
  20: #define MAXUSERS    50
  21: #define MAXJOBS     50
  22: #define READ        0
  23: #define DEFTIME     10      /* default sleep interval */
  24: #define JOBCOL      40      /* column for job # in -l format */
  25: #define OWNCOL      7       /* start of Owner column in normal */
  26: 
  27: struct  passwd user[MAXUSERS];      /* when users are specified */
  28: struct  direct *pdir;           /* for sorting stuff */
  29: 
  30: int jobs[MAXJOBS];          /* jobs specified on command line */
  31: int njobs = 0;          /* # of entries in jobs */
  32: int users;              /* # of users in user or < 0 */
  33: int current_pid;            /* current daemon file pid */
  34: int garbage = 0;            /* # of garbage df files */
  35: int rank = 0;           /* order to be printed */
  36: int slptime = DEFTIME;      /* pause between screen refereshes */
  37: int repeat = 0;         /* + flag indicator */
  38: int col;                /* column on screen */
  39: int lflag = 0;          /* long output option */
  40: int first;              /* first file in ``files'' column ? */
  41: int SIZCOL = 62;            /* start of Size column in normal */
  42: 
  43: char    line[132];          /* input line from daemon file */
  44: char    file[132];          /* print file name guess */
  45: char    ufile[132];         /* unlink file */
  46: char    *head0 = "Rank   Owner      Job #  Files";
  47: char    *head1 = "Total Size\n";
  48: 
  49: long    totsize = 0;            /* total print job size in bytes */
  50: 
  51: /*
  52:  * Printcap (a la termcap) stuff for mutiple printers
  53:  */
  54: char    *SD;                /* spooling directory */
  55: char    *LO;                /* name of lock file */
  56: char    *LP;                /* line printer name */
  57: char    *pgetstr();
  58: 
  59: struct passwd *getpwnam(), *getpwuid();
  60: char    *index();
  61: char    *getenv();
  62: 
  63: main(argc, argv)
  64:     char *argv[];
  65: {
  66:     register struct passwd *p;
  67:     register int n;
  68: 
  69:     argv++;
  70:     while (argc > 1) {
  71:         if (argv[0][0] == '+') {
  72:             if (argv[0][1] != '\0')
  73:                 if ((slptime = atoi(&argv[0][1])) < 0)
  74:                     slptime = DEFTIME;
  75:             repeat++;
  76:         } else if (argv[0][0] == '-')
  77:             switch(argv[0][1]) {
  78: 
  79:             case 'P':       /* printer name */
  80:                 if (!chkprinter(&argv[0][2]))
  81:                     fatal("%s: unknown printer", &argv[0][2]);
  82:                 break;
  83: 
  84:             case 'l':       /* long output */
  85:                 lflag++;
  86:                 break;
  87: 
  88:             default:
  89:                 usage();
  90:         } else {
  91:             if (isdigit(argv[0][0])) {
  92:                 if (njobs >= MAXJOBS)
  93:                     fatal("too many jobs requested");
  94:                 jobs[njobs++] = atoi(argv[0]);
  95:             } else {
  96:                 if (users >= MAXUSERS)
  97:                     fatal("too many users");
  98:                 p = getpwnam(*argv);
  99:                 if (p)
 100:                     user[users++] = *p;
 101:                 else
 102:                     printf("unknown user %s\n", *argv);
 103:             }
 104:         }
 105:         argc--;
 106:         argv++;
 107:     }
 108:     if (!users && !njobs)
 109:         users = -1;
 110:     if (SD == NULL) {
 111:         char *pr;
 112: 
 113:         if ((pr = getenv("PRINTER")) == NULL)
 114:             pr = DEFLP;
 115:         if (!chkprinter(pr))
 116:             fatal("%s: unknown printer", pr);
 117:     }
 118:     if (chdir(SD) < 0)
 119:         fatal("can't chdir to spooling area");
 120: 
 121:     if (repeat)
 122:         do {
 123:             if ((n = display()) > 0) {
 124:                 sleep(slptime);
 125:                 rank = 0;
 126:             }
 127:         } while (n > 0);
 128:     else
 129:         display();
 130: }
 131: 
 132: /*
 133:  * Display the current state of the q
 134:  */
 135: display()
 136: {
 137:     register int i, nitems;
 138:     int spfd;
 139:     struct stat statb;
 140:     int dcomp();
 141: 
 142:     /*
 143: 	 * Find all the spool files in the spooling directory
 144: 	 */
 145:     if ((spfd = open(".", READ)) < 0)
 146:         fatal("can't examine spooling area");
 147:     lseek(spfd, (long)(2*sizeof(struct direct)), 0);
 148:     pdir = (struct direct *)malloc(sizeof(struct direct));
 149:     nitems = 0;
 150:     while (1) {
 151:         struct direct *proto;
 152: 
 153:         proto = &pdir[nitems];
 154:         if (read(spfd, (char *)proto, sizeof(*proto)) != sizeof(*proto))
 155:             break;
 156:         if (proto->d_ino == 0 || proto->d_name[0] != 'd' ||
 157:             proto->d_name[1] != 'f')
 158:             continue;   /* just daemon files */
 159:         nitems++;
 160:         proto = (struct direct *)realloc((char *)pdir,
 161:                 (nitems+1)*sizeof(struct direct));
 162:         if (proto == NULL) {
 163:             standout(stdout, "out of memory, only showing %d jobs\n", nitems);
 164:             break;
 165:         }
 166:         pdir = proto;
 167:     }
 168:     if (nitems == 0) {
 169:         printf("no entries\n");
 170:         return(0);
 171:     }
 172:     close(spfd);
 173:     if ((spfd = open(LO, READ)) < 0)
 174:         garbage = nitems;
 175:     else {
 176:         lseek(spfd, (long)sizeof(int), 0);  /* skip daemon id */
 177:         if (read(spfd, (char *)&current_pid, sizeof(int)) != sizeof(int))
 178:             current_pid = -1;       /* should be invalid */
 179:         close(spfd);
 180:     }
 181:     qsort(pdir, nitems, sizeof(struct direct), dcomp);
 182:     /*
 183: 	 * Now, examine the daemon files and print out the jobs to
 184: 	 * be done for each user
 185: 	 */
 186:     if (!lflag && garbage < nitems)
 187:         header();
 188:     for (i = garbage; i < nitems; i++)
 189:         inform(pdir[i].d_name, 0);
 190: 
 191:     /*
 192: 	 * What's left is garbage, inform the user
 193: 	 */
 194:     if (garbage > 0) {
 195:         register short down = stat(LP, &statb) >= 0 &&
 196:                     (statb.st_mode&0777) == 0;
 197:         standout(stdout, down ? "Warning: printer down" :
 198:                 "Warning: no daemon present");
 199:         putchar('\n');
 200:         if (!lflag)
 201:             header();
 202:         for (i = 0; i < garbage; i++)
 203:             inform(pdir[i].d_name, 1);
 204:     }
 205:     return(nitems-garbage);
 206: }
 207: 
 208: /*
 209:  * Print the header for the short listing format
 210:  */
 211: header()
 212: {
 213:     printf(head0);
 214:     col = strlen(head0)+1;
 215:     blankfill(SIZCOL);
 216:     printf(head1);
 217: }
 218: 
 219: /*
 220:  * If we have the capability, print this in standout mode
 221:  */
 222: standout(f, s, a)
 223:     FILE *f;
 224:     register char *s;
 225: {
 226: }
 227: 
 228: dcomp(d1, d2)
 229:     register struct direct *d1, *d2;
 230: {
 231:     return(strncmp(d1->d_name, d2->d_name, DIRSIZ));
 232: }
 233: 
 234: inform(df, garb)
 235:     char *df;
 236: {
 237:     register int j, k;
 238:     register struct passwd *p;
 239:     FILE *fd;
 240:     int spfd, dfpid = atoi(df+3);
 241:     char *owner;
 242:     struct stat buf;
 243: 
 244:     /*
 245: 	 * There's a chance the daemon file has gone away
 246: 	 * in the meantime; if this is the case just keep going
 247: 	 */
 248:     if ((spfd = open(df, READ)) < 0)
 249:         return;
 250: 
 251:     fstat(spfd, &buf);
 252:     /*
 253: 	 * Was this file specified in the user's list
 254: 	 */
 255:     for (j = 0; j < users; j++)
 256:         if (user[j].pw_uid == buf.st_uid)
 257:             break;
 258:     if (j >= users) {           /* scan jobs list */
 259:         for (k = 0; k < njobs; k++)
 260:             if (dfpid == jobs[k])
 261:                 break;
 262:     } else
 263:         k = njobs;
 264:     if (users < 0 || j < users || k < njobs) {  /* found one */
 265:         if (lflag)
 266:             putchar('\n');
 267:         col = 0;
 268:         if (users < 0 || k < njobs)
 269:             owner = (p = getpwuid(buf.st_uid)) == NULL ? "???" :
 270:                     p->pw_name;
 271:         else if ((owner = user[j].pw_name) == NULL)
 272:             owner = "???";
 273:         if (lflag)
 274:             col += strlen(owner);
 275:         if (!garb && dfpid == current_pid)
 276:             rank = 0;
 277:         else
 278:             rank++;
 279:         if (lflag) {
 280:             printf("%s: ", owner), col += 2;
 281:             prank(rank);
 282:             blankfill(JOBCOL);
 283:             printf(" [job #%d]\n", dfpid);
 284:         } else {
 285:             prank(rank);
 286:             blankfill(OWNCOL);
 287:             printf("%-10s %-5d  ", owner, dfpid), col += 18;
 288:             first = 1;
 289:         }
 290: 
 291:         /*
 292: 		 * Now list the files associated with the
 293: 		 * print job
 294: 		 */
 295:         fd = fdopen(spfd, "r");
 296:         j = 0;          /* # of copies of a file */
 297:         *file = *ufile = '\0';
 298: 
 299:         while (fgets(line, sizeof(line), fd) != NULL) {
 300: 
 301:             switch(line[0]) {
 302: 
 303:             default:
 304:                 continue;
 305:             case 'N':
 306:                 if (*file) {
 307:                     /*
 308: 					 * Could miss a file which has been
 309: 					 *   linked...
 310: 					 */
 311:                     if (strcmp(file, line+1)) {
 312:                         show(file, file, j);
 313:                         j = 0;
 314:                         if (strcmp(line+1, " \n"))
 315:                             strcpy(file, line+1);
 316:                         continue;
 317:                     }
 318:                     j++;
 319:                 } else if (strcmp(line+1, " \n"))
 320:                     strcpy(file, line+1);
 321:                 k++;
 322:                 continue;
 323:             case 'U':
 324:                 strcpy(ufile, line+1);
 325:                 break;
 326: 
 327:             }
 328:             show(file, ufile, j);
 329:             j = 0;
 330:         }
 331:         fclose(fd);
 332:         if (*file)          /* there's a file left over */
 333:             show(file, ufile, j);
 334:         if (!lflag) {
 335:             blankfill(SIZCOL);
 336:             printf("%D bytes\n", totsize);
 337:             totsize = 0;
 338:         }
 339:     } else
 340:         rank++;
 341:     close(spfd);
 342: }
 343: 
 344: show(file, ufile, copies)
 345:     register char *ufile, *file;
 346: {
 347:     register char *t;
 348: 
 349:     if ((t = index(file, '\n')) == NULL)
 350:         strcpy(file, "(standard input)");
 351:     else
 352:         *t = '\0';
 353:     if ((t = index(ufile, '\n')) != NULL)
 354:         *t = '\0';
 355:     if (lflag)
 356:         ldump(file, *ufile ? ufile : file, copies);
 357:     else
 358:         dump(file, *ufile ? ufile : file, copies);
 359:     *ufile = *file = '\0';
 360: }
 361: 
 362: /*
 363:  * Fill the line with blanks to the specified column
 364:  */
 365: blankfill(n)
 366:     register int n;
 367: {
 368:     while (col++ < n)
 369:         putchar(' ');
 370: }
 371: 
 372: /*
 373:  * Give the abbreviated dump of the file names
 374:  */
 375: dump(file, ufile, copies)
 376:     char *file, *ufile;
 377: {
 378:     register short n, fill;
 379:     struct stat lbuf;
 380: 
 381:     /*
 382: 	 * Print as many files as will fit
 383: 	 *  (leaving room for the total size)
 384: 	 */
 385:      fill = first ? 0 : 2;  /* fill space for ``, '' */
 386:      if (((n = strlen(file)) + col + fill) >= SIZCOL-4) {
 387:         if (col < SIZCOL) {
 388:             printf(" ..."), col += 4;
 389:             blankfill(SIZCOL);
 390:         }
 391:     } else {
 392:         if (first)
 393:             first = 0;
 394:         else
 395:             printf(", ");
 396:         printf("%s", file);
 397:         col += n+fill;
 398:     }
 399:     if (*ufile && !stat(ufile, &lbuf))
 400:         totsize += copies ? (copies+1)*lbuf.st_size : lbuf.st_size;
 401: }
 402: 
 403: /*
 404:  * Print the long info about the file
 405:  */
 406: ldump(file, ufile, copies)
 407:     char *file, *ufile;
 408: {
 409:     struct stat lbuf;
 410: 
 411:     putchar('\t');
 412:     if (copies)
 413:         printf("%-2d copies of %-19s", copies+1, file);
 414:     else
 415:         printf("%-32s", file);
 416:     if (*ufile) {
 417:         if (!stat(ufile, &lbuf))
 418:             printf(" %D bytes", lbuf.st_size);
 419:         else
 420:             printf(" ??? bytes");
 421:     } else
 422:         printf(" ??? bytes");
 423:     putchar('\n');
 424: }
 425: 
 426: /*
 427:  * Print the job's rank in the queue,
 428:  *   update col for screen management
 429:  */
 430: prank(n)
 431: {
 432:     char line[100];
 433:     static char *r[] = {
 434:         "th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th"
 435:     };
 436: 
 437:     if (n == 0) {
 438:         printf("active");
 439:         col += 6;
 440:         return;
 441:     }
 442:     if ((n/10) == 1)
 443:         sprintf(line, "%dth", n);
 444:     else
 445:         sprintf(line, "%d%s", n, r[n%10]);
 446:     col += strlen(line);
 447:     printf("%s", line);
 448: }
 449: 
 450: usage()
 451: {
 452:     printf("usage: lpq [-l] [+[n]] [-Pprinter] [users...]\n");
 453:     exit(1);
 454: }
 455: 
 456: fatal(s, a)
 457:     char *s;
 458: {
 459:     standout(stderr, "lpq: ");
 460:     standout(stderr, s, a);
 461:     putc('\n', stderr);
 462:     exit(2);
 463: }
 464: 
 465: /*
 466:  * Interrogate the printer data base
 467:  */
 468: chkprinter(s)
 469:     char *s;
 470: {
 471:     static char buf[BUFSIZ/2];
 472:     char b[BUFSIZ];
 473:     int stat;
 474:     char *bp = buf;
 475: 
 476:     if ((stat = pgetent(b, s)) < 0)
 477:         fatal("can't open description file");
 478:     else if (stat == 0)
 479:         return(0);
 480:     if ((LP = pgetstr("lp", &bp)) == NULL)
 481:         LP = DEFDEVLP;
 482:     if ((SD = pgetstr("sd", &bp)) == NULL)
 483:         SD = DEFSPOOL;
 484:     if ((LO = pgetstr("lo", &bp)) == NULL)
 485:         LO = DEFLOCK;
 486:     return(1);
 487: }

Defined functions

blankfill defined in line 365; used 5 times
chkprinter defined in line 468; used 2 times
dcomp defined in line 228; used 2 times
display defined in line 135; used 2 times
dump defined in line 375; used 1 times
fatal defined in line 456; used 7 times
header defined in line 211; used 2 times
inform defined in line 234; used 2 times
ldump defined in line 406; used 1 times
main defined in line 63; never used
prank defined in line 430; used 2 times
show defined in line 344; used 3 times
standout defined in line 222; used 4 times
usage defined in line 450; used 1 times
  • in line 89

Defined variables

LO defined in line 55; used 3 times
LP defined in line 56; used 3 times
SD defined in line 54; used 4 times
SIZCOL defined in line 41; used 5 times
col defined in line 38; used 12 times
current_pid defined in line 33; used 3 times
file defined in line 44; used 27 times
first defined in line 40; used 4 times
garbage defined in line 34; used 6 times
head0 defined in line 46; used 2 times
head1 defined in line 47; used 1 times
jobs defined in line 30; used 2 times
lflag defined in line 39; used 8 times
line defined in line 43; used 14 times
njobs defined in line 31; used 7 times
pdir defined in line 28; used 7 times
rank defined in line 35; used 6 times
repeat defined in line 37; used 2 times
slptime defined in line 36; used 3 times
totsize defined in line 49; used 3 times
ufile defined in line 45; used 20 times
user defined in line 27; used 3 times
users defined in line 32; used 9 times

Defined macros

DEFTIME defined in line 23; used 2 times
JOBCOL defined in line 24; used 1 times
MAXJOBS defined in line 21; used 2 times
MAXUSERS defined in line 20; used 2 times
OWNCOL defined in line 25; used 1 times
READ defined in line 22; used 3 times
Last modified: 1983-12-09
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1497
Valid CSS Valid XHTML 1.0 Strict