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