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