1 #include <net-snmp/net-snmp-config.h>
2 #include <net-snmp/net-snmp-features.h>
3 
4 #ifdef solaris2
5 #define _KMEMUSER               /* Needed by <sys/user.h> */
6 #include <sys/types.h>          /* helps define struct rlimit */
7 #endif
8 
9 #if HAVE_IO_H                   /* win32 */
10 #include <io.h>
11 #endif
12 #if HAVE_STDLIB_H
13 #include <stdlib.h>
14 #endif
15 #if HAVE_UNISTD_H
16 #include <unistd.h>
17 #endif
18 #if HAVE_STRING_H
19 #include <string.h>
20 #else
21 #include <strings.h>
22 #endif
23 #if HAVE_MALLOC_H
24 #include <malloc.h>
25 #endif
26 #include <math.h>
27 #include <ctype.h>
28 #include <sys/types.h>
29 #if HAVE_NETINET_IN_H
30 #include <netinet/in.h>
31 #endif
32 #if TIME_WITH_SYS_TIME
33 # include <sys/time.h>
34 # include <time.h>
35 #else
36 # if HAVE_SYS_TIME_H
37 #  include <sys/time.h>
38 # else
39 #  include <time.h>
40 # endif
41 #endif
42 #if HAVE_PCRE_H
43 #include <pcre.h>
44 #endif
45 
46 #include <net-snmp/net-snmp-includes.h>
47 #include <net-snmp/agent/net-snmp-agent-includes.h>
48 
49 #include "mibdefs.h"
50 #include "struct.h"
51 #include "proc.h"
52 #ifdef USING_HOST_DATA_ACCESS_SWRUN_MODULE
53 #include <net-snmp/data_access/swrun.h>
54 #endif
55 #ifdef USING_UCD_SNMP_ERRORMIB_MODULE
56 #include "errormib.h"
57 #else
58 #define setPerrorstatus(x) snmp_log_perror(x)
59 #endif
60 #include "util_funcs.h"
61 
62 #define PROCMIN 3
63 #define PROCMAX 4
64 #define PROCCOUNT 5
65 
66 static struct myproc *get_proc_instance(struct myproc *, oid);
67 struct myproc  *procwatch = NULL;
68 static struct extensible fixproc;
69 int             numprocs = 0;
70 
71 void
init_proc(void)72 init_proc(void)
73 {
74     /*
75      * define the structure we're going to ask the agent to register our
76      * information at
77      */
78     struct variable2 extensible_proc_variables[] = {
79         {MIBINDEX, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
80          var_extensible_proc, 1, {MIBINDEX}},
81         {ERRORNAME, ASN_OCTET_STR, NETSNMP_OLDAPI_RONLY,
82          var_extensible_proc, 1, {ERRORNAME}},
83         {PROCMIN, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
84          var_extensible_proc, 1, {PROCMIN}},
85         {PROCMAX, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
86          var_extensible_proc, 1, {PROCMAX}},
87         {PROCCOUNT, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
88          var_extensible_proc, 1, {PROCCOUNT}},
89         {ERRORFLAG, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
90          var_extensible_proc, 1, {ERRORFLAG}},
91         {ERRORMSG, ASN_OCTET_STR, NETSNMP_OLDAPI_RONLY,
92          var_extensible_proc, 1, {ERRORMSG}},
93         {ERRORFIX, ASN_INTEGER, NETSNMP_OLDAPI_RWRITE,
94          var_extensible_proc, 1, {ERRORFIX}},
95         {ERRORFIXCMD, ASN_OCTET_STR, NETSNMP_OLDAPI_RONLY,
96          var_extensible_proc, 1, {ERRORFIXCMD}}
97     };
98 
99     /*
100      * Define the OID pointer to the top of the mib tree that we're
101      * registering underneath
102      */
103     oid             proc_variables_oid[] = { NETSNMP_UCDAVIS_MIB, NETSNMP_PROCMIBNUM, 1 };
104 
105     /*
106      * register ourselves with the agent to handle our mib tree
107      */
108     REGISTER_MIB("ucd-snmp/proc", extensible_proc_variables, variable2,
109                  proc_variables_oid);
110 
111 #ifdef HAVE_PCRE_H
112 #define proc_parse_usage "process-name [max-num] [min-num] [regexp]"
113 #else
114 #define proc_parse_usage "process-name [max-num] [min-num]"
115 #endif
116 
117     snmpd_register_config_handler("proc", proc_parse_config,
118                                   proc_free_config, proc_parse_usage);
119     snmpd_register_config_handler("procfix", procfix_parse_config, NULL,
120                                   "process-name program [arguments...]");
121 }
122 
123 
124 /*
125  * Define snmpd.conf reading routines first.  They get called
126  * automatically by the invocation of a macro in the proc.h file.
127  */
128 
129 void
proc_free_config(void)130 proc_free_config(void)
131 {
132     struct myproc  *ptmp, *ptmp2;
133 
134     for (ptmp = procwatch; ptmp != NULL;) {
135         ptmp2 = ptmp;
136         ptmp = ptmp->next;
137 #if HAVE_PCRE_H
138         free(ptmp2->regexp.regex_ptr);
139 #endif
140         free(ptmp2);
141     }
142     procwatch = NULL;
143     numprocs = 0;
144 }
145 
146 /*
147  * find a give entry in the linked list associated with a proc name
148  */
149 static struct myproc *
get_proc_by_name(char * name)150 get_proc_by_name(char *name)
151 {
152     struct myproc  *ptmp;
153 
154     if (name == NULL)
155         return NULL;
156 
157     for (ptmp = procwatch; ptmp != NULL && strcmp(ptmp->name, name) != 0;
158          ptmp = ptmp->next);
159     return ptmp;
160 }
161 
162 void
procfix_parse_config(const char * token,char * cptr)163 procfix_parse_config(const char *token, char *cptr)
164 {
165     char            tmpname[STRMAX];
166     struct myproc  *procp;
167 
168     /*
169      * don't allow two entries with the same name
170      */
171     cptr = copy_nword(cptr, tmpname, sizeof(tmpname));
172     if ((procp = get_proc_by_name(tmpname)) == NULL) {
173         config_perror("No proc entry registered for this proc name yet.");
174         return;
175     }
176 
177     if (strlen(cptr) > sizeof(procp->fixcmd)) {
178         config_perror("fix command too long.");
179         return;
180     }
181 
182     strlcpy(procp->fixcmd, cptr, sizeof(procp->fixcmd));
183 }
184 
185 
186 void
proc_parse_config(const char * token,char * cptr)187 proc_parse_config(const char *token, char *cptr)
188 {
189     char            tmpname[STRMAX];
190     struct myproc **procp = &procwatch;
191 
192     /*
193      * don't allow two entries with the same name
194      */
195     cptr = copy_nword(cptr, tmpname, sizeof(tmpname));
196     if (get_proc_by_name(tmpname) != NULL) {
197         config_perror("Already have an entry for this process.");
198         return;
199     }
200 
201     /*
202      * skip past used ones
203      */
204     while (*procp != NULL)
205         procp = &((*procp)->next);
206 
207     (*procp) = (struct myproc *) calloc(1, sizeof(struct myproc));
208     if (*procp == NULL)
209         return;                 /* memory alloc error */
210     numprocs++;
211 #if HAVE_PCRE_H
212     (*procp)->regexp.regex_ptr = NULL;
213 #endif
214     /*
215      * not blank and not a comment
216      */
217     strlcpy((*procp)->name, tmpname, sizeof((*procp)->name));
218     if (cptr) {
219         (*procp)->max = atoi(cptr);
220         cptr = skip_not_white(cptr);
221         if ((cptr = skip_white(cptr))) {
222             (*procp)->min = atoi(cptr);
223 #if HAVE_PCRE_H
224             cptr = skip_not_white(cptr);
225             if ((cptr = skip_white(cptr))) {
226                 const char *pcre_error;
227                 int pcre_error_offset;
228 
229                 DEBUGMSGTL(("ucd-snmp/regexp_proc", "Loading regex %s\n", cptr));
230                 (*procp)->regexp.regex_ptr =
231                     pcre_compile(cptr, 0,  &pcre_error, &pcre_error_offset, NULL);
232                 if ((*procp)->regexp.regex_ptr == NULL) {
233                     config_perror(pcre_error);
234                 }
235             }
236 #endif
237         } else
238             (*procp)->min = 0;
239     } else {
240         /* Default to asssume that we require at least one
241          *  such process to be running, but no upper limit */
242         (*procp)->max = 0;
243         (*procp)->min = 1;
244         /* This frees "proc <procname> 0 0" to monitor
245          * processes that should _not_ be running. */
246     }
247 #ifdef NETSNMP_PROCFIXCMD
248     sprintf((*procp)->fixcmd, NETSNMP_PROCFIXCMD, (*procp)->name);
249 #endif
250     DEBUGMSGTL(("ucd-snmp/proc", "Read:  %s (%d) (%d)\n",
251                 (*procp)->name, (*procp)->max, (*procp)->min));
252 }
253 
254 /*
255  * The routine that handles everything
256  */
257 
258 u_char         *
var_extensible_proc(struct variable * vp,oid * name,size_t * length,int exact,size_t * var_len,WriteMethod ** write_method)259 var_extensible_proc(struct variable *vp,
260                     oid * name,
261                     size_t * length,
262                     int exact,
263                     size_t * var_len, WriteMethod ** write_method)
264 {
265 
266     struct myproc  *proc;
267     static long     long_ret;
268     static char    *errmsg;
269     static char     empty_str[1];
270 
271     if (header_simple_table
272         (vp, name, length, exact, var_len, write_method, numprocs))
273         return (NULL);
274 
275     if ((proc = get_proc_instance(procwatch, name[*length - 1]))) {
276         switch (vp->magic) {
277         case MIBINDEX:
278             long_ret = name[*length - 1];
279             return ((u_char *) (&long_ret));
280         case ERRORNAME:        /* process name to check for */
281             *var_len = strlen(proc->name);
282             return ((u_char *) (proc->name));
283         case PROCMIN:
284             long_ret = proc->min;
285             return ((u_char *) (&long_ret));
286         case PROCMAX:
287             long_ret = proc->max;
288             return ((u_char *) (&long_ret));
289         case PROCCOUNT:
290             long_ret = sh_count_myprocs(proc);
291             return ((u_char *) (&long_ret));
292         case ERRORFLAG:
293             long_ret = sh_count_myprocs(proc);
294             if (long_ret >= 0 &&
295                    /* Too few processes running */
296                 ((proc->min && long_ret < proc->min) ||
297                    /* Too many processes running */
298                  (proc->max && long_ret > proc->max) ||
299                    /* Processes running that shouldn't be */
300                  (proc->min == 0 && proc->max == 0 && long_ret > 0))) {
301                 long_ret = 1;
302             } else {
303                 long_ret = 0;
304             }
305             return ((u_char *) (&long_ret));
306         case ERRORMSG:
307             free(errmsg);
308             errmsg = NULL;
309             long_ret = sh_count_myprocs(proc);
310             if (long_ret < 0) {
311                 /* catch out of mem errors return 0 count */
312             } else if (proc->min && long_ret < proc->min) {
313                 if (long_ret > 0) {
314                     if (asprintf(&errmsg, "Too few %s running (# = %d)",
315                                  proc->name, (int) long_ret) < 0) {
316                     }
317                 } else {
318                     if (asprintf(&errmsg, "No %s process running", proc->name)
319                         < 0) {
320                     }
321                 }
322             } else if (proc->max && long_ret > proc->max) {
323                 if (asprintf(&errmsg, "Too many %s running (# = %d)",
324                              proc->name, (int) long_ret) < 0) {
325                 }
326             } else if (proc->min == 0 && proc->max == 0 && long_ret > 0) {
327                 if (asprintf(&errmsg, "%s process should not be running.",
328                              proc->name) < 0) {
329                 }
330             }
331             *var_len = errmsg ? strlen(errmsg) : 0;
332             return (u_char *)(errmsg ? errmsg : empty_str);
333         case ERRORFIX:
334             *write_method = fixProcError;
335             long_return = fixproc.result;
336             return ((u_char *) & long_return);
337         case ERRORFIXCMD:
338             *var_len = strlen(proc->fixcmd);
339             return (u_char *) proc->fixcmd;
340         }
341         return NULL;
342     }
343     return NULL;
344 }
345 
346 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)347 fixProcError(int action,
348              u_char * var_val,
349              u_char var_val_type,
350              size_t var_val_len,
351              u_char * statP, oid * name, size_t name_len)
352 {
353 
354     struct myproc  *proc;
355     long            tmp = 0;
356 
357     if ((proc = get_proc_instance(procwatch, name[10]))) {
358         if (var_val_type != ASN_INTEGER) {
359             snmp_log(LOG_ERR, "Wrong type != int\n");
360             return SNMP_ERR_WRONGTYPE;
361         }
362         tmp = *((long *) var_val);
363         if (tmp == 1 && action == COMMIT) {
364             if (proc->fixcmd[0]) {
365                 free(fixproc.command);
366                 fixproc.command = strdup(proc->fixcmd);
367                 exec_command(&fixproc);
368             }
369         }
370         return SNMP_ERR_NOERROR;
371     }
372     return SNMP_ERR_WRONGTYPE;
373 }
374 
375 static struct myproc *
get_proc_instance(struct myproc * proc,oid inst)376 get_proc_instance(struct myproc *proc, oid inst)
377 {
378     int             i;
379 
380     if (proc == NULL)
381         return (NULL);
382     for (i = 1; (i != (int) inst) && (proc != NULL); i++)
383         proc = proc->next;
384     return (proc);
385 }
386 
387 int
sh_count_myprocs(struct myproc * proc)388 sh_count_myprocs(struct myproc *proc)
389 {
390     if (proc == NULL)
391         return 0;
392 
393 #if defined(USING_HOST_DATA_ACCESS_SWRUN_MODULE) && defined(HAVE_PCRE_H)
394     if (proc->regexp.regex_ptr != NULL)
395       return sh_count_procs_by_regex(proc->name, proc->regexp);
396 #endif
397 
398     return sh_count_procs(proc->name);
399 }
400 
401 #ifdef USING_HOST_DATA_ACCESS_SWRUN_MODULE
402 netsnmp_feature_require(swrun_count_processes_by_name);
403 int
sh_count_procs(char * procname)404 sh_count_procs(char *procname)
405 {
406   return swrun_count_processes_by_name( procname );
407 }
408 
409 #if HAVE_PCRE_H
410 netsnmp_feature_require(swrun_count_processes_by_regex);
411 int
sh_count_procs_by_regex(char * procname,netsnmp_regex_ptr regexp)412 sh_count_procs_by_regex(char *procname, netsnmp_regex_ptr regexp)
413 {
414   return swrun_count_processes_by_regex( procname, regexp );
415 }
416 #endif
417 
418 #else
419 
420 #ifdef bsdi2
421 #include <sys/param.h>
422 #include <sys/sysctl.h>
423 
424 #define PP(pp, field) ((pp)->kp_proc . field)
425 #define EP(pp, field) ((pp)->kp_eproc . field)
426 #define VP(pp, field) ((pp)->kp_eproc.e_vm . field)
427 
428 /*
429  * these are for keeping track of the proc array
430  */
431 
432 static size_t   nproc = 0;
433 static size_t   onproc = -1;
434 static struct kinfo_proc *pbase = 0;
435 
436 int
sh_count_procs(char * procname)437 sh_count_procs(char *procname)
438 {
439     register int    i, ret = 0;
440     register struct kinfo_proc *pp;
441     static int      mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL };
442 
443     if (sysctl(mib, 3, NULL, &nproc, NULL, 0) < 0)
444         return 0;
445 
446     if (nproc > onproc || !pbase) {
447         if ((pbase = (struct kinfo_proc *) realloc(pbase,
448                                                    nproc +
449                                                    sizeof(struct
450                                                           kinfo_proc))) ==
451             0)
452             return -1;
453         onproc = nproc;
454         memset(pbase, 0, nproc + sizeof(struct kinfo_proc));
455     }
456 
457     if (sysctl(mib, 3, pbase, &nproc, NULL, 0) < 0)
458         return -1;
459 
460     for (pp = pbase, i = 0; i < nproc / sizeof(struct kinfo_proc);
461          pp++, i++) {
462         if (PP(pp, p_stat) != 0 && (((PP(pp, p_flag) & P_SYSTEM) == 0))) {
463             if (PP(pp, p_stat) != SZOMB
464                 && !strcmp(PP(pp, p_comm), procname))
465                 ret++;
466         }
467     }
468     return ret;
469 }
470 
471 #elif defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7)
472 #include <procinfo.h>
473 #include <sys/types.h>
474 
475 struct procsinfo pinfo;
476 char pinfo_name[256];
477 
478 int
sh_count_procs(char * procname)479 sh_count_procs(char *procname)
480 {
481     pid_t index;
482     int count;
483     char *sep;
484 
485     index = 0;
486     count = 0;
487 
488     while(getprocs(&pinfo, sizeof(pinfo), NULL, 0, &index, 1) == 1) {
489         strlcpy(pinfo_name, pinfo.pi_comm, sizeof(pinfo_name));
490         sep = strchr(pinfo_name, ' ');
491         if(sep != NULL) *sep = 0;
492         if(strcmp(procname, pinfo_name) == 0) count++;
493     }
494 
495     return count;
496 }
497 
498 #elif NETSNMP_OSTYPE == NETSNMP_LINUXID
499 
500 #include <dirent.h>
501 #include <fcntl.h>
502 #include <unistd.h>
503 
504 int
sh_count_procs(char * procname)505 sh_count_procs(char *procname)
506 {
507     DIR *dir;
508     char cmdline[512], *tmpc;
509     char state[64];
510     struct dirent *ent;
511 #ifdef USE_PROC_CMDLINE
512     int fd;
513 #endif
514     int len,plen=strlen(procname),total = 0;
515     FILE *status;
516 
517     if ((dir = opendir("/proc")) == NULL) return -1;
518     while (NULL != (ent = readdir(dir))) {
519       if(!(ent->d_name[0] >= '0' && ent->d_name[0] <= '9')) continue;
520 #ifdef USE_PROC_CMDLINE  /* old method */
521       /* read /proc/XX/cmdline */
522       sprintf(cmdline,"/proc/%s/cmdline",ent->d_name);
523       if((fd = open(cmdline, O_RDONLY)) < 0) continue;
524       len = read(fd,cmdline,sizeof(cmdline) - 1);
525       close(fd);
526       if(len <= 0) continue;
527       cmdline[len] = 0;
528       while(--len && !cmdline[len]);
529       if(len <= 0) continue;
530       while(--len) if(!cmdline[len]) cmdline[len] = ' ';
531       if(!strncmp(cmdline,procname,plen)) total++;
532 #else
533       /* read /proc/XX/status */
534       sprintf(cmdline,"/proc/%s/status",ent->d_name);
535       if ((status = fopen(cmdline, "r")) == NULL)
536           continue;
537       if (fgets(cmdline, sizeof(cmdline), status) == NULL) {
538           fclose(status);
539           continue;
540       }
541       /* Grab the state of the process as well
542        * (so we can ignore zombie processes)
543        * XXX: Assumes the second line is the status
544        */
545       if (fgets(state, sizeof(state), status) == NULL) {
546           state[0]='\0';
547       }
548       fclose(status);
549       cmdline[sizeof(cmdline)-1] = '\0';
550       state[sizeof(state)-1] = '\0';
551       /* XXX: assumes Name: is first */
552       if (strncmp("Name:",cmdline, 5) != 0)
553           break;
554       tmpc = skip_token(cmdline);
555       if (!tmpc)
556           break;
557       for (len=0;; len++) {
558 	if (tmpc[len] && isgraph(tmpc[len])) continue;
559 	tmpc[len]='\0';
560 	break;
561       }
562       DEBUGMSGTL(("proc","Comparing wanted %s against %s\n",
563                   procname, tmpc));
564       if(len==plen && !strncmp(tmpc,procname,plen)) {
565           /* Do not count zombie process as they are not running processes */
566           if ( strstr(state, "zombie") == NULL ) {
567               total++;
568               DEBUGMSGTL(("proc", " Matched.  total count now=%d\n", total));
569           } else {
570               DEBUGMSGTL(("proc", " Skipping zombie process.\n"));
571           }
572       }
573 #endif
574     }
575     closedir(dir);
576     return total;
577 }
578 
579 #elif NETSNMP_OSTYPE == NETSNMP_ULTRIXID
580 
581 #define	NPROCS		32      /* number of proces to read at once */
582 
583 extern int      kmem, mem, swap;
584 
585 #include <sys/user.h>
586 #include <sys/proc.h>
587 #include <sys/file.h>
588 #include <sys/vm.h>
589 #include <machine/pte.h>
590 #ifdef HAVE_NLIST_H
591 #include <nlist.h>
592 #endif
593 
594 static struct user *getuser(struct proc *);
595 static int      getword(off_t);
596 static int      getstruct(off_t, char *, off_t, int);
597 
598 static struct nlist proc_nl[] = {
599     {"_nproc"},
600 #define X_NPROC		0
601     {"_proc"},
602 #define X_PROC		1
603     {"_proc_bitmap"},
604 #define X_PROC_BITMAP	2
605     {NULL}
606 };
607 
608 int
sh_count_procs(char * procname)609 sh_count_procs(char *procname)
610 {
611     int             total, proc_active, nproc;
612     int             thisproc = 0;
613     int             absolute_proc_number = -1;
614     struct user    *auser;
615     struct proc    *aproc, *procp;
616     unsigned        bitmap;
617     struct proc     procs[NPROCS], *procsp;
618     static int      inited = 0;
619 
620     procp = (struct proc *) getword(proc_nl[X_PROC].n_value);
621     nproc = getword(proc_nl[X_NPROC].n_value);
622 
623     total = 0;
624     for (;;) {
625         do {
626             while (thisproc == 0) {
627                 int             nread;
628                 int             psize;
629 
630                 if (nproc == 0)
631                     return (total);
632 
633                 thisproc = MIN(NPROCS, nproc);
634                 psize = thisproc * sizeof(struct proc);
635                 nproc -= thisproc;
636                 if (lseek(kmem, (off_t) procp, L_SET) == -1 ||
637                     (nread = read(kmem, (char *) procs, psize)) < 0) {
638                     /*
639                      * warn("read proc");
640                      */
641                     return (total);
642                 } else if (nread != psize) {
643                     thisproc = nread / sizeof(struct proc);
644                     nproc = 0;
645                     /*
646                      * warn("read proc: short read");
647                      */
648                 }
649                 procsp = procs;
650                 procp += thisproc;
651             }
652 
653             aproc = procsp++;
654             thisproc--;
655 
656             absolute_proc_number++;
657             if ((absolute_proc_number % 32) == 0)
658                 bitmap =
659                     getword((unsigned int) proc_nl[X_PROC_BITMAP].n_value +
660                             ((absolute_proc_number / 32) * 4));
661             proc_active =
662                 (bitmap & (1 << (absolute_proc_number % 32))) != 0;
663             if (proc_active && aproc->p_stat != SZOMB
664                 && !(aproc->p_type & SWEXIT))
665                 auser = getuser(aproc);
666         } while (!proc_active || auser == NULL);
667 
668         if (strcmp(auser->u_comm, procname) == 0)
669             total++;
670     }
671 }
672 
673 #define	SW_UADDR	dtob(getword((off_t)dmap.dm_ptdaddr))
674 #define	SW_UBYTES	sizeof(struct user)
675 
676 #define	SKRD(file, src, dst, size)			\
677 	(lseek(file, (off_t)(src), L_SET) == -1) ||	\
678 	(read(file, (char *)(dst), (size)) != (size))
679 
680 static struct user *
getuser(struct proc * aproc)681 getuser(struct proc *aproc)
682 {
683     static union {
684         struct user     user;
685         char            upgs[UPAGES][NBPG];
686     } u;
687     static struct pte uptes[UPAGES];
688     static struct dmap dmap;
689     int             i, nbytes;
690 
691     /*
692      * If process is not in core, we simply snarf it's user struct
693      * from the swap device.
694      */
695     if ((aproc->p_sched & SLOAD) == 0) {
696         if (!getstruct
697             ((off_t) aproc->p_smap, "aproc->p_smap", (off_t) & dmap,
698              sizeof(dmap))) {
699             /*
700              * warnx("can't read dmap for pid %d from %s", aproc->p_pid,
701              * _PATH_DRUM);
702              */
703             return (NULL);
704         }
705         if (SKRD(swap, SW_UADDR, &u.user, SW_UBYTES)) {
706             /*
707              * warnx("can't read u for pid %d from %s", aproc->p_pid, _PATH_DRUM);
708              */
709             return (NULL);
710         }
711         return (&u.user);
712     }
713 
714     /*
715      * Process is in core.  Follow p_addr to read in the page
716      * table entries that map the u-area and then read in the
717      * physical pages that comprise the u-area.
718      *
719      * If at any time, an lseek() or read() fails, print a warning
720      * message and return NULL.
721      */
722     if (SKRD(kmem, aproc->p_addr, uptes, sizeof(uptes))) {
723         /*
724          * warnx("can't read user pt for pid %d from %s", aproc->p_pid, _PATH_DRUM);
725          */
726         return (NULL);
727     }
728 
729     nbytes = sizeof(struct user);
730     for (i = 0; i < UPAGES && nbytes > 0; i++) {
731         if (SKRD(mem, ptob(uptes[i].pg_pfnum), u.upgs[i], NBPG)) {
732             /*
733              * warnx("can't read user page %u for pid %d from %s",
734              * uptes[i].pg_pfnum, aproc->p_pid, _PATH_MEM);
735              */
736             return (NULL);
737         }
738         nbytes -= NBPG;
739     }
740     return (&u.user);
741 }
742 
743 static int
getword(off_t loc)744 getword(off_t loc)
745 {
746     int             val;
747 
748     if (SKRD(kmem, loc, &val, sizeof(val)))
749         exit(1);
750     return (val);
751 }
752 
753 static int
getstruct(off_t loc,char * name,off_t dest,int size)754 getstruct(off_t loc, char *name, off_t dest, int size)
755 {
756     if (SKRD(kmem, loc, dest, size))
757         return (0);
758     return (1);
759 }
760 #elif NETSNMP_OSTYPE == NETSNMP_SOLARISID
761 
762 #ifdef _SLASH_PROC_METHOD_
763 
764 #include <fcntl.h>
765 #include <dirent.h>
766 
767 #include <procfs.h>
768 
769 /*
770  * Gets process information from /proc/.../psinfo
771  */
772 
773 int
sh_count_procs(char * procname)774 sh_count_procs(char *procname)
775 {
776     int             fd, total = 0;
777     struct psinfo   info;
778     char            fbuf[32];
779     struct dirent  *ent;
780     DIR            *dir;
781 
782     if (!(dir = opendir("/proc"))) {
783         snmp_perror("/proc");
784         return -1;
785     }
786 
787     while ((ent = readdir(dir))) {
788         if (!strcmp(ent->d_name, "..") || !strcmp(ent->d_name, "."))
789             continue;
790 
791         snprintf(fbuf, sizeof fbuf, "/proc/%s/psinfo", ent->d_name);
792         if ((fd = open(fbuf, O_RDONLY)) < 0) {  /* Continue or return error? */
793             snmp_perror(fbuf);
794 	    continue;
795         }
796 
797         if (read(fd, (char *) &info, sizeof(struct psinfo)) !=
798             sizeof(struct psinfo)) {
799             snmp_perror(fbuf);
800             close(fd);
801             closedir(dir);
802             return -1;
803         }
804 
805         if (!info.pr_nlwp && !info.pr_lwp.pr_lwpid) {
806             /*
807              * Zombie process
808              */
809         } else {
810             DEBUGMSGTL(("proc","Comparing wanted %s against %s\n",
811                         procname, info.pr_fname));
812             if (!strcmp(procname, info.pr_fname)) {
813                 total++;
814                 DEBUGMSGTL(("proc", " Matched.  total count now=%d\n", total));
815             }
816         }
817 
818         close(fd);
819     }
820     closedir(dir);
821     return total;
822 }
823 
824 #else                           /* _SLASH_PROC_METHOD_ */
825 
826 #define _KMEMUSER               /* Needed by <sys/user.h> */
827 
828 #include <kvm.h>
829 #include <fcntl.h>
830 #include <sys/user.h>
831 #include <sys/proc.h>
832 
833 int
sh_count_procs(char * procname)834 sh_count_procs(char *procname)
835 {
836     struct proc    *p;
837     struct user    *u;
838     int             total;
839 
840     if (kd == NULL) {
841         return -1;
842     }
843     if (kvm_setproc(kd) < 0) {
844         return (-1);
845     }
846     total = 0;
847     while ((p = kvm_nextproc(kd)) != NULL) {
848         u = kvm_getu(kd, p);
849         /*
850          * Skip this entry if u or u->u_comm is a NULL pointer
851          */
852         if (!u || !u->u_comm) {
853             continue;
854         }
855         if (strcmp(procname, u->u_comm) == 0)
856             total++;
857     }
858     return (total);
859 }
860 #endif                          /* _SLASH_PROC_METHOD_ */
861 #else
862 netsnmp_feature_require(find_field);
863 int
sh_count_procs(char * procname)864 sh_count_procs(char *procname)
865 {
866     char            line[STRMAX], *cptr, *cp;
867     int             ret = 0, fd;
868     FILE           *file;
869 #ifndef NETSNMP_EXCACHETIME
870 #endif
871     struct extensible ex;
872     int             slow = strstr(PSCMD, "ax") != NULL;
873 
874     ex.command = strdup(PSCMD);
875     if ((fd = get_exec_output(&ex)) >= 0) {
876         if ((file = fdopen(fd, "r")) == NULL) {
877             setPerrorstatus("fdopen");
878             close(fd);
879             return (-1);
880         }
881         while (fgets(line, sizeof(line), file) != NULL) {
882             if (slow) {
883                 cptr = find_field(line, 5);
884                 cp = strrchr(cptr, '/');
885                 if (cp)
886                     cptr = cp + 1;
887                 else if (*cptr == '-')
888                     cptr++;
889                 else if (*cptr == '[') {
890                     cptr++;
891                     cp = strchr(cptr, ']');
892                     if (cp)
893                         *cp = 0;
894                 }
895                 copy_nword(cptr, line, sizeof(line));
896                 cp = line + strlen(line) - 1;
897                 if (*cp == ':')
898                     *cp = 0;
899             } else {
900                 if ((cptr = find_field(line, NETSNMP_LASTFIELD)) == NULL)
901                     continue;
902                 copy_nword(cptr, line, sizeof(line));
903             }
904             if (!strcmp(line, procname))
905                 ret++;
906         }
907         if (ftell(file) < 2) {
908 #ifdef USING_UCD_SNMP_ERRORMIB_MODULE
909             seterrorstatus("process list unreasonable short (mem?)", 2);
910 #endif
911             ret = -1;
912         }
913         fclose(file);
914         wait_on_exec(&ex);
915     } else {
916         ret = -1;
917     }
918     return (ret);
919 }
920 #endif
921 #endif   /* !USING_HOST_DATA_ACCESS_SWRUN_MODULE */
922