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