/*
 *	Network Queueing System (NQS)
 *  This version of NQS is Copyright (C) 1992  John Roman
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 1, or (at your option)
 *  any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
/*
*  PROJECT:     Network Queueing System
*  AUTHOR:      John Roman
*
*  Modification history:
*
*       Version Who     When            Description
*       -------+-------+---------------+-------------------------
*       V01.10  JRR                     Initial version.
*       V01.20  JRR     16-Jan-1992	Added support for RS6000.
*	V01.30	JRR	17-Jan-1992	SHO_R_SHORT is now SHO_R_STANDARD
*					and _MED is now MONSANTO.
*       V01.40  JRR     17-Jan-1992	Fixed up conditional compilation.
*       V01.50  JRR     22-Jan-1992	Fix up summary line for non-SGI.
*       V01.60  JRR     24-Jan-1992	Re-introduce earlier changes.
*       V01.70  JRR     12-Feb-1992	Fix problems with Irix 4.0.
*       V01.8   JRR     12-Feb-1992	More of the same with Irix 4.0
*					(Statically declared routines).
*       V01.9   JRR     12-Feb-1992	I have to change more of the statics.
*       V01.10  JRR     02-Mar-1992	Added Cosmic V2 changes.
*       V01.11  JRR     23-Mar-1992	Added support for suspended requests.
*			02-Apr-1992	Added support for broadcasts.
*       V01.12  JRR     10-Apr-1992     Add load balanced queues.
*	V01.13	JRR	15-May-1992	Only show non-degrading priority if sgi.
*					Add usage information for RS6000.
*					Change the default qstat format slightly.
*	V01.14	JRR	17-Jun-1992	Added header.
*	V01.15	JRR	06-Nov-1992	Added support for HPUX.
*	V01.16	JRR	29-Dec-1992	If request not running, don't wrap on
*					long queue names.
*					If no start time or total time, don't print.
*	V01.17	JRR	11-Mar-1993	Fix compile error in call to get_node.
*	V01.18	JRR	28-Jul-1993	Get the total time used in HPUX.
*	V01.19	JRR	22-Oct-1993	Minor changes for debugging.
*	V01.20	JRR	24-Feb-1994	Put the IRIX 5.x changes back in.
*	V01.21	JRR	28-Feb-1994	Added support for SOLARIS.
*	V01.22	JRR	08-Apr-1994	Fix bug with HPUX.
* 	V01.23	SLH	20-Dec-1994	Remove (apparently) broken HPUX support
*	V01.24	SLH	21-Dec-1994	First attempt to fix HPUX support
*/
/*++ shoqbydesc.c - Network Queueing System
 *
 * $Source: /usr2/jrroma/nqs/nqs-3.36/lib/RCS/shoqbydesc.c,v $
 *
 * DESCRIPTION:
 *
 *	This module contains the function shoqbydesc().
 *	Shoqbydesc() is responsible for displaying information
 *	about the local queue whose descriptor it is called with.
 *
 *
 *	Author:
 *	-------
 *	Robert W. Sandstrom, Sterling Software Incorporated.
 *	August 12, 1985.
 *
 *
 * STANDARDS VIOLATIONS:
 *   None.
 *
 * REVISION HISTORY: ($Revision: 1.22 $ $Date: 1994/09/02 17:37:57 $ $State: Exp $)
 * $Log: shoqbydesc.c,v $
 * Revision 1.22  1994/09/02  17:37:57  jrroma
 * Version 3.36
 *
 * Revision 1.21  1994/03/30  20:32:44  jrroma
 * Version 3.35.6
 *
 * Revision 1.20  94/02/25  15:54:51  jrroma
 * Version 3.35.3
 * 
 * Revision 1.19  94/02/24  21:28:46  jrroma
 * Version 3.35.3
 * 
 * Revision 1.18  93/09/10  13:55:24  jrroma
 * Version 3.35
 * 
 * Revision 1.17  93/07/13  21:31:36  jrroma
 * Version 3.34
 * 
 * Revision 1.16  93/02/05  23:13:17  jrroma
 * Version 3.31
 * 
 * Revision 1.15  92/12/22  15:46:32  jrroma
 * Version 3.30
 * 
 * Revision 1.14  92/06/18  13:24:49  jrroma
 * Added gnu header
 * 
 * Revision 1.13  92/06/18  09:41:51  jrroma
 * Version 3.21
 * 
 * Revision 1.12  92/05/06  10:20:22  jrroma
 * Version 3.20
 * 
 * Revision 1.11  92/04/07  12:52:43  jrroma
 * *** empty log message ***
 * 
 * Revision 1.10  92/03/02  09:34:20  jrroma
 * First round at adding Cosmic V2 changes.
 * 
 * Revision 1.9  92/02/12  16:10:09  jrroma
 * Fixes for Irix 4.0.1
 * 
 * Revision 1.8  92/02/12  12:29:45  jrroma
 * Fixed static declaration of selrequest.
 * 
 * Revision 1.7  92/02/12  10:39:57  jrroma
 * Changes for Irix 4.0.
 * 
 * Revision 1.6  92/02/12  10:34:53  jrroma
 * Re-introduce earlier changes
 * 
 * Revision 1.5  92/01/22  13:24:00  jrroma
 * Fix summary line for non-SGI machines.
 * 
 * Revision 1.4  92/01/17  16:37:44  jrroma
 * Fix up SGI conditional compilation.
 * 
 * Revision 1.3  92/01/17  14:36:35  jrroma
 * Changed SHO_R_SHORT to SHO_R_STANDARD and _MED to _MONSANTO.
 * 
 * Revision 1.2  92/01/16  17:19:21  jrroma
 * Added support for RS6000.
 * 
 * Revision 1.1  91/10/03  15:26:50  jrroma
 * Initial revision
 * 
 *
 */

#include "nqs.h"		/* NQS definitions */
#include "nqsxdirs.h"		/* NQS directories */
#include <string.h>
#include <errno.h>
#define DESTSET_MARGIN  13      /* Used in shoquedesmap() */
#define DEVSET_MARGIN   12      /* Used in shoquedevmap() */
#define OUTPUT_WIDTH    78      /* Number of output columns - 1 */

#if	SGI | IBMRS | SOLARIS | HPUX
#include <stdlib.h>
#include <time.h>
#include <sys/proc.h>
#include <sys/param.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/user.h>
int	memfd;
int	procsize;
int	do_count;
long	total_time;	/* total cpu time */
time_t	start_time;
#define	    KMEM	"/dev/kmem"

#if	SGI	
#include <sys/syssgi.h>
#include <sys/sysmp.h>
#include <sys/var.h>
#if   IRIX5
#include <sys/fault.h>
#include <sys/syscall.h>
#include <sys/procfs.h>
#endif
#endif
#if	IBMRS
#define	    MAX_PROC	1000
#include <nlist.h>
#include <procinfo.h>	
struct nlist anlist;
#endif
#if SOLARIS
#include <sys/procfs.h>
#include <dirent.h>
#endif

#if	HPUX
#define	    MAX_PROC	1000
#include <nlist.h>
#include <sys/pstat.h>
struct nlist anlist;
#define X_AVENRUN       0
#define X_CCPU          1
#define X_NPROC         2
#define X_PROC          3
#define X_TOTAL         4
#define X_CP_TIME       5
#define X_MPID          6

#ifndef __hp9000s300
#define X_HZ            7
#endif


static struct nlist nlst[] = {
    { "_avenrun" },             /* 0 */
    { "_ccpu" },                /* 1 */
    { "_nproc" },               /* 2 */
    { "_proc" },                /* 3 */
    { "_total" },               /* 4 */
    { "_cp_time" },             /* 5 */
    { "_mpid" },                /* 6 */
#ifdef X_HZ
    { "_hz" },                  /* 7 */
#endif
    { 0 }
};
unsigned long proc;
int  nproc;
long hz;
static int bytes;
static struct proc *pbase;
static union pstun *pst;

#endif
#endif

#define	DESTSET_MARGIN	13	/* Used in shoquedesmap() */
#define	DEVSET_MARGIN	12	/* Used in shoquedevmap() */
#define	OUTPUT_WIDTH	78	/* Number of output columns - 1 */

#ifndef __CEXTRACT__
#if __STDC__

#if	SGI
static int get_node ( struct proc *pointer, pid_t pid_oi, pid_t proc_family );
#else
static int get_node ( int pointer, pid_t pid_oi, pid_t proc_family );
#endif
static char *get_units ( short units );
static int selrequest ( struct qentry *qentry, long flags, uid_t whomuid, struct reqset *requests );
static void shocpulim ( struct cpulimit *cpu, long explicit, long infinite, struct gendescr *que_descr );
static void shogap ( int gaplow, int gaphigh, char * state, int flags );
static void shogrp ( unsigned long gid );
static void shokey ( struct gendescr *que_descr );
static void shoomd ( char mode );
static void shoqueacc ( struct confd *file, struct gendescr *que_descr );
static void shoquedesmap ( struct gendescr *que_descr, struct confd *qmapfile, struct confd *pipeqfile );
static void shoquedevmap ( struct gendescr *que_descr, struct confd *qmapfile );
static void shoquehdr ( struct confd *file, struct gendescr *que_descr, short dae_present, long flags, char *hostname, struct confd *qmapfile, struct confd *pipeqfile, struct confd *qcomplexfile );
static void shoquelims ( struct gendescr * que_descr );
static void shoqueline ( short queue_type, long flags );
static void shoquetime ( struct gendescr *que_descr );
static void shoquolim ( struct quotalimit *quota, long explicit, long infinite, struct gendescr *que_descr );
static void shoreqlims ( struct gendescr *que_descr, struct rawreq *rawreqp );
static void shorequest ( struct qentry *qentry, int reqstate, struct gendescr *que_descr, int nth_request, long flags, char *hostname );
static void shotitle ( char *string1, char *string2 );
static void shousr ( unsigned long uid );
static int sho_mon_hdr ( void );
static int summary ( pid_t proc_family, struct rawreq *rawreqp );

#else /* __STDC__ */

static int get_node (/* struct proc *pointer, pid_t pid_oi, pid_t proc_family */);
static char *get_units (/* short units */);
static int selrequest (/* struct qentry *qentry, long flags, uid_t whomuid, struct reqset *requests */);
static void shocpulim (/* struct cpulimit *cpu, long explicit, long infinite, struct gendescr *que_descr */);
static void shogap (/* int gaplow, int gaphigh, char * state, int flags */);
static void shogrp (/* unsigned long gid */);
static void shokey (/* struct gendescr *que_descr */);
static void shoomd (/* char mode */);
static void shoqueacc (/* struct confd *file, struct gendescr *que_descr */);
static void shoquedesmap (/* struct gendescr *que_descr, struct confd *qmapfile, struct confd *pipeqfile */);
static void shoquedevmap (/* struct gendescr *que_descr, struct confd *qmapfile */);
static void shoquehdr (/* struct confd *file, struct gendescr *que_descr, short dae_present, long flags, char *hostname, struct confd *qmapfile, struct confd *pipeqfile, struct confd *qcomplexfile */);
static void shoquelims (/* struct gendescr * que_descr */);
static void shoqueline (/* short queue_type, long flags */);
static void shoquetime (/* struct gendescr *que_descr */);
static void shoquolim (/* struct quotalimit *quota, long explicit, long infinite, struct gendescr *que_descr */);
static void shoreqlims (/* struct gendescr *que_descr, struct rawreq *rawreqp */);
static void shorequest (/* struct qentry *qentry, int reqstate, struct gendescr *que_descr, int nth_request, long flags, char *hostname */);
static void shotitle (/* char *string1, char *string2 */);
static void shousr (/* unsigned long uid */);
static int sho_mon_hdr (/* void */);
static int summary (/* pid_t proc_family, struct rawreq *rawreqp */);

#endif /* __STDC__ */
#endif /* __CEXTRACT__ */

struct qcount {
        int arrive;
        int depart;
        int hold;
        int queued;
        int run;
        int stage;
        int wait;
};

static struct qcount qcount;            /* Queue count totalisers */

extern int monsanto_header;

static int acccolumn = 0;	/* Used by shoqueacc(), shogrp(), shousr() */

static char *unlim      = "**";
static char *unlimited  = "unlimited";
static char *unspec     = "--";
static char *unspecified = "unspecified";

static char *disp_byoper        = "By Operator";
static char *disp_byuser        = "By User";
static char disp_procs[15];
static char long_line[]  = "  --- --- --- ---";
static char short_line[] = "--- --- --- --- --- ---";

static char disp_string [50];   /* Display field composite string */
static char disp_string2 [50];  /* Secondary display field composite string */
static char hostname [256];     /* Name of local host */

/*** shoqbydesc
 *
 *
 *	int shoqbydesc():
 *
 *	Display information about a local NQS queue.  The caller
 *	of this function must be running with the current directory
 *	of:  Nqs_root.
 *
 *	Returns:
 *		0: If information about the queue and zero or more
 *		   requests residing in the queue was displayed.
 *	       -1: If no output was produced.
 *	       -2: If we were unable to open the queue request-ordering
 *		   file for the queue; no output was produced.
 *	       -3: If the queue was deleted while we were trying
 *		   to open the queue-ordering file.
 */
