displayq.c revision 15638
198944Sobrien/*
298944Sobrien * Copyright (c) 1983, 1993
398944Sobrien *	The Regents of the University of California.  All rights reserved.
498944Sobrien *
598944Sobrien * Redistribution and use in source and binary forms, with or without
698944Sobrien * modification, are permitted provided that the following conditions
798944Sobrien * are met:
898944Sobrien * 1. Redistributions of source code must retain the above copyright
998944Sobrien *    notice, this list of conditions and the following disclaimer.
1098944Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1198944Sobrien *    notice, this list of conditions and the following disclaimer in the
1298944Sobrien *    documentation and/or other materials provided with the distribution.
1398944Sobrien * 3. All advertising materials mentioning features or use of this software
1498944Sobrien *    must display the following acknowledgement:
1598944Sobrien *	This product includes software developed by the University of
1698944Sobrien *	California, Berkeley and its contributors.
1798944Sobrien * 4. Neither the name of the University nor the names of its contributors
1898944Sobrien *    may be used to endorse or promote products derived from this software
1998944Sobrien *    without specific prior written permission.
2098944Sobrien *
2198944Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2298944Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2398944Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2498944Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25130803Smarcel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26130803Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2798944Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28130803Smarcel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2998944Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30130803Smarcel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3198944Sobrien * SUCH DAMAGE.
3298944Sobrien */
3398944Sobrien
34130803Smarcel#ifndef lint
35130803Smarcelstatic char sccsid[] = "@(#)displayq.c	8.4 (Berkeley) 4/28/95";
3698944Sobrien#endif /* not lint */
37130803Smarcel
38130803Smarcel#include <sys/param.h>
3998944Sobrien#include <sys/stat.h>
40130803Smarcel#include <sys/file.h>
4198944Sobrien
42130803Smarcel#include <signal.h>
4398944Sobrien#include <fcntl.h>
44130803Smarcel#include <dirent.h>
45130803Smarcel#include <unistd.h>
4698944Sobrien#include <stdio.h>
47130803Smarcel#include <stdlib.h>
48130803Smarcel#include <string.h>
4998944Sobrien#include <ctype.h>
50130803Smarcel#include "lp.h"
5198944Sobrien#include "lp.local.h"
52130803Smarcel#include "pathnames.h"
53130803Smarcel
5498944Sobrien/*
55130803Smarcel * Routines to display the state of the queue.
5698944Sobrien */
5798944Sobrien#define JOBCOL	40		/* column for job # in -l format */
5898944Sobrien#define OWNCOL	7		/* start of Owner column in normal */
5998944Sobrien#define SIZCOL	62		/* start of Size column in normal */
6098944Sobrien
6198944Sobrien/*
6298944Sobrien * Stuff for handling job specifications
6398944Sobrien */
6498944Sobrienextern int	requ[];		/* job number of spool entries */
6598944Sobrienextern int	requests;	/* # of spool requests */
6698944Sobrienextern char    *user[];	        /* users to process */
6798944Sobrienextern int	users;		/* # of users in user array */
6898944Sobrien
6998944Sobrienstatic int	col;		/* column on screen */
7098944Sobrienstatic char	current[40];	/* current file being printed */
7198944Sobrienstatic char	file[132];	/* print file name */
7298944Sobrienstatic int	first;		/* first file in ``files'' column? */
7398944Sobrienstatic int	garbage;	/* # of garbage cf files */
7498944Sobrienstatic int	lflag;		/* long output option */
7598944Sobrienstatic int	rank;		/* order to be printed (-1=none, 0=active) */
7698944Sobrienstatic long	totsize;	/* total print job size in bytes */
7798944Sobrien
7898944Sobrienstatic char	*head0 = "Rank   Owner      Job  Files";
7998944Sobrienstatic char	*head1 = "Total Size\n";
8098944Sobrien
8198944Sobrien/*
8298944Sobrien * Display the current state of the queue. Format = 1 if long format.
8398944Sobrien */
8498944Sobrienvoid
8598944Sobriendisplayq(format)
8698944Sobrien	int format;
8798944Sobrien{
8898944Sobrien	register struct queue *q;
8998944Sobrien	register int i, nitems, fd;
9098944Sobrien	register char	*cp;
9198944Sobrien	struct queue **queue;
9298944Sobrien	struct stat statb;
9398944Sobrien	FILE *fp;
9498944Sobrien
9598944Sobrien	lflag = format;
96	totsize = 0;
97	rank = -1;
98	if ((i = cgetent(&bp, printcapdb, printer)) == -2)
99		fatal("can't open printer description file");
100	else if (i == -1)
101		fatal("unknown printer");
102	else if (i == -3)
103		fatal("potential reference loop detected in printcap file");
104	if (cgetstr(bp, "lp", &LP) < 0)
105		LP = _PATH_DEFDEVLP;
106	if (cgetstr(bp, "rp", &RP) < 0)
107		RP = DEFLP;
108	if (cgetstr(bp, "sd", &SD) < 0)
109		SD = _PATH_DEFSPOOL;
110	if (cgetstr(bp,"lo", &LO) < 0)
111		LO = DEFLOCK;
112	if (cgetstr(bp, "st", &ST) < 0)
113		ST = DEFSTAT;
114	cgetstr(bp, "rm", &RM);
115	if (cp = checkremote())
116		printf("Warning: %s\n", cp);
117
118	/*
119	 * Print out local queue
120	 * Find all the control files in the spooling directory
121	 */
122	if (chdir(SD) < 0)
123		fatal("cannot chdir to spooling directory");
124	if ((nitems = getq(&queue)) < 0)
125		fatal("cannot examine spooling area\n");
126	if (stat(LO, &statb) >= 0) {
127		if (statb.st_mode & 0100) {
128			if (remote)
129				printf("%s: ", host);
130			printf("Warning: %s is down: ", printer);
131			fd = open(ST, O_RDONLY);
132			if (fd >= 0) {
133				(void) flock(fd, LOCK_SH);
134				while ((i = read(fd, line, sizeof(line))) > 0)
135					(void) fwrite(line, 1, i, stdout);
136				(void) close(fd);	/* unlocks as well */
137			} else
138				putchar('\n');
139		}
140		if (statb.st_mode & 010) {
141			if (remote)
142				printf("%s: ", host);
143			printf("Warning: %s queue is turned off\n", printer);
144		}
145	}
146
147	if (nitems) {
148		fp = fopen(LO, "r");
149		if (fp == NULL)
150			warn();
151		else {
152			/* get daemon pid */
153			cp = current;
154			while ((i = getc(fp)) != EOF && i != '\n')
155				*cp++ = i;
156			*cp = '\0';
157			i = atoi(current);
158			if (i <= 0 || kill(i, 0) < 0)
159				warn();
160			else {
161				/* read current file name */
162				cp = current;
163				while ((i = getc(fp)) != EOF && i != '\n')
164					*cp++ = i;
165				*cp = '\0';
166				/*
167				 * Print the status file.
168				 */
169				if (remote)
170					printf("%s: ", host);
171				fd = open(ST, O_RDONLY);
172				if (fd >= 0) {
173					(void) flock(fd, LOCK_SH);
174					while ((i = read(fd, line, sizeof(line))) > 0)
175						(void) fwrite(line, 1, i, stdout);
176					(void) close(fd);	/* unlocks as well */
177				} else
178					putchar('\n');
179			}
180			(void) fclose(fp);
181		}
182		/*
183		 * Now, examine the control files and print out the jobs to
184		 * be done for each user.
185		 */
186		if (!lflag)
187			header();
188		for (i = 0; i < nitems; i++) {
189			q = queue[i];
190			inform(q->q_name);
191			free(q);
192		}
193		free(queue);
194	}
195	if (!remote) {
196		if (nitems == 0)
197			puts("no entries");
198		return;
199	}
200
201	/*
202	 * Print foreign queue
203	 * Note that a file in transit may show up in either queue.
204	 */
205	if (nitems)
206		putchar('\n');
207	(void) sprintf(line, "%c%s", format + '\3', RP);
208	cp = line;
209	for (i = 0; i < requests; i++) {
210		cp += strlen(cp);
211		(void) sprintf(cp, " %d", requ[i]);
212	}
213	for (i = 0; i < users; i++) {
214		cp += strlen(cp);
215		*cp++ = ' ';
216		(void) strcpy(cp, user[i]);
217	}
218	strcat(line, "\n");
219	fd = getport(RM, 0);
220	if (fd < 0) {
221		if (from != host)
222			printf("%s: ", host);
223		printf("connection to %s is down\n", RM);
224	}
225	else {
226		i = strlen(line);
227		if (write(fd, line, i) != i)
228			fatal("Lost connection");
229		while ((i = read(fd, line, sizeof(line))) > 0)
230			(void) fwrite(line, 1, i, stdout);
231		(void) close(fd);
232	}
233}
234
235/*
236 * Print a warning message if there is no daemon present.
237 */
238void
239warn()
240{
241	if (remote)
242		printf("\n%s: ", host);
243	puts("Warning: no daemon present");
244	current[0] = '\0';
245}
246
247/*
248 * Print the header for the short listing format
249 */
250void
251header()
252{
253	printf(head0);
254	col = strlen(head0)+1;
255	blankfill(SIZCOL);
256	printf(head1);
257}
258
259void
260inform(cf)
261	char *cf;
262{
263	register int j;
264	FILE *cfp;
265
266	/*
267	 * There's a chance the control file has gone away
268	 * in the meantime; if this is the case just keep going
269	 */
270	if ((cfp = fopen(cf, "r")) == NULL)
271		return;
272
273	if (rank < 0)
274		rank = 0;
275	if (remote || garbage || strcmp(cf, current))
276		rank++;
277	j = 0;
278	while (getline(cfp)) {
279		switch (line[0]) {
280		case 'P': /* Was this file specified in the user's list? */
281			if (!inlist(line+1, cf)) {
282				fclose(cfp);
283				return;
284			}
285			if (lflag) {
286				printf("\n%s: ", line+1);
287				col = strlen(line+1) + 2;
288				prank(rank);
289				blankfill(JOBCOL);
290				printf(" [job %s]\n", cf+3);
291			} else {
292				col = 0;
293				prank(rank);
294				blankfill(OWNCOL);
295				printf("%-10s %-3d  ", line+1, atoi(cf+3));
296				col += 16;
297				first = 1;
298			}
299			continue;
300		default: /* some format specifer and file name? */
301			if (line[0] < 'a' || line[0] > 'z')
302				continue;
303			if (j == 0 || strcmp(file, line+1) != 0)
304				(void) strcpy(file, line+1);
305			j++;
306			continue;
307		case 'N':
308			show(line+1, file, j);
309			file[0] = '\0';
310			j = 0;
311		}
312	}
313	fclose(cfp);
314	if (!lflag) {
315		blankfill(SIZCOL);
316		printf("%ld bytes\n", totsize);
317		totsize = 0;
318	}
319}
320
321int
322inlist(name, file)
323	char *name, *file;
324{
325	register int *r, n;
326	register char **u, *cp;
327
328	if (users == 0 && requests == 0)
329		return(1);
330	/*
331	 * Check to see if it's in the user list
332	 */
333	for (u = user; u < &user[users]; u++)
334		if (!strcmp(*u, name))
335			return(1);
336	/*
337	 * Check the request list
338	 */
339	for (n = 0, cp = file+3; isdigit(*cp); )
340		n = n * 10 + (*cp++ - '0');
341	for (r = requ; r < &requ[requests]; r++)
342		if (*r == n && !strcmp(cp, from))
343			return(1);
344	return(0);
345}
346
347void
348show(nfile, file, copies)
349	register char *nfile, *file;
350	int copies;
351{
352	if (strcmp(nfile, " ") == 0)
353		nfile = "(standard input)";
354	if (lflag)
355		ldump(nfile, file, copies);
356	else
357		dump(nfile, file, copies);
358}
359
360/*
361 * Fill the line with blanks to the specified column
362 */
363void
364blankfill(n)
365	register int n;
366{
367	while (col++ < n)
368		putchar(' ');
369}
370
371/*
372 * Give the abbreviated dump of the file names
373 */
374void
375dump(nfile, file, copies)
376	char *nfile, *file;
377	int copies;
378{
379	register short n, fill;
380	struct stat lbuf;
381
382	/*
383	 * Print as many files as will fit
384	 *  (leaving room for the total size)
385	 */
386	 fill = first ? 0 : 2;	/* fill space for ``, '' */
387	 if (((n = strlen(nfile)) + col + fill) >= SIZCOL-4) {
388		if (col < SIZCOL) {
389			printf(" ..."), col += 4;
390			blankfill(SIZCOL);
391		}
392	} else {
393		if (first)
394			first = 0;
395		else
396			printf(", ");
397		printf("%s", nfile);
398		col += n+fill;
399	}
400	if (*file && !stat(file, &lbuf))
401		totsize += copies * lbuf.st_size;
402}
403
404/*
405 * Print the long info about the file
406 */
407void
408ldump(nfile, file, copies)
409	char *nfile, *file;
410	int copies;
411{
412	struct stat lbuf;
413
414	putchar('\t');
415	if (copies > 1)
416		printf("%-2d copies of %-19s", copies, nfile);
417	else
418		printf("%-32s", nfile);
419	if (*file && !stat(file, &lbuf))
420		printf(" %ld bytes", (long)lbuf.st_size);
421	else
422		printf(" ??? bytes");
423	putchar('\n');
424}
425
426/*
427 * Print the job's rank in the queue,
428 *   update col for screen management
429 */
430void
431prank(n)
432	int n;
433{
434	char rline[100];
435	static char *r[] = {
436		"th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th"
437	};
438
439	if (n == 0) {
440		printf("active");
441		col += 6;
442		return;
443	}
444	if ((n/10)%10 == 1)
445		(void)snprintf(rline, sizeof(rline), "%dth", n);
446	else
447		(void)snprintf(rline, sizeof(rline), "%d%s", n, r[n%10]);
448	col += strlen(rline);
449	printf("%s", rline);
450}
451