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