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