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

Revision 16185, 32.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 Intel based SysVr4.2MP  (UnixWare 2)
5 *
6 * DESCRIPTION:
7 * System V release 4.2MP for i?86 (UnixWare2)
8 *
9 * LIBS:        -lelf
10 *
11 * CFLAGS:      -DHAVE_GETOPT -DORDER
12
13 * AUTHOR:      Daniel Harris   <daniel@greencape.com.au>
14 *              Mike Hopkirk    <hops@sco.com>
15 *
16 * BASED ON:    Most of the work in this module is attributable to the
17 *              authors of m_svr42.c and m_sunos5.c.  (Thanks!)
18 *
19 *              Originally written by Daniel Green as an implementation for
20 *              Unixware7 (sysVr5)
21 *              Incomplete for that but applied by Mike Hopkirk to svr4.2MP
22 *              for which there was not a working port available.
23 *             
24 * NOTES:
25 *
26 *      You shouldn't make this setuid anything.  It doesn't flip between
27 *      saved uids.
28 *
29 *      This module looks nothing like other top modules.  In my deluded
30 *      world, function follows form.  Code needs to look good in order
31 *      to work.  :-)  Apologies to anyone offended by by reformatting.
32 *
33 *      The number of processes is calculated by the number of entries in the
34 *      /proc filesystem.
35 *
36 *      sysinfo structure should be available from the kernel in preference
37 *      to following met_localdata_ptrs_p but if so its naming is obscure.
38 *
39 *      Ordering of tasks other than by the default isn't implemented yet.
40 *
41 *      Nice value is always displayed as 0 due bug in UW2
42 *
43 *
44 * DATE         CHANGE
45 * 03/09/1998   Couple of comment changes.  Prepare for release.
46 * 13/06/1998   Cleaned out debugging code, prepared for limited release.
47 * 09/07/1999   Modified for UnixWare 2 (2.1.2) build - hops
48 *              Added use of system getopt and additional sort orders
49 *
50 */
51
52
53/* ************************************************************************** */
54
55/* build config
56 *  SHOW_NICE - process nice fields always accessed as 0 so changed
57 *     default to display # of threads in use instead.
58 *     define this to display nice fields (values always 0)
59 * #define SHOW_NICE 1
60 */
61
62
63/*
64 * Defines
65 */
66
67#define _KMEMUSER       /* Needed to access appropriate system include file   */
68                        /* structures.                                        */
69
70
71#define UNIX    "/unix" /* Miscellaneous paths.                               */
72#define PROCFS  "/proc"
73#define PATH_KMEM "/dev/kmem"
74
75
76/*
77 * Maximum and minumum priorities.
78 */
79#ifndef PRIO_MAX
80#define PRIO_MAX        20
81#endif
82#ifndef PRIO_MIN
83#define PRIO_MIN        -20
84#endif
85
86
87/*
88 * Scaling factor used to adjust kernel load average numbers.
89 * Unixware note: as I can't find any documentation on the avenrun
90 * symbol, I'm not entirely sure if this is correct.
91 */
92#ifndef FSCALE
93#define FSHIFT  8               /* bits to right of fixed binary point */
94#define FSCALE  (1<<FSHIFT)
95#endif
96
97/* Macro to convert between avenrun load average numbers and normal     */
98/* load average.                                                        */
99#define loaddouble(x) ((double)(x) / FSCALE)
100
101
102/* Convert number of pages to size in kB.                               */
103#define pagetok(size) ((size * PAGESIZE) >> 10)
104
105
106/*
107 * Unixware doesn't explicitly track zombie processes.
108 * However, they can be identified as processes with no threads.
109 * Also, define an additional artificial process state to keep
110 * track of how many zombies there are.
111 */
112#define ZOMBIE(z)       ((z)->p.p_nlwp == 0)
113#define ZOMBIESTATE     6
114
115
116/*
117 * Definitions for the index in the nlist array.
118 */
119#define X_AVENRUN       0
120#define X_NEXTPID       1
121#define X_V             2
122#define X_OFFSETS       3
123#define X_TOTALMEM      4
124
125
126/*
127 * Hash function for the table of processes used to keep old information.
128 */
129#define HASH(x) ((x << 1) % numoldprocs)
130
131
132/* ************************************************************************** */
133
134/*
135 * Include files
136 */
137
138#include "utils.h"
139#include <stdio.h>
140#include <fcntl.h>
141#include <unistd.h>
142#include <stdlib.h>
143#include <errno.h>
144#include <dirent.h>
145#include <nlist.h>
146#include <string.h>
147#include <sys/types.h>
148#include <sys/param.h>
149#include <sys/proc.h>
150#include <sys/procfs.h>
151#include <sys/sysinfo.h>
152#include <sys/sysmacros.h>
153#include <sys/vmmeter.h>
154#include <sys/ksym.h>
155#include <vm/anon.h>
156#include <sys/priocntl.h>
157#include <sys/rtpriocntl.h>
158#include <sys/tspriocntl.h>
159#include <sys/procset.h>
160#include <sys/var.h>
161#include <sys/metrics.h>
162#include <sys/time.h>
163
164#include "top.h"
165#include "machine.h"
166
167
168/* ************************************************************************** */
169
170
171/*
172 * Structures
173 */
174
175/*
176 * A process is just a thread container under Unixware.
177 * So, define the following structure which will aggregate
178 * most of what we want.
179 */
180struct  uwproc
181{
182        int             dummy;
183        struct  psinfo  ps;
184        struct  proc    p;
185        struct  lwp     l;
186        double          pctcpu;
187        double          wcpu;
188};
189
190/* defines to simplify access to some of contents of uwproc struct */
191#define PR_pri   ps.pr_lwp.pr_pri
192#define PR_state ps.pr_lwp.pr_state
193#define PR_time  ps.pr_lwp.pr_time
194
195
196/*
197 * oldproc
198 * Oldproc is used to hold process CPU history necessary to
199 * calculate %CPU and WCPU figures.
200 */
201struct oldproc
202{
203        int     oldpid;
204        double  oldtime;        /* Duration of process in ns.   */
205        double  oldpct;
206};
207
208
209/*
210 * nlist
211 * An array of the kernel sybols used by this module.
212 */
213static struct nlist nlst[] =
214{
215        {"avenrun"},                    /* 0 X_AVENRUN   */
216        {"nextpid"},                    /* 1 X_NEXTPID   */
217        {"v"},                          /* 2 X_V         */
218        {"met_localdata_ptrs_p"},       /* 3 X_OFFSETS */
219        {"totalmem"},                   /* 4 X_TOTALMEM  */
220        {NULL}
221};
222
223
224/*
225 * Get_process_info passes back a handle.  This is what it looks like:
226 */
227
228struct handle
229{
230        struct uwproc   **next_proc;    /* points to next valid proc pointer */
231        int               remaining;    /* number of pointers remaining */
232};
233
234
235/* ************************************************************************** */
236
237
238/*
239 * Globals
240 */
241
242static unsigned long    avenrun_offset;
243static unsigned long    nextpid_offset;
244static unsigned long    v_offset;
245static unsigned long    offset_offset;
246static unsigned long    totalmem_offset;
247
248static int              kmem = -1;      /* FD to /dev/kmem.                   */
249
250static int              maxprocs;       /* Maximum number of processes that   */
251                                        /* can be running on the system.      */
252
253static int              numoldprocs;    /* Size of oldproc hash.              */
254
255static int              numprocs = 0;   /* Number of processes currently      */
256                                        /* running on the system.  Updated    */
257                                        /* each time getptable() is called.   */
258static int              bytes;          /* Size of array of process structs.  */
259static struct uwproc   *pbase;          /* Pointer to array of process info.  */
260static struct uwproc  **pref;           /* Vector of uwbase pointers.         */
261static struct oldproc  *oldbase;        /* Pointer to array of old proc info. */
262
263static DIR             *procdir;
264
265extern int              errno;
266extern char            *myname;
267
268
269/*
270 * An abbreviation of the states each process may be in.
271 */
272char *state_abbrev[] =
273        { "oncpu", "run", "sleep", "stop", "idle", "zomb", NULL};
274
275
276/*
277 * The states each process may be in.
278 */
279int process_states[6];
280char *procstatenames[] =
281{
282        " on cpu, ", " running, ", " sleeping, ", " stopped, ",
283        " idle, ", " zombie", NULL
284};
285
286
287/*
288 * CPU usage tracked by the kernel.
289 */
290#define CPUSTATES       4
291
292int cpu_states[CPUSTATES];
293char *cpustatenames[] =
294        {"idle", "wait", "user", "sys", NULL};
295
296
297/*
298 * These are for detailing the memory statistics.
299 */
300int memory_stats[3];
301char *memorynames[] =
302        {"K phys, ", "K swap, ", "K swap free", NULL};
303
304
305/*
306 *  These definitions control the format of the per-process area
307 */
308static char header[] =
309#ifdef SHOW_NICE
310    "  PID X        PRI NICE  SIZE   RES STATE   TIME   WCPU    CPU COMMAND";
311#else
312    "  PID X        PRI  THR  SIZE   RES STATE   TIME   WCPU    CPU  COMMAND";
313#endif
314
315/* 0123456   -- field to fill in starts at header+6 */  /* XXXX */
316#define UNAME_START 6
317#define PROC_FORMAT "%5d %-8.8s %3d %4d %5s %5s %-5s %6s %5.2f%% %5.2f%% %s"
318
319/* these are names given to allowed sorting orders -- first is default */
320char *ordernames[] =
321{"cpu", "state", "size", "res", "time", "pid", "uid", "rpid", "ruid", NULL};
322
323
324/* ************************************************************************** */
325
326
327/*
328 * Prototypes
329 */
330
331int             machine_init(struct statics *);
332char            *format_header(char *);
333void            get_system_info(struct system_info *);
334caddr_t         get_process_info(struct system_info *,
335                                 struct process_select *, int (*)());
336char            *format_next_process(caddr_t, char *(*)());
337int             check_nlist(register struct nlist *);
338int             getkval(unsigned long, void *, int, char *);
339int             proc_compare(void *, void *);
340void            getptable(struct uwproc *);
341uid_t           proc_owner(pid_t);
342int             setpriority(int, int, int);
343void            get_swapinfo(long *, long *);
344
345/* forward definitions for comparison functions */
346int compare_state(void *, void *);
347int compare_cpu(void *, void *);
348int compare_size(void *, void *);
349int compare_res(void *, void *);
350int compare_time(void *, void *);
351int compare_pid(void *, void *);
352int compare_uid(void *, void *);
353int compare_rpid(void *, void *);
354int compare_ruid(void *, void *);
355
356int (*proc_compares[])() = {
357    compare_cpu,
358    compare_state,
359    compare_size,
360    compare_res,
361    compare_time,
362    compare_pid,
363    compare_uid,
364    compare_rpid,
365    compare_ruid,
366    NULL };
367
368
369extern long     percentages ();
370extern void     quit ();
371
372
373
374/* ************************************************************************** */
375
376/*
377 * machine_int
378 * Perform once-off initialisation tasks.
379 */
380int
381machine_init (struct statics *statics)
382{
383        static   struct var              v;
384        struct  oldproc                 *op;
385        int                              i;
386
387        /*
388         * Fill in the statics information.
389         */
390        statics->procstate_names        = procstatenames;
391        statics->cpustate_names         = cpustatenames;
392        statics->memory_names           = memorynames;
393
394        statics->order_names            = ordernames;
395
396        /*
397         * Go through the kernel symbols required for this
398         * module, and check that they are available.
399         */
400        if (nlist (UNIX, nlst))
401        {
402                fprintf (stderr, "Unable to nlist %s\n", UNIX);
403                return -1;
404        }
405
406        /*
407         * Make sure they were all found.
408         */
409        if (check_nlist (nlst) > 0)
410                return -1;
411
412        /*
413         * Open KMEM device for future use.
414         */
415        kmem    = open(PATH_KMEM, O_RDONLY);
416        if (kmem == -1)
417        {
418                perror(PATH_KMEM);
419                return -1;
420        }
421
422        /*
423         * Extract the maximum number of running processes.
424         */
425        getkval(nlst[X_V].n_value, (void *)&v, sizeof(v), nlst[X_V].n_name);
426        maxprocs                = v.v_proc;
427
428        /*
429         * Save pointers.
430         */
431        avenrun_offset          = nlst[X_AVENRUN].n_value;
432        nextpid_offset          = nlst[X_NEXTPID].n_value;
433        v_offset                = nlst[X_V].n_value;
434        offset_offset           = nlst[X_OFFSETS].n_value;
435        totalmem_offset         = nlst[X_TOTALMEM].n_value;
436
437        /*
438         * Allocate space for proc structure array and array of pointers.
439         */
440        bytes    = maxprocs * sizeof (struct uwproc);
441
442        pbase    = (struct uwproc *) malloc (bytes);
443        pref     = (struct uwproc **)
444                   malloc (maxprocs * sizeof (struct uwproc *));
445
446        numoldprocs = maxprocs * 2;
447        oldbase  = (struct oldproc *)malloc(numoldprocs *
448                                            sizeof(struct oldproc));
449
450        if (pbase == (struct uwproc *) NULL ||
451            pref == (struct uwproc **) NULL ||
452            oldbase == (struct oldproc *) NULL)
453        {
454                fprintf(stderr, "%s: can't allocate sufficient memory\n",
455                        myname);
456                return -1;
457        }
458
459        /*
460         * Obtain a handle on the /proc filesystem, and change into it.
461         */
462        if (!(procdir = opendir (PROCFS)))
463        {
464                fprintf (stderr, "Unable to open %s\n", PROCFS);
465                return -1;
466        }
467
468        if (chdir (PROCFS))
469        {
470                fprintf (stderr, "Unable to chdir to %s\n", PROCFS);
471                return -1;
472        }
473
474        /*
475         * Initialise the oldproc structures.
476         */
477        for (op = oldbase, i = 0; i < numoldprocs; i++)
478        {
479                op[i].oldpid    = -1;
480        }
481
482
483        /*
484         * All done!
485         */
486        return (0);
487}
488
489/* ************************************************************************** */
490
491/*
492 * format_header
493 */
494
495char *
496format_header (char *uname_field)
497{
498        register char *ptr;
499
500        ptr = header + UNAME_START;
501        while (*uname_field != '\0')
502                *ptr++ = *uname_field++;
503
504        return (header);
505}
506
507/* ************************************************************************** */
508
509/*
510 * Extract information out of system data structures.
511 */
512void
513get_system_info (struct system_info *si)
514{
515        long                    avenrun[3];
516        static time_t           cp_old[CPUSTATES];
517        static time_t           cp_diff[CPUSTATES];/*for cpu state percentages*/
518        register int            i;
519
520        struct  met_localdata_ptrs      *mlpp;
521        struct  met_localdata_ptrs       mlp;
522        struct  plocalmet                plm;
523        struct  metp_cpu                 mc;
524
525        unsigned        long    totalmem;
526
527        long                    totalswap;
528        long                    totalswapfree;
529
530
531
532        /*
533         * Get process id of last process.
534         */
535        getkval (nextpid_offset, (void *)&(si->last_pid),
536                        sizeof (si->last_pid), "nextpid");
537        si->last_pid--;
538
539
540        /*
541         * Get load average array.
542         */
543        getkval (avenrun_offset, (void *) avenrun, sizeof (avenrun),
544                        "avenrun");
545       
546        /*
547         * Convert load averages to doubles.
548         */
549        for (i = 0; i < 3; i++)
550                si->load_avg[i] = loaddouble (avenrun[i]);
551
552        /*
553         * Extract CPU percentages.
554         */
555
556        /*
557         * 1. Retrieve pointer to metrics data structure.
558         */
559        getkval(offset_offset, (void *)&mlpp,
560                sizeof (struct met_localdata_ptrs_p *),
561                "met_localdata_ptrs_pp");
562
563        /*
564         * 2. Retrieve metrics data structure. (ptr to metrics engine)
565         */
566        getkval((unsigned long)mlpp, (void *)&mlp, sizeof (mlp),
567                "met_localdata_ptrs_p");
568
569        /*
570         * 3. Retrieve (first local metrics) plocalmet data structure.
571         */
572        getkval((unsigned long)mlp.localdata_p[0], (void *)&plm,
573                sizeof(struct plocalmet), "plocalmet");
574
575        percentages(CPUSTATES, cpu_states, plm.metp_cpu.mpc_cpu,
576                    cp_old, cp_diff);
577
578        /*
579         * Retrieve memory information.
580         */
581
582        /*
583         * 1.   Get physical memory size.
584         */
585        getkval(totalmem_offset, (void *)&totalmem, sizeof (unsigned long),
586                "totalmem");
587
588        /*
589         * 2.   Get physical swap size, and amount of swap remaining.
590         */
591        get_swapinfo(&totalswap, &totalswapfree);
592
593
594        /*
595         * Insert memory information into memory_stat structure.
596         */
597        memory_stats[0] = totalmem >> 10;
598        memory_stats[1] = pagetok(totalswap);
599        memory_stats[2] = pagetok(totalswapfree);
600
601        /*
602         * Set arrays and strings.
603         */
604        si->cpustates   = cpu_states;
605        si->memory      = memory_stats;
606}
607
608/* ************************************************************************** */
609
610/*
611 * Extract process information.
612 */
613static struct handle handle;
614caddr_t
615get_process_info (
616                   struct system_info *si,
617                   struct process_select *sel,
618                   int (*compare) ())
619{
620        register int    i;
621        register int    j = 0;
622        register int    active_procs;
623        register int    total_procs;
624        register struct uwproc **prefp;
625        register struct uwproc *uwp;
626
627
628        /*
629         * These are copied out of sel for speed.
630         */
631        int             show_idle;
632        int             show_system;
633        int             show_uid;
634
635        /*
636         * Read all the proc structures.
637         */
638        getptable (pbase);
639
640
641        /*
642         * Get a pointer to the states summary array.
643         */
644        si->procstates  = process_states;
645
646
647        /*
648         * Set up flags which define what we are going to select.
649         */
650        show_idle       = sel->idle;
651        show_system     = sel->system;
652        show_uid        = sel->uid != -1;
653
654        /*
655         * Count up process states and get pointers to interesting procs.
656         */
657        total_procs     = 0;
658        active_procs    = 0;
659
660
661        (void) memset (process_states, 0, sizeof (process_states));
662        prefp           = pref;
663
664        for (i = 0; i < numprocs; i++)
665        {
666
667                uwp     = &pbase[i];
668
669                /*
670                 * Place pointers to each valid proc structure in pref[].
671                 * Processes with P_SYS set are system processes---these
672                 * get ignored unless show_system is set.
673                 */
674
675                uwp->dummy      = 0;
676
677                if ((show_system || ((uwp->p.p_flag & P_SYS) == 0)))
678                {
679                        total_procs++;
680
681                        if (ZOMBIE(uwp))
682                        {
683                                process_states[ZOMBIESTATE]++;
684                        }
685                        else
686                        {
687                                if ( (show_idle || uwp->l.l_stat == SRUN ||
688                                      uwp->l.l_stat == SONPROC) &&
689                                     (!show_uid ||
690                                      uwp->ps.pr_uid == (uid_t)sel->uid))
691                                {
692                                        process_states[uwp->l.l_stat]++;
693
694                                        prefp[j]        = uwp;
695
696                                        j++;
697                                        active_procs++;
698                                }
699                        }
700                }
701        }
702
703
704        /*
705         * If requested, sort the "interesting" processes.
706         */
707        if (compare != NULL)
708                qsort ((void *) pref, active_procs,
709                       sizeof (struct uwproc *), compare);
710
711        /*
712         * Remember active and total counts.
713         */
714        si->p_total             = total_procs;
715        si->P_ACTIVE            = active_procs;
716
717        /*
718         * Pass back a handle.
719         */
720        handle.next_proc        = pref;
721        handle.remaining        = active_procs;
722
723        return ((caddr_t) & handle);
724}
725
726
727/* ************************************************************************** */
728/*
729 * Format the output string for a process.
730 */
731char fmt[MAX_COLS];                     /* static area where result is built */
732
733char *
734format_next_process (
735                      caddr_t handle,
736                      char *(*get_userid) ())
737{
738        register struct uwproc          *pp;
739        struct handle                   *hp;
740        register long                    cputime;
741        register double                  pctcpu;
742
743        /*
744         * Find and remember the next proc structure.
745         */
746        hp      = (struct handle *) handle;
747        pp      = *(hp->next_proc++);
748
749        hp->remaining--;
750
751        (void) snprintf (fmt, MAX_COLS,
752                PROC_FORMAT,
753                pp->ps.pr_pid,
754                (*get_userid) (pp->ps.pr_uid),
755                pp->PR_pri,
756#ifdef SHOW_NICE
757                pp->ps.pr_lwp.pr_nice,
758#else
759                (u_short)pp->p.p_nlwp < 999 ? (u_short)pp->p.p_nlwp : 999,
760#endif
761                format_k(pagetok (pp->ps.pr_size)),
762                format_k(pagetok (pp->ps.pr_rssize)),
763                state_abbrev[pp->PR_state],
764                format_time(pp->PR_time.tv_sec),
765                pp->wcpu,
766                pp->pctcpu,
767                pp->ps.pr_fname);
768
769        /*
770         * Return the result.
771         */
772        return (fmt);
773}
774
775/* ************************************************************************** */
776
777/*
778 * check_nlist(nlst) - checks the nlist to see if any symbols were not
779 *              found.  For every symbol that was not found, a one-line
780 *              message is printed to stderr.  The routine returns the
781 *              number of symbols NOT found.
782 */
783int
784check_nlist (register struct nlist *nlst)
785{
786        register int i;
787
788        /*
789         * Check to see if we got ALL the symbols we requested.
790         * This will write one line to stderr for every symbol not found.
791         */
792
793        i = 0;
794
795        while (nlst->n_name != NULL)
796        {
797                if (nlst->n_type == 0)
798                {
799                        /*
800                         * This one wasn't found.
801                         */
802                        fprintf(stderr, "kernel: no symbol named `%s'\n",
803                                nlst->n_name);
804                        i = 1;
805                }
806                nlst++;
807        }
808
809        return (i);
810}
811
812/* ************************************************************************** */
813
814/*
815 *  getkval(offset, ptr, size, refstr) - get a value out of the kernel.
816 *      "offset" is the byte offset into the kernel for the desired value,
817 *      "ptr" points to a buffer into which the value is retrieved,
818 *      "size" is the size of the buffer (and the object to retrieve),
819 *      "refstr" is a reference string used when printing error meessages,
820 *          if "refstr" starts with a '!', then a failure on read will not
821 *          be fatal (this may seem like a silly way to do things, but I
822 *          really didn't want the overhead of another argument).
823 *
824 */
825
826int
827getkval (
828          unsigned long offset,
829          void  *ptr,
830          int    size,
831          char *refstr)
832{
833        if (lseek (kmem, (long) offset, 0) == -1)
834        {
835                if (*refstr == '!')
836                        refstr++;
837                fprintf (stderr, "%s: lseek to %s: %s\n",
838                         myname, refstr, strerror(errno));
839                quit (22);
840        }
841        if (read (kmem, (char *) ptr, size) == -1)
842        {
843                if (*refstr == '!')
844                {
845                        /*
846                         * We lost the race with the kernel,
847                         * process isn't in memory.
848                         */
849                        return (0);
850                }
851                else
852                {
853                        (void) fprintf (stderr, "%s: reading %s: %s\n",
854                        myname, refstr, strerror(errno));
855                        quit (23);
856                }
857        }
858
859        return (1);
860}
861
862
863/* ************************************************************************** */
864
865/*
866 * Extract process table and derive %cpu figures.
867*/
868void
869getptable (struct uwproc *baseptr)
870{
871        struct dirent           *direntp;
872        struct uwproc           *curruwproc;
873        struct oldproc          *op;
874
875        static struct   timeval  lasttime = {0, 0};
876        struct          timeval  thistime;
877
878        double                   alpha, beta, timediff;
879
880        int                      pos, i;
881
882        numprocs                = 0;
883
884
885        gettimeofday(&thistime, NULL);
886
887        /*
888         * Calculate background information for CPU statistic.
889         */
890        if (lasttime.tv_sec)
891        {
892                timediff        = ((double)thistime.tv_sec * 1.0e7 +
893                                   (double)thistime.tv_usec * 10.0) -
894                                  ((double)lasttime.tv_sec * 1.0e7 +
895                                   (double)lasttime.tv_usec * 10.0);
896        }
897        else
898        {
899                timediff        = 1.0e7;
900        }
901
902        /*
903         * Constants for exponential average.  avg = alpha * new + beta * avg
904         * The goal is 50% decay in 30 sec.  However if the sample period
905         * is greater than 30 sec, there's not a lot we can do.
906         */
907        if (timediff < 30.0e7)
908        {
909                alpha   = 0.5 * (timediff / 30.0e7);
910                beta    = 1.0 - alpha;
911        }
912        else
913        {
914                alpha   = 0.5;
915                beta    = 0.5;
916        }
917
918
919        /*
920         * While there are still entries (processes) in the /proc
921         * filesystem to be examined...
922         */
923        for (rewinddir (procdir); direntp = readdir (procdir);)
924        {
925                char    buf[MAXPATHLEN];
926                int     fd;
927                int     rc;
928                int     pos;
929
930                /*
931                 * Ignore parent and current directory entries.
932                 */
933                if (direntp->d_name[0] == '.')
934                        continue;
935
936                /*
937                 * Construct filename representing the psinfo
938                 * structure on disk.
939                 */
940                snprintf(buf, MAXPATHLEN, PROCFS "/%s/psinfo", direntp->d_name);
941               
942                if ((fd = open (buf, O_RDONLY)) == -1)
943                {
944                        fprintf(stderr, "Can't open %s: %s\n", buf,
945                                strerror(errno));
946                        continue;
947                }
948
949                curruwproc              = &baseptr[numprocs];
950
951                /*
952                 * Read in psinfo structure from disk.
953                 */
954                if (read(fd, (void *)&curruwproc->ps,
955                         sizeof(psinfo_t)) != sizeof(psinfo_t))
956                {
957                        close(fd);
958                        fprintf(stderr, "Can't read %s: %s\n", buf,
959                                strerror(errno));
960                        continue;
961                }
962                close(fd);
963
964                /*
965                 * Extract the proc structure from the kernel.
966                 */
967                rc = getkval((unsigned long)curruwproc->ps.pr_addr,
968                                (void *)&curruwproc->p, sizeof(struct proc),
969                                "!proc");
970                if (rc == -1)
971                {
972                        fprintf(stderr, "Can't read proc structure\n");
973                        continue;
974                }
975
976
977                /*
978                 * Extract the lwp structure from the kernel.
979                 */
980                rc = getkval((unsigned long)curruwproc->ps.pr_lwp.pr_addr,
981                                (void *)&curruwproc->l, sizeof(struct lwp),
982                                "!lwp");
983                if (rc == -1)
984                {
985                        fprintf(stderr, "Can't read lwp structure\n");
986                        continue;
987                }
988
989
990                /*
991                 * Work out %cpu figure for process.
992                 */
993                pos     = HASH(curruwproc->p.p_epid);
994
995                while(1)
996                {
997                        if (oldbase[pos].oldpid == -1)
998                        {
999                                /*
1000                                 * Process not present in hash.
1001                                 */
1002                                break;
1003                        }
1004                        if (oldbase[pos].oldpid == curruwproc->p.p_epid)
1005                        {
1006                                double  new;
1007
1008                                /*
1009                                 * Found old data.
1010                                 */
1011                                new = (double)curruwproc->PR_time.tv_sec
1012                                        * 1.0e9 +
1013                                        curruwproc->PR_time.tv_nsec;
1014
1015                                curruwproc->pctcpu = ((
1016                                        (double)curruwproc->PR_time.tv_sec *
1017                                        1.0e9 +
1018                                        (double)curruwproc->PR_time.tv_nsec)
1019                                        - (double)oldbase[pos].oldtime) /
1020                                        timediff;
1021                               
1022
1023                                curruwproc->wcpu = oldbase[pos].oldpct *
1024                                        beta + curruwproc->pctcpu * alpha;
1025                               
1026                                break;
1027                        }
1028
1029                        pos++;
1030                        if (pos == numoldprocs)
1031                        {
1032                                pos     = 0;
1033                        }
1034                }
1035
1036                if (oldbase[pos].oldpid == -1)
1037                {
1038                        /*
1039                         * New process.
1040                         * All of its cputime used.
1041                         */
1042                        if (lasttime.tv_sec)
1043                        {
1044                                curruwproc->pctcpu =
1045                                        (curruwproc->PR_time.tv_sec * 1.0e9
1046                                         + curruwproc->PR_time.tv_nsec) /
1047                                        timediff;
1048
1049                                curruwproc->wcpu   = curruwproc->pctcpu;
1050                        }
1051                        else
1052                        {
1053                                curruwproc->pctcpu      = 0.0;
1054                                curruwproc->wcpu        = 0.0;
1055                        }
1056                }
1057
1058                numprocs++;
1059        }
1060
1061
1062        /*
1063         * Save current CPU time for next time around
1064         * For the moment recreate the hash table each time, as the code
1065         * is easier that way.
1066         */
1067
1068        /*
1069         * Empty the hash table.
1070         */
1071        for (pos = 0; pos < numoldprocs; pos++)
1072        {
1073                oldbase[pos].oldpid     = -1;
1074        }
1075
1076        /*
1077         * Recreate the hash table from the curruwproc information.
1078         */
1079        for (i = 0; i < numprocs; i++)
1080        {
1081
1082                /*
1083                 * Find an empty spot in the hash table.
1084                 */
1085                pos     = HASH(baseptr[i].p.p_epid);
1086
1087
1088                while (1)
1089                {
1090                        if (oldbase[pos].oldpid == -1)
1091                                break;
1092                        pos++;
1093
1094                        if (pos == numoldprocs)
1095                                pos     = 0;
1096                }
1097
1098                oldbase[pos].oldpid     = baseptr[i].p.p_epid;
1099
1100                oldbase[pos].oldtime    = baseptr[i].PR_time.tv_sec *
1101                                           1.0e9 +
1102                                          baseptr[i].PR_time.tv_nsec;
1103
1104                oldbase[pos].oldpct     = baseptr[i].wcpu;
1105        }
1106
1107        lasttime = thistime;
1108}
1109
1110
1111/* ************************************************************************** */
1112
1113/*
1114 * Return the owner of the specified process, for use in commands.c
1115 * as we're running setuid root.
1116 */
1117uid_t
1118proc_owner (pid_t pid)
1119{
1120        register struct uwproc          *uwp;
1121        struct  proc                     p;
1122        int                              i;
1123
1124        for (i = 0, uwp = pbase; i < numprocs; i++, uwp++)
1125        {
1126                if (uwp->p.p_epid == pid)
1127                        return (uwp->ps.pr_uid);
1128        }
1129
1130        return -1;
1131}
1132
1133/* ************************************************************************** */
1134
1135int
1136setpriority (int dummy, int who, int niceval)
1137{
1138        int             scale;
1139        int             prio;
1140        pcinfo_t        pcinfo;
1141        pcparms_t       pcparms;
1142        tsparms_t       *tsparms;
1143
1144        strcpy (pcinfo.pc_clname, "TS");
1145
1146        if (priocntl (0, 0, PC_GETCID, (caddr_t) & pcinfo) == -1)
1147                return -1;
1148
1149        prio = niceval;
1150        if (prio > PRIO_MAX)
1151                prio = PRIO_MAX;
1152        else if (prio < PRIO_MIN)
1153                prio = PRIO_MIN;
1154
1155        tsparms                 = (tsparms_t *) pcparms.pc_clparms;
1156        scale                   = ((tsinfo_t *) pcinfo.pc_clinfo)->ts_maxupri;
1157        tsparms->ts_uprilim     = tsparms->ts_upri = -(scale * prio) / 20;
1158        pcparms.pc_cid          = pcinfo.pc_cid;
1159
1160        if (priocntl (P_PID, who, PC_SETPARMS, (caddr_t) & pcparms) == -1)
1161                return (-1);
1162
1163        return (0);
1164}
1165
1166/* ************************************************************************** */
1167
1168/*
1169 * get_swapinfo
1170 * Get total and free swap.
1171 * Snarfed from m_sunos5.c
1172 */
1173void
1174get_swapinfo(long *total, long *fr)
1175{
1176        register int            cnt, i;
1177        register int            t, f;
1178
1179        struct swaptable        *swt;
1180        struct swapent          *ste;
1181
1182        static char             path[256];
1183
1184        /*
1185         * Get total number of swap entries.
1186         */
1187        cnt     = swapctl(SC_GETNSWP, 0);
1188
1189        /*
1190         * Allocate enough space to hold count + n swapents.
1191         */
1192        swt = (struct swaptable *)malloc(sizeof(int) +
1193        cnt * sizeof(struct swapent));
1194        if (swt == NULL)
1195        {
1196                *total = 0;
1197                *fr = 0;
1198
1199                return;
1200        }
1201        swt->swt_n = cnt;
1202
1203        /*
1204         * Fill in ste_path pointers: we don't care about the paths,
1205         * so we point them all to the same buffer.
1206         */
1207        ste = &(swt->swt_ent[0]);
1208        i = cnt;
1209        while (--i >= 0)
1210        {
1211                ste++->ste_path = path;
1212        }
1213
1214        /*
1215         * Grab all swap info.
1216         */
1217        swapctl(SC_LIST, swt);
1218
1219        /*
1220         * Walk thru the structs and sum up the fields.
1221         */
1222        t = f = 0;
1223        ste = &(swt->swt_ent[0]);
1224        i = cnt;
1225        while (--i >= 0)
1226        {
1227                /*
1228                 * Dont count slots being deleted.
1229                 */
1230                if (!(ste->ste_flags & ST_INDEL))
1231                {
1232                        t += ste->ste_pages;
1233                        f += ste->ste_free;
1234                }
1235                ste++;
1236        }
1237
1238        /*
1239         * Fill in the results.
1240         */
1241        *total = t;
1242        *fr = f;
1243
1244        free(swt);
1245}
1246
1247
1248/* ************************************************************************** */
1249
1250/* comparison routine for qsort */
1251
1252/*
1253 *  proc_compare - comparison function for "qsort"
1254 *      Compares the resource consumption of two processes using five
1255 *      distinct keys.  The keys (in descending order of importance) are:
1256 *      percent cpu, cpu ticks, state, resident set size, total virtual
1257 *      memory usage.  The process states are ordered as follows (from least
1258 *      to most important):  idle, stop, sleep, run, on processor.  The
1259 *      array declaration below maps a process state index into a number
1260 *      that reflects this ordering.
1261 */
1262
1263unsigned char sorted_state[] =
1264{
1265  5,                            /* run on a processor   */
1266  4,                            /* run                  */
1267  3,                            /* sleep                */
1268  2,                            /* stop                 */
1269  1,                            /* idle                 */
1270};
1271
1272
1273#if 0       /* original compare rtn for single sort order */
1274int
1275proc_compare(void *v1, void *v2)
1276{
1277    struct uwproc               **pp1 = (struct uwproc **)v1;
1278    struct uwproc               **pp2 = (struct uwproc **)v2;
1279
1280    register struct uwproc       *p1    = *pp1;
1281    register struct uwproc       *p2  = *pp2;
1282
1283    register long result;
1284
1285    double      d;
1286
1287    /* use %cpu to break the tie. */
1288    d = p2->pctcpu - p1->pctcpu;
1289
1290    if (d == 0.0)
1291    {
1292        /* use cpticks to break the tie */
1293        if ((result = p2->PR_time.tv_sec - p1->PR_time.tv_sec) == 0)
1294          {
1295            /* use process state to break the tie. */
1296            if ((result = (long) (sorted_state[p2->PR_state] -
1297                                  sorted_state[p1->.PR_state])) == 0)
1298              {
1299                /* use priority to break the tie */
1300                if ((result = p2->PR_pri - p1->PR_pri) == 0)
1301                  {
1302                    /* use resident set size (rssize) to break the tie */
1303                    if ((result = p2->ps.pr_rssize - p1->ps.pr_rssize) == 0)
1304                      {
1305                        /* use total memory to break the tie */
1306                        result = (p2->ps.pr_size - p1->ps.pr_size);
1307                      }
1308                  }
1309              }
1310          }
1311    }
1312    else
1313    {
1314        if (d < 0.0)
1315        {
1316                result  = -1;
1317        }
1318        else
1319        {
1320                result  = 1;
1321        }
1322    }
1323
1324    return (result);
1325}
1326#endif
1327
1328/* ----------------- comparison routines for qsort ---------------- */
1329
1330/* First, the possible comparison keys.  These are defined in such a way
1331   that they can be merely listed in the source code to define the actual
1332   desired ordering.
1333 */
1334
1335#define ORDERKEY_PCTCPU  if (dresult = p2->pctcpu - p1->pctcpu,\
1336                             (result = dresult > 0.0 ? 1 : \
1337                             dresult < 0.0 ? -1 : 0) == 0)
1338
1339#define ORDERKEY_CPTICKS if ((result = p2->PR_time.tv_sec - p1->PR_time.tv_sec) == 0)
1340#define ORDERKEY_STATE   if ((result = (long) (sorted_state[p2->PR_state] - \
1341                               sorted_state[p1->PR_state])) == 0)
1342
1343#define ORDERKEY_PRIO    if ((result = p2->PR_pri - p1->PR_pri) == 0)
1344#define ORDERKEY_RSSIZE  if ((result = p2->ps.pr_rssize-p1->ps.pr_rssize) == 0)
1345#define ORDERKEY_MEM     if ((result = (p2->ps.pr_size - p1->ps.pr_size)) == 0)
1346
1347#define ORDERKEY_PID     if ((result = (p2->ps.pr_pid  - p1->ps.pr_pid))  == 0)
1348#define ORDERKEY_UID     if ((result = (p2->ps.pr_uid  - p1->ps.pr_uid))  == 0)
1349#define ORDERKEY_RPID    if ((result = (p1->ps.pr_pid  - p2->ps.pr_pid))  == 0)
1350#define ORDERKEY_RUID    if ((result = (p1->ps.pr_uid  - p2->ps.pr_uid))  == 0)
1351
1352
1353/* compare_cpu - the comparison function for sorting by cpu % (deflt) */
1354int
1355compare_cpu(void *v1, void *v2)
1356{
1357    struct uwproc           **pp1 = (struct uwproc **)v1;
1358    struct uwproc           **pp2 = (struct uwproc **)v2;
1359    register struct uwproc  *p1;
1360    register struct uwproc  *p2;
1361    register long result;
1362    double dresult;
1363
1364    /* remove one level of indirection */
1365    p1 = *pp1;
1366    p2 = *pp2;
1367
1368    ORDERKEY_PCTCPU
1369
1370    ORDERKEY_CPTICKS
1371    ORDERKEY_STATE
1372    ORDERKEY_PRIO
1373    ORDERKEY_RSSIZE
1374    ORDERKEY_MEM
1375
1376    ;
1377
1378    return (result);
1379}
1380
1381/* compare_state - comparison function for sorting by state,pri,time,size */
1382int
1383compare_state (void *v1, void *v2)
1384{
1385    struct uwproc               **pp1 = (struct uwproc **)v1;
1386    struct uwproc               **pp2 = (struct uwproc **)v2;
1387    register struct uwproc  *p1;
1388    register struct uwproc  *p2;
1389    register long result;
1390    double dresult;
1391
1392    /* remove one level of indirection */
1393    p1 = *pp1;
1394    p2 = *pp2;
1395
1396    ORDERKEY_STATE
1397    ORDERKEY_PRIO
1398    ORDERKEY_CPTICKS
1399    ORDERKEY_RSSIZE
1400    ORDERKEY_MEM
1401    ORDERKEY_PCTCPU
1402    ;
1403
1404    return (result);
1405}
1406
1407/* compare_size - the comparison function for sorting by total memory usage */
1408int
1409compare_size(void *v1, void *v2)
1410{
1411    struct uwproc           **pp1 = (struct uwproc **)v1;
1412    struct uwproc           **pp2 = (struct uwproc **)v2;
1413    register struct uwproc  *p1;
1414    register struct uwproc  *p2;
1415    register long           result;
1416    double                  dresult;
1417
1418    /* remove one level of indirection */
1419    p1 = *pp1;
1420    p2 = *pp2;
1421
1422    ORDERKEY_MEM
1423    ORDERKEY_RSSIZE
1424    ORDERKEY_PCTCPU
1425    ORDERKEY_CPTICKS
1426    ORDERKEY_STATE
1427    ORDERKEY_PRIO
1428    ;
1429
1430    return (result);
1431  }
1432
1433/* compare_res - the comparison function for sorting by resident set size */
1434int
1435compare_res(void *v1, void *v2)
1436{
1437    struct uwproc           **pp1 = (struct uwproc **)v1;
1438    struct uwproc           **pp2 = (struct uwproc **)v2;
1439    register struct uwproc  *p1;
1440    register struct uwproc  *p2;
1441    register long result;
1442    double dresult;
1443
1444    /* remove one level of indirection */
1445    p1 = *pp1;
1446    p2 = *pp2;
1447
1448    ORDERKEY_RSSIZE
1449    ORDERKEY_MEM
1450    ORDERKEY_PCTCPU
1451    ORDERKEY_CPTICKS
1452    ORDERKEY_STATE
1453    ORDERKEY_PRIO
1454    ;
1455
1456    return (result);
1457  }
1458
1459/* compare_time - the comparison function for sorting by total cpu time */
1460int
1461compare_time(void *v1, void *v2)
1462{
1463    struct uwproc           **pp1 = (struct uwproc **)v1;
1464    struct uwproc           **pp2 = (struct uwproc **)v2;
1465    register struct uwproc  *p1;
1466    register struct uwproc  *p2;
1467    register long result;
1468    double dresult;
1469
1470    /* remove one level of indirection */
1471    p1 = *pp1;
1472    p2 = *pp2;
1473
1474    ORDERKEY_CPTICKS
1475    ORDERKEY_PCTCPU
1476    ORDERKEY_STATE
1477    ORDERKEY_PRIO
1478    ORDERKEY_MEM
1479    ORDERKEY_RSSIZE
1480    ;
1481
1482    return (result);
1483  }
1484
1485/* compare_pid - the comparison function for sorting by pid */
1486int
1487compare_pid(void *v1, void *v2)
1488{
1489    struct uwproc           **pp1 = (struct uwproc **)v1;
1490    struct uwproc           **pp2 = (struct uwproc **)v2;
1491    register struct uwproc  *p1;
1492    register struct uwproc  *p2;
1493    register long result;
1494    double dresult;
1495
1496    /* remove one level of indirection */
1497    p1 = *pp1;
1498    p2 = *pp2;
1499
1500    ORDERKEY_PID
1501    ORDERKEY_CPTICKS
1502    ORDERKEY_PCTCPU
1503    ORDERKEY_STATE
1504    ORDERKEY_PRIO
1505    ORDERKEY_MEM
1506    ORDERKEY_RSSIZE
1507    ;
1508
1509    return (result);
1510  }
1511
1512/* compare_uid - the comparison function for sorting by user ID */
1513int
1514compare_uid(void *v1, void *v2)
1515{
1516    struct uwproc           **pp1 = (struct uwproc **)v1;
1517    struct uwproc           **pp2 = (struct uwproc **)v2;
1518    register struct uwproc  *p1;
1519    register struct uwproc  *p2;
1520    register long result;
1521    double dresult;
1522
1523    /* remove one level of indirection */
1524    p1 = *pp1;
1525    p2 = *pp2;
1526
1527    ORDERKEY_UID
1528    ORDERKEY_CPTICKS
1529    ORDERKEY_PCTCPU
1530    ORDERKEY_STATE
1531    ORDERKEY_PRIO
1532    ORDERKEY_MEM
1533    ORDERKEY_RSSIZE
1534    ;
1535
1536    return (result);
1537  }
1538
1539/* compare_rpid - the comparison function for sorting by pid ascending */
1540int
1541compare_rpid(void *v1, void *v2)
1542{
1543    struct uwproc           **pp1 = (struct uwproc **)v1;
1544    struct uwproc           **pp2 = (struct uwproc **)v2;
1545    register struct uwproc  *p1;
1546    register struct uwproc  *p2;
1547    register long result;
1548    double dresult;
1549
1550    /* remove one level of indirection */
1551    p1 = *pp1;
1552    p2 = *pp2;
1553
1554    ORDERKEY_RPID
1555    ORDERKEY_CPTICKS
1556    ORDERKEY_PCTCPU
1557    ORDERKEY_STATE
1558    ORDERKEY_PRIO
1559    ORDERKEY_MEM
1560    ORDERKEY_RSSIZE
1561    ;
1562
1563    return (result);
1564  }
1565
1566/* compare_uid - the comparison function for sorting by user ID ascending */
1567int
1568compare_ruid(void *v1, void *v2)
1569{
1570    struct uwproc           **pp1 = (struct uwproc **)v1;
1571    struct uwproc           **pp2 = (struct uwproc **)v2;
1572    register struct uwproc  *p1;
1573    register struct uwproc  *p2;
1574    register long result;
1575    double dresult;
1576
1577    /* remove one level of indirection */
1578    p1 = *pp1;
1579    p2 = *pp2;
1580
1581    ORDERKEY_RUID
1582    ORDERKEY_CPTICKS
1583    ORDERKEY_PCTCPU
1584    ORDERKEY_STATE
1585    ORDERKEY_PRIO
1586    ORDERKEY_MEM
1587    ORDERKEY_RSSIZE
1588    ;
1589
1590    return (result);
1591  }
1592
Note: See TracBrowser for help on using the repository browser.