int shoqbydesc (
	struct confd *file,		/* NQS queue file containing.... */
	struct gendescr *que_descr,	/* the queue descriptor */
	long flags,			/* Display flags */
	uid_t whomuid,			/* Zero in on this user */
	struct reqset *requests,	/* Optional request selection set */
	short dae_present,		/* Boolean non-zero if the local NQS */
					/* daemon is present and running */
	struct confd *qmapfile,		/* NQS queue/device/destination */
					/* mapping database file */
	struct confd *pipeqfile,	/* NQS pipe-queue destination */
					/* database file */
	struct confd *qcomplexfile)     /* NQS queue complex definition file */
{

	char hostname [256];		/* Name of local host */
	struct qentry cache [QOFILE_CACHESIZ];
					/* Queue ordering file cache buffer */
	int cacheindex;			/* Current buffer cache index */
	int cachesize;			/* Number of queue entries in read */
					/* cache buffer */
	short header;			/* ~0 if queue header displayed */
	int nth_request;		/* Rank of this request */
	int gaplow;			/* Lowest rank among unshown reqs */
	int gaphigh;			/* Highest rank among unshown reqs */
	int fd;				/* Queue ordering file descriptor */
	int i;				/* Loop var */

	gethostname (hostname, 255);	/* Get name of local host and make */
	hostname [255] = '\0';		/* sure that it is null-terminated */
	header = 0;			/* Queue header has not been shown */
	nth_request = 0;		/* No requests yet displayed */
	gaplow = 1;			/* Set up boundary conditions */
	gaphigh = 0;			/* Set up boundary conditions */
	if (flags & (SHO_RS_EXIT | SHO_RS_RUN | SHO_RS_STAGE | SHO_RS_QUEUED |
			SHO_RS_WAIT | SHO_RS_HOLD | SHO_RS_ARRIVE)) {
		/*
		 *  Open the request queue ordering file.
		 */
		if (!dae_present) {
			/*
			 *  Override database if daemon not present.
			 */
			que_descr->v.que.queuedcount
				+= que_descr->v.que.runcount;
			que_descr->v.que.runcount = 0;
		}
		fd = openqord (file, que_descr);
		/*
		 *  fd >= 0 if the queue has requests, and we successfully
		 *	    opened the queue ordering file.
		 *  fd = -1 if the queue has no requests.
		 *  fd = -2 if the queue has requests, but an error prevented
		 *	    us from opening the queue ordering file for
		 *	    the queue.
		 *  fd = -3 if the queue was deleted.
		 */
		if (fd < -1) return (fd);	/* Error or queue was deleted */
	}
	else {
		/*
		 *  We are only interested in the queue header.
		 */
		if (!dae_present) {
			/*
			 *  Override database if daemon not present.
			 */
			que_descr->v.que.queuedcount
				+= que_descr->v.que.runcount;
			que_descr->v.que.runcount = 0;
		}
		shoquehdr (file, que_descr, dae_present, flags, hostname,
			   qmapfile, pipeqfile, qcomplexfile);
						/* Display queue header only */
		return (0);			/* Output was produced */
	}
        if ( (!monsanto_header ) && (flags & SHO_R_MONSANTO) &&
                                (flags & SHO_R_HEADER) ) {
                monsanto_header++;
                sho_mon_hdr();
        }
	/*
	 *  The queue ordering file does exist.
	 *  We use it to try to find requests that match our requirements.
	 */
	if (requests == (struct reqset *) 0) {
		/*
		 *  Definitely display queue header no matter what.
		 */
		header = 1;			/* Mark header as displayed */
		shoquehdr (file, que_descr, dae_present, flags, hostname,
			   qmapfile, pipeqfile, qcomplexfile);
	}
	if (fd == -1) {
		/*
		 *  No requests are in the queue.
		 */
		if (header) return (0);		/* Output was produced */
		return (-1);			/* No output produced */
	}
	cachesize = 0;				/* Mark read cache as invalid*/
	cacheindex = 0;
	if (requests == (struct reqset *) 0) {
		if (flags & SHO_R_STANDARD) shokey (que_descr);
	}
	if ((flags & SHO_RS_EXIT) && que_descr->v.que.type == QUE_BATCH) {
		/*
		 *  Show completed requests staging output files.
		 */
		for (i = 0; i < que_descr->v.que.departcount; i++) {
			nth_request++;
			if (cacheindex >= cachesize) {
				cachesize = read (fd, (char *) cache,
						  sizeof (cache));
				cachesize /= sizeof (struct qentry);
				cacheindex = 0;
			}
			if (selrequest (&cache [cacheindex], flags,
					whomuid, requests)) {
				if (!header) {
					/*
					 *  Display the queue header.
					 *  Mark header as displayed.
					 */
					header = 1;
					shoquehdr (file, que_descr, dae_present,
						   flags, hostname, qmapfile,
						   pipeqfile, qcomplexfile);
					if (flags & SHO_R_STANDARD) {
						shokey (que_descr);
					}
				}
				shogap (gaplow, gaphigh, "EXITING", flags);
				shorequest (&cache [cacheindex],
					    SHO_RS_EXIT, que_descr,
					    nth_request, flags, hostname);
				gaphigh = nth_request;
				gaplow = nth_request + 1;
			}
			else gaphigh++;
			cacheindex++;
		}
		shogap (gaplow, gaphigh, "EXITING", flags);
		gaphigh = nth_request;
		gaplow = nth_request + 1;
	}
	else if ((flags & SHO_RS_EXIT) && que_descr->v.que.type==QUE_PIPE) {
		/*
		 *  Show departing requests.
		 */
		for (i = 0; i < que_descr->v.que.departcount; i++) {
			nth_request++;
			if (cacheindex >= cachesize) {
				cachesize = read (fd, (char *) cache,
						  sizeof (cache));
				cachesize /= sizeof (struct qentry);
				cacheindex = 0;
			}
			if (selrequest (&cache [cacheindex], flags,
					whomuid, requests)) {
				if (!header) {
					/*
					 *  Display the queue header.
					 *  Mark header as displayed.
					 */
					header = 1;
					shoquehdr (file, que_descr, dae_present,
						   flags, hostname, qmapfile,
						   pipeqfile,qcomplexfile);
					if (flags & SHO_R_STANDARD) {
						shokey (que_descr);
					}
				}
				shogap (gaplow, gaphigh, "DEPARTING", flags);
				shorequest (&cache [cacheindex],
					    SHO_RS_EXIT, que_descr,
					    nth_request, flags, hostname);
				gaphigh = nth_request;
				gaplow = nth_request + 1;
			}
			else gaphigh++;
			cacheindex++;
		}
		shogap (gaplow, gaphigh, "DEPARTING", flags);
		gaphigh = nth_request;
		gaplow = nth_request + 1;
	}
	else lseek (fd, (long) (que_descr->v.que.departcount *
			sizeof (struct qentry)), 0);
	if ((flags & SHO_RS_RUN) && que_descr->v.que.type != QUE_PIPE) {
		/*
		 * Show running requests.
		 */
		for (i = 0; i < que_descr->v.que.runcount; i++) {
			nth_request++;
			if (cacheindex >= cachesize) {
				cachesize = read (fd, (char *) cache,
						  sizeof (cache));
				cachesize /= sizeof (struct qentry);
				cacheindex = 0;
			}
			if (selrequest (&cache [cacheindex], flags,
					whomuid, requests)) {
				if (!header) {
					/*
					 *  Display the queue header.
					 *  Mark header as displayed.
					 */
					header = 1;
					shoquehdr (file, que_descr, dae_present,
						   flags, hostname, qmapfile,
						   pipeqfile,qcomplexfile);
					if (flags & SHO_R_STANDARD) {
						shokey (que_descr);
					}
				}
				shogap (gaplow, gaphigh, "RUNNING", flags);
				shorequest (&cache [cacheindex], SHO_RS_RUN,
					    que_descr, nth_request, flags,
					    hostname);
				gaphigh = nth_request;
				gaplow = nth_request + 1;
			}
			else gaphigh++;
			cacheindex++;
		}
		shogap (gaplow, gaphigh, "RUNNING", flags);
		gaphigh = nth_request;
		gaplow = nth_request + 1;
	}
	else if ((flags & SHO_RS_RUN) && que_descr->v.que.type == QUE_PIPE) {
		for (i = 0; i < que_descr->v.que.runcount; i++) {
			nth_request++;
			if (cacheindex >= cachesize) {
				cachesize = read (fd, (char *) cache,
						  sizeof (cache));
				cachesize /= sizeof (struct qentry);
				cacheindex = 0;
			}
			if (selrequest (&cache [cacheindex], flags,
					whomuid, requests)) {
				if (!header) {
					/*
					 *  Display the queue header.
					 *  Mark header as displayed.
					 */
					header = 1;
					shoquehdr (file, que_descr, dae_present,
						   flags, hostname, qmapfile,
						   pipeqfile,qcomplexfile);
					if (flags & SHO_R_STANDARD) {
						shokey (que_descr);
					}
				}
				shogap (gaplow, gaphigh, "ROUTING", flags);
				shorequest (&cache [cacheindex], SHO_RS_RUN,
					    que_descr, nth_request, flags,
					    hostname);
				gaphigh = nth_request;
				gaplow = nth_request + 1;
			}
			else gaphigh++;
			cacheindex++;
		}
		shogap (gaplow, gaphigh, "ROUTING", flags);
		gaphigh = nth_request;
		gaplow = nth_request + 1;
	}
	else {
		cacheindex += que_descr->v.que.runcount;
		if (cacheindex > cachesize) {
			lseek (fd, (long) (cacheindex - cachesize)
					 * sizeof (struct qentry), 1);
		}
	}
	if ((flags & SHO_RS_STAGE) && que_descr->v.que.type == QUE_BATCH) {
		/*
		 * Show staging requests.
		 */
		for (i = 0; i < que_descr->v.que.stagecount; i++) {
			nth_request++;
			if (cacheindex >= cachesize) {
				cachesize = read (fd, (char *) cache,
						  sizeof (cache));
				cachesize /= sizeof (struct qentry);
				cacheindex = 0;
			}
			if (selrequest (&cache [cacheindex], flags,
					whomuid, requests)) {
				if (!header) {
					/*
					 *  Display the queue header.
					 *  Mark header as displayed.
					 */
					header = 1;
					shoquehdr (file, que_descr, dae_present,
						   flags, hostname, qmapfile,
						   pipeqfile,qcomplexfile);
					if (flags & SHO_R_STANDARD) {
						shokey (que_descr);
					}
				}
				shogap (gaplow, gaphigh, "STAGING", flags);
				shorequest (&cache [cacheindex],
					    SHO_RS_STAGE, que_descr,
					    nth_request, flags, hostname);
				gaphigh = nth_request;
				gaplow = nth_request + 1;
			}
			else gaphigh++;
			cacheindex++;
		}
		shogap (gaplow, gaphigh, "STAGING", flags);
		gaphigh = nth_request;
		gaplow = nth_request + 1;
	}
	else {
		cacheindex += que_descr->v.que.stagecount;
		if (cacheindex > cachesize) {
			lseek (fd, (long) (cacheindex - cachesize)
					 * sizeof (struct qentry), 1);
		}
	}
	if (flags & SHO_RS_QUEUED) {	/* Show queued requests */
		for (i = 0; i < que_descr->v.que.queuedcount; i++) {
			nth_request++;
			if (cacheindex >= cachesize) {
				cachesize = read (fd, (char *) cache,
						  sizeof (cache));
				cachesize /= sizeof (struct qentry);
				cacheindex = 0;
			}
			if (selrequest (&cache [cacheindex], flags,
					whomuid, requests)) {
				if (!header) {
					/*
					 *  Display the queue header.
					 *  Mark header as displayed.
					 */
					header = 1;
					shoquehdr (file, que_descr, dae_present,
						   flags, hostname, qmapfile,
						   pipeqfile, qcomplexfile);
					if (flags & SHO_R_STANDARD) {
						shokey (que_descr);
					}
				}
				shogap (gaplow, gaphigh, "QUEUED", flags);
				shorequest (&cache [cacheindex],
					    SHO_RS_QUEUED, que_descr,
					    nth_request, flags, hostname);
				gaphigh = nth_request;
				gaplow = nth_request + 1;
			}
			else gaphigh++;
			cacheindex++;
		}
		shogap (gaplow, gaphigh, "QUEUED", flags);
		gaphigh = nth_request;
		gaplow = nth_request + 1;
	}
	else {
		cacheindex += que_descr->v.que.queuedcount;
		if (cacheindex > cachesize) {
			lseek (fd, (long) (cacheindex - cachesize)
					 * sizeof (struct qentry), 1);
		}
	}
	if (flags & SHO_RS_WAIT) {	/* Show waiting requests */
		for (i = 0; i < que_descr->v.que.waitcount; i++) {
			nth_request++;
			if (cacheindex >= cachesize) {
				cachesize = read (fd, (char *) cache,
						  sizeof (cache));
				cachesize /= sizeof (struct qentry);
				cacheindex = 0;
			}
			if (selrequest (&cache [cacheindex], flags,
					whomuid, requests)) {
				if (!header) {
					/*
					 *  Display the queue header.
					 *  Mark header as displayed.
					 */
					header = 1;
					shoquehdr (file, que_descr, dae_present,
						   flags, hostname, qmapfile,
						   pipeqfile, qcomplexfile);
					if (flags & SHO_R_STANDARD) {
						shokey (que_descr);
					}
				}
				shogap (gaplow, gaphigh, "WAITING", flags);
				shorequest (&cache [cacheindex],
					    SHO_RS_WAIT, que_descr,
					    nth_request, flags, hostname);
				gaphigh = nth_request;
				gaplow = nth_request + 1;
			}
			else gaphigh++;
			cacheindex++;
		}
		shogap (gaplow, gaphigh, "WAITING", flags);
		gaphigh = nth_request;
		gaplow = nth_request + 1;
	}
	else {
		cacheindex += que_descr->v.que.waitcount;
		if (cacheindex > cachesize) {
			lseek (fd, (long) (cacheindex - cachesize)
					 * sizeof (struct qentry), 1);
		}
	}
	if (flags & SHO_RS_HOLD) {	/* Show requests holding */
		for (i = 0; i < que_descr->v.que.holdcount; i++) {
			nth_request++;
			if (cacheindex >= cachesize) {
				cachesize = read (fd, (char *) cache,
						  sizeof (cache));
				cachesize /= sizeof (struct qentry);
				cacheindex = 0;
			}
			if (selrequest (&cache [cacheindex], flags,
					whomuid, requests)) {
				if (!header) {
					/*
					 *  Display the queue header.
					 *  Mark header as displayed.
					 */
					header = 1;
					shoquehdr (file, que_descr, dae_present,
						   flags, hostname, qmapfile,
						   pipeqfile,qcomplexfile);
					if (flags & SHO_R_STANDARD) {
						shokey (que_descr);
					}
				}
				shogap (gaplow, gaphigh, "HOLDING", flags);
				shorequest (&cache [cacheindex],
					    SHO_RS_HOLD, que_descr,
					    nth_request, flags, hostname);
				gaphigh = nth_request;
				gaplow = nth_request + 1;
			}
			else gaphigh++;
			cacheindex++;
		}
		shogap (gaplow, gaphigh, "HOLDING", flags);
		gaphigh = nth_request;
		gaplow = nth_request + 1;
	}
	else {
		cacheindex += que_descr->v.que.holdcount;
		if (cacheindex > cachesize) {
			lseek (fd, (long) (cacheindex - cachesize)
					 * sizeof (struct qentry), 1);
		}
	}
	if (flags & SHO_RS_ARRIVE) {	/* Show arriving requests */
		for (i = 0; i < que_descr->v.que.arrivecount; i++) {
			nth_request++;
			if (cacheindex >= cachesize) {
				cachesize = read (fd, (char *) cache,
						  sizeof (cache));
				cachesize /= sizeof (struct qentry);
				cacheindex = 0;
			}
			if (selrequest (&cache [cacheindex], flags,
					whomuid, requests)) {
				if (!header) {
					/*
					 *  Display the queue header.
					 *  Mark header as displayed.
					 */
					header = 1;
					shoquehdr (file, que_descr, dae_present,
						   flags, hostname, qmapfile,
						   pipeqfile,qcomplexfile);
					if (flags & SHO_R_STANDARD) {
						shokey (que_descr);
					}
				}
				shogap (gaplow, gaphigh, "ARRIVING", flags);
				shorequest (&cache [cacheindex],
					    SHO_RS_ARRIVE, que_descr,
					    nth_request, flags, hostname);
				gaphigh = nth_request;
				gaplow = nth_request + 1;
			}
			else gaphigh++;
			cacheindex++;
		}
		shogap (gaplow, gaphigh, "ARRIVING", flags);
		gaphigh = nth_request;
		gaplow = nth_request + 1;
	}
	close (fd);			/* Close queue ordering file */
	if (header) return (0);		/* There was output */
	return (-1);			/* No output at all */
}


