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