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