displayq.c revision 1.9
1/*	$OpenBSD: displayq.c,v 1.9 1998/02/27 11:33:41 deraadt 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 char sccsid[] = "@(#)displayq.c	8.4 (Berkeley) 4/28/95";
39#else
40static char rcsid[] = "$OpenBSD: displayq.c,v 1.9 1998/02/27 11:33:41 deraadt 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[40];	/* current file being printed */
79static char	file[132];	/* 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	register struct queue *q;
97	register int i, nitems, fd, ret, len;
98	register char	*cp;
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			while ((i = getc(fp)) != EOF && i != '\n')
172				*cp++ = i;
173			*cp = '\0';
174			i = atoi(current);
175			if (i <= 0) {
176				ret = -1;
177			} else {
178				seteuid(euid);
179				ret = kill(i, 0);
180				seteuid(uid);
181			}
182			if (ret < 0) {
183				warn();
184			} else {
185				/* read current file name */
186				cp = current;
187				while ((i = getc(fp)) != EOF && i != '\n')
188					*cp++ = i;
189				*cp = '\0';
190				/*
191				 * Print the status file.
192				 */
193				if (remote)
194					printf("%s: ", host);
195				seteuid(euid);
196				fd = open(ST, O_RDONLY);
197				seteuid(uid);
198				if (fd >= 0) {
199					(void) flock(fd, LOCK_SH);
200					while ((i = read(fd, line, sizeof(line))) > 0)
201						(void) fwrite(line, 1, i, stdout);
202					(void) close(fd);	/* unlocks as well */
203				} else
204					putchar('\n');
205			}
206			(void) fclose(fp);
207		}
208		/*
209		 * Now, examine the control files and print out the jobs to
210		 * be done for each user.
211		 */
212		if (!lflag)
213			header();
214		for (i = 0; i < nitems; i++) {
215			q = queue[i];
216			inform(q->q_name);
217			free(q);
218		}
219		free(queue);
220	}
221	if (!remote) {
222		if (nitems == 0)
223			puts("no entries");
224		return;
225	}
226
227	/*
228	 * Print foreign queue
229	 * Note that a file in transit may show up in either queue.
230	 */
231	if (nitems)
232		putchar('\n');
233	(void) snprintf(line, sizeof line, "%c%s", format + '\3', RP);
234	cp = line;
235	cp += strlen(cp);
236	for (i = 0; i < requests && cp-line < sizeof(line) - 1; i++) {
237		len = line + sizeof line - cp;
238		if (snprintf(cp, len, " %d", requ[i]) > len) {
239			cp += strlen(cp);
240			break;
241		}
242		cp += strlen(cp);
243	}
244	for (i = 0; i < users && cp-line < sizeof(line) - 1; i++) {
245		len = line + sizeof line - cp;
246		if (snprintf(cp, len, " %s", user[i]) > len) {
247			cp += strlen(cp);
248			break;
249		}
250	}
251	if (cp-line < sizeof(line) - 1) {
252		strcat(line, "\n");
253	} else {
254		line[sizeof line-2] = '\n';
255	}
256	fd = getport(RM, 0);
257	if (fd < 0) {
258		if (from != host)
259			printf("%s: ", host);
260		printf("connection to %s is down\n", RM);
261	}
262	else {
263		i = strlen(line);
264		if (write(fd, line, i) != i)
265			fatal("Lost connection");
266		while ((i = read(fd, line, sizeof(line))) > 0)
267			(void) fwrite(line, 1, i, stdout);
268		(void) close(fd);
269	}
270}
271
272/*
273 * Print a warning message if there is no daemon present.
274 */
275void
276warn()
277{
278	if (remote)
279		printf("\n%s: ", host);
280	puts("Warning: no daemon present");
281	current[0] = '\0';
282}
283
284/*
285 * Print the header for the short listing format
286 */
287void
288header()
289{
290	printf(head0);
291	col = strlen(head0)+1;
292	blankfill(SIZCOL);
293	printf(head1);
294}
295
296void
297inform(cf)
298	char *cf;
299{
300	register int j;
301	FILE *cfp;
302
303	/*
304	 * There's a chance the control file has gone away
305	 * in the meantime; if this is the case just keep going
306	 */
307	seteuid(euid);
308	if ((cfp = fopen(cf, "r")) == NULL)
309		return;
310	seteuid(uid);
311
312	if (rank < 0)
313		rank = 0;
314	if (remote || garbage || strcmp(cf, current))
315		rank++;
316	j = 0;
317	while (getline(cfp)) {
318		switch (line[0]) {
319		case 'P': /* Was this file specified in the user's list? */
320			if (!inlist(line+1, cf)) {
321				fclose(cfp);
322				return;
323			}
324			if (lflag) {
325				printf("\n%s: ", line+1);
326				col = strlen(line+1) + 2;
327				prank(rank);
328				blankfill(JOBCOL);
329				printf(" [job %s]\n", cf+3);
330			} else {
331				col = 0;
332				prank(rank);
333				blankfill(OWNCOL);
334				printf("%-10s %-3d  ", line+1, atoi(cf+3));
335				col += 16;
336				first = 1;
337			}
338			continue;
339		default: /* some format specifer and file name? */
340			if (line[0] < 'a' || line[0] > 'z')
341				continue;
342			if (j == 0 || strcmp(file, line+1) != 0) {
343				(void) strncpy(file, line+1, sizeof(file) - 1);
344				file[sizeof(file) - 1] = '\0';
345			}
346			j++;
347			continue;
348		case 'N':
349			show(line+1, file, j);
350			file[0] = '\0';
351			j = 0;
352		}
353	}
354	fclose(cfp);
355	if (!lflag) {
356		blankfill(SIZCOL);
357		printf("%ld bytes\n", totsize);
358		totsize = 0;
359	}
360}
361
362int
363inlist(name, file)
364	char *name, *file;
365{
366	register int *r, n;
367	register char **u, *cp;
368
369	if (users == 0 && requests == 0)
370		return(1);
371	/*
372	 * Check to see if it's in the user list
373	 */
374	for (u = user; u < &user[users]; u++)
375		if (!strcmp(*u, name))
376			return(1);
377	/*
378	 * Check the request list
379	 */
380	for (n = 0, cp = file+3; isdigit(*cp); )
381		n = n * 10 + (*cp++ - '0');
382	for (r = requ; r < &requ[requests]; r++)
383		if (*r == n && !strcmp(cp, from))
384			return(1);
385	return(0);
386}
387
388void
389show(nfile, file, copies)
390	register char *nfile, *file;
391	int copies;
392{
393	if (strcmp(nfile, " ") == 0)
394		nfile = "(standard input)";
395	if (lflag)
396		ldump(nfile, file, copies);
397	else
398		dump(nfile, file, copies);
399}
400
401/*
402 * Fill the line with blanks to the specified column
403 */
404void
405blankfill(n)
406	register int n;
407{
408	while (col++ < n)
409		putchar(' ');
410}
411
412/*
413 * Give the abbreviated dump of the file names
414 */
415void
416dump(nfile, file, copies)
417	char *nfile, *file;
418	int copies;
419{
420	register short n, fill;
421	struct stat lbuf;
422
423	/*
424	 * Print as many files as will fit
425	 *  (leaving room for the total size)
426	 */
427	 fill = first ? 0 : 2;	/* fill space for ``, '' */
428	 if (((n = strlen(nfile)) + col + fill) >= SIZCOL-4) {
429		if (col < SIZCOL) {
430			printf(" ..."), col += 4;
431			blankfill(SIZCOL);
432		}
433	} else {
434		if (first)
435			first = 0;
436		else
437			printf(", ");
438		printf("%s", nfile);
439		col += n+fill;
440	}
441	seteuid(euid);
442	if (*file && !stat(file, &lbuf))
443		totsize += copies * lbuf.st_size;
444	seteuid(uid);
445}
446
447/*
448 * Print the long info about the file
449 */
450void
451ldump(nfile, file, copies)
452	char *nfile, *file;
453	int copies;
454{
455	struct stat lbuf;
456
457	putchar('\t');
458	if (copies > 1)
459		printf("%-2d copies of %-19s", copies, nfile);
460	else
461		printf("%-32s", nfile);
462	if (*file && !stat(file, &lbuf))
463		printf(" %qd bytes", lbuf.st_size);
464	else
465		printf(" ??? bytes");
466	putchar('\n');
467}
468
469/*
470 * Print the job's rank in the queue,
471 *   update col for screen management
472 */
473void
474prank(n)
475	int n;
476{
477	char rline[100];
478	static char *r[] = {
479		"th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th"
480	};
481
482	if (n == 0) {
483		printf("active");
484		col += 6;
485		return;
486	}
487	if ((n/10)%10 == 1)
488		(void)snprintf(rline, sizeof(rline), "%dth", n);
489	else
490		(void)snprintf(rline, sizeof(rline), "%d%s", n, r[n%10]);
491	col += strlen(rline);
492	printf("%s", rline);
493}
494