displayq.c revision 68401
1/* 2 * Copyright (c) 1983, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34#ifndef lint 35/* 36static char sccsid[] = "@(#)displayq.c 8.4 (Berkeley) 4/28/95"; 37*/ 38static const char rcsid[] = 39 "$FreeBSD: head/usr.sbin/lpr/common_source/displayq.c 68401 2000-11-06 19:36:38Z gad $"; 40#endif /* not lint */ 41 42#include <sys/param.h> 43#include <sys/stat.h> 44 45#include <ctype.h> 46#include <dirent.h> 47#include <errno.h> 48#include <fcntl.h> 49#include <signal.h> 50#include <stdio.h> 51#include <stdlib.h> 52#include <string.h> 53#define psignal foil_gcc_psignal 54#define sys_siglist foil_gcc_siglist 55#include <unistd.h> 56#undef psignal 57#undef sys_siglist 58 59#include "lp.h" 60#include "lp.local.h" 61#include "pathnames.h" 62 63/* 64 * Routines to display the state of the queue. 65 */ 66#define JOBCOL 40 /* column for job # in -l format */ 67#define OWNCOL 7 /* start of Owner column in normal */ 68#define SIZCOL 62 /* start of Size column in normal */ 69 70/* 71 * Stuff for handling job specifications 72 */ 73extern uid_t uid, euid; 74 75static int col; /* column on screen */ 76static char current[40]; /* current file being printed */ 77static char file[132]; /* print file name */ 78static int first; /* first file in ``files'' column? */ 79static int garbage; /* # of garbage cf files */ 80static int lflag; /* long output option */ 81static int rank; /* order to be printed (-1=none, 0=active) */ 82static long totsize; /* total print job size in bytes */ 83 84static char *head0 = "Rank Owner Job Files"; 85static char *head1 = "Total Size\n"; 86 87static void alarmhandler __P((int)); 88static void warn __P((const struct printer *pp)); 89 90/* 91 * Display the current state of the queue. Format = 1 if long format. 92 */ 93void 94displayq(pp, format) 95 struct printer *pp; 96 int format; 97{ 98 register struct jobqueue *q; 99 register int i, nitems, fd, ret; 100 register char *cp; 101 struct jobqueue **queue; 102 struct stat statb; 103 FILE *fp; 104 void (*savealrm)(int); 105 106 lflag = format; 107 totsize = 0; 108 rank = -1; 109 110 if ((cp = checkremote(pp))) { 111 printf("Warning: %s\n", cp); 112 free(cp); 113 } 114 115 /* 116 * Print out local queue 117 * Find all the control files in the spooling directory 118 */ 119 seteuid(euid); 120 if (chdir(pp->spool_dir) < 0) 121 fatal(pp, "cannot chdir to spooling directory: %s", 122 strerror(errno)); 123 seteuid(uid); 124 if ((nitems = getq(pp, &queue)) < 0) 125 fatal(pp, "cannot examine spooling area\n"); 126 seteuid(euid); 127 ret = stat(pp->lock_file, &statb); 128 seteuid(uid); 129 if (ret >= 0) { 130 if (statb.st_mode & LFM_PRINT_DIS) { 131 if (pp->remote) 132 printf("%s: ", host); 133 printf("Warning: %s is down: ", pp->printer); 134 seteuid(euid); 135 fd = open(pp->status_file, O_RDONLY|O_SHLOCK); 136 seteuid(uid); 137 if (fd >= 0) { 138 while ((i = read(fd, line, sizeof(line))) > 0) 139 (void) fwrite(line, 1, i, stdout); 140 (void) close(fd); /* unlocks as well */ 141 } else 142 putchar('\n'); 143 } 144 if (statb.st_mode & LFM_QUEUE_DIS) { 145 if (pp->remote) 146 printf("%s: ", host); 147 printf("Warning: %s queue is turned off\n", 148 pp->printer); 149 } 150 } 151 152 if (nitems) { 153 seteuid(euid); 154 fp = fopen(pp->lock_file, "r"); 155 seteuid(uid); 156 if (fp == NULL) 157 warn(pp); 158 else { 159 /* get daemon pid */ 160 cp = current; 161 while ((i = getc(fp)) != EOF && i != '\n') 162 *cp++ = i; 163 *cp = '\0'; 164 i = atoi(current); 165 if (i <= 0) { 166 ret = -1; 167 } else { 168 seteuid(euid); 169 ret = kill(i, 0); 170 seteuid(uid); 171 } 172 if (ret < 0) { 173 warn(pp); 174 } else { 175 /* read current file name */ 176 cp = current; 177 while ((i = getc(fp)) != EOF && i != '\n') 178 *cp++ = i; 179 *cp = '\0'; 180 /* 181 * Print the status file. 182 */ 183 if (pp->remote) 184 printf("%s: ", host); 185 seteuid(euid); 186 fd = open(pp->status_file, O_RDONLY|O_SHLOCK); 187 seteuid(uid); 188 if (fd >= 0) { 189 while ((i = read(fd, line, 190 sizeof(line))) > 0) 191 fwrite(line, 1, i, stdout); 192 close(fd); /* unlocks as well */ 193 } else 194 putchar('\n'); 195 } 196 (void) fclose(fp); 197 } 198 /* 199 * Now, examine the control files and print out the jobs to 200 * be done for each user. 201 */ 202 if (!lflag) 203 header(); 204 for (i = 0; i < nitems; i++) { 205 q = queue[i]; 206 inform(pp, q->job_cfname); 207 free(q); 208 } 209 free(queue); 210 } 211 if (!pp->remote) { 212 if (nitems == 0) 213 puts("no entries"); 214 return; 215 } 216 217 /* 218 * Print foreign queue 219 * Note that a file in transit may show up in either queue. 220 */ 221 if (nitems) 222 putchar('\n'); 223 (void) snprintf(line, sizeof(line), "%c%s", format ? '\4' : '\3', 224 pp->remote_queue); 225 cp = line; 226 for (i = 0; i < requests && cp-line+10 < sizeof(line) - 1; i++) { 227 cp += strlen(cp); 228 (void) sprintf(cp, " %d", requ[i]); 229 } 230 for (i = 0; i < users && cp - line + 1 + strlen(user[i]) < 231 sizeof(line) - 1; i++) { 232 cp += strlen(cp); 233 *cp++ = ' '; 234 (void) strcpy(cp, user[i]); 235 } 236 strcat(line, "\n"); 237 savealrm = signal(SIGALRM, alarmhandler); 238 alarm(pp->conn_timeout); 239 fd = getport(pp, pp->remote_host, 0); 240 alarm(0); 241 (void)signal(SIGALRM, savealrm); 242 if (fd < 0) { 243 if (from != host) 244 printf("%s: ", host); 245 printf("connection to %s is down\n", pp->remote_host); 246 } 247 else { 248 i = strlen(line); 249 if (write(fd, line, i) != i) 250 fatal(pp, "Lost connection"); 251 while ((i = read(fd, line, sizeof(line))) > 0) 252 (void) fwrite(line, 1, i, stdout); 253 (void) close(fd); 254 } 255} 256 257/* 258 * Print a warning message if there is no daemon present. 259 */ 260static void 261warn(pp) 262 const struct printer *pp; 263{ 264 if (pp->remote) 265 printf("%s: ", host); 266 puts("Warning: no daemon present"); 267 current[0] = '\0'; 268} 269 270/* 271 * Print the header for the short listing format 272 */ 273void 274header() 275{ 276 printf(head0); 277 col = strlen(head0)+1; 278 blankfill(SIZCOL); 279 printf(head1); 280} 281 282void 283inform(pp, cf) 284 const struct printer *pp; 285 char *cf; 286{ 287 register int copycnt; 288 char savedname[MAXPATHLEN+1]; 289 FILE *cfp; 290 291 /* 292 * There's a chance the control file has gone away 293 * in the meantime; if this is the case just keep going 294 */ 295 seteuid(euid); 296 if ((cfp = fopen(cf, "r")) == NULL) 297 return; 298 seteuid(uid); 299 300 if (rank < 0) 301 rank = 0; 302 if (pp->remote || garbage || strcmp(cf, current)) 303 rank++; 304 305 /* 306 * The cf-file may include commands to print more than one datafile 307 * from the user. For each datafile, the cf-file contains at least 308 * one line which starts with some format-specifier ('a'-'z'), and 309 * a second line ('N'ame) which indicates the original name the user 310 * specified for that file. There can be multiple format-spec lines 311 * for a single Name-line, if the user requested multiple copies of 312 * that file. Standard lpr puts the format-spec line(s) before the 313 * Name-line, while lprNG puts the Name-line before the format-spec 314 * line(s). This section needs to handle the lines in either order. 315 */ 316 copycnt = 0; 317 file[0] = '\0'; 318 savedname[0] = '\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 break; 344 if (copycnt == 0 || strcmp(file, line+1) != 0) { 345 strncpy(file, line + 1, sizeof(file) - 1); 346 file[sizeof(file) - 1] = '\0'; 347 } 348 copycnt++; 349 /* 350 * deliberately 'continue' to another getline(), so 351 * all format-spec lines for this datafile are read 352 * in and counted before calling show() 353 */ 354 continue; 355 case 'N': 356 strncpy(savedname, line + 1, sizeof(savedname) - 1); 357 savedname[sizeof(savedname) - 1] = '\0'; 358 break; 359 } 360 if ((file[0] != '\0') && (savedname[0] != '\0')) { 361 show(savedname, file, copycnt); 362 copycnt = 0; 363 file[0] = '\0'; 364 savedname[0] = '\0'; 365 } 366 } 367 fclose(cfp); 368 /* check for a file which hasn't been shown yet */ 369 if (file[0] != '\0') { 370 if (savedname[0] == '\0') { 371 /* a safeguard in case the N-ame line is missing */ 372 strncpy(savedname, file, sizeof(savedname) - 1); 373 savedname[sizeof(savedname) - 1] = '\0'; 374 } 375 show(savedname, file, copycnt); 376 } 377 if (!lflag) { 378 blankfill(SIZCOL); 379 printf("%ld bytes\n", totsize); 380 totsize = 0; 381 } 382} 383 384int 385inlist(name, file) 386 char *name, *file; 387{ 388 register int *r, n; 389 register char **u, *cp; 390 391 if (users == 0 && requests == 0) 392 return(1); 393 /* 394 * Check to see if it's in the user list 395 */ 396 for (u = user; u < &user[users]; u++) 397 if (!strcmp(*u, name)) 398 return(1); 399 /* 400 * Check the request list 401 */ 402 for (n = 0, cp = file+3; isdigit(*cp); ) 403 n = n * 10 + (*cp++ - '0'); 404 for (r = requ; r < &requ[requests]; r++) 405 if (*r == n && !strcmp(cp, from)) 406 return(1); 407 return(0); 408} 409 410void 411show(nfile, file, copies) 412 register char *nfile, *file; 413 int copies; 414{ 415 if (strcmp(nfile, " ") == 0) 416 nfile = "(standard input)"; 417 if (lflag) 418 ldump(nfile, file, copies); 419 else 420 dump(nfile, file, copies); 421} 422 423/* 424 * Fill the line with blanks to the specified column 425 */ 426void 427blankfill(n) 428 register int n; 429{ 430 while (col++ < n) 431 putchar(' '); 432} 433 434/* 435 * Give the abbreviated dump of the file names 436 */ 437void 438dump(nfile, file, copies) 439 char *nfile, *file; 440 int copies; 441{ 442 struct stat lbuf; 443 const char etctmpl[] = ", ..."; 444 char etc[sizeof(etctmpl)]; 445 char *lastsep; 446 short fill, nlen; 447 short rem, remetc; 448 449 /* 450 * Print as many filenames as will fit 451 * (leaving room for the 'total size' field) 452 */ 453 fill = first ? 0 : 2; /* fill space for ``, '' */ 454 nlen = strlen(nfile); 455 rem = SIZCOL - 1 - col; 456 if (nlen + fill > rem) { 457 if (first) { 458 /* print the right-most part of the name */ 459 printf("...%s ", &nfile[3+nlen-rem]); 460 col = SIZCOL; 461 } else if (rem > 0) { 462 /* fit as much of the etc-string as we can */ 463 remetc = rem; 464 if (rem > strlen(etctmpl)) 465 remetc = strlen(etctmpl); 466 etc[0] = '\0'; 467 strncat(etc, etctmpl, remetc); 468 printf(etc); 469 col += remetc; 470 rem -= remetc; 471 /* room for the last segment of this filename? */ 472 lastsep = strrchr(nfile, '/'); 473 if ((lastsep != NULL) && (rem > strlen(lastsep))) { 474 /* print the right-most part of this name */ 475 printf("%s", lastsep); 476 col += strlen(lastsep); 477 } else { 478 /* do not pack any more names in here */ 479 blankfill(SIZCOL); 480 } 481 } 482 } else { 483 if (!first) 484 printf(", "); 485 printf("%s", nfile); 486 col += nlen + fill; 487 } 488 first = 0; 489 490 seteuid(euid); 491 if (*file && !stat(file, &lbuf)) 492 totsize += copies * lbuf.st_size; 493 seteuid(uid); 494} 495 496/* 497 * Print the long info about the file 498 */ 499void 500ldump(nfile, file, copies) 501 char *nfile, *file; 502 int copies; 503{ 504 struct stat lbuf; 505 506 putchar('\t'); 507 if (copies > 1) 508 printf("%-2d copies of %-19s", copies, nfile); 509 else 510 printf("%-32s", nfile); 511 if (*file && !stat(file, &lbuf)) 512 printf(" %qd bytes", (long long) lbuf.st_size); 513 else 514 printf(" ??? bytes"); 515 putchar('\n'); 516} 517 518/* 519 * Print the job's rank in the queue, 520 * update col for screen management 521 */ 522void 523prank(n) 524 int n; 525{ 526 char rline[100]; 527 static char *r[] = { 528 "th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th" 529 }; 530 531 if (n == 0) { 532 printf("active"); 533 col += 6; 534 return; 535 } 536 if ((n/10)%10 == 1) 537 (void)snprintf(rline, sizeof(rline), "%dth", n); 538 else 539 (void)snprintf(rline, sizeof(rline), "%d%s", n, r[n%10]); 540 col += strlen(rline); 541 printf("%s", rline); 542} 543 544void 545alarmhandler(signo) 546 int signo; 547{ 548 /* ignored */ 549} 550