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) 6/6/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 	 * Figure out whether the local machine is the same as the remote
76 	 * machine entry (if it exists).  If not, then ignore the local
77 	 * queue information.
78 	 */
79 	 if (RM != (char *) NULL) {
80 		char name[256];
81 		struct hostent *hp;
82 
83 		/* get the standard network name of the local host */
84 		gethostname(name, sizeof(name));
85 		name[sizeof(name)-1] = '\0';
86 		hp = gethostbyname(name);
87 		if (hp == (struct hostent *) NULL) {
88 		    printf("unable to get network name for local machine %s\n",
89 			name);
90 		    goto localcheck_done;
91 		} else strcpy(name, hp->h_name);
92 
93 		/* get the network standard name of RM */
94 		hp = gethostbyname(RM);
95 		if (hp == (struct hostent *) NULL) {
96 		    printf("unable to get hostname for remote machine %s\n",
97 			RM);
98 		    goto localcheck_done;
99 		}
100 
101 		/* if printer is not on local machine, ignore LP */
102 		if (strcmp(name, hp->h_name) != 0) *LP = '\0';
103 	}
104 localcheck_done:
105 
106 	/*
107 	 * If there is no local printer, then print the queue on
108 	 * the remote machine and then what's in the queue here.
109 	 * Note that a file in transit may not show up in either queue.
110 	 */
111 	if (*LP == '\0') {
112 		register char *cp;
113 		char c;
114 
115 		sendtorem++;
116 		(void) sprintf(line, "%c%s", format + '\3', RP);
117 		cp = line;
118 		for (i = 0; i < requests; i++) {
119 			cp += strlen(cp);
120 			(void) sprintf(cp, " %d", requ[i]);
121 		}
122 		for (i = 0; i < users; i++) {
123 			cp += strlen(cp);
124 			*cp++ = ' ';
125 			strcpy(cp, user[i]);
126 		}
127 		strcat(line, "\n");
128 		fd = getport(RM);
129 		if (fd < 0) {
130 			if (from != host)
131 				printf("%s: ", host);
132 			printf("connection to %s is down\n", RM);
133 		} else {
134 			i = strlen(line);
135 			if (write(fd, line, i) != i)
136 				fatal("Lost connection");
137 			while ((i = read(fd, line, sizeof(line))) > 0)
138 				(void) fwrite(line, 1, i, stdout);
139 			(void) close(fd);
140 		}
141 	}
142 	/*
143 	 * Find all the control files in the spooling directory
144 	 */
145 	if (chdir(SD) < 0)
146 		fatal("cannot chdir to spooling directory");
147 	if ((nitems = getq(&queue)) < 0)
148 		fatal("cannot examine spooling area\n");
149 	if (stat(LO, &statb) >= 0) {
150 		if ((statb.st_mode & 0110) && sendtorem)
151 			printf("\n");
152 		if (statb.st_mode & 0100) {
153 			if (sendtorem)
154 				printf("%s: ", host);
155 			printf("Warning: %s is down: ", printer);
156 			fd = open(ST, O_RDONLY);
157 			if (fd >= 0) {
158 				(void) flock(fd, LOCK_SH);
159 				while ((i = read(fd, line, sizeof(line))) > 0)
160 					(void) fwrite(line, 1, i, stdout);
161 				(void) close(fd);	/* unlocks as well */
162 			} else
163 				putchar('\n');
164 		}
165 		if (statb.st_mode & 010) {
166 			if (sendtorem)
167 				printf("%s: ", host);
168 			printf("Warning: %s queue is turned off\n", printer);
169 		}
170 	}
171 	if (nitems == 0) {
172 		if (!sendtorem)
173 			printf("no entries\n");
174 		return(0);
175 	}
176 	fp = fopen(LO, "r");
177 	if (fp == NULL)
178 		warn();
179 	else {
180 		register char *cp;
181 
182 		/* get daemon pid */
183 		cp = current;
184 		while ((*cp = getc(fp)) != EOF && *cp != '\n')
185 			cp++;
186 		*cp = '\0';
187 		i = atoi(current);
188 		if (i <= 0 || kill(i, 0) < 0)
189 			warn();
190 		else {
191 			/* read current file name */
192 			cp = current;
193 			while ((*cp = getc(fp)) != EOF && *cp != '\n')
194 				cp++;
195 			*cp = '\0';
196 			/*
197 			 * Print the status file.
198 			 */
199 			if (sendtorem)
200 				printf("\n%s: ", host);
201 			fd = open(ST, O_RDONLY);
202 			if (fd >= 0) {
203 				(void) flock(fd, LOCK_SH);
204 				while ((i = read(fd, line, sizeof(line))) > 0)
205 					(void) fwrite(line, 1, i, stdout);
206 				(void) close(fd);	/* unlocks as well */
207 			} else
208 				putchar('\n');
209 		}
210 		(void) fclose(fp);
211 	}
212 	/*
213 	 * Now, examine the control files and print out the jobs to
214 	 * be done for each user.
215 	 */
216 	if (!lflag)
217 		header();
218 	for (i = 0; i < nitems; i++) {
219 		q = queue[i];
220 		inform(q->q_name);
221 		free(q);
222 	}
223 	free(queue);
224 	return(nitems-garbage);
225 }
226 
227 /*
228  * Print a warning message if there is no daemon present.
229  */
230 warn()
231 {
232 	if (sendtorem)
233 		printf("\n%s: ", host);
234 	printf("Warning: no daemon present\n");
235 	current[0] = '\0';
236 }
237 
238 /*
239  * Print the header for the short listing format
240  */
241 header()
242 {
243 	printf(head0);
244 	col = strlen(head0)+1;
245 	blankfill(SIZCOL);
246 	printf(head1);
247 }
248 
249 inform(cf)
250 	char *cf;
251 {
252 	register int j, k;
253 	register char *cp;
254 	FILE *cfp;
255 
256 	/*
257 	 * There's a chance the control file has gone away
258 	 * in the meantime; if this is the case just keep going
259 	 */
260 	if ((cfp = fopen(cf, "r")) == NULL)
261 		return;
262 
263 	if (rank < 0)
264 		rank = 0;
265 	if (sendtorem || garbage || strcmp(cf, current))
266 		rank++;
267 	j = 0;
268 	while (getline(cfp)) {
269 		switch (line[0]) {
270 		case 'P': /* Was this file specified in the user's list? */
271 			if (!inlist(line+1, cf)) {
272 				fclose(cfp);
273 				return;
274 			}
275 			if (lflag) {
276 				printf("\n%s: ", line+1);
277 				col = strlen(line+1) + 2;
278 				prank(rank);
279 				blankfill(JOBCOL);
280 				printf(" [job %s]\n", cf+3);
281 			} else {
282 				col = 0;
283 				prank(rank);
284 				blankfill(OWNCOL);
285 				printf("%-10s %-3d  ", line+1, atoi(cf+3));
286 				col += 16;
287 				first = 1;
288 			}
289 			continue;
290 		default: /* some format specifer and file name? */
291 			if (line[0] < 'a' || line[0] > 'z')
292 				continue;
293 			if (j == 0 || strcmp(file, line+1) != 0)
294 				strcpy(file, line+1);
295 			j++;
296 			continue;
297 		case 'N':
298 			show(line+1, file, j);
299 			file[0] = '\0';
300 			j = 0;
301 		}
302 	}
303 	fclose(cfp);
304 	if (!lflag) {
305 		blankfill(SIZCOL);
306 		printf("%D bytes\n", totsize);
307 		totsize = 0;
308 	}
309 }
310 
311 inlist(name, file)
312 	char *name, *file;
313 {
314 	register int *r, n;
315 	register char **u, *cp;
316 
317 	if (users == 0 && requests == 0)
318 		return(1);
319 	/*
320 	 * Check to see if it's in the user list
321 	 */
322 	for (u = user; u < &user[users]; u++)
323 		if (!strcmp(*u, name))
324 			return(1);
325 	/*
326 	 * Check the request list
327 	 */
328 	for (n = 0, cp = file+3; isdigit(*cp); )
329 		n = n * 10 + (*cp++ - '0');
330 	for (r = requ; r < &requ[requests]; r++)
331 		if (*r == n && !strcmp(cp, from))
332 			return(1);
333 	return(0);
334 }
335 
336 show(nfile, file, copies)
337 	register char *nfile, *file;
338 {
339 	if (strcmp(nfile, " ") == 0)
340 		nfile = "(standard input)";
341 	if (lflag)
342 		ldump(nfile, file, copies);
343 	else
344 		dump(nfile, file, copies);
345 }
346 
347 /*
348  * Fill the line with blanks to the specified column
349  */
350 blankfill(n)
351 	register int n;
352 {
353 	while (col++ < n)
354 		putchar(' ');
355 }
356 
357 /*
358  * Give the abbreviated dump of the file names
359  */
360 dump(nfile, file, copies)
361 	char *nfile, *file;
362 {
363 	register short n, fill;
364 	struct stat lbuf;
365 
366 	/*
367 	 * Print as many files as will fit
368 	 *  (leaving room for the total size)
369 	 */
370 	 fill = first ? 0 : 2;	/* fill space for ``, '' */
371 	 if (((n = strlen(nfile)) + col + fill) >= SIZCOL-4) {
372 		if (col < SIZCOL) {
373 			printf(" ..."), col += 4;
374 			blankfill(SIZCOL);
375 		}
376 	} else {
377 		if (first)
378 			first = 0;
379 		else
380 			printf(", ");
381 		printf("%s", nfile);
382 		col += n+fill;
383 	}
384 	if (*file && !stat(file, &lbuf))
385 		totsize += copies * lbuf.st_size;
386 }
387 
388 /*
389  * Print the long info about the file
390  */
391 ldump(nfile, file, copies)
392 	char *nfile, *file;
393 {
394 	struct stat lbuf;
395 
396 	putchar('\t');
397 	if (copies > 1)
398 		printf("%-2d copies of %-19s", copies, nfile);
399 	else
400 		printf("%-32s", nfile);
401 	if (*file && !stat(file, &lbuf))
402 		printf(" %D bytes", lbuf.st_size);
403 	else
404 		printf(" ??? bytes");
405 	putchar('\n');
406 }
407 
408 /*
409  * Print the job's rank in the queue,
410  *   update col for screen management
411  */
412 prank(n)
413 {
414 	char line[100];
415 	static char *r[] = {
416 		"th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th"
417 	};
418 
419 	if (n == 0) {
420 		printf("active");
421 		col += 6;
422 		return;
423 	}
424 	if ((n/10) == 1)
425 		(void) sprintf(line, "%dth", n);
426 	else
427 		(void) sprintf(line, "%d%s", n, r[n%10]);
428 	col += strlen(line);
429 	printf("%s", line);
430 }
431