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