displayq.c revision 30437
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)); 79static void warn __P((void)); 80 81/* 82 * Display the current state of the queue. Format = 1 if long format. 83 */ 84void 85displayq(format) 86 int format; 87{ 88 register struct queue *q; 89 register int i, nitems, fd, ret; 90 register char *cp; 91 struct queue **queue; 92 struct stat statb; 93 FILE *fp; 94 void (*savealrm)(int); 95 96 lflag = format; 97 totsize = 0; 98 rank = -1; 99 if ((i = cgetent(&bp, printcapdb, printer)) == -2) 100 fatal("can't open printer description file"); 101 else if (i == -1) 102 fatal("unknown printer"); 103 else if (i == -3) 104 fatal("potential reference loop detected in printcap file"); 105 if (cgetstr(bp, "lp", &LP) < 0) 106 LP = _PATH_DEFDEVLP; 107 if (cgetstr(bp, "rp", &RP) < 0) 108 RP = DEFLP; 109 if (cgetstr(bp, "sd", &SD) < 0) 110 SD = _PATH_DEFSPOOL; 111 if (cgetstr(bp,"lo", &LO) < 0) 112 LO = DEFLOCK; 113 if (cgetstr(bp, "st", &ST) < 0) 114 ST = DEFSTAT; 115 if (cgetnum(bp, "ct", &CT) < 0) 116 CT = DEFTIMEOUT; 117 if (cgetstr(bp, "rm", &RM) < 0) 118 RM = NULL; 119 if ((cp = checkremote())) 120 printf("Warning: %s\n", cp); 121 122 /* 123 * Print out local queue 124 * Find all the control files in the spooling directory 125 */ 126 seteuid(euid); 127 if (chdir(SD) < 0) 128 fatal("cannot chdir to spooling directory"); 129 seteuid(uid); 130 if ((nitems = getq(&queue)) < 0) 131 fatal("cannot examine spooling area\n"); 132 seteuid(euid); 133 ret = stat(LO, &statb); 134 seteuid(uid); 135 if (ret >= 0) { 136 if (statb.st_mode & 0100) { 137 if (remote) 138 printf("%s: ", host); 139 printf("Warning: %s is down: ", printer); 140 seteuid(euid); 141 fd = open(ST, O_RDONLY); 142 seteuid(uid); 143 if (fd >= 0) { 144 (void) flock(fd, LOCK_SH); 145 while ((i = read(fd, line, sizeof(line))) > 0) 146 (void) fwrite(line, 1, i, stdout); 147 (void) close(fd); /* unlocks as well */ 148 } else 149 putchar('\n'); 150 } 151 if (statb.st_mode & 010) { 152 if (remote) 153 printf("%s: ", host); 154 printf("Warning: %s queue is turned off\n", printer); 155 } 156 } 157 158 if (nitems) { 159 seteuid(euid); 160 fp = fopen(LO, "r"); 161 seteuid(uid); 162 if (fp == NULL) 163 warn(); 164 else { 165 /* get daemon pid */ 166 cp = current; 167 while ((i = getc(fp)) != EOF && i != '\n') 168 *cp++ = i; 169 *cp = '\0'; 170 i = atoi(current); 171 if (i <= 0) { 172 ret = -1; 173 } else { 174 seteuid(euid); 175 ret = kill(i, 0); 176 seteuid(uid); 177 } 178 if (ret < 0) { 179 warn(); 180 } else { 181 /* read current file name */ 182 cp = current; 183 while ((i = getc(fp)) != EOF && i != '\n') 184 *cp++ = i; 185 *cp = '\0'; 186 /* 187 * Print the status file. 188 */ 189 if (remote) 190 printf("%s: ", host); 191 seteuid(euid); 192 fd = open(ST, O_RDONLY); 193 seteuid(uid); 194 if (fd >= 0) { 195 (void) flock(fd, LOCK_SH); 196 while ((i = read(fd, line, sizeof(line))) > 0) 197 (void) fwrite(line, 1, i, stdout); 198 (void) close(fd); /* unlocks as well */ 199 } else 200 putchar('\n'); 201 } 202 (void) fclose(fp); 203 } 204 /* 205 * Now, examine the control files and print out the jobs to 206 * be done for each user. 207 */ 208 if (!lflag) 209 header(); 210 for (i = 0; i < nitems; i++) { 211 q = queue[i]; 212 inform(q->q_name); 213 free(q); 214 } 215 free(queue); 216 } 217 if (!remote) { 218 if (nitems == 0) 219 puts("no entries"); 220 return; 221 } 222 223 /* 224 * Print foreign queue 225 * Note that a file in transit may show up in either queue. 226 */ 227 if (nitems) 228 putchar('\n'); 229 (void) snprintf(line, sizeof(line), "%c%s", format + '\3', RP); 230 cp = line; 231 for (i = 0; i < requests && cp-line+10 < sizeof(line) - 1; i++) { 232 cp += strlen(cp); 233 (void) sprintf(cp, " %d", requ[i]); 234 } 235 for (i = 0; i < users && cp - line + 1 + strlen(user[i]) < 236 sizeof(line) - 1; i++) { 237 cp += strlen(cp); 238 *cp++ = ' '; 239 (void) strcpy(cp, user[i]); 240 } 241 strcat(line, "\n"); 242 savealrm = signal(SIGALRM, alarmhandler); 243 alarm(CT); 244 fd = getport(RM, 0); 245 (void)signal(SIGALRM, savealrm); 246 if (fd < 0) { 247 if (from != host) 248 printf("%s: ", host); 249 printf("connection to %s is down\n", RM); 250 } 251 else { 252 i = strlen(line); 253 if (write(fd, line, i) != i) 254 fatal("Lost connection"); 255 while ((i = read(fd, line, sizeof(line))) > 0) 256 (void) fwrite(line, 1, i, stdout); 257 (void) close(fd); 258 } 259} 260 261/* 262 * Print a warning message if there is no daemon present. 263 */ 264static void 265warn() 266{ 267 if (remote) 268 printf("%s: ", host); 269 puts("Warning: no daemon present"); 270 current[0] = '\0'; 271} 272 273/* 274 * Print the header for the short listing format 275 */ 276void 277header() 278{ 279 printf(head0); 280 col = strlen(head0)+1; 281 blankfill(SIZCOL); 282 printf(head1); 283} 284 285void 286inform(cf) 287 char *cf; 288{ 289 register int j; 290 FILE *cfp; 291 292 /* 293 * There's a chance the control file has gone away 294 * in the meantime; if this is the case just keep going 295 */ 296 seteuid(euid); 297 if ((cfp = fopen(cf, "r")) == NULL) 298 return; 299 seteuid(uid); 300 301 if (rank < 0) 302 rank = 0; 303 if (remote || garbage || strcmp(cf, current)) 304 rank++; 305 j = 0; 306 while (getline(cfp)) { 307 switch (line[0]) { 308 case 'P': /* Was this file specified in the user's list? */ 309 if (!inlist(line+1, cf)) { 310 fclose(cfp); 311 return; 312 } 313 if (lflag) { 314 printf("\n%s: ", line+1); 315 col = strlen(line+1) + 2; 316 prank(rank); 317 blankfill(JOBCOL); 318 printf(" [job %s]\n", cf+3); 319 } else { 320 col = 0; 321 prank(rank); 322 blankfill(OWNCOL); 323 printf("%-10s %-3d ", line+1, atoi(cf+3)); 324 col += 16; 325 first = 1; 326 } 327 continue; 328 default: /* some format specifer and file name? */ 329 if (line[0] < 'a' || line[0] > 'z') 330 continue; 331 if (j == 0 || strcmp(file, line+1) != 0) { 332 (void) strncpy(file, line+1, sizeof(file) - 1); 333 file[sizeof(file) - 1] = '\0'; 334 } 335 j++; 336 continue; 337 case 'N': 338 show(line+1, file, j); 339 file[0] = '\0'; 340 j = 0; 341 } 342 } 343 fclose(cfp); 344 if (!lflag) { 345 blankfill(SIZCOL); 346 printf("%ld bytes\n", totsize); 347 totsize = 0; 348 } 349} 350 351int 352inlist(name, file) 353 char *name, *file; 354{ 355 register int *r, n; 356 register char **u, *cp; 357 358 if (users == 0 && requests == 0) 359 return(1); 360 /* 361 * Check to see if it's in the user list 362 */ 363 for (u = user; u < &user[users]; u++) 364 if (!strcmp(*u, name)) 365 return(1); 366 /* 367 * Check the request list 368 */ 369 for (n = 0, cp = file+3; isdigit(*cp); ) 370 n = n * 10 + (*cp++ - '0'); 371 for (r = requ; r < &requ[requests]; r++) 372 if (*r == n && !strcmp(cp, from)) 373 return(1); 374 return(0); 375} 376 377void 378show(nfile, file, copies) 379 register char *nfile, *file; 380 int copies; 381{ 382 if (strcmp(nfile, " ") == 0) 383 nfile = "(standard input)"; 384 if (lflag) 385 ldump(nfile, file, copies); 386 else 387 dump(nfile, file, copies); 388} 389 390/* 391 * Fill the line with blanks to the specified column 392 */ 393void 394blankfill(n) 395 register int n; 396{ 397 while (col++ < n) 398 putchar(' '); 399} 400 401/* 402 * Give the abbreviated dump of the file names 403 */ 404void 405dump(nfile, file, copies) 406 char *nfile, *file; 407 int copies; 408{ 409 register short n, fill; 410 struct stat lbuf; 411 412 /* 413 * Print as many files as will fit 414 * (leaving room for the total size) 415 */ 416 fill = first ? 0 : 2; /* fill space for ``, '' */ 417 if (((n = strlen(nfile)) + col + fill) >= SIZCOL-4) { 418 if (col < SIZCOL) { 419 printf(" ..."), col += 4; 420 blankfill(SIZCOL); 421 } 422 } else { 423 if (first) 424 first = 0; 425 else 426 printf(", "); 427 printf("%s", nfile); 428 col += n+fill; 429 } 430 seteuid(euid); 431 if (*file && !stat(file, &lbuf)) 432 totsize += copies * lbuf.st_size; 433 seteuid(uid); 434} 435 436/* 437 * Print the long info about the file 438 */ 439void 440ldump(nfile, file, copies) 441 char *nfile, *file; 442 int copies; 443{ 444 struct stat lbuf; 445 446 putchar('\t'); 447 if (copies > 1) 448 printf("%-2d copies of %-19s", copies, nfile); 449 else 450 printf("%-32s", nfile); 451 if (*file && !stat(file, &lbuf)) 452 printf(" %qd bytes", lbuf.st_size); 453 else 454 printf(" ??? bytes"); 455 putchar('\n'); 456} 457 458/* 459 * Print the job's rank in the queue, 460 * update col for screen management 461 */ 462void 463prank(n) 464 int n; 465{ 466 char rline[100]; 467 static char *r[] = { 468 "th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th" 469 }; 470 471 if (n == 0) { 472 printf("active"); 473 col += 6; 474 return; 475 } 476 if ((n/10)%10 == 1) 477 (void)snprintf(rline, sizeof(rline), "%dth", n); 478 else 479 (void)snprintf(rline, sizeof(rline), "%d%s", n, r[n%10]); 480 col += strlen(rline); 481 printf("%s", rline); 482} 483 484void 485alarmhandler(signo) 486 int signo; 487{ 488 /* ignored */ 489} 490