122427Sdist /*
222427Sdist  * Copyright (c) 1983 Regents of the University of California.
334203Sbostic  * All rights reserved.
434203Sbostic  *
5*56120Selan  * Redistribution and use in source and binary forms, with or without
6*56120Selan  * modification, are permitted provided that the following conditions
7*56120Selan  * are met:
8*56120Selan  * 1. Redistributions of source code must retain the above copyright
9*56120Selan  *    notice, this list of conditions and the following disclaimer.
10*56120Selan  * 2. Redistributions in binary form must reproduce the above copyright
11*56120Selan  *    notice, this list of conditions and the following disclaimer in the
12*56120Selan  *    documentation and/or other materials provided with the distribution.
13*56120Selan  * 3. All advertising materials mentioning features or use of this software
14*56120Selan  *    must display the following acknowledgement:
15*56120Selan  *	This product includes software developed by the University of
16*56120Selan  *	California, Berkeley and its contributors.
17*56120Selan  * 4. Neither the name of the University nor the names of its contributors
18*56120Selan  *    may be used to endorse or promote products derived from this software
19*56120Selan  *    without specific prior written permission.
20*56120Selan  *
21*56120Selan  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22*56120Selan  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23*56120Selan  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24*56120Selan  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25*56120Selan  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26*56120Selan  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27*56120Selan  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28*56120Selan  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29*56120Selan  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30*56120Selan  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31*56120Selan  * SUCH DAMAGE.
3222427Sdist  */
3322427Sdist 
3413952Ssam #ifndef lint
35*56120Selan static char sccsid[] = "@(#)displayq.c	5.16 (Berkeley) 8/31/92";
3634203Sbostic #endif /* not lint */
3713952Ssam 
3855470Sbostic #include <sys/param.h>
3955470Sbostic #include <sys/stat.h>
4012113Sralph 
4155470Sbostic #include <signal.h>
4255470Sbostic #include <fcntl.h>
4355470Sbostic #include <dirent.h>
4455470Sbostic #include <unistd.h>
4555470Sbostic #include <stdio.h>
4655470Sbostic #include <stdlib.h>
4755470Sbostic #include <string.h>
4855470Sbostic #include <ctype.h>
4912113Sralph #include "lp.h"
5055470Sbostic #include "lp.local.h"
5137968Sbostic #include "pathnames.h"
5212113Sralph 
5355470Sbostic /*
5455470Sbostic  * Routines to display the state of the queue.
5555470Sbostic  */
5613170Sralph #define JOBCOL	40		/* column for job # in -l format */
5713170Sralph #define OWNCOL	7		/* start of Owner column in normal */
5813170Sralph #define SIZCOL	62		/* start of Size column in normal */
5912113Sralph 
6012113Sralph /*
6112113Sralph  * Stuff for handling job specifications
6212113Sralph  */
6312113Sralph extern int	requ[];		/* job number of spool entries */
6412113Sralph extern int	requests;	/* # of spool requests */
65*56120Selan extern char    *user[];	        /* users to process */
66*56120Selan extern int	users;		/* # of users in user array */
6712113Sralph 
68*56120Selan static int	col;		/* column on screen */
69*56120Selan static char	current[40];	/* current file being printed */
70*56120Selan static char	file[132];	/* print file name */
71*56120Selan static int	first;		/* first file in ``files'' column? */
72*56120Selan static int	garbage;	/* # of garbage cf files */
73*56120Selan static int	lflag;		/* long output option */
74*56120Selan static int	rank;		/* order to be printed (-1=none, 0=active) */
75*56120Selan static long	totsize;	/* total print job size in bytes */
7612113Sralph 
77*56120Selan static char	*head0 = "Rank   Owner      Job  Files";
78*56120Selan static char	*head1 = "Total Size\n";
7912113Sralph 
8012113Sralph /*
8112113Sralph  * Display the current state of the queue. Format = 1 if long format.
8212113Sralph  */
8355470Sbostic void
8412113Sralph displayq(format)
8512113Sralph 	int format;
8612113Sralph {
8712113Sralph 	register struct queue *q;
8812113Sralph 	register int i, nitems, fd;
8930995Sbostic 	register char	*cp;
9012113Sralph 	struct queue **queue;
9112113Sralph 	struct stat statb;
9212113Sralph 	FILE *fp;
9312113Sralph 
9412113Sralph 	lflag = format;
9512113Sralph 	totsize = 0;
9612113Sralph 	rank = -1;
97*56120Selan 	if ((i = cgetent(&bp, printcapdb, printer)) == -2)
98*56120Selan 		fatal("can't open printer description file");
99*56120Selan 	else if (i == -1)
10012113Sralph 		fatal("unknown printer");
101*56120Selan 	else if (i == -3)
102*56120Selan 		fatal("potential reference loop detected in printcap file");
103*56120Selan 	if (cgetstr(bp, "lp", &LP) < 0)
10437968Sbostic 		LP = _PATH_DEFDEVLP;
105*56120Selan 	if (cgetstr(bp, "rp", &RP) < 0)
10612434Sralph 		RP = DEFLP;
107*56120Selan 	if (cgetstr(bp, "sd", &SD) < 0)
10837968Sbostic 		SD = _PATH_DEFSPOOL;
109*56120Selan 	if (cgetstr(bp,"lo", &LO) < 0)
11012113Sralph 		LO = DEFLOCK;
111*56120Selan 	if (cgetstr(bp, "st", &ST) < 0)
11212113Sralph 		ST = DEFSTAT;
113*56120Selan 	cgetstr(bp, "rm", &RM);
11438736Stef 	if (cp = checkremote())
11538736Stef 		printf("Warning: %s\n", cp);
11612113Sralph 
11712113Sralph 	/*
11830995Sbostic 	 * Print out local queue
11912113Sralph 	 * Find all the control files in the spooling directory
12012113Sralph 	 */
12112113Sralph 	if (chdir(SD) < 0)
12212113Sralph 		fatal("cannot chdir to spooling directory");
12312113Sralph 	if ((nitems = getq(&queue)) < 0)
12412113Sralph 		fatal("cannot examine spooling area\n");
12516205Sralph 	if (stat(LO, &statb) >= 0) {
12616205Sralph 		if (statb.st_mode & 0100) {
12716205Sralph 			if (sendtorem)
12816205Sralph 				printf("%s: ", host);
12916205Sralph 			printf("Warning: %s is down: ", printer);
13016205Sralph 			fd = open(ST, O_RDONLY);
13116205Sralph 			if (fd >= 0) {
13216205Sralph 				(void) flock(fd, LOCK_SH);
13316205Sralph 				while ((i = read(fd, line, sizeof(line))) > 0)
13416205Sralph 					(void) fwrite(line, 1, i, stdout);
13516205Sralph 				(void) close(fd);	/* unlocks as well */
13616205Sralph 			} else
13716205Sralph 				putchar('\n');
13816205Sralph 		}
13916205Sralph 		if (statb.st_mode & 010) {
14016205Sralph 			if (sendtorem)
14116205Sralph 				printf("%s: ", host);
14216205Sralph 			printf("Warning: %s queue is turned off\n", printer);
14316205Sralph 		}
14412740Sralph 	}
14512113Sralph 
14630995Sbostic 	if (nitems) {
14730995Sbostic 		fp = fopen(LO, "r");
14830995Sbostic 		if (fp == NULL)
14913441Sralph 			warn();
15013441Sralph 		else {
15130995Sbostic 			/* get daemon pid */
15213441Sralph 			cp = current;
15313441Sralph 			while ((*cp = getc(fp)) != EOF && *cp != '\n')
15413441Sralph 				cp++;
15513441Sralph 			*cp = '\0';
15630995Sbostic 			i = atoi(current);
15730995Sbostic 			if (i <= 0 || kill(i, 0) < 0)
15830995Sbostic 				warn();
15930995Sbostic 			else {
16030995Sbostic 				/* read current file name */
16130995Sbostic 				cp = current;
16230995Sbostic 				while ((*cp = getc(fp)) != EOF && *cp != '\n')
16330995Sbostic 					cp++;
16430995Sbostic 				*cp = '\0';
16530995Sbostic 				/*
16630995Sbostic 				 * Print the status file.
16730995Sbostic 				 */
16830995Sbostic 				if (sendtorem)
16930995Sbostic 					printf("%s: ", host);
17030995Sbostic 				fd = open(ST, O_RDONLY);
17130995Sbostic 				if (fd >= 0) {
17230995Sbostic 					(void) flock(fd, LOCK_SH);
17330995Sbostic 					while ((i = read(fd, line, sizeof(line))) > 0)
17430995Sbostic 						(void) fwrite(line, 1, i, stdout);
17530995Sbostic 					(void) close(fd);	/* unlocks as well */
17630995Sbostic 				} else
17730995Sbostic 					putchar('\n');
17830995Sbostic 			}
17930995Sbostic 			(void) fclose(fp);
18013441Sralph 		}
18130995Sbostic 		/*
18230995Sbostic 		 * Now, examine the control files and print out the jobs to
18330995Sbostic 		 * be done for each user.
18430995Sbostic 		 */
18530995Sbostic 		if (!lflag)
18630995Sbostic 			header();
18730995Sbostic 		for (i = 0; i < nitems; i++) {
18830995Sbostic 			q = queue[i];
18930995Sbostic 			inform(q->q_name);
19030995Sbostic 			free(q);
19130995Sbostic 		}
19230995Sbostic 		free(queue);
19312113Sralph 	}
19431678Skarels 	if (!sendtorem) {
19531678Skarels 		if (nitems == 0)
19631678Skarels 			puts("no entries");
19730995Sbostic 		return;
19830995Sbostic 	}
19930995Sbostic 
20012113Sralph 	/*
20130995Sbostic 	 * Print foreign queue
20230995Sbostic 	 * Note that a file in transit may show up in either queue.
20312113Sralph 	 */
20430995Sbostic 	if (nitems)
20530995Sbostic 		putchar('\n');
20630995Sbostic 	(void) sprintf(line, "%c%s", format + '\3', RP);
20730995Sbostic 	cp = line;
20830995Sbostic 	for (i = 0; i < requests; i++) {
20930995Sbostic 		cp += strlen(cp);
21030995Sbostic 		(void) sprintf(cp, " %d", requ[i]);
21112113Sralph 	}
21230995Sbostic 	for (i = 0; i < users; i++) {
21330995Sbostic 		cp += strlen(cp);
21430995Sbostic 		*cp++ = ' ';
21530995Sbostic 		(void) strcpy(cp, user[i]);
21630995Sbostic 	}
21730995Sbostic 	strcat(line, "\n");
21830995Sbostic 	fd = getport(RM);
21930995Sbostic 	if (fd < 0) {
22030995Sbostic 		if (from != host)
22130995Sbostic 			printf("%s: ", host);
22230995Sbostic 		printf("connection to %s is down\n", RM);
22330995Sbostic 	}
22430995Sbostic 	else {
22530995Sbostic 		i = strlen(line);
22630995Sbostic 		if (write(fd, line, i) != i)
22730995Sbostic 			fatal("Lost connection");
22830995Sbostic 		while ((i = read(fd, line, sizeof(line))) > 0)
22930995Sbostic 			(void) fwrite(line, 1, i, stdout);
23030995Sbostic 		(void) close(fd);
23130995Sbostic 	}
23212113Sralph }
23312113Sralph 
23412113Sralph /*
23513441Sralph  * Print a warning message if there is no daemon present.
23613441Sralph  */
23755470Sbostic void
23813441Sralph warn()
23913441Sralph {
24013441Sralph 	if (sendtorem)
24113441Sralph 		printf("\n%s: ", host);
24230995Sbostic 	puts("Warning: no daemon present");
24313441Sralph 	current[0] = '\0';
24413441Sralph }
24513441Sralph 
24613441Sralph /*
24712113Sralph  * Print the header for the short listing format
24812113Sralph  */
24955470Sbostic void
25012113Sralph header()
25112113Sralph {
25212113Sralph 	printf(head0);
25312113Sralph 	col = strlen(head0)+1;
25412113Sralph 	blankfill(SIZCOL);
25512113Sralph 	printf(head1);
25612113Sralph }
25712113Sralph 
25855470Sbostic void
25912113Sralph inform(cf)
26012113Sralph 	char *cf;
26112113Sralph {
26255470Sbostic 	register int j;
26312113Sralph 	FILE *cfp;
26412113Sralph 
26512113Sralph 	/*
26612113Sralph 	 * There's a chance the control file has gone away
26712113Sralph 	 * in the meantime; if this is the case just keep going
26812113Sralph 	 */
26912113Sralph 	if ((cfp = fopen(cf, "r")) == NULL)
27012113Sralph 		return;
27112113Sralph 
27212113Sralph 	if (rank < 0)
27312113Sralph 		rank = 0;
27412113Sralph 	if (sendtorem || garbage || strcmp(cf, current))
27512113Sralph 		rank++;
27612113Sralph 	j = 0;
27712113Sralph 	while (getline(cfp)) {
27812113Sralph 		switch (line[0]) {
27912113Sralph 		case 'P': /* Was this file specified in the user's list? */
28012113Sralph 			if (!inlist(line+1, cf)) {
28112113Sralph 				fclose(cfp);
28212113Sralph 				return;
28312113Sralph 			}
28412113Sralph 			if (lflag) {
28512113Sralph 				printf("\n%s: ", line+1);
28612113Sralph 				col = strlen(line+1) + 2;
28712113Sralph 				prank(rank);
28812113Sralph 				blankfill(JOBCOL);
28912113Sralph 				printf(" [job %s]\n", cf+3);
29012113Sralph 			} else {
29112113Sralph 				col = 0;
29212113Sralph 				prank(rank);
29312113Sralph 				blankfill(OWNCOL);
29412113Sralph 				printf("%-10s %-3d  ", line+1, atoi(cf+3));
29512113Sralph 				col += 16;
29612113Sralph 				first = 1;
29712113Sralph 			}
29812113Sralph 			continue;
29912113Sralph 		default: /* some format specifer and file name? */
30012113Sralph 			if (line[0] < 'a' || line[0] > 'z')
30112113Sralph 				continue;
30212113Sralph 			if (j == 0 || strcmp(file, line+1) != 0)
30330995Sbostic 				(void) strcpy(file, line+1);
30412113Sralph 			j++;
30512113Sralph 			continue;
30612113Sralph 		case 'N':
30712113Sralph 			show(line+1, file, j);
30812113Sralph 			file[0] = '\0';
30912113Sralph 			j = 0;
31012113Sralph 		}
31112113Sralph 	}
31212113Sralph 	fclose(cfp);
31312113Sralph 	if (!lflag) {
31412113Sralph 		blankfill(SIZCOL);
31534587Sbostic 		printf("%ld bytes\n", totsize);
31612113Sralph 		totsize = 0;
31712113Sralph 	}
31812113Sralph }
31912113Sralph 
32055470Sbostic int
32112113Sralph inlist(name, file)
32212113Sralph 	char *name, *file;
32312113Sralph {
32412113Sralph 	register int *r, n;
32512113Sralph 	register char **u, *cp;
32612113Sralph 
32712113Sralph 	if (users == 0 && requests == 0)
32812113Sralph 		return(1);
32912113Sralph 	/*
33012113Sralph 	 * Check to see if it's in the user list
33112113Sralph 	 */
33212113Sralph 	for (u = user; u < &user[users]; u++)
33312113Sralph 		if (!strcmp(*u, name))
33412113Sralph 			return(1);
33512113Sralph 	/*
33612113Sralph 	 * Check the request list
33712113Sralph 	 */
33812113Sralph 	for (n = 0, cp = file+3; isdigit(*cp); )
33912113Sralph 		n = n * 10 + (*cp++ - '0');
34012113Sralph 	for (r = requ; r < &requ[requests]; r++)
34112113Sralph 		if (*r == n && !strcmp(cp, from))
34212113Sralph 			return(1);
34312113Sralph 	return(0);
34412113Sralph }
34512113Sralph 
34655470Sbostic void
34712113Sralph show(nfile, file, copies)
34812113Sralph 	register char *nfile, *file;
34955470Sbostic 	int copies;
35012113Sralph {
35112113Sralph 	if (strcmp(nfile, " ") == 0)
35212113Sralph 		nfile = "(standard input)";
35312113Sralph 	if (lflag)
35412113Sralph 		ldump(nfile, file, copies);
35512113Sralph 	else
35612113Sralph 		dump(nfile, file, copies);
35712113Sralph }
35812113Sralph 
35912113Sralph /*
36012113Sralph  * Fill the line with blanks to the specified column
36112113Sralph  */
36255470Sbostic void
36312113Sralph blankfill(n)
36412113Sralph 	register int n;
36512113Sralph {
36612113Sralph 	while (col++ < n)
36712113Sralph 		putchar(' ');
36812113Sralph }
36912113Sralph 
37012113Sralph /*
37112113Sralph  * Give the abbreviated dump of the file names
37212113Sralph  */
37355470Sbostic void
37412113Sralph dump(nfile, file, copies)
37512113Sralph 	char *nfile, *file;
37655470Sbostic 	int copies;
37712113Sralph {
37812113Sralph 	register short n, fill;
37912113Sralph 	struct stat lbuf;
38012113Sralph 
38112113Sralph 	/*
38212113Sralph 	 * Print as many files as will fit
38312113Sralph 	 *  (leaving room for the total size)
38412113Sralph 	 */
38512113Sralph 	 fill = first ? 0 : 2;	/* fill space for ``, '' */
38612113Sralph 	 if (((n = strlen(nfile)) + col + fill) >= SIZCOL-4) {
38712113Sralph 		if (col < SIZCOL) {
38812113Sralph 			printf(" ..."), col += 4;
38912113Sralph 			blankfill(SIZCOL);
39012113Sralph 		}
39112113Sralph 	} else {
39212113Sralph 		if (first)
39312113Sralph 			first = 0;
39412113Sralph 		else
39512113Sralph 			printf(", ");
39612113Sralph 		printf("%s", nfile);
39712113Sralph 		col += n+fill;
39812113Sralph 	}
39912113Sralph 	if (*file && !stat(file, &lbuf))
40012113Sralph 		totsize += copies * lbuf.st_size;
40112113Sralph }
40212113Sralph 
40312113Sralph /*
40412113Sralph  * Print the long info about the file
40512113Sralph  */
40655470Sbostic void
40712113Sralph ldump(nfile, file, copies)
40812113Sralph 	char *nfile, *file;
40955470Sbostic 	int copies;
41012113Sralph {
41112113Sralph 	struct stat lbuf;
41212113Sralph 
41312113Sralph 	putchar('\t');
41412113Sralph 	if (copies > 1)
41512113Sralph 		printf("%-2d copies of %-19s", copies, nfile);
41612113Sralph 	else
41712113Sralph 		printf("%-32s", nfile);
41812113Sralph 	if (*file && !stat(file, &lbuf))
41955470Sbostic 		printf(" %qd bytes", lbuf.st_size);
42012113Sralph 	else
42112113Sralph 		printf(" ??? bytes");
42212113Sralph 	putchar('\n');
42312113Sralph }
42412113Sralph 
42512113Sralph /*
42612113Sralph  * Print the job's rank in the queue,
42712113Sralph  *   update col for screen management
42812113Sralph  */
42955470Sbostic void
43012113Sralph prank(n)
43155470Sbostic 	int n;
43212113Sralph {
43355470Sbostic 	char rline[100];
43412113Sralph 	static char *r[] = {
43512113Sralph 		"th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th"
43612113Sralph 	};
43712113Sralph 
43812113Sralph 	if (n == 0) {
43912113Sralph 		printf("active");
44012113Sralph 		col += 6;
44112113Sralph 		return;
44212113Sralph 	}
44338491Sbostic 	if ((n/10)%10 == 1)
44455470Sbostic 		(void)snprintf(rline, sizeof(rline), "%dth", n);
44512113Sralph 	else
44655470Sbostic 		(void)snprintf(rline, sizeof(rline), "%d%s", n, r[n%10]);
44755470Sbostic 	col += strlen(rline);
44855470Sbostic 	printf("%s", rline);
44912113Sralph }
450