components/net-snmp/sun/agent/modules/seaExtensions/sunProcesses.c
changeset 252 ee0fb1eabcbf
child 1853 7d5d194ae029
equal deleted inserted replaced
251:f527656d334f 252:ee0fb1eabcbf
       
     1 /*
       
     2  * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
       
     3  *
       
     4  * U.S. Government Rights - Commercial software. Government users are subject
       
     5  * to the Sun Microsystems, Inc. standard license agreement and applicable
       
     6  * provisions of the FAR and its supplements.
       
     7  *
       
     8  *
       
     9  * This distribution may include materials developed by third parties. Sun,
       
    10  * Sun Microsystems, the Sun logo and Solaris are trademarks or registered
       
    11  * trademarks of Sun Microsystems, Inc. in the U.S. and other countries.
       
    12  *
       
    13  */
       
    14 /*
       
    15  * Note: this file originally auto-generated by mib2c using
       
    16  *         : mib2c.iterate.conf,v 5.5 2002/12/16 22:50:18 hardaker Exp $
       
    17  */
       
    18 
       
    19 #include <net-snmp/net-snmp-config.h>
       
    20 #include <net-snmp/net-snmp-includes.h>
       
    21 #include <net-snmp/agent/net-snmp-agent-includes.h>
       
    22 #include "sunProcesses.h"
       
    23 
       
    24 #include <stdio.h>
       
    25 #include <errno.h>
       
    26 #include <sys/types.h>
       
    27 #include <sys/procfs.h>
       
    28 #include <sys/fcntl.h>
       
    29 #include <sys/stat.h>
       
    30 #include <sys/time.h>
       
    31 #include <sys/mntent.h>
       
    32 #include <sys/mnttab.h>
       
    33 #include <ftw.h>
       
    34 #include <stdlib.h>
       
    35 #include <dirent.h>
       
    36 #include <string.h>
       
    37 #include <memory.h>
       
    38 #include <pwd.h>
       
    39 #include <syslog.h>
       
    40 
       
    41 #include "snmpvars.h"
       
    42 #include "agent.h"
       
    43 #include "asn1.h"
       
    44 
       
    45 /* The following code is borrowed from ps.c */
       
    46 #define        NUID        64
       
    47 #define TRUE 1
       
    48 #define FALSE 0
       
    49 
       
    50 #define NTTYS 20      /* max ttys that can be specified with the -t option  */
       
    51 #define SIZ 30        /* max processes that can be specified with -p and -g */
       
    52 #define ARGSIZ 30     /* size of buffer holding args for -t, -p, -u options */
       
    53 
       
    54 #define FSTYPE_MAX 8
       
    55 
       
    56 #ifndef MAXLOGIN
       
    57 #define MAXLOGIN 8    /* max number of chars in login that will be printed */
       
    58 #endif
       
    59 
       
    60 #define UDQ 50
       
    61 
       
    62 
       
    63 static struct prpsinfo info; /* process information structure from /proc */
       
    64 
       
    65 char *ttyname();
       
    66 static char *psfile = "/tmp/mibiisa_ps_data";
       
    67 
       
    68 
       
    69 static int ndev;             /* number of devices */
       
    70 static int maxdev;           /* number of devl structures allocated */
       
    71 
       
    72 #define DNSIZE 14
       
    73 static struct devl {         /* device list */
       
    74     char   dname[DNSIZE]; /* device name */
       
    75     dev_t  dev;           /* device number */
       
    76 } *devl = NULL;
       
    77 
       
    78 static char *procdir = "/proc";  /* standard /proc directory */
       
    79 static int  rd_only = 0;         /* flag for remote filesystem read-only */
       
    80 void usage();             /* print usage message and quit */
       
    81 
       
    82 static time_t ps_cache_time = 0;
       
    83 time_t cache_now = 0;
       
    84 int cache_lifetime = 45;
       
    85 
       
    86 static void call_ftw_for_dev(void);
       
    87 static void wrdata();
       
    88 static void write_tmp_file();
       
    89 static int isprocdir();
       
    90 static void get_ps_data(void);
       
    91 static void clean_ps(ps_ldata_t *);
       
    92 static char *get_usr_name(uid_t);
       
    93 static ps_data_t *find_ps_data(pid_t pid);
       
    94 static void pr_ps(void);
       
    95 
       
    96 ps_data_t *pstable = PS_NULL;
       
    97 int pstable_lines = 0;   /* # of items in memory block pointed    */
       
    98                                 /* to by pstable.                        */
       
    99 
       
   100 static void
       
   101 clean_ps(ps_ldata_t *head)
       
   102 {
       
   103     if (head != PS_LNULL) {
       
   104         ps_ldata_t *pdp;
       
   105         ps_ldata_t *nxt;
       
   106         for (pdp = head; pdp != PS_LNULL; pdp = nxt) {
       
   107             nxt = pdp->link;
       
   108             free(pdp);
       
   109         }
       
   110     }
       
   111 }
       
   112 
       
   113 static int
       
   114 pscomp(ps_data_t *i, ps_data_t *j)
       
   115 {
       
   116     return (i->pid - j->pid);
       
   117 }
       
   118 
       
   119 static struct ncache {
       
   120     uid_t uid;
       
   121     char  name[USRNM_SZ+1];
       
   122 } nc[NUID];
       
   123 
       
   124 /*
       
   125  * This function assumes that the password file is hashed
       
   126  * (or some such) to allow fast access based on a uid key.
       
   127  */
       
   128 static char *
       
   129 get_usr_name(uid_t uid)
       
   130 {
       
   131     struct passwd *pw;
       
   132     int cp;
       
   133 
       
   134 #if        (((NUID) & ((NUID) - 1)) != 0)
       
   135 cp = uid % (NUID);
       
   136 #else
       
   137 cp = uid & ((NUID) - 1);
       
   138 #endif
       
   139     if (uid >= 0 && nc[cp].uid == uid && nc[cp].name[0])
       
   140         return (nc[cp].name);
       
   141     pw = getpwuid(uid);
       
   142     if (!pw)
       
   143         return ((char *)0);
       
   144     nc[cp].uid = uid;
       
   145     strncpy(nc[cp].name, pw->pw_name, USRNM_SZ);
       
   146 
       
   147     return (nc[cp].name);
       
   148 }
       
   149 
       
   150 void
       
   151 pr_ps(void)
       
   152 {
       
   153     ps_data_t *psp;
       
   154     int lines;
       
   155 
       
   156     printf("%d entries\n", pstable_lines);
       
   157     printf("UID   PID   PPID   SZ   USR   WCHAN  TTY  CPU  CMD \n\n");
       
   158 
       
   159     for (psp = pstable, lines = 0; lines < pstable_lines; psp++, lines++) {
       
   160         printf("%d     %u     %u        %d    %s     %s    %s    %d   %s\n",
       
   161             psp->uid,
       
   162             psp->pid,
       
   163             psp->ppid,
       
   164             psp->sz,
       
   165             psp->usrname,
       
   166             psp->wchan,
       
   167             psp->tty,
       
   168             psp->cpu,
       
   169             psp->cmd);
       
   170     }
       
   171 }
       
   172 
       
   173 /*
       
   174  *  Locate a particular PID.
       
   175  *  Return a pointer to the entry or NULL if not found.
       
   176  */
       
   177 static ps_data_t * find_ps_data(pid_t pid)
       
   178 {
       
   179     ps_data_t *psp;
       
   180     ps_data_t key;
       
   181 
       
   182     key.pid = pid;
       
   183 
       
   184     /* Should add a cache here */
       
   185 
       
   186     psp = (ps_data_t *)bsearch((char *)&key, (char *)pstable,
       
   187                             pstable_lines, sizeof (ps_data_t),
       
   188                             (int (*)())pscomp);
       
   189     return (psp);
       
   190 }
       
   191 
       
   192 
       
   193 void
       
   194 get_ps_data(void)
       
   195 {
       
   196     ps_ldata_t *ps_last = PS_LNULL;
       
   197     ps_ldata_t *ps_head = PS_LNULL;
       
   198     ps_ldata_t *psp;
       
   199     ps_data_t  *pstp;
       
   200     static char *usrname;
       
   201     int i = 0;
       
   202     DIR *dirp;
       
   203     struct dirent *dentp;
       
   204     char pname[MAXNAMELEN];
       
   205     int pdlen;
       
   206     char *gettty();
       
   207 
       
   208     if (pstable != PS_NULL) {  /* Don't run ps unless we need to */
       
   209         if ((cache_now - ps_cache_time) <= cache_lifetime)
       
   210             return;
       
   211         free(pstable);
       
   212     }
       
   213 
       
   214     pstable_lines = 0;
       
   215     ps_cache_time = cache_now;
       
   216     /*
       
   217      * Determine root path for remote machine.
       
   218      */
       
   219     if (!readata()) {        /* get data from psfile */
       
   220         call_ftw_for_dev();
       
   221         wrdata();
       
   222     }
       
   223 
       
   224     /*
       
   225      * Determine which processes to print info about by searching
       
   226      * the /proc directory and looking at each process.
       
   227      */
       
   228     if ((dirp = opendir(procdir)) == NULL) {
       
   229         (void) SYSLOG0("Cannot open PROC directory\n");
       
   230         return;
       
   231     }
       
   232 
       
   233     (void) strcpy(pname, procdir);
       
   234     pdlen = strlen(pname);
       
   235     pname[pdlen++] = '/';
       
   236 
       
   237     /* for each active process --- */
       
   238     while (dentp = readdir(dirp)) {
       
   239         int procfd;
       
   240 
       
   241         if (dentp->d_name[0] == '.')                /* skip . and .. */
       
   242                 continue;
       
   243         (void) strcpy(pname + pdlen, dentp->d_name);
       
   244 retry:
       
   245         if ((procfd = open(pname, O_RDONLY)) == -1)
       
   246                 continue;
       
   247 
       
   248         /*
       
   249          * Get the info structure for the process and close quickly.
       
   250          */
       
   251         if (ioctl(procfd, PIOCPSINFO, (char *)&info) == -1) {
       
   252             int saverr = errno;
       
   253 
       
   254             (void) close(procfd);
       
   255             if (saverr == EAGAIN)
       
   256                 goto retry;
       
   257             if (saverr != ENOENT)
       
   258                 (void) SYSLOG2("PIOCPSINFO on %s: %s\n",
       
   259                                pname, strerror(saverr));
       
   260             continue;
       
   261         }
       
   262         (void) close(procfd);
       
   263         if ((psp = (ps_ldata_t *)malloc(sizeof (ps_ldata_t))) == PS_LNULL)
       
   264             break;
       
   265         memset((char *)psp, 0, sizeof (ps_ldata_t));
       
   266         psp->pdata.uid = info.pr_uid;
       
   267         psp->pdata.pid = info.pr_pid;
       
   268         psp->pdata.ppid = info.pr_ppid;
       
   269         psp->pdata.sz = info.pr_size;
       
   270         if (info.pr_wchan)
       
   271             sprintf(psp->pdata.wchan, "%9x", info.pr_wchan);
       
   272         else
       
   273             strcpy(psp->pdata.wchan, "         ");
       
   274         memset(&psp->pdata.stat[0], 0, STAT_SZ+1);
       
   275         if (info.pr_sname)
       
   276             psp->pdata.stat[0] = info.pr_sname;
       
   277         i = 0;
       
   278         strcpy(psp->pdata.tty, (char *)gettty(&i));
       
   279         psp->pdata.cpu = info.pr_time.tv_sec;
       
   280         strcpy(psp->pdata.cmd, info.pr_fname);
       
   281 
       
   282         if ((usrname = (get_usr_name(psp->pdata.uid))) != NULL)
       
   283             strncpy(psp->pdata.usrname, usrname, USRNM_SZ);
       
   284         else {
       
   285             free(psp);
       
   286             continue;
       
   287         }
       
   288 
       
   289         psp->pdata.usrname[USRNM_SZ] = '\0';
       
   290         pstable_lines++;
       
   291         if (ps_last == PS_LNULL)
       
   292             ps_head = psp;
       
   293         else
       
   294             ps_last->link = psp;
       
   295         ps_last = psp;
       
   296     }
       
   297 
       
   298     (void) closedir(dirp);
       
   299     if ((pstable = (ps_data_t *)malloc(pstable_lines
       
   300                     * sizeof (ps_data_t))) == PS_NULL) {
       
   301         clean_ps(ps_head);
       
   302         return;
       
   303     }
       
   304     for (pstp = pstable, psp = ps_head; psp != PS_LNULL;
       
   305                                     pstp++, psp = psp->link) {
       
   306         memcpy((char *)pstp, (char *)&(psp->pdata), sizeof (ps_data_t));
       
   307     }
       
   308     clean_ps(ps_head);
       
   309     qsort(pstable, pstable_lines, sizeof (ps_data_t), (int (*)())pscomp);
       
   310 }
       
   311 
       
   312 int
       
   313 readata()
       
   314 {
       
   315     struct stat sbuf1, sbuf2;
       
   316     int fd;
       
   317 
       
   318     if ((fd = open(psfile, O_RDONLY)) == -1)
       
   319         return (0);
       
   320 
       
   321     if (fstat(fd, &sbuf1) < 0 || sbuf1.st_size == 0 ||
       
   322         stat("/dev", &sbuf2) == -1 || sbuf1.st_mtime <= sbuf2.st_mtime ||
       
   323         sbuf1.st_mtime <= sbuf2.st_ctime) {
       
   324 
       
   325         if (!rd_only) {                /* if read-only, believe old data */
       
   326             (void) close(fd);
       
   327             return (0);
       
   328         }
       
   329     }
       
   330 
       
   331     /* Read /dev data from psfile. */
       
   332     if (read_tmp_file(fd, (char *) &ndev, sizeof (ndev)) == 0)  {
       
   333         (void) close(fd);
       
   334         return (0);
       
   335     }
       
   336 
       
   337     if (devl)
       
   338         free(devl);
       
   339 
       
   340     if ((devl = (struct devl *)malloc(ndev * sizeof (*devl))) == NULL) {
       
   341         SYSLOG1("malloc() for device table failed, %s\n", strerror(errno));
       
   342         exit(1);
       
   343     }
       
   344     if (read_tmp_file(fd, (char *)devl, ndev * sizeof (*devl)) == 0)  {
       
   345         (void) close(fd);
       
   346         return (0);
       
   347     }
       
   348 
       
   349     (void) close(fd);
       
   350     return (1);
       
   351 }
       
   352 
       
   353 /*
       
   354  * call_ftw_for_dev() uses ftw() to pass pathnames under /dev to gdev()
       
   355  * along with a status buffer.
       
   356  */
       
   357 static void
       
   358 call_ftw_for_dev(void)
       
   359 {
       
   360     int gdev();
       
   361     int rcode;
       
   362 
       
   363     ndev = 0;
       
   364     rcode = ftw("/dev", gdev, 17);
       
   365 
       
   366     switch (rcode) {
       
   367     case 0:
       
   368         return;                /* successful return, devl populated */
       
   369     case 1:
       
   370         SYSLOG0(" ftw() encountered problem\n");
       
   371         break;
       
   372     case -1:
       
   373         SYSLOG1(" ftw() failed, %s\n", strerror(errno));
       
   374         break;
       
   375     default:
       
   376         SYSLOG1(" ftw() unexpected return, rcode=%d\n", rcode);
       
   377         break;
       
   378     }
       
   379     exit(1);
       
   380 }
       
   381 
       
   382 /*
       
   383  * gdev() puts device names and ID into the devl structure for character
       
   384  * special files in /dev.  The "/dev/" string is stripped from the name
       
   385  * and if the resulting pathname exceeds DNSIZE in length then the highest
       
   386  * level directory names are stripped until the pathname is DNSIZE or less.
       
   387  */
       
   388 int
       
   389 gdev(objptr, statp, numb)
       
   390     char        *objptr;
       
   391     struct stat *statp;
       
   392     int        numb;
       
   393 {
       
   394     int i;
       
   395     int leng, start;
       
   396     static struct devl ldevl[2];
       
   397     static int lndev, consflg;
       
   398 
       
   399     switch (numb) {
       
   400 
       
   401     case FTW_F:
       
   402         if ((statp->st_mode & S_IFMT) == S_IFCHR) {
       
   403             /* Get more and be ready for syscon & systty. */
       
   404             while (ndev + lndev >= maxdev) {
       
   405                 maxdev += UDQ;
       
   406                 devl = (struct devl *) ((devl == NULL) ?
       
   407                             malloc(sizeof (struct devl) * maxdev) :
       
   408                             realloc(devl, sizeof (struct devl) * maxdev));
       
   409                 if (devl == NULL) {
       
   410                     SYSLOG1(" not enough memory for %d devices\n", maxdev);
       
   411                     exit(1);
       
   412                 }
       
   413             }
       
   414             /*
       
   415              * Save systty & syscon entries if the console
       
   416              * entry hasn't been seen.
       
   417              */
       
   418             if (!consflg && (strcmp("/dev/systty", objptr) == 0 ||
       
   419                 strcmp("/dev/syscon", objptr) == 0)) {
       
   420                 (void) strncpy(ldevl[lndev].dname, &objptr[5], DNSIZE);
       
   421                 ldevl[lndev].dev = statp->st_rdev;
       
   422                 lndev++;
       
   423                 return (0);
       
   424             }
       
   425 
       
   426             leng = strlen(objptr);
       
   427             /* Strip off /dev/ */
       
   428             if (leng < DNSIZE + 4)
       
   429                 (void) strcpy(devl[ndev].dname, &objptr[5]);
       
   430             else {
       
   431                 start = leng - DNSIZE - 1;
       
   432 
       
   433                 for (i = start; i < leng && (objptr[i] != '/'); i++)
       
   434                             ;
       
   435                 if (i == leng)
       
   436                     (void) strncpy(devl[ndev].dname,
       
   437                                     &objptr[start], DNSIZE);
       
   438                 else
       
   439                     (void) strncpy(devl[ndev].dname,
       
   440                                     &objptr[i+1], DNSIZE);
       
   441             }
       
   442             devl[ndev].dev = statp->st_rdev;
       
   443             ndev++;
       
   444             /*
       
   445              * Put systty & syscon entries in devl when console
       
   446              * is found.
       
   447              */
       
   448             if (strcmp("/dev/console", objptr) == 0) {
       
   449                 consflg++;
       
   450                 for (i = 0; i < lndev; i++) {
       
   451                     (void) strncpy(devl[ndev].dname,
       
   452                                     ldevl[i].dname, DNSIZE);
       
   453                     devl[ndev].dev = ldevl[i].dev;
       
   454                     ndev++;
       
   455                 }
       
   456                 lndev = 0;
       
   457             }
       
   458         }
       
   459         return (0);
       
   460 
       
   461     case FTW_D:
       
   462     case FTW_DNR:
       
   463     case FTW_NS:
       
   464         return (0);
       
   465 
       
   466     default:
       
   467         SYSLOG1(" gdev() error, %d, encountered\n", numb);
       
   468         return (1);
       
   469     }
       
   470 }
       
   471 
       
   472 
       
   473 void
       
   474 wrdata()
       
   475 {
       
   476     char tmpname[MAXNAMELEN];
       
   477     char *tfname;
       
   478     int        fd;
       
   479 
       
   480     (void) umask(02);
       
   481     (void) strcpy(tmpname, "/tmp/mibiisa_ps.XXXXXX");
       
   482     if ((tfname = mktemp(tmpname)) == NULL || *tfname == '\0') {
       
   483         SYSLOG1(" mktemp(\"/tmp/mibiisa_ps.XXXXXX\") failed, %s\n",
       
   484                 strerror(errno));
       
   485         return;
       
   486     }
       
   487 
       
   488     if ((fd = open(tfname, O_WRONLY|O_CREAT|O_EXCL, 0664)) < 0) {
       
   489         SYSLOG2(" open(\"%s\") for write failed, %s\n",
       
   490                 tfname, strerror(errno));
       
   491         return;
       
   492     }
       
   493 
       
   494     /*
       
   495      * Make owner root, group sys.
       
   496      */
       
   497     (void) chown(tfname, (uid_t)0, (gid_t)3);
       
   498 
       
   499     /* write /dev data */
       
   500     write_tmp_file(fd, (char *) &ndev, sizeof (ndev));
       
   501     write_tmp_file(fd, (char *)devl, ndev * sizeof (*devl));
       
   502 
       
   503     (void) close(fd);
       
   504 
       
   505     if (rename(tfname, psfile) != 0) {
       
   506         SYSLOG2(" rename(\"%s\",\"%s\") failed\n", tfname, psfile);
       
   507         return;
       
   508     }
       
   509 }
       
   510 
       
   511 /*
       
   512  * gettty returns the user's tty number or ? if none.
       
   513  */
       
   514 char *
       
   515 gettty(ip)
       
   516 int        *ip;        /* where the search left off last time */
       
   517 {
       
   518     int        i;
       
   519 
       
   520     if (info.pr_ttydev != PRNODEV && *ip >= 0) {
       
   521         for (i = *ip; i < ndev; i++) {
       
   522             if (devl[i].dev == info.pr_ttydev) {
       
   523                 *ip = i + 1;
       
   524                 return (devl[i].dname);
       
   525             }
       
   526         }
       
   527     }
       
   528     *ip = -1;
       
   529     return ("?");
       
   530 }
       
   531 
       
   532 /*
       
   533  * Special read; unlinks psfile on read error.
       
   534  */
       
   535 int
       
   536 read_tmp_file(fd, bp, bs)
       
   537     int fd;
       
   538     char *bp;
       
   539     unsigned int bs;
       
   540 {
       
   541     int rbs;
       
   542 
       
   543     if ((rbs = read(fd, bp, bs)) != bs) {
       
   544         SYSLOG2("read_tmp_file() error on read, rbs=%d, bs=%d\n",
       
   545                 rbs, bs);
       
   546         (void) unlink(psfile);
       
   547         return (0);
       
   548     }
       
   549     return (1);
       
   550 }
       
   551 
       
   552 /*
       
   553  * Special write; unlinks psfile on write error.
       
   554  */
       
   555 void
       
   556 write_tmp_file(fd, bp, bs)
       
   557 int fd;
       
   558 char *bp;
       
   559 unsigned bs;
       
   560 {
       
   561     int wbs;
       
   562 
       
   563     if ((wbs = write(fd, bp, bs)) != bs) {
       
   564         SYSLOG2("write_tmp_file() error on write, wbs=%d, bs=%d\n",
       
   565                 wbs, bs);
       
   566         (void) unlink(psfile);
       
   567     }
       
   568 }
       
   569 
       
   570 
       
   571 /*
       
   572  * Return true iff dir is a /proc directory.
       
   573  *
       
   574  * This works because of the fact that "/proc/0" and "/proc/00" are the
       
   575  * same file, namely process 0, and are not linked to each other.  Ugly.
       
   576  */
       
   577 static int
       
   578 isprocdir(dir)                /* return TRUE iff dir is a PROC directory */
       
   579     char *dir;
       
   580 {
       
   581     struct stat stat1;        /* dir/0  */
       
   582     struct stat stat2;        /* dir/00 */
       
   583     char path[200];
       
   584     char *p;
       
   585 
       
   586     /*
       
   587      * Make a copy of the directory name without trailing '/'s
       
   588      */
       
   589     if (dir == NULL)
       
   590         (void) strcpy(path, ".");
       
   591     else {
       
   592         (void) strncpy(path, dir, (int) sizeof (path) - 4);
       
   593         path[sizeof (path)-4] = '\0';
       
   594         p = path + strlen(path);
       
   595         while (p > path && *--p == '/')
       
   596             *p = '\0';
       
   597         if (*path == '\0')
       
   598             (void) strcpy(path, ".");
       
   599     }
       
   600 
       
   601     /*
       
   602      * Append "/0" to the directory path and stat() the file.
       
   603      */
       
   604     p = path + strlen(path);
       
   605     *p++ = '/';
       
   606     *p++ = '0';
       
   607     *p = '\0';
       
   608     if (stat(path, &stat1) != 0)
       
   609         return (FALSE);
       
   610 
       
   611     /*
       
   612      * Append "/00" to the directory path and stat() the file.
       
   613      */
       
   614     *p++ = '0';
       
   615     *p = '\0';
       
   616     if (stat(path, &stat2) != 0)
       
   617         return (FALSE);
       
   618 
       
   619     /*
       
   620      * See if we ended up with the same file.
       
   621      */
       
   622     if (stat1.st_dev != stat2.st_dev || stat1.st_ino != stat2.st_ino ||
       
   623         stat1.st_mode != stat2.st_mode ||
       
   624         stat1.st_nlink != stat2.st_nlink ||
       
   625         stat1.st_uid != stat2.st_uid || stat1.st_gid != stat2.st_gid ||
       
   626         stat1.st_size != stat2.st_size)
       
   627         return (FALSE);
       
   628 
       
   629     /*
       
   630      * Return TRUE iff we have a regular file with a single link.
       
   631      */
       
   632     return ((stat1.st_mode & S_IFMT) == S_IFREG && stat1.st_nlink == 1);
       
   633 }
       
   634 
       
   635 
       
   636 /*
       
   637  * Initialize the sunProcessTable table by defining its contents and how
       
   638  * it's structured
       
   639  */
       
   640 void initialize_table_sunProcessTable(void) {
       
   641 
       
   642     static oid sunProcessTable_oid[] = {1, 3, 6, 1, 4, 1, 42, 3, 12};
       
   643     netsnmp_table_registration_info *table_info;
       
   644     netsnmp_handler_registration *my_handler;
       
   645     netsnmp_iterator_info *iinfo;
       
   646 
       
   647     /* create the table structure itself */
       
   648     table_info = SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info);
       
   649     iinfo = SNMP_MALLOC_TYPEDEF(netsnmp_iterator_info);
       
   650 
       
   651     /*
       
   652      * if your table is read only, it's easiest to change the
       
   653      * HANDLER_CAN_RWRITE definition below to HANDLER_CAN_RONLY
       
   654      */
       
   655     my_handler = netsnmp_create_handler_registration("sunProcessTable",
       
   656                                             sunProcessTable_handler,
       
   657                                             sunProcessTable_oid,
       
   658                                             OID_LENGTH(sunProcessTable_oid),
       
   659                                             HANDLER_CAN_RWRITE);
       
   660 
       
   661     if (!my_handler || !table_info || !iinfo)
       
   662         return; /* mallocs failed */
       
   663 
       
   664     /*
       
   665      * Setting up the table's definition
       
   666      */
       
   667     netsnmp_table_helper_add_indexes(table_info, ASN_INTEGER, 0);
       
   668 
       
   669     table_info->min_column = 1;
       
   670     table_info->max_column = 11;
       
   671 
       
   672     /* iterator access routines */
       
   673     iinfo->get_first_data_point = sunProcessTable_get_first_data_point;
       
   674     iinfo->get_next_data_point = sunProcessTable_get_next_data_point;
       
   675 
       
   676     iinfo->table_reginfo = table_info;
       
   677 
       
   678     /*
       
   679      * registering the table with the master agent
       
   680      */
       
   681     DEBUGMSGTL(("initialize_table_sunProcessTable",
       
   682                 "Registering table sunProcessTable as a table iterator\n"));
       
   683     netsnmp_register_table_iterator(my_handler, iinfo);
       
   684 }
       
   685 
       
   686 /* Initializes the sunProcesses module */
       
   687 void init_sunProcesses(void) {
       
   688 
       
   689     (void) time(&cache_now);
       
   690 
       
   691     /* here we initialize all the tables we're planning on supporting */
       
   692     initialize_table_sunProcessTable();
       
   693 }
       
   694 
       
   695 /*
       
   696  * returns the first data point within the sunProcessTable table data.
       
   697  *
       
   698  * Set the my_loop_context variable to the first data point structure
       
   699  * of your choice (from which you can find the next one). This could
       
   700  * be anything from the first node in a linked list, to an integer
       
   701  * pointer containing the beginning of an array variable.
       
   702  *
       
   703  * Set the my_data_context variable to something to be returned to
       
   704  * you later that will provide you with the data to return in a given
       
   705  * row. * This could be the same pointer as what my_loop_context is
       
   706  * set to, or something different.
       
   707  *
       
   708  * The put_index_data variable contains a list of snmp variable
       
   709  * bindings, one for each index in your table. * Set the values of
       
   710  * each appropriately according to the data matching the first row
       
   711  * and return the put_index_data variable at the end of the function.
       
   712  */
       
   713 netsnmp_variable_list *
       
   714 sunProcessTable_get_first_data_point(void **my_loop_context,
       
   715                                 void **my_data_context,
       
   716                                 netsnmp_variable_list *put_index_data,
       
   717                                 netsnmp_iterator_info *mydata) {
       
   718     long long_type;
       
   719     netsnmp_variable_list *vptr;
       
   720     ps_data_t *ps_ptr;
       
   721 
       
   722     get_ps_data();
       
   723 
       
   724     ps_ptr = pstable;
       
   725     if (ps_ptr == NULL) {
       
   726         return (NULL);
       
   727     }
       
   728 
       
   729     *my_loop_context = ps_ptr;
       
   730     *my_data_context = ps_ptr;
       
   731 
       
   732     vptr = put_index_data;
       
   733 
       
   734     long_type = (long)ps_ptr[0].pid;
       
   735     snmp_set_var_value(vptr, (u_char *) &long_type, sizeof(long_type));
       
   736 
       
   737     /*    vptr = vptr->next_variable; */
       
   738 /*
       
   739 pr_ps();
       
   740 */
       
   741     return (put_index_data);
       
   742 }
       
   743 
       
   744 /*
       
   745  * functionally the same as sunProcessTable_get_first_data_point, but
       
   746  * my_loop_context has already been set to a previous value and should
       
   747  * be updated to the next in the list.  For example, if it was a
       
   748  * linked list, you might want to cast it and the return
       
   749  * my_loop_context->next.  The my_data_context pointer should be set
       
   750  * to something you need later and the indexes in put_index_data
       
   751  * updated again.
       
   752  */
       
   753 
       
   754 netsnmp_variable_list *
       
   755 sunProcessTable_get_next_data_point(void **my_loop_context,
       
   756                                         void **my_data_context,
       
   757                                         netsnmp_variable_list *put_index_data,
       
   758                                         netsnmp_iterator_info *mydata)
       
   759 {
       
   760     long long_type;
       
   761     netsnmp_variable_list *vptr;
       
   762     ps_data_t *ps_ptr;
       
   763 
       
   764     get_ps_data();
       
   765 
       
   766     ps_ptr = (ps_data_t *) (*my_loop_context);
       
   767     ps_ptr++;
       
   768 
       
   769     if (ps_ptr > &(pstable[pstable_lines - 1])) {
       
   770         return (NULL);
       
   771     }
       
   772 
       
   773     *my_loop_context = ps_ptr;
       
   774     *my_data_context = ps_ptr;
       
   775 
       
   776     vptr = put_index_data;
       
   777 
       
   778     long_type = (long)ps_ptr[0].pid;
       
   779     snmp_set_var_value(vptr, (u_char *) &long_type, sizeof(long_type));
       
   780 
       
   781     /*    vptr = vptr->next_variable; */
       
   782 
       
   783     return (put_index_data);
       
   784 }
       
   785 
       
   786 /*
       
   787  * handles requests for the sunProcessTable table,
       
   788  * if anything else needs to be done
       
   789  */
       
   790 int sunProcessTable_handler(netsnmp_mib_handler *handler,
       
   791                         netsnmp_handler_registration *reginfo,
       
   792                         netsnmp_agent_request_info *reqinfo,
       
   793                         netsnmp_request_info *requests) {
       
   794 
       
   795     long long_type;
       
   796     netsnmp_request_info *request;
       
   797     netsnmp_table_request_info *table_info;
       
   798     netsnmp_variable_list *var;
       
   799     ps_data_t *psp;
       
   800 
       
   801     /* For caching purposes, find out what the time is now */
       
   802     (void) time(&cache_now);
       
   803 
       
   804     for (request = requests; request; request = request->next) {
       
   805         var = request->requestvb;
       
   806         if (request->processed != 0)
       
   807             continue;
       
   808 
       
   809         /* perform anything here that you need to do before each */
       
   810         /* request is processed. */
       
   811 
       
   812         /* the following extracts the my_data_context pointer set in */
       
   813         /* the loop functions above.  You can then use the results to */
       
   814         /* help return data for the columns of the sunProcessTable */
       
   815         /* table in question */
       
   816         psp = (ps_data_t *) netsnmp_extract_iterator_context(request);
       
   817         if (psp == NULL) {
       
   818             if (reqinfo->mode == MODE_GET ||
       
   819                 reqinfo->mode == MODE_SET_RESERVE1) {
       
   820 
       
   821                 netsnmp_set_request_error(reqinfo, request,
       
   822                                             SNMP_NOSUCHINSTANCE);
       
   823                 continue;
       
   824             }
       
   825             /*
       
   826              * XXX: no row existed, if you support creation and this is a
       
   827              * set, start dealing with it here, else continue
       
   828              */
       
   829         }
       
   830 
       
   831         /* extracts the information about the table from the request */
       
   832         table_info = netsnmp_extract_table_info(request);
       
   833 
       
   834         /* table_info->colnum contains the column number requested */
       
   835         /* table_info->indexes contains a linked list of snmp variable */
       
   836         /* bindings for the indexes of the table.  Values in the list */
       
   837         /* have been set corresponding to the indexes of the request */
       
   838         if (table_info == NULL) {
       
   839             continue;
       
   840         }
       
   841 
       
   842         switch (reqinfo->mode) {
       
   843         /*
       
   844          * the table_iterator helper should change all GETNEXTs
       
   845          * into GETs for you automatically, so you don't have to
       
   846          * worry about the GETNEXT case.  Only GETs and SETs need
       
   847          * to be dealt with here
       
   848          */
       
   849         case MODE_GET:
       
   850             switch (table_info->colnum) {
       
   851             case COLUMN_PSPROCESSID:
       
   852                 long_type = (long)psp->pid;
       
   853                 snmp_set_var_typed_value(var, ASN_INTEGER,
       
   854                                     (u_char *) &long_type,
       
   855                                     sizeof (long_type));
       
   856                 break;
       
   857 
       
   858             case COLUMN_PSPARENTPROCESSID:
       
   859                 long_type = (long)psp->ppid;
       
   860                 snmp_set_var_typed_value(var, ASN_INTEGER,
       
   861                                     (u_char *) &long_type,
       
   862                                     sizeof (long_type));
       
   863                 break;
       
   864 
       
   865             case COLUMN_PSPROCESSSIZE:
       
   866                 long_type = (long)psp->sz;
       
   867                 snmp_set_var_typed_value(var, ASN_INTEGER,
       
   868                                     (u_char *) &long_type,
       
   869                                     sizeof (long_type));
       
   870                 break;
       
   871 
       
   872             case COLUMN_PSPROCESSCPUTIME:
       
   873                 long_type = (long)psp->cpu;
       
   874                 snmp_set_var_typed_value(var, ASN_INTEGER,
       
   875                                     (u_char *) &long_type,
       
   876                                     sizeof (long_type));
       
   877                 break;
       
   878 
       
   879             case COLUMN_PSPROCESSSTATE:
       
   880                 snmp_set_var_typed_value(var, ASN_OCTET_STR,
       
   881                                     (u_char *) &psp->stat,
       
   882                                     strlen(psp->stat));
       
   883                 break;
       
   884 
       
   885             case COLUMN_PSPROCESSWAITCHANNEL:
       
   886                 snmp_set_var_typed_value(var, ASN_OCTET_STR,
       
   887                                     (u_char *) &psp->wchan,
       
   888                                     strlen(psp->wchan));
       
   889                 break;
       
   890 
       
   891             case COLUMN_PSPROCESSTTY:
       
   892                 snmp_set_var_typed_value(var, ASN_OCTET_STR,
       
   893                                     (u_char *) &psp->tty,
       
   894                                     strlen(psp->tty));
       
   895                 break;
       
   896 
       
   897             case COLUMN_PSPROCESSUSERNAME:
       
   898                 snmp_set_var_typed_value(var, ASN_OCTET_STR,
       
   899                                     (u_char *) &psp->usrname,
       
   900                                     strlen(psp->usrname));
       
   901                 break;
       
   902 
       
   903             case COLUMN_PSPROCESSUSERID:
       
   904                 long_type = (long)psp->uid;
       
   905                 snmp_set_var_typed_value(var, ASN_INTEGER,
       
   906                                     (u_char *) &long_type,
       
   907                                     sizeof (long_type));
       
   908                 break;
       
   909 
       
   910             case COLUMN_PSPROCESSNAME:
       
   911                 snmp_set_var_typed_value(var, ASN_OCTET_STR,
       
   912                                     (u_char *) &psp->cmd,
       
   913                                     strlen(psp->cmd));
       
   914                 break;
       
   915 
       
   916             case COLUMN_PSPROCESSSTATUS:
       
   917                 long_type = (long)psp->sz;
       
   918                 snmp_set_var_typed_value(var, ASN_INTEGER,
       
   919                                     (u_char *) &long_type,
       
   920                                     sizeof (long_type));
       
   921                 break;
       
   922 
       
   923             default:
       
   924                 /* We shouldn't get here */
       
   925                 snmp_log(LOG_ERR,
       
   926 "problem encountered in sunProcessTable_handler: unknown column\n");
       
   927             }
       
   928             break;
       
   929 
       
   930         case MODE_SET_RESERVE1:
       
   931             break;
       
   932 
       
   933         case MODE_SET_RESERVE2:
       
   934             break;
       
   935 
       
   936         case MODE_SET_FREE:
       
   937             break;
       
   938 
       
   939         case MODE_SET_ACTION:
       
   940             /* set handling... */
       
   941 /* XXX don't know about 64 bit */
       
   942             if ((int) *(requests->requestvb->val.integer) != 0) {
       
   943                 (void) kill(psp->pid,
       
   944                         (int)*(requests->requestvb->val.integer));
       
   945             }
       
   946             break;
       
   947 
       
   948         case MODE_SET_COMMIT:
       
   949             break;
       
   950 
       
   951         case MODE_SET_UNDO:
       
   952             break;
       
   953 
       
   954         default:
       
   955             snmp_log(LOG_ERR,
       
   956     "problem encountered in sunProcessTable_handler: unsupported mode\n");
       
   957         }
       
   958     }
       
   959 
       
   960     return (SNMP_ERR_NOERROR);
       
   961 }