displayq.c revision 1.14
1/*	$OpenBSD: displayq.c,v 1.14 2001/08/30 17:38:13 millert Exp $	*/
2
3/*
4 * Copyright (c) 1983, 1993
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 *    must display the following acknowledgement:
17 *	This product includes software developed by the University of
18 *	California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 *    may be used to endorse or promote products derived from this software
21 *    without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36#ifndef lint
37#if 0
38static const char sccsid[] = "@(#)displayq.c	8.4 (Berkeley) 4/28/95";
39#else
40static const char rcsid[] = "$OpenBSD: displayq.c,v 1.14 2001/08/30 17:38:13 millert Exp $";
41#endif
42#endif /* not lint */
43
44#include <sys/param.h>
45#include <sys/stat.h>
46#include <sys/file.h>
47
48#include <signal.h>
49#include <fcntl.h>
50#include <dirent.h>
51#include <unistd.h>
52#include <stdio.h>
53#include <stdlib.h>
54#include <string.h>
55#include <ctype.h>
56#include "lp.h"
57#include "lp.local.h"
58#include "pathnames.h"
59
60/*
61 * Routines to display the state of the queue.
62 */
63#define JOBCOL	40		/* column for job # in -l format */
64#define OWNCOL	7		/* start of Owner column in normal */
65#define SIZCOL	62		/* start of Size column in normal */
66
67/*
68 * Stuff for handling job specifications
69 */
70extern int	requ[];		/* job number of spool entries */
71extern int	requests;	/* # of spool requests */
72extern char    *user[];	        /* users to process */
73extern int	users;		/* # of users in user array */
74
75extern uid_t	uid, euid;
76
77static int	col;		/* column on screen */
78static char	current[NAME_MAX]; /* current file being printed */
79static char	file[NAME_MAX];	/* print file name */
80static int	first;		/* first file in ``files'' column? */
81static int	garbage;	/* # of garbage cf files */
82static int	lflag;		/* long output option */
83static int	rank;		/* order to be printed (-1=none, 0=active) */
84static long	totsize;	/* total print job size in bytes */
85
86static char	*head0 = "Rank   Owner      Job  Files";
87static char	*head1 = "Total Size\n";
88
89/*
90 * Display the current state of the queue. Format = 1 if long format.
91 */
92void
93displayq(format)
94	int format;
95{
96	struct queue *q;
97	int i, nitems, fd, ret, len;
98	char *cp, *ecp;
99	struct queue **queue;
100	struct stat statb;
101	FILE *fp;
102
103	lflag = format;
104	totsize = 0;
105	rank = -1;
106	if ((i = cgetent(&bp, printcapdb, printer)) == -2)
107		fatal("can't open printer description file");
108	else if (i == -1)
109		fatal("unknown printer");
110	else if (i == -3)
111		fatal("potential reference loop detected in printcap file");
112	if (cgetstr(bp, "lp", &LP) < 0)
113		LP = _PATH_DEFDEVLP;
114	if (cgetstr(bp, "rp", &RP) < 0)
115		RP = DEFLP;
116	if (cgetstr(bp, "sd", &SD) < 0)
117		SD = _PATH_DEFSPOOL;
118	if (cgetstr(bp,"lo", &LO) < 0)
119		LO = DEFLOCK;
120	if (cgetstr(bp, "st", &ST) < 0)
121		ST = DEFSTAT;
122	cgetstr(bp, "rm", &RM);
123	if ((cp = checkremote()))
124		printf("Warning: %s\n", cp);
125
126	/*
127	 * Print out local queue
128	 * Find all the control files in the spooling directory
129	 */
130	seteuid(euid);
131	if (chdir(SD) < 0)
132		fatal("cannot chdir to spooling directory");
133	seteuid(uid);
134	if ((nitems = getq(&queue)) < 0)
135		fatal("cannot examine spooling area\n");
136	seteuid(euid);
137	ret = stat(LO, &statb);
138	seteuid(uid);
139	if (ret >= 0) {
140		if (statb.st_mode & 0100) {
141			if (remote)
142				printf("%s: ", host);
143			printf("Warning: %s is down: ", printer);
144			seteuid(euid);
145			fd = open(ST, O_RDONLY);
146			seteuid(uid);
147			if (fd >= 0) {
148				(void) flock(fd, LOCK_SH);
149				while ((i = read(fd, line, sizeof(line))) > 0)
150					(void) fwrite(line, 1, i, stdout);
151				(void) close(fd);	/* unlocks as well */
152			} else
153				putchar('\n');
154		}
155		if (statb.st_mode & 010) {
156			if (remote)
157				printf("%s: ", host);
158			printf("Warning: %s queue is turned off\n", printer);
159		}
160	}
161
162	if (nitems) {
163		seteuid(euid);
164		fp = fopen(LO, "r");
165		seteuid(uid);
166		if (fp == NULL)
167			warn();
168		else {
169			/* get daemon pid */
170			cp = current;
171			ecp = cp + sizeof(current) - 1;
172			while ((i = getc(fp)) != EOF && i != '\n') {
173				if (cp < ecp)
174					*cp++ = i;
175			}
176			*cp = '\0';
177			i = atoi(current);
178			if (i <= 0) {
179				ret = -1;
180			} else {
181				seteuid(euid);
182				ret = kill(i, 0);
183				seteuid(uid);
184			}
185			if (ret < 0) {
186				warn();
187			} else {
188				/* read current file name */
189				cp = current;
190		    		ecp = cp + sizeof(current) - 1;
191				while ((i = getc(fp)) != EOF && i != '\n') {
192					if (cp < ecp)
193						*cp++ = i;
194				}
195				*cp = '\0';
196				/*
197				 * Print the status file.
198				 */
199				if (remote)
200					printf("%s: ", host);
201				seteuid(euid);
202				fd = open(ST, O_RDONLY);
203				seteuid(uid);
204				if (fd >= 0) {
205					(void) flock(fd, LOCK_SH);
206					while ((i = read(fd, line, sizeof(line))) > 0)
207						(void) fwrite(line, 1, i, stdout);
208					(void) close(fd);	/* unlocks as well */
209				} else
210					putchar('\n');
211			}
212			(void) fclose(fp);
213		}
214		/*
215		 * Now, examine the control files and print out the jobs to
216		 * be done for each user.
217		 */
218		if (!lflag)
219			header();
220		for (i = 0; i < nitems; i++) {
221			q = queue[i];
222			inform(q->q_name);
223			free(q);
224		}
225		free(queue);
226	}
227	if (!remote) {
228		if (nitems == 0)
229			puts("no entries");
230		return;
231	}
232
233	/*
234	 * Print foreign queue
235	 * Note that a file in transit may show up in either queue.
236	 */
237	if (nitems)
238		putchar('\n');
239	(void) snprintf(line, sizeof line, "%c%s", format + '\3', RP);
240	cp = line;
241	cp += strlen(cp);
242	for (i = 0; i < requests && cp-line < sizeof(line) - 1; i++) {
243		len = line + sizeof line - cp;
244		if (snprintf(cp, len, " %d", requ[i]) >= len) {
245			cp += strlen(cp);
246			break;
247		}
248		cp += strlen(cp);
249	}
250	for (i = 0; i < users && cp-line < sizeof(line) - 1; i++) {
251		len = line + sizeof line - cp;
252		if (snprintf(cp, len, " %s", user[i]) >= len) {
253			cp += strlen(cp);
254			break;
255		}
256	}
257	if (cp-line < sizeof(line) - 1) {
258		strcat(line, "\n");
259	} else {
260		line[sizeof line-2] = '\n';
261	}
262	fd = getport(RM, 0);
263	if (fd < 0) {
264		if (from != host)
265			printf("%s: ", host);
266		printf("connection to %s is down\n", RM);
267	}
268	else {
269		i = strlen(line);
270		if (write(fd, line, i) != i)
271			fatal("Lost connection");
272		while ((i = read(fd, line, sizeof(line))) > 0)
273			(void) fwrite(line, 1, i, stdout);
274		(void) close(fd);
275	}
276}
277
278/*
279 * Print a warning message if there is no daemon present.
280 */
281void
282warn()
283{
284	if (remote)
285		printf("\n%s: ", host);
286	puts("Warning: no daemon present");
287	current[0] = '\0';
288}
289
290/*
291 * Print the header for the short listing format
292 */
293void
294header()
295{
296	printf(head0);
297	col = strlen(head0)+1;
298	blankfill(SIZCOL);
299	printf(head1);
300}
301
302void
303inform(cf)
304	char *cf;
305{
306	int j;
307	FILE *cfp;
308
309	/*
310	 * There's a chance the control file has gone away
311	 * in the meantime; if this is the case just keep going
312	 */
313	seteuid(euid);
314	if ((cfp = fopen(cf, "r")) == NULL)
315		return;
316	seteuid(uid);
317
318	if (rank < 0)
319		rank = 0;
320	if (remote || garbage || strcmp(cf, current))
321		rank++;
322	j = 0;
323	while (getline(cfp)) {
324		switch (line[0]) {
325		case 'P': /* Was this file specified in the user's list? */
326			if (!inlist(line+1, cf)) {
327				fclose(cfp);
328				return;
329			}
330			if (lflag) {
331				printf("\n%s: ", line+1);
332				col = strlen(line+1) + 2;
333				prank(rank);
334				blankfill(JOBCOL);
335				printf(" [job %s]\n", cf+3);
336			} else {
337				col = 0;
338				prank(rank);
339				blankfill(OWNCOL);
340				printf("%-10s %-3d  ", line+1, atoi(cf+3));
341				col += 16;
342				first = 1;
343			}
344			continue;
345		default: /* some format specifer and file name? */
346			if (line[0] < 'a' || line[0] > 'z')
347				continue;
348			if (j == 0 || strcmp(file, line+1) != 0) {
349				(void) strlcpy(file, line+1, sizeof(file));
350			}
351			j++;
352			continue;
353		case 'N':
354			show(line+1, file, j);
355			file[0] = '\0';
356			j = 0;
357		}
358	}
359	fclose(cfp);
360	if (!lflag) {
361		blankfill(SIZCOL);
362		printf("%ld bytes\n", totsize);
363		totsize = 0;
364	}
365}
366
367int
368inlist(name, file)
369	char *name, *file;
370{
371	int *r, n;
372	char **u, *cp;
373
374	if (users == 0 && requests == 0)
375		return(1);
376	/*
377	 * Check to see if it's in the user list
378	 */
379	for (u = user; u < &user[users]; u++)
380		if (!strcmp(*u, name))
381			return(1);
382	/*
383	 * Check the request list
384	 */
385	for (n = 0, cp = file+3; isdigit(*cp); )
386		n = n * 10 + (*cp++ - '0');
387	for (r = requ; r < &requ[requests]; r++)
388		if (*r == n && !strcmp(cp, from))
389			return(1);
390	return(0);
391}
392
393void
394show(nfile, file, copies)
395	char *nfile, *file;
396	int copies;
397{
398	if (strcmp(nfile, " ") == 0)
399		nfile = "(standard input)";
400	if (lflag)
401		ldump(nfile, file, copies);
402	else
403		dump(nfile, file, copies);
404}
405
406/*
407 * Fill the line with blanks to the specified column
408 */
409void
410blankfill(n)
411	int n;
412{
413	while (col++ < n)
414		putchar(' ');
415}
416
417/*
418 * Give the abbreviated dump of the file names
419 */
420void
421dump(nfile, file, copies)
422	char *nfile, *file;
423	int copies;
424{
425	short n, fill;
426	struct stat lbuf;
427
428	/*
429	 * Print as many files as will fit
430	 *  (leaving room for the total size)
431	 */
432	 fill = first ? 0 : 2;	/* fill space for ``, '' */
433	 if (((n = strlen(nfile)) + col + fill) >= SIZCOL-4) {
434		if (col < SIZCOL) {
435			printf(" ..."), col += 4;
436			blankfill(SIZCOL);
437		}
438	} else {
439		if (first)
440			first = 0;
441		else
442			printf(", ");
443		printf("%s", nfile);
444		col += n+fill;
445	}
446	seteuid(euid);
447	if (*file && !stat(file, &lbuf))
448		totsize += copies * lbuf.st_size;
449	seteuid(uid);
450}
451
452/*
453 * Print the long info about the file
454 */
455void
456ldump(nfile, file, copies)
457	char *nfile, *file;
458	int copies;
459{
460	struct stat lbuf;
461
462	putchar('\t');
463	if (copies > 1)
464		printf("%-2d copies of %-19s", copies, nfile);
465	else
466		printf("%-32s", nfile);
467	if (*file && !stat(file, &lbuf))
468		printf(" %qd bytes", lbuf.st_size);
469	else
470		printf(" ??? bytes");
471	putchar('\n');
472}
473
474/*
475 * Print the job's rank in the queue,
476 *   update col for screen management
477 */
478void
479prank(n)
480	int n;
481{
482	char rline[100];
483	static char *r[] = {
484		"th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th"
485	};
486
487	if (n == 0) {
488		printf("active");
489		col += 6;
490		return;
491	}
492	if ((n/10)%10 == 1)
493		(void)snprintf(rline, sizeof(rline), "%dth", n);
494	else
495		(void)snprintf(rline, sizeof(rline), "%d%s", n, r[n%10]);
496	col += strlen(rline);
497	printf("%s", rline);
498}
499