/*** get_units
 *
 *
 *	char *get_units():
 *	Get quota units.
 */
static char *get_units (short units)
{
	switch (units) {
	case QLM_BYTES:
		return ("bytes");
	case QLM_WORDS:
		return ("words");
	case QLM_KBYTES:
		return ("kilobytes");
	case QLM_KWORDS:
		return ("kilowords");
	case QLM_MBYTES:
		return ("megabytes");
	case QLM_MWORDS:
		return ("megawords");
	case QLM_GBYTES:
		return ("gigabytes");
	case QLM_GWORDS:
		return ("gigawords");
	}
	return ("");		/* Unknown units! */
}


/*** selrequest
 *
 *
 *	int selrequest():
 *	Select a request.
 *
 *	Returns:
 *		1: if the request was selected for display;
 *		0: if not.
 */
static int selrequest (
	register struct qentry *qentry,	/* Request queue entry */
	long flags,			/* Display mode flags */
	uid_t whomuid,			/* Whom we are asking about */
	register struct reqset *requests)/* Specific request select list */
{
	if (requests == (struct reqset *) 0 ) {	
		if (flags & SHO_R_ALLUID) return (1);
		else {
			if (qentry->uid == whomuid) {
				return (1);	/* Request will be shown */
			}
			return (0);		/* Request will not be shown */
		}
	}
	/*
	 *  Scan specific request set.
	 */
	do {
		if ((flags & SHO_R_ALLUID) || qentry->uid == whomuid) {
			/*
			 *  Might be one of the requests we are looking for.
			 */
			if (requests->selecttype == SEL_REQNAME) {
				/*
				 *  Selection is by request name.
				 */
				if (strncmp (requests->v.reqname,
					     qentry->reqname_v,
					     MAX_REQNAME) == 0) {
					return (1);	/* A match */
				}
			}
			else {
				/*
				 *  Selection is by request-id.
				 */
                                /*
                                 * If the seqno is 0, we are looking for
                                 * requests that originated on the machine.
                                 */
                                if (requests->v.reqid.orig_mid
                                        == qentry->orig_mid &&
                                    requests->v.reqid.orig_seqno
                                        == 0) {
                                        return (1);     /* A match */
                                }
                                if (requests->v.reqid.orig_mid
                                        == qentry->orig_mid &&
                                    requests->v.reqid.orig_seqno
                                        == qentry->orig_seqno) {
                                        return (1);     /* A match */
				}
			}
		}
		requests = requests->next;	/* Get next request */
						/* in selection set */
	} while (requests != (struct reqset *) 0);	/* until end of set */
	return (0);			/* It wasn't one of the requests */
					/* we are looking for. */
}


/*** shocpulim
 *
 *
 *	void shocpulim():
 *	Display a CPU time limit quota.
 */
static void shocpulim (
	register struct cpulimit *cpu,
	long explicit,
	long infinite,
	struct gendescr *que_descr)
{
	if (infinite == 0) {
		printf ("= [%1lu.%1d, %1lu.%1d]",
			 cpu->max_seconds, cpu->max_ms,
			 cpu->warn_seconds, cpu->warn_ms);
		if (explicit == 0) printf ("<DEFAULT>");
	}
	else {
		/*
		 *  The limit is infinite, or is not specified.
		 */
		if (que_descr->v.que.type == QUE_BATCH || explicit) {
			printf ("= UNLIMITED ");
			if (explicit == 0) printf ("<DEFAULT>");
		}
		else printf ("= UNSPECIFIED");
	}
	putchar ('\n');
}


/*** shogap
 *
 *
 *	void shogap():
 *	Display a gap in between requests we are interested in.
 */
static void shogap (
	int gaplow,
	int gaphigh,
	char * state,
	int flags)
{
        if (flags & SHO_R_MONSANTO) return;
	if (gaplow > gaphigh) return;
	if (gaplow == gaphigh) printf ("<1 request %s>\n", state);
	else printf ("<%d requests %s>\n", gaphigh - gaplow + 1, state);
}


/*** shogrp
 *
 *
 *	void shogrp():
 *	Display a group name.
 */
static void shogrp (unsigned long gid)
{
	if (acccolumn >= 4) {
		acccolumn = 0;
		printf ("\n    ");
	}
	else printf ("%s\t", getgrpnam ((int) gid));
	acccolumn++;
}


/*** shokey
 *
 *
 *	void shokey():
 *	Display column headings.
 */
static void shokey (struct gendescr *que_descr)
{
        if (que_descr->v.que.type == QUE_DEVICE) {
                printf ("         REQUEST NAME        REQUEST ID            ");
                printf ("USER  PRI    STATE     SIZE\n");
                return;
        }
        printf ("         REQUEST NAME        REQUEST ID            ");
        printf ("USER  PRI    STATE     PGRP\n");
}


/*** shoomd
 *
 *
 *	void shoomd():
 *	Display an output mode.
 */
static void shoomd (char mode)
{
	if (mode & OMD_SPOOL) {
		printf ("SPOOL\n");
	}
	else if (mode & OMD_EO) {
		printf ("EO\n");
	}
	else printf ("NOSPOOL\n");
}


/*** shoqueacc
 *
 *
 *	void shoqueacc():
 *	Display the groups and users allowed to access a queue.
 */
static void shoqueacc (
	struct confd *file,
	struct gendescr *que_descr)
{
	void shousr();			/* Show user */
	
	int fd;				/* File descriptor */
	unsigned long buffer [QAFILE_CACHESIZ];
	int done;			/* Boolean */
	int cachebytes;			/* Try to read this much */
	int bytes;			/* Did read this much */
	int entries;			/* Did read this many */
	int i;				/* Loop variable */


	fd = openqacc (file, que_descr);
	/*
	 * Openqacc returns 0 if the queue is restricted and the file
	 * is open; -1 if the queue is unrestricted; -2 if the queue
	 * queue is restricted but the file is not open, and -3
	 * if the queue appears to have been deleted.
	 */
	if (fd < -1) {
		printf ("  Failed to open queue access file.\n");
		return;
	}
	if (fd == -1) {
		printf ("  Unrestricted access\n");
		return;
	}
	printf ("  Groups with access:  ");
	acccolumn = 2;
	done = 0;
	cachebytes = QAFILE_CACHESIZ * sizeof (unsigned long);
	while ((bytes = read (fd, (char *) buffer, cachebytes)) > 0) {
		entries = bytes / sizeof (unsigned long);
		for (i = 0; i < entries; i++) {
			/* Zero comes only at the end */
			if (buffer [i] == 0) {
				done = 1;
				break;
			}
			if ((buffer [i] & MAKEGID) != 0) /* A group */
				shogrp (buffer [i] & ~MAKEGID);
		}
		if (done) break;
	}
	putchar ('\n');
	lseek (fd, 0, 0);			/* Back to the beginning */
	printf ("  Users with access:  ");
	acccolumn = 2;
	done = 0;
	shousr ((unsigned long) 0);		/* Root always has access */
	while ((bytes = read (fd, (char *) buffer, cachebytes)) > 0) {
		entries = bytes / sizeof (unsigned long);
		for (i = 0; i < entries; i++) {
			/* Zero comes only at the end */
			if (buffer [i] == 0) {
				done = 1;
				break;
			}
			if ((buffer [i] & MAKEGID) == 0) /* Not a group */
				shousr (buffer [i]);
		}
		if (done) break;
	}
	putchar ('\n');
}


/*** shoquedesmap
 *
 *
 *	void shoquedesmap():
 *	Display the destination set for a pipe queue.
 */
static void shoquedesmap (
	struct gendescr *que_descr,	/* The queue descriptor */
	struct confd *qmapfile,		/* Queue/device/destination mapping */
					/* database file */
	struct confd *pipeqfile)	/* Pipe-destination database file */
{
	register struct gendescr *dbds1;/* NQS database file generic descr */
	register struct gendescr *dbds2;/* NQS database file generic descr */
	register short column;		/* Current output column */
	register short fldsiz;		/* Size of output field */
	short preamble;			/* Display flag */
	short first;			/* Display flag */
	char *rhostname;		/* Remote host destination name */
	
