displayq.c revision 35998
11556Srgrimes/*
21556Srgrimes * Copyright (c) 1983, 1993
31556Srgrimes *	The Regents of the University of California.  All rights reserved.
41556Srgrimes *
51556Srgrimes * Redistribution and use in source and binary forms, with or without
61556Srgrimes * modification, are permitted provided that the following conditions
71556Srgrimes * are met:
81556Srgrimes * 1. Redistributions of source code must retain the above copyright
91556Srgrimes *    notice, this list of conditions and the following disclaimer.
101556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111556Srgrimes *    notice, this list of conditions and the following disclaimer in the
121556Srgrimes *    documentation and/or other materials provided with the distribution.
131556Srgrimes * 3. All advertising materials mentioning features or use of this software
141556Srgrimes *    must display the following acknowledgement:
151556Srgrimes *	This product includes software developed by the University of
161556Srgrimes *	California, Berkeley and its contributors.
171556Srgrimes * 4. Neither the name of the University nor the names of its contributors
181556Srgrimes *    may be used to endorse or promote products derived from this software
191556Srgrimes *    without specific prior written permission.
201556Srgrimes *
211556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241556Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311556Srgrimes * SUCH DAMAGE.
321556Srgrimes */
331556Srgrimes
341556Srgrimes#ifndef lint
353044Sdg/*
3620425Sstevestatic char sccsid[] = "@(#)displayq.c	8.4 (Berkeley) 4/28/95";
371556Srgrimes*/
381556Srgrimesstatic const char rcsid[] =
391556Srgrimes	"$Id: displayq.c,v 1.13 1997/12/02 20:45:19 wollman Exp $";
4020425Ssteve#endif /* not lint */
411556Srgrimes
421556Srgrimes#include <sys/param.h>
4317987Speter#include <sys/stat.h>
4417987Speter
451556Srgrimes#include <ctype.h>
461556Srgrimes#include <dirent.h>
471556Srgrimes#include <errno.h>
481556Srgrimes#include <fcntl.h>
491556Srgrimes#include <signal.h>
501556Srgrimes#include <stdio.h>
511556Srgrimes#include <stdlib.h>
521556Srgrimes#include <string.h>
531556Srgrimes#define psignal foil_gcc_psignal
541556Srgrimes#define	sys_siglist foil_gcc_siglist
551556Srgrimes#include <unistd.h>
561556Srgrimes#undef psignal
571556Srgrimes#undef sys_siglist
581556Srgrimes
5917987Speter#include "lp.h"
6017987Speter#include "lp.local.h"
611556Srgrimes#include "pathnames.h"
6217987Speter
631556Srgrimes/*
641556Srgrimes * Routines to display the state of the queue.
651556Srgrimes */
661556Srgrimes#define JOBCOL	40		/* column for job # in -l format */
671556Srgrimes#define OWNCOL	7		/* start of Owner column in normal */
681556Srgrimes#define SIZCOL	62		/* start of Size column in normal */
691556Srgrimes
701556Srgrimes/*
7117987Speter * Stuff for handling job specifications
721556Srgrimes */
731556Srgrimesextern uid_t	uid, euid;
741556Srgrimes
751556Srgrimesstatic int	col;		/* column on screen */
761556Srgrimesstatic char	current[40];	/* current file being printed */
771556Srgrimesstatic char	file[132];	/* print file name */
781556Srgrimesstatic int	first;		/* first file in ``files'' column? */
791556Srgrimesstatic int	garbage;	/* # of garbage cf files */
801556Srgrimesstatic int	lflag;		/* long output option */
811556Srgrimesstatic int	rank;		/* order to be printed (-1=none, 0=active) */
821556Srgrimesstatic long	totsize;	/* total print job size in bytes */
831556Srgrimes
841556Srgrimesstatic char	*head0 = "Rank   Owner      Job  Files";
851556Srgrimesstatic char	*head1 = "Total Size\n";
861556Srgrimes
871556Srgrimesstatic void	alarmhandler __P((int));
881556Srgrimesstatic void	warn __P((const struct printer *pp));
891556Srgrimes
901556Srgrimes/*
911556Srgrimes * Display the current state of the queue. Format = 1 if long format.
921556Srgrimes */
931556Srgrimesvoid
941556Srgrimesdisplayq(pp, format)
951556Srgrimes	struct printer *pp;
961556Srgrimes	int format;
971556Srgrimes{
9818018Speter	register struct queue *q;
9918018Speter	register int i, nitems, fd, ret;
1001556Srgrimes	register char	*cp;
1011556Srgrimes	struct queue **queue;
1021556Srgrimes	struct stat statb;
1031556Srgrimes	FILE *fp;
1041556Srgrimes	void (*savealrm)(int);
1051556Srgrimes
1061556Srgrimes	lflag = format;
1071556Srgrimes	totsize = 0;
1081556Srgrimes	rank = -1;
1091556Srgrimes
1101556Srgrimes	if ((cp = checkremote(pp))) {
1111556Srgrimes		printf("Warning: %s\n", cp);
1121556Srgrimes		free(cp);
11317987Speter	}
1141556Srgrimes
1151556Srgrimes	/*
11617987Speter	 * Print out local queue
1171556Srgrimes	 * Find all the control files in the spooling directory
11817987Speter	 */
1191556Srgrimes	seteuid(euid);
1201556Srgrimes	if (chdir(pp->spool_dir) < 0)
1211556Srgrimes		fatal(pp, "cannot chdir to spooling directory: %s",
1221556Srgrimes		      strerror(errno));
12320425Ssteve	seteuid(uid);
1241556Srgrimes	if ((nitems = getq(pp, &queue)) < 0)
12517987Speter		fatal(pp, "cannot examine spooling area\n");
1261556Srgrimes	seteuid(euid);
1271556Srgrimes	ret = stat(pp->lock_file, &statb);
1281556Srgrimes	seteuid(uid);
1291556Srgrimes	if (ret >= 0) {
1301556Srgrimes		if (statb.st_mode & LFM_PRINT_DIS) {
1311556Srgrimes			if (pp->remote)
13220425Ssteve				printf("%s: ", host);
13317987Speter			printf("Warning: %s is down: ", pp->printer);
13417987Speter			seteuid(euid);
1351556Srgrimes			fd = open(pp->status_file, O_RDONLY|O_SHLOCK);
1361556Srgrimes			seteuid(uid);
1371556Srgrimes			if (fd >= 0) {
1381556Srgrimes				while ((i = read(fd, line, sizeof(line))) > 0)
1391556Srgrimes					(void) fwrite(line, 1, i, stdout);
1401556Srgrimes				(void) close(fd);	/* unlocks as well */
1411556Srgrimes			} else
1421556Srgrimes				putchar('\n');
1431556Srgrimes		}
1441556Srgrimes		if (statb.st_mode & LFM_QUEUE_DIS) {
1451556Srgrimes			if (pp->remote)
1461556Srgrimes				printf("%s: ", host);
1471556Srgrimes			printf("Warning: %s queue is turned off\n",
1481556Srgrimes			       pp->printer);
1491556Srgrimes		}
1501556Srgrimes	}
1511556Srgrimes
1521556Srgrimes	if (nitems) {
1531556Srgrimes		seteuid(euid);
15420425Ssteve		fp = fopen(pp->lock_file, "r");
15517987Speter		seteuid(uid);
15617987Speter		if (fp == NULL)
1571556Srgrimes			warn(pp);
15817987Speter		else {
1591556Srgrimes			/* get daemon pid */
1601556Srgrimes			cp = current;
1611556Srgrimes			while ((i = getc(fp)) != EOF && i != '\n')
1621556Srgrimes				*cp++ = i;
16317987Speter			*cp = '\0';
1641556Srgrimes			i = atoi(current);
16517987Speter			if (i <= 0) {
16617987Speter				ret = -1;
16717987Speter			} else {
16817987Speter				seteuid(euid);
16917987Speter				ret = kill(i, 0);
17017987Speter				seteuid(uid);
17117987Speter			}
17217987Speter			if (ret < 0) {
17317987Speter				warn(pp);
17417987Speter			} else {
17517987Speter				/* read current file name */
17617987Speter				cp = current;
17717987Speter				while ((i = getc(fp)) != EOF && i != '\n')
17817987Speter					*cp++ = i;
17917987Speter				*cp = '\0';
18017987Speter				/*
18117987Speter				 * Print the status file.
18217987Speter				 */
18317987Speter				if (pp->remote)
18417987Speter					printf("%s: ", host);
18517987Speter				seteuid(euid);
18617987Speter				fd = open(pp->status_file, O_RDONLY|O_SHLOCK);
18717987Speter				seteuid(uid);
18817987Speter				if (fd >= 0) {
18917987Speter					while ((i = read(fd, line,
19017987Speter							 sizeof(line))) > 0)
19113882Sjoerg						fwrite(line, 1, i, stdout);
19217987Speter					close(fd);	/* unlocks as well */
19317987Speter				} else
19417987Speter					putchar('\n');
1951556Srgrimes			}
19617987Speter			(void) fclose(fp);
19717987Speter		}
19817987Speter		/*
19917987Speter		 * Now, examine the control files and print out the jobs to
20017987Speter		 * be done for each user.
20117987Speter		 */
20217987Speter		if (!lflag)
2031556Srgrimes			header();
2041556Srgrimes		for (i = 0; i < nitems; i++) {
2051556Srgrimes			q = queue[i];
2061556Srgrimes			inform(pp, q->q_name);
2071556Srgrimes			free(q);
2081556Srgrimes		}
2091556Srgrimes		free(queue);
2101556Srgrimes	}
2111556Srgrimes	if (!pp->remote) {
2121556Srgrimes		if (nitems == 0)
2131556Srgrimes			puts("no entries");
2141556Srgrimes		return;
2151556Srgrimes	}
2161556Srgrimes
2171556Srgrimes	/*
2181556Srgrimes	 * Print foreign queue
2191556Srgrimes	 * Note that a file in transit may show up in either queue.
2201556Srgrimes	 */
2211556Srgrimes	if (nitems)
2221556Srgrimes		putchar('\n');
2231556Srgrimes	(void) snprintf(line, sizeof(line), "%c%s", format ? '\4' : '\3',
2241556Srgrimes			pp->remote_queue);
2251556Srgrimes	cp = line;
2261556Srgrimes	for (i = 0; i < requests && cp-line+10 < sizeof(line) - 1; i++) {
2271556Srgrimes		cp += strlen(cp);
2281556Srgrimes		(void) sprintf(cp, " %d", requ[i]);
2291556Srgrimes	}
2301556Srgrimes	for (i = 0; i < users && cp - line + 1 + strlen(user[i]) <
2311556Srgrimes		sizeof(line) - 1; i++) {
2321556Srgrimes		cp += strlen(cp);
2331556Srgrimes		*cp++ = ' ';
2341556Srgrimes		(void) strcpy(cp, user[i]);
2351556Srgrimes	}
2361556Srgrimes	strcat(line, "\n");
2371556Srgrimes	savealrm = signal(SIGALRM, alarmhandler);
2381556Srgrimes	alarm(pp->conn_timeout);
2391556Srgrimes	fd = getport(pp, pp->remote_host, 0);
2401556Srgrimes	alarm(0);
2411556Srgrimes	(void)signal(SIGALRM, savealrm);
2421556Srgrimes	if (fd < 0) {
2431556Srgrimes		if (from != host)
2441556Srgrimes			printf("%s: ", host);
2451556Srgrimes		printf("connection to %s is down\n", pp->remote_host);
2461556Srgrimes	}
2471556Srgrimes	else {
2481556Srgrimes		i = strlen(line);
2491556Srgrimes		if (write(fd, line, i) != i)
2501556Srgrimes			fatal(pp, "Lost connection");
2511556Srgrimes		while ((i = read(fd, line, sizeof(line))) > 0)
25220425Ssteve			(void) fwrite(line, 1, i, stdout);
2531556Srgrimes		(void) close(fd);
2541556Srgrimes	}
2551556Srgrimes}
2561556Srgrimes
2571556Srgrimes/*
2581556Srgrimes * Print a warning message if there is no daemon present.
2591556Srgrimes */
2601556Srgrimesstatic void
2611556Srgrimeswarn(pp)
2621556Srgrimes	const struct printer *pp;
2631556Srgrimes{
2641556Srgrimes	if (pp->remote)
2651556Srgrimes		printf("%s: ", host);
2661556Srgrimes	puts("Warning: no daemon present");
2671556Srgrimes	current[0] = '\0';
2681556Srgrimes}
2691556Srgrimes
2701556Srgrimes/*
2711556Srgrimes * Print the header for the short listing format
2721556Srgrimes */
2731556Srgrimesvoid
2741556Srgrimesheader()
2751556Srgrimes{
2761556Srgrimes	printf(head0);
2771556Srgrimes	col = strlen(head0)+1;
2781556Srgrimes	blankfill(SIZCOL);
2791556Srgrimes	printf(head1);
2801556Srgrimes}
2811556Srgrimes
2821556Srgrimesvoid
2831556Srgrimesinform(pp, cf)
2841556Srgrimes	const struct printer *pp;
28520425Ssteve	char *cf;
2861556Srgrimes{
2871556Srgrimes	register int j;
28817987Speter	FILE *cfp;
28917987Speter
2901556Srgrimes	/*
29120425Ssteve	 * There's a chance the control file has gone away
2921556Srgrimes	 * in the meantime; if this is the case just keep going
2931556Srgrimes	 */
2941556Srgrimes	seteuid(euid);
2951556Srgrimes	if ((cfp = fopen(cf, "r")) == NULL)
2961556Srgrimes		return;
2971556Srgrimes	seteuid(uid);
2981556Srgrimes
2991556Srgrimes	if (rank < 0)
30020425Ssteve		rank = 0;
30120425Ssteve	if (pp->remote || garbage || strcmp(cf, current))
30220425Ssteve		rank++;
30320425Ssteve	j = 0;
30420425Ssteve	while (getline(cfp)) {
30520425Ssteve		switch (line[0]) {
3061556Srgrimes		case 'P': /* Was this file specified in the user's list? */
3071556Srgrimes			if (!inlist(line+1, cf)) {
3081556Srgrimes				fclose(cfp);
3091556Srgrimes				return;
3101556Srgrimes			}
3111556Srgrimes			if (lflag) {
3121556Srgrimes				printf("\n%s: ", line+1);
3131556Srgrimes				col = strlen(line+1) + 2;
3141556Srgrimes				prank(rank);
3151556Srgrimes				blankfill(JOBCOL);
3161556Srgrimes				printf(" [job %s]\n", cf+3);
3171556Srgrimes			} else {
3181556Srgrimes				col = 0;
3191556Srgrimes				prank(rank);
3201556Srgrimes				blankfill(OWNCOL);
3211556Srgrimes				printf("%-10s %-3d  ", line+1, atoi(cf+3));
3221556Srgrimes				col += 16;
3231556Srgrimes				first = 1;
3241556Srgrimes			}
3251556Srgrimes			continue;
3261556Srgrimes		default: /* some format specifer and file name? */
3271556Srgrimes			if (line[0] < 'a' || line[0] > 'z')
3281556Srgrimes				continue;
3291556Srgrimes			if (j == 0 || strcmp(file, line+1) != 0) {
3301556Srgrimes				(void) strncpy(file, line+1, sizeof(file) - 1);
3311556Srgrimes				file[sizeof(file) - 1] = '\0';
3321556Srgrimes			}
3331556Srgrimes			j++;
3341556Srgrimes			continue;
3351556Srgrimes		case 'N':
3361556Srgrimes			show(line+1, file, j);
3371556Srgrimes			file[0] = '\0';
3381556Srgrimes			j = 0;
3391556Srgrimes		}
3401556Srgrimes	}
3411556Srgrimes	fclose(cfp);
3421556Srgrimes	if (!lflag) {
3431556Srgrimes		blankfill(SIZCOL);
3441556Srgrimes		printf("%ld bytes\n", totsize);
3451556Srgrimes		totsize = 0;
3461556Srgrimes	}
3471556Srgrimes}
3481556Srgrimes
3491556Srgrimesint
3501556Srgrimesinlist(name, file)
3511556Srgrimes	char *name, *file;
3521556Srgrimes{
3531556Srgrimes	register int *r, n;
3541556Srgrimes	register char **u, *cp;
3551556Srgrimes
3561556Srgrimes	if (users == 0 && requests == 0)
3571556Srgrimes		return(1);
3581556Srgrimes	/*
3591556Srgrimes	 * Check to see if it's in the user list
3601556Srgrimes	 */
3611556Srgrimes	for (u = user; u < &user[users]; u++)
3621556Srgrimes		if (!strcmp(*u, name))
3631556Srgrimes			return(1);
3641556Srgrimes	/*
3651556Srgrimes	 * Check the request list
3661556Srgrimes	 */
3671556Srgrimes	for (n = 0, cp = file+3; isdigit(*cp); )
3681556Srgrimes		n = n * 10 + (*cp++ - '0');
3691556Srgrimes	for (r = requ; r < &requ[requests]; r++)
3701556Srgrimes		if (*r == n && !strcmp(cp, from))
3711556Srgrimes			return(1);
3721556Srgrimes	return(0);
3731556Srgrimes}
3741556Srgrimes
3751556Srgrimesvoid
3761556Srgrimesshow(nfile, file, copies)
3771556Srgrimes	register char *nfile, *file;
3781556Srgrimes	int copies;
3791556Srgrimes{
3801556Srgrimes	if (strcmp(nfile, " ") == 0)
3811556Srgrimes		nfile = "(standard input)";
3821556Srgrimes	if (lflag)
3831556Srgrimes		ldump(nfile, file, copies);
3841556Srgrimes	else
3851556Srgrimes		dump(nfile, file, copies);
3861556Srgrimes}
3871556Srgrimes
3881556Srgrimes/*
3891556Srgrimes * Fill the line with blanks to the specified column
3901556Srgrimes */
3911556Srgrimesvoid
3921556Srgrimesblankfill(n)
3931556Srgrimes	register int n;
3941556Srgrimes{
3951556Srgrimes	while (col++ < n)
3961556Srgrimes		putchar(' ');
3971556Srgrimes}
3981556Srgrimes
3991556Srgrimes/*
4001556Srgrimes * Give the abbreviated dump of the file names
4011556Srgrimes */
4021556Srgrimesvoid
4031556Srgrimesdump(nfile, file, copies)
4041556Srgrimes	char *nfile, *file;
4051556Srgrimes	int copies;
4061556Srgrimes{
4071556Srgrimes	register short n, fill;
4081556Srgrimes	struct stat lbuf;
4091556Srgrimes
4101556Srgrimes	/*
4111556Srgrimes	 * Print as many files as will fit
4121556Srgrimes	 *  (leaving room for the total size)
4131556Srgrimes	 */
41418018Speter	 fill = first ? 0 : 2;	/* fill space for ``, '' */
4152760Ssef	 if (((n = strlen(nfile)) + col + fill) >= SIZCOL-4) {
4162760Ssef		if (col < SIZCOL) {
4171556Srgrimes			printf(" ..."), col += 4;
4181556Srgrimes			blankfill(SIZCOL);
4191556Srgrimes		}
4201556Srgrimes	} else {
4211556Srgrimes		if (first)
4221556Srgrimes			first = 0;
4231556Srgrimes		else
4241556Srgrimes			printf(", ");
4252760Ssef		printf("%s", nfile);
4261556Srgrimes		col += n+fill;
4271556Srgrimes	}
4282760Ssef	seteuid(euid);
4291556Srgrimes	if (*file && !stat(file, &lbuf))
4301556Srgrimes		totsize += copies * lbuf.st_size;
4311556Srgrimes	seteuid(uid);
43218018Speter}
4331556Srgrimes
4342760Ssef/*
4352760Ssef * Print the long info about the file
4362760Ssef */
4372760Ssefvoid
43818018Speterldump(nfile, file, copies)
4392760Ssef	char *nfile, *file;
4402760Ssef	int copies;
4412760Ssef{
4421556Srgrimes	struct stat lbuf;
4432760Ssef
44418018Speter	putchar('\t');
4451556Srgrimes	if (copies > 1)
4461556Srgrimes		printf("%-2d copies of %-19s", copies, nfile);
4471556Srgrimes	else
4481556Srgrimes		printf("%-32s", nfile);
4491556Srgrimes	if (*file && !stat(file, &lbuf))
4501556Srgrimes		printf(" %qd bytes", (long long) lbuf.st_size);
4511556Srgrimes	else
4521556Srgrimes		printf(" ??? bytes");
4531556Srgrimes	putchar('\n');
4541556Srgrimes}
4551556Srgrimes
4561556Srgrimes/*
4571556Srgrimes * Print the job's rank in the queue,
4581556Srgrimes *   update col for screen management
4591556Srgrimes */
4601556Srgrimesvoid
4611556Srgrimesprank(n)
4621556Srgrimes	int n;
4631556Srgrimes{
46417987Speter	char rline[100];
46517987Speter	static char *r[] = {
46617987Speter		"th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th"
46717987Speter	};
46817987Speter
46917987Speter	if (n == 0) {
47017987Speter		printf("active");
47120425Ssteve		col += 6;
47220425Ssteve		return;
4731556Srgrimes	}
47410399Sjoerg	if ((n/10)%10 == 1)
4751556Srgrimes		(void)snprintf(rline, sizeof(rline), "%dth", n);
47617987Speter	else
4771556Srgrimes		(void)snprintf(rline, sizeof(rline), "%d%s", n, r[n%10]);
47820425Ssteve	col += strlen(rline);
47920425Ssteve	printf("%s", rline);
4801556Srgrimes}
4811556Srgrimes
4821556Srgrimesvoid
4831556Srgrimesalarmhandler(signo)
4841556Srgrimes	int signo;
4851556Srgrimes{
4861556Srgrimes	/* ignored */
4871556Srgrimes}
4881556Srgrimes