displayq.c revision 27757
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));
79
80/*
81 * Display the current state of the queue. Format = 1 if long format.
82 */
83void
84displayq(format)
85	int format;
86{
87	register struct queue *q;
88	register int i, nitems, fd, ret;
89	register char	*cp;
90	struct queue **queue;
91	struct stat statb;
92	FILE *fp;
93	void (*savealrm)(int);
94
95	lflag = format;
96	totsize = 0;
97	rank = -1;
98	if ((i = cgetent(&bp, printcapdb, printer)) == -2)
99		fatal("can't open printer description file");
100	else if (i == -1)
101		fatal("unknown printer");
102	else if (i == -3)
103		fatal("potential reference loop detected in printcap file");
104	if (cgetstr(bp, "lp", &LP) < 0)
105		LP = _PATH_DEFDEVLP;
106	if (cgetstr(bp, "rp", &RP) < 0)
107		RP = DEFLP;
108	if (cgetstr(bp, "sd", &SD) < 0)
109		SD = _PATH_DEFSPOOL;
110	if (cgetstr(bp,"lo", &LO) < 0)
111		LO = DEFLOCK;
112	if (cgetstr(bp, "st", &ST) < 0)
113		ST = DEFSTAT;
114	cgetstr(bp, "rm", &RM);
115	if ((cp = checkremote()))
116		printf("Warning: %s\n", cp);
117
118	/*
119	 * Print out local queue
120	 * Find all the control files in the spooling directory
121	 */
122	seteuid(euid);
123	if (chdir(SD) < 0)
124		fatal("cannot chdir to spooling directory");
125	seteuid(uid);
126	if ((nitems = getq(&queue)) < 0)
127		fatal("cannot examine spooling area\n");
128	seteuid(euid);
129	ret = stat(LO, &statb);
130	seteuid(uid);
131	if (ret >= 0) {
132		if (statb.st_mode & 0100) {
133			if (remote)
134				printf("%s: ", host);
135			printf("Warning: %s is down: ", printer);
136			seteuid(euid);
137			fd = open(ST, O_RDONLY);
138			seteuid(uid);
139			if (fd >= 0) {
140				(void) flock(fd, LOCK_SH);
141				while ((i = read(fd, line, sizeof(line))) > 0)
142					(void) fwrite(line, 1, i, stdout);
143				(void) close(fd);	/* unlocks as well */
144			} else
145				putchar('\n');
146		}
147		if (statb.st_mode & 010) {
148			if (remote)
149				printf("%s: ", host);
150			printf("Warning: %s queue is turned off\n", printer);
151		}
152	}
153
154	if (nitems) {
155		seteuid(euid);
156		fp = fopen(LO, "r");
157		seteuid(uid);
158		if (fp == NULL)
159			warn();
160		else {
161			/* get daemon pid */
162			cp = current;
163			while ((i = getc(fp)) != EOF && i != '\n')
164				*cp++ = i;
165			*cp = '\0';
166			i = atoi(current);
167			if (i <= 0) {
168				ret = -1;
169			} else {
170				seteuid(euid);
171				ret = kill(i, 0);
172				seteuid(uid);
173			}
174			if (ret < 0) {
175				warn();
176			} else {
177				/* read current file name */
178				cp = current;
179				while ((i = getc(fp)) != EOF && i != '\n')
180					*cp++ = i;
181				*cp = '\0';
182				/*
183				 * Print the status file.
184				 */
185				if (remote)
186					printf("%s: ", host);
187				seteuid(euid);
188				fd = open(ST, O_RDONLY);
189				seteuid(uid);
190				if (fd >= 0) {
191					(void) flock(fd, LOCK_SH);
192					while ((i = read(fd, line, sizeof(line))) > 0)
193						(void) fwrite(line, 1, i, stdout);
194					(void) close(fd);	/* unlocks as well */
195				} else
196					putchar('\n');
197			}
198			(void) fclose(fp);
199		}
200		/*
201		 * Now, examine the control files and print out the jobs to
202		 * be done for each user.
203		 */
204		if (!lflag)
205			header();
206		for (i = 0; i < nitems; i++) {
207			q = queue[i];
208			inform(q->q_name);
209			free(q);
210		}
211		free(queue);
212	}
213	if (!remote) {
214		if (nitems == 0)
215			puts("no entries");
216		return;
217	}
218
219	/*
220	 * Print foreign queue
221	 * Note that a file in transit may show up in either queue.
222	 */
223	if (nitems)
224		putchar('\n');
225	(void) snprintf(line, sizeof(line), "%c%s", format + '\3', RP);
226	cp = line;
227	for (i = 0; i < requests && cp-line+10 < sizeof(line) - 1; i++) {
228		cp += strlen(cp);
229		(void) sprintf(cp, " %d", requ[i]);
230	}
231	for (i = 0; i < users && cp - line + 1 + strlen(user[i]) <
232		sizeof(line) - 1; i++) {
233		cp += strlen(cp);
234		*cp++ = ' ';
235		(void) strcpy(cp, user[i]);
236	}
237	strcat(line, "\n");
238	savealrm = signal(SIGALRM, alarmhandler);
239	alarm(10);
240	fd = getport(RM, 0);
241	(void)signal(SIGALRM, savealrm);
242	if (fd < 0) {
243		if (from != host)
244			printf("%s: ", host);
245		printf("connection to %s is down\n", RM);
246	}
247	else {
248		i = strlen(line);
249		if (write(fd, line, i) != i)
250			fatal("Lost connection");
251		while ((i = read(fd, line, sizeof(line))) > 0)
252			(void) fwrite(line, 1, i, stdout);
253		(void) close(fd);
254	}
255}
256
257/*
258 * Print a warning message if there is no daemon present.
259 */
260void
261warn()
262{
263	if (remote)
264		printf("\n%s: ", host);
265	puts("Warning: no daemon present");
266	current[0] = '\0';
267}
268
269/*
270 * Print the header for the short listing format
271 */
272void
273header()
274{
275	printf(head0);
276	col = strlen(head0)+1;
277	blankfill(SIZCOL);
278	printf(head1);
279}
280
281void
282inform(cf)
283	char *cf;
284{
285	register int j;
286	FILE *cfp;
287
288	/*
289	 * There's a chance the control file has gone away
290	 * in the meantime; if this is the case just keep going
291	 */
292	seteuid(euid);
293	if ((cfp = fopen(cf, "r")) == NULL)
294		return;
295	seteuid(uid);
296
297	if (rank < 0)
298		rank = 0;
299	if (remote || garbage || strcmp(cf, current))
300		rank++;
301	j = 0;
302	while (getline(cfp)) {
303		switch (line[0]) {
304		case 'P': /* Was this file specified in the user's list? */
305			if (!inlist(line+1, cf)) {
306				fclose(cfp);
307				return;
308			}
309			if (lflag) {
310				printf("\n%s: ", line+1);
311				col = strlen(line+1) + 2;
312				prank(rank);
313				blankfill(JOBCOL);
314				printf(" [job %s]\n", cf+3);
315			} else {
316				col = 0;
317				prank(rank);
318				blankfill(OWNCOL);
319				printf("%-10s %-3d  ", line+1, atoi(cf+3));
320				col += 16;
321				first = 1;
322			}
323			continue;
324		default: /* some format specifer and file name? */
325			if (line[0] < 'a' || line[0] > 'z')
326				continue;
327			if (j == 0 || strcmp(file, line+1) != 0) {
328				(void) strncpy(file, line+1, sizeof(file) - 1);
329				file[sizeof(file) - 1] = '\0';
330			}
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
347int
348inlist(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
373void
374show(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 */
389void
390blankfill(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 */
400void
401dump(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 */
435void
436ldump(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 */
458void
459prank(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
480void
481alarmhandler(signo)
482	int signo;
483{
484	/* ignored */
485}
486