	if (telldb (qmapfile) != -1) {
		/*
		 *  We are not necessarily at the start of the
		 *  queue/device/destination descriptor database
		 *  file....
		 */
		seekdbb (qmapfile, 0L);	/* Seek to the beginning */
	}
	dbds1 = nextdb (qmapfile);
	preamble = 0;		/* "Destset = [" not displayed yet */
	first = 1;		/* If destination displayed, it will */
				/* be the first in the set */
	while (dbds1 != (struct gendescr *) 0) {
		if (!dbds1->v.map.qtodevmap &&
		    strcmp (dbds1->v.map.v.qdestmap.lqueue,
			    que_descr->v.que.namev.name) == 0) {
			/*
			 *  We have located a pipe-queue/destination mapping
			 *  for the pipe queue.
			 *
			 *  Now, locate the database description for the
			 *  pipe queue destination referenced in the mapping.
			 */
			if (telldb (pipeqfile) != -1) {
				/*
				 *  We are not necessarily at the start of the
				 *  pipe queue descriptor database file....
				 */
				seekdbb (pipeqfile, 0L);/* Seek to start */
			}
			dbds2 = nextdb (pipeqfile);
			while (dbds2 != (struct gendescr *) 0 &&
			      (strcmp (dbds1->v.map.v.qdestmap.rqueue,
				       dbds2->v.dest.rqueue) ||
			       dbds1->v.map.v.qdestmap.rhost_mid !=
			       dbds2->v.dest.rhost_mid)) {
				/*
				 *  We have not yet located the pipe queue
				 *  destination referred to in the mapping
				 *  descriptor.
				 */
				dbds2 = nextdb (pipeqfile);
			}
			if (dbds2 != (struct gendescr *) 0) {
			    /*
			     *  We have located the pipe-queue
			     *  descriptor for the mapping.
			     */
			    if (!preamble) {
				/*
				 *  Display destination set
				 *  header.
				 */
				preamble = 1;
				printf ("  Destset = {");
				column = DESTSET_MARGIN; /* From 0 */
			    }
			    rhostname = getmacnam (dbds2->v.dest.rhost_mid);
			    if (!(dbds2->v.dest.status & DEST_ENABLED) &&
				 (dbds2->v.dest.status & DEST_RETRY)) {
				/*
				 *  The destination is in the retry
				 *  state.  Show the time of the
				 *  next earliest retry, and the
				 *  time of the first failure.
				 */
				if (column != DESTSET_MARGIN) {
					printf (",\n%*s", DESTSET_MARGIN, "");
				}
				printf ("%s@%s [RETRY]\n",
					dbds2->v.dest.rqueue, rhostname);
				printf ("%*s<Unreachable since: %s>\n",
					DESTSET_MARGIN+4, "",
					fmttime (&dbds2->v.dest.retrytime));
				printf ("%*s<Next retry at: %s>\n%*s",
					DESTSET_MARGIN+4, "",
					fmttime (&dbds2->v.dest.retry_at),
					DESTSET_MARGIN, "");
				column = DESTSET_MARGIN;
			    }
			    else {
				/*
				 *  The destination is either enabled,
				 *  or has been marked as failed.
				 */
				fldsiz = strlen (dbds2->v.dest.rqueue)
				       + strlen (rhostname) + 1;
				if (dbds2->v.dest.status & DEST_FAILED) {
					/*
					 *  This destination has been
					 *  marked as failed.
					 */
					fldsiz += 9;	/* _[FAILED] */
				}
				if (!first) {
					putchar (',');
					fldsiz += 2;	/*+2 for ', '*/
				}
				if (column + fldsiz >= OUTPUT_WIDTH) {
					printf ("\n%*s", DESTSET_MARGIN, "");
					column = fldsiz + DESTSET_MARGIN;
					if (!first) column -= 2;
				}
				else {
					if (!first) putchar (' ');
					column += fldsiz;
				}
				printf ("%s@%s", dbds2->v.dest.rqueue,
					rhostname);
				if (dbds2->v.dest.status & DEST_FAILED) {
					printf (" [FAILED]");
				}
			    }
			    first = 0;		/* Not the first */
			}
		}
		dbds1 = nextdb (qmapfile);
	}
	if (preamble) printf ("};\n");
}


/*** shoquehdr
 *
 *
 *	void shoquehdr():
 *	Display the queue header.
 */
static void shoquehdr (
	struct confd *file,		/* NQS queue file containing.... */
	struct gendescr *que_descr,	/* The Queue-descriptor */
	short dae_present,		/* Non-zero if the local NQS daemon */
					/* is present and running */
	long flags,			/* Display mode flags */
	char *hostname,			/* Name of local host */
	struct confd *qmapfile,		/* Queue/device/destination mapping */
					/* database file */
	struct confd *pipeqfile,	/* Pipe-destination database file */
	struct confd *qcomplexfile)     /* Queue complex definition file */
{
        struct gendescr *qcom_descr;    /* A queue-complex-descriptor */
        register char *namep, *qname;
        register int i, found;


	if (flags & SHO_R_MONSANTO ) return;
	/* ---------------------------------------------------------------
	 * Here is where we print the queue name -- it can be long enough
	 * to wrap around ....
	 */

	printf ("%s@%s;  type=", que_descr->v.que.namev.name, hostname);
	switch (que_descr->v.que.type) {
	case QUE_BATCH:
		printf ("BATCH");
		break;
	case QUE_DEVICE:
		printf ("DEVICE");
		break;
	case QUE_PIPE:
		printf ("PIPE");
		break;
	case QUE_NET:
		printf ("NETWORK");
		break;
	default:
		printf ("UNKNOWN");
		break;
	}
	printf (";  [");
	if (que_descr->v.que.status & QUE_ENABLED) {
		if (dae_present) printf ("ENABLED, ");
		else printf ("CLOSED, ");
	}
	else printf ("DISABLED, ");
	if (que_descr->v.que.status & QUE_RUNNING) {
		if (!dae_present) printf ("SHUTDOWN");
		else if (que_descr->v.que.runcount) printf ("RUNNING");
		else printf ("INACTIVE");
	}
	else if (que_descr->v.que.runcount && dae_present) printf ("STOPPING");
	else printf ("STOPPED");
	fputs ("];", stdout);
	if (que_descr->v.que.status & QUE_PIPEONLY) {
		fputs ("  PIPEONLY;", stdout);
	}
	printf ("  pri=%1d", que_descr->v.que.priority);
        printf ("  lim=");
        switch (que_descr->v.que.type) {
        case QUE_BATCH:
                printf ("%1d\n", que_descr->v.que.v1.batch.runlimit);
                printf (" %2d exit;  ", que_descr->v.que.departcount);
                printf ("%2d run;  ", que_descr->v.que.runcount);
                printf ("%2d stage;  ", que_descr->v.que.stagecount);
                break;
        case QUE_DEVICE:
                printf ("1\n");
                break;
        case QUE_PIPE:
                printf ("%1d\n", que_descr->v.que.v1.pipe.runlimit);
                printf (" %2d depart;  ", que_descr->v.que.departcount);
                printf ("%2d route;  ", que_descr->v.que.runcount);
                break;
        case QUE_NET:
                printf ("%1d\n", que_descr->v.que.v1.network.runlimit);
                printf (" %2d run;  ", que_descr->v.que.runcount);
                break;
        }
	printf ("%2d queued;  ", que_descr->v.que.queuedcount);
	printf ("%2d wait;  ", que_descr->v.que.waitcount);
	printf ("%2d hold;  ", que_descr->v.que.holdcount);
	printf ("%2d arrive;\n", que_descr->v.que.arrivecount);
        if (flags & SHO_H_DEST) {
	    if (que_descr->v.que.type == QUE_BATCH) 
	        printf("  User run limit= %1d\n", 
			que_descr->v.que.v1.batch.userlimit);
	}
	if (flags & SHO_H_DEST) {
            if (que_descr->v.que.type == QUE_PIPE) {
	        if (que_descr->v.que.status & QUE_LDB_IN )
	             fputs ("  Load balanced inbound.\n", stdout);
	        else if (que_descr->v.que.status & QUE_LDB_OUT)
	             fputs ("  Load balanced outbound.\n", stdout);
	    }
	}
	if (flags & SHO_H_TIME) {
		shoquetime (que_descr);
	}
	if (flags & SHO_H_ACCESS && que_descr->v.que.type != QUE_NET) {
		shoqueacc (file, que_descr);
	}
	if (flags & SHO_H_SERV && que_descr->v.que.type == QUE_PIPE) {
		printf ("  Queue server: %s\n",
			que_descr->v.que.v1.pipe.server);
	}
	if (flags & SHO_H_MAP && que_descr->v.que.type == QUE_DEVICE) {
		shoquedevmap (que_descr, qmapfile);
	}
	else if (flags & SHO_H_DEST && que_descr->v.que.type == QUE_PIPE) {
		shoquedesmap (que_descr, qmapfile, pipeqfile);
	}
        if (que_descr->v.que.type == QUE_BATCH) {
                found = 0;
                if (telldb (qcomplexfile) != -1) {
                        seekdbb (qcomplexfile, 0L);     /* Seek to beginning */
                }
                qname = que_descr->v.que.namev.name;
                while ((qcom_descr = nextdb( qcomplexfile )) !=
                      (struct gendescr *)0) {
                        for (i = 0; i < MAX_QSPERCOMPLX; i++) {
                                namep = qcom_descr->v.qcom.queues[i];
                                if (*namep == '\0') continue;
                                if (strcmp(namep, qname) != 0) continue;
                                if (!found) {
                                        printf("  Queue Complex Membership:");
                                }
                                found = 1;
                                printf("  %s;", qcom_descr->v.qcom.name);
                        }
                }
                if (found) putchar('\n');
                if (flags & SHO_H_LIM) {
                        shoquelims (que_descr);
                }
        }
	putchar ('\n');				/* Leave one blank line */
}


/*** shoquelims
 *
 *
 *	void shoquelims():
 *	Display the limits associated with a queue.
 */
