1 /* $NetBSD: displayq.c,v 1.29 2006/01/04 15:32:50 garbled 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.29 2006/01/04 15:32:50 garbled 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 fname[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, *rmhost; 99 struct queue **queue; 100 struct stat statb; 101 FILE *fp; 102 103 lflag = format; 104 totsize = 0; 105 rank = -1; 106 getprintcap(printer); 107 108 /* 109 * Print out local queue 110 * Find all the control files in the spooling directory 111 */ 112 seteuid(euid); 113 if (chdir(SD) < 0) 114 fatal("cannot chdir to spooling directory"); 115 seteuid(uid); 116 if ((nitems = getq(&queue)) < 0) 117 fatal("cannot examine spooling area\n"); 118 seteuid(euid); 119 ret = stat(LO, &statb); 120 seteuid(uid); 121 if (ret >= 0) { 122 if (statb.st_mode & S_IXUSR) { 123 if (remote) 124 printf("%s: ", host); 125 printf("Warning: %s is down: ", printer); 126 seteuid(euid); 127 fd = open(ST, O_RDONLY); 128 seteuid(uid); 129 if (fd >= 0) { 130 (void)flock(fd, LOCK_SH); 131 while ((i = read(fd, line, sizeof(line))) > 0) 132 (void)fwrite(line, 1, (size_t)i, stdout); 133 (void)close(fd); /* unlocks as well */ 134 } else 135 putchar('\n'); 136 } 137 if (statb.st_mode & S_IXGRP) { 138 if (remote) 139 printf("%s: ", host); 140 printf("Warning: %s queue is turned off\n", printer); 141 } 142 } 143 144 if (nitems) { 145 seteuid(euid); 146 fp = fopen(LO, "r"); 147 seteuid(uid); 148 if (fp == NULL) 149 nodaemon(); 150 else { 151 /* get daemon pid */ 152 cp = current; 153 ecp = cp + sizeof(current) - 1; 154 while ((i = getc(fp)) != EOF && i != '\n') { 155 if (cp < ecp) 156 *cp++ = i; 157 } 158 *cp = '\0'; 159 i = atoi(current); 160 if (i <= 0) { 161 ret = -1; 162 } else { 163 seteuid(euid); 164 ret = kill(i, 0); 165 seteuid(uid); 166 } 167 if (ret < 0) { 168 nodaemon(); 169 } else { 170 /* read current file name */ 171 cp = current; 172 ecp = cp + sizeof(current) - 1; 173 while ((i = getc(fp)) != EOF && i != '\n') { 174 if (cp < ecp) 175 *cp++ = i; 176 } 177 *cp = '\0'; 178 /* 179 * Print the status file. 180 */ 181 if (remote) 182 printf("%s: ", host); 183 seteuid(euid); 184 fd = open(ST, O_RDONLY); 185 seteuid(uid); 186 if (fd >= 0) { 187 (void)flock(fd, LOCK_SH); 188 while ((i = read(fd, line, sizeof(line))) > 0) 189 (void)fwrite(line, 1, (size_t)i, stdout); 190 (void)close(fd); /* unlocks as well */ 191 } else 192 putchar('\n'); 193 } 194 (void)fclose(fp); 195 } 196 /* 197 * Now, examine the control files and print out the jobs to 198 * be done for each user. 199 */ 200 if (!lflag) 201 header(); 202 for (i = 0; i < nitems; i++) { 203 q = queue[i]; 204 inform(q->q_name); 205 free(q); 206 } 207 free(queue); 208 } 209 if (!remote) { 210 if (nitems == 0) 211 puts("no entries"); 212 return; 213 } 214 215 /* 216 * Print foreign queue 217 * Note that a file in transit may show up in either queue. 218 */ 219 if (nitems) 220 putchar('\n'); 221 (void)snprintf(line, sizeof(line), "%c%s", format + '\3', RP); 222 cp = line; 223 ecp = line + sizeof(line); 224 for (i = 0; i < requests && cp - line + 11 < sizeof(line) - 2; i++) { 225 cp += strlen(cp); 226 (void)snprintf(cp, ecp - cp, " %d", requ[i]); 227 } 228 for (i = 0; i < users && cp - line + 1 + strlen(user[i]) < 229 sizeof(line) - 2; i++) { 230 cp += strlen(cp); 231 if (cp - line > sizeof(line) - 2) 232 break; 233 *cp++ = ' '; 234 /* truncation may happen */ 235 (void)strlcpy(cp, user[i], ecp - cp); 236 } 237 (void)strlcat(line, "\n", sizeof(line)); 238 if ((rmhost = strchr(RM, '@'))) 239 fd = getport(rmhost+1, atoi(RM)); 240 else 241 fd = getport(RM, 0); 242 if (fd < 0) { 243 if (from != host) 244 printf("%s: ", host); 245 (void)printf("connection to %s is down\n", RM); 246 } 247 else { 248 struct sigaction osa, nsa; 249 250 i = strlen(line); 251 if (write(fd, line, (size_t)i) != i) 252 fatal("Lost connection"); 253 nsa.sa_handler = alarmer; 254 sigemptyset(&nsa.sa_mask); 255 sigaddset(&nsa.sa_mask, SIGALRM); 256 nsa.sa_flags = 0; 257 (void)sigaction(SIGALRM, &nsa, &osa); 258 alarm(wait_time); 259 while ((i = read(fd, line, sizeof(line))) > 0) { 260 (void)fwrite(line, 1, (size_t)i, stdout); 261 alarm(wait_time); 262 } 263 alarm(0); 264 (void)sigaction(SIGALRM, &osa, NULL); 265 (void)close(fd); 266 } 267 } 268 269 static void 270 alarmer(int s) 271 { 272 /* nothing */ 273 } 274 275 /* 276 * Print a warning message if there is no daemon present. 277 */ 278 void 279 nodaemon(void) 280 { 281 if (remote) 282 printf("\n%s: ", host); 283 puts("Warning: no daemon present"); 284 current[0] = '\0'; 285 } 286 287 /* 288 * Print the header for the short listing format 289 */ 290 void 291 header(void) 292 { 293 printf(head0); 294 col = strlen(head0)+1; 295 blankfill(SIZCOL); 296 printf(head1); 297 } 298 299 void 300 inform(const char *cf) 301 { 302 int j; 303 FILE *cfp; 304 305 /* 306 * There's a chance the control file has gone away 307 * in the meantime; if this is the case just keep going 308 */ 309 seteuid(euid); 310 if ((cfp = fopen(cf, "r")) == NULL) 311 return; 312 seteuid(uid); 313 314 if (rank < 0) 315 rank = 0; 316 if (remote || garbage || strcmp(cf, current)) 317 rank++; 318 j = 0; 319 while (getline(cfp)) { 320 switch (line[0]) { 321 case 'P': /* Was this file specified in the user's list? */ 322 if (!inlist(line+1, cf)) { 323 fclose(cfp); 324 return; 325 } 326 if (lflag) { 327 printf("\n%s: ", line+1); 328 col = strlen(line+1) + 2; 329 prank(rank); 330 blankfill(JOBCOL); 331 printf(" [job %s]\n", cf+3); 332 } else { 333 col = 0; 334 prank(rank); 335 blankfill(OWNCOL); 336 printf("%-10s %-3d ", line+1, atoi(cf+3)); 337 col += 16; 338 first = 1; 339 } 340 continue; 341 default: /* some format specifer and file name? */ 342 if (line[0] < 'a' || line[0] > 'z') 343 continue; 344 if (j == 0 || strcmp(fname, line+1) != 0) { 345 (void)strlcpy(fname, line+1, sizeof(fname)); 346 } 347 j++; 348 continue; 349 case 'N': 350 show(line + 1, fname, j); 351 fname[0] = '\0'; 352 j = 0; 353 } 354 } 355 fclose(cfp); 356 if (!lflag) { 357 blankfill(SIZCOL); 358 printf("%ld bytes\n", totsize); 359 totsize = 0; 360 } 361 } 362 363 int 364 inlist(const char *name, const char *file) 365 { 366 int *r, n; 367 char **u; 368 const char *cp; 369 370 if (users == 0 && requests == 0) 371 return(1); 372 /* 373 * Check to see if it's in the user list 374 */ 375 for (u = user; u < &user[users]; u++) 376 if (!strcmp(*u, name)) 377 return(1); 378 /* 379 * Check the request list 380 */ 381 for (n = 0, cp = file+3; isdigit((unsigned char)*cp); ) 382 n = n * 10 + (*cp++ - '0'); 383 for (r = requ; r < &requ[requests]; r++) 384 if (*r == n && !strcmp(cp, from)) 385 return(1); 386 return(0); 387 } 388 389 void 390 show(const char *nfile, const char *file, int copies) 391 { 392 if (strcmp(nfile, " ") == 0) 393 nfile = "(standard input)"; 394 if (lflag) 395 ldump(nfile, file, copies); 396 else 397 dump(nfile, file, copies); 398 } 399 400 /* 401 * Fill the line with blanks to the specified column 402 */ 403 void 404 blankfill(int n) 405 { 406 while (col++ < n) 407 putchar(' '); 408 } 409 410 /* 411 * Give the abbreviated dump of the file names 412 */ 413 void 414 dump(const char *nfile, const char *file, int copies) 415 { 416 short n, fill; 417 struct stat lbuf; 418 419 /* 420 * Print as many files as will fit 421 * (leaving room for the total size) 422 */ 423 fill = first ? 0 : 2; /* fill space for ``, '' */ 424 if (((n = strlen(nfile)) + col + fill) >= SIZCOL-4) { 425 if (col < SIZCOL) { 426 printf(" ..."), col += 4; 427 blankfill(SIZCOL); 428 } 429 } else { 430 if (first) 431 first = 0; 432 else 433 printf(", "); 434 printf("%s", nfile); 435 col += n+fill; 436 } 437 seteuid(euid); 438 if (*file && !stat(file, &lbuf)) 439 totsize += copies * (long)lbuf.st_size; 440 seteuid(uid); 441 } 442 443 /* 444 * Print the long info about the file 445 */ 446 void 447 ldump(const char *nfile, const char *file, int copies) 448 { 449 struct stat lbuf; 450 451 putchar('\t'); 452 if (copies > 1) 453 printf("%-2d copies of %-19s", copies, nfile); 454 else 455 printf("%-32s", nfile); 456 if (*file && !stat(file, &lbuf)) 457 printf(" %lld bytes", (long long)lbuf.st_size); 458 else 459 printf(" ??? bytes"); 460 putchar('\n'); 461 } 462 463 /* 464 * Print the job's rank in the queue, 465 * update col for screen management 466 */ 467 void 468 prank(int n) 469 { 470 char rline[100]; 471 static const char *r[] = { 472 "th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th" 473 }; 474 475 if (n == 0) { 476 printf("active"); 477 col += 6; 478 return; 479 } 480 if ((n/10)%10 == 1) 481 (void)snprintf(rline, sizeof(rline), "%dth", n); 482 else 483 (void)snprintf(rline, sizeof(rline), "%d%s", n, r[n%10]); 484 col += strlen(rline); 485 printf("%s", rline); 486 } 487