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