summaryrefslogtreecommitdiff
path: root/agent/mibgroup/ucd-snmp/proc.c
diff options
context:
space:
mode:
Diffstat (limited to 'agent/mibgroup/ucd-snmp/proc.c')
-rw-r--r--agent/mibgroup/ucd-snmp/proc.c876
1 files changed, 876 insertions, 0 deletions
diff --git a/agent/mibgroup/ucd-snmp/proc.c b/agent/mibgroup/ucd-snmp/proc.c
new file mode 100644
index 0000000..e90c2e8
--- /dev/null
+++ b/agent/mibgroup/ucd-snmp/proc.c
@@ -0,0 +1,876 @@
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-features.h>
+
+#ifdef solaris2
+#define _KMEMUSER /* Needed by <sys/user.h> */
+#include <sys/types.h> /* helps define struct rlimit */
+#endif
+
+#if HAVE_IO_H /* win32 */
+#include <io.h>
+#endif
+#if HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+#if HAVE_MALLOC_H
+#include <malloc.h>
+#endif
+#include <math.h>
+#include <ctype.h>
+#include <sys/types.h>
+#if HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+#if HAVE_KVM_H
+#include <kvm.h>
+#endif
+
+#include <net-snmp/net-snmp-includes.h>
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+
+#include "struct.h"
+#include "proc.h"
+#ifdef USING_HOST_DATA_ACCESS_SWRUN_MODULE
+#include <net-snmp/data_access/swrun.h>
+#endif
+#ifdef USING_UCD_SNMP_ERRORMIB_MODULE
+#include "errormib.h"
+#else
+#define setPerrorstatus(x) snmp_log_perror(x)
+#endif
+#include "util_funcs.h"
+#include "kernel.h"
+
+static struct myproc *get_proc_instance(struct myproc *, oid);
+struct myproc *procwatch = NULL;
+static struct extensible fixproc;
+int numprocs = 0;
+
+void
+init_proc(void)
+{
+
+ /*
+ * define the structure we're going to ask the agent to register our
+ * information at
+ */
+ struct variable2 extensible_proc_variables[] = {
+ {MIBINDEX, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
+ var_extensible_proc, 1, {MIBINDEX}},
+ {ERRORNAME, ASN_OCTET_STR, NETSNMP_OLDAPI_RONLY,
+ var_extensible_proc, 1, {ERRORNAME}},
+ {PROCMIN, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
+ var_extensible_proc, 1, {PROCMIN}},
+ {PROCMAX, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
+ var_extensible_proc, 1, {PROCMAX}},
+ {PROCCOUNT, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
+ var_extensible_proc, 1, {PROCCOUNT}},
+ {ERRORFLAG, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
+ var_extensible_proc, 1, {ERRORFLAG}},
+ {ERRORMSG, ASN_OCTET_STR, NETSNMP_OLDAPI_RONLY,
+ var_extensible_proc, 1, {ERRORMSG}},
+ {ERRORFIX, ASN_INTEGER, NETSNMP_OLDAPI_RWRITE,
+ var_extensible_proc, 1, {ERRORFIX}},
+ {ERRORFIXCMD, ASN_OCTET_STR, NETSNMP_OLDAPI_RONLY,
+ var_extensible_proc, 1, {ERRORFIXCMD}}
+ };
+
+ /*
+ * Define the OID pointer to the top of the mib tree that we're
+ * registering underneath
+ */
+ oid proc_variables_oid[] = { NETSNMP_UCDAVIS_MIB, NETSNMP_PROCMIBNUM, 1 };
+
+ /*
+ * register ourselves with the agent to handle our mib tree
+ */
+ REGISTER_MIB("ucd-snmp/proc", extensible_proc_variables, variable2,
+ proc_variables_oid);
+
+ snmpd_register_config_handler("proc", proc_parse_config,
+ proc_free_config,
+ "process-name [max-num] [min-num]");
+ snmpd_register_config_handler("procfix", procfix_parse_config, NULL,
+ "process-name program [arguments...]");
+}
+
+
+/*
+ * Define snmpd.conf reading routines first. They get called
+ * automatically by the invocation of a macro in the proc.h file.
+ */
+
+void
+proc_free_config(void)
+{
+ struct myproc *ptmp, *ptmp2;
+
+ for (ptmp = procwatch; ptmp != NULL;) {
+ ptmp2 = ptmp;
+ ptmp = ptmp->next;
+ free(ptmp2);
+ }
+ procwatch = NULL;
+ numprocs = 0;
+}
+
+/*
+ * find a give entry in the linked list associated with a proc name
+ */
+static struct myproc *
+get_proc_by_name(char *name)
+{
+ struct myproc *ptmp;
+
+ if (name == NULL)
+ return NULL;
+
+ for (ptmp = procwatch; ptmp != NULL && strcmp(ptmp->name, name) != 0;
+ ptmp = ptmp->next);
+ return ptmp;
+}
+
+void
+procfix_parse_config(const char *token, char *cptr)
+{
+ char tmpname[STRMAX];
+ struct myproc *procp;
+
+ /*
+ * don't allow two entries with the same name
+ */
+ cptr = copy_nword(cptr, tmpname, sizeof(tmpname));
+ if ((procp = get_proc_by_name(tmpname)) == NULL) {
+ config_perror("No proc entry registered for this proc name yet.");
+ return;
+ }
+
+ if (strlen(cptr) > sizeof(procp->fixcmd)) {
+ config_perror("fix command too long.");
+ return;
+ }
+
+ strcpy(procp->fixcmd, cptr);
+}
+
+
+void
+proc_parse_config(const char *token, char *cptr)
+{
+ char tmpname[STRMAX];
+ struct myproc **procp = &procwatch;
+
+ /*
+ * don't allow two entries with the same name
+ */
+ copy_nword(cptr, tmpname, sizeof(tmpname));
+ if (get_proc_by_name(tmpname) != NULL) {
+ config_perror("Already have an entry for this process.");
+ return;
+ }
+
+ /*
+ * skip past used ones
+ */
+ while (*procp != NULL)
+ procp = &((*procp)->next);
+
+ (*procp) = (struct myproc *) calloc(1, sizeof(struct myproc));
+ if (*procp == NULL)
+ return; /* memory alloc error */
+ numprocs++;
+ /*
+ * not blank and not a comment
+ */
+ copy_nword(cptr, (*procp)->name, sizeof((*procp)->name));
+ cptr = skip_not_white(cptr);
+ if ((cptr = skip_white(cptr))) {
+ (*procp)->max = atoi(cptr);
+ cptr = skip_not_white(cptr);
+ if ((cptr = skip_white(cptr)))
+ (*procp)->min = atoi(cptr);
+ else
+ (*procp)->min = 0;
+ } else {
+ /* Default to asssume that we require at least one
+ * such process to be running, but no upper limit */
+ (*procp)->max = 0;
+ (*procp)->min = 1;
+ /* This frees "proc <procname> 0 0" to monitor
+ * processes that should _not_ be running. */
+ }
+#ifdef NETSNMP_PROCFIXCMD
+ sprintf((*procp)->fixcmd, NETSNMP_PROCFIXCMD, (*procp)->name);
+#endif
+ DEBUGMSGTL(("ucd-snmp/proc", "Read: %s (%d) (%d)\n",
+ (*procp)->name, (*procp)->max, (*procp)->min));
+}
+
+/*
+ * The routine that handles everything
+ */
+
+u_char *
+var_extensible_proc(struct variable *vp,
+ oid * name,
+ size_t * length,
+ int exact,
+ size_t * var_len, WriteMethod ** write_method)
+{
+
+ struct myproc *proc;
+ static long long_ret;
+ static char errmsg[300];
+
+
+ if (header_simple_table
+ (vp, name, length, exact, var_len, write_method, numprocs))
+ return (NULL);
+
+ if ((proc = get_proc_instance(procwatch, name[*length - 1]))) {
+ switch (vp->magic) {
+ case MIBINDEX:
+ long_ret = name[*length - 1];
+ return ((u_char *) (&long_ret));
+ case ERRORNAME: /* process name to check for */
+ *var_len = strlen(proc->name);
+ return ((u_char *) (proc->name));
+ case PROCMIN:
+ long_ret = proc->min;
+ return ((u_char *) (&long_ret));
+ case PROCMAX:
+ long_ret = proc->max;
+ return ((u_char *) (&long_ret));
+ case PROCCOUNT:
+ long_ret = sh_count_procs(proc->name);
+ return ((u_char *) (&long_ret));
+ case ERRORFLAG:
+ long_ret = sh_count_procs(proc->name);
+ if (long_ret >= 0 &&
+ /* Too few processes running */
+ ((proc->min && long_ret < proc->min) ||
+ /* Too many processes running */
+ (proc->max && long_ret > proc->max) ||
+ /* Processes running that shouldn't be */
+ (proc->min == 0 && proc->max == 0 && long_ret > 0))) {
+ long_ret = 1;
+ } else {
+ long_ret = 0;
+ }
+ return ((u_char *) (&long_ret));
+ case ERRORMSG:
+ long_ret = sh_count_procs(proc->name);
+ if (long_ret < 0) {
+ errmsg[0] = 0; /* catch out of mem errors return 0 count */
+ } else if (proc->min && long_ret < proc->min) {
+ if ( long_ret > 0 )
+ snprintf(errmsg, sizeof(errmsg),
+ "Too few %s running (# = %d)",
+ proc->name, (int) long_ret);
+ else
+ snprintf(errmsg, sizeof(errmsg),
+ "No %s process running", proc->name);
+ } else if (proc->max && long_ret > proc->max) {
+ snprintf(errmsg, sizeof(errmsg),
+ "Too many %s running (# = %d)",
+ proc->name, (int) long_ret);
+ } else if (proc->min == 0 && proc->max == 0 && long_ret > 0) {
+ snprintf(errmsg, sizeof(errmsg),
+ "%s process should not be running.", proc->name);
+ } else {
+ errmsg[0] = 0;
+ }
+ errmsg[ sizeof(errmsg)-1 ] = 0;
+ *var_len = strlen(errmsg);
+ return ((u_char *) errmsg);
+ case ERRORFIX:
+ *write_method = fixProcError;
+ long_return = fixproc.result;
+ return ((u_char *) & long_return);
+ case ERRORFIXCMD:
+ if (proc->fixcmd) {
+ *var_len = strlen(proc->fixcmd);
+ return (u_char *) proc->fixcmd;
+ }
+ errmsg[0] = 0;
+ *var_len = 0;
+ return ((u_char *) errmsg);
+ }
+ return NULL;
+ }
+ return NULL;
+}
+
+int
+fixProcError(int action,
+ u_char * var_val,
+ u_char var_val_type,
+ size_t var_val_len,
+ u_char * statP, oid * name, size_t name_len)
+{
+
+ struct myproc *proc;
+ long tmp = 0;
+
+ if ((proc = get_proc_instance(procwatch, name[10]))) {
+ if (var_val_type != ASN_INTEGER) {
+ snmp_log(LOG_ERR, "Wrong type != int\n");
+ return SNMP_ERR_WRONGTYPE;
+ }
+ tmp = *((long *) var_val);
+ if (tmp == 1 && action == COMMIT) {
+ if (proc->fixcmd[0]) {
+ strcpy(fixproc.command, proc->fixcmd);
+ exec_command(&fixproc);
+ }
+ }
+ return SNMP_ERR_NOERROR;
+ }
+ return SNMP_ERR_WRONGTYPE;
+}
+
+static struct myproc *
+get_proc_instance(struct myproc *proc, oid inst)
+{
+ int i;
+
+ if (proc == NULL)
+ return (NULL);
+ for (i = 1; (i != (int) inst) && (proc != NULL); i++)
+ proc = proc->next;
+ return (proc);
+}
+
+#ifdef USING_HOST_DATA_ACCESS_SWRUN_MODULE
+netsnmp_feature_require(swrun_count_processes_by_name)
+int
+sh_count_procs(char *procname)
+{
+ return swrun_count_processes_by_name( procname );
+}
+#else
+
+#ifdef bsdi2
+#include <sys/param.h>
+#include <sys/sysctl.h>
+
+#define PP(pp, field) ((pp)->kp_proc . field)
+#define EP(pp, field) ((pp)->kp_eproc . field)
+#define VP(pp, field) ((pp)->kp_eproc.e_vm . field)
+
+/*
+ * these are for keeping track of the proc array
+ */
+
+static size_t nproc = 0;
+static size_t onproc = -1;
+static struct kinfo_proc *pbase = 0;
+
+int
+sh_count_procs(char *procname)
+{
+ register int i, ret = 0;
+ register struct kinfo_proc *pp;
+ static int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL };
+
+ if (sysctl(mib, 3, NULL, &nproc, NULL, 0) < 0)
+ return 0;
+
+ if (nproc > onproc || !pbase) {
+ if ((pbase = (struct kinfo_proc *) realloc(pbase,
+ nproc +
+ sizeof(struct
+ kinfo_proc))) ==
+ 0)
+ return -1;
+ onproc = nproc;
+ memset(pbase, 0, nproc + sizeof(struct kinfo_proc));
+ }
+
+ if (sysctl(mib, 3, pbase, &nproc, NULL, 0) < 0)
+ return -1;
+
+ for (pp = pbase, i = 0; i < nproc / sizeof(struct kinfo_proc);
+ pp++, i++) {
+ if (PP(pp, p_stat) != 0 && (((PP(pp, p_flag) & P_SYSTEM) == 0))) {
+ if (PP(pp, p_stat) != SZOMB
+ && !strcmp(PP(pp, p_comm), procname))
+ ret++;
+ }
+ }
+ return ret;
+}
+
+#elif defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7)
+#include <procinfo.h>
+#include <sys/types.h>
+
+struct procsinfo pinfo;
+char pinfo_name[256];
+
+int
+sh_count_procs(char *procname)
+{
+ pid_t index;
+ int count;
+ char *sep;
+
+ index = 0;
+ count = 0;
+
+ while(getprocs(&pinfo, sizeof(pinfo), NULL, 0, &index, 1) == 1) {
+ strlcpy(pinfo_name, pinfo.pi_comm, sizeof(pinfo_name));
+ sep = strchr(pinfo_name, ' ');
+ if(sep != NULL) *sep = 0;
+ if(strcmp(procname, pinfo_name) == 0) count++;
+ }
+
+ return count;
+}
+
+#elif NETSNMP_OSTYPE == NETSNMP_LINUXID
+
+#include <dirent.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+int
+sh_count_procs(char *procname)
+{
+ DIR *dir;
+ char cmdline[512], *tmpc;
+ char state[64];
+ struct dirent *ent;
+#ifdef USE_PROC_CMDLINE
+ int fd;
+#endif
+ int len,plen=strlen(procname),total = 0;
+ FILE *status;
+
+ if ((dir = opendir("/proc")) == NULL) return -1;
+ while (NULL != (ent = readdir(dir))) {
+ if(!(ent->d_name[0] >= '0' && ent->d_name[0] <= '9')) continue;
+#ifdef USE_PROC_CMDLINE /* old method */
+ /* read /proc/XX/cmdline */
+ sprintf(cmdline,"/proc/%s/cmdline",ent->d_name);
+ if((fd = open(cmdline, O_RDONLY)) < 0) continue;
+ len = read(fd,cmdline,sizeof(cmdline) - 1);
+ close(fd);
+ if(len <= 0) continue;
+ cmdline[len] = 0;
+ while(--len && !cmdline[len]);
+ if(len <= 0) continue;
+ while(--len) if(!cmdline[len]) cmdline[len] = ' ';
+ if(!strncmp(cmdline,procname,plen)) total++;
+#else
+ /* read /proc/XX/status */
+ sprintf(cmdline,"/proc/%s/status",ent->d_name);
+ if ((status = fopen(cmdline, "r")) == NULL)
+ continue;
+ if (fgets(cmdline, sizeof(cmdline), status) == NULL) {
+ fclose(status);
+ continue;
+ }
+ /* Grab the state of the process as well
+ * (so we can ignore zombie processes)
+ * XXX: Assumes the second line is the status
+ */
+ if (fgets(state, sizeof(state), status) == NULL) {
+ state[0]='\0';
+ }
+ fclose(status);
+ cmdline[sizeof(cmdline)-1] = '\0';
+ state[sizeof(state)-1] = '\0';
+ /* XXX: assumes Name: is first */
+ if (strncmp("Name:",cmdline, 5) != 0)
+ break;
+ tmpc = skip_token(cmdline);
+ if (!tmpc)
+ break;
+ for (len=0;; len++) {
+ if (tmpc[len] && isgraph(tmpc[len])) continue;
+ tmpc[len]='\0';
+ break;
+ }
+ DEBUGMSGTL(("proc","Comparing wanted %s against %s\n",
+ procname, tmpc));
+ if(len==plen && !strncmp(tmpc,procname,plen)) {
+ /* Do not count zombie process as they are not running processes */
+ if ( strstr(state, "zombie") == NULL ) {
+ total++;
+ DEBUGMSGTL(("proc", " Matched. total count now=%d\n", total));
+ } else {
+ DEBUGMSGTL(("proc", " Skipping zombie process.\n"));
+ }
+ }
+#endif
+ }
+ closedir(dir);
+ return total;
+}
+
+#elif NETSNMP_OSTYPE == NETSNMP_ULTRIXID
+
+#define NPROCS 32 /* number of proces to read at once */
+
+extern int kmem, mem, swap;
+
+#include <sys/user.h>
+#include <sys/proc.h>
+#include <sys/file.h>
+#include <sys/vm.h>
+#include <machine/pte.h>
+#ifdef HAVE_NLIST_H
+#include <nlist.h>
+#endif
+
+static struct user *getuser(struct proc *);
+static int getword(off_t);
+static int getstruct(off_t, char *, off_t, int);
+
+static struct nlist proc_nl[] = {
+ {"_nproc"},
+#define X_NPROC 0
+ {"_proc"},
+#define X_PROC 1
+ {"_proc_bitmap"},
+#define X_PROC_BITMAP 2
+ {NULL}
+};
+
+int
+sh_count_procs(char *procname)
+{
+ int total, proc_active, nproc;
+ int thisproc = 0;
+ int absolute_proc_number = -1;
+ struct user *auser;
+ struct proc *aproc, *procp;
+ unsigned bitmap;
+ struct proc procs[NPROCS], *procsp;
+ static int inited = 0;
+
+ procp = (struct proc *) getword(proc_nl[X_PROC].n_value);
+ nproc = getword(proc_nl[X_NPROC].n_value);
+
+ total = 0;
+ for (;;) {
+ do {
+ while (thisproc == 0) {
+ int nread;
+ int psize;
+
+ if (nproc == 0)
+ return (total);
+
+ thisproc = MIN(NPROCS, nproc);
+ psize = thisproc * sizeof(struct proc);
+ nproc -= thisproc;
+ if (lseek(kmem, (off_t) procp, L_SET) == -1 ||
+ (nread = read(kmem, (char *) procs, psize)) < 0) {
+ /*
+ * warn("read proc");
+ */
+ return (total);
+ } else if (nread != psize) {
+ thisproc = nread / sizeof(struct proc);
+ nproc = 0;
+ /*
+ * warn("read proc: short read");
+ */
+ }
+ procsp = procs;
+ procp += thisproc;
+ }
+
+ aproc = procsp++;
+ thisproc--;
+
+ absolute_proc_number++;
+ if ((absolute_proc_number % 32) == 0)
+ bitmap =
+ getword((unsigned int) proc_nl[X_PROC_BITMAP].n_value +
+ ((absolute_proc_number / 32) * 4));
+ proc_active =
+ (bitmap & (1 << (absolute_proc_number % 32))) != 0;
+ if (proc_active && aproc->p_stat != SZOMB
+ && !(aproc->p_type & SWEXIT))
+ auser = getuser(aproc);
+ } while (!proc_active || auser == NULL);
+
+ if (strcmp(auser->u_comm, procname) == 0)
+ total++;
+ }
+}
+
+#define SW_UADDR dtob(getword((off_t)dmap.dm_ptdaddr))
+#define SW_UBYTES sizeof(struct user)
+
+#define SKRD(file, src, dst, size) \
+ (lseek(file, (off_t)(src), L_SET) == -1) || \
+ (read(file, (char *)(dst), (size)) != (size))
+
+static struct user *
+getuser(struct proc *aproc)
+{
+ static union {
+ struct user user;
+ char upgs[UPAGES][NBPG];
+ } u;
+ static struct pte uptes[UPAGES];
+ static struct dmap dmap;
+ int i, nbytes;
+
+ /*
+ * If process is not in core, we simply snarf it's user struct
+ * from the swap device.
+ */
+ if ((aproc->p_sched & SLOAD) == 0) {
+ if (!getstruct
+ ((off_t) aproc->p_smap, "aproc->p_smap", (off_t) & dmap,
+ sizeof(dmap))) {
+ /*
+ * warnx("can't read dmap for pid %d from %s", aproc->p_pid,
+ * _PATH_DRUM);
+ */
+ return (NULL);
+ }
+ if (SKRD(swap, SW_UADDR, &u.user, SW_UBYTES)) {
+ /*
+ * warnx("can't read u for pid %d from %s", aproc->p_pid, _PATH_DRUM);
+ */
+ return (NULL);
+ }
+ return (&u.user);
+ }
+
+ /*
+ * Process is in core. Follow p_addr to read in the page
+ * table entries that map the u-area and then read in the
+ * physical pages that comprise the u-area.
+ *
+ * If at any time, an lseek() or read() fails, print a warning
+ * message and return NULL.
+ */
+ if (SKRD(kmem, aproc->p_addr, uptes, sizeof(uptes))) {
+ /*
+ * warnx("can't read user pt for pid %d from %s", aproc->p_pid, _PATH_DRUM);
+ */
+ return (NULL);
+ }
+
+ nbytes = sizeof(struct user);
+ for (i = 0; i < UPAGES && nbytes > 0; i++) {
+ if (SKRD(mem, ptob(uptes[i].pg_pfnum), u.upgs[i], NBPG)) {
+ /*
+ * warnx("can't read user page %u for pid %d from %s",
+ * uptes[i].pg_pfnum, aproc->p_pid, _PATH_MEM);
+ */
+ return (NULL);
+ }
+ nbytes -= NBPG;
+ }
+ return (&u.user);
+}
+
+static int
+getword(off_t loc)
+{
+ int val;
+
+ if (SKRD(kmem, loc, &val, sizeof(val)))
+ exit(1);
+ return (val);
+}
+
+static int
+getstruct(off_t loc, char *name, off_t dest, int size)
+{
+ if (SKRD(kmem, loc, dest, size))
+ return (0);
+ return (1);
+}
+#elif NETSNMP_OSTYPE == NETSNMP_SOLARISID
+
+#ifdef _SLASH_PROC_METHOD_
+
+#include <fcntl.h>
+#include <dirent.h>
+
+#include <procfs.h>
+
+/*
+ * Gets process information from /proc/.../psinfo
+ */
+
+int
+sh_count_procs(char *procname)
+{
+ int fd, total = 0;
+ struct psinfo info;
+ char fbuf[32];
+ struct dirent *ent;
+ DIR *dir;
+
+ if (!(dir = opendir("/proc"))) {
+ snmp_perror("/proc");
+ return -1;
+ }
+
+ while ((ent = readdir(dir))) {
+ if (!strcmp(ent->d_name, "..") || !strcmp(ent->d_name, "."))
+ continue;
+
+ snprintf(fbuf, sizeof fbuf, "/proc/%s/psinfo", ent->d_name);
+ if ((fd = open(fbuf, O_RDONLY)) < 0) { /* Continue or return error? */
+ snmp_perror(fbuf);
+ continue;
+ }
+
+ if (read(fd, (char *) &info, sizeof(struct psinfo)) !=
+ sizeof(struct psinfo)) {
+ snmp_perror(fbuf);
+ close(fd);
+ closedir(dir);
+ return -1;
+ }
+
+ if (!info.pr_nlwp && !info.pr_lwp.pr_lwpid) {
+ /*
+ * Zombie process
+ */
+ } else {
+ DEBUGMSGTL(("proc","Comparing wanted %s against %s\n",
+ procname, info.pr_fname));
+ if (!strcmp(procname, info.pr_fname)) {
+ total++;
+ DEBUGMSGTL(("proc", " Matched. total count now=%d\n", total));
+ }
+ }
+
+ close(fd);
+ }
+ closedir(dir);
+ return total;
+}
+
+#else /* _SLASH_PROC_METHOD_ */
+
+#define _KMEMUSER /* Needed by <sys/user.h> */
+
+#include <kvm.h>
+#include <fcntl.h>
+#include <sys/user.h>
+#include <sys/proc.h>
+
+int
+sh_count_procs(char *procname)
+{
+ struct proc *p;
+ struct user *u;
+ int total;
+
+ if (kd == NULL) {
+ return -1;
+ }
+ if (kvm_setproc(kd) < 0) {
+ return (-1);
+ }
+ kvm_setproc(kd);
+ total = 0;
+ while ((p = kvm_nextproc(kd)) != NULL) {
+ if (!p) {
+ return (-1);
+ }
+ u = kvm_getu(kd, p);
+ /*
+ * Skip this entry if u or u->u_comm is a NULL pointer
+ */
+ if (!u) {
+ continue;
+ }
+ if (strcmp(procname, u->u_comm) == 0)
+ total++;
+ }
+ return (total);
+}
+#endif /* _SLASH_PROC_METHOD_ */
+#else
+netsnmp_feature_require(find_field)
+int
+sh_count_procs(char *procname)
+{
+ char line[STRMAX], *cptr, *cp;
+ int ret = 0, fd;
+ FILE *file;
+#ifndef NETSNMP_EXCACHETIME
+#endif
+ struct extensible ex;
+ int slow = strstr(PSCMD, "ax") != NULL;
+
+ strcpy(ex.command, PSCMD);
+ if ((fd = get_exec_output(&ex)) >= 0) {
+ if ((file = fdopen(fd, "r")) == NULL) {
+ setPerrorstatus("fdopen");
+ close(fd);
+ return (-1);
+ }
+ while (fgets(line, sizeof(line), file) != NULL) {
+ if (slow) {
+ cptr = find_field(line, 5);
+ cp = strrchr(cptr, '/');
+ if (cp)
+ cptr = cp + 1;
+ else if (*cptr == '-')
+ cptr++;
+ else if (*cptr == '[') {
+ cptr++;
+ cp = strchr(cptr, ']');
+ if (cp)
+ *cp = 0;
+ }
+ copy_nword(cptr, line, sizeof(line));
+ cp = line + strlen(line) - 1;
+ if (*cp == ':')
+ *cp = 0;
+ } else {
+ if ((cptr = find_field(line, NETSNMP_LASTFIELD)) == NULL)
+ continue;
+ copy_nword(cptr, line, sizeof(line));
+ }
+ if (!strcmp(line, procname))
+ ret++;
+ }
+ if (ftell(file) < 2) {
+#ifdef USING_UCD_SNMP_ERRORMIB_MODULE
+ seterrorstatus("process list unreasonable short (mem?)", 2);
+#endif
+ ret = -1;
+ }
+ fclose(file);
+ wait_on_exec(&ex);
+ } else {
+ ret = -1;
+ }
+ return (ret);
+}
+#endif
+#endif /* !USING_HOST_DATA_ACCESS_SWRUN_MODULE */