1 /* $NetBSD: displayq.c,v 1.9 1997/04/19 06:33:13 thorpej Exp $ */ 2 3 /* 4 * Copyright (c) 1983, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #ifndef lint 37 static char sccsid[] = "@(#)displayq.c 8.1 (Berkeley) 6/6/93"; 38 #endif /* not lint */ 39 40 #include <sys/param.h> 41 #include <sys/stat.h> 42 43 #include <signal.h> 44 #include <fcntl.h> 45 #include <dirent.h> 46 #include <unistd.h> 47 #include <stdio.h> 48 #include <stdlib.h> 49 #include <string.h> 50 #include <ctype.h> 51 #include "lp.h" 52 #include "lp.local.h" 53 #include "pathnames.h" 54 55 /* 56 * Routines to display the state of the queue. 57 */ 58 #define JOBCOL 40 /* column for job # in -l format */ 59 #define OWNCOL 7 /* start of Owner column in normal */ 60 #define SIZCOL 62 /* start of Size column in normal */ 61 62 /* 63 * Stuff for handling job specifications 64 */ 65 extern int requ[]; /* job number of spool entries */ 66 extern int requests; /* # of spool requests */ 67 extern char *user[]; /* users to process */ 68 extern int users; /* # of users in user array */ 69 70 extern uid_t uid, euid; 71 72 static int col; /* column on screen */ 73 static char current[40]; /* current file being printed */ 74 static char file[132]; /* print file name */ 75 static int first; /* first file in ``files'' column? */ 76 static int garbage; /* # of garbage cf files */ 77 static int lflag; /* long output option */ 78 static int rank; /* order to be printed (-1=none, 0=active) */ 79 static long totsize; /* total print job size in bytes */ 80 81 static char *head0 = "Rank Owner Job Files"; 82 static char *head1 = "Total Size\n"; 83 84 /* 85 * Display the current state of the queue. Format = 1 if long format. 86 */ 87 void 88 displayq(format) 89 int format; 90 { 91 register struct queue *q; 92 register int i, nitems, fd, ret, c; 93 register char *cp; 94 struct queue **queue; 95 struct stat statb; 96 FILE *fp; 97 98 lflag = format; 99 totsize = 0; 100 rank = -1; 101 if ((i = cgetent(&bp, printcapdb, printer)) == -2) 102 fatal("can't open printer description file"); 103 else if (i == -1) 104 fatal("unknown printer"); 105 else if (i == -3) 106 fatal("potential reference loop detected in printcap file"); 107 if (cgetstr(bp, "lp", &LP) < 0) 108 LP = _PATH_DEFDEVLP; 109 if (cgetstr(bp, "rp", &RP) < 0) 110 RP = DEFLP; 111 if (cgetstr(bp, "sd", &SD) < 0) 112 SD = _PATH_DEFSPOOL; 113 if (cgetstr(bp,"lo", &LO) < 0) 114 LO = DEFLOCK; 115 if (cgetstr(bp, "st", &ST) < 0) 116 ST = DEFSTAT; 117 cgetstr(bp, "rm", &RM); 118 if (cp = checkremote()) 119 printf("Warning: %s\n", cp); 120 121 /* 122 * Print out local queue 123 * Find all the control files in the spooling directory 124 */ 125 seteuid(euid); 126 if (chdir(SD) < 0) 127 fatal("cannot chdir to spooling directory"); 128 seteuid(uid); 129 if ((nitems = getq(&queue)) < 0) 130 fatal("cannot examine spooling area\n"); 131 seteuid(euid); 132 ret = stat(LO, &statb); 133 seteuid(uid); 134 if (ret >= 0) { 135 if (statb.st_mode & 0100) { 136 if (sendtorem) 137 printf("%s: ", host); 138 printf("Warning: %s is down: ", printer); 139 seteuid(euid); 140 fd = open(ST, O_RDONLY); 141 seteuid(uid); 142 if (fd >= 0) { 143 (void)flock(fd, LOCK_SH); 144 while ((i = read(fd, line, sizeof(line))) > 0) 145 (void)fwrite(line, 1, i, stdout); 146 (void)close(fd); /* unlocks as well */ 147 } else 148 putchar('\n'); 149 } 150 if (statb.st_mode & 010) { 151 if (sendtorem) 152 printf("%s: ", host); 153 printf("Warning: %s queue is turned off\n", printer); 154 } 155 } 156 157 if (nitems) { 158 seteuid(euid); 159 fp = fopen(LO, "r"); 160 seteuid(uid); 161 if (fp == NULL) 162 warn(); 163 else { 164 /* get daemon pid */ 165 cp = current; 166 while ((c = getc(fp)) != EOF && (*cp = c) != '\n') 167 cp++; 168 *cp = '\0'; 169 i = atoi(current); 170 if (i <= 0) { 171 ret = -1; 172 } else { 173 seteuid(euid); 174 ret = kill(i, 0); 175 seteuid(uid); 176 } 177 if (ret < 0) { 178 warn(); 179 } else { 180 /* read current file name */ 181 cp = current; 182 while ((c = getc(fp)) != EOF && 183 (*cp = c) != '\n') 184 cp++; 185 *cp = '\0'; 186 /* 187 * Print the status file. 188 */ 189 if (sendtorem) 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 (!sendtorem) { 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; i++) { 232 cp += strlen(cp); 233 (void)snprintf(cp, line - cp, " %d", requ[i]); 234 } 235 for (i = 0; i < users; i++) { 236 cp += strlen(cp); 237 if (cp - line > sizeof(line) - 1) 238 break; 239 *cp++ = ' '; 240 (void)strncpy(cp, user[i], line - cp - 1); 241 } 242 (void)strncat(line, "\n", sizeof(line) - strlen(line) - 1); 243 fd = getport(RM); 244 if (fd < 0) { 245 if (from != host) 246 printf("%s: ", host); 247 (void)printf("connection to %s is down\n", RM); 248 } 249 else { 250 i = strlen(line); 251 if (write(fd, line, i) != i) 252 fatal("Lost connection"); 253 while ((i = read(fd, line, sizeof(line))) > 0) 254 (void)fwrite(line, 1, i, stdout); 255 (void)close(fd); 256 } 257 } 258 259 /* 260 * Print a warning message if there is no daemon present. 261 */ 262 void 263 warn() 264 { 265 if (sendtorem) 266 printf("\n%s: ", host); 267 puts("Warning: no daemon present"); 268 current[0] = '\0'; 269 } 270 271 /* 272 * Print the header for the short listing format 273 */ 274 void 275 header() 276 { 277 printf(head0); 278 col = strlen(head0)+1; 279 blankfill(SIZCOL); 280 printf(head1); 281 } 282 283 void 284 inform(cf) 285 char *cf; 286 { 287 register int j; 288 FILE *cfp; 289 290 /* 291 * There's a chance the control file has gone away 292 * in the meantime; if this is the case just keep going 293 */ 294 seteuid(euid); 295 if ((cfp = fopen(cf, "r")) == NULL) 296 return; 297 seteuid(uid); 298 299 if (rank < 0) 300 rank = 0; 301 if (sendtorem || garbage || strcmp(cf, current)) 302 rank++; 303 j = 0; 304 while (getline(cfp)) { 305 switch (line[0]) { 306 case 'P': /* Was this file specified in the user's list? */ 307 if (!inlist(line+1, cf)) { 308 fclose(cfp); 309 return; 310 } 311 if (lflag) { 312 printf("\n%s: ", line+1); 313 col = strlen(line+1) + 2; 314 prank(rank); 315 blankfill(JOBCOL); 316 printf(" [job %s]\n", cf+3); 317 } else { 318 col = 0; 319 prank(rank); 320 blankfill(OWNCOL); 321 printf("%-10s %-3d ", line+1, atoi(cf+3)); 322 col += 16; 323 first = 1; 324 } 325 continue; 326 default: /* some format specifer and file name? */ 327 if (line[0] < 'a' || line[0] > 'z') 328 continue; 329 if (j == 0 || strcmp(file, line+1) != 0) 330 (void)strncpy(file, line+1, sizeof(file) - 1); 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 347 int 348 inlist(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 373 void 374 show(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 */ 389 void 390 blankfill(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 */ 400 void 401 dump(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 */ 435 void 436 ldump(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 */ 458 void 459 prank(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