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