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