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