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