static void shoquelims (struct gendescr *que_descr)
{
static char *unlimited = "UNLIMITED";
static char *def = " <DEFAULT>";

#if	(VALID_LIMITS & LIM_PRDRIVES)
	printf ("  Per-request tape drives limit = ");
	if (que_descr->v.que.v1.batch.infinite & LIM_PRDRIVES) {
		fputs (unlimited, stdout);
	}
	else printf ("%1d", que_descr->v.que.v1.batch.prdrives);
	if (!(que_descr->v.que.v1.batch.explicit & LIM_PRDRIVES)) {
		fputs (def, stdout);
	}
	putchar ('\n');
#endif
#if	(VALID_LIMITS & LIM_PPCORE)
	printf ("  Per-process core file size limit = ");
	if (que_descr->v.que.v1.batch.infinite & LIM_PPCORE) {
		fputs (unlimited, stdout);
	}
	else {
		printf ("%1lu %s",
			que_descr->v.que.v1.batch.ppcorecoeff,
			get_units (que_descr->v.que.v1.batch.ppcoreunits));
	}
	if (!(que_descr->v.que.v1.batch.explicit & LIM_PPCORE)) {
		fputs (def, stdout);
	}
	putchar ('\n');
#endif
#if	(VALID_LIMITS & LIM_PPDATA)
	printf ("  Per-process data size limit = ");
	if (que_descr->v.que.v1.batch.infinite & LIM_PPDATA) {
		fputs (unlimited, stdout);
	}
	else {
		printf ("%1lu %s",
			que_descr->v.que.v1.batch.ppdatacoeff,
			get_units (que_descr->v.que.v1.batch.ppdataunits));
	}
	if (!(que_descr->v.que.v1.batch.explicit & LIM_PPDATA)) {
		fputs (def, stdout);
	}
	putchar ('\n');
#endif
#if	(VALID_LIMITS & LIM_PPPFILE)
	printf ("  Per-process permanent file ");
	printf ("size limit = ");
	if (que_descr->v.que.v1.batch.infinite & LIM_PPPFILE) {
		fputs (unlimited, stdout);
	}
	else {
		printf ("%1lu %s",
			que_descr->v.que.v1.batch.pppfilecoeff,
			get_units (que_descr->v.que.v1.batch.pppfileunits));
	}
	if (!(que_descr->v.que.v1.batch.explicit & LIM_PPPFILE)) {
		fputs (def, stdout);
	}
	putchar ('\n');
#endif
#if	(VALID_LIMITS & LIM_PRPFILE)
	printf ("  Per-request permanent file ");
	printf ("space limit = ");
	if (que_descr->v.que.v1.batch.infinite & LIM_PRPFILE) {
		fputs (unlimited, stdout);
	}
	else {
		printf ("%1lu %s",
			que_descr->v.que.v1.batch.prpfilecoeff,
			get_units (que_descr->v.que.v1.batch.prpfileunits));
	}
	if (!(que_descr->v.que.v1.batch.explicit & LIM_PRPFILE)) {
		fputs (def, stdout);
	}
	putchar ('\n');
#endif
#if	(VALID_LIMITS & LIM_PPMEM)
	printf ("  Per-process memory size limit = ");
	if (que_descr->v.que.v1.batch.infinite & LIM_PPMEM) {
		fputs (unlimited, stdout);
	}
	else {
		printf ("%1lu %s", que_descr->v.que.v1.batch.ppmemcoeff,
			get_units (que_descr->v.que.v1.batch.ppmemunits));
	}
	if (!(que_descr->v.que.v1.batch.explicit & LIM_PPMEM)) {
		fputs (def, stdout);
	}
	putchar ('\n');
#endif
#if	(VALID_LIMITS & LIM_PRMEM)
	printf ("  Per-request memory size limit = ");
	if (que_descr->v.que.v1.batch.infinite & LIM_PRMEM) {
		fputs (unlimited, stdout);
	}
	else {
		printf ("%1lu %s", que_descr->v.que.v1.batch.prmemcoeff,
			get_units (que_descr->v.que.v1.batch.prmemunits));
	}
	if (!(que_descr->v.que.v1.batch.explicit & LIM_PRMEM)) {
		fputs (def, stdout);
	}
	putchar ('\n');
#endif
#if	SGI
        printf ("  Queue nondegrading priority = ");
        printf ("%4d ", que_descr->v.que.ndp);
        putchar ('\n');
#endif

#if	(VALID_LIMITS & LIM_PPNICE)
	printf ("  Per-process execution nice value = ");
	if (que_descr->v.que.v1.batch.infinite & LIM_PPNICE) {
		fputs (unlimited, stdout);
	}
	else printf ("%1d", que_descr->v.que.v1.batch.ppnice);
	if (!(que_descr->v.que.v1.batch.explicit & LIM_PPNICE)) {
		fputs (def, stdout);
	}
	putchar ('\n');
#endif
#if	(VALID_LIMITS & LIM_PRNCPUS)
	printf ("  Per-request number of cpus limit = ");
	if (que_descr->v.que.v1.batch.infinite & LIM_PRNCPUS) {
		fputs (unlimited, stdout);
	}
	else printf ("%1d", que_descr->v.que.v1.batch.prncpus);
	if (!(que_descr->v.que.v1.batch.explicit & LIM_PRNCPUS)) {
		fputs (def, stdout);
	}
	putchar ('\n');
#endif
#if	(VALID_LIMITS & LIM_PPQFILE)
	printf ("  Per-process quick file ");
	printf ("size limit = ");
	if (que_descr->v.que.v1.batch.infinite & LIM_PPQFILE) {
		fputs (unlimited, stdout);
	}
	else {
		printf ("%1lu %s",
			que_descr->v.que.v1.batch.ppqfilecoeff,
			get_units (que_descr->v.que.v1.batch.ppqfileunits));
	}
	if (!(que_descr->v.que.v1.batch.explicit & LIM_PPQFILE)) {
		fputs (def, stdout);
	}
	putchar ('\n');
#endif
#if	(VALID_LIMITS & LIM_PRQFILE)
	printf ("  Per-request quick file ");
	printf ("space limit = ");
	if (que_descr->v.que.v1.batch.infinite & LIM_PRQFILE) {
		fputs (unlimited, stdout);
	}
	else {
		printf ("%1lu %s",
			que_descr->v.que.v1.batch.prqfilecoeff,
			get_units (que_descr->v.que.v1.batch.prqfileunits));
	}
	if (!(que_descr->v.que.v1.batch.explicit & LIM_PRQFILE)) {
		fputs (def, stdout);
	}
	putchar ('\n');
#endif
#if	(VALID_LIMITS & LIM_PPSTACK)
	printf ("  Per-process stack size limit = ");
	if (que_descr->v.que.v1.batch.infinite & LIM_PPSTACK) {
		fputs (unlimited, stdout);
	}
	else {
		printf ("%1lu %s",
			que_descr->v.que.v1.batch.ppstackcoeff,
			get_units (que_descr->v.que.v1.batch.ppstackunits));
	}
	if (!(que_descr->v.que.v1.batch.explicit & LIM_PPSTACK)) {
		fputs (def, stdout);
	}
	putchar ('\n');
#endif
#if	(VALID_LIMITS & LIM_PPCPUT)
	printf ("  Per-process CPU time limit = ");
	if (que_descr->v.que.v1.batch.infinite & LIM_PPCPUT) {
		fputs (unlimited, stdout);
	}
	else {
		printf ("%1lu.%1d", que_descr->v.que.v1.batch.ppcpusecs,
			que_descr->v.que.v1.batch.ppcpums);
	}
	if (!(que_descr->v.que.v1.batch.explicit & LIM_PPCPUT)) {
		fputs (def, stdout);
	}
	putchar ('\n');
#endif
#if	(VALID_LIMITS & LIM_PRCPUT)
	printf ("  Per-request CPU time limit = ");
	if (que_descr->v.que.v1.batch.infinite & LIM_PRCPUT) {
		fputs (unlimited, stdout);
	}
	else {
		printf ("%1lu.%1d", que_descr->v.que.v1.batch.prcpusecs,
			que_descr->v.que.v1.batch.prcpums);
	}
	if (!(que_descr->v.que.v1.batch.explicit & LIM_PRCPUT)) {
		fputs (def, stdout);
	}
	putchar ('\n');
#endif
#if	(VALID_LIMITS & LIM_PPTFILE)
	printf ("  Per-process temporary file ");
	printf ("size limit = ");
	if (que_descr->v.que.v1.batch.infinite & LIM_PPTFILE) {
		fputs (unlimited, stdout);
	}
	else {
		printf ("%1lu %s",
			que_descr->v.que.v1.batch.pptfilecoeff,
			get_units (que_descr->v.que.v1.batch.pptfileunits));
	}
	if (!(que_descr->v.que.v1.batch.explicit & LIM_PPTFILE)) {
		fputs (def, stdout);
	}
	putchar ('\n');
#endif
#if	(VALID_LIMITS & LIM_PRTFILE)
	printf ("  Per-request temporary file ");
	printf ("space limit = ");
	if (que_descr->v.que.v1.batch.infinite & LIM_PRTFILE) {
		fputs (unlimited, stdout);
	}
	else {
		printf ("%1lu %s",
			que_descr->v.que.v1.batch.prtfilecoeff,
			get_units (que_descr->v.que.v1.batch.prtfileunits));
	}
	if (!(que_descr->v.que.v1.batch.explicit & LIM_PRTFILE)) {
		fputs (def, stdout);
	}
	putchar ('\n');
#endif
#if	(VALID_LIMITS & LIM_PPWORK)
	printf ("  Per-process working set limit = ");
	if (que_descr->v.que.v1.batch.infinite & LIM_PPWORK) {
		fputs (unlimited, stdout);
	}
	else {
		printf ("%1lu %s",
			que_descr->v.que.v1.batch.ppworkcoeff,
			get_units(que_descr->v.que.v1.batch.ppworkunits));
	}
	if (!(que_descr->v.que.v1.batch.explicit & LIM_PPWORK)) {
		fputs (def, stdout);
	}
	putchar ('\n');
#endif
}


/*** shoquedevmap
 *
 *
 *	void shoquedevmap():
 *	Display the queue-to-device mappings for a queue.
 */
static void shoquedevmap (
	struct gendescr *que_descr,	/* The queue descriptor */
	struct confd *qmapfile)		/* Queue/device/destination mapping */
					/* database file */
{
	register struct gendescr *dbdsc;/* NQS database file generic descr */
	register short column;		/* Current output column */
	register short fldsiz;		/* Current field size */
	short preamble;			/* Display flag */
	short first;			/* Display flag */
	
	if (telldb (qmapfile) != -1) {
		/*
		 *  We are not necessarily at the start of the database file.
		 */
		seekdbb (qmapfile, 0L);	/* Seek to the beginning */
	}
	dbdsc = nextdb (qmapfile);
	preamble = 0;		/* "Device set = [" not displayed */
	first = 1;		/* If device displayed, it will be */
				/* the first in the set */
	while (dbdsc != (struct gendescr *) 0) {
		if (dbdsc->v.map.qtodevmap) {
			if (strcmp (dbdsc->v.map.v.qdevmap.qname,
				    que_descr->v.que.namev.name) == 0) {
				if (!preamble) {
					/*
					 *  Display device set header.
					 */
					preamble = 1;
					printf ("  Devset = {");
					column = DEVSET_MARGIN;	/* From 0 */
				}
				fldsiz = strlen (dbdsc->v.map.v.qdevmap.dname);
				if (!first) {
					putchar (',');
					fldsiz += 2;	/* +2 for ', '*/
				}
				if (column + fldsiz >= OUTPUT_WIDTH) {
					printf ("\n%*s", DEVSET_MARGIN, "");
					column = fldsiz + DEVSET_MARGIN;
					if (!first) column -= 2;
				}
				else {
					if (!first) putchar (' ');
					column += fldsiz;
				}
				fputs (dbdsc->v.map.v.qdevmap.dname, stdout);
				first = 0;	/* Not the first */
			}
		}
		dbdsc = nextdb (qmapfile);
	}
	if (preamble) printf ("};\n");
}


/*** shoquetime
 *
 *
 *	void shoquetime():
 *	Display the cumulative cpu time used by requests in a queue.
 */
static void shoquetime (struct gendescr *que_descr)
{
	printf ("  Cumulative system space time = ");
#if	HPUX | SGI | SOLARIS | SYS52 | IBMRS | LINUX
	printf ("%ld.%02d seconds\n", (int) (que_descr->v.que.ru_stime / CPU_MEAS_GRAN),
		(int) (((que_descr->v.que.ru_stime % CPU_MEAS_GRAN) * 100) /
		CPU_MEAS_GRAN));
#else
#if	BSD43 | ULTRIX | DECOSF
	printf ("%ld.%06ld seconds\n", que_descr->v.que.ru_stime,
		que_descr->v.que.ru_stime_usec);
#else
BSD SYSTEM TYPE
#endif
#endif
	printf ("  Cumulative user space time = ");
#if	HPUX | SGI | SOLARIS | SYS52 | IBMRS | LINUX
	printf ("%ld.%02d seconds\n", (int) (que_descr->v.que.ru_utime / CPU_MEAS_GRAN),
		(int) (((que_descr->v.que.ru_utime % CPU_MEAS_GRAN) * 100) /
		CPU_MEAS_GRAN));
#else
#if	BSD43 | ULTRIX | DECOSF
	printf ("%ld.%06ld seconds\n", que_descr->v.que.ru_utime,
		que_descr->v.que.ru_utime_usec);
#else
BSD SYSTEM TYPE
#endif
#endif
}


/*** shoquolim
 *
 *
 *	void shoquolim():
 *	Display a quota limit.
 */
static void shoquolim (
	struct quotalimit *quota,
	long explicit,
	long infinite,
	struct gendescr *que_descr)
{
	if (infinite == 0) {
		printf ("= [%1lu %s, %1lu %s]", quota->max_quota,
			get_units (quota->max_units), quota->warn_quota,
			get_units (quota->warn_units));
		if (explicit == 0) printf ("<DEFAULT>");
	}
	else {
		/*
		 *  The limit is infinite, or is not specified.
		 */
		if (que_descr->v.que.type == QUE_BATCH || explicit) {
			printf ("= UNLIMITED ");
			if (explicit == 0) printf ("<DEFAULT>");
		}
		/* Infinite, default limits are meaningless in a pipe queue */
		else printf ("= UNSPECIFIED");
	}
	putchar ('\n');
}


/*** shoreqlims
 *
 *
 *	void shoreqlims():
 *	Display the limits associated with a request.
 */
