displayq.c revision 35998
1207753Smm/*
2207753Smm * Copyright (c) 1983, 1993
3207753Smm *	The Regents of the University of California.  All rights reserved.
4207753Smm *
5207753Smm * Redistribution and use in source and binary forms, with or without
6207753Smm * modification, are permitted provided that the following conditions
7207753Smm * are met:
8207753Smm * 1. Redistributions of source code must retain the above copyright
9207753Smm *    notice, this list of conditions and the following disclaimer.
10207753Smm * 2. Redistributions in binary form must reproduce the above copyright
11207753Smm *    notice, this list of conditions and the following disclaimer in the
12207753Smm *    documentation and/or other materials provided with the distribution.
13207753Smm * 3. All advertising materials mentioning features or use of this software
14207753Smm *    must display the following acknowledgement:
15207753Smm *	This product includes software developed by the University of
16207753Smm *	California, Berkeley and its contributors.
17207753Smm * 4. Neither the name of the University nor the names of its contributors
18207753Smm *    may be used to endorse or promote products derived from this software
19207753Smm *    without specific prior written permission.
20207753Smm *
21207753Smm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22207753Smm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23207753Smm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24207753Smm * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25207753Smm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26207753Smm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27207753Smm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28207753Smm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29207753Smm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30207753Smm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31207753Smm * SUCH DAMAGE.
32215187Smm */
33207753Smm
34207753Smm#ifndef lint
35207753Smm/*
36207753Smmstatic char sccsid[] = "@(#)displayq.c	8.4 (Berkeley) 4/28/95";
37207753Smm*/
38207753Smmstatic const char rcsid[] =
39207753Smm	"$Id: displayq.c,v 1.13 1997/12/02 20:45:19 wollman Exp $";
40207753Smm#endif /* not lint */
41207753Smm
42215187Smm#include <sys/param.h>
43207753Smm#include <sys/stat.h>
44207753Smm
45207753Smm#include <ctype.h>
46207753Smm#include <dirent.h>
47207753Smm#include <errno.h>
48207753Smm#include <fcntl.h>
49207753Smm#include <signal.h>
50207753Smm#include <stdio.h>
51207753Smm#include <stdlib.h>
52207753Smm#include <string.h>
53207753Smm#define psignal foil_gcc_psignal
54207753Smm#define	sys_siglist foil_gcc_siglist
55215187Smm#include <unistd.h>
56215187Smm#undef psignal
57215187Smm#undef sys_siglist
58207753Smm
59215187Smm#include "lp.h"
60215187Smm#include "lp.local.h"
61215187Smm#include "pathnames.h"
62207753Smm
63207753Smm/*
64207753Smm * Routines to display the state of the queue.
65207753Smm */
66207753Smm#define JOBCOL	40		/* column for job # in -l format */
67215187Smm#define OWNCOL	7		/* start of Owner column in normal */
68207753Smm#define SIZCOL	62		/* start of Size column in normal */
69207753Smm
70207753Smm/*
71207753Smm * Stuff for handling job specifications
72207753Smm */
73207753Smmextern uid_t	uid, euid;
74207753Smm
75207753Smmstatic int	col;		/* column on screen */
76207753Smmstatic char	current[40];	/* current file being printed */
77207753Smmstatic char	file[132];	/* print file name */
78207753Smmstatic int	first;		/* first file in ``files'' column? */
79207753Smmstatic int	garbage;	/* # of garbage cf files */
80207753Smmstatic int	lflag;		/* long output option */
81207753Smmstatic int	rank;		/* order to be printed (-1=none, 0=active) */
82207753Smmstatic long	totsize;	/* total print job size in bytes */
83207753Smm
84207753Smmstatic char	*head0 = "Rank   Owner      Job  Files";
85207753Smmstatic char	*head1 = "Total Size\n";
86207753Smm
87207753Smmstatic void	alarmhandler __P((int));
88207753Smmstatic void	warn __P((const struct printer *pp));
89207753Smm
90215187Smm/*
91215187Smm * Display the current state of the queue. Format = 1 if long format.
92215187Smm */
93207753Smmvoid
94207753Smmdisplayq(pp, format)
95207753Smm	struct printer *pp;
96207753Smm	int format;
97207753Smm{
98207753Smm	register struct queue *q;
99207753Smm	register int i, nitems, fd, ret;
100207753Smm	register char	*cp;
101207753Smm	struct queue **queue;
102207753Smm	struct stat statb;
103207753Smm	FILE *fp;
104207753Smm	void (*savealrm)(int);
105207753Smm
106207753Smm	lflag = format;
107207753Smm	totsize = 0;
108207753Smm	rank = -1;
109207753Smm
110207753Smm	if ((cp = checkremote(pp))) {
111207753Smm		printf("Warning: %s\n", cp);
112207753Smm		free(cp);
113207753Smm	}
114207753Smm
115213700Smm	/*
116213700Smm	 * Print out local queue
117207753Smm	 * Find all the control files in the spooling directory
118207753Smm	 */
119207753Smm	seteuid(euid);
120207753Smm	if (chdir(pp->spool_dir) < 0)
121207753Smm		fatal(pp, "cannot chdir to spooling directory: %s",
122207753Smm		      strerror(errno));
123207753Smm	seteuid(uid);
124207753Smm	if ((nitems = getq(pp, &queue)) < 0)
125207753Smm		fatal(pp, "cannot examine spooling area\n");
126207753Smm	seteuid(euid);
127207753Smm	ret = stat(pp->lock_file, &statb);
128215187Smm	seteuid(uid);
129215187Smm	if (ret >= 0) {
130215187Smm		if (statb.st_mode & LFM_PRINT_DIS) {
131207753Smm			if (pp->remote)
132207753Smm				printf("%s: ", host);
133207753Smm			printf("Warning: %s is down: ", pp->printer);
134207753Smm			seteuid(euid);
135207753Smm			fd = open(pp->status_file, O_RDONLY|O_SHLOCK);
136207753Smm			seteuid(uid);
137207753Smm			if (fd >= 0) {
138207753Smm				while ((i = read(fd, line, sizeof(line))) > 0)
139207753Smm					(void) fwrite(line, 1, i, stdout);
140207753Smm				(void) close(fd);	/* unlocks as well */
141207753Smm			} else
142207753Smm				putchar('\n');
143207753Smm		}
144207753Smm		if (statb.st_mode & LFM_QUEUE_DIS) {
145207753Smm			if (pp->remote)
146207753Smm				printf("%s: ", host);
147207753Smm			printf("Warning: %s queue is turned off\n",
148207753Smm			       pp->printer);
149207753Smm		}
150207753Smm	}
151207753Smm
152207753Smm	if (nitems) {
153207753Smm		seteuid(euid);
154213700Smm		fp = fopen(pp->lock_file, "r");
155213700Smm		seteuid(uid);
156213700Smm		if (fp == NULL)
157207753Smm			warn(pp);
158207753Smm		else {
159207753Smm			/* get daemon pid */
160207753Smm			cp = current;
161207753Smm			while ((i = getc(fp)) != EOF && i != '\n')
162207753Smm				*cp++ = i;
163207753Smm			*cp = '\0';
164207753Smm			i = atoi(current);
165207753Smm			if (i <= 0) {
166207753Smm				ret = -1;
167			} else {
168				seteuid(euid);
169				ret = kill(i, 0);
170				seteuid(uid);
171			}
172			if (ret < 0) {
173				warn(pp);
174			} else {
175				/* read current file name */
176				cp = current;
177				while ((i = getc(fp)) != EOF && i != '\n')
178					*cp++ = i;
179				*cp = '\0';
180				/*
181				 * Print the status file.
182				 */
183				if (pp->remote)
184					printf("%s: ", host);
185				seteuid(euid);
186				fd = open(pp->status_file, O_RDONLY|O_SHLOCK);
187				seteuid(uid);
188				if (fd >= 0) {
189					while ((i = read(fd, line,
190							 sizeof(line))) > 0)
191						fwrite(line, 1, i, stdout);
192					close(fd);	/* unlocks as well */
193				} else
194					putchar('\n');
195			}
196			(void) fclose(fp);
197		}
198		/*
199		 * Now, examine the control files and print out the jobs to
200		 * be done for each user.
201		 */
202		if (!lflag)
203			header();
204		for (i = 0; i < nitems; i++) {
205			q = queue[i];
206			inform(pp, q->q_name);
207			free(q);
208		}
209		free(queue);
210	}
211	if (!pp->remote) {
212		if (nitems == 0)
213			puts("no entries");
214		return;
215	}
216
217	/*
218	 * Print foreign queue
219	 * Note that a file in transit may show up in either queue.
220	 */
221	if (nitems)
222		putchar('\n');
223	(void) snprintf(line, sizeof(line), "%c%s", format ? '\4' : '\3',
224			pp->remote_queue);
225	cp = line;
226	for (i = 0; i < requests && cp-line+10 < sizeof(line) - 1; i++) {
227		cp += strlen(cp);
228		(void) sprintf(cp, " %d", requ[i]);
229	}
230	for (i = 0; i < users && cp - line + 1 + strlen(user[i]) <
231		sizeof(line) - 1; i++) {
232		cp += strlen(cp);
233		*cp++ = ' ';
234		(void) strcpy(cp, user[i]);
235	}
236	strcat(line, "\n");
237	savealrm = signal(SIGALRM, alarmhandler);
238	alarm(pp->conn_timeout);
239	fd = getport(pp, pp->remote_host, 0);
240	alarm(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", pp->remote_host);
246	}
247	else {
248		i = strlen(line);
249		if (write(fd, line, i) != i)
250			fatal(pp, "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 */
260static void
261warn(pp)
262	const struct printer *pp;
263{
264	if (pp->remote)
265		printf("%s: ", host);
266	puts("Warning: no daemon present");
267	current[0] = '\0';
268}
269
270/*
271 * Print the header for the short listing format
272 */
273void
274header()
275{
276	printf(head0);
277	col = strlen(head0)+1;
278	blankfill(SIZCOL);
279	printf(head1);
280}
281
282void
283inform(pp, cf)
284	const struct printer *pp;
285	char *cf;
286{
287	register int j;
288	FILE *cfp;
289
290	/*
291	 * There's a chance the control file has gone away
292	 * in the meantime; if this is the case just keep going
293	 */
294	seteuid(euid);
295	if ((cfp = fopen(cf, "r")) == NULL)
296		return;
297	seteuid(uid);
298
299	if (rank < 0)
300		rank = 0;
301	if (pp->remote || garbage || strcmp(cf, current))
302		rank++;
303	j = 0;
304	while (getline(cfp)) {
305		switch (line[0]) {
306		case 'P': /* Was this file specified in the user's list? */
307			if (!inlist(line+1, cf)) {
308				fclose(cfp);
309				return;
310			}
311			if (lflag) {
312				printf("\n%s: ", line+1);
313				col = strlen(line+1) + 2;
314				prank(rank);
315				blankfill(JOBCOL);
316				printf(" [job %s]\n", cf+3);
317			} else {
318				col = 0;
319				prank(rank);
320				blankfill(OWNCOL);
321				printf("%-10s %-3d  ", line+1, atoi(cf+3));
322				col += 16;
323				first = 1;
324			}
325			continue;
326		default: /* some format specifer and file name? */
327			if (line[0] < 'a' || line[0] > 'z')
328				continue;
329			if (j == 0 || strcmp(file, line+1) != 0) {
330				(void) strncpy(file, line+1, sizeof(file) - 1);
331				file[sizeof(file) - 1] = '\0';
332			}
333			j++;
334			continue;
335		case 'N':
336			show(line+1, file, j);
337			file[0] = '\0';
338			j = 0;
339		}
340	}
341	fclose(cfp);
342	if (!lflag) {
343		blankfill(SIZCOL);
344		printf("%ld bytes\n", totsize);
345		totsize = 0;
346	}
347}
348
349int
350inlist(name, file)
351	char *name, *file;
352{
353	register int *r, n;
354	register char **u, *cp;
355
356	if (users == 0 && requests == 0)
357		return(1);
358	/*
359	 * Check to see if it's in the user list
360	 */
361	for (u = user; u < &user[users]; u++)
362		if (!strcmp(*u, name))
363			return(1);
364	/*
365	 * Check the request list
366	 */
367	for (n = 0, cp = file+3; isdigit(*cp); )
368		n = n * 10 + (*cp++ - '0');
369	for (r = requ; r < &requ[requests]; r++)
370		if (*r == n && !strcmp(cp, from))
371			return(1);
372	return(0);
373}
374
375void
376show(nfile, file, copies)
377	register char *nfile, *file;
378	int copies;
379{
380	if (strcmp(nfile, " ") == 0)
381		nfile = "(standard input)";
382	if (lflag)
383		ldump(nfile, file, copies);
384	else
385		dump(nfile, file, copies);
386}
387
388/*
389 * Fill the line with blanks to the specified column
390 */
391void
392blankfill(n)
393	register int n;
394{
395	while (col++ < n)
396		putchar(' ');
397}
398
399/*
400 * Give the abbreviated dump of the file names
401 */
402void
403dump(nfile, file, copies)
404	char *nfile, *file;
405	int copies;
406{
407	register short n, fill;
408	struct stat lbuf;
409
410	/*
411	 * Print as many files as will fit
412	 *  (leaving room for the total size)
413	 */
414	 fill = first ? 0 : 2;	/* fill space for ``, '' */
415	 if (((n = strlen(nfile)) + col + fill) >= SIZCOL-4) {
416		if (col < SIZCOL) {
417			printf(" ..."), col += 4;
418			blankfill(SIZCOL);
419		}
420	} else {
421		if (first)
422			first = 0;
423		else
424			printf(", ");
425		printf("%s", nfile);
426		col += n+fill;
427	}
428	seteuid(euid);
429	if (*file && !stat(file, &lbuf))
430		totsize += copies * lbuf.st_size;
431	seteuid(uid);
432}
433
434/*
435 * Print the long info about the file
436 */
437void
438ldump(nfile, file, copies)
439	char *nfile, *file;
440	int copies;
441{
442	struct stat lbuf;
443
444	putchar('\t');
445	if (copies > 1)
446		printf("%-2d copies of %-19s", copies, nfile);
447	else
448		printf("%-32s", nfile);
449	if (*file && !stat(file, &lbuf))
450		printf(" %qd bytes", (long long) lbuf.st_size);
451	else
452		printf(" ??? bytes");
453	putchar('\n');
454}
455
456/*
457 * Print the job's rank in the queue,
458 *   update col for screen management
459 */
460void
461prank(n)
462	int n;
463{
464	char rline[100];
465	static char *r[] = {
466		"th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th"
467	};
468
469	if (n == 0) {
470		printf("active");
471		col += 6;
472		return;
473	}
474	if ((n/10)%10 == 1)
475		(void)snprintf(rline, sizeof(rline), "%dth", n);
476	else
477		(void)snprintf(rline, sizeof(rline), "%d%s", n, r[n%10]);
478	col += strlen(rline);
479	printf("%s", rline);
480}
481
482void
483alarmhandler(signo)
484	int signo;
485{
486	/* ignored */
487}
488