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