displayq.c revision 30407
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
35static char sccsid[] = "@(#)displayq.c	8.4 (Berkeley) 4/28/95";
36#endif /* not lint */
37
38#include <sys/param.h>
39#include <sys/stat.h>
40#include <sys/file.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 */
64extern uid_t	uid, euid;
65
66static int	col;		/* column on screen */
67static char	current[40];	/* current file being printed */
68static char	file[132];	/* print file name */
69static int	first;		/* first file in ``files'' column? */
70static int	garbage;	/* # of garbage cf files */
71static int	lflag;		/* long output option */
72static int	rank;		/* order to be printed (-1=none, 0=active) */
73static long	totsize;	/* total print job size in bytes */
74
75static char	*head0 = "Rank   Owner      Job  Files";
76static char	*head1 = "Total Size\n";
77
78static void	alarmhandler __P((int));
79static void	warn __P((void));
80
81/*
82 * Display the current state of the queue. Format = 1 if long format.
83 */
84void
85displayq(format)
86	int format;
87{
88	register struct queue *q;
89	register int i, nitems, fd, ret;
90	register char	*cp;
91	struct queue **queue;
92	struct stat statb;
93	FILE *fp;
94	void (*savealrm)(int);
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	if (cgetnum(bp, "ct", &CT) < 0)
116		CT = DEFTIMEOUT;
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 (remote)
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 (remote)
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 ((i = getc(fp)) != EOF && i != '\n')
167				*cp++ = i;
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 ((i = getc(fp)) != EOF && i != '\n')
183					*cp++ = i;
184				*cp = '\0';
185				/*
186				 * Print the status file.
187				 */
188				if (remote)
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 (!remote) {
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) snprintf(line, sizeof(line), "%c%s", format + '\3', RP);
229	cp = line;
230	for (i = 0; i < requests && cp-line+10 < sizeof(line) - 1; i++) {
231		cp += strlen(cp);
232		(void) sprintf(cp, " %d", requ[i]);
233	}
234	for (i = 0; i < users && cp - line + 1 + strlen(user[i]) <
235		sizeof(line) - 1; i++) {
236		cp += strlen(cp);
237		*cp++ = ' ';
238		(void) strcpy(cp, user[i]);
239	}
240	strcat(line, "\n");
241	savealrm = signal(SIGALRM, alarmhandler);
242	alarm(CT);
243	fd = getport(RM, 0);
244	(void)signal(SIGALRM, savealrm);
245	if (fd < 0) {
246		if (from != host)
247			printf("%s: ", host);
248		printf("connection to %s is down\n", RM);
249	}
250	else {
251		i = strlen(line);
252		if (write(fd, line, i) != i)
253			fatal("Lost connection");
254		while ((i = read(fd, line, sizeof(line))) > 0)
255			(void) fwrite(line, 1, i, stdout);
256		(void) close(fd);
257	}
258}
259
260/*
261 * Print a warning message if there is no daemon present.
262 */
263static void
264warn()
265{
266	if (remote)
267		printf("\n%s: ", host);
268	puts("Warning: no daemon present");
269	current[0] = '\0';
270}
271
272/*
273 * Print the header for the short listing format
274 */
275void
276header()
277{
278	printf(head0);
279	col = strlen(head0)+1;
280	blankfill(SIZCOL);
281	printf(head1);
282}
283
284void
285inform(cf)
286	char *cf;
287{
288	register int j;
289	FILE *cfp;
290
291	/*
292	 * There's a chance the control file has gone away
293	 * in the meantime; if this is the case just keep going
294	 */
295	seteuid(euid);
296	if ((cfp = fopen(cf, "r")) == NULL)
297		return;
298	seteuid(uid);
299
300	if (rank < 0)
301		rank = 0;
302	if (remote || garbage || strcmp(cf, current))
303		rank++;
304	j = 0;
305	while (getline(cfp)) {
306		switch (line[0]) {
307		case 'P': /* Was this file specified in the user's list? */
308			if (!inlist(line+1, cf)) {
309				fclose(cfp);
310				return;
311			}
312			if (lflag) {
313				printf("\n%s: ", line+1);
314				col = strlen(line+1) + 2;
315				prank(rank);
316				blankfill(JOBCOL);
317				printf(" [job %s]\n", cf+3);
318			} else {
319				col = 0;
320				prank(rank);
321				blankfill(OWNCOL);
322				printf("%-10s %-3d  ", line+1, atoi(cf+3));
323				col += 16;
324				first = 1;
325			}
326			continue;
327		default: /* some format specifer and file name? */
328			if (line[0] < 'a' || line[0] > 'z')
329				continue;
330			if (j == 0 || strcmp(file, line+1) != 0) {
331				(void) strncpy(file, line+1, sizeof(file) - 1);
332				file[sizeof(file) - 1] = '\0';
333			}
334			j++;
335			continue;
336		case 'N':
337			show(line+1, file, j);
338			file[0] = '\0';
339			j = 0;
340		}
341	}
342	fclose(cfp);
343	if (!lflag) {
344		blankfill(SIZCOL);
345		printf("%ld bytes\n", totsize);
346		totsize = 0;
347	}
348}
349
350int
351inlist(name, file)
352	char *name, *file;
353{
354	register int *r, n;
355	register char **u, *cp;
356
357	if (users == 0 && requests == 0)
358		return(1);
359	/*
360	 * Check to see if it's in the user list
361	 */
362	for (u = user; u < &user[users]; u++)
363		if (!strcmp(*u, name))
364			return(1);
365	/*
366	 * Check the request list
367	 */
368	for (n = 0, cp = file+3; isdigit(*cp); )
369		n = n * 10 + (*cp++ - '0');
370	for (r = requ; r < &requ[requests]; r++)
371		if (*r == n && !strcmp(cp, from))
372			return(1);
373	return(0);
374}
375
376void
377show(nfile, file, copies)
378	register char *nfile, *file;
379	int copies;
380{
381	if (strcmp(nfile, " ") == 0)
382		nfile = "(standard input)";
383	if (lflag)
384		ldump(nfile, file, copies);
385	else
386		dump(nfile, file, copies);
387}
388
389/*
390 * Fill the line with blanks to the specified column
391 */
392void
393blankfill(n)
394	register int n;
395{
396	while (col++ < n)
397		putchar(' ');
398}
399
400/*
401 * Give the abbreviated dump of the file names
402 */
403void
404dump(nfile, file, copies)
405	char *nfile, *file;
406	int copies;
407{
408	register short n, fill;
409	struct stat lbuf;
410
411	/*
412	 * Print as many files as will fit
413	 *  (leaving room for the total size)
414	 */
415	 fill = first ? 0 : 2;	/* fill space for ``, '' */
416	 if (((n = strlen(nfile)) + col + fill) >= SIZCOL-4) {
417		if (col < SIZCOL) {
418			printf(" ..."), col += 4;
419			blankfill(SIZCOL);
420		}
421	} else {
422		if (first)
423			first = 0;
424		else
425			printf(", ");
426		printf("%s", nfile);
427		col += n+fill;
428	}
429	seteuid(euid);
430	if (*file && !stat(file, &lbuf))
431		totsize += copies * lbuf.st_size;
432	seteuid(uid);
433}
434
435/*
436 * Print the long info about the file
437 */
438void
439ldump(nfile, file, copies)
440	char *nfile, *file;
441	int copies;
442{
443	struct stat lbuf;
444
445	putchar('\t');
446	if (copies > 1)
447		printf("%-2d copies of %-19s", copies, nfile);
448	else
449		printf("%-32s", nfile);
450	if (*file && !stat(file, &lbuf))
451		printf(" %qd bytes", lbuf.st_size);
452	else
453		printf(" ??? bytes");
454	putchar('\n');
455}
456
457/*
458 * Print the job's rank in the queue,
459 *   update col for screen management
460 */
461void
462prank(n)
463	int n;
464{
465	char rline[100];
466	static char *r[] = {
467		"th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th"
468	};
469
470	if (n == 0) {
471		printf("active");
472		col += 6;
473		return;
474	}
475	if ((n/10)%10 == 1)
476		(void)snprintf(rline, sizeof(rline), "%dth", n);
477	else
478		(void)snprintf(rline, sizeof(rline), "%d%s", n, r[n%10]);
479	col += strlen(rline);
480	printf("%s", rline);
481}
482
483void
484alarmhandler(signo)
485	int signo;
486{
487	/* ignored */
488}
489