displayq.c revision 35998
1207753Smm/* 2207753Smm * Copyright (c) 1983, 1993 3207753Smm * The Regents of the University of California. All rights reserved. 4207753Smm * 5207753Smm * Redistribution and use in source and binary forms, with or without 6207753Smm * modification, are permitted provided that the following conditions 7207753Smm * are met: 8207753Smm * 1. Redistributions of source code must retain the above copyright 9207753Smm * notice, this list of conditions and the following disclaimer. 10207753Smm * 2. Redistributions in binary form must reproduce the above copyright 11207753Smm * notice, this list of conditions and the following disclaimer in the 12207753Smm * documentation and/or other materials provided with the distribution. 13207753Smm * 3. All advertising materials mentioning features or use of this software 14207753Smm * must display the following acknowledgement: 15207753Smm * This product includes software developed by the University of 16207753Smm * California, Berkeley and its contributors. 17207753Smm * 4. Neither the name of the University nor the names of its contributors 18207753Smm * may be used to endorse or promote products derived from this software 19207753Smm * without specific prior written permission. 20207753Smm * 21207753Smm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22207753Smm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23207753Smm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24207753Smm * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25207753Smm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26207753Smm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27207753Smm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28207753Smm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29207753Smm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30207753Smm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31207753Smm * SUCH DAMAGE. 32215187Smm */ 33207753Smm 34207753Smm#ifndef lint 35207753Smm/* 36207753Smmstatic char sccsid[] = "@(#)displayq.c 8.4 (Berkeley) 4/28/95"; 37207753Smm*/ 38207753Smmstatic const char rcsid[] = 39207753Smm "$Id: displayq.c,v 1.13 1997/12/02 20:45:19 wollman Exp $"; 40207753Smm#endif /* not lint */ 41207753Smm 42215187Smm#include <sys/param.h> 43207753Smm#include <sys/stat.h> 44207753Smm 45207753Smm#include <ctype.h> 46207753Smm#include <dirent.h> 47207753Smm#include <errno.h> 48207753Smm#include <fcntl.h> 49207753Smm#include <signal.h> 50207753Smm#include <stdio.h> 51207753Smm#include <stdlib.h> 52207753Smm#include <string.h> 53207753Smm#define psignal foil_gcc_psignal 54207753Smm#define sys_siglist foil_gcc_siglist 55215187Smm#include <unistd.h> 56215187Smm#undef psignal 57215187Smm#undef sys_siglist 58207753Smm 59215187Smm#include "lp.h" 60215187Smm#include "lp.local.h" 61215187Smm#include "pathnames.h" 62207753Smm 63207753Smm/* 64207753Smm * Routines to display the state of the queue. 65207753Smm */ 66207753Smm#define JOBCOL 40 /* column for job # in -l format */ 67215187Smm#define OWNCOL 7 /* start of Owner column in normal */ 68207753Smm#define SIZCOL 62 /* start of Size column in normal */ 69207753Smm 70207753Smm/* 71207753Smm * Stuff for handling job specifications 72207753Smm */ 73207753Smmextern uid_t uid, euid; 74207753Smm 75207753Smmstatic int col; /* column on screen */ 76207753Smmstatic char current[40]; /* current file being printed */ 77207753Smmstatic char file[132]; /* print file name */ 78207753Smmstatic int first; /* first file in ``files'' column? */ 79207753Smmstatic int garbage; /* # of garbage cf files */ 80207753Smmstatic int lflag; /* long output option */ 81207753Smmstatic int rank; /* order to be printed (-1=none, 0=active) */ 82207753Smmstatic long totsize; /* total print job size in bytes */ 83207753Smm 84207753Smmstatic char *head0 = "Rank Owner Job Files"; 85207753Smmstatic char *head1 = "Total Size\n"; 86207753Smm 87207753Smmstatic void alarmhandler __P((int)); 88207753Smmstatic void warn __P((const struct printer *pp)); 89207753Smm 90215187Smm/* 91215187Smm * Display the current state of the queue. Format = 1 if long format. 92215187Smm */ 93207753Smmvoid 94207753Smmdisplayq(pp, format) 95207753Smm struct printer *pp; 96207753Smm int format; 97207753Smm{ 98207753Smm register struct queue *q; 99207753Smm register int i, nitems, fd, ret; 100207753Smm register char *cp; 101207753Smm struct queue **queue; 102207753Smm struct stat statb; 103207753Smm FILE *fp; 104207753Smm void (*savealrm)(int); 105207753Smm 106207753Smm lflag = format; 107207753Smm totsize = 0; 108207753Smm rank = -1; 109207753Smm 110207753Smm if ((cp = checkremote(pp))) { 111207753Smm printf("Warning: %s\n", cp); 112207753Smm free(cp); 113207753Smm } 114207753Smm 115213700Smm /* 116213700Smm * Print out local queue 117207753Smm * Find all the control files in the spooling directory 118207753Smm */ 119207753Smm seteuid(euid); 120207753Smm if (chdir(pp->spool_dir) < 0) 121207753Smm fatal(pp, "cannot chdir to spooling directory: %s", 122207753Smm strerror(errno)); 123207753Smm seteuid(uid); 124207753Smm if ((nitems = getq(pp, &queue)) < 0) 125207753Smm fatal(pp, "cannot examine spooling area\n"); 126207753Smm seteuid(euid); 127207753Smm ret = stat(pp->lock_file, &statb); 128215187Smm seteuid(uid); 129215187Smm if (ret >= 0) { 130215187Smm if (statb.st_mode & LFM_PRINT_DIS) { 131207753Smm if (pp->remote) 132207753Smm printf("%s: ", host); 133207753Smm printf("Warning: %s is down: ", pp->printer); 134207753Smm seteuid(euid); 135207753Smm fd = open(pp->status_file, O_RDONLY|O_SHLOCK); 136207753Smm seteuid(uid); 137207753Smm if (fd >= 0) { 138207753Smm while ((i = read(fd, line, sizeof(line))) > 0) 139207753Smm (void) fwrite(line, 1, i, stdout); 140207753Smm (void) close(fd); /* unlocks as well */ 141207753Smm } else 142207753Smm putchar('\n'); 143207753Smm } 144207753Smm if (statb.st_mode & LFM_QUEUE_DIS) { 145207753Smm if (pp->remote) 146207753Smm printf("%s: ", host); 147207753Smm printf("Warning: %s queue is turned off\n", 148207753Smm pp->printer); 149207753Smm } 150207753Smm } 151207753Smm 152207753Smm if (nitems) { 153207753Smm seteuid(euid); 154213700Smm fp = fopen(pp->lock_file, "r"); 155213700Smm seteuid(uid); 156213700Smm if (fp == NULL) 157207753Smm warn(pp); 158207753Smm else { 159207753Smm /* get daemon pid */ 160207753Smm cp = current; 161207753Smm while ((i = getc(fp)) != EOF && i != '\n') 162207753Smm *cp++ = i; 163207753Smm *cp = '\0'; 164207753Smm i = atoi(current); 165207753Smm if (i <= 0) { 166207753Smm 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->q_name); 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 j; 288 FILE *cfp; 289 290 /* 291 * There's a chance the control file has gone away 292 * in the meantime; if this is the case just keep going 293 */ 294 seteuid(euid); 295 if ((cfp = fopen(cf, "r")) == NULL) 296 return; 297 seteuid(uid); 298 299 if (rank < 0) 300 rank = 0; 301 if (pp->remote || garbage || strcmp(cf, current)) 302 rank++; 303 j = 0; 304 while (getline(cfp)) { 305 switch (line[0]) { 306 case 'P': /* Was this file specified in the user's list? */ 307 if (!inlist(line+1, cf)) { 308 fclose(cfp); 309 return; 310 } 311 if (lflag) { 312 printf("\n%s: ", line+1); 313 col = strlen(line+1) + 2; 314 prank(rank); 315 blankfill(JOBCOL); 316 printf(" [job %s]\n", cf+3); 317 } else { 318 col = 0; 319 prank(rank); 320 blankfill(OWNCOL); 321 printf("%-10s %-3d ", line+1, atoi(cf+3)); 322 col += 16; 323 first = 1; 324 } 325 continue; 326 default: /* some format specifer and file name? */ 327 if (line[0] < 'a' || line[0] > 'z') 328 continue; 329 if (j == 0 || strcmp(file, line+1) != 0) { 330 (void) strncpy(file, line+1, sizeof(file) - 1); 331 file[sizeof(file) - 1] = '\0'; 332 } 333 j++; 334 continue; 335 case 'N': 336 show(line+1, file, j); 337 file[0] = '\0'; 338 j = 0; 339 } 340 } 341 fclose(cfp); 342 if (!lflag) { 343 blankfill(SIZCOL); 344 printf("%ld bytes\n", totsize); 345 totsize = 0; 346 } 347} 348 349int 350inlist(name, file) 351 char *name, *file; 352{ 353 register int *r, n; 354 register char **u, *cp; 355 356 if (users == 0 && requests == 0) 357 return(1); 358 /* 359 * Check to see if it's in the user list 360 */ 361 for (u = user; u < &user[users]; u++) 362 if (!strcmp(*u, name)) 363 return(1); 364 /* 365 * Check the request list 366 */ 367 for (n = 0, cp = file+3; isdigit(*cp); ) 368 n = n * 10 + (*cp++ - '0'); 369 for (r = requ; r < &requ[requests]; r++) 370 if (*r == n && !strcmp(cp, from)) 371 return(1); 372 return(0); 373} 374 375void 376show(nfile, file, copies) 377 register char *nfile, *file; 378 int copies; 379{ 380 if (strcmp(nfile, " ") == 0) 381 nfile = "(standard input)"; 382 if (lflag) 383 ldump(nfile, file, copies); 384 else 385 dump(nfile, file, copies); 386} 387 388/* 389 * Fill the line with blanks to the specified column 390 */ 391void 392blankfill(n) 393 register int n; 394{ 395 while (col++ < n) 396 putchar(' '); 397} 398 399/* 400 * Give the abbreviated dump of the file names 401 */ 402void 403dump(nfile, file, copies) 404 char *nfile, *file; 405 int copies; 406{ 407 register short n, fill; 408 struct stat lbuf; 409 410 /* 411 * Print as many files as will fit 412 * (leaving room for the total size) 413 */ 414 fill = first ? 0 : 2; /* fill space for ``, '' */ 415 if (((n = strlen(nfile)) + col + fill) >= SIZCOL-4) { 416 if (col < SIZCOL) { 417 printf(" ..."), col += 4; 418 blankfill(SIZCOL); 419 } 420 } else { 421 if (first) 422 first = 0; 423 else 424 printf(", "); 425 printf("%s", nfile); 426 col += n+fill; 427 } 428 seteuid(euid); 429 if (*file && !stat(file, &lbuf)) 430 totsize += copies * lbuf.st_size; 431 seteuid(uid); 432} 433 434/* 435 * Print the long info about the file 436 */ 437void 438ldump(nfile, file, copies) 439 char *nfile, *file; 440 int copies; 441{ 442 struct stat lbuf; 443 444 putchar('\t'); 445 if (copies > 1) 446 printf("%-2d copies of %-19s", copies, nfile); 447 else 448 printf("%-32s", nfile); 449 if (*file && !stat(file, &lbuf)) 450 printf(" %qd bytes", (long long) lbuf.st_size); 451 else 452 printf(" ??? bytes"); 453 putchar('\n'); 454} 455 456/* 457 * Print the job's rank in the queue, 458 * update col for screen management 459 */ 460void 461prank(n) 462 int n; 463{ 464 char rline[100]; 465 static char *r[] = { 466 "th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th" 467 }; 468 469 if (n == 0) { 470 printf("active"); 471 col += 6; 472 return; 473 } 474 if ((n/10)%10 == 1) 475 (void)snprintf(rline, sizeof(rline), "%dth", n); 476 else 477 (void)snprintf(rline, sizeof(rline), "%d%s", n, r[n%10]); 478 col += strlen(rline); 479 printf("%s", rline); 480} 481 482void 483alarmhandler(signo) 484 int signo; 485{ 486 /* ignored */ 487} 488