displayq.c revision 15703
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) sprintf(line, "%c%s", format + '\3', RP);
203	cp = line;
204	for (i = 0; i < requests; i++) {
205		cp += strlen(cp);
206		(void) sprintf(cp, " %d", requ[i]);
207	}
208	for (i = 0; i < users; i++) {
209		cp += strlen(cp);
210		*cp++ = ' ';
211		(void) strcpy(cp, user[i]);
212	}
213	strcat(line, "\n");
214	fd = getport(RM, 0);
215	if (fd < 0) {
216		if (from != host)
217			printf("%s: ", host);
218		printf("connection to %s is down\n", RM);
219	}
220	else {
221		i = strlen(line);
222		if (write(fd, line, i) != i)
223			fatal("Lost connection");
224		while ((i = read(fd, line, sizeof(line))) > 0)
225			(void) fwrite(line, 1, i, stdout);
226		(void) close(fd);
227	}
228}
229
230/*
231 * Print a warning message if there is no daemon present.
232 */
233void
234warn()
235{
236	if (remote)
237		printf("\n%s: ", host);
238	puts("Warning: no daemon present");
239	current[0] = '\0';
240}
241
242/*
243 * Print the header for the short listing format
244 */
245void
246header()
247{
248	printf(head0);
249	col = strlen(head0)+1;
250	blankfill(SIZCOL);
251	printf(head1);
252}
253
254void
255inform(cf)
256	char *cf;
257{
258	register int j;
259	FILE *cfp;
260
261	/*
262	 * There's a chance the control file has gone away
263	 * in the meantime; if this is the case just keep going
264	 */
265	if ((cfp = fopen(cf, "r")) == NULL)
266		return;
267
268	if (rank < 0)
269		rank = 0;
270	if (remote || garbage || strcmp(cf, current))
271		rank++;
272	j = 0;
273	while (getline(cfp)) {
274		switch (line[0]) {
275		case 'P': /* Was this file specified in the user's list? */
276			if (!inlist(line+1, cf)) {
277				fclose(cfp);
278				return;
279			}
280			if (lflag) {
281				printf("\n%s: ", line+1);
282				col = strlen(line+1) + 2;
283				prank(rank);
284				blankfill(JOBCOL);
285				printf(" [job %s]\n", cf+3);
286			} else {
287				col = 0;
288				prank(rank);
289				blankfill(OWNCOL);
290				printf("%-10s %-3d  ", line+1, atoi(cf+3));
291				col += 16;
292				first = 1;
293			}
294			continue;
295		default: /* some format specifer and file name? */
296			if (line[0] < 'a' || line[0] > 'z')
297				continue;
298			if (j == 0 || strcmp(file, line+1) != 0)
299				(void) strcpy(file, line+1);
300			j++;
301			continue;
302		case 'N':
303			show(line+1, file, j);
304			file[0] = '\0';
305			j = 0;
306		}
307	}
308	fclose(cfp);
309	if (!lflag) {
310		blankfill(SIZCOL);
311		printf("%ld bytes\n", totsize);
312		totsize = 0;
313	}
314}
315
316int
317inlist(name, file)
318	char *name, *file;
319{
320	register int *r, n;
321	register char **u, *cp;
322
323	if (users == 0 && requests == 0)
324		return(1);
325	/*
326	 * Check to see if it's in the user list
327	 */
328	for (u = user; u < &user[users]; u++)
329		if (!strcmp(*u, name))
330			return(1);
331	/*
332	 * Check the request list
333	 */
334	for (n = 0, cp = file+3; isdigit(*cp); )
335		n = n * 10 + (*cp++ - '0');
336	for (r = requ; r < &requ[requests]; r++)
337		if (*r == n && !strcmp(cp, from))
338			return(1);
339	return(0);
340}
341
342void
343show(nfile, file, copies)
344	register char *nfile, *file;
345	int copies;
346{
347	if (strcmp(nfile, " ") == 0)
348		nfile = "(standard input)";
349	if (lflag)
350		ldump(nfile, file, copies);
351	else
352		dump(nfile, file, copies);
353}
354
355/*
356 * Fill the line with blanks to the specified column
357 */
358void
359blankfill(n)
360	register int n;
361{
362	while (col++ < n)
363		putchar(' ');
364}
365
366/*
367 * Give the abbreviated dump of the file names
368 */
369void
370dump(nfile, file, copies)
371	char *nfile, *file;
372	int copies;
373{
374	register short n, fill;
375	struct stat lbuf;
376
377	/*
378	 * Print as many files as will fit
379	 *  (leaving room for the total size)
380	 */
381	 fill = first ? 0 : 2;	/* fill space for ``, '' */
382	 if (((n = strlen(nfile)) + col + fill) >= SIZCOL-4) {
383		if (col < SIZCOL) {
384			printf(" ..."), col += 4;
385			blankfill(SIZCOL);
386		}
387	} else {
388		if (first)
389			first = 0;
390		else
391			printf(", ");
392		printf("%s", nfile);
393		col += n+fill;
394	}
395	if (*file && !stat(file, &lbuf))
396		totsize += copies * lbuf.st_size;
397}
398
399/*
400 * Print the long info about the file
401 */
402void
403ldump(nfile, file, copies)
404	char *nfile, *file;
405	int copies;
406{
407	struct stat lbuf;
408
409	putchar('\t');
410	if (copies > 1)
411		printf("%-2d copies of %-19s", copies, nfile);
412	else
413		printf("%-32s", nfile);
414	if (*file && !stat(file, &lbuf))
415		printf(" %qd bytes", lbuf.st_size);
416	else
417		printf(" ??? bytes");
418	putchar('\n');
419}
420
421/*
422 * Print the job's rank in the queue,
423 *   update col for screen management
424 */
425void
426prank(n)
427	int n;
428{
429	char rline[100];
430	static char *r[] = {
431		"th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th"
432	};
433
434	if (n == 0) {
435		printf("active");
436		col += 6;
437		return;
438	}
439	if ((n/10)%10 == 1)
440		(void)snprintf(rline, sizeof(rline), "%dth", n);
441	else
442		(void)snprintf(rline, sizeof(rline), "%d%s", n, r[n%10]);
443	col += strlen(rline);
444	printf("%s", rline);
445}
446