File:  [DragonFly] / src / usr.sbin / lpr / common_source / displayq.c
Revision 1.2: download - view: text, annotated - select for diffs
Tue Jun 17 04:29:56 2003 UTC (11 years, 4 months ago) by dillon
Branches: MAIN
CVS tags: HEAD
Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids.  Most
ids have been removed from !lint sections and moved into comment sections.

    1: /*
    2:  * Copyright (c) 1983, 1993
    3:  *	The Regents of the University of California.  All rights reserved.
    4:  *
    5:  * Redistribution and use in source and binary forms, with or without
    6:  * modification, are permitted provided that the following conditions
    7:  * are met:
    8:  * 1. Redistributions of source code must retain the above copyright
    9:  *    notice, this list of conditions and the following disclaimer.
   10:  * 2. Redistributions in binary form must reproduce the above copyright
   11:  *    notice, this list of conditions and the following disclaimer in the
   12:  *    documentation and/or other materials provided with the distribution.
   13:  * 3. All advertising materials mentioning features or use of this software
   14:  *    must display the following acknowledgement:
   15:  *	This product includes software developed by the University of
   16:  *	California, Berkeley and its contributors.
   17:  * 4. Neither the name of the University nor the names of its contributors
   18:  *    may be used to endorse or promote products derived from this software
   19:  *    without specific prior written permission.
   20:  *
   21:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   22:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   23:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   24:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   25:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   26:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   27:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   28:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   29:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   30:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   31:  * SUCH DAMAGE.
   32:  *
   33:  * @(#)displayq.c	8.4 (Berkeley) 4/28/95
   34:  * $FreeBSD: src/usr.sbin/lpr/common_source/displayq.c,v 1.15.2.8 2001/08/30 09:27:41 kris Exp $
   35:  * $DragonFly: src/usr.sbin/lpr/common_source/displayq.c,v 1.2 2003/06/17 04:29:56 dillon Exp $
   36:  */
   37: 
   38: #include <sys/param.h>
   39: #include <sys/stat.h>
   40: 
   41: #include <ctype.h>
   42: #include <dirent.h>
   43: #include <errno.h>
   44: #include <fcntl.h>
   45: #include <signal.h>
   46: #include <stdio.h>
   47: #include <stdlib.h>
   48: #include <string.h>
   49: #define psignal foil_gcc_psignal
   50: #define	sys_siglist foil_gcc_siglist
   51: #include <unistd.h>
   52: #undef psignal
   53: #undef sys_siglist
   54: 
   55: #include "lp.h"
   56: #include "lp.local.h"
   57: #include "pathnames.h"
   58: 
   59: /*
   60:  * Routines to display the state of the queue.
   61:  */
   62: #define JOBCOL	40		/* column for job # in -l format */
   63: #define OWNCOL	7		/* start of Owner column in normal */
   64: #define SIZCOL	62		/* start of Size column in normal */
   65: 
   66: /*
   67:  * Stuff for handling job specifications
   68:  */
   69: extern uid_t	uid, euid;
   70: 
   71: static int	col;		/* column on screen */
   72: static char	current[MAXNAMLEN+1];	/* current file being printed */
   73: static char	file[MAXNAMLEN+1];	/* print file name */
   74: static int	first;		/* first file in ``files'' column? */
   75: static int	garbage;	/* # of garbage cf files */
   76: static int	lflag;		/* long output option */
   77: static int	rank;		/* order to be printed (-1=none, 0=active) */
   78: static long	totsize;	/* total print job size in bytes */
   79: 
   80: static const char  *head0 = "Rank   Owner      Job  Files";
   81: static const char  *head1 = "Total Size\n";
   82: 
   83: static void	alarmhandler(int _signo);
   84: static void	warn(const struct printer *_pp);
   85: 
   86: /*
   87:  * Display the current state of the queue. Format = 1 if long format.
   88:  */
   89: void
   90: displayq(struct printer *pp, int format)
   91: {
   92: 	register struct jobqueue *q;
   93: 	register int i, nitems, fd, ret;
   94: 	char *cp, *endp;
   95: 	struct jobqueue **queue;
   96: 	struct stat statb;
   97: 	FILE *fp;
   98: 	void (*savealrm)(int);
   99: 
  100: 	lflag = format;
  101: 	totsize = 0;
  102: 	rank = -1;
  103: 
  104: 	if ((cp = checkremote(pp))) {
  105: 		printf("Warning: %s\n", cp);
  106: 		free(cp);
  107: 	}
  108: 
  109: 	/*
  110: 	 * Print out local queue
  111: 	 * Find all the control files in the spooling directory
  112: 	 */
  113: 	seteuid(euid);
  114: 	if (chdir(pp->spool_dir) < 0)
  115: 		fatal(pp, "cannot chdir to spooling directory: %s",
  116: 		      strerror(errno));
  117: 	seteuid(uid);
  118: 	if ((nitems = getq(pp, &queue)) < 0)
  119: 		fatal(pp, "cannot examine spooling area\n");
  120: 	seteuid(euid);
  121: 	ret = stat(pp->lock_file, &statb);
  122: 	seteuid(uid);
  123: 	if (ret >= 0) {
  124: 		if (statb.st_mode & LFM_PRINT_DIS) {
  125: 			if (pp->remote)
  126: 				printf("%s: ", local_host);
  127: 			printf("Warning: %s is down: ", pp->printer);
  128: 			seteuid(euid);
  129: 			fd = open(pp->status_file, O_RDONLY|O_SHLOCK);
  130: 			seteuid(uid);
  131: 			if (fd >= 0) {
  132: 				while ((i = read(fd, line, sizeof(line))) > 0)
  133: 					(void) fwrite(line, 1, i, stdout);
  134: 				(void) close(fd);	/* unlocks as well */
  135: 			} else
  136: 				putchar('\n');
  137: 		}
  138: 		if (statb.st_mode & LFM_QUEUE_DIS) {
  139: 			if (pp->remote)
  140: 				printf("%s: ", local_host);
  141: 			printf("Warning: %s queue is turned off\n", 
  142: 			       pp->printer);
  143: 		}
  144: 	}
  145: 
  146: 	if (nitems) {
  147: 		seteuid(euid);
  148: 		fp = fopen(pp->lock_file, "r");
  149: 		seteuid(uid);
  150: 		if (fp == NULL)
  151: 			warn(pp);
  152: 		else {
  153: 			/* get daemon pid */
  154: 			cp = current;
  155: 			endp = cp + sizeof(current) - 1;
  156: 			while ((i = getc(fp)) != EOF && i != '\n') {
  157: 				if (cp < endp)
  158: 					*cp++ = i;
  159: 			}
  160: 			*cp = '\0';
  161: 			i = atoi(current);
  162: 			if (i <= 0) {
  163: 				ret = -1;
  164: 			} else {
  165: 				seteuid(euid);
  166: 				ret = kill(i, 0);
  167: 				seteuid(uid);
  168: 			}
  169: 			if (ret < 0) {
  170: 				warn(pp);
  171: 			} else {
  172: 				/* read current file name */
  173: 				cp = current;
  174: 				endp = cp + sizeof(current) - 1;
  175: 				while ((i = getc(fp)) != EOF && i != '\n') {
  176: 					if (cp < endp)
  177: 						*cp++ = i;
  178: 				}
  179: 				*cp = '\0';
  180: 				/*
  181: 				 * Print the status file.
  182: 				 */
  183: 				if (pp->remote)
  184: 					printf("%s: ", local_host);
  185: 				seteuid(euid);
  186: 				fd = open(pp->status_file, O_RDONLY|O_SHLOCK);
  187: 				seteuid(uid);
  188: 				if (fd >= 0) {
  189: 					while ((i = read(fd, line,
  190: 							 sizeof(line))) > 0)
  191: 						fwrite(line, 1, i, stdout);
  192: 					close(fd);	/* unlocks as well */
  193: 				} else
  194: 					putchar('\n');
  195: 			}
  196: 			(void) fclose(fp);
  197: 		}
  198: 		/*
  199: 		 * Now, examine the control files and print out the jobs to
  200: 		 * be done for each user.
  201: 		 */
  202: 		if (!lflag)
  203: 			header();
  204: 		for (i = 0; i < nitems; i++) {
  205: 			q = queue[i];
  206: 			inform(pp, q->job_cfname);
  207: 			free(q);
  208: 		}
  209: 		free(queue);
  210: 	}
  211: 	if (!pp->remote) {
  212: 		if (nitems == 0)
  213: 			puts("no entries");
  214: 		return;
  215: 	}
  216: 
  217: 	/*
  218: 	 * Print foreign queue
  219: 	 * Note that a file in transit may show up in either queue.
  220: 	 */
  221: 	if (nitems)
  222: 		putchar('\n');
  223: 	(void) snprintf(line, sizeof(line), "%c%s", format ? '\4' : '\3',
  224: 			pp->remote_queue);
  225: 	cp = line;
  226: 	for (i = 0; i < requests && cp-line+10 < sizeof(line) - 1; i++) {
  227: 		cp += strlen(cp);
  228: 		(void) sprintf(cp, " %d", requ[i]);
  229: 	}
  230: 	for (i = 0; i < users && cp - line + 1 + strlen(user[i]) < 
  231: 		sizeof(line) - 1; i++) {
  232: 		cp += strlen(cp);
  233: 		*cp++ = ' ';
  234: 		(void) strcpy(cp, user[i]);
  235: 	}
  236: 	strcat(line, "\n");
  237: 	savealrm = signal(SIGALRM, alarmhandler);
  238: 	alarm(pp->conn_timeout);
  239: 	fd = getport(pp, pp->remote_host, 0);
  240: 	alarm(0);
  241: 	(void)signal(SIGALRM, savealrm);
  242: 	if (fd < 0) {
  243: 		if (from_host != local_host)
  244: 			printf("%s: ", local_host);
  245: 		printf("connection to %s is down\n", pp->remote_host);
  246: 	}
  247: 	else {
  248: 		i = strlen(line);
  249: 		if (write(fd, line, i) != i)
  250: 			fatal(pp, "Lost connection");
  251: 		while ((i = read(fd, line, sizeof(line))) > 0)
  252: 			(void) fwrite(line, 1, i, stdout);
  253: 		(void) close(fd);
  254: 	}
  255: }
  256: 
  257: /*
  258:  * Print a warning message if there is no daemon present.
  259:  */
  260: static void
  261: warn(const struct printer *pp)
  262: {
  263: 	if (pp->remote)
  264: 		printf("%s: ", local_host);
  265: 	puts("Warning: no daemon present");
  266: 	current[0] = '\0';
  267: }
  268: 
  269: /*
  270:  * Print the header for the short listing format
  271:  */
  272: void
  273: header(void)
  274: {
  275: 	printf("%s", head0);
  276: 	col = strlen(head0)+1;
  277: 	blankfill(SIZCOL);
  278: 	printf("%s", head1);
  279: }
  280: 
  281: void
  282: inform(const struct printer *pp, char *cf)
  283: {
  284: 	register int copycnt;
  285: 	char	 savedname[MAXPATHLEN+1];
  286: 	FILE	*cfp;
  287: 
  288: 	/*
  289: 	 * There's a chance the control file has gone away
  290: 	 * in the meantime; if this is the case just keep going
  291: 	 */
  292: 	seteuid(euid);
  293: 	if ((cfp = fopen(cf, "r")) == NULL)
  294: 		return;
  295: 	seteuid(uid);
  296: 
  297: 	if (rank < 0)
  298: 		rank = 0;
  299: 	if (pp->remote || garbage || strcmp(cf, current))
  300: 		rank++;
  301: 
  302: 	/*
  303: 	 * The cf-file may include commands to print more than one datafile
  304: 	 * from the user.  For each datafile, the cf-file contains at least
  305: 	 * one line which starts with some format-specifier ('a'-'z'), and
  306: 	 * a second line ('N'ame) which indicates the original name the user
  307: 	 * specified for that file.  There can be multiple format-spec lines
  308: 	 * for a single Name-line, if the user requested multiple copies of
  309: 	 * that file.  Standard lpr puts the format-spec line(s) before the
  310: 	 * Name-line, while lprNG puts the Name-line before the format-spec
  311: 	 * line(s).  This section needs to handle the lines in either order.
  312: 	 */
  313: 	copycnt = 0;
  314: 	file[0] = '\0';
  315: 	savedname[0] = '\0';
  316: 	while (getline(cfp)) {
  317: 		switch (line[0]) {
  318: 		case 'P': /* Was this file specified in the user's list? */
  319: 			if (!inlist(line+1, cf)) {
  320: 				fclose(cfp);
  321: 				return;
  322: 			}
  323: 			if (lflag) {
  324: 				printf("\n%s: ", line+1);
  325: 				col = strlen(line+1) + 2;
  326: 				prank(rank);
  327: 				blankfill(JOBCOL);
  328: 				printf(" [job %s]\n", cf+3);
  329: 			} else {
  330: 				col = 0;
  331: 				prank(rank);
  332: 				blankfill(OWNCOL);
  333: 				printf("%-10s %-3d  ", line+1, atoi(cf+3));
  334: 				col += 16;
  335: 				first = 1;
  336: 			}
  337: 			continue;
  338: 		default: /* some format specifer and file name? */
  339: 			if (line[0] < 'a' || line[0] > 'z')
  340: 				break;
  341: 			if (copycnt == 0 || strcmp(file, line+1) != 0) {
  342: 				strlcpy(file, line + 1, sizeof(file));
  343: 			}
  344: 			copycnt++;
  345: 			/*
  346: 			 * deliberately 'continue' to another getline(), so
  347: 			 * all format-spec lines for this datafile are read
  348: 			 * in and counted before calling show()
  349: 			 */
  350: 			continue;
  351: 		case 'N':
  352: 			strlcpy(savedname, line + 1, sizeof(savedname));
  353: 			break;
  354: 		}
  355: 		if ((file[0] != '\0') && (savedname[0] != '\0')) {
  356: 			show(savedname, file, copycnt);
  357: 			copycnt = 0;
  358: 			file[0] = '\0';
  359: 			savedname[0] = '\0';
  360: 		}
  361: 	}
  362: 	fclose(cfp);
  363: 	/* check for a file which hasn't been shown yet */
  364: 	if (file[0] != '\0') {
  365: 		if (savedname[0] == '\0') {
  366: 			/* a safeguard in case the N-ame line is missing */
  367: 			strlcpy(savedname, file, sizeof(savedname));
  368: 		}
  369: 		show(savedname, file, copycnt);
  370: 	}
  371: 	if (!lflag) {
  372: 		blankfill(SIZCOL);
  373: 		printf("%ld bytes\n", totsize);
  374: 		totsize = 0;
  375: 	}
  376: }
  377: 
  378: int
  379: inlist(char *uname, char *cfile)
  380: {
  381: 	register int *r, n;
  382: 	register char **u, *cp;
  383: 
  384: 	if (users == 0 && requests == 0)
  385: 		return(1);
  386: 	/*
  387: 	 * Check to see if it's in the user list
  388: 	 */
  389: 	for (u = user; u < &user[users]; u++)
  390: 		if (!strcmp(*u, uname))
  391: 			return(1);
  392: 	/*
  393: 	 * Check the request list
  394: 	 */
  395: 	for (n = 0, cp = cfile+3; isdigit(*cp); )
  396: 		n = n * 10 + (*cp++ - '0');
  397: 	for (r = requ; r < &requ[requests]; r++)
  398: 		if (*r == n && !strcmp(cp, from_host))
  399: 			return(1);
  400: 	return(0);
  401: }
  402: 
  403: void
  404: show(const char *nfile, const char *datafile, int copies)
  405: {
  406: 	if (strcmp(nfile, " ") == 0)
  407: 		nfile = "(standard input)";
  408: 	if (lflag)
  409: 		ldump(nfile, datafile, copies);
  410: 	else
  411: 		dump(nfile, datafile, copies);
  412: }
  413: 
  414: /*
  415:  * Fill the line with blanks to the specified column
  416:  */
  417: void
  418: blankfill(int tocol)
  419: {
  420: 	while (col++ < tocol)
  421: 		putchar(' ');
  422: }
  423: 
  424: /*
  425:  * Give the abbreviated dump of the file names
  426:  */
  427: void
  428: dump(const char *nfile, const char *datafile, int copies)
  429: {
  430: 	struct stat lbuf;
  431: 	const char etctmpl[] = ", ...";
  432: 	char	 etc[sizeof(etctmpl)];
  433: 	char	*lastsep;
  434: 	short	 fill, nlen;
  435: 	short	 rem, remetc;
  436: 
  437: 	/*
  438: 	 * Print as many filenames as will fit
  439: 	 *      (leaving room for the 'total size' field)
  440: 	 */
  441: 	fill = first ? 0 : 2;	/* fill space for ``, '' */
  442: 	nlen = strlen(nfile);
  443: 	rem = SIZCOL - 1 - col;
  444: 	if (nlen + fill > rem) {
  445: 		if (first) {
  446: 			/* print the right-most part of the name */
  447: 			printf("...%s ", &nfile[3+nlen-rem]);
  448: 			col = SIZCOL;
  449: 		} else if (rem > 0) {
  450: 			/* fit as much of the etc-string as we can */
  451: 			remetc = rem;
  452: 			if (rem > strlen(etctmpl))
  453: 				remetc = strlen(etctmpl);
  454: 			etc[0] = '\0';
  455: 			strncat(etc, etctmpl, remetc);
  456: 			printf("%s", etc);
  457: 			col += remetc;
  458: 			rem -= remetc;
  459: 			/* room for the last segment of this filename? */
  460: 			lastsep = strrchr(nfile, '/');
  461: 			if ((lastsep != NULL) && (rem > strlen(lastsep))) {
  462: 				/* print the right-most part of this name */
  463: 				printf("%s", lastsep);
  464: 				col += strlen(lastsep);
  465: 			} else {
  466: 				/* do not pack any more names in here */
  467: 				blankfill(SIZCOL);
  468: 			}
  469: 		}
  470: 	} else {
  471: 		if (!first)
  472: 			printf(", ");
  473: 		printf("%s", nfile);
  474: 		col += nlen + fill;
  475: 	}
  476: 	first = 0;
  477: 
  478: 	seteuid(euid);
  479: 	if (*datafile && !stat(datafile, &lbuf))
  480: 		totsize += copies * lbuf.st_size;
  481: 	seteuid(uid);
  482: }
  483: 
  484: /*
  485:  * Print the long info about the file
  486:  */
  487: void
  488: ldump(const char *nfile, const char *datafile, int copies)
  489: {
  490: 	struct stat lbuf;
  491: 
  492: 	putchar('\t');
  493: 	if (copies > 1)
  494: 		printf("%-2d copies of %-19s", copies, nfile);
  495: 	else
  496: 		printf("%-32s", nfile);
  497: 	if (*datafile && !stat(datafile, &lbuf))
  498: 		printf(" %qd bytes", (long long) lbuf.st_size);
  499: 	else
  500: 		printf(" ??? bytes");
  501: 	putchar('\n');
  502: }
  503: 
  504: /*
  505:  * Print the job's rank in the queue,
  506:  *   update col for screen management
  507:  */
  508: void
  509: prank(int n)
  510: {
  511: 	char rline[100];
  512: 	static const char *r[] = {
  513: 		"th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th"
  514: 	};
  515: 
  516: 	if (n == 0) {
  517: 		printf("active");
  518: 		col += 6;
  519: 		return;
  520: 	}
  521: 	if ((n/10)%10 == 1)
  522: 		(void)snprintf(rline, sizeof(rline), "%dth", n);
  523: 	else
  524: 		(void)snprintf(rline, sizeof(rline), "%d%s", n, r[n%10]);
  525: 	col += strlen(rline);
  526: 	printf("%s", rline);
  527: }
  528: 
  529: void
  530: alarmhandler(int signo __unused)
  531: {
  532: 	/* the signal is ignored */
  533: 	/* (the '__unused' is just to avoid a compile-time warning) */
  534: }