displayq.c revision 15648
11553Srgrimes/*
21553Srgrimes * Copyright (c) 1983, 1993
31553Srgrimes *	The Regents of the University of California.  All rights reserved.
41553Srgrimes *
51553Srgrimes * Redistribution and use in source and binary forms, with or without
61553Srgrimes * modification, are permitted provided that the following conditions
71553Srgrimes * are met:
81553Srgrimes * 1. Redistributions of source code must retain the above copyright
91553Srgrimes *    notice, this list of conditions and the following disclaimer.
101553Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111553Srgrimes *    notice, this list of conditions and the following disclaimer in the
121553Srgrimes *    documentation and/or other materials provided with the distribution.
131553Srgrimes * 3. All advertising materials mentioning features or use of this software
141553Srgrimes *    must display the following acknowledgement:
151553Srgrimes *	This product includes software developed by the University of
161553Srgrimes *	California, Berkeley and its contributors.
171553Srgrimes * 4. Neither the name of the University nor the names of its contributors
181553Srgrimes *    may be used to endorse or promote products derived from this software
191553Srgrimes *    without specific prior written permission.
201553Srgrimes *
211553Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221553Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231553Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241553Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251553Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261553Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271553Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281553Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291553Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301553Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311553Srgrimes * SUCH DAMAGE.
321553Srgrimes */
331553Srgrimes
341553Srgrimes#ifndef lint
3515648Sjoergstatic char sccsid[] = "@(#)displayq.c	8.4 (Berkeley) 4/28/95";
361553Srgrimes#endif /* not lint */
371553Srgrimes
381553Srgrimes#include <sys/param.h>
391553Srgrimes#include <sys/stat.h>
4015648Sjoerg#include <sys/file.h>
411553Srgrimes
421553Srgrimes#include <signal.h>
431553Srgrimes#include <fcntl.h>
441553Srgrimes#include <dirent.h>
451553Srgrimes#include <unistd.h>
461553Srgrimes#include <stdio.h>
471553Srgrimes#include <stdlib.h>
481553Srgrimes#include <string.h>
491553Srgrimes#include <ctype.h>
501553Srgrimes#include "lp.h"
511553Srgrimes#include "lp.local.h"
521553Srgrimes#include "pathnames.h"
531553Srgrimes
541553Srgrimes/*
551553Srgrimes * Routines to display the state of the queue.
561553Srgrimes */
571553Srgrimes#define JOBCOL	40		/* column for job # in -l format */
581553Srgrimes#define OWNCOL	7		/* start of Owner column in normal */
591553Srgrimes#define SIZCOL	62		/* start of Size column in normal */
601553Srgrimes
611553Srgrimes/*
621553Srgrimes * Stuff for handling job specifications
631553Srgrimes */
641553Srgrimesextern int	requ[];		/* job number of spool entries */
651553Srgrimesextern int	requests;	/* # of spool requests */
661553Srgrimesextern char    *user[];	        /* users to process */
671553Srgrimesextern int	users;		/* # of users in user array */
681553Srgrimes
691553Srgrimesstatic int	col;		/* column on screen */
701553Srgrimesstatic char	current[40];	/* current file being printed */
711553Srgrimesstatic char	file[132];	/* print file name */
721553Srgrimesstatic int	first;		/* first file in ``files'' column? */
731553Srgrimesstatic int	garbage;	/* # of garbage cf files */
741553Srgrimesstatic int	lflag;		/* long output option */
751553Srgrimesstatic int	rank;		/* order to be printed (-1=none, 0=active) */
761553Srgrimesstatic long	totsize;	/* total print job size in bytes */
771553Srgrimes
781553Srgrimesstatic char	*head0 = "Rank   Owner      Job  Files";
791553Srgrimesstatic char	*head1 = "Total Size\n";
801553Srgrimes
811553Srgrimes/*
821553Srgrimes * Display the current state of the queue. Format = 1 if long format.
831553Srgrimes */
841553Srgrimesvoid
851553Srgrimesdisplayq(format)
861553Srgrimes	int format;
871553Srgrimes{
881553Srgrimes	register struct queue *q;
891553Srgrimes	register int i, nitems, fd;
901553Srgrimes	register char	*cp;
911553Srgrimes	struct queue **queue;
921553Srgrimes	struct stat statb;
931553Srgrimes	FILE *fp;
941553Srgrimes
951553Srgrimes	lflag = format;
961553Srgrimes	totsize = 0;
971553Srgrimes	rank = -1;
981553Srgrimes	if ((i = cgetent(&bp, printcapdb, printer)) == -2)
991553Srgrimes		fatal("can't open printer description file");
1001553Srgrimes	else if (i == -1)
1011553Srgrimes		fatal("unknown printer");
1021553Srgrimes	else if (i == -3)
1031553Srgrimes		fatal("potential reference loop detected in printcap file");
1041553Srgrimes	if (cgetstr(bp, "lp", &LP) < 0)
1051553Srgrimes		LP = _PATH_DEFDEVLP;
1061553Srgrimes	if (cgetstr(bp, "rp", &RP) < 0)
1071553Srgrimes		RP = DEFLP;
1081553Srgrimes	if (cgetstr(bp, "sd", &SD) < 0)
1091553Srgrimes		SD = _PATH_DEFSPOOL;
1101553Srgrimes	if (cgetstr(bp,"lo", &LO) < 0)
1111553Srgrimes		LO = DEFLOCK;
1121553Srgrimes	if (cgetstr(bp, "st", &ST) < 0)
1131553Srgrimes		ST = DEFSTAT;
1141553Srgrimes	cgetstr(bp, "rm", &RM);
1151553Srgrimes	if (cp = checkremote())
1161553Srgrimes		printf("Warning: %s\n", cp);
1171553Srgrimes
1181553Srgrimes	/*
1191553Srgrimes	 * Print out local queue
1201553Srgrimes	 * Find all the control files in the spooling directory
1211553Srgrimes	 */
1221553Srgrimes	if (chdir(SD) < 0)
1231553Srgrimes		fatal("cannot chdir to spooling directory");
1241553Srgrimes	if ((nitems = getq(&queue)) < 0)
1251553Srgrimes		fatal("cannot examine spooling area\n");
1261553Srgrimes	if (stat(LO, &statb) >= 0) {
1271553Srgrimes		if (statb.st_mode & 0100) {
12815648Sjoerg			if (remote)
1291553Srgrimes				printf("%s: ", host);
1301553Srgrimes			printf("Warning: %s is down: ", printer);
1311553Srgrimes			fd = open(ST, O_RDONLY);
1321553Srgrimes			if (fd >= 0) {
1331553Srgrimes				(void) flock(fd, LOCK_SH);
1341553Srgrimes				while ((i = read(fd, line, sizeof(line))) > 0)
1351553Srgrimes					(void) fwrite(line, 1, i, stdout);
1361553Srgrimes				(void) close(fd);	/* unlocks as well */
1371553Srgrimes			} else
1381553Srgrimes				putchar('\n');
1391553Srgrimes		}
1401553Srgrimes		if (statb.st_mode & 010) {
14115648Sjoerg			if (remote)
1421553Srgrimes				printf("%s: ", host);
1431553Srgrimes			printf("Warning: %s queue is turned off\n", printer);
1441553Srgrimes		}
1451553Srgrimes	}
1461553Srgrimes
1471553Srgrimes	if (nitems) {
1481553Srgrimes		fp = fopen(LO, "r");
1491553Srgrimes		if (fp == NULL)
1501553Srgrimes			warn();
1511553Srgrimes		else {
1521553Srgrimes			/* get daemon pid */
1531553Srgrimes			cp = current;
15415648Sjoerg			while ((i = getc(fp)) != EOF && i != '\n')
15515648Sjoerg				*cp++ = i;
1561553Srgrimes			*cp = '\0';
1571553Srgrimes			i = atoi(current);
1581553Srgrimes			if (i <= 0 || kill(i, 0) < 0)
1591553Srgrimes				warn();
1601553Srgrimes			else {
1611553Srgrimes				/* read current file name */
1621553Srgrimes				cp = current;
16315648Sjoerg				while ((i = getc(fp)) != EOF && i != '\n')
16415648Sjoerg					*cp++ = i;
1651553Srgrimes				*cp = '\0';
1661553Srgrimes				/*
1671553Srgrimes				 * Print the status file.
1681553Srgrimes				 */
16915648Sjoerg				if (remote)
1701553Srgrimes					printf("%s: ", host);
1711553Srgrimes				fd = open(ST, O_RDONLY);
1721553Srgrimes				if (fd >= 0) {
1731553Srgrimes					(void) flock(fd, LOCK_SH);
1741553Srgrimes					while ((i = read(fd, line, sizeof(line))) > 0)
1751553Srgrimes						(void) fwrite(line, 1, i, stdout);
1761553Srgrimes					(void) close(fd);	/* unlocks as well */
1771553Srgrimes				} else
1781553Srgrimes					putchar('\n');
1791553Srgrimes			}
1801553Srgrimes			(void) fclose(fp);
1811553Srgrimes		}
1821553Srgrimes		/*
1831553Srgrimes		 * Now, examine the control files and print out the jobs to
1841553Srgrimes		 * be done for each user.
1851553Srgrimes		 */
1861553Srgrimes		if (!lflag)
1871553Srgrimes			header();
1881553Srgrimes		for (i = 0; i < nitems; i++) {
1891553Srgrimes			q = queue[i];
1901553Srgrimes			inform(q->q_name);
1911553Srgrimes			free(q);
1921553Srgrimes		}
1931553Srgrimes		free(queue);
1941553Srgrimes	}
19515648Sjoerg	if (!remote) {
1961553Srgrimes		if (nitems == 0)
1971553Srgrimes			puts("no entries");
1981553Srgrimes		return;
1991553Srgrimes	}
2001553Srgrimes
2011553Srgrimes	/*
2021553Srgrimes	 * Print foreign queue
2031553Srgrimes	 * Note that a file in transit may show up in either queue.
2041553Srgrimes	 */
2051553Srgrimes	if (nitems)
2061553Srgrimes		putchar('\n');
2071553Srgrimes	(void) sprintf(line, "%c%s", format + '\3', RP);
2081553Srgrimes	cp = line;
2091553Srgrimes	for (i = 0; i < requests; i++) {
2101553Srgrimes		cp += strlen(cp);
2111553Srgrimes		(void) sprintf(cp, " %d", requ[i]);
2121553Srgrimes	}
2131553Srgrimes	for (i = 0; i < users; i++) {
2141553Srgrimes		cp += strlen(cp);
2151553Srgrimes		*cp++ = ' ';
2161553Srgrimes		(void) strcpy(cp, user[i]);
2171553Srgrimes	}
2181553Srgrimes	strcat(line, "\n");
21915648Sjoerg	fd = getport(RM, 0);
2201553Srgrimes	if (fd < 0) {
2211553Srgrimes		if (from != host)
2221553Srgrimes			printf("%s: ", host);
2231553Srgrimes		printf("connection to %s is down\n", RM);
2241553Srgrimes	}
2251553Srgrimes	else {
2261553Srgrimes		i = strlen(line);
2271553Srgrimes		if (write(fd, line, i) != i)
2281553Srgrimes			fatal("Lost connection");
2291553Srgrimes		while ((i = read(fd, line, sizeof(line))) > 0)
2301553Srgrimes			(void) fwrite(line, 1, i, stdout);
2311553Srgrimes		(void) close(fd);
2321553Srgrimes	}
2331553Srgrimes}
2341553Srgrimes
2351553Srgrimes/*
2361553Srgrimes * Print a warning message if there is no daemon present.
2371553Srgrimes */
2381553Srgrimesvoid
2391553Srgrimeswarn()
2401553Srgrimes{
24115648Sjoerg	if (remote)
2421553Srgrimes		printf("\n%s: ", host);
2431553Srgrimes	puts("Warning: no daemon present");
2441553Srgrimes	current[0] = '\0';
2451553Srgrimes}
2461553Srgrimes
2471553Srgrimes/*
2481553Srgrimes * Print the header for the short listing format
2491553Srgrimes */
2501553Srgrimesvoid
2511553Srgrimesheader()
2521553Srgrimes{
2531553Srgrimes	printf(head0);
2541553Srgrimes	col = strlen(head0)+1;
2551553Srgrimes	blankfill(SIZCOL);
2561553Srgrimes	printf(head1);
2571553Srgrimes}
2581553Srgrimes
2591553Srgrimesvoid
2601553Srgrimesinform(cf)
2611553Srgrimes	char *cf;
2621553Srgrimes{
2631553Srgrimes	register int j;
2641553Srgrimes	FILE *cfp;
2651553Srgrimes
2661553Srgrimes	/*
2671553Srgrimes	 * There's a chance the control file has gone away
2681553Srgrimes	 * in the meantime; if this is the case just keep going
2691553Srgrimes	 */
2701553Srgrimes	if ((cfp = fopen(cf, "r")) == NULL)
2711553Srgrimes		return;
2721553Srgrimes
2731553Srgrimes	if (rank < 0)
2741553Srgrimes		rank = 0;
27515648Sjoerg	if (remote || garbage || strcmp(cf, current))
2761553Srgrimes		rank++;
2771553Srgrimes	j = 0;
2781553Srgrimes	while (getline(cfp)) {
2791553Srgrimes		switch (line[0]) {
2801553Srgrimes		case 'P': /* Was this file specified in the user's list? */
2811553Srgrimes			if (!inlist(line+1, cf)) {
2821553Srgrimes				fclose(cfp);
2831553Srgrimes				return;
2841553Srgrimes			}
2851553Srgrimes			if (lflag) {
2861553Srgrimes				printf("\n%s: ", line+1);
2871553Srgrimes				col = strlen(line+1) + 2;
2881553Srgrimes				prank(rank);
2891553Srgrimes				blankfill(JOBCOL);
2901553Srgrimes				printf(" [job %s]\n", cf+3);
2911553Srgrimes			} else {
2921553Srgrimes				col = 0;
2931553Srgrimes				prank(rank);
2941553Srgrimes				blankfill(OWNCOL);
2951553Srgrimes				printf("%-10s %-3d  ", line+1, atoi(cf+3));
2961553Srgrimes				col += 16;
2971553Srgrimes				first = 1;
2981553Srgrimes			}
2991553Srgrimes			continue;
3001553Srgrimes		default: /* some format specifer and file name? */
3011553Srgrimes			if (line[0] < 'a' || line[0] > 'z')
3021553Srgrimes				continue;
3031553Srgrimes			if (j == 0 || strcmp(file, line+1) != 0)
3041553Srgrimes				(void) strcpy(file, line+1);
3051553Srgrimes			j++;
3061553Srgrimes			continue;
3071553Srgrimes		case 'N':
3081553Srgrimes			show(line+1, file, j);
3091553Srgrimes			file[0] = '\0';
3101553Srgrimes			j = 0;
3111553Srgrimes		}
3121553Srgrimes	}
3131553Srgrimes	fclose(cfp);
3141553Srgrimes	if (!lflag) {
3151553Srgrimes		blankfill(SIZCOL);
3161553Srgrimes		printf("%ld bytes\n", totsize);
3171553Srgrimes		totsize = 0;
3181553Srgrimes	}
3191553Srgrimes}
3201553Srgrimes
3211553Srgrimesint
3221553Srgrimesinlist(name, file)
3231553Srgrimes	char *name, *file;
3241553Srgrimes{
3251553Srgrimes	register int *r, n;
3261553Srgrimes	register char **u, *cp;
3271553Srgrimes
3281553Srgrimes	if (users == 0 && requests == 0)
3291553Srgrimes		return(1);
3301553Srgrimes	/*
3311553Srgrimes	 * Check to see if it's in the user list
3321553Srgrimes	 */
3331553Srgrimes	for (u = user; u < &user[users]; u++)
3341553Srgrimes		if (!strcmp(*u, name))
3351553Srgrimes			return(1);
3361553Srgrimes	/*
3371553Srgrimes	 * Check the request list
3381553Srgrimes	 */
3391553Srgrimes	for (n = 0, cp = file+3; isdigit(*cp); )
3401553Srgrimes		n = n * 10 + (*cp++ - '0');
3411553Srgrimes	for (r = requ; r < &requ[requests]; r++)
3421553Srgrimes		if (*r == n && !strcmp(cp, from))
3431553Srgrimes			return(1);
3441553Srgrimes	return(0);
3451553Srgrimes}
3461553Srgrimes
3471553Srgrimesvoid
3481553Srgrimesshow(nfile, file, copies)
3491553Srgrimes	register char *nfile, *file;
3501553Srgrimes	int copies;
3511553Srgrimes{
3521553Srgrimes	if (strcmp(nfile, " ") == 0)
3531553Srgrimes		nfile = "(standard input)";
3541553Srgrimes	if (lflag)
3551553Srgrimes		ldump(nfile, file, copies);
3561553Srgrimes	else
3571553Srgrimes		dump(nfile, file, copies);
3581553Srgrimes}
3591553Srgrimes
3601553Srgrimes/*
3611553Srgrimes * Fill the line with blanks to the specified column
3621553Srgrimes */
3631553Srgrimesvoid
3641553Srgrimesblankfill(n)
3651553Srgrimes	register int n;
3661553Srgrimes{
3671553Srgrimes	while (col++ < n)
3681553Srgrimes		putchar(' ');
3691553Srgrimes}
3701553Srgrimes
3711553Srgrimes/*
3721553Srgrimes * Give the abbreviated dump of the file names
3731553Srgrimes */
3741553Srgrimesvoid
3751553Srgrimesdump(nfile, file, copies)
3761553Srgrimes	char *nfile, *file;
3771553Srgrimes	int copies;
3781553Srgrimes{
3791553Srgrimes	register short n, fill;
3801553Srgrimes	struct stat lbuf;
3811553Srgrimes
3821553Srgrimes	/*
3831553Srgrimes	 * Print as many files as will fit
3841553Srgrimes	 *  (leaving room for the total size)
3851553Srgrimes	 */
3861553Srgrimes	 fill = first ? 0 : 2;	/* fill space for ``, '' */
3871553Srgrimes	 if (((n = strlen(nfile)) + col + fill) >= SIZCOL-4) {
3881553Srgrimes		if (col < SIZCOL) {
3891553Srgrimes			printf(" ..."), col += 4;
3901553Srgrimes			blankfill(SIZCOL);
3911553Srgrimes		}
3921553Srgrimes	} else {
3931553Srgrimes		if (first)
3941553Srgrimes			first = 0;
3951553Srgrimes		else
3961553Srgrimes			printf(", ");
3971553Srgrimes		printf("%s", nfile);
3981553Srgrimes		col += n+fill;
3991553Srgrimes	}
4001553Srgrimes	if (*file && !stat(file, &lbuf))
4011553Srgrimes		totsize += copies * lbuf.st_size;
4021553Srgrimes}
4031553Srgrimes
4041553Srgrimes/*
4051553Srgrimes * Print the long info about the file
4061553Srgrimes */
4071553Srgrimesvoid
4081553Srgrimesldump(nfile, file, copies)
4091553Srgrimes	char *nfile, *file;
4101553Srgrimes	int copies;
4111553Srgrimes{
4121553Srgrimes	struct stat lbuf;
4131553Srgrimes
4141553Srgrimes	putchar('\t');
4151553Srgrimes	if (copies > 1)
4161553Srgrimes		printf("%-2d copies of %-19s", copies, nfile);
4171553Srgrimes	else
4181553Srgrimes		printf("%-32s", nfile);
4191553Srgrimes	if (*file && !stat(file, &lbuf))
42015646Sjoerg		printf(" %qd bytes", lbuf.st_size);
4211553Srgrimes	else
4221553Srgrimes		printf(" ??? bytes");
4231553Srgrimes	putchar('\n');
4241553Srgrimes}
4251553Srgrimes
4261553Srgrimes/*
4271553Srgrimes * Print the job's rank in the queue,
4281553Srgrimes *   update col for screen management
4291553Srgrimes */
4301553Srgrimesvoid
4311553Srgrimesprank(n)
4321553Srgrimes	int n;
4331553Srgrimes{
4341553Srgrimes	char rline[100];
4351553Srgrimes	static char *r[] = {
4361553Srgrimes		"th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th"
4371553Srgrimes	};
4381553Srgrimes
4391553Srgrimes	if (n == 0) {
4401553Srgrimes		printf("active");
4411553Srgrimes		col += 6;
4421553Srgrimes		return;
4431553Srgrimes	}
4441553Srgrimes	if ((n/10)%10 == 1)
4451553Srgrimes		(void)snprintf(rline, sizeof(rline), "%dth", n);
4461553Srgrimes	else
4471553Srgrimes		(void)snprintf(rline, sizeof(rline), "%d%s", n, r[n%10]);
4481553Srgrimes	col += strlen(rline);
4491553Srgrimes	printf("%s", rline);
4501553Srgrimes}
451