static void shoreqlims (
	struct gendescr *que_descr,	/* Needed to detect pipe queues */
	struct rawreq *rawreqp)		/* The request as a rawreq */
{
	if (que_descr->v.que.type == QUE_PIPE ||
	   (VALID_LIMITS & LIM_PRDRIVES)) {
		printf ("  Per-req. tape drives limit");
		if ((rawreqp->v.bat.infinite & LIM_PRDRIVES) == 0) {
			printf (" = %1d", rawreqp->v.bat.prdrives);
			if (!(rawreqp->v.bat.explicit & LIM_PRDRIVES)) {
				printf (" <DEFAULT>");
			}
		}
		else printf (" = UNSPECIFIED");
		putchar ('\n');
	}
	if (que_descr->v.que.type == QUE_PIPE ||
	   (VALID_LIMITS & LIM_PPCORE)) {
		printf ("  Per-proc. core file size limit");
		shoquolim (&rawreqp->v.bat.ppcoresize,
			   rawreqp->v.bat.explicit & LIM_PPCORE,
			   rawreqp->v.bat.infinite & LIM_PPCORE,
			   que_descr);
	}
	if (que_descr->v.que.type == QUE_PIPE ||
	   (VALID_LIMITS & LIM_PPDATA)) {
		printf ("  Per-proc. data size limit");
		shoquolim (&rawreqp->v.bat.ppdatasize,
			   rawreqp->v.bat.explicit & LIM_PPDATA,
			   rawreqp->v.bat.infinite & LIM_PPDATA,
			   que_descr);
	}
	if (que_descr->v.que.type == QUE_PIPE ||
	   (VALID_LIMITS & LIM_PPPFILE)) {
		printf ("  Per-proc. permanent file ");
		printf ("size limit");
		shoquolim (&rawreqp->v.bat.pppfilesize,
			   rawreqp->v.bat.explicit & LIM_PPPFILE,
			   rawreqp->v.bat.infinite & LIM_PPPFILE,
			   que_descr);
	}
	if (que_descr->v.que.type == QUE_PIPE ||
	   (VALID_LIMITS & LIM_PRPFILE)) {
		printf ("  Per-req. permanent file ");
		printf ("space limit");
		shoquolim (&rawreqp->v.bat.prpfilespace,
			   rawreqp->v.bat.explicit & LIM_PRPFILE,
			   rawreqp->v.bat.infinite & LIM_PRPFILE,
			   que_descr);
	}
	if (que_descr->v.que.type == QUE_PIPE ||
	   (VALID_LIMITS & LIM_PPMEM)) {
		printf ("  Per-proc. memory size limit");
		shoquolim (&rawreqp->v.bat.ppmemsize,
			   rawreqp->v.bat.explicit & LIM_PPMEM,
			   rawreqp->v.bat.infinite & LIM_PPMEM,
			   que_descr);
	}
	if (que_descr->v.que.type == QUE_PIPE ||
	   (VALID_LIMITS & LIM_PRMEM)) {
		printf ("  Per-req. memory size limit");
		shoquolim (&rawreqp->v.bat.prmemsize,
			   rawreqp->v.bat.explicit & LIM_PRMEM,
			   rawreqp->v.bat.infinite & LIM_PRMEM,
			   que_descr);
	}
	if (que_descr->v.que.type == QUE_PIPE ||
	   (VALID_LIMITS & LIM_PPNICE)) {
		printf ("  Per-proc. execution nice priority");
		if ((rawreqp->v.bat.infinite & LIM_PPNICE) == 0) {
			printf (" = %1d", rawreqp->v.bat.ppnice);
			if (!(rawreqp->v.bat.explicit & LIM_PPNICE)) {
				printf (" <DEFAULT>");
			}
		}
		else printf (" = UNSPECIFIED");
		putchar ('\n');
	}
	if (que_descr->v.que.type == QUE_PIPE ||
	   (VALID_LIMITS & LIM_PRNCPUS)) {
		printf ("  Per-req. # of cpus limit");
		if ((rawreqp->v.bat.infinite & LIM_PRNCPUS) == 0) {
			printf (" = %1d", rawreqp->v.bat.prncpus);
			if (!(rawreqp->v.bat.explicit & LIM_PRNCPUS)) {
				printf (" <DEFAULT>");
			}
		}
		else printf (" = UNSPECIFIED");
		putchar ('\n');
	}
	if (que_descr->v.que.type == QUE_PIPE ||
	   (VALID_LIMITS & LIM_PPQFILE)) {
		printf ("  Per-proc. quick file ");
		printf ("size limit");
		shoquolim (&rawreqp->v.bat.ppqfilesize,
			   rawreqp->v.bat.explicit & LIM_PPQFILE,
			   rawreqp->v.bat.infinite & LIM_PPQFILE,
			   que_descr);
	}
	if (que_descr->v.que.type == QUE_PIPE ||
	   (VALID_LIMITS & LIM_PRQFILE)) {
		printf ("  Per-req. quick file ");
		printf ("space limit");
		shoquolim (&rawreqp->v.bat.prqfilespace,
			   rawreqp->v.bat.explicit & LIM_PRQFILE,
			   rawreqp->v.bat.infinite & LIM_PRQFILE,
			   que_descr);
	}
	if (que_descr->v.que.type == QUE_PIPE ||
	   (VALID_LIMITS & LIM_PPSTACK)) {
		printf ("  Per-proc. stack size limit");
		shoquolim (&rawreqp->v.bat.ppstacksize,
			   rawreqp->v.bat.explicit & LIM_PPSTACK,
			   rawreqp->v.bat.infinite & LIM_PPSTACK,
			   que_descr);
	}
	if (que_descr->v.que.type == QUE_PIPE ||
	   (VALID_LIMITS & LIM_PPCPUT)) {
		printf ("  Per-proc. CPU time limit");
		shocpulim (&rawreqp->v.bat.ppcputime,
			   rawreqp->v.bat.explicit & LIM_PPCPUT,
			   rawreqp->v.bat.infinite & LIM_PPCPUT,
			   que_descr);
	}
	if (que_descr->v.que.type == QUE_PIPE ||
	   (VALID_LIMITS & LIM_PRCPUT)) {
		printf ("  Per-req. CPU time limit");
		shocpulim (&rawreqp->v.bat.prcputime,
			   rawreqp->v.bat.explicit & LIM_PRCPUT,
			   rawreqp->v.bat.infinite & LIM_PRCPUT,
			   que_descr);
	}
	if (que_descr->v.que.type == QUE_PIPE ||
	   (VALID_LIMITS & LIM_PPTFILE)) {
		printf ("  Per-proc. temporary file ");
		printf ("size limit");
		shoquolim (&rawreqp->v.bat.pptfilesize,
			   rawreqp->v.bat.explicit & LIM_PPTFILE,
			   rawreqp->v.bat.infinite & LIM_PPTFILE,
			   que_descr);
	}
	if (que_descr->v.que.type == QUE_PIPE ||
	   (VALID_LIMITS & LIM_PRTFILE)) {
		printf ("  Per-req. temporary file ");
		printf ("space limit");
		shoquolim (&rawreqp->v.bat.prtfilespace,
			   rawreqp->v.bat.explicit & LIM_PRTFILE,
			   rawreqp->v.bat.infinite & LIM_PRTFILE,
			   que_descr);
	}
	if (que_descr->v.que.type == QUE_PIPE ||
	   (VALID_LIMITS & LIM_PPWORK)) {
		printf ("  Per-proc. working set limit");
		shoquolim (&rawreqp->v.bat.ppworkset,
			   rawreqp->v.bat.explicit & LIM_PPWORK,
			   rawreqp->v.bat.infinite & LIM_PPWORK,
			   que_descr);
	}
}


/*** shorequest
 *
 *
 *	void shorequest():
 *	Display a request.
 */
static void shorequest (
	struct qentry *qentry,		/* Queue entry describing request */
	int reqstate,			/* Req state=[HOLDING,RUNNING,QUEUED] */
	struct gendescr *que_descr,	/* Queue file queue-descriptor */
	int nth_request,		/* N-th request number in the queue */
	long flags,			/* Display mode flags */
	char *hostname)			/* Local host name */
{
	char reqname [MAX_REQNAME+1];	/* Name of request */
	char *status;			/* Request status */
	char *machinename;		/* Name of originating machine */
	char *username;			/* User name of request owner */
	struct rawreq rawreq;		/* Control file raw request */
	int cfd;			/* Control file file-descr */
	int chars;			/* String length */
/*	register int i;			   apparently unused	*/

	machinename = getmacnam (qentry->orig_mid);
	username = getusenam (qentry->uid);
	switch (reqstate) {
	case SHO_RS_EXIT:
		if (que_descr->v.que.type == QUE_BATCH) {
			status = "EXITING";
		}
		else if (que_descr->v.que.type == QUE_PIPE) {
			status = "DEPARTING";
		}
		else status = "UNKNOWN";
		break;
	case SHO_RS_RUN:
		if (que_descr->v.que.type == QUE_PIPE) {
			status = "ROUTING";
		} else { 
		    status = "RUNNING";
		    if ((cfd = getreq ((long)qentry->orig_seqno,
				qentry->orig_mid, &rawreq)) != -1) {
			if (rawreq.flags & RQF_SUSPENDED) status = "SUSPENDED";
		    }
		}
		break;
	case SHO_RS_STAGE:
		if (que_descr->v.que.type == QUE_BATCH) {
			status = "STAGING";
		}
		else status = "UNKNOWN";
		break;
	case SHO_RS_QUEUED:
		status = "QUEUED";
		break;
	case SHO_RS_WAIT:
		status = "WAITING";
		break;
	case SHO_RS_HOLD:
		status = "HOLDING";
		break;
	case SHO_RS_ARRIVE:
		status = "ARRIVING";
		break;
	default:
		status = "UNKNOWN";	/* We should never get here */
		break;
	}
	strncpy (reqname, qentry->reqname_v, MAX_REQNAME);
	reqname [MAX_REQNAME] = '\0';	/* Force null termination */
        if (flags & SHO_R_MONSANTO) {
                if (!monsanto_header) {
                        sho_mon_hdr();
                        monsanto_header++;
                }
		if (strlen(reqname) > 14) {
			printf("%s\n", reqname);
			printf("%-14s", " ");
		} else 
			printf ("%-14s", reqname);
                printf ("  %4ld", (long) qentry->orig_seqno);
                chars = strlen (username);
                if (chars > 8) username [8] = '\0';
                printf ("  %-8s", username);
#if SGI | IBMRS | SOLARIS | HPUX
		if (reqstate == SHO_RS_RUN) {
		    if (strlen(que_descr->v.que.namev.name) > 8) {
			printf(" %s\n", que_descr->v.que.namev.name);
			printf(" %-38s", " ");
		    } else 
			printf(" %-8s", que_descr->v.que.namev.name);
		    if ((cfd = getreq ((long)qentry->orig_seqno,
				qentry->orig_mid, &rawreq)) != -1) {
		    	/*
		     	 *  We have a good control file.
		     	 */
			summary(qentry->v.process_family, &rawreq);
		    }
		} else {
		    printf(" %-36s", que_descr->v.que.namev.name);
		    printf("        ");
		}
#else
		printf(" %-36s", que_descr->v.que.namev.name);
		printf("        ");
#endif
                printf (" %1.1s", status);
                putchar ('\n');
        }

	if (flags & SHO_R_STANDARD) {
		if (strlen(reqname) > 15) {
			printf (" %4d:%s\n", nth_request, reqname);
			printf (" %20s", " ");
		} else
			printf (" %4d:%15s", nth_request, reqname);
		chars = strlen (machinename);
		if (chars > 15) machinename [15] = '\0';
		printf (" %9ld.%s", (long) qentry->orig_seqno, machinename);
		for (; chars < 15; chars++) {
			putchar (' ');
		}
		chars = strlen (username);
		if (chars > 8) username [8] = '\0';
		printf (" %8s", username);
		printf (" %3d", qentry->priority);
		printf (" %8s", status);
		if (que_descr->v.que.type == QUE_DEVICE) {
			/*
			 *  For device queues we show the request size, and
			 *  not the process-family.
			 */
			printf ("%9lu", qentry->size);
		}
		else if (reqstate == SHO_RS_RUN &&
			 qentry->reqname_v [MAX_REQNAME]) {
			/*
			 *  For non-device queues, we show the process-family,
			 *  and not the request size.
			 *
			 *  Qentry->reqname_v [MAX_REQNAME] is used as a flag,
			 *  telling whether the process family field is valid
			 *  yet.
			 */
			printf ("%9ld", qentry->v.process_family);
		}
		putchar ('\n');
	}
	else if ( flags & SHO_R_LONG) { /* qstat -m or -l */
		printf ("  Request %4d:", nth_request);
		printf ("  Name=%s\n", reqname);
		printf ("  Id=%1ld.%s", (long) qentry->orig_seqno,
			machinename);
		printf ("     Owner=%s  Priority=%1d  %s  ", username,
			qentry->priority, status);
		if (reqstate == SHO_RS_RUN) {
			/*
		 	 *  The request is running or is being spawned.  Try
		 	 *  to show the process family (group).
		 	 */
			if (qentry->reqname_v [MAX_REQNAME]) {
				/*
				 *  The process-family field validity byte is
				 *  set.  Show the process-family.
				 */
				printf ("Pgrp=%ld  ",
					qentry->v.process_family);
			}
		}
		else if (reqstate == SHO_RS_WAIT) {
			/*
			 *  Show the -a time.
			 */
			printf ("%s  ", fmttime (&qentry->v.start_time));
		}
		if (que_descr->v.que.type == QUE_DEVICE) {
			printf ("Size=%lu", qentry->size);
		}
		putchar ('\n');
	}
	if (flags & SHO_R_LONG) {
		if ((cfd = getreq ((long)qentry->orig_seqno, qentry->orig_mid,
				    &rawreq)) != -1) {
		    /*
		     *  We have a good control file.
		     */
		    printf ("  Created at %s\n",
			    fmttime (&rawreq.create_time));
		    if (que_descr->v.que.type == QUE_PIPE) {
			if (rawreq.start_time > 0) {
			    printf ("  Execute after %s\n",
				    fmttime (&rawreq.start_time));
			}
		    }
		    fputs ("  Mail = [", stdout);
		    if (rawreq.flags & RQF_BEGINMAIL) {
			if (rawreq.flags & RQF_ENDMAIL)
				fputs ("BEGIN, END]\n", stdout);
			else fputs ("BEGIN]\n", stdout);
		    }
		    else if (rawreq.flags & RQF_ENDMAIL) {
			fputs ("END]\n", stdout);
		    }
		    else fputs ("NONE]\n", stdout);
		    /*
		     *  Show where the mail will be sent.
		     */
		    printf ("  Mail address = %s@%s\n", rawreq.mail_name,
			    getmacnam (rawreq.mail_mid));
		    printf ("  Owner user name at originating ");
		    printf ("machine = %s\n", rawreq.username);
		    /*
		     * Show restart information.
		     */
		    fputs ("  Request is ", stdout);
		    if ( !(rawreq.flags & RQF_RESTARTABLE))
			    fputs ("not", stdout);
		    fputs("restartable, ", stdout);
		    if ( !(rawreq.flags & RQF_RECOVERABLE))
			    fputs ("not",  stdout);
		    fputs ("recoverable.\n", stdout);
		    /*
		     * Show broadcast information.
		     */
		    fputs ("  Broadcast = [", stdout);
		    if (rawreq.flags & RQF_BEGINBCST) {
			if (rawreq.flags & RQF_ENDBCST)
				fputs ("BEGIN, END]\n", stdout);
			else fputs ("BEGIN]\n", stdout);
		    }
		    else if (rawreq.flags & RQF_ENDBCST) {
			fputs ("END]\n", stdout);
		    }
		    else fputs ("NONE]\n", stdout);
		    /*
		     *  Show request-type dependent information.
		     */
		    if (rawreq.type == RTYPE_DEVICE) {
			/*
			 *  The request is a device-oriented request.
			 */
			printf ("  Forms = ");
			if (rawreq.v.dev.forms [0] == '\0') printf ("DEFAULT");
			else fputs (rawreq.v.dev.forms, stdout);
			printf (";  Copies = %1d\n", rawreq.v.dev.copies);
		    }
		    else {
			/*
			 *  The request is not device-oriented.
			 *  The request is a batch request requiring
			 *  only the resource of a CPU.
			 */
			shoreqlims (que_descr, &rawreq);
			printf ("  Standard-error access mode = ");
			shoomd (rawreq.v.bat.stderr_acc);
			if ((rawreq.v.bat.stderr_acc & OMD_EO) == 0) {
			    if (rawreq.v.bat.stderr_acc & OMD_M_KEEP) {
				if (que_descr->v.que.type == QUE_BATCH) {
				    /*
				     *  Use the name of the local host.
				     */
				    machinename = hostname;
				}
				else machinename = "<execution-host>";
			    }
			    else {
				machinename=getmacnam(rawreq.v.bat.stderr_mid);
			    }
			    printf ("  Standard-error name = %s:%s\n",
				    machinename, rawreq.v.bat.stderr_name);
			}
			printf ("  Standard-output access mode = ");
			shoomd (rawreq.v.bat.stdout_acc);
			if (rawreq.v.bat.stdout_acc & OMD_M_KEEP) {
			    if (que_descr->v.que.type==QUE_BATCH) {
				/*
				 *  Use the name of the local
				 *  host.
				 */
				machinename = hostname;
			    }
			    else machinename = "<execution-host>";
			}
			else {
			    machinename = getmacnam (rawreq.v.bat.stdout_mid);
			}
			printf ("  Standard-output name = %s:%s\n",
				machinename, rawreq.v.bat.stdout_name);
			printf ("  Shell = ");
			if (rawreq.v.bat.shell_name [0] == '\0') {
			    printf ("DEFAULT\n");
			}
			else {	/* An explicit shell spec is given */
			    fputs (rawreq.v.bat.shell_name, stdout);
			    putchar ('\n');
			}
			printf ("  Umask = %3o\n", rawreq.v.bat.umask);
			putchar ('\n');	/* Blank line separator */
		    }
		    close (cfd);		/* Close the control file */
		}
		else if (reqstate == SHO_RS_RUN) {
		    printf ("\n  <exiting>\n\n");
		}
		else {
		    printf ("\n  update in progress");
		    printf (" for sequence number: %ld, Machine id %u errno returned: %d\n",  
			(long)qentry->orig_seqno, qentry->orig_mid, errno);
		}
	}
}


