displayq.c revision 30437
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	if (cgetstr(bp, "rm", &RM) < 0)
118		RM = NULL;
119	if ((cp = checkremote()))
120		printf("Warning: %s\n", cp);
121
122	/*
123	 * Print out local queue
124	 * Find all the control files in the spooling directory
125	 */
126	seteuid(euid);
127	if (chdir(SD) < 0)
128		fatal("cannot chdir to spooling directory");
129	seteuid(uid);
130	if ((nitems = getq(&queue)) < 0)
131		fatal("cannot examine spooling area\n");
132	seteuid(euid);
133	ret = stat(LO, &statb);
134	seteuid(uid);
135	if (ret >= 0) {
136		if (statb.st_mode & 0100) {
137			if (remote)
138				printf("%s: ", host);
139			printf("Warning: %s is down: ", printer);
140			seteuid(euid);
141			fd = open(ST, O_RDONLY);
142			seteuid(uid);
143			if (fd >= 0) {
144				(void) flock(fd, LOCK_SH);
145				while ((i = read(fd, line, sizeof(line))) > 0)
146					(void) fwrite(line, 1, i, stdout);
147				(void) close(fd);	/* unlocks as well */
148			} else
149				putchar('\n');
150		}
151		if (statb.st_mode & 010) {
152			if (remote)
153				printf("%s: ", host);
154			printf("Warning: %s queue is turned off\n", printer);
155		}
156	}
157
158	if (nitems) {
159		seteuid(euid);
160		fp = fopen(LO, "r");
161		seteuid(uid);
162		if (fp == NULL)
163			warn();
164		else {
165			/* get daemon pid */
166			cp = current;
167			while ((i = getc(fp)) != EOF && i != '\n')
168				*cp++ = i;
169			*cp = '\0';
170			i = atoi(current);
171			if (i <= 0) {
172				ret = -1;
173			} else {
174				seteuid(euid);
175				ret = kill(i, 0);
176				seteuid(uid);
177			}
178			if (ret < 0) {
179				warn();
180			} else {
181				/* read current file name */
182				cp = current;
183				while ((i = getc(fp)) != EOF && i != '\n')
184					*cp++ = i;
185				*cp = '\0';
186				/*
187				 * Print the status file.
188				 */
189				if (remote)
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 (!remote) {
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 && cp-line+10 < sizeof(line) - 1; i++) {
232		cp += strlen(cp);
233		(void) sprintf(cp, " %d", requ[i]);
234	}
235	for (i = 0; i < users && cp - line + 1 + strlen(user[i]) <
236		sizeof(line) - 1; i++) {
237		cp += strlen(cp);
238		*cp++ = ' ';
239		(void) strcpy(cp, user[i]);
240	}
241	strcat(line, "\n");
242	savealrm = signal(SIGALRM, alarmhandler);
243	alarm(CT);
244	fd = getport(RM, 0);
245	(void)signal(SIGALRM, savealrm);
246	if (fd < 0) {
247		if (from != host)
248			printf("%s: ", host);
249		printf("connection to %s is down\n", RM);
250	}
251	else {
252		i = strlen(line);
253		if (write(fd, line, i) != i)
254			fatal("Lost connection");
255		while ((i = read(fd, line, sizeof(line))) > 0)
256			(void) fwrite(line, 1, i, stdout);
257		(void) close(fd);
258	}
259}
260
261/*
262 * Print a warning message if there is no daemon present.
263 */
264static void
265warn()
266{
267	if (remote)
268		printf("%s: ", host);
269	puts("Warning: no daemon present");
270	current[0] = '\0';
271}
272
273/*
274 * Print the header for the short listing format
275 */
276void
277header()
278{
279	printf(head0);
280	col = strlen(head0)+1;
281	blankfill(SIZCOL);
282	printf(head1);
283}
284
285void
286inform(cf)
287	char *cf;
288{
289	register int j;
290	FILE *cfp;
291
292	/*
293	 * There's a chance the control file has gone away
294	 * in the meantime; if this is the case just keep going
295	 */
296	seteuid(euid);
297	if ((cfp = fopen(cf, "r")) == NULL)
298		return;
299	seteuid(uid);
300
301	if (rank < 0)
302		rank = 0;
303	if (remote || garbage || strcmp(cf, current))
304		rank++;
305	j = 0;
306	while (getline(cfp)) {
307		switch (line[0]) {
308		case 'P': /* Was this file specified in the user's list? */
309			if (!inlist(line+1, cf)) {
310				fclose(cfp);
311				return;
312			}
313			if (lflag) {
314				printf("\n%s: ", line+1);
315				col = strlen(line+1) + 2;
316				prank(rank);
317				blankfill(JOBCOL);
318				printf(" [job %s]\n", cf+3);
319			} else {
320				col = 0;
321				prank(rank);
322				blankfill(OWNCOL);
323				printf("%-10s %-3d  ", line+1, atoi(cf+3));
324				col += 16;
325				first = 1;
326			}
327			continue;
328		default: /* some format specifer and file name? */
329			if (line[0] < 'a' || line[0] > 'z')
330				continue;
331			if (j == 0 || strcmp(file, line+1) != 0) {
332				(void) strncpy(file, line+1, sizeof(file) - 1);
333				file[sizeof(file) - 1] = '\0';
334			}
335			j++;
336			continue;
337		case 'N':
338			show(line+1, file, j);
339			file[0] = '\0';
340			j = 0;
341		}
342	}
343	fclose(cfp);
344	if (!lflag) {
345		blankfill(SIZCOL);
346		printf("%ld bytes\n", totsize);
347		totsize = 0;
348	}
349}
350
351int
352inlist(name, file)
353	char *name, *file;
354{
355	register int *r, n;
356	register char **u, *cp;
357
358	if (users == 0 && requests == 0)
359		return(1);
360	/*
361	 * Check to see if it's in the user list
362	 */
363	for (u = user; u < &user[users]; u++)
364		if (!strcmp(*u, name))
365			return(1);
366	/*
367	 * Check the request list
368	 */
369	for (n = 0, cp = file+3; isdigit(*cp); )
370		n = n * 10 + (*cp++ - '0');
371	for (r = requ; r < &requ[requests]; r++)
372		if (*r == n && !strcmp(cp, from))
373			return(1);
374	return(0);
375}
376
377void
378show(nfile, file, copies)
379	register char *nfile, *file;
380	int copies;
381{
382	if (strcmp(nfile, " ") == 0)
383		nfile = "(standard input)";
384	if (lflag)
385		ldump(nfile, file, copies);
386	else
387		dump(nfile, file, copies);
388}
389
390/*
391 * Fill the line with blanks to the specified column
392 */
393void
394blankfill(n)
395	register int n;
396{
397	while (col++ < n)
398		putchar(' ');
399}
400
401/*
402 * Give the abbreviated dump of the file names
403 */
404void
405dump(nfile, file, copies)
406	char *nfile, *file;
407	int copies;
408{
409	register short n, fill;
410	struct stat lbuf;
411
412	/*
413	 * Print as many files as will fit
414	 *  (leaving room for the total size)
415	 */
416	 fill = first ? 0 : 2;	/* fill space for ``, '' */
417	 if (((n = strlen(nfile)) + col + fill) >= SIZCOL-4) {
418		if (col < SIZCOL) {
419			printf(" ..."), col += 4;
420			blankfill(SIZCOL);
421		}
422	} else {
423		if (first)
424			first = 0;
425		else
426			printf(", ");
427		printf("%s", nfile);
428		col += n+fill;
429	}
430	seteuid(euid);
431	if (*file && !stat(file, &lbuf))
432		totsize += copies * lbuf.st_size;
433	seteuid(uid);
434}
435
436/*
437 * Print the long info about the file
438 */
439void
440ldump(nfile, file, copies)
441	char *nfile, *file;
442	int copies;
443{
444	struct stat lbuf;
445
446	putchar('\t');
447	if (copies > 1)
448		printf("%-2d copies of %-19s", copies, nfile);
449	else
450		printf("%-32s", nfile);
451	if (*file && !stat(file, &lbuf))
452		printf(" %qd bytes", lbuf.st_size);
453	else
454		printf(" ??? bytes");
455	putchar('\n');
456}
457
458/*
459 * Print the job's rank in the queue,
460 *   update col for screen management
461 */
462void
463prank(n)
464	int n;
465{
466	char rline[100];
467	static char *r[] = {
468		"th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th"
469	};
470
471	if (n == 0) {
472		printf("active");
473		col += 6;
474		return;
475	}
476	if ((n/10)%10 == 1)
477		(void)snprintf(rline, sizeof(rline), "%dth", n);
478	else
479		(void)snprintf(rline, sizeof(rline), "%d%s", n, r[n%10]);
480	col += strlen(rline);
481	printf("%s", rline);
482}
483
484void
485alarmhandler(signo)
486	int signo;
487{
488	/* ignored */
489}
490