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