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