displayq.c revision 79739
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
3531492Swollman/*
3615648Sjoergstatic char sccsid[] = "@(#)displayq.c	8.4 (Berkeley) 4/28/95";
3731492Swollman*/
3831492Swollmanstatic const char rcsid[] =
3950479Speter  "$FreeBSD: head/usr.sbin/lpr/common_source/displayq.c 79739 2001-07-15 00:09:46Z gad $";
401553Srgrimes#endif /* not lint */
411553Srgrimes
421553Srgrimes#include <sys/param.h>
431553Srgrimes#include <sys/stat.h>
441553Srgrimes
4531492Swollman#include <ctype.h>
4631492Swollman#include <dirent.h>
4731492Swollman#include <errno.h>
4831492Swollman#include <fcntl.h>
491553Srgrimes#include <signal.h>
501553Srgrimes#include <stdio.h>
511553Srgrimes#include <stdlib.h>
521553Srgrimes#include <string.h>
5331492Swollman#define psignal foil_gcc_psignal
5431492Swollman#define	sys_siglist foil_gcc_siglist
5531492Swollman#include <unistd.h>
5631492Swollman#undef psignal
5731492Swollman#undef sys_siglist
5831492Swollman
591553Srgrimes#include "lp.h"
601553Srgrimes#include "lp.local.h"
611553Srgrimes#include "pathnames.h"
621553Srgrimes
631553Srgrimes/*
641553Srgrimes * Routines to display the state of the queue.
651553Srgrimes */
661553Srgrimes#define JOBCOL	40		/* column for job # in -l format */
671553Srgrimes#define OWNCOL	7		/* start of Owner column in normal */
681553Srgrimes#define SIZCOL	62		/* start of Size column in normal */
691553Srgrimes
701553Srgrimes/*
711553Srgrimes * Stuff for handling job specifications
721553Srgrimes */
7327618Simpextern uid_t	uid, euid;
7427618Simp
751553Srgrimesstatic int	col;		/* column on screen */
761553Srgrimesstatic char	current[40];	/* current file being printed */
771553Srgrimesstatic char	file[132];	/* print file name */
781553Srgrimesstatic int	first;		/* first file in ``files'' column? */
791553Srgrimesstatic int	garbage;	/* # of garbage cf files */
801553Srgrimesstatic int	lflag;		/* long output option */
811553Srgrimesstatic int	rank;		/* order to be printed (-1=none, 0=active) */
821553Srgrimesstatic long	totsize;	/* total print job size in bytes */
831553Srgrimes
8478146Sgadstatic const char  *head0 = "Rank   Owner      Job  Files";
8578146Sgadstatic const char  *head1 = "Total Size\n";
861553Srgrimes
8778146Sgadstatic void	alarmhandler(int _signo);
8878146Sgadstatic void	warn(const struct printer *_pp);
8926844Sjoerg
901553Srgrimes/*
911553Srgrimes * Display the current state of the queue. Format = 1 if long format.
921553Srgrimes */
931553Srgrimesvoid
9478146Sgaddisplayq(struct printer *pp, int format)
951553Srgrimes{
9668401Sgad	register struct jobqueue *q;
9727618Simp	register int i, nitems, fd, ret;
981553Srgrimes	register char	*cp;
9968401Sgad	struct jobqueue **queue;
1001553Srgrimes	struct stat statb;
1011553Srgrimes	FILE *fp;
10226844Sjoerg	void (*savealrm)(int);
1031553Srgrimes
1041553Srgrimes	lflag = format;
1051553Srgrimes	totsize = 0;
1061553Srgrimes	rank = -1;
10731492Swollman
10831492Swollman	if ((cp = checkremote(pp))) {
1091553Srgrimes		printf("Warning: %s\n", cp);
11031492Swollman		free(cp);
11131492Swollman	}
1121553Srgrimes
1131553Srgrimes	/*
1141553Srgrimes	 * Print out local queue
1151553Srgrimes	 * Find all the control files in the spooling directory
1161553Srgrimes	 */
11727618Simp	seteuid(euid);
11831492Swollman	if (chdir(pp->spool_dir) < 0)
11931492Swollman		fatal(pp, "cannot chdir to spooling directory: %s",
12031492Swollman		      strerror(errno));
12127618Simp	seteuid(uid);
12231492Swollman	if ((nitems = getq(pp, &queue)) < 0)
12331492Swollman		fatal(pp, "cannot examine spooling area\n");
12427618Simp	seteuid(euid);
12531492Swollman	ret = stat(pp->lock_file, &statb);
12627618Simp	seteuid(uid);
12727618Simp	if (ret >= 0) {
12831492Swollman		if (statb.st_mode & LFM_PRINT_DIS) {
12931492Swollman			if (pp->remote)
13078300Sgad				printf("%s: ", local_host);
13131492Swollman			printf("Warning: %s is down: ", pp->printer);
13227618Simp			seteuid(euid);
13331492Swollman			fd = open(pp->status_file, O_RDONLY|O_SHLOCK);
13427618Simp			seteuid(uid);
1351553Srgrimes			if (fd >= 0) {
1361553Srgrimes				while ((i = read(fd, line, sizeof(line))) > 0)
1371553Srgrimes					(void) fwrite(line, 1, i, stdout);
1381553Srgrimes				(void) close(fd);	/* unlocks as well */
1391553Srgrimes			} else
1401553Srgrimes				putchar('\n');
1411553Srgrimes		}
14231492Swollman		if (statb.st_mode & LFM_QUEUE_DIS) {
14331492Swollman			if (pp->remote)
14478300Sgad				printf("%s: ", local_host);
14531492Swollman			printf("Warning: %s queue is turned off\n",
14631492Swollman			       pp->printer);
1471553Srgrimes		}
1481553Srgrimes	}
1491553Srgrimes
1501553Srgrimes	if (nitems) {
15127618Simp		seteuid(euid);
15231492Swollman		fp = fopen(pp->lock_file, "r");
15327618Simp		seteuid(uid);
1541553Srgrimes		if (fp == NULL)
15531492Swollman			warn(pp);
1561553Srgrimes		else {
1571553Srgrimes			/* get daemon pid */
1581553Srgrimes			cp = current;
15915648Sjoerg			while ((i = getc(fp)) != EOF && i != '\n')
16015648Sjoerg				*cp++ = i;
1611553Srgrimes			*cp = '\0';
1621553Srgrimes			i = atoi(current);
16327618Simp			if (i <= 0) {
16427618Simp				ret = -1;
16527618Simp			} else {
16627618Simp				seteuid(euid);
16727618Simp				ret = kill(i, 0);
16827618Simp				seteuid(uid);
16927618Simp			}
17027618Simp			if (ret < 0) {
17131492Swollman				warn(pp);
17227618Simp			} else {
1731553Srgrimes				/* read current file name */
1741553Srgrimes				cp = current;
17515648Sjoerg				while ((i = getc(fp)) != EOF && i != '\n')
17615648Sjoerg					*cp++ = i;
1771553Srgrimes				*cp = '\0';
1781553Srgrimes				/*
1791553Srgrimes				 * Print the status file.
1801553Srgrimes				 */
18131492Swollman				if (pp->remote)
18278300Sgad					printf("%s: ", local_host);
18327618Simp				seteuid(euid);
18431492Swollman				fd = open(pp->status_file, O_RDONLY|O_SHLOCK);
18527618Simp				seteuid(uid);
1861553Srgrimes				if (fd >= 0) {
18731492Swollman					while ((i = read(fd, line,
18831492Swollman							 sizeof(line))) > 0)
18931492Swollman						fwrite(line, 1, i, stdout);
19031492Swollman					close(fd);	/* unlocks as well */
1911553Srgrimes				} else
1921553Srgrimes					putchar('\n');
1931553Srgrimes			}
1941553Srgrimes			(void) fclose(fp);
1951553Srgrimes		}
1961553Srgrimes		/*
1971553Srgrimes		 * Now, examine the control files and print out the jobs to
1981553Srgrimes		 * be done for each user.
1991553Srgrimes		 */
2001553Srgrimes		if (!lflag)
2011553Srgrimes			header();
2021553Srgrimes		for (i = 0; i < nitems; i++) {
2031553Srgrimes			q = queue[i];
20468401Sgad			inform(pp, q->job_cfname);
2051553Srgrimes			free(q);
2061553Srgrimes		}
2071553Srgrimes		free(queue);
2081553Srgrimes	}
20931492Swollman	if (!pp->remote) {
2101553Srgrimes		if (nitems == 0)
2111553Srgrimes			puts("no entries");
2121553Srgrimes		return;
2131553Srgrimes	}
2141553Srgrimes
2151553Srgrimes	/*
2161553Srgrimes	 * Print foreign queue
2171553Srgrimes	 * Note that a file in transit may show up in either queue.
2181553Srgrimes	 */
2191553Srgrimes	if (nitems)
2201553Srgrimes		putchar('\n');
22131492Swollman	(void) snprintf(line, sizeof(line), "%c%s", format ? '\4' : '\3',
22231492Swollman			pp->remote_queue);
2231553Srgrimes	cp = line;
22427757Simp	for (i = 0; i < requests && cp-line+10 < sizeof(line) - 1; i++) {
2251553Srgrimes		cp += strlen(cp);
2261553Srgrimes		(void) sprintf(cp, " %d", requ[i]);
2271553Srgrimes	}
22822466Simp	for (i = 0; i < users && cp - line + 1 + strlen(user[i]) <
22927757Simp		sizeof(line) - 1; i++) {
2301553Srgrimes		cp += strlen(cp);
2311553Srgrimes		*cp++ = ' ';
2321553Srgrimes		(void) strcpy(cp, user[i]);
2331553Srgrimes	}
2341553Srgrimes	strcat(line, "\n");
23526844Sjoerg	savealrm = signal(SIGALRM, alarmhandler);
23631492Swollman	alarm(pp->conn_timeout);
23731492Swollman	fd = getport(pp, pp->remote_host, 0);
23831020Sjoerg	alarm(0);
23926844Sjoerg	(void)signal(SIGALRM, savealrm);
2401553Srgrimes	if (fd < 0) {
24178300Sgad		if (from_host != local_host)
24278300Sgad			printf("%s: ", local_host);
24331492Swollman		printf("connection to %s is down\n", pp->remote_host);
2441553Srgrimes	}
2451553Srgrimes	else {
2461553Srgrimes		i = strlen(line);
2471553Srgrimes		if (write(fd, line, i) != i)
24831492Swollman			fatal(pp, "Lost connection");
2491553Srgrimes		while ((i = read(fd, line, sizeof(line))) > 0)
2501553Srgrimes			(void) fwrite(line, 1, i, stdout);
2511553Srgrimes		(void) close(fd);
2521553Srgrimes	}
2531553Srgrimes}
2541553Srgrimes
2551553Srgrimes/*
2561553Srgrimes * Print a warning message if there is no daemon present.
2571553Srgrimes */
25828621Sjoergstatic void
25978146Sgadwarn(const struct printer *pp)
2601553Srgrimes{
26131492Swollman	if (pp->remote)
26278300Sgad		printf("%s: ", local_host);
2631553Srgrimes	puts("Warning: no daemon present");
2641553Srgrimes	current[0] = '\0';
2651553Srgrimes}
2661553Srgrimes
2671553Srgrimes/*
2681553Srgrimes * Print the header for the short listing format
2691553Srgrimes */
2701553Srgrimesvoid
27178146Sgadheader(void)
2721553Srgrimes{
27379739Sgad	printf("%s", head0);
2741553Srgrimes	col = strlen(head0)+1;
2751553Srgrimes	blankfill(SIZCOL);
27679739Sgad	printf("%s", head1);
2771553Srgrimes}
2781553Srgrimes
2791553Srgrimesvoid
28078146Sgadinform(const struct printer *pp, char *cf)
2811553Srgrimes{
28268100Sgad	register int copycnt;
28368100Sgad	char	 savedname[MAXPATHLEN+1];
28468100Sgad	FILE	*cfp;
2851553Srgrimes
2861553Srgrimes	/*
2871553Srgrimes	 * There's a chance the control file has gone away
2881553Srgrimes	 * in the meantime; if this is the case just keep going
2891553Srgrimes	 */
29027618Simp	seteuid(euid);
2911553Srgrimes	if ((cfp = fopen(cf, "r")) == NULL)
2921553Srgrimes		return;
29327618Simp	seteuid(uid);
2941553Srgrimes
2951553Srgrimes	if (rank < 0)
2961553Srgrimes		rank = 0;
29731492Swollman	if (pp->remote || garbage || strcmp(cf, current))
2981553Srgrimes		rank++;
29968100Sgad
30068100Sgad	/*
30168100Sgad	 * The cf-file may include commands to print more than one datafile
30268100Sgad	 * from the user.  For each datafile, the cf-file contains at least
30368100Sgad	 * one line which starts with some format-specifier ('a'-'z'), and
30468100Sgad	 * a second line ('N'ame) which indicates the original name the user
30568100Sgad	 * specified for that file.  There can be multiple format-spec lines
30668100Sgad	 * for a single Name-line, if the user requested multiple copies of
30768100Sgad	 * that file.  Standard lpr puts the format-spec line(s) before the
30868100Sgad	 * Name-line, while lprNG puts the Name-line before the format-spec
30968100Sgad	 * line(s).  This section needs to handle the lines in either order.
31068100Sgad	 */
31168100Sgad	copycnt = 0;
31268100Sgad	file[0] = '\0';
31368100Sgad	savedname[0] = '\0';
3141553Srgrimes	while (getline(cfp)) {
3151553Srgrimes		switch (line[0]) {
3161553Srgrimes		case 'P': /* Was this file specified in the user's list? */
3171553Srgrimes			if (!inlist(line+1, cf)) {
3181553Srgrimes				fclose(cfp);
3191553Srgrimes				return;
3201553Srgrimes			}
3211553Srgrimes			if (lflag) {
3221553Srgrimes				printf("\n%s: ", line+1);
3231553Srgrimes				col = strlen(line+1) + 2;
3241553Srgrimes				prank(rank);
3251553Srgrimes				blankfill(JOBCOL);
3261553Srgrimes				printf(" [job %s]\n", cf+3);
3271553Srgrimes			} else {
3281553Srgrimes				col = 0;
3291553Srgrimes				prank(rank);
3301553Srgrimes				blankfill(OWNCOL);
3311553Srgrimes				printf("%-10s %-3d  ", line+1, atoi(cf+3));
3321553Srgrimes				col += 16;
3331553Srgrimes				first = 1;
3341553Srgrimes			}
3351553Srgrimes			continue;
3361553Srgrimes		default: /* some format specifer and file name? */
3371553Srgrimes			if (line[0] < 'a' || line[0] > 'z')
33868100Sgad				break;
33968100Sgad			if (copycnt == 0 || strcmp(file, line+1) != 0) {
34068100Sgad				strncpy(file, line + 1, sizeof(file) - 1);
34122466Simp				file[sizeof(file) - 1] = '\0';
34222466Simp			}
34368100Sgad			copycnt++;
34468100Sgad			/*
34568100Sgad			 * deliberately 'continue' to another getline(), so
34668100Sgad			 * all format-spec lines for this datafile are read
34768100Sgad			 * in and counted before calling show()
34868100Sgad			 */
3491553Srgrimes			continue;
3501553Srgrimes		case 'N':
35168100Sgad			strncpy(savedname, line + 1, sizeof(savedname) - 1);
35268100Sgad			savedname[sizeof(savedname) - 1] = '\0';
35368100Sgad			break;
35468100Sgad		}
35568100Sgad		if ((file[0] != '\0') && (savedname[0] != '\0')) {
35668100Sgad			show(savedname, file, copycnt);
35768100Sgad			copycnt = 0;
3581553Srgrimes			file[0] = '\0';
35968100Sgad			savedname[0] = '\0';
3601553Srgrimes		}
3611553Srgrimes	}
3621553Srgrimes	fclose(cfp);
36368100Sgad	/* check for a file which hasn't been shown yet */
36468100Sgad	if (file[0] != '\0') {
36568100Sgad		if (savedname[0] == '\0') {
36668100Sgad			/* a safeguard in case the N-ame line is missing */
36768100Sgad			strncpy(savedname, file, sizeof(savedname) - 1);
36868100Sgad			savedname[sizeof(savedname) - 1] = '\0';
36968100Sgad		}
37068100Sgad		show(savedname, file, copycnt);
37168100Sgad	}
3721553Srgrimes	if (!lflag) {
3731553Srgrimes		blankfill(SIZCOL);
3741553Srgrimes		printf("%ld bytes\n", totsize);
3751553Srgrimes		totsize = 0;
3761553Srgrimes	}
3771553Srgrimes}
3781553Srgrimes
3791553Srgrimesint
38078146Sgadinlist(char *uname, char *cfile)
3811553Srgrimes{
3821553Srgrimes	register int *r, n;
3831553Srgrimes	register char **u, *cp;
3841553Srgrimes
3851553Srgrimes	if (users == 0 && requests == 0)
3861553Srgrimes		return(1);
3871553Srgrimes	/*
3881553Srgrimes	 * Check to see if it's in the user list
3891553Srgrimes	 */
3901553Srgrimes	for (u = user; u < &user[users]; u++)
39178146Sgad		if (!strcmp(*u, uname))
3921553Srgrimes			return(1);
3931553Srgrimes	/*
3941553Srgrimes	 * Check the request list
3951553Srgrimes	 */
39678146Sgad	for (n = 0, cp = cfile+3; isdigit(*cp); )
3971553Srgrimes		n = n * 10 + (*cp++ - '0');
3981553Srgrimes	for (r = requ; r < &requ[requests]; r++)
39978300Sgad		if (*r == n && !strcmp(cp, from_host))
4001553Srgrimes			return(1);
4011553Srgrimes	return(0);
4021553Srgrimes}
4031553Srgrimes
4041553Srgrimesvoid
40578146Sgadshow(const char *nfile, const char *datafile, int copies)
4061553Srgrimes{
4071553Srgrimes	if (strcmp(nfile, " ") == 0)
4081553Srgrimes		nfile = "(standard input)";
4091553Srgrimes	if (lflag)
41078146Sgad		ldump(nfile, datafile, copies);
4111553Srgrimes	else
41278146Sgad		dump(nfile, datafile, copies);
4131553Srgrimes}
4141553Srgrimes
4151553Srgrimes/*
4161553Srgrimes * Fill the line with blanks to the specified column
4171553Srgrimes */
4181553Srgrimesvoid
41978146Sgadblankfill(int tocol)
4201553Srgrimes{
42178146Sgad	while (col++ < tocol)
4221553Srgrimes		putchar(' ');
4231553Srgrimes}
4241553Srgrimes
4251553Srgrimes/*
4261553Srgrimes * Give the abbreviated dump of the file names
4271553Srgrimes */
4281553Srgrimesvoid
42978146Sgaddump(const char *nfile, const char *datafile, int copies)
4301553Srgrimes{
4311553Srgrimes	struct stat lbuf;
43268101Sgad	const char etctmpl[] = ", ...";
43368101Sgad	char	 etc[sizeof(etctmpl)];
43468101Sgad	char	*lastsep;
43568101Sgad	short	 fill, nlen;
43668101Sgad	short	 rem, remetc;
4371553Srgrimes
4381553Srgrimes	/*
43968101Sgad	 * Print as many filenames as will fit
44068101Sgad	 *      (leaving room for the 'total size' field)
4411553Srgrimes	 */
44268101Sgad	fill = first ? 0 : 2;	/* fill space for ``, '' */
44368101Sgad	nlen = strlen(nfile);
44468101Sgad	rem = SIZCOL - 1 - col;
44568101Sgad	if (nlen + fill > rem) {
44668101Sgad		if (first) {
44768101Sgad			/* print the right-most part of the name */
44868101Sgad			printf("...%s ", &nfile[3+nlen-rem]);
44968101Sgad			col = SIZCOL;
45068101Sgad		} else if (rem > 0) {
45168101Sgad			/* fit as much of the etc-string as we can */
45268101Sgad			remetc = rem;
45368101Sgad			if (rem > strlen(etctmpl))
45468101Sgad				remetc = strlen(etctmpl);
45568101Sgad			etc[0] = '\0';
45668101Sgad			strncat(etc, etctmpl, remetc);
45779739Sgad			printf("%s", etc);
45868101Sgad			col += remetc;
45968101Sgad			rem -= remetc;
46068101Sgad			/* room for the last segment of this filename? */
46168101Sgad			lastsep = strrchr(nfile, '/');
46268101Sgad			if ((lastsep != NULL) && (rem > strlen(lastsep))) {
46368101Sgad				/* print the right-most part of this name */
46468101Sgad				printf("%s", lastsep);
46568101Sgad				col += strlen(lastsep);
46668101Sgad			} else {
46768101Sgad				/* do not pack any more names in here */
46868101Sgad				blankfill(SIZCOL);
46968101Sgad			}
4701553Srgrimes		}
4711553Srgrimes	} else {
47268101Sgad		if (!first)
4731553Srgrimes			printf(", ");
4741553Srgrimes		printf("%s", nfile);
47568101Sgad		col += nlen + fill;
4761553Srgrimes	}
47768101Sgad	first = 0;
47868101Sgad
47927618Simp	seteuid(euid);
48078146Sgad	if (*datafile && !stat(datafile, &lbuf))
4811553Srgrimes		totsize += copies * lbuf.st_size;
48227618Simp	seteuid(uid);
4831553Srgrimes}
4841553Srgrimes
4851553Srgrimes/*
4861553Srgrimes * Print the long info about the file
4871553Srgrimes */
4881553Srgrimesvoid
48978146Sgadldump(const char *nfile, const char *datafile, int copies)
4901553Srgrimes{
4911553Srgrimes	struct stat lbuf;
4921553Srgrimes
4931553Srgrimes	putchar('\t');
4941553Srgrimes	if (copies > 1)
4951553Srgrimes		printf("%-2d copies of %-19s", copies, nfile);
4961553Srgrimes	else
4971553Srgrimes		printf("%-32s", nfile);
49878146Sgad	if (*datafile && !stat(datafile, &lbuf))
49935998Sjb		printf(" %qd bytes", (long long) lbuf.st_size);
5001553Srgrimes	else
5011553Srgrimes		printf(" ??? bytes");
5021553Srgrimes	putchar('\n');
5031553Srgrimes}
5041553Srgrimes
5051553Srgrimes/*
5061553Srgrimes * Print the job's rank in the queue,
5071553Srgrimes *   update col for screen management
5081553Srgrimes */
5091553Srgrimesvoid
51078146Sgadprank(int n)
5111553Srgrimes{
5121553Srgrimes	char rline[100];
51378146Sgad	static const char *r[] = {
5141553Srgrimes		"th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th"
5151553Srgrimes	};
5161553Srgrimes
5171553Srgrimes	if (n == 0) {
5181553Srgrimes		printf("active");
5191553Srgrimes		col += 6;
5201553Srgrimes		return;
5211553Srgrimes	}
5221553Srgrimes	if ((n/10)%10 == 1)
5231553Srgrimes		(void)snprintf(rline, sizeof(rline), "%dth", n);
5241553Srgrimes	else
5251553Srgrimes		(void)snprintf(rline, sizeof(rline), "%d%s", n, r[n%10]);
5261553Srgrimes	col += strlen(rline);
5271553Srgrimes	printf("%s", rline);
5281553Srgrimes}
52926844Sjoerg
53026844Sjoergvoid
53178146Sgadalarmhandler(int signo __unused)
53226844Sjoerg{
53378146Sgad	/* the signal is ignored */
53478146Sgad	/* (the '__unused' is just to avoid a compile-time warning) */
53526844Sjoerg}
536