1 /* $NetBSD: displayq.c,v 1.20 2001/06/25 11:04:52 mrg 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.20 2001/06/25 11:04:52 mrg 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[40]; /* current file being printed */ 80 static char file[132]; /* 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; 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 while ((i = getc(fp)) != EOF && i != '\n') 177 *cp++ = i; 178 *cp = '\0'; 179 i = atoi(current); 180 if (i <= 0) { 181 ret = -1; 182 } else { 183 seteuid(euid); 184 ret = kill(i, 0); 185 seteuid(uid); 186 } 187 if (ret < 0) { 188 nodaemon(); 189 } else { 190 /* read current file name */ 191 cp = current; 192 while ((i = getc(fp)) != EOF && i != '\n') 193 *cp++ = i; 194 *cp = '\0'; 195 /* 196 * Print the status file. 197 */ 198 if (remote) 199 printf("%s: ", host); 200 seteuid(euid); 201 fd = open(ST, O_RDONLY); 202 seteuid(uid); 203 if (fd >= 0) { 204 (void)flock(fd, LOCK_SH); 205 while ((i = read(fd, line, sizeof(line))) > 0) 206 (void)fwrite(line, 1, (size_t)i, stdout); 207 (void)close(fd); /* unlocks as well */ 208 } else 209 putchar('\n'); 210 } 211 (void)fclose(fp); 212 } 213 /* 214 * Now, examine the control files and print out the jobs to 215 * be done for each user. 216 */ 217 if (!lflag) 218 header(); 219 for (i = 0; i < nitems; i++) { 220 q = queue[i]; 221 inform(q->q_name); 222 free(q); 223 } 224 free(queue); 225 } 226 if (!remote) { 227 if (nitems == 0) 228 puts("no entries"); 229 return; 230 } 231 232 /* 233 * Print foreign queue 234 * Note that a file in transit may show up in either queue. 235 */ 236 if (nitems) 237 putchar('\n'); 238 (void)snprintf(line, sizeof(line), "%c%s", format + '\3', RP); 239 cp = line; 240 for (i = 0; i < requests && cp-line+10 < sizeof(line) - 1; i++) { 241 cp += strlen(cp); 242 (void)snprintf(cp, (size_t)(line - cp), " %d", requ[i]); 243 } 244 for (i = 0; i < users && cp - line + 1 + strlen(user[i]) < 245 sizeof(line) - 1; i++) { 246 cp += strlen(cp); 247 if (cp - line > sizeof(line) - 1) 248 break; 249 *cp++ = ' '; 250 if (strlen(user[i]) < (sizeof(line) - (cp - line) - 1)) 251 (void)strcpy(cp, user[i]); 252 else 253 (void)strncpy(cp, user[i], 254 (sizeof(line) - (cp - line) - 1)); 255 } 256 (void)strncat(line, "\n", sizeof(line) - strlen(line) - 1); 257 fd = getport(RM, 0); 258 if (fd < 0) { 259 if (from != host) 260 printf("%s: ", host); 261 (void)printf("connection to %s is down\n", RM); 262 } 263 else { 264 struct sigaction osa, nsa; 265 266 i = strlen(line); 267 if (write(fd, line, (size_t)i) != i) 268 fatal("Lost connection"); 269 nsa.sa_handler = alarmer; 270 sigemptyset(&nsa.sa_mask); 271 sigaddset(&nsa.sa_mask, SIGALRM); 272 nsa.sa_flags = 0; 273 (void)sigaction(SIGALRM, &nsa, &osa); 274 alarm(wait_time); 275 while ((i = read(fd, line, sizeof(line))) > 0) { 276 (void)fwrite(line, 1, (size_t)i, stdout); 277 alarm(wait_time); 278 } 279 alarm(0); 280 (void)sigaction(SIGALRM, &osa, NULL); 281 (void)close(fd); 282 } 283 } 284 285 static void 286 alarmer(s) 287 int s; 288 { 289 /* nothing */ 290 } 291 292 /* 293 * Print a warning message if there is no daemon present. 294 */ 295 void 296 nodaemon() 297 { 298 if (remote) 299 printf("\n%s: ", host); 300 puts("Warning: no daemon present"); 301 current[0] = '\0'; 302 } 303 304 /* 305 * Print the header for the short listing format 306 */ 307 void 308 header() 309 { 310 printf(head0); 311 col = strlen(head0)+1; 312 blankfill(SIZCOL); 313 printf(head1); 314 } 315 316 void 317 inform(cf) 318 char *cf; 319 { 320 int j; 321 FILE *cfp; 322 323 /* 324 * There's a chance the control file has gone away 325 * in the meantime; if this is the case just keep going 326 */ 327 seteuid(euid); 328 if ((cfp = fopen(cf, "r")) == NULL) 329 return; 330 seteuid(uid); 331 332 if (rank < 0) 333 rank = 0; 334 if (remote || garbage || strcmp(cf, current)) 335 rank++; 336 j = 0; 337 while (getline(cfp)) { 338 switch (line[0]) { 339 case 'P': /* Was this file specified in the user's list? */ 340 if (!inlist(line+1, cf)) { 341 fclose(cfp); 342 return; 343 } 344 if (lflag) { 345 printf("\n%s: ", line+1); 346 col = strlen(line+1) + 2; 347 prank(rank); 348 blankfill(JOBCOL); 349 printf(" [job %s]\n", cf+3); 350 } else { 351 col = 0; 352 prank(rank); 353 blankfill(OWNCOL); 354 printf("%-10s %-3d ", line+1, atoi(cf+3)); 355 col += 16; 356 first = 1; 357 } 358 continue; 359 default: /* some format specifer and file name? */ 360 if (line[0] < 'a' || line[0] > 'z') 361 continue; 362 if (j == 0 || strcmp(file, line+1) != 0) { 363 (void)strncpy(file, line+1, sizeof(file) - 1); 364 file[sizeof(file) - 1] = '\0'; 365 } 366 j++; 367 continue; 368 case 'N': 369 show(line+1, file, j); 370 file[0] = '\0'; 371 j = 0; 372 } 373 } 374 fclose(cfp); 375 if (!lflag) { 376 blankfill(SIZCOL); 377 printf("%ld bytes\n", totsize); 378 totsize = 0; 379 } 380 } 381 382 int 383 inlist(name, file) 384 char *name, *file; 385 { 386 int *r, n; 387 char **u, *cp; 388 389 if (users == 0 && requests == 0) 390 return(1); 391 /* 392 * Check to see if it's in the user list 393 */ 394 for (u = user; u < &user[users]; u++) 395 if (!strcmp(*u, name)) 396 return(1); 397 /* 398 * Check the request list 399 */ 400 for (n = 0, cp = file+3; isdigit(*cp); ) 401 n = n * 10 + (*cp++ - '0'); 402 for (r = requ; r < &requ[requests]; r++) 403 if (*r == n && !strcmp(cp, from)) 404 return(1); 405 return(0); 406 } 407 408 void 409 show(nfile, file, copies) 410 char *nfile, *file; 411 int copies; 412 { 413 if (strcmp(nfile, " ") == 0) 414 nfile = "(standard input)"; 415 if (lflag) 416 ldump(nfile, file, copies); 417 else 418 dump(nfile, file, copies); 419 } 420 421 /* 422 * Fill the line with blanks to the specified column 423 */ 424 void 425 blankfill(n) 426 int n; 427 { 428 while (col++ < n) 429 putchar(' '); 430 } 431 432 /* 433 * Give the abbreviated dump of the file names 434 */ 435 void 436 dump(nfile, file, copies) 437 char *nfile, *file; 438 int copies; 439 { 440 short n, fill; 441 struct stat lbuf; 442 443 /* 444 * Print as many files as will fit 445 * (leaving room for the total size) 446 */ 447 fill = first ? 0 : 2; /* fill space for ``, '' */ 448 if (((n = strlen(nfile)) + col + fill) >= SIZCOL-4) { 449 if (col < SIZCOL) { 450 printf(" ..."), col += 4; 451 blankfill(SIZCOL); 452 } 453 } else { 454 if (first) 455 first = 0; 456 else 457 printf(", "); 458 printf("%s", nfile); 459 col += n+fill; 460 } 461 seteuid(euid); 462 if (*file && !stat(file, &lbuf)) 463 totsize += copies * (long)lbuf.st_size; 464 seteuid(uid); 465 } 466 467 /* 468 * Print the long info about the file 469 */ 470 void 471 ldump(nfile, file, copies) 472 char *nfile, *file; 473 int copies; 474 { 475 struct stat lbuf; 476 477 putchar('\t'); 478 if (copies > 1) 479 printf("%-2d copies of %-19s", copies, nfile); 480 else 481 printf("%-32s", nfile); 482 if (*file && !stat(file, &lbuf)) 483 printf(" %lld bytes", (long long)lbuf.st_size); 484 else 485 printf(" ??? bytes"); 486 putchar('\n'); 487 } 488 489 /* 490 * Print the job's rank in the queue, 491 * update col for screen management 492 */ 493 void 494 prank(n) 495 int n; 496 { 497 char rline[100]; 498 static char *r[] = { 499 "th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th" 500 }; 501 502 if (n == 0) { 503 printf("active"); 504 col += 6; 505 return; 506 } 507 if ((n/10)%10 == 1) 508 (void)snprintf(rline, sizeof(rline), "%dth", n); 509 else 510 (void)snprintf(rline, sizeof(rline), "%d%s", n, r[n%10]); 511 col += strlen(rline); 512 printf("%s", rline); 513 } 514