displayq.c revision 27757
1/* 2 * Copyright (c) 1983, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34#ifndef lint 35static char sccsid[] = "@(#)displayq.c 8.4 (Berkeley) 4/28/95"; 36#endif /* not lint */ 37 38#include <sys/param.h> 39#include <sys/stat.h> 40#include <sys/file.h> 41 42#include <signal.h> 43#include <fcntl.h> 44#include <dirent.h> 45#include <unistd.h> 46#include <stdio.h> 47#include <stdlib.h> 48#include <string.h> 49#include <ctype.h> 50#include "lp.h" 51#include "lp.local.h" 52#include "pathnames.h" 53 54/* 55 * Routines to display the state of the queue. 56 */ 57#define JOBCOL 40 /* column for job # in -l format */ 58#define OWNCOL 7 /* start of Owner column in normal */ 59#define SIZCOL 62 /* start of Size column in normal */ 60 61/* 62 * Stuff for handling job specifications 63 */ 64extern uid_t uid, euid; 65 66static int col; /* column on screen */ 67static char current[40]; /* current file being printed */ 68static char file[132]; /* print file name */ 69static int first; /* first file in ``files'' column? */ 70static int garbage; /* # of garbage cf files */ 71static int lflag; /* long output option */ 72static int rank; /* order to be printed (-1=none, 0=active) */ 73static long totsize; /* total print job size in bytes */ 74 75static char *head0 = "Rank Owner Job Files"; 76static char *head1 = "Total Size\n"; 77 78static void alarmhandler __P((int)); 79 80/* 81 * Display the current state of the queue. Format = 1 if long format. 82 */ 83void 84displayq(format) 85 int format; 86{ 87 register struct queue *q; 88 register int i, nitems, fd, ret; 89 register char *cp; 90 struct queue **queue; 91 struct stat statb; 92 FILE *fp; 93 void (*savealrm)(int); 94 95 lflag = format; 96 totsize = 0; 97 rank = -1; 98 if ((i = cgetent(&bp, printcapdb, printer)) == -2) 99 fatal("can't open printer description file"); 100 else if (i == -1) 101 fatal("unknown printer"); 102 else if (i == -3) 103 fatal("potential reference loop detected in printcap file"); 104 if (cgetstr(bp, "lp", &LP) < 0) 105 LP = _PATH_DEFDEVLP; 106 if (cgetstr(bp, "rp", &RP) < 0) 107 RP = DEFLP; 108 if (cgetstr(bp, "sd", &SD) < 0) 109 SD = _PATH_DEFSPOOL; 110 if (cgetstr(bp,"lo", &LO) < 0) 111 LO = DEFLOCK; 112 if (cgetstr(bp, "st", &ST) < 0) 113 ST = DEFSTAT; 114 cgetstr(bp, "rm", &RM); 115 if ((cp = checkremote())) 116 printf("Warning: %s\n", cp); 117 118 /* 119 * Print out local queue 120 * Find all the control files in the spooling directory 121 */ 122 seteuid(euid); 123 if (chdir(SD) < 0) 124 fatal("cannot chdir to spooling directory"); 125 seteuid(uid); 126 if ((nitems = getq(&queue)) < 0) 127 fatal("cannot examine spooling area\n"); 128 seteuid(euid); 129 ret = stat(LO, &statb); 130 seteuid(uid); 131 if (ret >= 0) { 132 if (statb.st_mode & 0100) { 133 if (remote) 134 printf("%s: ", host); 135 printf("Warning: %s is down: ", printer); 136 seteuid(euid); 137 fd = open(ST, O_RDONLY); 138 seteuid(uid); 139 if (fd >= 0) { 140 (void) flock(fd, LOCK_SH); 141 while ((i = read(fd, line, sizeof(line))) > 0) 142 (void) fwrite(line, 1, i, stdout); 143 (void) close(fd); /* unlocks as well */ 144 } else 145 putchar('\n'); 146 } 147 if (statb.st_mode & 010) { 148 if (remote) 149 printf("%s: ", host); 150 printf("Warning: %s queue is turned off\n", printer); 151 } 152 } 153 154 if (nitems) { 155 seteuid(euid); 156 fp = fopen(LO, "r"); 157 seteuid(uid); 158 if (fp == NULL) 159 warn(); 160 else { 161 /* get daemon pid */ 162 cp = current; 163 while ((i = getc(fp)) != EOF && i != '\n') 164 *cp++ = i; 165 *cp = '\0'; 166 i = atoi(current); 167 if (i <= 0) { 168 ret = -1; 169 } else { 170 seteuid(euid); 171 ret = kill(i, 0); 172 seteuid(uid); 173 } 174 if (ret < 0) { 175 warn(); 176 } else { 177 /* read current file name */ 178 cp = current; 179 while ((i = getc(fp)) != EOF && i != '\n') 180 *cp++ = i; 181 *cp = '\0'; 182 /* 183 * Print the status file. 184 */ 185 if (remote) 186 printf("%s: ", host); 187 seteuid(euid); 188 fd = open(ST, O_RDONLY); 189 seteuid(uid); 190 if (fd >= 0) { 191 (void) flock(fd, LOCK_SH); 192 while ((i = read(fd, line, sizeof(line))) > 0) 193 (void) fwrite(line, 1, i, stdout); 194 (void) close(fd); /* unlocks as well */ 195 } else 196 putchar('\n'); 197 } 198 (void) fclose(fp); 199 } 200 /* 201 * Now, examine the control files and print out the jobs to 202 * be done for each user. 203 */ 204 if (!lflag) 205 header(); 206 for (i = 0; i < nitems; i++) { 207 q = queue[i]; 208 inform(q->q_name); 209 free(q); 210 } 211 free(queue); 212 } 213 if (!remote) { 214 if (nitems == 0) 215 puts("no entries"); 216 return; 217 } 218 219 /* 220 * Print foreign queue 221 * Note that a file in transit may show up in either queue. 222 */ 223 if (nitems) 224 putchar('\n'); 225 (void) snprintf(line, sizeof(line), "%c%s", format + '\3', RP); 226 cp = line; 227 for (i = 0; i < requests && cp-line+10 < sizeof(line) - 1; i++) { 228 cp += strlen(cp); 229 (void) sprintf(cp, " %d", requ[i]); 230 } 231 for (i = 0; i < users && cp - line + 1 + strlen(user[i]) < 232 sizeof(line) - 1; i++) { 233 cp += strlen(cp); 234 *cp++ = ' '; 235 (void) strcpy(cp, user[i]); 236 } 237 strcat(line, "\n"); 238 savealrm = signal(SIGALRM, alarmhandler); 239 alarm(10); 240 fd = getport(RM, 0); 241 (void)signal(SIGALRM, savealrm); 242 if (fd < 0) { 243 if (from != host) 244 printf("%s: ", host); 245 printf("connection to %s is down\n", RM); 246 } 247 else { 248 i = strlen(line); 249 if (write(fd, line, i) != i) 250 fatal("Lost connection"); 251 while ((i = read(fd, line, sizeof(line))) > 0) 252 (void) fwrite(line, 1, i, stdout); 253 (void) close(fd); 254 } 255} 256 257/* 258 * Print a warning message if there is no daemon present. 259 */ 260void 261warn() 262{ 263 if (remote) 264 printf("\n%s: ", host); 265 puts("Warning: no daemon present"); 266 current[0] = '\0'; 267} 268 269/* 270 * Print the header for the short listing format 271 */ 272void 273header() 274{ 275 printf(head0); 276 col = strlen(head0)+1; 277 blankfill(SIZCOL); 278 printf(head1); 279} 280 281void 282inform(cf) 283 char *cf; 284{ 285 register int j; 286 FILE *cfp; 287 288 /* 289 * There's a chance the control file has gone away 290 * in the meantime; if this is the case just keep going 291 */ 292 seteuid(euid); 293 if ((cfp = fopen(cf, "r")) == NULL) 294 return; 295 seteuid(uid); 296 297 if (rank < 0) 298 rank = 0; 299 if (remote || garbage || strcmp(cf, current)) 300 rank++; 301 j = 0; 302 while (getline(cfp)) { 303 switch (line[0]) { 304 case 'P': /* Was this file specified in the user's list? */ 305 if (!inlist(line+1, cf)) { 306 fclose(cfp); 307 return; 308 } 309 if (lflag) { 310 printf("\n%s: ", line+1); 311 col = strlen(line+1) + 2; 312 prank(rank); 313 blankfill(JOBCOL); 314 printf(" [job %s]\n", cf+3); 315 } else { 316 col = 0; 317 prank(rank); 318 blankfill(OWNCOL); 319 printf("%-10s %-3d ", line+1, atoi(cf+3)); 320 col += 16; 321 first = 1; 322 } 323 continue; 324 default: /* some format specifer and file name? */ 325 if (line[0] < 'a' || line[0] > 'z') 326 continue; 327 if (j == 0 || strcmp(file, line+1) != 0) { 328 (void) strncpy(file, line+1, sizeof(file) - 1); 329 file[sizeof(file) - 1] = '\0'; 330 } 331 j++; 332 continue; 333 case 'N': 334 show(line+1, file, j); 335 file[0] = '\0'; 336 j = 0; 337 } 338 } 339 fclose(cfp); 340 if (!lflag) { 341 blankfill(SIZCOL); 342 printf("%ld bytes\n", totsize); 343 totsize = 0; 344 } 345} 346 347int 348inlist(name, file) 349 char *name, *file; 350{ 351 register int *r, n; 352 register char **u, *cp; 353 354 if (users == 0 && requests == 0) 355 return(1); 356 /* 357 * Check to see if it's in the user list 358 */ 359 for (u = user; u < &user[users]; u++) 360 if (!strcmp(*u, name)) 361 return(1); 362 /* 363 * Check the request list 364 */ 365 for (n = 0, cp = file+3; isdigit(*cp); ) 366 n = n * 10 + (*cp++ - '0'); 367 for (r = requ; r < &requ[requests]; r++) 368 if (*r == n && !strcmp(cp, from)) 369 return(1); 370 return(0); 371} 372 373void 374show(nfile, file, copies) 375 register char *nfile, *file; 376 int copies; 377{ 378 if (strcmp(nfile, " ") == 0) 379 nfile = "(standard input)"; 380 if (lflag) 381 ldump(nfile, file, copies); 382 else 383 dump(nfile, file, copies); 384} 385 386/* 387 * Fill the line with blanks to the specified column 388 */ 389void 390blankfill(n) 391 register int n; 392{ 393 while (col++ < n) 394 putchar(' '); 395} 396 397/* 398 * Give the abbreviated dump of the file names 399 */ 400void 401dump(nfile, file, copies) 402 char *nfile, *file; 403 int copies; 404{ 405 register short n, fill; 406 struct stat lbuf; 407 408 /* 409 * Print as many files as will fit 410 * (leaving room for the total size) 411 */ 412 fill = first ? 0 : 2; /* fill space for ``, '' */ 413 if (((n = strlen(nfile)) + col + fill) >= SIZCOL-4) { 414 if (col < SIZCOL) { 415 printf(" ..."), col += 4; 416 blankfill(SIZCOL); 417 } 418 } else { 419 if (first) 420 first = 0; 421 else 422 printf(", "); 423 printf("%s", nfile); 424 col += n+fill; 425 } 426 seteuid(euid); 427 if (*file && !stat(file, &lbuf)) 428 totsize += copies * lbuf.st_size; 429 seteuid(uid); 430} 431 432/* 433 * Print the long info about the file 434 */ 435void 436ldump(nfile, file, copies) 437 char *nfile, *file; 438 int copies; 439{ 440 struct stat lbuf; 441 442 putchar('\t'); 443 if (copies > 1) 444 printf("%-2d copies of %-19s", copies, nfile); 445 else 446 printf("%-32s", nfile); 447 if (*file && !stat(file, &lbuf)) 448 printf(" %qd bytes", lbuf.st_size); 449 else 450 printf(" ??? bytes"); 451 putchar('\n'); 452} 453 454/* 455 * Print the job's rank in the queue, 456 * update col for screen management 457 */ 458void 459prank(n) 460 int n; 461{ 462 char rline[100]; 463 static char *r[] = { 464 "th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th" 465 }; 466 467 if (n == 0) { 468 printf("active"); 469 col += 6; 470 return; 471 } 472 if ((n/10)%10 == 1) 473 (void)snprintf(rline, sizeof(rline), "%dth", n); 474 else 475 (void)snprintf(rline, sizeof(rline), "%d%s", n, r[n%10]); 476 col += strlen(rline); 477 printf("%s", rline); 478} 479 480void 481alarmhandler(signo) 482 int signo; 483{ 484 /* ignored */ 485} 486