displayq.c revision 22466
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 */
64static int	col;		/* column on screen */
65static char	current[40];	/* current file being printed */
66static char	file[132];	/* print file name */
67static int	first;		/* first file in ``files'' column? */
68static int	garbage;	/* # of garbage cf files */
69static int	lflag;		/* long output option */
70static int	rank;		/* order to be printed (-1=none, 0=active) */
71static long	totsize;	/* total print job size in bytes */
72
73static char	*head0 = "Rank   Owner      Job  Files";
74static char	*head1 = "Total Size\n";
75
76/*
77 * Display the current state of the queue. Format = 1 if long format.
78 */
79void
80displayq(format)
81	int format;
82{
83	register struct queue *q;
84	register int i, nitems, fd;
85	register char	*cp;
86	struct queue **queue;
87	struct stat statb;
88	FILE *fp;
89
90	lflag = format;
91	totsize = 0;
92	rank = -1;
93	if ((i = cgetent(&bp, printcapdb, printer)) == -2)
94		fatal("can't open printer description file");
95	else if (i == -1)
96		fatal("unknown printer");
97	else if (i == -3)
98		fatal("potential reference loop detected in printcap file");
99	if (cgetstr(bp, "lp", &LP) < 0)
100		LP = _PATH_DEFDEVLP;
101	if (cgetstr(bp, "rp", &RP) < 0)
102		RP = DEFLP;
103	if (cgetstr(bp, "sd", &SD) < 0)
104		SD = _PATH_DEFSPOOL;
105	if (cgetstr(bp,"lo", &LO) < 0)
106		LO = DEFLOCK;
107	if (cgetstr(bp, "st", &ST) < 0)
108		ST = DEFSTAT;
109	cgetstr(bp, "rm", &RM);
110	if (cp = checkremote())
111		printf("Warning: %s\n", cp);
112
113	/*
114	 * Print out local queue
115	 * Find all the control files in the spooling directory
116	 */
117	if (chdir(SD) < 0)
118		fatal("cannot chdir to spooling directory");
119	if ((nitems = getq(&queue)) < 0)
120		fatal("cannot examine spooling area\n");
121	if (stat(LO, &statb) >= 0) {
122		if (statb.st_mode & 0100) {
123			if (remote)
124				printf("%s: ", host);
125			printf("Warning: %s is down: ", printer);
126			fd = open(ST, O_RDONLY);
127			if (fd >= 0) {
128				(void) flock(fd, LOCK_SH);
129				while ((i = read(fd, line, sizeof(line))) > 0)
130					(void) fwrite(line, 1, i, stdout);
131				(void) close(fd);	/* unlocks as well */
132			} else
133				putchar('\n');
134		}
135		if (statb.st_mode & 010) {
136			if (remote)
137				printf("%s: ", host);
138			printf("Warning: %s queue is turned off\n", printer);
139		}
140	}
141
142	if (nitems) {
143		fp = fopen(LO, "r");
144		if (fp == NULL)
145			warn();
146		else {
147			/* get daemon pid */
148			cp = current;
149			while ((i = getc(fp)) != EOF && i != '\n')
150				*cp++ = i;
151			*cp = '\0';
152			i = atoi(current);
153			if (i <= 0 || kill(i, 0) < 0)
154				warn();
155			else {
156				/* read current file name */
157				cp = current;
158				while ((i = getc(fp)) != EOF && i != '\n')
159					*cp++ = i;
160				*cp = '\0';
161				/*
162				 * Print the status file.
163				 */
164				if (remote)
165					printf("%s: ", host);
166				fd = open(ST, O_RDONLY);
167				if (fd >= 0) {
168					(void) flock(fd, LOCK_SH);
169					while ((i = read(fd, line, sizeof(line))) > 0)
170						(void) fwrite(line, 1, i, stdout);
171					(void) close(fd);	/* unlocks as well */
172				} else
173					putchar('\n');
174			}
175			(void) fclose(fp);
176		}
177		/*
178		 * Now, examine the control files and print out the jobs to
179		 * be done for each user.
180		 */
181		if (!lflag)
182			header();
183		for (i = 0; i < nitems; i++) {
184			q = queue[i];
185			inform(q->q_name);
186			free(q);
187		}
188		free(queue);
189	}
190	if (!remote) {
191		if (nitems == 0)
192			puts("no entries");
193		return;
194	}
195
196	/*
197	 * Print foreign queue
198	 * Note that a file in transit may show up in either queue.
199	 */
200	if (nitems)
201		putchar('\n');
202	(void) snprintf(line, sizeof(line), "%c%s", format + '\3', RP);
203	cp = line;
204	for (i = 0; i < requests && cp-line+10 < sizeof(line); i++) {
205		cp += strlen(cp);
206		(void) sprintf(cp, " %d", requ[i]);
207	}
208	for (i = 0; i < users && cp - line + 1 + strlen(user[i]) <
209		sizeof(line); i++) {
210		cp += strlen(cp);
211		*cp++ = ' ';
212		(void) strcpy(cp, user[i]);
213	}
214	strcat(line, "\n");
215	fd = getport(RM, 0);
216	if (fd < 0) {
217		if (from != host)
218			printf("%s: ", host);
219		printf("connection to %s is down\n", RM);
220	}
221	else {
222		i = strlen(line);
223		if (write(fd, line, i) != i)
224			fatal("Lost connection");
225		while ((i = read(fd, line, sizeof(line))) > 0)
226			(void) fwrite(line, 1, i, stdout);
227		(void) close(fd);
228	}
229}
230
231/*
232 * Print a warning message if there is no daemon present.
233 */
234void
235warn()
236{
237	if (remote)
238		printf("\n%s: ", host);
239	puts("Warning: no daemon present");
240	current[0] = '\0';
241}
242
243/*
244 * Print the header for the short listing format
245 */
246void
247header()
248{
249	printf(head0);
250	col = strlen(head0)+1;
251	blankfill(SIZCOL);
252	printf(head1);
253}
254
255void
256inform(cf)
257	char *cf;
258{
259	register int j;
260	FILE *cfp;
261
262	/*
263	 * There's a chance the control file has gone away
264	 * in the meantime; if this is the case just keep going
265	 */
266	if ((cfp = fopen(cf, "r")) == NULL)
267		return;
268
269	if (rank < 0)
270		rank = 0;
271	if (remote || garbage || strcmp(cf, current))
272		rank++;
273	j = 0;
274	while (getline(cfp)) {
275		switch (line[0]) {
276		case 'P': /* Was this file specified in the user's list? */
277			if (!inlist(line+1, cf)) {
278				fclose(cfp);
279				return;
280			}
281			if (lflag) {
282				printf("\n%s: ", line+1);
283				col = strlen(line+1) + 2;
284				prank(rank);
285				blankfill(JOBCOL);
286				printf(" [job %s]\n", cf+3);
287			} else {
288				col = 0;
289				prank(rank);
290				blankfill(OWNCOL);
291				printf("%-10s %-3d  ", line+1, atoi(cf+3));
292				col += 16;
293				first = 1;
294			}
295			continue;
296		default: /* some format specifer and file name? */
297			if (line[0] < 'a' || line[0] > 'z')
298				continue;
299			if (j == 0 || strcmp(file, line+1) != 0) {
300				(void) strncpy(file, line+1, sizeof(file) - 1);
301				file[sizeof(file) - 1] = '\0';
302			}
303			j++;
304			continue;
305		case 'N':
306			show(line+1, file, j);
307			file[0] = '\0';
308			j = 0;
309		}
310	}
311	fclose(cfp);
312	if (!lflag) {
313		blankfill(SIZCOL);
314		printf("%ld bytes\n", totsize);
315		totsize = 0;
316	}
317}
318
319int
320inlist(name, file)
321	char *name, *file;
322{
323	register int *r, n;
324	register char **u, *cp;
325
326	if (users == 0 && requests == 0)
327		return(1);
328	/*
329	 * Check to see if it's in the user list
330	 */
331	for (u = user; u < &user[users]; u++)
332		if (!strcmp(*u, name))
333			return(1);
334	/*
335	 * Check the request list
336	 */
337	for (n = 0, cp = file+3; isdigit(*cp); )
338		n = n * 10 + (*cp++ - '0');
339	for (r = requ; r < &requ[requests]; r++)
340		if (*r == n && !strcmp(cp, from))
341			return(1);
342	return(0);
343}
344
345void
346show(nfile, file, copies)
347	register char *nfile, *file;
348	int copies;
349{
350	if (strcmp(nfile, " ") == 0)
351		nfile = "(standard input)";
352	if (lflag)
353		ldump(nfile, file, copies);
354	else
355		dump(nfile, file, copies);
356}
357
358/*
359 * Fill the line with blanks to the specified column
360 */
361void
362blankfill(n)
363	register int n;
364{
365	while (col++ < n)
366		putchar(' ');
367}
368
369/*
370 * Give the abbreviated dump of the file names
371 */
372void
373dump(nfile, file, copies)
374	char *nfile, *file;
375	int copies;
376{
377	register short n, fill;
378	struct stat lbuf;
379
380	/*
381	 * Print as many files as will fit
382	 *  (leaving room for the total size)
383	 */
384	 fill = first ? 0 : 2;	/* fill space for ``, '' */
385	 if (((n = strlen(nfile)) + col + fill) >= SIZCOL-4) {
386		if (col < SIZCOL) {
387			printf(" ..."), col += 4;
388			blankfill(SIZCOL);
389		}
390	} else {
391		if (first)
392			first = 0;
393		else
394			printf(", ");
395		printf("%s", nfile);
396		col += n+fill;
397	}
398	if (*file && !stat(file, &lbuf))
399		totsize += copies * lbuf.st_size;
400}
401
402/*
403 * Print the long info about the file
404 */
405void
406ldump(nfile, file, copies)
407	char *nfile, *file;
408	int copies;
409{
410	struct stat lbuf;
411
412	putchar('\t');
413	if (copies > 1)
414		printf("%-2d copies of %-19s", copies, nfile);
415	else
416		printf("%-32s", nfile);
417	if (*file && !stat(file, &lbuf))
418		printf(" %qd bytes", lbuf.st_size);
419	else
420		printf(" ??? bytes");
421	putchar('\n');
422}
423
424/*
425 * Print the job's rank in the queue,
426 *   update col for screen management
427 */
428void
429prank(n)
430	int n;
431{
432	char rline[100];
433	static char *r[] = {
434		"th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th"
435	};
436
437	if (n == 0) {
438		printf("active");
439		col += 6;
440		return;
441	}
442	if ((n/10)%10 == 1)
443		(void)snprintf(rline, sizeof(rline), "%dth", n);
444	else
445		(void)snprintf(rline, sizeof(rline), "%d%s", n, r[n%10]);
446	col += strlen(rline);
447	printf("%s", rline);
448}
449