1 /* $NetBSD: displayq.c,v 1.10 1997/07/10 06:19:53 mikel 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 #if 0 38 static char sccsid[] = "@(#)displayq.c 8.1 (Berkeley) 6/6/93"; 39 #else 40 static char rcsid[] = "$NetBSD: displayq.c,v 1.10 1997/07/10 06:19:53 mikel Exp $"; 41 #endif 42 #endif /* not lint */ 43 44 #include <sys/param.h> 45 #include <sys/stat.h> 46 47 #include <signal.h> 48 #include <fcntl.h> 49 #include <dirent.h> 50 #include <unistd.h> 51 #include <stdio.h> 52 #include <stdlib.h> 53 #include <string.h> 54 #include <ctype.h> 55 #include "lp.h" 56 #include "lp.local.h" 57 #include "pathnames.h" 58 59 /* 60 * Routines to display the state of the queue. 61 */ 62 #define JOBCOL 40 /* column for job # in -l format */ 63 #define OWNCOL 7 /* start of Owner column in normal */ 64 #define SIZCOL 62 /* start of Size column in normal */ 65 66 /* 67 * Stuff for handling job specifications 68 */ 69 extern int requ[]; /* job number of spool entries */ 70 extern int requests; /* # of spool requests */ 71 extern char *user[]; /* users to process */ 72 extern int users; /* # of users in user array */ 73 74 extern uid_t uid, euid; 75 76 static int col; /* column on screen */ 77 static char current[40]; /* current file being printed */ 78 static char file[132]; /* print file name */ 79 static int first; /* first file in ``files'' column? */ 80 static int garbage; /* # of garbage cf files */ 81 static int lflag; /* long output option */ 82 static int rank; /* order to be printed (-1=none, 0=active) */ 83 static long totsize; /* total print job size in bytes */ 84 85 static char *head0 = "Rank Owner Job Files"; 86 static char *head1 = "Total Size\n"; 87 88 /* 89 * Display the current state of the queue. Format = 1 if long format. 90 */ 91 void 92 displayq(format) 93 int format; 94 { 95 register struct queue *q; 96 register int i, nitems, fd, ret, c; 97 register char *cp; 98 struct queue **queue; 99 struct stat statb; 100 FILE *fp; 101 102 lflag = format; 103 totsize = 0; 104 rank = -1; 105 if ((i = cgetent(&bp, printcapdb, printer)) == -2) 106 fatal("can't open printer description file"); 107 else if (i == -1) 108 fatal("unknown printer"); 109 else if (i == -3) 110 fatal("potential reference loop detected in printcap file"); 111 if (cgetstr(bp, "lp", &LP) < 0) 112 LP = _PATH_DEFDEVLP; 113 if (cgetstr(bp, "rp", &RP) < 0) 114 RP = DEFLP; 115 if (cgetstr(bp, "sd", &SD) < 0) 116 SD = _PATH_DEFSPOOL; 117 if (cgetstr(bp,"lo", &LO) < 0) 118 LO = DEFLOCK; 119 if (cgetstr(bp, "st", &ST) < 0) 120 ST = DEFSTAT; 121 cgetstr(bp, "rm", &RM); 122 if ((cp = checkremote()) != NULL) 123 printf("Warning: %s\n", cp); 124 125 /* 126 * Print out local queue 127 * Find all the control files in the spooling directory 128 */ 129 seteuid(euid); 130 if (chdir(SD) < 0) 131 fatal("cannot chdir to spooling directory"); 132 seteuid(uid); 133 if ((nitems = getq(&queue)) < 0) 134 fatal("cannot examine spooling area\n"); 135 seteuid(euid); 136 ret = stat(LO, &statb); 137 seteuid(uid); 138 if (ret >= 0) { 139 if (statb.st_mode & 0100) { 140 if (sendtorem) 141 printf("%s: ", host); 142 printf("Warning: %s is down: ", printer); 143 seteuid(euid); 144 fd = open(ST, O_RDONLY); 145 seteuid(uid); 146 if (fd >= 0) { 147 (void)flock(fd, LOCK_SH); 148 while ((i = read(fd, line, sizeof(line))) > 0) 149 (void)fwrite(line, 1, i, stdout); 150 (void)close(fd); /* unlocks as well */ 151 } else 152 putchar('\n'); 153 } 154 if (statb.st_mode & 010) { 155 if (sendtorem) 156 printf("%s: ", host); 157 printf("Warning: %s queue is turned off\n", printer); 158 } 159 } 160 161 if (nitems) { 162 seteuid(euid); 163 fp = fopen(LO, "r"); 164 seteuid(uid); 165 if (fp == NULL) 166 warn(); 167 else { 168 /* get daemon pid */ 169 cp = current; 170 while ((c = getc(fp)) != EOF && (*cp = c) != '\n') 171 cp++; 172 *cp = '\0'; 173 i = atoi(current); 174 if (i <= 0) { 175 ret = -1; 176 } else { 177 seteuid(euid); 178 ret = kill(i, 0); 179 seteuid(uid); 180 } 181 if (ret < 0) { 182 warn(); 183 } else { 184 /* read current file name */ 185 cp = current; 186 while ((c = getc(fp)) != EOF && 187 (*cp = c) != '\n') 188 cp++; 189 *cp = '\0'; 190 /* 191 * Print the status file. 192 */ 193 if (sendtorem) 194 printf("%s: ", host); 195 seteuid(euid); 196 fd = open(ST, O_RDONLY); 197 seteuid(uid); 198 if (fd >= 0) { 199 (void)flock(fd, LOCK_SH); 200 while ((i = read(fd, line, sizeof(line))) > 0) 201 (void)fwrite(line, 1, i, stdout); 202 (void)close(fd); /* unlocks as well */ 203 } else 204 putchar('\n'); 205 } 206 (void)fclose(fp); 207 } 208 /* 209 * Now, examine the control files and print out the jobs to 210 * be done for each user. 211 */ 212 if (!lflag) 213 header(); 214 for (i = 0; i < nitems; i++) { 215 q = queue[i]; 216 inform(q->q_name); 217 free(q); 218 } 219 free(queue); 220 } 221 if (!sendtorem) { 222 if (nitems == 0) 223 puts("no entries"); 224 return; 225 } 226 227 /* 228 * Print foreign queue 229 * Note that a file in transit may show up in either queue. 230 */ 231 if (nitems) 232 putchar('\n'); 233 (void)snprintf(line, sizeof(line), "%c%s", format + '\3', RP); 234 cp = line; 235 for (i = 0; i < requests; i++) { 236 cp += strlen(cp); 237 (void)snprintf(cp, line - cp, " %d", requ[i]); 238 } 239 for (i = 0; i < users; i++) { 240 cp += strlen(cp); 241 if (cp - line > sizeof(line) - 1) 242 break; 243 *cp++ = ' '; 244 (void)strncpy(cp, user[i], line - cp - 1); 245 } 246 (void)strncat(line, "\n", sizeof(line) - strlen(line) - 1); 247 fd = getport(RM); 248 if (fd < 0) { 249 if (from != host) 250 printf("%s: ", host); 251 (void)printf("connection to %s is down\n", RM); 252 } 253 else { 254 i = strlen(line); 255 if (write(fd, line, i) != i) 256 fatal("Lost connection"); 257 while ((i = read(fd, line, sizeof(line))) > 0) 258 (void)fwrite(line, 1, i, stdout); 259 (void)close(fd); 260 } 261 } 262 263 /* 264 * Print a warning message if there is no daemon present. 265 */ 266 void 267 warn() 268 { 269 if (sendtorem) 270 printf("\n%s: ", host); 271 puts("Warning: no daemon present"); 272 current[0] = '\0'; 273 } 274 275 /* 276 * Print the header for the short listing format 277 */ 278 void 279 header() 280 { 281 printf(head0); 282 col = strlen(head0)+1; 283 blankfill(SIZCOL); 284 printf(head1); 285 } 286 287 void 288 inform(cf) 289 char *cf; 290 { 291 register int j; 292 FILE *cfp; 293 294 /* 295 * There's a chance the control file has gone away 296 * in the meantime; if this is the case just keep going 297 */ 298 seteuid(euid); 299 if ((cfp = fopen(cf, "r")) == NULL) 300 return; 301 seteuid(uid); 302 303 if (rank < 0) 304 rank = 0; 305 if (sendtorem || garbage || strcmp(cf, current)) 306 rank++; 307 j = 0; 308 while (getline(cfp)) { 309 switch (line[0]) { 310 case 'P': /* Was this file specified in the user's list? */ 311 if (!inlist(line+1, cf)) { 312 fclose(cfp); 313 return; 314 } 315 if (lflag) { 316 printf("\n%s: ", line+1); 317 col = strlen(line+1) + 2; 318 prank(rank); 319 blankfill(JOBCOL); 320 printf(" [job %s]\n", cf+3); 321 } else { 322 col = 0; 323 prank(rank); 324 blankfill(OWNCOL); 325 printf("%-10s %-3d ", line+1, atoi(cf+3)); 326 col += 16; 327 first = 1; 328 } 329 continue; 330 default: /* some format specifer and file name? */ 331 if (line[0] < 'a' || line[0] > 'z') 332 continue; 333 if (j == 0 || strcmp(file, line+1) != 0) 334 (void)strncpy(file, line+1, sizeof(file) - 1); 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 351 int 352 inlist(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 377 void 378 show(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 */ 393 void 394 blankfill(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 */ 404 void 405 dump(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 */ 439 void 440 ldump(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 */ 462 void 463 prank(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