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