/*** shousr
 *
 *
 *	void shousr():
 *	Display a user name.
 */
static void shousr (unsigned long uid)
{
	if (acccolumn >= 4) {
		acccolumn = 0;
		printf ("\n    ");
	}
	printf ("%s\t", getusenam ((int) uid));
	acccolumn++;
}

/***
 *
 *
 *      void shotitle():
 *      Show display title
 *
 */
static void shotitle (char *string1, char *string2)
{
        register int hdlen;
        register int chars;
        char string [48];

        sprintf (string, "NQS %-37.37s",  string1);
        hdlen = 5  + strlen(string1);

        for (chars = hdlen; chars>0; chars--)    fputs ("-\0", stdout);
	printf("\n");
        printf ("%s", string);
        if (string2 [0] != '\0')
                printf ("%s", string2);
	printf("\n");
        for (chars = hdlen; chars>0; chars--)    fputs ("-\0", stdout);
        for (chars = 48 - hdlen; chars >0; chars--)     fputs (" \0", stdout);
}

/*** shoqueline
 *
 *
 *      void shoqueline():
 *      Display queue summary separator line
 */
static void shoqueline (short queue_type, long flags)
{
        printf ("----------------------- ");
        switch (queue_type)     {
        case QUE_BATCH:
                        printf ("%s", short_line);
                                printf ("%s", long_line);

                        printf ("--- ---");
                        printf (" ----- -----");

                        printf (" ---");
                        printf (" ---");
              break;
        case QUE_DEVICE:
        case QUE_PIPE:
                printf ("%s", short_line);
                        printf ("%s", long_line);
                        printf ("  -------------");
                break;
        default:
                break;
        }
	printf("\n");
}

#if 	TAMU
#include <sys/types.h>
#include <sys/dir.h>
	/* for IRIX 6, avoid 64 bit KMEM , and go straight to /proc */
static summary(
	pid_t	proc_family,		/* process family */
	struct  rawreq	*rawreqp)
{
	struct	tm  *start_tm;
	int	status;
	int	days, hours, minutes;
	int	max_time;
        int     fd;
        int     retval;
	prpsinfo_t prpsinfo;
        char char_pid[32];
	pid_t	sesid;
	DIR 	*dirp;
	struct direct *dir;

	total_time = start_time = 0;

	/* use /proc to read leader info directly */
        sprintf(char_pid, "/proc/pinfo/%05d", proc_family);
        fd = open (char_pid, O_RDONLY);
        if (fd != -1) {
	    retval = ioctl(fd, PIOCPSINFO, &prpsinfo);
	    start_time = prpsinfo.pr_start.tv_sec;
	    sesid = prpsinfo.pr_sid;
            close (fd);
        }

	/* walk /proc, accumulating time for all procs in sesid */
	dirp = opendir("/proc/pinfo");
	while ((dir = readdir(dirp)) != NULL) {
		sprintf(char_pid, "/proc/pinfo/%s",dir->d_name);
		fd = open(char_pid,O_RDONLY);
		if (fd != -1) {
			retval = ioctl(fd,PIOCPSINFO, &prpsinfo);
			if (prpsinfo.pr_sid == sesid) {
				total_time += prpsinfo.pr_time.tv_sec
					   +  prpsinfo.pr_ctime.tv_sec;
			}
			close(fd);
		}
	}

	if ( start_time ) {
	    start_tm = localtime(&start_time);
	    printf(" %2d/%2.2d %2.2d:%2.2d", start_tm->tm_mon+1,
			start_tm->tm_mday,
			start_tm->tm_hour,
			start_tm->tm_min);
	} else {
	    printf("            ");
	}
	/*
	 * Calculate and print the per process max time.
	 */
	max_time = rawreqp->v.bat.ppcputime.max_seconds;
	days = max_time / (24 * 60 * 60);
	max_time -= days * 24 * 60 * 60;
	hours = max_time / (60 * 60);
	max_time -= hours * 60 * 60;
	minutes = max_time / 60;
	max_time -= minutes * 60;
	printf("  %3d %2d:%2.2d", days, hours, minutes);
	/*
	 * Calculate and print the total time used by all processes.
	 */
	if ( total_time ) {
	    days = total_time / (24 * 60 * 60);
	    total_time -= days * 24 * 60 * 60;
	    hours = total_time / (60 * 60);
	    total_time -= hours * 60 * 60;
	    minutes = total_time / 60;
	    total_time -= minutes * 60;
	    if (days > 9)
	        printf("   %3d %2d:%2.2d ", days, hours, minutes);
	    else
	        printf("   %d %2d:%2.2d:%2.2d", days, hours, minutes, total_time);
	} else {
	    printf("             ");
	}
}


#else
#if	SGI

static summary(
	pid_t	proc_family,		/* process family */
	struct  rawreq	*rawreqp)
{

	struct	tm  *start_tm;
	int	status;
	struct proc *poffset;
	pid_t	pid_oi;
	struct	proc   proc_buff;
	int	days, hours, minutes;
	int	max_time;

	total_time = start_time = 0;
	pid_oi = proc_family;

#if	DEBUG_QSTAT
	printf( "pid is %d\n", pid_oi);
#endif
	procsize = sysmp(MP_KERNADDR,  MPKA_PROCSIZE);
#if	DEBUG_QSTAT
	printf ("Procsize is %d\n", procsize);
#endif
	poffset = (struct proc *)sysmp(MP_KERNADDR,  MPKA_PROC);
#if	DEBUG_QSTAT
	printf ("pointer is %x (or %d)\n", poffset, poffset);
#endif
	memfd = open (KMEM, O_RDONLY);
	if (memfd == -1) {
		perror("Open");
		exit(1);
	}
	poffset = (struct proc *) ( (int) poffset & ~0x80000000);
#if	DEBUG_QSTAT
	printf ("pointer is %x (or %d)\n", poffset, poffset);
#endif
	status = lseek(memfd, (int) poffset, SEEK_SET);
	if (status != (int) poffset) {
		perror("Lseek");
		exit(1);
	}
	status = read (memfd, &proc_buff, procsize);
	if (status != procsize) {
		perror ("Read");
		exit(1);
	}
	poffset =  proc_buff.p_child;
	do_count = 0;
	get_node(poffset, pid_oi, proc_family);
  
	if ( start_time ) {
	    start_tm = localtime(&start_time);
	    printf(" %2d/%2.2d %2.2d:%2.2d", start_tm->tm_mon+1,
			start_tm->tm_mday,
			start_tm->tm_hour,
			start_tm->tm_min);
	} else {
	    printf("            ");
	}
	/*
	 * Calculate and print the per process max time.
	 */
	max_time = rawreqp->v.bat.ppcputime.max_seconds;
	days = max_time / (24 * 60 * 60);
	max_time -= days * 24 * 60 * 60;
	hours = max_time / (60 * 60);
	max_time -= hours * 60 * 60;
	minutes = max_time / 60;
	max_time -= minutes * 60;
	printf("  %3d %2d:%2.2d", days, hours, minutes);
	/*
	 * Calculate and print the total time used by all processes.
	 */
	if ( total_time ) {
#if	!IRIX5
	    total_time = total_time/100;
#endif
	    days = total_time / (24 * 60 * 60);
	    total_time -= days * 24 * 60 * 60;
	    hours = total_time / (60 * 60);
	    total_time -= hours * 60 * 60;
	    minutes = total_time / 60;
	    total_time -= minutes * 60;
	    if (days > 9)
	        printf("   %3d %2d:%2.2d ", days, hours, minutes);
	    else
	        printf("   %d %2d:%2.2d:%2.2d", days, hours, minutes, total_time);
	} else {
	    printf("             ");
	}
}
static get_node(
	struct proc *pointer,
	pid_t	pid_oi,
	pid_t	proc_family)
{
	int	status;
	struct  user  *uptr;
	struct user   auser;
	struct	proc   proc_buff;
#if   IRIX5
        int     fd;
        int     retval;
        prstatus_t prstatus;
        char char_pid[16];
#endif


	if (pointer == 0) return(0);
        pointer = (struct proc *) ((int) pointer & ~0x80000000);
        status = lseek(memfd, (int) pointer, SEEK_SET);
        if (status != (int) pointer) {
            perror("Lseek");
            exit(1);
        }
        status = read (memfd, &proc_buff, procsize);
        if (status != procsize) {
            perror ("Read");
	    exit(1);
        }
	if (proc_buff.p_pid == pid_oi) do_count++;
#if	DEBUG_QSTAT
        if (do_count) printf(">>>>>>>>Pid is %d\n", proc_buff.p_pid);
#endif
	uptr = &auser;
	status = syssgi (SGI_RDUBLK, proc_buff.p_pid, uptr, sizeof(auser) );
#if   IRIX5
        if (do_count) {
            sprintf(char_pid, "/proc/%05d", proc_buff.p_pid);
            fd = open (char_pid, O_RDONLY);
            if (fd != -1) {
                retval = ioctl(fd, PIOCSTATUS, &prstatus);
                total_time += prstatus.pr_cutime.tv_sec+
                                prstatus.pr_cstime.tv_sec +
                                prstatus.pr_utime.tv_sec +
                                prstatus.pr_stime.tv_sec;
#if   DEBUG_QSTAT
                printf(">>>>>>>>total_time: %d\n", total_time);
#endif
                close (fd);
            }
        }
#else

	if (do_count) total_time += uptr->u_utime + uptr->u_stime
			+ uptr->u_cutime + uptr->u_cstime;
#endif
	if (proc_buff.p_pid == proc_family) start_time = uptr->u_start;
        status = get_node (proc_buff.p_child, pid_oi, proc_family);
	if (proc_buff.p_pid == pid_oi) do_count = 0;
	status = get_node(proc_buff.p_sibling, pid_oi, proc_family);
}
#endif
#endif


