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