xref: /minix3/external/bsd/top/dist/machine/m_hpux10.c (revision b89261ba018da33f0bd8cd05f5a1fe9e7a9c837b)
1*b89261baSDavid van Moolenbroek /*
2*b89261baSDavid van Moolenbroek  * Copyright (c) 1984 through 2008, William LeFebvre
3*b89261baSDavid van Moolenbroek  * All rights reserved.
4*b89261baSDavid van Moolenbroek  *
5*b89261baSDavid van Moolenbroek  * Redistribution and use in source and binary forms, with or without
6*b89261baSDavid van Moolenbroek  * modification, are permitted provided that the following conditions are met:
7*b89261baSDavid van Moolenbroek  *
8*b89261baSDavid van Moolenbroek  *     * Redistributions of source code must retain the above copyright
9*b89261baSDavid van Moolenbroek  * notice, this list of conditions and the following disclaimer.
10*b89261baSDavid van Moolenbroek  *
11*b89261baSDavid van Moolenbroek  *     * Redistributions in binary form must reproduce the above
12*b89261baSDavid van Moolenbroek  * copyright notice, this list of conditions and the following disclaimer
13*b89261baSDavid van Moolenbroek  * in the documentation and/or other materials provided with the
14*b89261baSDavid van Moolenbroek  * distribution.
15*b89261baSDavid van Moolenbroek  *
16*b89261baSDavid van Moolenbroek  *     * Neither the name of William LeFebvre nor the names of other
17*b89261baSDavid van Moolenbroek  * contributors may be used to endorse or promote products derived from
18*b89261baSDavid van Moolenbroek  * this software without specific prior written permission.
19*b89261baSDavid van Moolenbroek  *
20*b89261baSDavid van Moolenbroek  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21*b89261baSDavid van Moolenbroek  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22*b89261baSDavid van Moolenbroek  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23*b89261baSDavid van Moolenbroek  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24*b89261baSDavid van Moolenbroek  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25*b89261baSDavid van Moolenbroek  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26*b89261baSDavid van Moolenbroek  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27*b89261baSDavid van Moolenbroek  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28*b89261baSDavid van Moolenbroek  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29*b89261baSDavid van Moolenbroek  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30*b89261baSDavid van Moolenbroek  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31*b89261baSDavid van Moolenbroek  */
32*b89261baSDavid van Moolenbroek 
33*b89261baSDavid van Moolenbroek /*
34*b89261baSDavid van Moolenbroek  * top - a top users display for Unix
35*b89261baSDavid van Moolenbroek  *
36*b89261baSDavid van Moolenbroek  * SYNOPSIS:  any hp9000 running hpux version 10.x
37*b89261baSDavid van Moolenbroek  *
38*b89261baSDavid van Moolenbroek  * DESCRIPTION:
39*b89261baSDavid van Moolenbroek  * This is the machine-dependent module for HPUX 10/11 that uses pstat.
40*b89261baSDavid van Moolenbroek  * It has been tested on HP/UX 10.01, 10.20, and 11.00.  It is presumed
41*b89261baSDavid van Moolenbroek  * to work also on 10.10.
42*b89261baSDavid van Moolenbroek  * Idle processes are marked by being either runnable or having a %CPU
43*b89261baSDavid van Moolenbroek  * of at least 0.1%.  This fraction is defined by CPU_IDLE_THRESH and
44*b89261baSDavid van Moolenbroek  * can be adjusted at compile time.
45*b89261baSDavid van Moolenbroek  *
46*b89261baSDavid van Moolenbroek  * CFLAGS: -DHAVE_GETOPT
47*b89261baSDavid van Moolenbroek  *
48*b89261baSDavid van Moolenbroek  * LIBS:
49*b89261baSDavid van Moolenbroek  *
50*b89261baSDavid van Moolenbroek  * AUTHOR: John Haxby <john_haxby@hp.com>
51*b89261baSDavid van Moolenbroek  * AUTHOR: adapted from Rich Holland <holland@synopsys.com>
52*b89261baSDavid van Moolenbroek  * AUTHOR: adapted from Kevin Schmidt <kevin@mcl.ucsb.edu>
53*b89261baSDavid van Moolenbroek  */
54*b89261baSDavid van Moolenbroek 
55*b89261baSDavid van Moolenbroek #include "config.h"
56*b89261baSDavid van Moolenbroek #include <stdio.h>
57*b89261baSDavid van Moolenbroek #include <errno.h>
58*b89261baSDavid van Moolenbroek #include <unistd.h>
59*b89261baSDavid van Moolenbroek #include <ctype.h>
60*b89261baSDavid van Moolenbroek #include <signal.h>
61*b89261baSDavid van Moolenbroek #include <nlist.h>
62*b89261baSDavid van Moolenbroek #include <fcntl.h>
63*b89261baSDavid van Moolenbroek #include <stdlib.h>
64*b89261baSDavid van Moolenbroek 
65*b89261baSDavid van Moolenbroek #include <sys/types.h>
66*b89261baSDavid van Moolenbroek #include <sys/param.h>
67*b89261baSDavid van Moolenbroek #include <sys/pstat.h>
68*b89261baSDavid van Moolenbroek #include <sys/dk.h>
69*b89261baSDavid van Moolenbroek #include <sys/stat.h>
70*b89261baSDavid van Moolenbroek #include <sys/dirent.h>
71*b89261baSDavid van Moolenbroek 
72*b89261baSDavid van Moolenbroek #include "top.h"
73*b89261baSDavid van Moolenbroek #include "machine.h"
74*b89261baSDavid van Moolenbroek #include "utils.h"
75*b89261baSDavid van Moolenbroek 
76*b89261baSDavid van Moolenbroek /*
77*b89261baSDavid van Moolenbroek  * The idle threshold (CPU_IDLE_THRESH) is an extension to the normal
78*b89261baSDavid van Moolenbroek  * idle process check.  Basically, we regard a process as idle if it is
79*b89261baSDavid van Moolenbroek  * both asleep and using less that CPU_IDLE_THRESH percent cpu time.  I
80*b89261baSDavid van Moolenbroek  * believe this makes the "i" option more useful, but if you don't, add
81*b89261baSDavid van Moolenbroek  * "-DCPU_IDLE_THRESH=0.0" to the CFLAGS.
82*b89261baSDavid van Moolenbroek  */
83*b89261baSDavid van Moolenbroek #ifndef CPU_IDLE_THRESH
84*b89261baSDavid van Moolenbroek #define CPU_IDLE_THRESH 0.1
85*b89261baSDavid van Moolenbroek #endif
86*b89261baSDavid van Moolenbroek 
87*b89261baSDavid van Moolenbroek # define P_RSSIZE(p) (p)->pst_rssize
88*b89261baSDavid van Moolenbroek # define P_TSIZE(p) (p)->pst_tsize
89*b89261baSDavid van Moolenbroek # define P_DSIZE(p) (p)->pst_dsize
90*b89261baSDavid van Moolenbroek # define P_SSIZE(p) (p)->pst_ssize
91*b89261baSDavid van Moolenbroek 
92*b89261baSDavid van Moolenbroek #define VMUNIX	"/stand/vmunix"
93*b89261baSDavid van Moolenbroek #define KMEM	"/dev/kmem"
94*b89261baSDavid van Moolenbroek #define MEM	"/dev/mem"
95*b89261baSDavid van Moolenbroek #ifdef DOSWAP
96*b89261baSDavid van Moolenbroek #define SWAP	"/dev/dmem"
97*b89261baSDavid van Moolenbroek #endif
98*b89261baSDavid van Moolenbroek 
99*b89261baSDavid van Moolenbroek /* what we consider to be process size: */
100*b89261baSDavid van Moolenbroek #define PROCSIZE(pp) (P_TSIZE(pp) + P_DSIZE(pp) + P_SSIZE(pp))
101*b89261baSDavid van Moolenbroek 
102*b89261baSDavid van Moolenbroek /* definitions for indices in the nlist array */
103*b89261baSDavid van Moolenbroek #define X_MPID		0
104*b89261baSDavid van Moolenbroek 
105*b89261baSDavid van Moolenbroek static struct nlist nlst[] = {
106*b89261baSDavid van Moolenbroek     { "mpid" },
107*b89261baSDavid van Moolenbroek     { 0 }
108*b89261baSDavid van Moolenbroek };
109*b89261baSDavid van Moolenbroek 
110*b89261baSDavid van Moolenbroek /*
111*b89261baSDavid van Moolenbroek  *  These definitions control the format of the per-process area
112*b89261baSDavid van Moolenbroek  */
113*b89261baSDavid van Moolenbroek 
114*b89261baSDavid van Moolenbroek static char header[] =
115*b89261baSDavid van Moolenbroek   "     TTY   PID X         PRI NICE  SIZE   RES STATE   TIME    CPU COMMAND";
116*b89261baSDavid van Moolenbroek /* 0123456789.12345 -- field to fill in starts at header+6 */
117*b89261baSDavid van Moolenbroek #define UNAME_START 15
118*b89261baSDavid van Moolenbroek 
119*b89261baSDavid van Moolenbroek #define Proc_format \
120*b89261baSDavid van Moolenbroek 	"%8.8s %5d %-8.8s %4d %4d %5s %5s %-5s %6s %5.2f%% %s"
121*b89261baSDavid van Moolenbroek 
122*b89261baSDavid van Moolenbroek /* process state names for the "STATE" column of the display */
123*b89261baSDavid van Moolenbroek 
124*b89261baSDavid van Moolenbroek char *state_abbrev[] =
125*b89261baSDavid van Moolenbroek {
126*b89261baSDavid van Moolenbroek     "", "sleep", "run", "stop", "zomb", "trans", "start"
127*b89261baSDavid van Moolenbroek };
128*b89261baSDavid van Moolenbroek 
129*b89261baSDavid van Moolenbroek 
130*b89261baSDavid van Moolenbroek /* values that we stash away in _init and use in later routines */
131*b89261baSDavid van Moolenbroek static int kmem;
132*b89261baSDavid van Moolenbroek static struct pst_status *pst;
133*b89261baSDavid van Moolenbroek 
134*b89261baSDavid van Moolenbroek /* these are retrieved from the OS in _init */
135*b89261baSDavid van Moolenbroek static int nproc;
136*b89261baSDavid van Moolenbroek static int ncpu = 0;
137*b89261baSDavid van Moolenbroek 
138*b89261baSDavid van Moolenbroek /* these are offsets obtained via nlist and used in the get_ functions */
139*b89261baSDavid van Moolenbroek static unsigned long mpid_offset;
140*b89261baSDavid van Moolenbroek 
141*b89261baSDavid van Moolenbroek /* these are for calculating cpu state percentages */
142*b89261baSDavid van Moolenbroek static long cp_time[PST_MAX_CPUSTATES];
143*b89261baSDavid van Moolenbroek static long cp_old[PST_MAX_CPUSTATES];
144*b89261baSDavid van Moolenbroek static long cp_diff[PST_MAX_CPUSTATES];
145*b89261baSDavid van Moolenbroek 
146*b89261baSDavid van Moolenbroek /* these are for detailing the process states */
147*b89261baSDavid van Moolenbroek int process_states[7];
148*b89261baSDavid van Moolenbroek char *procstatenames[] = {
149*b89261baSDavid van Moolenbroek     "", " sleeping, ", " running, ", " stopped, ", " zombie, ",
150*b89261baSDavid van Moolenbroek     " trans, ", " starting, ",
151*b89261baSDavid van Moolenbroek     NULL
152*b89261baSDavid van Moolenbroek };
153*b89261baSDavid van Moolenbroek 
154*b89261baSDavid van Moolenbroek /* these are for detailing the cpu states */
155*b89261baSDavid van Moolenbroek int cpu_states[PST_MAX_CPUSTATES];
156*b89261baSDavid van Moolenbroek char *cpustatenames[] = {
157*b89261baSDavid van Moolenbroek     /* roll "swait" into "block" and "ssys" into "sys" */
158*b89261baSDavid van Moolenbroek     "usr", "nice", "sys", "idle", "", "block", "\0swait", "intr", "\0ssys",
159*b89261baSDavid van Moolenbroek     NULL
160*b89261baSDavid van Moolenbroek };
161*b89261baSDavid van Moolenbroek 
162*b89261baSDavid van Moolenbroek /* these are for detailing the memory statistics */
163*b89261baSDavid van Moolenbroek long memory_stats[8];
164*b89261baSDavid van Moolenbroek char *memorynames[] = {
165*b89261baSDavid van Moolenbroek     "Real: ", "K act, ", "K tot  ", "Virtual: ", "K act, ",
166*b89261baSDavid van Moolenbroek     "K tot, ", "K free", NULL
167*b89261baSDavid van Moolenbroek };
168*b89261baSDavid van Moolenbroek 
169*b89261baSDavid van Moolenbroek /* these are for getting the memory statistics */
170*b89261baSDavid van Moolenbroek static int pageshift;		/* log base 2 of the pagesize */
171*b89261baSDavid van Moolenbroek 
172*b89261baSDavid van Moolenbroek /* define pagetok in terms of pageshift */
173*b89261baSDavid van Moolenbroek #define pagetok(size) ((size) << pageshift)
174*b89261baSDavid van Moolenbroek 
175*b89261baSDavid van Moolenbroek /* Mapping TTY major/minor numbers is done through this structure */
176*b89261baSDavid van Moolenbroek struct ttymap {
177*b89261baSDavid van Moolenbroek     dev_t dev;
178*b89261baSDavid van Moolenbroek     char name [9];
179*b89261baSDavid van Moolenbroek };
180*b89261baSDavid van Moolenbroek static struct ttymap *ttynames = NULL;
181*b89261baSDavid van Moolenbroek static int nttys = 0;
182*b89261baSDavid van Moolenbroek static get_tty_names ();
183*b89261baSDavid van Moolenbroek 
184*b89261baSDavid van Moolenbroek /* comparison routine for qsort */
185*b89261baSDavid van Moolenbroek 
186*b89261baSDavid van Moolenbroek /*
187*b89261baSDavid van Moolenbroek  *  proc_compare - comparison function for "qsort"
188*b89261baSDavid van Moolenbroek  *	Compares the resource consumption of two processes using five
189*b89261baSDavid van Moolenbroek  *  	distinct keys.  The keys (in descending order of importance) are:
190*b89261baSDavid van Moolenbroek  *  	percent cpu, cpu ticks, state, resident set size, total virtual
191*b89261baSDavid van Moolenbroek  *  	memory usage.  The process states are ordered as follows (from least
192*b89261baSDavid van Moolenbroek  *  	to most important):  WAIT, zombie, sleep, stop, start, run.  The
193*b89261baSDavid van Moolenbroek  *  	array declaration below maps a process state index into a number
194*b89261baSDavid van Moolenbroek  *  	that reflects this ordering.
195*b89261baSDavid van Moolenbroek  */
196*b89261baSDavid van Moolenbroek 
197*b89261baSDavid van Moolenbroek static unsigned char sorted_state[] =
198*b89261baSDavid van Moolenbroek {
199*b89261baSDavid van Moolenbroek     0,	/* not used		*/
200*b89261baSDavid van Moolenbroek     3,	/* sleep		*/
201*b89261baSDavid van Moolenbroek     6,	/* run			*/
202*b89261baSDavid van Moolenbroek     4,	/* stop			*/
203*b89261baSDavid van Moolenbroek     2,	/* zombie		*/
204*b89261baSDavid van Moolenbroek     5,	/* start		*/
205*b89261baSDavid van Moolenbroek     1,  /* other                */
206*b89261baSDavid van Moolenbroek };
207*b89261baSDavid van Moolenbroek 
208*b89261baSDavid van Moolenbroek proc_compare(p1, p2)
209*b89261baSDavid van Moolenbroek struct pst_status *p1;
210*b89261baSDavid van Moolenbroek struct pst_status *p2;
211*b89261baSDavid van Moolenbroek 
212*b89261baSDavid van Moolenbroek {
213*b89261baSDavid van Moolenbroek     int result;
214*b89261baSDavid van Moolenbroek     float lresult;
215*b89261baSDavid van Moolenbroek 
216*b89261baSDavid van Moolenbroek     /* compare percent cpu (pctcpu) */
217*b89261baSDavid van Moolenbroek     if ((lresult = p2->pst_pctcpu - p1->pst_pctcpu) == 0)
218*b89261baSDavid van Moolenbroek     {
219*b89261baSDavid van Moolenbroek 	/* use cpticks to break the tie */
220*b89261baSDavid van Moolenbroek 	if ((result = p2->pst_cpticks - p1->pst_cpticks) == 0)
221*b89261baSDavid van Moolenbroek 	{
222*b89261baSDavid van Moolenbroek 	    /* use process state to break the tie */
223*b89261baSDavid van Moolenbroek 	    if ((result = sorted_state[p2->pst_stat] -
224*b89261baSDavid van Moolenbroek 			  sorted_state[p1->pst_stat])  == 0)
225*b89261baSDavid van Moolenbroek 	    {
226*b89261baSDavid van Moolenbroek 		/* use priority to break the tie */
227*b89261baSDavid van Moolenbroek 		if ((result = p2->pst_pri - p1->pst_pri) == 0)
228*b89261baSDavid van Moolenbroek 		{
229*b89261baSDavid van Moolenbroek 		    /* use resident set size (rssize) to break the tie */
230*b89261baSDavid van Moolenbroek 		    if ((result = P_RSSIZE(p2) - P_RSSIZE(p1)) == 0)
231*b89261baSDavid van Moolenbroek 		    {
232*b89261baSDavid van Moolenbroek 			/* use total memory to break the tie */
233*b89261baSDavid van Moolenbroek 			result = PROCSIZE(p2) - PROCSIZE(p1);
234*b89261baSDavid van Moolenbroek 		    }
235*b89261baSDavid van Moolenbroek 		}
236*b89261baSDavid van Moolenbroek 	    }
237*b89261baSDavid van Moolenbroek 	}
238*b89261baSDavid van Moolenbroek     }
239*b89261baSDavid van Moolenbroek     else
240*b89261baSDavid van Moolenbroek     {
241*b89261baSDavid van Moolenbroek 	result = lresult < 0 ? -1 : 1;
242*b89261baSDavid van Moolenbroek     }
243*b89261baSDavid van Moolenbroek 
244*b89261baSDavid van Moolenbroek     return(result);
245*b89261baSDavid van Moolenbroek }
246*b89261baSDavid van Moolenbroek 
247*b89261baSDavid van Moolenbroek machine_init(statics)
248*b89261baSDavid van Moolenbroek 
249*b89261baSDavid van Moolenbroek struct statics *statics;
250*b89261baSDavid van Moolenbroek 
251*b89261baSDavid van Moolenbroek {
252*b89261baSDavid van Moolenbroek     struct pst_static info;
253*b89261baSDavid van Moolenbroek     int i = 0;
254*b89261baSDavid van Moolenbroek     int pagesize;
255*b89261baSDavid van Moolenbroek 
256*b89261baSDavid van Moolenbroek     /* If we can get mpid from the kernel, we'll use it, otherwise    */
257*b89261baSDavid van Moolenbroek     /* we'll guess from the most recently started proces              */
258*b89261baSDavid van Moolenbroek     if ((kmem = open (KMEM, O_RDONLY)) < 0 ||
259*b89261baSDavid van Moolenbroek 	(nlist (VMUNIX, nlst)) < 0 ||
260*b89261baSDavid van Moolenbroek 	(nlst[X_MPID].n_type) == 0)
261*b89261baSDavid van Moolenbroek 	mpid_offset = 0;
262*b89261baSDavid van Moolenbroek     else
263*b89261baSDavid van Moolenbroek 	mpid_offset = nlst[X_MPID].n_value;
264*b89261baSDavid van Moolenbroek 
265*b89261baSDavid van Moolenbroek     if (pstat_getstatic (&info, sizeof (info), 1, 0) < 0)
266*b89261baSDavid van Moolenbroek     {
267*b89261baSDavid van Moolenbroek 	perror ("pstat_getstatic");
268*b89261baSDavid van Moolenbroek 	return -1;
269*b89261baSDavid van Moolenbroek     }
270*b89261baSDavid van Moolenbroek 
271*b89261baSDavid van Moolenbroek     /*
272*b89261baSDavid van Moolenbroek      * Allocate space for the per-process structures (pst_status).  To
273*b89261baSDavid van Moolenbroek      * make life easier, simply allocate enough storage to hold all the
274*b89261baSDavid van Moolenbroek      * process information at once.  This won't normally be a problem
275*b89261baSDavid van Moolenbroek      * since machines with lots of processes configured will also have
276*b89261baSDavid van Moolenbroek      * lots of memory.
277*b89261baSDavid van Moolenbroek      */
278*b89261baSDavid van Moolenbroek     nproc = info.max_proc;
279*b89261baSDavid van Moolenbroek     pst = (struct pst_status *) malloc (nproc * sizeof (struct pst_status));
280*b89261baSDavid van Moolenbroek     if (pst == NULL)
281*b89261baSDavid van Moolenbroek     {
282*b89261baSDavid van Moolenbroek 	fprintf (stderr, "out of memory\n");
283*b89261baSDavid van Moolenbroek 	return -1;
284*b89261baSDavid van Moolenbroek     }
285*b89261baSDavid van Moolenbroek 
286*b89261baSDavid van Moolenbroek     /*
287*b89261baSDavid van Moolenbroek      * Calculate pageshift -- the value needed to convert pages to Kbytes.
288*b89261baSDavid van Moolenbroek      * This will usually be 2.
289*b89261baSDavid van Moolenbroek      */
290*b89261baSDavid van Moolenbroek     pageshift = 0;
291*b89261baSDavid van Moolenbroek     for (pagesize = info.page_size; pagesize > 1; pagesize >>= 1)
292*b89261baSDavid van Moolenbroek 	pageshift += 1;
293*b89261baSDavid van Moolenbroek     pageshift -= LOG1024;
294*b89261baSDavid van Moolenbroek 
295*b89261baSDavid van Moolenbroek     /* get tty name information */
296*b89261baSDavid van Moolenbroek     i = 0;
297*b89261baSDavid van Moolenbroek     get_tty_names ("/dev", &i);
298*b89261baSDavid van Moolenbroek 
299*b89261baSDavid van Moolenbroek     /* fill in the statics information */
300*b89261baSDavid van Moolenbroek     statics->procstate_names = procstatenames;
301*b89261baSDavid van Moolenbroek     statics->cpustate_names = cpustatenames;
302*b89261baSDavid van Moolenbroek     statics->memory_names = memorynames;
303*b89261baSDavid van Moolenbroek 
304*b89261baSDavid van Moolenbroek     /* all done! */
305*b89261baSDavid van Moolenbroek     return(0);
306*b89261baSDavid van Moolenbroek }
307*b89261baSDavid van Moolenbroek 
format_header(uname_field)308*b89261baSDavid van Moolenbroek char *format_header(uname_field)
309*b89261baSDavid van Moolenbroek char *uname_field;
310*b89261baSDavid van Moolenbroek {
311*b89261baSDavid van Moolenbroek     char *ptr = header + UNAME_START;
312*b89261baSDavid van Moolenbroek     while (*uname_field != '\0')
313*b89261baSDavid van Moolenbroek 	*ptr++ = *uname_field++;
314*b89261baSDavid van Moolenbroek 
315*b89261baSDavid van Moolenbroek     return header;
316*b89261baSDavid van Moolenbroek }
317*b89261baSDavid van Moolenbroek 
318*b89261baSDavid van Moolenbroek void
get_system_info(si)319*b89261baSDavid van Moolenbroek get_system_info(si)
320*b89261baSDavid van Moolenbroek 
321*b89261baSDavid van Moolenbroek struct system_info *si;
322*b89261baSDavid van Moolenbroek 
323*b89261baSDavid van Moolenbroek {
324*b89261baSDavid van Moolenbroek     static struct pst_dynamic dynamic;
325*b89261baSDavid van Moolenbroek     int i, n;
326*b89261baSDavid van Moolenbroek     long total;
327*b89261baSDavid van Moolenbroek 
328*b89261baSDavid van Moolenbroek     pstat_getdynamic (&dynamic, sizeof (dynamic), 1, 0);
329*b89261baSDavid van Moolenbroek     ncpu = dynamic.psd_proc_cnt;  /* need this later */
330*b89261baSDavid van Moolenbroek 
331*b89261baSDavid van Moolenbroek     /* Load average */
332*b89261baSDavid van Moolenbroek     si->load_avg[0] = dynamic.psd_avg_1_min;
333*b89261baSDavid van Moolenbroek     si->load_avg[1] = dynamic.psd_avg_5_min;
334*b89261baSDavid van Moolenbroek     si->load_avg[2] = dynamic.psd_avg_15_min;
335*b89261baSDavid van Moolenbroek 
336*b89261baSDavid van Moolenbroek     /*
337*b89261baSDavid van Moolenbroek      * CPU times
338*b89261baSDavid van Moolenbroek      * to avoid space problems, we roll SWAIT (kernel semaphore block)
339*b89261baSDavid van Moolenbroek      * into BLOCK (spin lock block) and SSYS (kernel process) into SYS
340*b89261baSDavid van Moolenbroek      * (system time) Ideally, all screens would be wider :-)
341*b89261baSDavid van Moolenbroek      */
342*b89261baSDavid van Moolenbroek     dynamic.psd_cpu_time [CP_BLOCK] += dynamic.psd_cpu_time [CP_SWAIT];
343*b89261baSDavid van Moolenbroek     dynamic.psd_cpu_time [CP_SWAIT] = 0;
344*b89261baSDavid van Moolenbroek     dynamic.psd_cpu_time [CP_SYS] += dynamic.psd_cpu_time [CP_SSYS];
345*b89261baSDavid van Moolenbroek     dynamic.psd_cpu_time [CP_SSYS] = 0;
346*b89261baSDavid van Moolenbroek     for (i = 0; i < PST_MAX_CPUSTATES; i++)
347*b89261baSDavid van Moolenbroek 	cp_time [i] = dynamic.psd_cpu_time [i];
348*b89261baSDavid van Moolenbroek     percentages(PST_MAX_CPUSTATES, cpu_states, cp_time, cp_old, cp_diff);
349*b89261baSDavid van Moolenbroek     si->cpustates = cpu_states;
350*b89261baSDavid van Moolenbroek 
351*b89261baSDavid van Moolenbroek     /*
352*b89261baSDavid van Moolenbroek      * VM statistics
353*b89261baSDavid van Moolenbroek      */
354*b89261baSDavid van Moolenbroek     memory_stats[0] = -1;
355*b89261baSDavid van Moolenbroek     memory_stats[1] = pagetok (dynamic.psd_arm);
356*b89261baSDavid van Moolenbroek     memory_stats[2] = pagetok (dynamic.psd_rm);
357*b89261baSDavid van Moolenbroek     memory_stats[3] = -1;
358*b89261baSDavid van Moolenbroek     memory_stats[4] = pagetok (dynamic.psd_avm);
359*b89261baSDavid van Moolenbroek     memory_stats[5] = pagetok (dynamic.psd_vm);
360*b89261baSDavid van Moolenbroek     memory_stats[6] = pagetok (dynamic.psd_free);
361*b89261baSDavid van Moolenbroek     si->memory = memory_stats;
362*b89261baSDavid van Moolenbroek 
363*b89261baSDavid van Moolenbroek     /*
364*b89261baSDavid van Moolenbroek      * If we can get mpid from the kernel, then we will do so now.
365*b89261baSDavid van Moolenbroek      * Otherwise we'll guess at mpid from the most recently started
366*b89261baSDavid van Moolenbroek      * process time.  Note that this requires us to get the pst array
367*b89261baSDavid van Moolenbroek      * now rather than in get_process_info().  We rely on
368*b89261baSDavid van Moolenbroek      * get_system_info() being called before get_system_info() for this
369*b89261baSDavid van Moolenbroek      * to work reliably.
370*b89261baSDavid van Moolenbroek      */
371*b89261baSDavid van Moolenbroek     for (i = 0; i < nproc; i++)
372*b89261baSDavid van Moolenbroek 	pst[i].pst_pid = -1;
373*b89261baSDavid van Moolenbroek     n = pstat_getproc (pst, sizeof (*pst), nproc, 0);
374*b89261baSDavid van Moolenbroek 
375*b89261baSDavid van Moolenbroek     if (kmem >= 0 && mpid_offset > 0)
376*b89261baSDavid van Moolenbroek 	(void) getkval(mpid_offset, &(si->last_pid), sizeof(si->last_pid), "mpid");
377*b89261baSDavid van Moolenbroek     else
378*b89261baSDavid van Moolenbroek     {
379*b89261baSDavid van Moolenbroek 	static int last_start_time = 0;
380*b89261baSDavid van Moolenbroek 	int pid = 0;
381*b89261baSDavid van Moolenbroek 
382*b89261baSDavid van Moolenbroek 	for (i = 0; i < n; i++)
383*b89261baSDavid van Moolenbroek 	{
384*b89261baSDavid van Moolenbroek 	    if (last_start_time <= pst[i].pst_start)
385*b89261baSDavid van Moolenbroek 	    {
386*b89261baSDavid van Moolenbroek 	    	last_start_time = pst[i].pst_start;
387*b89261baSDavid van Moolenbroek 		if (pid <= pst[i].pst_pid)
388*b89261baSDavid van Moolenbroek 		    pid = pst[i].pst_pid;
389*b89261baSDavid van Moolenbroek 	    }
390*b89261baSDavid van Moolenbroek 	}
391*b89261baSDavid van Moolenbroek 	if (pid != 0)
392*b89261baSDavid van Moolenbroek 	    si->last_pid = pid;
393*b89261baSDavid van Moolenbroek     }
394*b89261baSDavid van Moolenbroek }
395*b89261baSDavid van Moolenbroek 
get_process_info(si,sel,compare_index)396*b89261baSDavid van Moolenbroek caddr_t get_process_info(si, sel, compare_index)
397*b89261baSDavid van Moolenbroek 
398*b89261baSDavid van Moolenbroek struct system_info *si;
399*b89261baSDavid van Moolenbroek struct process_select *sel;
400*b89261baSDavid van Moolenbroek int compare_index;
401*b89261baSDavid van Moolenbroek 
402*b89261baSDavid van Moolenbroek {
403*b89261baSDavid van Moolenbroek     static int handle;
404*b89261baSDavid van Moolenbroek     int i, active, total;
405*b89261baSDavid van Moolenbroek 
406*b89261baSDavid van Moolenbroek     /*
407*b89261baSDavid van Moolenbroek      * Eliminate unwanted processes
408*b89261baSDavid van Moolenbroek      * and tot up all the wanted processes by state
409*b89261baSDavid van Moolenbroek      */
410*b89261baSDavid van Moolenbroek     for (i = 0; i < sizeof (process_states)/sizeof (process_states[0]); i++)
411*b89261baSDavid van Moolenbroek 	process_states [i] = 0;
412*b89261baSDavid van Moolenbroek 
413*b89261baSDavid van Moolenbroek     for (total = 0, active = 0, i = 0; pst[i].pst_pid >= 0; i++)
414*b89261baSDavid van Moolenbroek     {
415*b89261baSDavid van Moolenbroek 	int state = pst[i].pst_stat;
416*b89261baSDavid van Moolenbroek 
417*b89261baSDavid van Moolenbroek 	process_states [state] += 1;
418*b89261baSDavid van Moolenbroek 	total += 1;
419*b89261baSDavid van Moolenbroek 
420*b89261baSDavid van Moolenbroek 	if (!sel->system && (pst[i].pst_flag & PS_SYS))
421*b89261baSDavid van Moolenbroek 	{
422*b89261baSDavid van Moolenbroek 	    pst[i].pst_stat = -1;
423*b89261baSDavid van Moolenbroek 	    continue;
424*b89261baSDavid van Moolenbroek 	}
425*b89261baSDavid van Moolenbroek 
426*b89261baSDavid van Moolenbroek 	/*
427*b89261baSDavid van Moolenbroek 	 * If we are eliminating idle processes, then a process is regarded
428*b89261baSDavid van Moolenbroek 	 * as idle if it is in a short term sleep and not using much
429*b89261baSDavid van Moolenbroek 	 * CPU, or stopped, or simple dead.
430*b89261baSDavid van Moolenbroek 	 */
431*b89261baSDavid van Moolenbroek 	if (!sel->idle
432*b89261baSDavid van Moolenbroek 	    && (state == PS_SLEEP || state == PS_STOP || state == PS_ZOMBIE)
433*b89261baSDavid van Moolenbroek 	    && (state != PS_SLEEP && pst[i].pst_pctcpu < CPU_IDLE_THRESH/100.0))
434*b89261baSDavid van Moolenbroek 	    pst[i].pst_stat = -1;
435*b89261baSDavid van Moolenbroek 
436*b89261baSDavid van Moolenbroek 	if (sel->uid > 0 && sel->uid != pst[i].pst_uid)
437*b89261baSDavid van Moolenbroek 	    pst[i].pst_stat = -1;
438*b89261baSDavid van Moolenbroek 
439*b89261baSDavid van Moolenbroek 	if (sel->command != NULL &&
440*b89261baSDavid van Moolenbroek 	    strncmp (sel->command, pst[i].pst_ucomm, strlen (pst[i].pst_ucomm)) != 0)
441*b89261baSDavid van Moolenbroek 	    pst[i].pst_stat = -1;
442*b89261baSDavid van Moolenbroek 
443*b89261baSDavid van Moolenbroek 	if (pst[i].pst_stat >= 0)
444*b89261baSDavid van Moolenbroek 	    active += 1;
445*b89261baSDavid van Moolenbroek     }
446*b89261baSDavid van Moolenbroek     si->procstates = process_states;
447*b89261baSDavid van Moolenbroek     si->p_total = total;
448*b89261baSDavid van Moolenbroek     si->p_active = active;
449*b89261baSDavid van Moolenbroek 
450*b89261baSDavid van Moolenbroek     qsort ((char *)pst, i, sizeof(*pst), proc_compare);
451*b89261baSDavid van Moolenbroek 
452*b89261baSDavid van Moolenbroek     /* handle is simply an index into the process structures */
453*b89261baSDavid van Moolenbroek     handle = 0;
454*b89261baSDavid van Moolenbroek     return (caddr_t) &handle;
455*b89261baSDavid van Moolenbroek }
456*b89261baSDavid van Moolenbroek 
457*b89261baSDavid van Moolenbroek /*
458*b89261baSDavid van Moolenbroek  * Find the terminal name associated with a particular
459*b89261baSDavid van Moolenbroek  * major/minor number pair
460*b89261baSDavid van Moolenbroek  */
term_name(term)461*b89261baSDavid van Moolenbroek static char *term_name (term)
462*b89261baSDavid van Moolenbroek struct psdev *term;
463*b89261baSDavid van Moolenbroek {
464*b89261baSDavid van Moolenbroek     dev_t dev;
465*b89261baSDavid van Moolenbroek     int i;
466*b89261baSDavid van Moolenbroek 
467*b89261baSDavid van Moolenbroek     if (term->psd_major == -1 && term->psd_minor == -1)
468*b89261baSDavid van Moolenbroek 	return "?";
469*b89261baSDavid van Moolenbroek 
470*b89261baSDavid van Moolenbroek     dev = makedev (term->psd_major, term->psd_minor);
471*b89261baSDavid van Moolenbroek     for (i = 0; i < nttys && ttynames[i].name[0] != '\0'; i++)
472*b89261baSDavid van Moolenbroek     {
473*b89261baSDavid van Moolenbroek 	if (dev == ttynames[i].dev)
474*b89261baSDavid van Moolenbroek 	    return ttynames[i].name;
475*b89261baSDavid van Moolenbroek     }
476*b89261baSDavid van Moolenbroek     return "<unk>";
477*b89261baSDavid van Moolenbroek }
478*b89261baSDavid van Moolenbroek 
format_next_process(handle,get_userid)479*b89261baSDavid van Moolenbroek char *format_next_process(handle, get_userid)
480*b89261baSDavid van Moolenbroek 
481*b89261baSDavid van Moolenbroek caddr_t handle;
482*b89261baSDavid van Moolenbroek char *(*get_userid)();
483*b89261baSDavid van Moolenbroek 
484*b89261baSDavid van Moolenbroek {
485*b89261baSDavid van Moolenbroek     static char fmt[MAX_COLS];	/* static area where result is built */
486*b89261baSDavid van Moolenbroek     char run [sizeof ("runNN")];
487*b89261baSDavid van Moolenbroek     int idx;
488*b89261baSDavid van Moolenbroek     struct pst_status *proc;
489*b89261baSDavid van Moolenbroek     char *state;
490*b89261baSDavid van Moolenbroek     int size;
491*b89261baSDavid van Moolenbroek 
492*b89261baSDavid van Moolenbroek     register long cputime;
493*b89261baSDavid van Moolenbroek     register double pct;
494*b89261baSDavid van Moolenbroek     int where;
495*b89261baSDavid van Moolenbroek     struct handle *hp;
496*b89261baSDavid van Moolenbroek     struct timeval time;
497*b89261baSDavid van Moolenbroek     struct timezone timezone;
498*b89261baSDavid van Moolenbroek 
499*b89261baSDavid van Moolenbroek     /* sanity check */
500*b89261baSDavid van Moolenbroek     if (handle == NULL)
501*b89261baSDavid van Moolenbroek 	return "";
502*b89261baSDavid van Moolenbroek 
503*b89261baSDavid van Moolenbroek     idx = *((int *) handle);
504*b89261baSDavid van Moolenbroek     while (idx < nproc && pst[idx].pst_stat < 0)
505*b89261baSDavid van Moolenbroek 	idx += 1;
506*b89261baSDavid van Moolenbroek     if (idx >= nproc || pst[idx].pst_stat < 0)
507*b89261baSDavid van Moolenbroek 	return "";
508*b89261baSDavid van Moolenbroek     proc = &pst[idx];
509*b89261baSDavid van Moolenbroek     *((int *) handle) = idx+1;
510*b89261baSDavid van Moolenbroek 
511*b89261baSDavid van Moolenbroek     /* set ucomm for system processes, although we shouldn't need to */
512*b89261baSDavid van Moolenbroek     if (proc->pst_ucomm[0] == '\0')
513*b89261baSDavid van Moolenbroek     {
514*b89261baSDavid van Moolenbroek 	if (proc->pst_pid == 0)
515*b89261baSDavid van Moolenbroek 	    strcpy (proc->pst_ucomm, "Swapper");
516*b89261baSDavid van Moolenbroek 	else if (proc->pst_pid == 2)
517*b89261baSDavid van Moolenbroek 	    strcpy (proc->pst_ucomm, "Pager");
518*b89261baSDavid van Moolenbroek     }
519*b89261baSDavid van Moolenbroek 
520*b89261baSDavid van Moolenbroek     size = proc->pst_tsize + proc->pst_dsize + proc->pst_ssize;
521*b89261baSDavid van Moolenbroek 
522*b89261baSDavid van Moolenbroek     if (ncpu > 1 && proc->pst_stat == PS_RUN)
523*b89261baSDavid van Moolenbroek     {
524*b89261baSDavid van Moolenbroek 	sprintf (run, "run%02d", proc->pst_procnum);
525*b89261baSDavid van Moolenbroek 	state = run;
526*b89261baSDavid van Moolenbroek     }
527*b89261baSDavid van Moolenbroek     else if (proc->pst_stat == PS_SLEEP)
528*b89261baSDavid van Moolenbroek     {
529*b89261baSDavid van Moolenbroek 	switch (proc->pst_pri+PTIMESHARE) {
530*b89261baSDavid van Moolenbroek 	case PSWP:	state = "SWP"; break; /* also PMEM */
531*b89261baSDavid van Moolenbroek 	case PRIRWLOCK:	state = "RWLOCK"; break;
532*b89261baSDavid van Moolenbroek 	case PRIBETA:	state = "BETA"; break;
533*b89261baSDavid van Moolenbroek 	case PRIALPHA:	state = "ALPHA"; break;
534*b89261baSDavid van Moolenbroek 	case PRISYNC:	state = "SYNC"; break;
535*b89261baSDavid van Moolenbroek 	case PINOD:	state = "INOD"; break;
536*b89261baSDavid van Moolenbroek 	case PRIBIO:	state = "BIO"; break;
537*b89261baSDavid van Moolenbroek 	case PLLIO:	state = "LLIO"; break; /* also PRIUBA  */
538*b89261baSDavid van Moolenbroek 	case PZERO:	state = "ZERO"; break;
539*b89261baSDavid van Moolenbroek 	case PPIPE:	state = "pipe"; break;
540*b89261baSDavid van Moolenbroek 	case PVFS:	state = "vfs"; break;
541*b89261baSDavid van Moolenbroek 	case PWAIT:	state = "wait"; break;
542*b89261baSDavid van Moolenbroek 	case PLOCK:	state = "lock"; break;
543*b89261baSDavid van Moolenbroek 	case PSLEP:	state = "slep"; break;
544*b89261baSDavid van Moolenbroek 	case PUSER:	state = "user"; break;
545*b89261baSDavid van Moolenbroek 	default:
546*b89261baSDavid van Moolenbroek 	    if (proc->pst_pri < PZERO-PTIMESHARE)
547*b89261baSDavid van Moolenbroek 		state = "SLEEP";
548*b89261baSDavid van Moolenbroek 	    else
549*b89261baSDavid van Moolenbroek 		state = "sleep";
550*b89261baSDavid van Moolenbroek 	}
551*b89261baSDavid van Moolenbroek     }
552*b89261baSDavid van Moolenbroek     else
553*b89261baSDavid van Moolenbroek 	state = state_abbrev [proc->pst_stat];
554*b89261baSDavid van Moolenbroek 
555*b89261baSDavid van Moolenbroek     /* format this entry */
556*b89261baSDavid van Moolenbroek     sprintf(fmt,
557*b89261baSDavid van Moolenbroek 	    Proc_format,
558*b89261baSDavid van Moolenbroek 	    term_name (&proc->pst_term),
559*b89261baSDavid van Moolenbroek 	    proc->pst_pid,
560*b89261baSDavid van Moolenbroek 	    (*get_userid)(proc->pst_uid),
561*b89261baSDavid van Moolenbroek 	    proc->pst_pri,
562*b89261baSDavid van Moolenbroek 	    proc->pst_nice - NZERO,
563*b89261baSDavid van Moolenbroek 	    format_k(size),
564*b89261baSDavid van Moolenbroek 	    format_k(proc->pst_rssize),
565*b89261baSDavid van Moolenbroek 	    state,
566*b89261baSDavid van Moolenbroek 	    format_time(proc->pst_utime + proc->pst_stime),
567*b89261baSDavid van Moolenbroek 	    100.0 * proc->pst_pctcpu,
568*b89261baSDavid van Moolenbroek 	    printable(proc->pst_ucomm));
569*b89261baSDavid van Moolenbroek 
570*b89261baSDavid van Moolenbroek     /* return the result */
571*b89261baSDavid van Moolenbroek     return(fmt);
572*b89261baSDavid van Moolenbroek }
573*b89261baSDavid van Moolenbroek 
574*b89261baSDavid van Moolenbroek 
575*b89261baSDavid van Moolenbroek 
576*b89261baSDavid van Moolenbroek /*
577*b89261baSDavid van Moolenbroek  *  getkval(offset, ptr, size, refstr) - get a value out of the kernel.
578*b89261baSDavid van Moolenbroek  *	"offset" is the byte offset into the kernel for the desired value,
579*b89261baSDavid van Moolenbroek  *  	"ptr" points to a buffer into which the value is retrieved,
580*b89261baSDavid van Moolenbroek  *  	"size" is the size of the buffer (and the object to retrieve),
581*b89261baSDavid van Moolenbroek  *  	"refstr" is a reference string used when printing error meessages,
582*b89261baSDavid van Moolenbroek  *	    if "refstr" starts with a '!', then a failure on read will not
583*b89261baSDavid van Moolenbroek  *  	    be fatal (this may seem like a silly way to do things, but I
584*b89261baSDavid van Moolenbroek  *  	    really didn't want the overhead of another argument).
585*b89261baSDavid van Moolenbroek  *
586*b89261baSDavid van Moolenbroek  */
587*b89261baSDavid van Moolenbroek 
getkval(offset,ptr,size,refstr)588*b89261baSDavid van Moolenbroek getkval(offset, ptr, size, refstr)
589*b89261baSDavid van Moolenbroek 
590*b89261baSDavid van Moolenbroek unsigned long offset;
591*b89261baSDavid van Moolenbroek int *ptr;
592*b89261baSDavid van Moolenbroek int size;
593*b89261baSDavid van Moolenbroek char *refstr;
594*b89261baSDavid van Moolenbroek 
595*b89261baSDavid van Moolenbroek {
596*b89261baSDavid van Moolenbroek     if (lseek(kmem, (long)offset, SEEK_SET) == -1) {
597*b89261baSDavid van Moolenbroek         if (*refstr == '!')
598*b89261baSDavid van Moolenbroek             refstr++;
599*b89261baSDavid van Moolenbroek         (void) fprintf(stderr, "%s: lseek to %s: %s\n", KMEM,
600*b89261baSDavid van Moolenbroek 		       refstr, strerror(errno));
601*b89261baSDavid van Moolenbroek         quit(23);
602*b89261baSDavid van Moolenbroek     }
603*b89261baSDavid van Moolenbroek     if (read(kmem, (char *) ptr, size) == -1) {
604*b89261baSDavid van Moolenbroek         if (*refstr == '!')
605*b89261baSDavid van Moolenbroek             return(0);
606*b89261baSDavid van Moolenbroek         else {
607*b89261baSDavid van Moolenbroek             (void) fprintf(stderr, "%s: reading %s: %s\n", KMEM,
608*b89261baSDavid van Moolenbroek 			   refstr, strerror(errno));
609*b89261baSDavid van Moolenbroek             quit(23);
610*b89261baSDavid van Moolenbroek         }
611*b89261baSDavid van Moolenbroek     }
612*b89261baSDavid van Moolenbroek     return(1);
613*b89261baSDavid van Moolenbroek }
614*b89261baSDavid van Moolenbroek 
615*b89261baSDavid van Moolenbroek void (*signal(sig, func))()
616*b89261baSDavid van Moolenbroek     int sig;
617*b89261baSDavid van Moolenbroek     void (*func)();
618*b89261baSDavid van Moolenbroek {
619*b89261baSDavid van Moolenbroek     struct sigaction act;
620*b89261baSDavid van Moolenbroek     struct sigaction oact;
621*b89261baSDavid van Moolenbroek 
622*b89261baSDavid van Moolenbroek     memset (&act, 0, sizeof (act));
623*b89261baSDavid van Moolenbroek     act.sa_handler = func;
624*b89261baSDavid van Moolenbroek 
625*b89261baSDavid van Moolenbroek     if (sigaction (sig, &act, &oact) < 0)
626*b89261baSDavid van Moolenbroek 	return BADSIG;
627*b89261baSDavid van Moolenbroek     return oact.sa_handler;
628*b89261baSDavid van Moolenbroek }
629*b89261baSDavid van Moolenbroek 
630*b89261baSDavid van Moolenbroek /*
631*b89261baSDavid van Moolenbroek  * proc_owner(pid) - returns the uid that owns process "pid", or -1 if
632*b89261baSDavid van Moolenbroek  *		the process does not exist.
633*b89261baSDavid van Moolenbroek  *		It is EXTREMLY IMPORTANT that this function work correctly.
634*b89261baSDavid van Moolenbroek  *		If top runs setuid root (as in SVR4), then this function
635*b89261baSDavid van Moolenbroek  *		is the only thing that stands in the way of a serious
636*b89261baSDavid van Moolenbroek  *		security problem.  It validates requests for the "kill"
637*b89261baSDavid van Moolenbroek  *		and "renice" commands.
638*b89261baSDavid van Moolenbroek  */
proc_owner(pid)639*b89261baSDavid van Moolenbroek int proc_owner(pid)
640*b89261baSDavid van Moolenbroek int pid;
641*b89261baSDavid van Moolenbroek {
642*b89261baSDavid van Moolenbroek     int i;
643*b89261baSDavid van Moolenbroek 
644*b89261baSDavid van Moolenbroek     for (i = 0;  i < nproc; i++)
645*b89261baSDavid van Moolenbroek     {
646*b89261baSDavid van Moolenbroek 	if (pst[i].pst_pid == pid)
647*b89261baSDavid van Moolenbroek 	    return pst[i].pst_uid;
648*b89261baSDavid van Moolenbroek     }
649*b89261baSDavid van Moolenbroek     return -1;
650*b89261baSDavid van Moolenbroek }
651*b89261baSDavid van Moolenbroek 
652*b89261baSDavid van Moolenbroek 
get_tty_names(dir,m)653*b89261baSDavid van Moolenbroek static get_tty_names (dir, m)
654*b89261baSDavid van Moolenbroek char *dir;
655*b89261baSDavid van Moolenbroek int *m;
656*b89261baSDavid van Moolenbroek {
657*b89261baSDavid van Moolenbroek     char name [MAXPATHLEN+1];
658*b89261baSDavid van Moolenbroek     struct dirent **namelist;
659*b89261baSDavid van Moolenbroek     int i, n;
660*b89261baSDavid van Moolenbroek 
661*b89261baSDavid van Moolenbroek     if ((n = scandir (dir, &namelist, NULL, NULL)) < 0)
662*b89261baSDavid van Moolenbroek 	return;
663*b89261baSDavid van Moolenbroek 
664*b89261baSDavid van Moolenbroek     if (ttynames == NULL)
665*b89261baSDavid van Moolenbroek     {
666*b89261baSDavid van Moolenbroek 	nttys = n;
667*b89261baSDavid van Moolenbroek 	ttynames = malloc (n*sizeof (*ttynames));
668*b89261baSDavid van Moolenbroek     }
669*b89261baSDavid van Moolenbroek     else
670*b89261baSDavid van Moolenbroek     {
671*b89261baSDavid van Moolenbroek 	nttys += n;
672*b89261baSDavid van Moolenbroek 	ttynames = realloc (ttynames, nttys*sizeof (*ttynames));
673*b89261baSDavid van Moolenbroek     }
674*b89261baSDavid van Moolenbroek 
675*b89261baSDavid van Moolenbroek     for (i = 0; i < n; i++)
676*b89261baSDavid van Moolenbroek     {
677*b89261baSDavid van Moolenbroek 	struct stat statbuf;
678*b89261baSDavid van Moolenbroek 	char *str = namelist[i]->d_name;
679*b89261baSDavid van Moolenbroek 	if (*str == '.')
680*b89261baSDavid van Moolenbroek 	    continue;
681*b89261baSDavid van Moolenbroek 	sprintf (name, "%s/%s", dir, str);
682*b89261baSDavid van Moolenbroek 	if (stat (name, &statbuf) < 0)
683*b89261baSDavid van Moolenbroek 	    continue;
684*b89261baSDavid van Moolenbroek 
685*b89261baSDavid van Moolenbroek 	if (!isalpha (*str))
686*b89261baSDavid van Moolenbroek 	    str = name + sizeof ("/dev");
687*b89261baSDavid van Moolenbroek 	if (S_ISCHR (statbuf.st_mode))
688*b89261baSDavid van Moolenbroek 	{
689*b89261baSDavid van Moolenbroek 	    ttynames [*m].dev = statbuf.st_rdev;
690*b89261baSDavid van Moolenbroek 	    strncpy (ttynames[*m].name, str, 8);
691*b89261baSDavid van Moolenbroek 	    ttynames[*m].name[9] = '\0';
692*b89261baSDavid van Moolenbroek 	    *m += 1;
693*b89261baSDavid van Moolenbroek 	}
694*b89261baSDavid van Moolenbroek 	else if (S_ISDIR (statbuf.st_mode))
695*b89261baSDavid van Moolenbroek 	    get_tty_names (name, m);
696*b89261baSDavid van Moolenbroek     }
697*b89261baSDavid van Moolenbroek     if (*m < nttys)
698*b89261baSDavid van Moolenbroek 	ttynames[*m].name[0] = '\0';
699*b89261baSDavid van Moolenbroek     free (namelist);
700*b89261baSDavid van Moolenbroek }
701*b89261baSDavid van Moolenbroek 
702