#if	IBMRS
static summary(
	pid_t	proc_family,	    /* process family */
	struct  rawreq	*rawreqp)
{

	struct	tm  *start_tm;
	int	status;
	int	poffset;
	pid_t	pid_oi;
	unsigned long	procstart;
	struct	proc   myproc;
	int	days, hours, minutes;
	int	max_time;
	
	total_time = start_time = 0;
	pid_oi = proc_family;
#if	DEBUG_QSTAT
	printf( "pid is %d\n", pid_oi);
#endif
	memfd = open (KMEM, O_RDONLY);
	if (memfd == -1) {
		perror("Open");
		exit(1);
	}
	anlist.n_name = "proc";
	knlist(&anlist, 1, sizeof(struct nlist));
	procstart = anlist.n_value;
#if	DEBUG_QSTAT
	printf ("pointer is %x (or %d)\n", procstart, procstart); 
#endif
	status = findproc( procstart,  &myproc);
	poffset = (int) myproc.p_child;
	do_count = 0;
	get_node(poffset, pid_oi, proc_family);

	if ( start_time ) {
	    start_tm = localtime(&start_time);
	    printf(" %2d/%2.2d %2.2d:%2.2d", start_tm->tm_mon+1,
			start_tm->tm_mday,
			start_tm->tm_hour,
			start_tm->tm_min);
	} else {
	    printf("            ");
	}
	/*
	 * Calculate and print the per process max time.
	 */
	max_time = rawreqp->v.bat.ppcputime.max_seconds;
	days = max_time / (24 * 60 * 60);
	max_time -= days * 24 * 60 * 60;
	hours = max_time / (60 * 60);
	max_time -= hours * 60 * 60;
	minutes = max_time / 60;
	max_time -= minutes * 60;
	printf("  %3d %2d:%2.2d", days, hours, minutes);
	/*
	 * Calculate and print the total time used by all processes.
	 */
	if ( total_time ) {
	    days = total_time / (24 * 60 * 60);
	    total_time -= days * 24 * 60 * 60;
	    hours = total_time / (60 * 60);
	    total_time -= hours * 60 * 60;
	    minutes = total_time / 60;
	    total_time -= minutes * 60;
	    if (days > 9)
	        printf("   %3d %2d:%2.2d ", days, hours, minutes);
	    else
	        printf("   %d %2d:%2.2d:%2.2d", days, hours, minutes, total_time);
	} else {
	    printf("             ");
	}
}
static get_node(
	int	pointer,
	pid_t	pid_oi,
	pid_t	proc_family)
{
	int	status;
	struct  user  myuser;
	struct	proc   myproc;

	if (pointer == 0) return(0);
	status = findproc(pointer,  &myproc);
	if (myproc.p_pid == pid_oi) do_count++;
#if	DEBUG_QSTAT
        if (do_count) printf(">>>>>>>>Pid is %d\n", myproc.p_pid);
#endif
	status = finduser(myproc.p_pid,  &myuser);
	if (do_count) total_time += myuser.u_utime+myuser.u_stime
			+myuser.u_cutime+myuser.u_cstime;
#if	DEBUG_QSTAT
	printf("Total time is %d\n",  total_time);
#endif
	if (myproc.p_pid == proc_family) start_time = myuser.u_start;
        status = get_node(myproc.p_child, pid_oi, proc_family);
	if (myproc.p_pid == pid_oi) do_count = 0;
	status = get_node(myproc.p_siblings, pid_oi, proc_family);
}
static findproc(
	unsigned long address,
	struct proc *myproc)
{
    int	    rtn;
    unsigned long   offset;
    offset = address & 0x7fffffff;
    rtn = lseek(memfd,  offset,  0);
    if (rtn == -1) return (0);
    rtn = readx(memfd, myproc, sizeof(struct proc),  1);
    if (rtn == -1) return (0);
    return(1);
}

finduser(long pid,  struct user *user)
{
    struct procinfo pinfo[MAX_PROC];
    int	proc_no,  nproc;
    int status;
    
    nproc = getproc(&pinfo[0],  MAX_PROC,  sizeof(struct procinfo) );
#if DEBUG_QSTAT
    printf("Nproc = %d\n",  nproc);
#endif
    for (proc_no = 0; proc_no < nproc; proc_no++) {
	if (pid == pinfo[proc_no].pi_pid) break;
    }
    status = getuser(&pinfo[proc_no],  sizeof(struct procinfo),  user, 
		    sizeof(struct user) );
#if DEBUG_QSTAT
    printf("Getuser status is %d\n",  status);
#endif
    return (status);
}
#endif

#if	HPUX

static summary(
	pid_t	proc_family,	    /* process family */
	struct  rawreq	*rawreqp)
{

    struct	tm  *start_tm;
    int		status;
    static int nlist_flag = 0;
    int		i;
    pid_t	pid_oi;
    int		days, hours, minutes;
    int		max_time;
	
    total_time = start_time = 0;
    pid_oi = proc_family;
#if	DEBUG_QSTAT
    printf( "pid is %d\n", pid_oi);
#endif
    memfd = open (KMEM, O_RDONLY);
    if (memfd == -1) {
       perror("Open");
       exit(1);
    }
    if (!nlist_flag) {
#ifdef __hp9000s800
        /* 800 names don't have leading underscores */
        for (i = 0; nlst[i].n_name; nlst[i++].n_name++)
            continue;
#endif

        status =  nlist("/hp-ux", nlst);
        if (nlst[0].n_type == 0) {
            fprintf(stderr, "psx: nlist failed\n");
            return(-1);
        }
	nlist_flag = 1;
    }
    (void) getkval(nlst[X_PROC].n_value,   (int *)(&proc),      sizeof(proc),
            nlst[X_PROC].n_name);
    (void) getkval(nlst[X_NPROC].n_value,  &nproc,              sizeof(nproc),
            nlst[X_NPROC].n_name);
#ifdef X_HZ
    (void) getkval(nlst[X_HZ].n_value,     (int *)(&hz),        sizeof(hz),
            nlst[X_HZ].n_name);
#else
    hz = HZ;
#endif

    bytes = nproc * sizeof(struct proc);
    pbase = (struct proc *)malloc(bytes);
    if (pbase == NULL ) printf("Error allocating pbase.\n");
    pst   = (union pstun *)malloc(nproc * sizeof(union pstun));

    (void) getkval(proc, (int *)pbase, bytes, "proc array");
    for (i = 0; i < nproc; ++i) {
        pst[i].pst_status=(struct pst_status *)malloc(sizeof(struct pst_status));
        if (pstat(PSTAT_PROC, pst[i], sizeof(struct pst_status), 0, pbase[i].p_pid) != 1)
	           pbase[i].p_upreg = (preg_t *) 0;
        else
            pbase[i].p_upreg = (preg_t *) pst[i].pst_status;
        pbase[i].p_nice = pst[i].pst_status->pst_nice;
        pbase[i].p_cpticks = pst[i].pst_status->pst_cpticks;
    }
    /*
     * Implemntation note:  It looks like the p_sid field can be used.  If
     * the p_sid is the same as the process family,  then we can count it.
     */
    get_process_info (pid_oi, proc_family);
    if ( start_time ) {
       start_tm = localtime(&start_time);
       printf(" %2d/%2.2d %2.2d:%2.2d", start_tm->tm_mon+1,
			start_tm->tm_mday,
			start_tm->tm_hour,
			start_tm->tm_min);
   }  else {
       printf("            ");
    }
    /*
     * Calculate and print the per process max time.
     */
    max_time = rawreqp->v.bat.ppcputime.max_seconds;
    days = max_time / (24 * 60 * 60);
    max_time -= days * 24 * 60 * 60;
    hours = max_time / (60 * 60);
    max_time -= hours * 60 * 60;
    minutes = max_time / 60;
    max_time -= minutes * 60;
    printf("  %3d %2d:%2.2d", days, hours, minutes);
    /*
     * Calculate and print the total time used by all processes.
     */
    if ( total_time ) {
        days = total_time / (24 * 60 * 60);
        total_time -= days * 24 * 60 * 60;
        hours = total_time / (60 * 60);
	total_time -= hours * 60 * 60;
        minutes = total_time / 60;
        total_time -= minutes * 60;
        if (days > 9)
            printf("   %3d %2d:%2.2d ", days, hours, minutes);
        else
	    printf("   %d %2d:%2.2d:%2.2d", days, hours, minutes, total_time);
    } else {
        printf("             ");
    }
}

get_process_info(
	pid_t pid,
	pid_t proc_family)
{
    int i;
    struct proc *pp;
    struct pst_status *ps;

    for (pp = pbase , i = 0; i< nproc; i++, pp++) {
	if (pp->p_pid == proc_family) start_time = pp->p_start;
        if (pp->p_pid == pid) {
            if ((ps = (struct pst_status *) pp->p_upreg) != NULL) {
                total_time += (ps->pst_cptickstotal)/hz;
            }
        }
        if (pp->p_ppid == pid) get_process_info(pp->p_pid, proc_family);
     }
}

/*
 *  getkval(offset, ptr, size, refstr) - get a value out of the kernel.
 *      "offset" is the byte offset into the kernel for the desired value,
 *      "ptr" points to a buffer into which the value is retrieved,
 *      "size" is the size of the buffer (and the object to retrieve),
 *      "refstr" is a reference string used when printing error meessages,
 *
 */

getkval(
	unsigned long offset,
	int *ptr,
	int size,
	char *refstr)

{
    if (lseek(memfd, (long)offset, L_SET) == -1) {
        (void) fprintf(stderr, "%s: lseek to %s: %s\n", "/dev/kmem",
                       refstr, strerror(errno));
        exit(23);
    }
    if (read(memfd, (char *) ptr, size) == -1) {
            (void) fprintf(stderr, "%s: reading %s: %s\n", "/dev/kmem",
                           refstr, strerror(errno));
            exit(23);
    }
    return(1);
}

#endif

#if SOLARIS
#define PROCFS "/proc"
 
static summary(
        pid_t   proc_family,            /* process family */
        struct  rawreq  *rawreqp)

{
 
    struct      tm  *start_tm;
    int         days, hours, minutes;
    int         max_time;
 
    total_time = start_time = 0;
 
    get_process_info (proc_family);
    if ( start_time ) {
       start_tm = localtime(&start_time);
       printf(" %2d/%2.2d %2.2d:%2.2d", start_tm->tm_mon+1,
                        start_tm->tm_mday,
                        start_tm->tm_hour,
                        start_tm->tm_min);
   }  else {
       printf("            ");
    }
    /*
     * Calculate and print the per process max time.
     */
    max_time = rawreqp->v.bat.ppcputime.max_seconds;
    days = max_time / (24 * 60 * 60);
    max_time -= days * 24 * 60 * 60;
    hours = max_time / (60 * 60);
    max_time -= hours * 60 * 60;
    minutes = max_time / 60;
    max_time -= minutes * 60;
    printf("  %3d %2d:%2.2d", days, hours, minutes);
    /*
     * Calculate and print the total time used by all processes.
     */
    if ( total_time ) {
        days = total_time / (24 * 60 * 60);
        total_time -= days * 24 * 60 * 60;
        hours = total_time / (60 * 60);
        total_time -= hours * 60 * 60;
        minutes = total_time / 60;
        total_time -= minutes * 60;
        if (days > 9)
            printf("   %3d %2d:%2.2d ", days, hours, minutes);
        else
            printf("   %d %2d:%2.2d:%2.2ld", days, hours, minutes, total_time);
    } else {
        printf("             ");
    }
}
 
int get_process_info(pid_t proc_family)
{
    char current_dir[255];
    static DIR *procdir;
    struct dirent *direntp;
    struct prpsinfo *ps, ps_struct;
 
    (void) getcwd (current_dir, 255);
    procdir = opendir (PROCFS);
 
    chdir (PROCFS);
 
    ps=&ps_struct;
    for (rewinddir (procdir); (direntp = readdir (procdir));)
    {
        int fd;
 
        if ((fd = open (direntp->d_name, O_RDONLY)) < 0)
                continue;
 
        if (ioctl (fd, PIOCPSINFO, ps) < 0) {
                (void) close (fd);
                continue;
        }
 
        if (ps->pr_pid == proc_family) start_time = ps->pr_start.tv_sec;
 
        if (ps->pr_sid == proc_family) total_time += ps->pr_time.tv_sec;
 
        close (fd);
     }
     closedir(procdir);
     chdir(current_dir);
}
 
#endif

static sho_mon_hdr()
{
printf(
"Request         I.D.  Owner    Queue    ");
#if SGI | IBMRS | SOLARIS | HPUX
                        printf(         "Start Time   Time Limit  Total Time ");
#else
                        printf(         "                                    ");
#endif
                        printf(                                              "St\n");
printf(
"-------------- ------ -------- -------- ");
#if SGI | IBMRS | SOLARIS | HPUX
                        printf(          "-----------  ----------  ---------- ");
#else
                        printf(          "                                    ");
#endif
                        printf(                                              "--\n");
}

