displayq.c revision 1.9 1 /* $NetBSD: displayq.c,v 1.9 1997/04/19 06:33:13 thorpej 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, c;
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 ((c = getc(fp)) != EOF && (*cp = c) != '\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 ((c = getc(fp)) != EOF &&
183 (*cp = c) != '\n')
184 cp++;
185 *cp = '\0';
186 /*
187 * Print the status file.
188 */
189 if (sendtorem)
190 printf("%s: ", host);
191 seteuid(euid);
192 fd = open(ST, O_RDONLY);
193 seteuid(uid);
194 if (fd >= 0) {
195 (void)flock(fd, LOCK_SH);
196 while ((i = read(fd, line, sizeof(line))) > 0)
197 (void)fwrite(line, 1, i, stdout);
198 (void)close(fd); /* unlocks as well */
199 } else
200 putchar('\n');
201 }
202 (void)fclose(fp);
203 }
204 /*
205 * Now, examine the control files and print out the jobs to
206 * be done for each user.
207 */
208 if (!lflag)
209 header();
210 for (i = 0; i < nitems; i++) {
211 q = queue[i];
212 inform(q->q_name);
213 free(q);
214 }
215 free(queue);
216 }
217 if (!sendtorem) {
218 if (nitems == 0)
219 puts("no entries");
220 return;
221 }
222
223 /*
224 * Print foreign queue
225 * Note that a file in transit may show up in either queue.
226 */
227 if (nitems)
228 putchar('\n');
229 (void)snprintf(line, sizeof(line), "%c%s", format + '\3', RP);
230 cp = line;
231 for (i = 0; i < requests; i++) {
232 cp += strlen(cp);
233 (void)snprintf(cp, line - cp, " %d", requ[i]);
234 }
235 for (i = 0; i < users; i++) {
236 cp += strlen(cp);
237 if (cp - line > sizeof(line) - 1)
238 break;
239 *cp++ = ' ';
240 (void)strncpy(cp, user[i], line - cp - 1);
241 }
242 (void)strncat(line, "\n", sizeof(line) - strlen(line) - 1);
243 fd = getport(RM);
244 if (fd < 0) {
245 if (from != host)
246 printf("%s: ", host);
247 (void)printf("connection to %s is down\n", RM);
248 }
249 else {
250 i = strlen(line);
251 if (write(fd, line, i) != i)
252 fatal("Lost connection");
253 while ((i = read(fd, line, sizeof(line))) > 0)
254 (void)fwrite(line, 1, i, stdout);
255 (void)close(fd);
256 }
257 }
258
259 /*
260 * Print a warning message if there is no daemon present.
261 */
262 void
263 warn()
264 {
265 if (sendtorem)
266 printf("\n%s: ", host);
267 puts("Warning: no daemon present");
268 current[0] = '\0';
269 }
270
271 /*
272 * Print the header for the short listing format
273 */
274 void
275 header()
276 {
277 printf(head0);
278 col = strlen(head0)+1;
279 blankfill(SIZCOL);
280 printf(head1);
281 }
282
283 void
284 inform(cf)
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 (sendtorem || 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 j++;
332 continue;
333 case 'N':
334 show(line+1, file, j);
335 file[0] = '\0';
336 j = 0;
337 }
338 }
339 fclose(cfp);
340 if (!lflag) {
341 blankfill(SIZCOL);
342 printf("%ld bytes\n", totsize);
343 totsize = 0;
344 }
345 }
346
347 int
348 inlist(name, file)
349 char *name, *file;
350 {
351 register int *r, n;
352 register char **u, *cp;
353
354 if (users == 0 && requests == 0)
355 return(1);
356 /*
357 * Check to see if it's in the user list
358 */
359 for (u = user; u < &user[users]; u++)
360 if (!strcmp(*u, name))
361 return(1);
362 /*
363 * Check the request list
364 */
365 for (n = 0, cp = file+3; isdigit(*cp); )
366 n = n * 10 + (*cp++ - '0');
367 for (r = requ; r < &requ[requests]; r++)
368 if (*r == n && !strcmp(cp, from))
369 return(1);
370 return(0);
371 }
372
373 void
374 show(nfile, file, copies)
375 register char *nfile, *file;
376 int copies;
377 {
378 if (strcmp(nfile, " ") == 0)
379 nfile = "(standard input)";
380 if (lflag)
381 ldump(nfile, file, copies);
382 else
383 dump(nfile, file, copies);
384 }
385
386 /*
387 * Fill the line with blanks to the specified column
388 */
389 void
390 blankfill(n)
391 register int n;
392 {
393 while (col++ < n)
394 putchar(' ');
395 }
396
397 /*
398 * Give the abbreviated dump of the file names
399 */
400 void
401 dump(nfile, file, copies)
402 char *nfile, *file;
403 int copies;
404 {
405 register short n, fill;
406 struct stat lbuf;
407
408 /*
409 * Print as many files as will fit
410 * (leaving room for the total size)
411 */
412 fill = first ? 0 : 2; /* fill space for ``, '' */
413 if (((n = strlen(nfile)) + col + fill) >= SIZCOL-4) {
414 if (col < SIZCOL) {
415 printf(" ..."), col += 4;
416 blankfill(SIZCOL);
417 }
418 } else {
419 if (first)
420 first = 0;
421 else
422 printf(", ");
423 printf("%s", nfile);
424 col += n+fill;
425 }
426 seteuid(euid);
427 if (*file && !stat(file, &lbuf))
428 totsize += copies * lbuf.st_size;
429 seteuid(uid);
430 }
431
432 /*
433 * Print the long info about the file
434 */
435 void
436 ldump(nfile, file, copies)
437 char *nfile, *file;
438 int copies;
439 {
440 struct stat lbuf;
441
442 putchar('\t');
443 if (copies > 1)
444 printf("%-2d copies of %-19s", copies, nfile);
445 else
446 printf("%-32s", nfile);
447 if (*file && !stat(file, &lbuf))
448 printf(" %qd bytes", lbuf.st_size);
449 else
450 printf(" ??? bytes");
451 putchar('\n');
452 }
453
454 /*
455 * Print the job's rank in the queue,
456 * update col for screen management
457 */
458 void
459 prank(n)
460 int n;
461 {
462 char rline[100];
463 static char *r[] = {
464 "th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th"
465 };
466
467 if (n == 0) {
468 printf("active");
469 col += 6;
470 return;
471 }
472 if ((n/10)%10 == 1)
473 (void)snprintf(rline, sizeof(rline), "%dth", n);
474 else
475 (void)snprintf(rline, sizeof(rline), "%d%s", n, r[n%10]);
476 col += strlen(rline);
477 printf("%s", rline);
478 }
479