displayq.c revision 1.11 1 /* $NetBSD: displayq.c,v 1.11 1997/10/05 11:52:19 mrg 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[] = "$NetBSD: displayq.c,v 1.11 1997/10/05 11:52:19 mrg 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, c;
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()) != NULL)
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 ((c = getc(fp)) != EOF && (*cp = c) != '\n')
172 cp++;
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 ((c = getc(fp)) != EOF &&
188 (*cp = c) != '\n')
189 cp++;
190 *cp = '\0';
191 /*
192 * Print the status file.
193 */
194 if (remote)
195 printf("%s: ", host);
196 seteuid(euid);
197 fd = open(ST, O_RDONLY);
198 seteuid(uid);
199 if (fd >= 0) {
200 (void)flock(fd, LOCK_SH);
201 while ((i = read(fd, line, sizeof(line))) > 0)
202 (void)fwrite(line, 1, i, stdout);
203 (void)close(fd); /* unlocks as well */
204 } else
205 putchar('\n');
206 }
207 (void)fclose(fp);
208 }
209 /*
210 * Now, examine the control files and print out the jobs to
211 * be done for each user.
212 */
213 if (!lflag)
214 header();
215 for (i = 0; i < nitems; i++) {
216 q = queue[i];
217 inform(q->q_name);
218 free(q);
219 }
220 free(queue);
221 }
222 if (!remote) {
223 if (nitems == 0)
224 puts("no entries");
225 return;
226 }
227
228 /*
229 * Print foreign queue
230 * Note that a file in transit may show up in either queue.
231 */
232 if (nitems)
233 putchar('\n');
234 (void)snprintf(line, sizeof(line), "%c%s", format + '\3', RP);
235 cp = line;
236 for (i = 0; i < requests; i++) {
237 cp += strlen(cp);
238 (void)snprintf(cp, line - cp, " %d", requ[i]);
239 }
240 for (i = 0; i < users; i++) {
241 cp += strlen(cp);
242 if (cp - line > sizeof(line) - 1)
243 break;
244 *cp++ = ' ';
245 (void)strncpy(cp, user[i], line - cp - 1);
246 }
247 (void)strncat(line, "\n", sizeof(line) - strlen(line) - 1);
248 fd = getport(RM, 0);
249 if (fd < 0) {
250 if (from != host)
251 printf("%s: ", host);
252 (void)printf("connection to %s is down\n", RM);
253 }
254 else {
255 i = strlen(line);
256 if (write(fd, line, i) != i)
257 fatal("Lost connection");
258 while ((i = read(fd, line, sizeof(line))) > 0)
259 (void)fwrite(line, 1, i, stdout);
260 (void)close(fd);
261 }
262 }
263
264 /*
265 * Print a warning message if there is no daemon present.
266 */
267 void
268 warn()
269 {
270 if (remote)
271 printf("\n%s: ", host);
272 puts("Warning: no daemon present");
273 current[0] = '\0';
274 }
275
276 /*
277 * Print the header for the short listing format
278 */
279 void
280 header()
281 {
282 printf(head0);
283 col = strlen(head0)+1;
284 blankfill(SIZCOL);
285 printf(head1);
286 }
287
288 void
289 inform(cf)
290 char *cf;
291 {
292 register int j;
293 FILE *cfp;
294
295 /*
296 * There's a chance the control file has gone away
297 * in the meantime; if this is the case just keep going
298 */
299 seteuid(euid);
300 if ((cfp = fopen(cf, "r")) == NULL)
301 return;
302 seteuid(uid);
303
304 if (rank < 0)
305 rank = 0;
306 if (remote || garbage || strcmp(cf, current))
307 rank++;
308 j = 0;
309 while (getline(cfp)) {
310 switch (line[0]) {
311 case 'P': /* Was this file specified in the user's list? */
312 if (!inlist(line+1, cf)) {
313 fclose(cfp);
314 return;
315 }
316 if (lflag) {
317 printf("\n%s: ", line+1);
318 col = strlen(line+1) + 2;
319 prank(rank);
320 blankfill(JOBCOL);
321 printf(" [job %s]\n", cf+3);
322 } else {
323 col = 0;
324 prank(rank);
325 blankfill(OWNCOL);
326 printf("%-10s %-3d ", line+1, atoi(cf+3));
327 col += 16;
328 first = 1;
329 }
330 continue;
331 default: /* some format specifer and file name? */
332 if (line[0] < 'a' || line[0] > 'z')
333 continue;
334 if (j == 0 || strcmp(file, line+1) != 0)
335 (void)strncpy(file, line+1, sizeof(file) - 1);
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(" %ld bytes", (long)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