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