source: trunk/third/top/machine/m_netbsd132.c @ 16185

Revision 16185, 25.9 KB checked in by ghudson, 23 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r16184, which included commits to RCS files with non-trunk default branches.
Line 
1/*
2 * top - a top users display for Unix
3 *
4 * SYNOPSIS:  For a NetBSD-1.3.2 (4.4BSD) system
5 *          Note process resident sizes could be wrong, but ps shows
6 *          zero for them too..
7 *
8 * DESCRIPTION:
9 * Originally written for BSD4.4 system by Christos Zoulas.
10 * Based on the FreeBSD 2.0 version by Steven Wallace && Wolfram Schneider
11 * NetBSD-1.0 port by Arne Helme
12 * NetBSD-1.3.2(sparc) port by moto kawasaki
13 * .
14 * This is the machine-dependent module for NetBSD-1.3.2
15 * Works for:
16 *    NetBSD-1.3.2
17 *
18 * LIBS: -lkvm
19 *
20 * CFLAGS: -DHAVE_GETOPT -D__NetBSD132__
21 *
22 * AUTHOR:  Christos Zoulas <christos@ee.cornell.edu>
23 *          Steven Wallace  <swallace@freebsd.org>
24 *          Wolfram Schneider <wosch@cs.tu-berlin.de>
25 *        Arne Helme <arne@acm.org>
26 *          moto kawasaki <kawasaki@sphere.ad.jp>
27 *
28 * $Id: m_netbsd132.c,v 1.1.1.1 2001-05-08 21:47:58 ghudson Exp $
29 */
30
31
32
33#define LASTPID      /**/  /* use last pid, compiler depended */
34/* #define LASTPID_FIXED /**/
35#define VM_REAL      /**/  /* use the same values as vmstat -s */
36#define USE_SWAP    /**/  /* use swap usage (pstat -s),
37                              need to much cpu time */
38#ifdef __NetBSD132__
39# undef USE_SWAP
40#endif                        /* moto kawasaki */
41/* #define DEBUG 1      /**/
42
43#include <sys/types.h>
44#include <sys/signal.h>
45#include <sys/param.h>
46
47#include "os.h"
48#include <stdio.h>
49#include <nlist.h>
50#include <math.h>
51#include <kvm.h>
52#include <sys/errno.h>
53#include <sys/sysctl.h>
54#include <sys/dir.h>
55#include <sys/dkstat.h>
56#include <sys/file.h>
57#include <sys/time.h>
58
59#ifdef USE_SWAP
60#include <stdlib.h>
61#include <sys/map.h>
62#include <sys/conf.h>
63#endif
64
65static int check_nlist __P((struct nlist *));
66static int getkval __P((unsigned long, int *, int, char *));
67extern char* printable __P((char *));
68
69#include "top.h"
70#include "machine.h"
71
72
73/* get_process_info passes back a handle.  This is what it looks like: */
74
75struct handle
76{
77    struct kinfo_proc **next_proc;    /* points to next valid proc pointer
78
79    int remaining;            /* number of pointers remaining */
80};
81
82/* declarations for load_avg */
83#include "loadavg.h"
84
85#define PP(pp, field) ((pp)->kp_proc . field)
86#define EP(pp, field) ((pp)->kp_eproc . field)
87#define VP(pp, field) ((pp)->kp_eproc.e_vm . field)
88
89/* define what weighted cpu is.  */
90#define weighted_cpu(pct, pp) (PP((pp), p_swtime) == 0 ? 0.0 : \
91                       ((pct) / (1.0 - exp(PP((pp), p_swtime) * logcpu))))
92
93/* what we consider to be process size: */
94#define PROCSIZE(pp) (VP((pp), vm_tsize) + VP((pp), vm_dsize) + VP((pp),
95_ssize))
96
97/* definitions for indices in the nlist array */
98
99
100static struct nlist nlst[] = {
101#define X_CCPU                0
102    { "_ccpu" },              /* 0 */
103#define X_CP_TIME     1
104    { "_cp_time" },           /* 1 */
105#define X_HZ          2
106    { "_hz" },                        /* 2 */
107#define X_STATHZ      3
108    { "_stathz" },            /* 3 */
109#define X_AVENRUN     4
110    { "_averunnable" },               /* 4 */
111
112#ifdef USE_SWAP
113#define VM_SWAPMAP    5
114      { "_swapmap" }, /* list of free swap areas */
115#define VM_NSWAPMAP   6
116      { "_nswapmap" },/* size of the swap map */
117#define VM_SWDEVT     7
118      { "_swdevt" },  /* list of swap devices and sizes */
119#define VM_NSWAP      8
120      { "_nswap" },   /* size of largest swap device */
121#define VM_NSWDEV     9
122      { "_nswdev" },  /* number of swap devices */
123#define VM_DMMAX      10
124      { "_dmmax" },   /* maximum size of a swap block */
125#define VM_NISWAP     11
126      { "_niswap" },
127#define VM_NISWDEV    12
128      { "_niswdev" },
129#endif /* USE_SWAP */
130
131#ifdef VM_REAL
132#ifdef USE_SWAP
133#define X_CNT           13
134#else
135#define X_CNT           5
136#endif
137    { "_cnt" },                       /* struct vmmeter cnt */
138#endif
139
140#ifdef LASTPID
141#if (defined USE_SWAP && defined VM_REAL)
142#define X_LASTPID     14
143#elif (defined VM_REAL)
144#define X_LASTPID     6
145#else
146#define X_LASTPID       5
147#endif
148#ifdef LASTPID_FIXED
149    { "_nextpid" },
150#else
151    { "_nextpid.178" },               /* lastpid, compiler depended
152                               * should be changed
153                               * in /sys/kern/kern_fork.c */
154#endif
155#endif
156
157    { 0 }
158};
159
160/*
161 *  These definitions control the format of the per-process area
162 */
163
164static char header[] =
165  "  PID X        PRI NICE   SIZE   RES STATE   TIME   WCPU    CPU COMMAND";
166/* 0123456   -- field to fill in starts at header+6 */
167#define UNAME_START 6
168
169#define Proc_format \
170      "%5d %-8.8s %3d %4d%7s %5s %-5s%7s %5.2f%% %5.2f%% %.14s"
171
172
173/* process state names for the "STATE" column of the display */
174/* the extra nulls in the string "run" are for adding a slash and
175   the processor number when needed */
176
177char *state_abbrev[] =
178{
179    "", "start", "run\0\0\0", "sleep", "stop", "zomb", "WAIT"
180};
181
182
183static kvm_t *kd;
184
185/* values that we stash away in _init and use in later routines */
186
187static double logcpu;
188
189/* these are retrieved from the kernel in _init */
190
191static          long hz;
192static load_avg  ccpu;
193
194/* these are offsets obtained via nlist and used in the get_ functions */
195
196static unsigned long cp_time_offset;
197static unsigned long avenrun_offset;
198#ifdef LASTPID
199static unsigned long lastpid_offset;
200static long lastpid;
201#endif
202#ifdef VM_REAL
203static unsigned long cnt_offset;
204static long cnt;
205#endif
206/* these are for calculating cpu state percentages */
207
208static long cp_time[CPUSTATES];
209static long cp_old[CPUSTATES];
210static long cp_diff[CPUSTATES];
211
212/* these are for detailing the process states */
213
214int process_states[7];
215char *procstatenames[] = {
216    "", " starting, ", " running, ", " sleeping, ", " stopped, ",
217    " zombie, ", " ABANDONED, ",
218    NULL
219};
220
221/* these are for detailing the cpu states */
222
223int cpu_states[CPUSTATES];
224char *cpustatenames[] = {
225    "user", "nice", "system", "interrupt", "idle", NULL
226};
227
228/* these are for detailing the memory statistics */
229
230int memory_stats[8];
231char *memorynames[] = {
232#ifndef VM_REAL
233    "Real: ", "K/", "K ", "Virt: ", "K/",
234    "K ", "Free: ", "K", NULL
235#else
236#if 0
237    "K Act ", "K Inact ", "K Wired ", "K Free ", "% Swap, ",
238    "K/", "K SWIO",
239#else
240    "K Act ", "K Inact ", "K Wired ", "K Free ", "% Swap, ",
241    "Kin ", "Kout",
242#endif
243    NULL
244#endif
245};
246
247/* these are for keeping track of the proc array */
248
249static int nproc;
250static int onproc = -1;
251static int pref_len;
252static struct kinfo_proc *pbase;
253static struct kinfo_proc **pref;
254
255/* these are for getting the memory statistics */
256
257static int pageshift;         /* log base 2 of the pagesize */
258
259/* define pagetok in terms of pageshift */
260
261#define pagetok(size) ((size) << pageshift)
262
263/* useful externals */
264long percentages();
265
266int
267machine_init(statics)
268
269struct statics *statics;
270
271{
272    register int i = 0;
273    register int pagesize;
274
275    if ((kd = kvm_open(NULL, NULL, NULL, O_RDONLY, "kvm_open")) == NULL)
276      return -1;
277
278
279    /* get the list of symbols we want to access in the kernel */
280    (void) kvm_nlist(kd, nlst);
281    if (nlst[0].n_type == 0)
282    {
283      fprintf(stderr, "top: nlist failed\n");
284      return(-1);
285    }
286
287    /* make sure they were all found */
288    if (i > 0 && check_nlist(nlst) > 0)
289    {
290      return(-1);
291    }
292
293    /* get the symbol values out of kmem */
294    (void) getkval(nlst[X_STATHZ].n_value, (int *)(&hz), sizeof(hz), "!");
295    if (!hz) {
296      (void) getkval(nlst[X_HZ].n_value, (int *)(&hz), sizeof(hz),
297                     nlst[X_HZ].n_name);
298    }
299
300
301#if (defined DEBUG)
302    fprintf(stderr, "Hertz: %d\n", hz);
303#endif
304
305    (void) getkval(nlst[X_CCPU].n_value,   (int *)(&ccpu),    sizeof(ccpu),
306          nlst[X_CCPU].n_name);
307
308    /* stash away certain offsets for later use */
309    cp_time_offset = nlst[X_CP_TIME].n_value;
310    avenrun_offset = nlst[X_AVENRUN].n_value;
311#ifdef LASTPID
312    lastpid_offset =  nlst[X_LASTPID].n_value;
313#endif
314#ifdef VM_REAL
315    cnt_offset = nlst[X_CNT].n_value;
316#endif
317
318    /* this is used in calculating WCPU -- calculate it ahead of time */
319    logcpu = log(loaddouble(ccpu));
320
321    pbase = NULL;
322    pref = NULL;
323    nproc = 0;
324    onproc = -1;
325    /* get the page size with "getpagesize" and calculate pageshift from it
326
327    pagesize = getpagesize();
328    pageshift = 0;
329    while (pagesize > 1)
330    {
331      pageshift++;
332      pagesize >>= 1;
333    }
334
335    /* we only need the amount of log(2)1024 for our conversion */
336    pageshift -= LOG1024;
337
338    /* fill in the statics information */
339    statics->procstate_names = procstatenames;
340    statics->cpustate_names = cpustatenames;
341    statics->memory_names = memorynames;
342
343    /* all done! */
344    return(0);
345}
346
347char *format_header(uname_field)
348
349register char *uname_field;
350
351{
352    register char *ptr;
353
354    ptr = header + UNAME_START;
355    while (*uname_field != '\0')
356    {
357      *ptr++ = *uname_field++;
358    }
359
360    return(header);
361}
362
363static int swappgsin = -1;
364static int swappgsout = -1;
365extern struct timeval timeout;
366
367void
368get_system_info(si)
369
370struct system_info *si;
371
372{
373    long total;
374    load_avg avenrun[3];
375
376    /* get the cp_time array */
377    (void) getkval(cp_time_offset, (int *)cp_time, sizeof(cp_time),
378                 nlst[X_CP_TIME].n_name);
379    (void) getkval(avenrun_offset, (int *)avenrun, sizeof(avenrun),
380                 nlst[X_AVENRUN].n_name);
381
382#ifdef LASTPID
383    (void) getkval(lastpid_offset, (int *)(&lastpid), sizeof(lastpid),
384                 "!");
385#endif
386
387    /* convert load averages to doubles */
388    {
389      register int i;
390      register double *infoloadp;
391      load_avg *avenrunp;
392
393#ifdef notyet
394      struct loadavg sysload;
395      int size;
396      getkerninfo(KINFO_LOADAVG, &sysload, &size, 0);
397#endif
398
399      infoloadp = si->load_avg;
400      avenrunp = avenrun;
401      for (i = 0; i < 3; i++)
402      {
403#ifdef notyet
404          *infoloadp++ = ((double) sysload.ldavg[i]) / sysload.fscale;
405#endif
406          *infoloadp++ = loaddouble(*avenrunp++);
407      }
408    }
409
410    /* convert cp_time counts to percentages */
411    total = percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff);
412
413    /* sum memory statistics */
414    {
415
416#ifndef VM_REAL
417      struct vmtotal total;
418      int size = sizeof(total);
419      static int mib[] = { CTL_VM, VM_METER };
420
421      /* get total -- systemwide main memory usage structure */
422      if (sysctl(mib, 2, &total, &size, NULL, 0) < 0) {
423          (void) fprintf(stderr, "top: sysctl failed: %s\n",
424rerror(errno));
425          bzero(&total, sizeof(total));
426      }
427      /* convert memory stats to Kbytes */
428      memory_stats[0] = -1;
429      memory_stats[1] = pagetok(total.t_arm);
430      memory_stats[2] = pagetok(total.t_rm);
431      memory_stats[3] = -1;
432      memory_stats[4] = pagetok(total.t_avm);
433      memory_stats[5] = pagetok(total.t_vm);
434      memory_stats[6] = -1;
435      memory_stats[7] = pagetok(total.t_free);
436    }
437#else
438      struct vmmeter sum;
439      static unsigned int swap_delay = 0;
440
441        (void) getkval(cnt_offset, (int *)(&sum), sizeof(sum),
442                 "_cnt");
443
444      /* convert memory stats to Kbytes */
445      memory_stats[0] = pagetok(sum.v_active_count);
446      memory_stats[1] = pagetok(sum.v_inactive_count);
447      memory_stats[2] = pagetok(sum.v_wire_count);
448      memory_stats[3] = pagetok(sum.v_free_count);
449
450        if (swappgsin < 0) {
451          memory_stats[5] = 0;
452          memory_stats[6] = 0;
453      } else {
454          memory_stats[5] = pagetok(((sum.v_pswpin - swappgsin)));
455          memory_stats[6] = pagetok(((sum.v_pswpout - swappgsout)));
456      }
457        swappgsin = sum.v_pswpin;
458      swappgsout = sum.v_pswpout;
459
460#ifdef USE_SWAP
461        if ((memory_stats[5] > 0 || memory_stats[6]) > 0 || swap_delay == 0)
462
463          memory_stats[4] = swapmode();
464      }
465        /* swap_delay++; XXX Arne */
466#else
467        memory_stats[4] = 0;
468#endif
469
470
471      memory_stats[7] = -1;
472    }
473#endif
474    /* set arrays and strings */
475    si->cpustates = cpu_states;
476    si->memory = memory_stats;
477#ifdef LASTPID
478    if(lastpid > 0) {
479      si->last_pid = lastpid;
480    } else {
481      si->last_pid = -1;
482    }
483#else
484    si->last_pid = -1;
485#endif
486
487}
488
489static struct handle handle;
490
491caddr_t get_process_info(si, sel, compare)
492
493struct system_info *si;
494struct process_select *sel;
495int (*compare)();
496
497{
498    register int i;
499    register int total_procs;
500    register int active_procs;
501    register struct kinfo_proc **prefp;
502    register struct kinfo_proc *pp;
503
504    /* these are copied out of sel for speed */
505    int show_idle;
506    int show_system;
507    int show_uid;
508    int show_command;
509
510
511    pbase = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nproc);
512    if (nproc > onproc)
513      pref = (struct kinfo_proc **) realloc(pref, sizeof(struct kinfo_proc
514
515              * (onproc = nproc));
516    if (pref == NULL || pbase == NULL) {
517      (void) fprintf(stderr, "top: Out of memory.\n");
518      quit(23);
519    }
520    /* get a pointer to the states summary array */
521    si->procstates = process_states;
522
523    /* set up flags which define what we are going to select */
524    show_idle = sel->idle;
525    show_system = sel->system;
526    show_uid = sel->uid != -1;
527    show_command = sel->command != NULL;
528
529    /* count up process states and get pointers to interesting procs */
530    total_procs = 0;
531    active_procs = 0;
532    memset((char *)process_states, 0, sizeof(process_states));
533    prefp = pref;
534    for (pp = pbase, i = 0; i < nproc; pp++, i++)
535    {
536      /*
537       *  Place pointers to each valid proc structure in pref[].
538       *  Process slots that are actually in use have a non-zero
539       *  status field.  Processes with P_SYSTEM set are system
540       *  processes---these get ignored unless show_sysprocs is set.
541       */
542      if (PP(pp, p_stat) != 0 &&
543          (show_system || ((PP(pp, p_flag) & P_SYSTEM) == 0)))
544      {
545          total_procs++;
546          process_states[(unsigned char) PP(pp, p_stat)]++;
547          if ((PP(pp, p_stat) != SZOMB) &&
548              (show_idle || (PP(pp, p_pctcpu) != 0) ||
549               (PP(pp, p_stat) == SRUN)) &&
550              (!show_uid || EP(pp, e_pcred.p_ruid) == (uid_t)sel->uid))
551          {
552              *prefp++ = pp;
553              active_procs++;
554          }
555      }
556    }
557
558    /* if requested, sort the "interesting" processes */
559    if (compare != NULL)
560    {
561      qsort((char *)pref, active_procs, sizeof(struct kinfo_proc *),
562mpare);
563    }
564
565    /* remember active and total counts */
566    si->p_total = total_procs;
567    si->p_active = pref_len = active_procs;
568
569    /* pass back a handle */
570    handle.next_proc = pref;
571    handle.remaining = active_procs;
572    return((caddr_t)&handle);
573}
574
575char fmt[128];                /* static area where result is built */
576
577char *format_next_process(handle, get_userid)
578
579caddr_t handle;
580char *(*get_userid)();
581
582{
583    register struct kinfo_proc *pp;
584    register long cputime;
585    register double pct;
586    struct handle *hp;
587
588    /* find and remember the next proc structure */
589    hp = (struct handle *)handle;
590    pp = *(hp->next_proc++);
591    hp->remaining--;
592
593
594    /* get the process's user struct and set cputime */
595    if ((PP(pp, p_flag) & P_INMEM) == 0) {
596      /*
597       * Print swapped processes as <pname>
598       */
599      char *comm = PP(pp, p_comm);
600#define COMSIZ sizeof(PP(pp, p_comm))
601      char buf[COMSIZ];
602      (void) strncpy(buf, comm, COMSIZ);
603      comm[0] = '<';
604      (void) strncpy(&comm[1], buf, COMSIZ - 2);
605      comm[COMSIZ - 2] = '\0';
606      (void) strncat(comm, ">", COMSIZ - 1);
607      comm[COMSIZ - 1] = '\0';
608    }
609
610#if 0
611    /* This does not produce the correct results */
612    cputime = PP(pp, p_uticks) + PP(pp, p_sticks) + PP(pp, p_iticks);
613#endif
614    cputime = PP(pp, p_rtime).tv_sec; /* This does not count interrupts */
615
616    /* calculate the base for cpu percentages */
617    pct = pctdouble(PP(pp, p_pctcpu));
618
619    /* format this entry */
620    sprintf(fmt,
621          Proc_format,
622          PP(pp, p_pid),
623          (*get_userid)(EP(pp, e_pcred.p_ruid)),
624          PP(pp, p_priority) - PZERO,
625          PP(pp, p_nice) - NZERO,
626          format_k(pagetok(PROCSIZE(pp))),
627          format_k(pagetok(VP(pp, vm_rssize))),
628          state_abbrev[(unsigned char) PP(pp, p_stat)],
629          format_time(cputime),
630          10000.0 * weighted_cpu(pct, pp) / hz,
631          10000.0 * pct / hz,
632          printable(PP(pp, p_comm)));
633
634    /* return the result */
635    return(fmt);
636}
637
638
639/*
640 * check_nlist(nlst) - checks the nlist to see if any symbols were not
641 *            found.  For every symbol that was not found, a one-line
642 *            message is printed to stderr.  The routine returns the
643 *            number of symbols NOT found.
644 */
645
646static int check_nlist(nlst)
647
648register struct nlist *nlst;
649
650{
651    register int i;
652
653    /* check to see if we got ALL the symbols we requested */
654    /* this will write one line to stderr for every symbol not found */
655
656    i = 0;
657    while (nlst->n_name != NULL)
658    {
659      if (nlst->n_type == 0)
660      {
661          /* this one wasn't found */
662          (void) fprintf(stderr, "kernel: no symbol named `%s'\n",
663                         nlst->n_name);
664          i = 1;
665      }
666      nlst++;
667    }
668
669    return(i);
670}
671
672
673/*
674 *  getkval(offset, ptr, size, refstr) - get a value out of the kernel.
675 *    "offset" is the byte offset into the kernel for the desired value,
676 *    "ptr" points to a buffer into which the value is retrieved,
677 *    "size" is the size of the buffer (and the object to retrieve),
678 *    "refstr" is a reference string used when printing error meessages,
679 *        if "refstr" starts with a '!', then a failure on read will not
680 *        be fatal (this may seem like a silly way to do things, but I
681 *        really didn't want the overhead of another argument).
682 *
683 */
684
685static int getkval(offset, ptr, size, refstr)
686
687unsigned long offset;
688int *ptr;
689int size;
690char *refstr;
691
692{
693    if (kvm_read(kd, offset, (char *) ptr, size) != size)
694    {
695      if (*refstr == '!')
696      {
697          return(0);
698      }
699      else
700      {
701          fprintf(stderr, "top: kvm_read for %s: %s\n",
702              refstr, strerror(errno));
703          quit(23);
704      }
705    }
706    return(1);
707}
708
709/* comparison routine for qsort */
710
711/*
712 *  proc_compare - comparison function for "qsort"
713 *    Compares the resource consumption of two processes using five
714 *    distinct keys.  The keys (in descending order of importance) are:
715 *    percent cpu, cpu ticks, state, resident set size, total virtual
716 *    memory usage.  The process states are ordered as follows (from least
717 *    to most important):  WAIT, zombie, sleep, stop, start, run.  The
718 *    array declaration below maps a process state index into a number
719 *    that reflects this ordering.
720 */
721
722static unsigned char sorted_state[] =
723{
724    0,        /* not used             */
725    3,        /* sleep                */
726    1,        /* ABANDONED (WAIT)     */
727    6,        /* run                  */
728    5,        /* start                */
729    2,        /* zombie               */
730    4 /* stop                 */
731};
732
733int
734proc_compare(pp1, pp2)
735
736struct proc **pp1;
737struct proc **pp2;
738
739{
740    register struct kinfo_proc *p1;
741    register struct kinfo_proc *p2;
742    register int result;
743    register pctcpu lresult;
744
745    /* remove one level of indirection */
746    p1 = *(struct kinfo_proc **) pp1;
747    p2 = *(struct kinfo_proc **) pp2;
748
749    /* compare percent cpu (pctcpu) */
750    if ((lresult = PP(p2, p_pctcpu) - PP(p1, p_pctcpu)) == 0)
751    {
752      /* use cpticks to break the tie */
753      if ((result = PP(p2, p_cpticks) - PP(p1, p_cpticks)) == 0)
754      {
755          /* use process state to break the tie */
756          if ((result = sorted_state[(unsigned char) PP(p2, p_stat)] -
757                        sorted_state[(unsigned char) PP(p1, p_stat)])  == 0)
758          {
759              /* use priority to break the tie */
760              if ((result = PP(p2, p_priority) - PP(p1, p_priority)) == 0)
761              {
762                  /* use resident set size (rssize) to break the tie */
763                  if ((result = VP(p2, vm_rssize) - VP(p1, vm_rssize)) == 0)
764                  {
765                      /* use total memory to break the tie */
766                      result = PROCSIZE(p2) - PROCSIZE(p1);
767                  }
768              }
769          }
770      }
771    }
772    else
773    {
774      result = lresult < 0 ? -1 : 1;
775    }
776
777    return(result);
778}
779
780
781/*
782 * proc_owner(pid) - returns the uid that owns process "pid", or -1 if
783 *            the process does not exist.
784 *            It is EXTREMLY IMPORTANT that this function work correctly.
785 *            If top runs setuid root (as in SVR4), then this function
786 *            is the only thing that stands in the way of a serious
787 *            security problem.  It validates requests for the "kill"
788 *            and "renice" commands.
789 */
790
791int proc_owner(pid)
792
793int pid;
794
795{
796    register int cnt;
797    register struct kinfo_proc **prefp;
798    register struct kinfo_proc *pp;
799
800    prefp = pref;
801    cnt = pref_len;
802    while (--cnt >= 0)
803    {
804      pp = *prefp++;
805      if (PP(pp, p_pid) == (pid_t)pid)
806      {
807          return((int)EP(pp, e_pcred.p_ruid));
808      }
809    }
810    return(-1);
811}
812
813
814#ifdef USE_SWAP
815/*
816 * swapmode is based on a program called swapinfo written
817 * by Kevin Lahey <kml@rokkaku.atl.ga.us>.
818 */
819
820#define       SVAR(var) __STRING(var) /* to force expansion */
821#define       KGET(idx,
822r)                                                  \
823      KGET1(idx, &var, sizeof(var), SVAR(var))
824#define       KGET1(idx, p, s,
825g)                                           \
826      KGET2(nlst[idx].n_value, p, s, msg)
827#define       KGET2(addr, p, s,
828g)                                          \
829      if (kvm_read(kd, (u_long)(addr), p, s) != s)                    \
830              warnx("cannot read %s: %s", msg, kvm_geterr(kd))
831#define       KGETRET(addr, p, s,
832g)                                        \
833      if (kvm_read(kd, (u_long)(addr), p, s) != s) {                  \
834              warnx("cannot read %s: %s", msg, kvm_geterr(kd));       \
835              return (0);                                             \
836      }
837
838int
839swapmode()
840{
841      char *header;
842      int hlen, nswap, nswdev, dmmax, nswapmap, niswap, niswdev;
843      int s, e, div, i, l, avail, nfree, npfree, used;
844      struct swdevt *sw;
845      long blocksize, *perdev;
846      struct map *swapmap, *kswapmap;
847      struct mapent *mp, *freemp;
848
849      KGET(VM_NSWAP, nswap);
850      KGET(VM_NSWDEV, nswdev);
851      KGET(VM_DMMAX, dmmax);
852      KGET(VM_NSWAPMAP, nswapmap);
853      KGET(VM_SWAPMAP, kswapmap);     /* kernel `swapmap' is a pointer */
854      if ((sw = malloc(nswdev * sizeof(*sw))) == NULL ||
855          (perdev = malloc(nswdev * sizeof(*perdev))) == NULL ||
856          (freemp = mp = malloc(nswapmap * sizeof(*mp))) == NULL)
857              err(1, "malloc");
858      KGET1(VM_SWDEVT, sw, nswdev * sizeof(*sw), "swdevt");
859      KGET2((long)kswapmap, mp, nswapmap * sizeof(*mp), "swapmap");
860
861      /* Supports sequential swap */
862      if (nlst[VM_NISWAP].n_value != 0) {
863              KGET(VM_NISWAP, niswap);
864              KGET(VM_NISWDEV, niswdev);
865      } else {
866              niswap = nswap;
867              niswdev = nswdev;
868      }
869
870      /* First entry in map is `struct map'; rest are mapent's. */
871      swapmap = (struct map *)mp;
872      if (nswapmap != swapmap->m_limit - (struct mapent *)kswapmap)
873              errx(1, "panic: nswapmap goof");
874
875      /* Count up swap space. */
876      nfree = 0;
877      memset(perdev, 0, nswdev * sizeof(*perdev));
878      for (mp++; mp->m_addr != 0; mp++) {
879              s = mp->m_addr;                 /* start of swap region */
880              e = mp->m_addr + mp->m_size;    /* end of region */
881              nfree += mp->m_size;
882
883              /*
884               * Swap space is split up among the configured disks.
885               *
886               * For interleaved swap devices, the first dmmax blocks
887               * of swap space some from the first disk, the next dmmax
888               * blocks from the next, and so on up to niswap blocks.
889               *
890               * Sequential swap devices follow the interleaved devices
891               * (i.e. blocks starting at niswap) in the order in which
892               * they appear in the swdev table.  The size of each device
893               * will be a multiple of dmmax.
894               *
895               * The list of free space joins adjacent free blocks,
896               * ignoring device boundries.  If we want to keep track
897               * of this information per device, we'll just have to
898               * extract it ourselves.  We know that dmmax-sized chunks
899               * cannot span device boundaries (interleaved or sequential)
900               * so we loop over such chunks assigning them to devices.
901               */
902              i = -1;
903              while (s < e) {         /* XXX this is inefficient */
904                      int bound = roundup(s+1, dmmax);
905
906                      if (bound > e)
907                              bound = e;
908                      if (bound <= niswap) {
909                              /* Interleaved swap chunk. */
910                              if (i == -1)
911                                      i = (s / dmmax) % niswdev;
912                              perdev[i] += bound - s;
913                              if (++i >= niswdev)
914                                      i = 0;
915                      } else {
916                              /* Sequential swap chunk. */
917                              if (i < niswdev) {
918                                      i = niswdev;
919                                      l = niswap + sw[i].sw_nblks;
920                              }
921                              while (s >= l) {
922                                      /* XXX don't die on bogus blocks */
923                                      if (i == nswdev-1)
924                                              break;
925                                      l += sw[++i].sw_nblks;
926                              }
927                              perdev[i] += bound - s;
928                      }
929                      s = bound;
930              }
931      }
932
933      header = getbsize(&hlen, &blocksize);
934      div = blocksize / 512;
935      avail = npfree = 0;
936      for (i = 0; i < nswdev; i++) {
937              int xsize, xfree;
938
939              xsize = sw[i].sw_nblks;
940              xfree = perdev[i];
941              used = xsize - xfree;
942              npfree++;
943              avail += xsize;
944      }
945
946      /*
947       * If only one partition has been set up via swapon(8), we don't
948       * need to bother with totals.
949       */
950      used = avail - nfree;
951      free (sw); free (freemp); free (perdev);
952      return  (int)(((double)used / (double)avail * 100.0) + 0.5);
953}
954
955
956#endif
957
Note: See TracBrowser for help on using the repository browser.