1*7027866aSroy /* $NetBSD: displayq.c,v 1.34 2009/07/13 19:05:41 roy Exp $ */
221908ddbSjtc
361f28255Scgd /*
42847add2Scgd * Copyright (c) 1983, 1993
52847add2Scgd * The Regents of the University of California. All rights reserved.
661f28255Scgd *
761f28255Scgd * Redistribution and use in source and binary forms, with or without
861f28255Scgd * modification, are permitted provided that the following conditions
961f28255Scgd * are met:
1061f28255Scgd * 1. Redistributions of source code must retain the above copyright
1161f28255Scgd * notice, this list of conditions and the following disclaimer.
1261f28255Scgd * 2. Redistributions in binary form must reproduce the above copyright
1361f28255Scgd * notice, this list of conditions and the following disclaimer in the
1461f28255Scgd * documentation and/or other materials provided with the distribution.
15326b2259Sagc * 3. Neither the name of the University nor the names of its contributors
1661f28255Scgd * may be used to endorse or promote products derived from this software
1761f28255Scgd * without specific prior written permission.
1861f28255Scgd *
1961f28255Scgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2061f28255Scgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2161f28255Scgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2261f28255Scgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2361f28255Scgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2461f28255Scgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2561f28255Scgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2661f28255Scgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2761f28255Scgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2861f28255Scgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2961f28255Scgd * SUCH DAMAGE.
3061f28255Scgd */
3161f28255Scgd
32fe7ed7ceSmrg #include <sys/cdefs.h>
3361f28255Scgd #ifndef lint
34ad1d6861Smikel #if 0
35e6a91a09Smrg static char sccsid[] = "@(#)displayq.c 8.4 (Berkeley) 4/28/95";
36ad1d6861Smikel #else
37*7027866aSroy __RCSID("$NetBSD: displayq.c,v 1.34 2009/07/13 19:05:41 roy Exp $");
38ad1d6861Smikel #endif
3961f28255Scgd #endif /* not lint */
4061f28255Scgd
412847add2Scgd #include <sys/param.h>
422847add2Scgd #include <sys/stat.h>
43e6a91a09Smrg #include <sys/file.h>
442847add2Scgd
452847add2Scgd #include <signal.h>
462847add2Scgd #include <fcntl.h>
472847add2Scgd #include <dirent.h>
482847add2Scgd #include <unistd.h>
492847add2Scgd #include <stdio.h>
502847add2Scgd #include <stdlib.h>
512847add2Scgd #include <string.h>
522847add2Scgd #include <ctype.h>
532847add2Scgd #include "lp.h"
542847add2Scgd #include "lp.local.h"
552847add2Scgd #include "pathnames.h"
562847add2Scgd
5761f28255Scgd /*
5861f28255Scgd * Routines to display the state of the queue.
5961f28255Scgd */
6061f28255Scgd #define JOBCOL 40 /* column for job # in -l format */
6161f28255Scgd #define OWNCOL 7 /* start of Owner column in normal */
6261f28255Scgd #define SIZCOL 62 /* start of Size column in normal */
6361f28255Scgd
6461f28255Scgd /*
6561f28255Scgd * Stuff for handling job specifications
6661f28255Scgd */
6761f28255Scgd extern int requ[]; /* job number of spool entries */
6861f28255Scgd extern int requests; /* # of spool requests */
692847add2Scgd extern char *user[]; /* users to process */
702847add2Scgd extern int users; /* # of users in user array */
7161f28255Scgd
728e41ca80Shpeyerl extern uid_t uid, euid;
738e41ca80Shpeyerl
742847add2Scgd static int col; /* column on screen */
75c9e786ceSitojun static char current[MAXPATHLEN]; /* current file being printed */
7604723c3fSchristos static char fname[MAXPATHLEN]; /* print file name */
772847add2Scgd static int first; /* first file in ``files'' column? */
782847add2Scgd static int garbage; /* # of garbage cf files */
792847add2Scgd static int lflag; /* long output option */
802847add2Scgd static int rank; /* order to be printed (-1=none, 0=active) */
812847add2Scgd static long totsize; /* total print job size in bytes */
8261f28255Scgd
83d8302e2dSis static const char head0[] = "Rank Owner Job Files";
84d8302e2dSis static const char head1[] = "Total Size\n";
8561f28255Scgd
86895dc72aSwiz static void alarmer(int);
875b6d0e7eSmrg
885b6d0e7eSmrg int wait_time = 300; /* time out after 5 minutes by default */
895b6d0e7eSmrg
9061f28255Scgd /*
9161f28255Scgd * Display the current state of the queue. Format = 1 if long format.
9261f28255Scgd */
932847add2Scgd void
displayq(int format)94895dc72aSwiz displayq(int format)
9561f28255Scgd {
96fe7ed7ceSmrg struct queue *q;
97fe7ed7ceSmrg int i, nitems, fd, ret;
98c6813048Schristos char *cp, *ecp;
9961f28255Scgd struct queue **queue;
10061f28255Scgd struct stat statb;
10161f28255Scgd FILE *fp;
10261f28255Scgd
10361f28255Scgd lflag = format;
10461f28255Scgd totsize = 0;
10561f28255Scgd rank = -1;
10604723c3fSchristos getprintcap(printer);
10761f28255Scgd
10861f28255Scgd /*
10961f28255Scgd * Print out local queue
11061f28255Scgd * Find all the control files in the spooling directory
11161f28255Scgd */
1128e41ca80Shpeyerl seteuid(euid);
11361f28255Scgd if (chdir(SD) < 0)
11461f28255Scgd fatal("cannot chdir to spooling directory");
1158e41ca80Shpeyerl seteuid(uid);
11661f28255Scgd if ((nitems = getq(&queue)) < 0)
11761f28255Scgd fatal("cannot examine spooling area\n");
1188e41ca80Shpeyerl seteuid(euid);
1198e41ca80Shpeyerl ret = stat(LO, &statb);
1208e41ca80Shpeyerl seteuid(uid);
1218e41ca80Shpeyerl if (ret >= 0) {
1225da00734Sitojun if (statb.st_mode & S_IXUSR) {
123e6a91a09Smrg if (remote)
12461f28255Scgd printf("%s: ", host);
12561f28255Scgd printf("Warning: %s is down: ", printer);
1268e41ca80Shpeyerl seteuid(euid);
12761f28255Scgd fd = open(ST, O_RDONLY);
1288e41ca80Shpeyerl seteuid(uid);
12961f28255Scgd if (fd >= 0) {
13061f28255Scgd (void)flock(fd, LOCK_SH);
13161f28255Scgd while ((i = read(fd, line, sizeof(line))) > 0)
13223b9fac0Smrg (void)fwrite(line, 1, (size_t)i, stdout);
13361f28255Scgd (void)close(fd); /* unlocks as well */
13461f28255Scgd } else
13561f28255Scgd putchar('\n');
13661f28255Scgd }
1375da00734Sitojun if (statb.st_mode & S_IXGRP) {
138e6a91a09Smrg if (remote)
13961f28255Scgd printf("%s: ", host);
14061f28255Scgd printf("Warning: %s queue is turned off\n", printer);
14161f28255Scgd }
14261f28255Scgd }
14361f28255Scgd
14461f28255Scgd if (nitems) {
1458e41ca80Shpeyerl seteuid(euid);
14661f28255Scgd fp = fopen(LO, "r");
1478e41ca80Shpeyerl seteuid(uid);
14861f28255Scgd if (fp == NULL)
149fe7ed7ceSmrg nodaemon();
15061f28255Scgd else {
15161f28255Scgd /* get daemon pid */
15261f28255Scgd cp = current;
153c9e786ceSitojun ecp = cp + sizeof(current) - 1;
154c9e786ceSitojun while ((i = getc(fp)) != EOF && i != '\n') {
155c9e786ceSitojun if (cp < ecp)
156fe7ed7ceSmrg *cp++ = i;
157c9e786ceSitojun }
15861f28255Scgd *cp = '\0';
15961f28255Scgd i = atoi(current);
1608e41ca80Shpeyerl if (i <= 0) {
1610e9c04faSpk ret = -1;
1620e9c04faSpk } else {
1638e41ca80Shpeyerl seteuid(euid);
1648e41ca80Shpeyerl ret = kill(i, 0);
1658e41ca80Shpeyerl seteuid(uid);
1668e41ca80Shpeyerl }
1678e41ca80Shpeyerl if (ret < 0) {
168fe7ed7ceSmrg nodaemon();
1690e9c04faSpk } else {
17061f28255Scgd /* read current file name */
17161f28255Scgd cp = current;
172c9e786ceSitojun ecp = cp + sizeof(current) - 1;
173c9e786ceSitojun while ((i = getc(fp)) != EOF && i != '\n') {
174c9e786ceSitojun if (cp < ecp)
175fe7ed7ceSmrg *cp++ = i;
176c9e786ceSitojun }
17761f28255Scgd *cp = '\0';
17861f28255Scgd /*
17961f28255Scgd * Print the status file.
18061f28255Scgd */
181e6a91a09Smrg if (remote)
18261f28255Scgd printf("%s: ", host);
1838e41ca80Shpeyerl seteuid(euid);
18461f28255Scgd fd = open(ST, O_RDONLY);
1858e41ca80Shpeyerl seteuid(uid);
18661f28255Scgd if (fd >= 0) {
18761f28255Scgd (void)flock(fd, LOCK_SH);
18861f28255Scgd while ((i = read(fd, line, sizeof(line))) > 0)
18923b9fac0Smrg (void)fwrite(line, 1, (size_t)i, stdout);
19061f28255Scgd (void)close(fd); /* unlocks as well */
19161f28255Scgd } else
19261f28255Scgd putchar('\n');
19361f28255Scgd }
19461f28255Scgd (void)fclose(fp);
19561f28255Scgd }
19661f28255Scgd /*
19761f28255Scgd * Now, examine the control files and print out the jobs to
19861f28255Scgd * be done for each user.
19961f28255Scgd */
20061f28255Scgd if (!lflag)
20161f28255Scgd header();
20261f28255Scgd for (i = 0; i < nitems; i++) {
20361f28255Scgd q = queue[i];
20461f28255Scgd inform(q->q_name);
20561f28255Scgd }
20661f28255Scgd }
2074a6e5a62Schristos freeq(queue, nitems);
208e6a91a09Smrg if (!remote) {
20961f28255Scgd if (nitems == 0)
21061f28255Scgd puts("no entries");
21161f28255Scgd return;
21261f28255Scgd }
21361f28255Scgd
21461f28255Scgd /*
21561f28255Scgd * Print foreign queue
21661f28255Scgd * Note that a file in transit may show up in either queue.
21761f28255Scgd */
21861f28255Scgd if (nitems)
21961f28255Scgd putchar('\n');
220077acf50Smrg (void)snprintf(line, sizeof(line), "%c%s", format + '\3', RP);
22161f28255Scgd cp = line;
22285da8822Sitojun ecp = line + sizeof(line);
223f5a433a7Slukem for (i = 0;
224f5a433a7Slukem i < requests && (size_t)(cp - line + 11) < sizeof(line) - 2;
225f5a433a7Slukem i++) {
22661f28255Scgd cp += strlen(cp);
22785da8822Sitojun (void)snprintf(cp, ecp - cp, " %d", requ[i]);
22861f28255Scgd }
229f5a433a7Slukem for (i = 0;
230f5a433a7Slukem i < users && cp - line + 1 + strlen(user[i]) < sizeof(line) - 2;
231f5a433a7Slukem i++) {
23261f28255Scgd cp += strlen(cp);
233f5a433a7Slukem if ((size_t)(cp - line) > sizeof(line) - 2)
234077acf50Smrg break;
23561f28255Scgd *cp++ = ' ';
23685da8822Sitojun /* truncation may happen */
23785da8822Sitojun (void)strlcpy(cp, user[i], ecp - cp);
23861f28255Scgd }
23985da8822Sitojun (void)strlcat(line, "\n", sizeof(line));
240c6813048Schristos fd = getport(RM);
24161f28255Scgd if (fd < 0) {
24261f28255Scgd if (from != host)
24361f28255Scgd printf("%s: ", host);
244077acf50Smrg (void)printf("connection to %s is down\n", RM);
24561f28255Scgd }
24661f28255Scgd else {
2475b6d0e7eSmrg struct sigaction osa, nsa;
2485b6d0e7eSmrg
24961f28255Scgd i = strlen(line);
25023b9fac0Smrg if (write(fd, line, (size_t)i) != i)
25161f28255Scgd fatal("Lost connection");
2525b6d0e7eSmrg nsa.sa_handler = alarmer;
2535b6d0e7eSmrg sigemptyset(&nsa.sa_mask);
2545b6d0e7eSmrg sigaddset(&nsa.sa_mask, SIGALRM);
2555b6d0e7eSmrg nsa.sa_flags = 0;
2565b6d0e7eSmrg (void)sigaction(SIGALRM, &nsa, &osa);
2575b6d0e7eSmrg alarm(wait_time);
2585b6d0e7eSmrg while ((i = read(fd, line, sizeof(line))) > 0) {
25923b9fac0Smrg (void)fwrite(line, 1, (size_t)i, stdout);
2605b6d0e7eSmrg alarm(wait_time);
2615b6d0e7eSmrg }
2625b6d0e7eSmrg alarm(0);
2635b6d0e7eSmrg (void)sigaction(SIGALRM, &osa, NULL);
26461f28255Scgd (void)close(fd);
26561f28255Scgd }
26661f28255Scgd }
26761f28255Scgd
2685b6d0e7eSmrg static void
alarmer(int s)269895dc72aSwiz alarmer(int s)
2705b6d0e7eSmrg {
2715b6d0e7eSmrg /* nothing */
2725b6d0e7eSmrg }
2735b6d0e7eSmrg
27461f28255Scgd /*
27561f28255Scgd * Print a warning message if there is no daemon present.
27661f28255Scgd */
2772847add2Scgd void
nodaemon(void)278895dc72aSwiz nodaemon(void)
27961f28255Scgd {
280e6a91a09Smrg if (remote)
28161f28255Scgd printf("\n%s: ", host);
28261f28255Scgd puts("Warning: no daemon present");
28361f28255Scgd current[0] = '\0';
28461f28255Scgd }
28561f28255Scgd
28661f28255Scgd /*
28761f28255Scgd * Print the header for the short listing format
28861f28255Scgd */
2892847add2Scgd void
header(void)290895dc72aSwiz header(void)
29161f28255Scgd {
29261f28255Scgd printf(head0);
29361f28255Scgd col = strlen(head0)+1;
29461f28255Scgd blankfill(SIZCOL);
29561f28255Scgd printf(head1);
29661f28255Scgd }
29761f28255Scgd
2982847add2Scgd void
inform(const char * cf)29904723c3fSchristos inform(const char *cf)
30061f28255Scgd {
301fe7ed7ceSmrg int j;
30261f28255Scgd FILE *cfp;
30361f28255Scgd
30461f28255Scgd /*
30561f28255Scgd * There's a chance the control file has gone away
30661f28255Scgd * in the meantime; if this is the case just keep going
30761f28255Scgd */
3088e41ca80Shpeyerl seteuid(euid);
30961f28255Scgd if ((cfp = fopen(cf, "r")) == NULL)
31061f28255Scgd return;
3118e41ca80Shpeyerl seteuid(uid);
31261f28255Scgd
31361f28255Scgd if (rank < 0)
31461f28255Scgd rank = 0;
315e6a91a09Smrg if (remote || garbage || strcmp(cf, current))
31661f28255Scgd rank++;
31761f28255Scgd j = 0;
318*7027866aSroy while (get_line(cfp)) {
31961f28255Scgd switch (line[0]) {
32061f28255Scgd case 'P': /* Was this file specified in the user's list? */
32161f28255Scgd if (!inlist(line+1, cf)) {
32261f28255Scgd fclose(cfp);
32361f28255Scgd return;
32461f28255Scgd }
32561f28255Scgd if (lflag) {
32661f28255Scgd printf("\n%s: ", line+1);
32761f28255Scgd col = strlen(line+1) + 2;
32861f28255Scgd prank(rank);
32961f28255Scgd blankfill(JOBCOL);
33061f28255Scgd printf(" [job %s]\n", cf+3);
33161f28255Scgd } else {
33261f28255Scgd col = 0;
33361f28255Scgd prank(rank);
33461f28255Scgd blankfill(OWNCOL);
33561f28255Scgd printf("%-10s %-3d ", line+1, atoi(cf+3));
33661f28255Scgd col += 16;
33761f28255Scgd first = 1;
33861f28255Scgd }
33961f28255Scgd continue;
34061f28255Scgd default: /* some format specifer and file name? */
34161f28255Scgd if (line[0] < 'a' || line[0] > 'z')
34261f28255Scgd continue;
34304723c3fSchristos if (j == 0 || strcmp(fname, line+1) != 0) {
34404723c3fSchristos (void)strlcpy(fname, line+1, sizeof(fname));
345fe7ed7ceSmrg }
34661f28255Scgd j++;
34761f28255Scgd continue;
34861f28255Scgd case 'N':
34904723c3fSchristos show(line + 1, fname, j);
35004723c3fSchristos fname[0] = '\0';
35161f28255Scgd j = 0;
35261f28255Scgd }
35361f28255Scgd }
35461f28255Scgd fclose(cfp);
35561f28255Scgd if (!lflag) {
35661f28255Scgd blankfill(SIZCOL);
35761f28255Scgd printf("%ld bytes\n", totsize);
35861f28255Scgd totsize = 0;
35961f28255Scgd }
36061f28255Scgd }
36161f28255Scgd
3622847add2Scgd int
inlist(const char * name,const char * file)36304723c3fSchristos inlist(const char *name, const char *file)
36461f28255Scgd {
365fe7ed7ceSmrg int *r, n;
36604723c3fSchristos char **u;
36704723c3fSchristos const char *cp;
36861f28255Scgd
36961f28255Scgd if (users == 0 && requests == 0)
37061f28255Scgd return(1);
37161f28255Scgd /*
37261f28255Scgd * Check to see if it's in the user list
37361f28255Scgd */
37461f28255Scgd for (u = user; u < &user[users]; u++)
37561f28255Scgd if (!strcmp(*u, name))
37661f28255Scgd return(1);
37761f28255Scgd /*
37861f28255Scgd * Check the request list
37961f28255Scgd */
38075ba9fc7Sdsl for (n = 0, cp = file+3; isdigit((unsigned char)*cp); )
38161f28255Scgd n = n * 10 + (*cp++ - '0');
38261f28255Scgd for (r = requ; r < &requ[requests]; r++)
38361f28255Scgd if (*r == n && !strcmp(cp, from))
38461f28255Scgd return(1);
38561f28255Scgd return(0);
38661f28255Scgd }
38761f28255Scgd
3882847add2Scgd void
show(const char * nfile,const char * file,int copies)38904723c3fSchristos show(const char *nfile, const char *file, int copies)
39061f28255Scgd {
39161f28255Scgd if (strcmp(nfile, " ") == 0)
39261f28255Scgd nfile = "(standard input)";
39361f28255Scgd if (lflag)
39461f28255Scgd ldump(nfile, file, copies);
39561f28255Scgd else
39661f28255Scgd dump(nfile, file, copies);
39761f28255Scgd }
39861f28255Scgd
39961f28255Scgd /*
40061f28255Scgd * Fill the line with blanks to the specified column
40161f28255Scgd */
4022847add2Scgd void
blankfill(int n)403895dc72aSwiz blankfill(int n)
40461f28255Scgd {
40561f28255Scgd while (col++ < n)
40661f28255Scgd putchar(' ');
40761f28255Scgd }
40861f28255Scgd
40961f28255Scgd /*
41061f28255Scgd * Give the abbreviated dump of the file names
41161f28255Scgd */
4122847add2Scgd void
dump(const char * nfile,const char * file,int copies)41304723c3fSchristos dump(const char *nfile, const char *file, int copies)
41461f28255Scgd {
415fe7ed7ceSmrg short n, fill;
41661f28255Scgd struct stat lbuf;
41761f28255Scgd
41861f28255Scgd /*
41961f28255Scgd * Print as many files as will fit
42061f28255Scgd * (leaving room for the total size)
42161f28255Scgd */
42261f28255Scgd fill = first ? 0 : 2; /* fill space for ``, '' */
42361f28255Scgd if (((n = strlen(nfile)) + col + fill) >= SIZCOL-4) {
42461f28255Scgd if (col < SIZCOL) {
42561f28255Scgd printf(" ..."), col += 4;
42661f28255Scgd blankfill(SIZCOL);
42761f28255Scgd }
42861f28255Scgd } else {
42961f28255Scgd if (first)
43061f28255Scgd first = 0;
43161f28255Scgd else
43261f28255Scgd printf(", ");
43361f28255Scgd printf("%s", nfile);
43461f28255Scgd col += n+fill;
43561f28255Scgd }
4368e41ca80Shpeyerl seteuid(euid);
43761f28255Scgd if (*file && !stat(file, &lbuf))
43823b9fac0Smrg totsize += copies * (long)lbuf.st_size;
4398e41ca80Shpeyerl seteuid(uid);
44061f28255Scgd }
44161f28255Scgd
44261f28255Scgd /*
44361f28255Scgd * Print the long info about the file
44461f28255Scgd */
4452847add2Scgd void
ldump(const char * nfile,const char * file,int copies)44604723c3fSchristos ldump(const char *nfile, const char *file, int copies)
44761f28255Scgd {
44861f28255Scgd struct stat lbuf;
44961f28255Scgd
45061f28255Scgd putchar('\t');
45161f28255Scgd if (copies > 1)
45261f28255Scgd printf("%-2d copies of %-19s", copies, nfile);
45361f28255Scgd else
45461f28255Scgd printf("%-32s", nfile);
45561f28255Scgd if (*file && !stat(file, &lbuf))
456c2aa46e7Slukem printf(" %lld bytes", (long long)lbuf.st_size);
45761f28255Scgd else
45861f28255Scgd printf(" ??? bytes");
45961f28255Scgd putchar('\n');
46061f28255Scgd }
46161f28255Scgd
46261f28255Scgd /*
46361f28255Scgd * Print the job's rank in the queue,
46461f28255Scgd * update col for screen management
46561f28255Scgd */
4662847add2Scgd void
prank(int n)467895dc72aSwiz prank(int n)
46861f28255Scgd {
4692847add2Scgd char rline[100];
47004723c3fSchristos static const char *r[] = {
47161f28255Scgd "th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th"
47261f28255Scgd };
47361f28255Scgd
47461f28255Scgd if (n == 0) {
47561f28255Scgd printf("active");
47661f28255Scgd col += 6;
47761f28255Scgd return;
47861f28255Scgd }
47961f28255Scgd if ((n/10)%10 == 1)
4802847add2Scgd (void)snprintf(rline, sizeof(rline), "%dth", n);
48161f28255Scgd else
4822847add2Scgd (void)snprintf(rline, sizeof(rline), "%d%s", n, r[n%10]);
4832847add2Scgd col += strlen(rline);
4842847add2Scgd printf("%s", rline);
48561f28255Scgd }
486