and added files
[bcm963xx.git] / userapps / opensource / net-snmp / agent / mibgroup / host / hr_swrun.c
1 /*
2  *  Host Resources MIB - Running Software group implementation - hr_swrun.c
3  *      (also includes Running Software Performance group )
4  *
5  */
6
7 #include <net-snmp/net-snmp-config.h>
8 #if HAVE_STDLIB_H
9 #include <stdlib.h>
10 #endif
11 #include <fcntl.h>
12 #if HAVE_UNISTD_H
13 #include <unistd.h>
14 #endif
15
16 #include <sys/param.h>
17 #include <ctype.h>
18 #if HAVE_SYS_PSTAT_H
19 #include <sys/pstat.h>
20 #endif
21 #if HAVE_SYS_USER_H
22 #ifdef solaris2
23 #define _KMEMUSER
24 #endif
25 #include <sys/user.h>
26 #endif
27 #if HAVE_SYS_PROC_H
28 #include <sys/proc.h>
29 #endif
30 #if HAVE_KVM_H
31 #include <kvm.h>
32 #endif
33 #if HAVE_SYS_SYSCTL_H
34 #include <sys/sysctl.h>
35 #endif
36 #if HAVE_DIRENT_H && !defined(cygwin)
37 #include <dirent.h>
38 #else
39 # define dirent direct
40 # if HAVE_SYS_NDIR_H
41 #  include <sys/ndir.h>
42 # endif
43 # if HAVE_SYS_DIR_H
44 #  include <sys/dir.h>
45 # endif
46 # if HAVE_NDIR_H
47 #  include <ndir.h>
48 # endif
49 #endif
50 #ifdef cygwin
51 #include <windows.h>
52 #include <sys/cygwin.h>
53 #include <tlhelp32.h>
54 #include <psapi.h>
55 #endif
56
57 #if _SLASH_PROC_METHOD_
58 #include <procfs.h>
59 #endif
60
61 #if HAVE_STRING_H
62 #include <string.h>
63 #else
64 #include <strings.h>
65 #endif
66
67 #include <stdio.h>
68
69 #include <net-snmp/output_api.h>
70 #include "host_res.h"
71 #include "hr_swrun.h"
72 #include <net-snmp/agent/auto_nlist.h>
73 #include "kernel.h"
74 #if solaris2
75 #include "kernel_sunos5.h"
76 #endif
77
78         /*********************
79          *
80          *  Initialisation & common implementation functions
81          *
82          *********************/
83 void            Init_HR_SWRun(void);
84 int             Get_Next_HR_SWRun(void);
85 void            End_HR_SWRun(void);
86 int             header_hrswrun(struct variable *, oid *, size_t *, int,
87                                size_t *, WriteMethod **);
88 int             header_hrswrunEntry(struct variable *, oid *, size_t *,
89                                     int, size_t *, WriteMethod **);
90
91 #ifdef dynix
92 pid_t           nextproc;
93 static prpsinfo_t lowpsinfo, mypsinfo;
94 #endif
95 #ifdef cygwin
96 static struct external_pinfo *curproc;
97 static struct external_pinfo lowproc;
98 #elif !defined(linux)
99 static int      LowProcIndex;
100 #endif
101 #if defined(hpux10) || defined(hpux11)
102 struct pst_status *proc_table;
103 struct pst_dynamic pst_dyn;
104 #elif HAVE_KVM_GETPROCS
105 struct kinfo_proc *proc_table;
106 #elif defined(solaris2)
107 int            *proc_table;
108 #else
109 struct proc    *proc_table;
110 #endif
111 #ifndef dynix
112 int             current_proc_entry;
113 #endif
114
115
116 #define HRSWRUN_OSINDEX         1
117
118 #define HRSWRUN_INDEX           2
119 #define HRSWRUN_NAME            3
120 #define HRSWRUN_ID              4
121 #define HRSWRUN_PATH            5
122 #define HRSWRUN_PARAMS          6
123 #define HRSWRUN_TYPE            7
124 #define HRSWRUN_STATUS          8
125
126 #define HRSWRUNPERF_CPU         9
127 #define HRSWRUNPERF_MEM         10
128
129 struct variable4 hrswrun_variables[] = {
130     {HRSWRUN_OSINDEX, ASN_INTEGER, RONLY, var_hrswrun, 1, {1}},
131     {HRSWRUN_INDEX, ASN_INTEGER, RONLY, var_hrswrun, 3, {2, 1, 1}},
132     {HRSWRUN_NAME, ASN_OCTET_STR, RONLY, var_hrswrun, 3, {2, 1, 2}},
133     {HRSWRUN_ID, ASN_OBJECT_ID, RONLY, var_hrswrun, 3, {2, 1, 3}},
134     {HRSWRUN_PATH, ASN_OCTET_STR, RONLY, var_hrswrun, 3, {2, 1, 4}},
135     {HRSWRUN_PARAMS, ASN_OCTET_STR, RONLY, var_hrswrun, 3, {2, 1, 5}},
136     {HRSWRUN_TYPE, ASN_INTEGER, RONLY, var_hrswrun, 3, {2, 1, 6}},
137     {HRSWRUN_STATUS, ASN_INTEGER, RONLY, var_hrswrun, 3, {2, 1, 7}}
138 };
139
140 struct variable4 hrswrunperf_variables[] = {
141     {HRSWRUNPERF_CPU, ASN_INTEGER, RONLY, var_hrswrun, 3, {1, 1, 1}},
142     {HRSWRUNPERF_MEM, ASN_INTEGER, RONLY, var_hrswrun, 3, {1, 1, 2}}
143 };
144
145 oid             hrswrun_variables_oid[] = { 1, 3, 6, 1, 2, 1, 25, 4 };
146 oid             hrswrunperf_variables_oid[] = { 1, 3, 6, 1, 2, 1, 25, 5 };
147
148 #ifdef cygwin
149
150 /*
151  * a lot of this is "stolen" from cygwin ps.cc
152  */
153
154 typedef         BOOL(WINAPI * ENUMPROCESSMODULES) (HANDLE hProcess,
155                                                    HMODULE * lphModule,
156                                                    DWORD cb,
157                                                    LPDWORD lpcbNeeded);
158
159 typedef         DWORD(WINAPI * GETMODULEFILENAME) (HANDLE hProcess,
160                                                    HMODULE hModule,
161                                                    LPTSTR lpstrFIleName,
162                                                    DWORD nSize);
163
164 typedef         DWORD(WINAPI * GETPROCESSMEMORYINFO) (HANDLE hProcess,
165                                                       PPROCESS_MEMORY_COUNTERS
166                                                       pmc, DWORD nSize);
167
168 typedef         HANDLE(WINAPI * CREATESNAPSHOT) (DWORD dwFlags,
169                                                  DWORD th32ProcessID);
170
171 typedef         BOOL(WINAPI * PROCESSWALK) (HANDLE hSnapshot,
172                                             LPPROCESSENTRY32 lppe);
173
174 ENUMPROCESSMODULES myEnumProcessModules;
175 GETMODULEFILENAME myGetModuleFileNameEx;
176 CREATESNAPSHOT  myCreateToolhelp32Snapshot;
177 PROCESSWALK     myProcess32First;
178 PROCESSWALK     myProcess32Next;
179 GETPROCESSMEMORYINFO myGetProcessMemoryInfo = NULL;
180 cygwin_getinfo_types query = CW_GETPINFO;
181
182 static BOOL WINAPI
183 dummyprocessmodules(HANDLE hProcess,
184                     HMODULE * lphModule, DWORD cb, LPDWORD lpcbNeeded)
185 {
186     lphModule[0] = (HMODULE) * lpcbNeeded;
187     *lpcbNeeded = 1;
188     return 1;
189 }
190
191 static DWORD WINAPI
192 GetModuleFileNameEx95(HANDLE hProcess,
193                       HMODULE hModule, LPTSTR lpstrFileName, DWORD n)
194 {
195     HANDLE          h;
196     DWORD           pid = (DWORD) hModule;
197     PROCESSENTRY32  proc;
198
199     h = myCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
200     if (!h)
201         return 0;
202     proc.dwSize = sizeof(proc);
203     if (myProcess32First(h, &proc))
204         do
205             if (proc.th32ProcessID == pid) {
206                 CloseHandle(h);
207                 strcpy(lpstrFileName, proc.szExeFile);
208                 return 1;
209             }
210         while (myProcess32Next(h, &proc));
211     CloseHandle(h);
212     return 0;
213 }
214
215 #define FACTOR (0x19db1ded53ea710LL)
216 #define NSPERSEC 10000000LL
217 #define NSPERMSEC 10000LL
218
219 static time_t   __stdcall
220 to_time_t(PFILETIME ptr)
221 {
222     long            rem;
223     long long       x =
224         ((long long) ptr->dwHighDateTime << 32) +
225         ((unsigned) ptr->dwLowDateTime);
226     x -= FACTOR;
227     rem = x % NSPERSEC;
228     rem += NSPERSEC / 2;
229     x /= NSPERSEC;
230     x += rem / NSPERSEC;
231     return x;
232 }
233
234 static long
235 to_msec(PFILETIME ptr)
236 {
237     long long       x =
238         ((long long) ptr->dwHighDateTime << 32) +
239         (unsigned) ptr->dwLowDateTime;
240     x /= NSPERMSEC;
241     return x;
242 }
243
244 #endif                          /* cygwin */
245
246
247 void
248 init_hr_swrun(void)
249 {
250 #ifdef cygwin
251     OSVERSIONINFO   ver;
252     HMODULE         h;
253
254     memset(&ver, 0, sizeof ver);
255     ver.dwOSVersionInfoSize = sizeof ver;
256     GetVersionEx(&ver);
257
258     if (ver.dwPlatformId == VER_PLATFORM_WIN32_NT) {
259         h = LoadLibrary("psapi.dll");
260         if (h) {
261             myEnumProcessModules =
262                 (ENUMPROCESSMODULES) GetProcAddress(h,
263                                                     "EnumProcessModules");
264             myGetModuleFileNameEx =
265                 (GETMODULEFILENAME) GetProcAddress(h,
266                                                    "GetModuleFileNameExA");
267             myGetProcessMemoryInfo =
268                 (GETPROCESSMEMORYINFO) GetProcAddress(h,
269                                                       "GetProcessMemoryInfo");
270             if (myEnumProcessModules && myGetModuleFileNameEx)
271                 query = CW_GETPINFO_FULL;
272             else
273                 snmp_log(LOG_ERR, "hr_swrun failed NT init\n");
274         } else
275             snmp_log(LOG_ERR, "hr_swrun failed to load psapi.dll\n");
276     } else {
277         h = GetModuleHandle("KERNEL32.DLL");
278         myCreateToolhelp32Snapshot =
279             (CREATESNAPSHOT) GetProcAddress(h, "CreateToolhelp32Snapshot");
280         myProcess32First =
281             (PROCESSWALK) GetProcAddress(h, "Process32First");
282         myProcess32Next = (PROCESSWALK) GetProcAddress(h, "Process32Next");
283         myEnumProcessModules = dummyprocessmodules;
284         myGetModuleFileNameEx = GetModuleFileNameEx95;
285         if (myCreateToolhelp32Snapshot && myProcess32First
286             && myProcess32Next)
287 #if 0
288             /*
289              * This doesn't work after all on Win98 SE 
290              */
291             query = CW_GETPINFO_FULL;
292 #else
293             query = CW_GETPINFO;
294 #endif
295         else
296             snmp_log(LOG_ERR, "hr_swrun failed non-NT init\n");
297     }
298 #endif                          /* cygwin */
299 #ifdef PROC_SYMBOL
300     auto_nlist(PROC_SYMBOL, 0, 0);
301 #endif
302 #ifdef NPROC_SYMBOL
303     auto_nlist(NPROC_SYMBOL, 0, 0);
304 #endif
305
306     proc_table = 0;
307
308     REGISTER_MIB("host/hr_swrun", hrswrun_variables, variable4,
309                  hrswrun_variables_oid);
310     REGISTER_MIB("host/hr_swrun", hrswrunperf_variables, variable4,
311                  hrswrunperf_variables_oid);
312 }
313
314 /*
315  * header_hrswrun(...
316  * Arguments:
317  * vp     IN      - pointer to variable entry that points here
318  * name    IN/OUT  - IN/name requested, OUT/name found
319  * length  IN/OUT  - length of IN/OUT oid's 
320  * exact   IN      - TRUE if an exact match was requested
321  * var_len OUT     - length of variable or 0 if function returned
322  * write_method
323  * 
324  */
325
326 int
327 header_hrswrun(struct variable *vp,
328                oid * name,
329                size_t * length,
330                int exact, size_t * var_len, WriteMethod ** write_method)
331 {
332 #define HRSWRUN_NAME_LENGTH     9
333     oid             newname[MAX_OID_LEN];
334     int             result;
335
336     DEBUGMSGTL(("host/hr_swrun", "var_hrswrun: "));
337     DEBUGMSGOID(("host/hr_swrun", name, *length));
338     DEBUGMSG(("host/hr_swrun", " %d\n", exact));
339
340     memcpy((char *) newname, (char *) vp->name, vp->namelen * sizeof(oid));
341     newname[HRSWRUN_NAME_LENGTH] = 0;
342     result = snmp_oid_compare(name, *length, newname, vp->namelen + 1);
343     if ((exact && (result != 0)) || (!exact && (result >= 0)))
344         return (MATCH_FAILED);
345     memcpy((char *) name, (char *) newname,
346            (vp->namelen + 1) * sizeof(oid));
347     *length = vp->namelen + 1;
348
349     *write_method = 0;
350     *var_len = sizeof(long);    /* default to 'long' results */
351     return (MATCH_SUCCEEDED);
352 }
353
354 int
355 header_hrswrunEntry(struct variable *vp,
356                     oid * name,
357                     size_t * length,
358                     int exact,
359                     size_t * var_len, WriteMethod ** write_method)
360 {
361 #define HRSWRUN_ENTRY_NAME_LENGTH       11
362     oid             newname[MAX_OID_LEN];
363     int             pid, LowPid = -1;
364     int             result;
365
366     DEBUGMSGTL(("host/hr_swrun", "var_hrswrunEntry: "));
367     DEBUGMSGOID(("host/hr_swrun", name, *length));
368     DEBUGMSG(("host/hr_swrun", " %d\n", exact));
369
370     memcpy((char *) newname, (char *) vp->name, vp->namelen * sizeof(oid));
371
372     /*
373      *  Find the "next" running process
374      */
375     Init_HR_SWRun();
376     for (;;) {
377         pid = Get_Next_HR_SWRun();
378 #ifndef linux
379 #ifndef dynix
380         DEBUGMSG(("host/hr_swrun",
381                   "(index %d (entry #%d) ....", pid, current_proc_entry));
382 #else
383         DEBUGMSG(("host/hr_swrun", "pid %d; nextproc %d ....", pid,
384                   nextproc));
385 #endif
386 #endif
387         if (pid == -1)
388             break;
389         newname[HRSWRUN_ENTRY_NAME_LENGTH] = pid;
390         DEBUGMSGOID(("host/hr_swrun", newname, *length));
391         DEBUGMSG(("host/hr_swrun", "\n"));
392         result = snmp_oid_compare(name, *length, newname, vp->namelen + 1);
393         if (exact && (result == 0)) {
394             LowPid = pid;
395 #ifdef cygwin
396             lowproc = *curproc;
397 #elif  dynix
398             memcpy(&lowpsinfo, &mypsinfo, sizeof(prpsinfo_t));
399 #elif !defined(linux)
400             LowProcIndex = current_proc_entry - 1;
401 #endif
402             DEBUGMSGTL(("host/hr_swrun", " saved\n"));
403             /*
404              * Save process status information 
405              */
406             break;
407         }
408         if ((!exact && (result < 0)) && (LowPid == -1 || pid < LowPid)) {
409             LowPid = pid;
410 #ifdef cygwin
411             lowproc = *curproc;
412 #elif !defined(linux)
413             LowProcIndex = current_proc_entry - 1;
414 #endif
415             /*
416              * Save process status information 
417              */
418             DEBUGMSG(("host/hr_swrun", " saved"));
419         }
420         DEBUGMSG(("host/hr_swrun", "\n"));
421     }
422     End_HR_SWRun();
423
424     if (LowPid == -1) {
425         DEBUGMSGTL(("host/hr_swrun", "... index out of range\n"));
426         return (MATCH_FAILED);
427     }
428
429     newname[HRSWRUN_ENTRY_NAME_LENGTH] = LowPid;
430     memcpy((char *) name, (char *) newname,
431            (vp->namelen + 1) * sizeof(oid));
432     *length = vp->namelen + 1;
433     *write_method = 0;
434     *var_len = sizeof(long);    /* default to 'long' results */
435
436     DEBUGMSGTL(("host/hr_swrun", "... get process stats "));
437     DEBUGMSGOID(("host/hr_swrun", name, *length));
438     DEBUGMSG(("host/hr_swrun", "\n"));
439     return LowPid;
440 }
441
442         /*********************
443          *
444          *  System specific implementation functions
445          *
446          *********************/
447
448
449 u_char         *
450 var_hrswrun(struct variable * vp,
451             oid * name,
452             size_t * length,
453             int exact, size_t * var_len, WriteMethod ** write_method)
454 {
455     int             pid = 0;
456     static char     string[256];
457 #ifdef HAVE_SYS_PSTAT_H
458     struct pst_status proc_buf;
459 #elif defined(solaris2)
460 #if _SLASH_PROC_METHOD_
461     static psinfo_t psinfo;
462     static psinfo_t *proc_buf;
463     int             procfd;
464     char            procfn[sizeof "/proc/00000/psinfo"];
465 #else
466     static struct proc *proc_buf;
467     char           *cp1;
468 #endif                          /* _SLASH_PROC_METHOD_ */
469     static time_t   when = 0;
470     time_t          now;
471     static int      oldpid = -1;
472 #endif
473 #if HAVE_KVM_GETPROCS
474     char          **argv;
475 #endif
476 #ifdef linux
477     FILE           *fp;
478     char            buf[256];
479     int             i;
480 #endif
481     char           *cp;
482
483     if (vp->magic == HRSWRUN_OSINDEX) {
484         if (header_hrswrun(vp, name, length, exact, var_len, write_method)
485             == MATCH_FAILED)
486             return NULL;
487     } else {
488
489         pid =
490             header_hrswrunEntry(vp, name, length, exact, var_len,
491                                 write_method);
492         if (pid == MATCH_FAILED)
493             return NULL;
494     }
495
496 #ifdef HAVE_SYS_PSTAT_H
497     if (pstat_getproc(&proc_buf, sizeof(struct pst_status), 0, pid) == -1)
498         return NULL;
499 #elif defined(solaris2)
500     time(&now);
501     if (pid == oldpid) {
502         if (now != when)
503             oldpid = -1;
504     }
505     if (oldpid != pid || proc_buf == NULL) {
506 #if _SLASH_PROC_METHOD_
507         proc_buf = &psinfo;
508         sprintf(procfn, "/proc/%.5d/psinfo", pid);
509         if ((procfd = open(procfn, O_RDONLY)) != -1) {
510             if (read(procfd, proc_buf, sizeof(*proc_buf)) !=
511                 sizeof(*proc_buf))
512                 abort();
513             close(procfd);
514         } else
515             proc_buf = NULL;
516 #else
517         if (kd == NULL)
518             return NULL;
519         if ((proc_buf = kvm_getproc(kd, pid)) == NULL)
520             return NULL;
521 #endif
522         oldpid = pid;
523         when = now;
524     }
525 #endif
526
527     switch (vp->magic) {
528     case HRSWRUN_OSINDEX:
529 #if NO_DUMMY_VALUES
530         return NULL;
531 #else
532         long_return = 1;        /* Probably! */
533         return (u_char *) & long_return;
534 #endif
535
536     case HRSWRUN_INDEX:
537         long_return = pid;
538         return (u_char *) & long_return;
539     case HRSWRUN_NAME:
540 #ifdef HAVE_SYS_PSTAT_H
541         snprintf(string, sizeof(string), "%s", proc_buf.pst_cmd);
542         string[ sizeof(string)-1 ] = 0;
543         cp = strchr(string, ' ');
544         if (cp != NULL)
545             *cp = '\0';
546 #elif defined(dynix)
547         snprintf(string, sizeof(string), "%s", lowpsinfo.pr_fname);
548         string[ sizeof(string)-1 ] = 0;
549         cp = strchr(string, ' ');
550         if (cp != NULL)
551             *cp = '\0';
552 #elif defined(solaris2)
553 #if _SLASH_PROC_METHOD_
554         if (proc_buf)
555             strncpy(string, proc_buf->pr_fname, sizeof(string));
556         else
557             strcpy(string, "<exited>");
558         string[ sizeof(string)-1 ] = 0;
559 #else
560         strncpy(string, proc_buf->p_user.u_comm, sizeof(string));
561         string[ sizeof(string)-1 ] = 0;
562 #endif
563 #elif HAVE_KVM_GETPROCS
564         strcpy(string, proc_table[LowProcIndex].kp_proc.p_comm);
565 #elif defined(linux)
566         sprintf(string, "/proc/%d/status", pid);
567         if ((fp = fopen(string, "r")) == NULL)
568             return NULL;
569         fgets(buf, sizeof(buf), fp);    /* Name: process name */
570         cp = buf;
571         while (*cp != ':')
572             ++cp;
573         ++cp;
574         while (isspace(*cp))
575             ++cp;
576         strcpy(string, cp);
577         fclose(fp);
578 #elif defined(cygwin)
579         if (lowproc.process_state & (PID_ZOMBIE | PID_EXITED))
580             strcpy(string, "<defunct>");
581         else if (lowproc.ppid) {
582             cygwin_conv_to_posix_path(lowproc.progname, string);
583             cp = strrchr(string, '/');
584             if (cp)
585                 strcpy(string, cp + 1);
586         } else if (query == CW_GETPINFO_FULL) {
587             DWORD           n = lowproc.dwProcessId & 0xffff;
588             HANDLE          h =
589                 OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
590                             FALSE, n);
591
592             if (h) {
593                 HMODULE         hm[1000];
594                 if (!myEnumProcessModules(h, hm, sizeof hm, &n)) {
595                     snmp_log(LOG_DEBUG, "no module handle for %lu\n", n);
596                     n = 0;
597                 }
598                 if (n
599                     && myGetModuleFileNameEx(h, hm[0], string,
600                                              sizeof string)) {
601                     cp = strrchr(string, '\\');
602                     if (cp)
603                         strcpy(string, cp + 1);
604                 } else
605                     strcpy(string, "*** unknown");
606                 CloseHandle(h);
607             } else {
608                 snmp_log(LOG_INFO, "no process handle for %lu\n", n);
609                 strcpy(string, "** unknown");
610             }
611         } else
612             strcpy(string, "* unknown");
613         cp = strchr(string, '\0') - 4;
614         if (cp > string && strcasecmp(cp, ".exe") == 0)
615             *cp = '\0';
616 #else
617 #if NO_DUMMY_VALUES
618         return NULL;
619 #endif
620         sprintf(string, "process name");
621 #endif
622         *var_len = strlen(string);
623         /*
624          * remove trailing newline 
625          */
626         if (*var_len) {
627             cp = string + *var_len - 1;
628             if (*cp == '\n')
629                 --(*var_len);
630         }
631         return (u_char *) string;
632     case HRSWRUN_ID:
633         *var_len = nullOidLen;
634         return (u_char *) nullOid;
635     case HRSWRUN_PATH:
636 #ifdef HAVE_SYS_PSTAT_H
637         /*
638          * Path not available - use argv[0] 
639          */
640         sprintf(string, "%s", proc_buf.pst_cmd);
641         cp = strchr(string, ' ');
642         if (cp != NULL)
643             *cp = '\0';
644 #elif defined(dynix)
645         /*
646          * Path not available - use argv[0] 
647          */
648         sprintf(string, "%s", lowpsinfo.pr_psargs);
649         cp = strchr(string, ' ');
650         if (cp != NULL)
651             *cp = '\0';
652 #elif defined(solaris2)
653 #ifdef _SLASH_PROC_METHOD_
654         if (proc_buf)
655             strcpy(string, proc_buf->pr_psargs);
656         else
657             sprintf(string, "<exited>");
658         cp = strchr(string, ' ');
659         if (cp)
660             *cp = 0;
661 #else
662         cp = proc_buf->p_user.u_psargs;
663         cp1 = string;
664         while (*cp && *cp != ' ')
665             *cp1++ = *cp++;
666         *cp1 = 0;
667 #endif
668 #elif HAVE_KVM_GETPROCS
669         strcpy(string, proc_table[LowProcIndex].kp_proc.p_comm);
670 #elif defined(linux)
671         sprintf(string, "/proc/%d/cmdline", pid);
672         if ((fp = fopen(string, "r")) == NULL)
673             return NULL;
674         if (fgets(buf, sizeof(buf) - 1, fp))    /* argv[0] '\0' argv[1] '\0' .... */
675             strcpy(string, buf);
676         else {
677             /*
678              * swapped out - no cmdline 
679              */
680             fclose(fp);
681             sprintf(string, "/proc/%d/status", pid);
682             if ((fp = fopen(string, "r")) == NULL)
683                 return NULL;
684             fgets(buf, sizeof(buf), fp);        /* Name: process name */
685             cp = strchr(buf, ':');
686             ++cp;
687             while (isspace(*cp))
688                 ++cp;
689             strcpy(string, cp);
690             cp = strchr(string, '\n');
691             if (cp)
692                 *cp = 0;
693         }
694         fclose(fp);
695 #elif defined(cygwin)
696         if (lowproc.process_state & (PID_ZOMBIE | PID_EXITED))
697             strcpy(string, "<defunct>");
698         else if (lowproc.ppid)
699             cygwin_conv_to_posix_path(lowproc.progname, string);
700         else if (query == CW_GETPINFO_FULL) {
701             DWORD           n = lowproc.dwProcessId & 0xFFFF;
702             HANDLE          h =
703                 OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
704                             FALSE, n);
705             if (h) {
706                 HMODULE         hm[1000];
707                 if (!myEnumProcessModules(h, hm, sizeof hm, &n))
708                     n = 0;
709                 if (!n
710                     || !myGetModuleFileNameEx(h, hm[0], string,
711                                               sizeof string))
712                     strcpy(string, "*** unknown");
713                 CloseHandle(h);
714             } else
715                 strcpy(string, "** unknown");
716         } else
717             strcpy(string, "* unknown");
718 #else
719 #if NO_DUMMY_VALUES
720         return NULL;
721 #endif
722         sprintf(string, "/bin/wombat");
723 #endif
724         *var_len = strlen(string);
725         return (u_char *) string;
726     case HRSWRUN_PARAMS:
727 #ifdef HAVE_SYS_PSTAT_H
728         cp = strchr(proc_buf.pst_cmd, ' ');
729         if (cp != NULL) {
730             cp++;
731             sprintf(string, "%s", cp);
732         } else
733             string[0] = '\0';
734 #elif defined(dynix)
735         cp = strchr(lowpsinfo.pr_psargs, ' ');
736         if (cp != NULL) {
737             cp++;
738             sprintf(string, "%s", cp);
739         } else
740             string[0] = '\0';
741 #elif defined(solaris2)
742 #ifdef _SLASH_PROC_METHOD_
743         if (proc_buf) {
744             cp = strchr(proc_buf->pr_psargs, ' ');
745             if (cp)
746                 strcpy(string, cp + 1);
747             else
748                 string[0] = 0;
749         } else
750             string[0] = 0;
751 #else
752         cp = proc_buf->p_user.u_psargs;
753         while (*cp && *cp != ' ')
754             cp++;
755         if (*cp == ' ')
756             cp++;
757         strcpy(string, cp);
758 #endif
759 #elif HAVE_KVM_GETPROCS
760         string[0] = 0;
761         argv = kvm_getargv(kd, proc_table + LowProcIndex, sizeof(string));
762         if (argv)
763             argv++;
764         while (argv && *argv) {
765             if (string[0] != 0)
766                 strcat(string, " ");
767             strcat(string, *argv);
768             argv++;
769         }
770 #elif defined(linux)
771         sprintf(string, "/proc/%d/cmdline", pid);
772         if ((fp = fopen(string, "r")) == NULL)
773             return NULL;
774         memset(buf, 0, sizeof(buf));
775
776         /*
777          * argv[0] '\0' argv[1] '\0' .... 
778          */
779         if (!fgets(buf, sizeof(buf) - 2, fp)) {
780             /*
781              * maybe be empty (even argv[0] is missing) 
782              */
783             string[0] = '\0';
784             *var_len = 0;
785             fclose(fp);
786             return string;
787         }
788
789         /*
790          * Skip over argv[0] 
791          */
792         cp = buf;
793         while (*cp)
794             ++cp;
795         ++cp;
796         /*
797          * Now join together separate arguments. 
798          */
799         while (1) {
800             while (*cp)
801                 ++cp;
802             if (*(cp + 1) == '\0')
803                 break;          /* '\0''\0' => End of command line */
804             *cp = ' ';
805         }
806
807         cp = buf;
808         while (*cp)
809             ++cp;
810         ++cp;
811         strcpy(string, cp);
812         fclose(fp);
813 #elif defined(cygwin)
814         string[0] = 0;
815 #else
816 #if NO_DUMMY_VALUES
817         return NULL;
818 #endif
819         sprintf(string, "-h -q -v");
820 #endif
821         *var_len = strlen(string);
822         return (u_char *) string;
823     case HRSWRUN_TYPE:
824 #ifdef PID_MAXSYS
825         if (pid < PID_MAXSYS)
826             long_return = 2;    /* operatingSystem */
827         else
828 #endif
829             long_return = 4;    /* application */
830         return (u_char *) & long_return;
831     case HRSWRUN_STATUS:
832 #if defined(cygwin)
833         if (lowproc.process_state & PID_STOPPED)
834             long_return = 3;    /* notRunnable */
835         else if (lowproc.process_state & PID_ZOMBIE)
836             long_return = 4;    /* invalid */
837         else
838             long_return = 1;    /* running */
839 #elif !defined(linux)
840 #if defined(hpux10) || defined(hpux11)
841         switch (proc_table[LowProcIndex].pst_stat) {
842         case PS_STOP:
843             long_return = 3;    /* notRunnable */
844             break;
845         case PS_SLEEP:
846             long_return = 2;    /* runnable */
847             break;
848         case PS_RUN:
849             long_return = 1;    /* running */
850             break;
851         case PS_ZOMBIE:
852         case PS_IDLE:
853         case PS_OTHER:
854         default:
855             long_return = 4;    /* invalid */
856             break;
857         }
858 #else
859 #if HAVE_KVM_GETPROCS
860         switch (proc_table[LowProcIndex].kp_proc.p_stat) {
861 #elif defined(dynix)
862         switch (lowpsinfo.pr_state) {
863 #elif defined(solaris2)
864 #if _SLASH_PROC_METHOD_
865         switch (proc_buf ? proc_buf->pr_lwp.pr_state : SIDL) {
866 #else
867         switch (proc_buf->p_stat) {
868 #endif
869 #else
870         switch (proc_table[LowProcIndex].p_stat) {
871 #endif
872         case SSTOP:
873             long_return = 3;    /* notRunnable */
874             break;
875         case 0:
876 #ifdef SSWAP
877         case SSWAP:
878 #endif
879 #ifdef SSLEEP
880         case SSLEEP:
881 #endif
882 #ifdef SWAIT
883         case SWAIT:
884 #endif
885             long_return = 2;    /* runnable */
886             break;
887 #ifdef SACTIVE
888         case SACTIVE:
889 #endif
890 #ifdef SRUN
891         case SRUN:
892 #endif
893 #ifdef SONPROC
894         case SONPROC:
895 #endif
896             long_return = 1;    /* running */
897             break;
898         case SIDL:
899         case SZOMB:
900         default:
901             long_return = 4;    /* invalid */
902             break;
903         }
904 #endif
905 #else
906         sprintf(string, "/proc/%d/stat", pid);
907         if ((fp = fopen(string, "r")) != NULL) {
908             fgets(buf, sizeof(buf), fp);
909             cp = buf;
910             for (i = 0; i < 2; ++i) {   /* skip two fields */
911                 while (*cp != ' ')
912                     ++cp;
913                 ++cp;
914             }
915
916             switch (*cp) {
917             case 'R':
918                 long_return = 1;        /* running */
919                 break;
920             case 'S':
921                 long_return = 2;        /* runnable */
922                 break;
923             case 'D':
924             case 'T':
925                 long_return = 3;        /* notRunnable */
926                 break;
927             case 'Z':
928             default:
929                 long_return = 4;        /* invalid */
930                 break;
931             }
932             fclose(fp);
933         } else
934             long_return = 4;    /* invalid */
935 #endif
936         return (u_char *) & long_return;
937
938     case HRSWRUNPERF_CPU:
939 #ifdef HAVE_SYS_PSTAT_H
940         long_return = proc_buf.pst_cptickstotal;
941         /*
942          * Not convinced this is right, but....
943          */
944 #elif defined(dynix)
945         long_return = lowpsinfo.pr_time.tv_sec * 100 +
946             lowpsinfo.pr_time.tv_nsec / 10000000;
947 #elif defined(solaris2)
948 #if _SLASH_PROC_METHOD_
949         long_return = proc_buf ? proc_buf->pr_time.tv_sec * 100 +
950             proc_buf->pr_time.tv_nsec / 10000000 : 0;
951 #else
952         long_return = proc_buf->p_utime * 100 + proc_buf->p_stime * 100;
953 #endif
954 #elif HAVE_KVM_GETPROCS
955         long_return = proc_table[LowProcIndex].kp_proc.p_uticks +
956             proc_table[LowProcIndex].kp_proc.p_sticks +
957             proc_table[LowProcIndex].kp_proc.p_iticks;
958 #elif defined(linux)
959         sprintf(string, "/proc/%d/stat", pid);
960         if ((fp = fopen(string, "r")) == NULL)
961             return NULL;
962         fgets(buf, sizeof(buf), fp);
963         cp = buf;
964         for (i = 0; i < 13; ++i) {      /* skip 13 fields */
965             while (*cp != ' ')
966                 ++cp;
967             ++cp;
968         }
969
970         long_return = atoi(cp); /* utime */
971
972         while (*cp != ' ')
973             ++cp;
974         ++cp;
975         long_return += atoi(cp);        /* + stime */
976         fclose(fp);
977 #elif defined(sunos4)
978         long_return = proc_table[LowProcIndex].p_time;
979 #elif defined(cygwin)
980         {
981             DWORD           n = lowproc.dwProcessId;
982             HANDLE          h =
983                 OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
984                             FALSE, n);
985             FILETIME        ct, et, kt, ut;
986
987             if (h) {
988                 if (GetProcessTimes(h, &ct, &et, &kt, &ut))
989                     long_return = (to_msec(&kt) + to_msec(&ut)) / 10;
990                 else {
991                     snmp_log(LOG_INFO, "no process times for %lu (%lu)\n",
992                              lowproc.pid, n);
993                     long_return = 0;
994                 }
995                 CloseHandle(h);
996             } else {
997                 snmp_log(LOG_INFO, "no process handle for %lu (%lu)\n",
998                          lowproc.pid, n);
999                 long_return = 0;
1000             }
1001         }
1002 #elif defined(aix4)
1003         long_return = proc_table[LowProcIndex].p_ru.ru_utime.tv_sec * 100 +
1004             proc_table[LowProcIndex].p_ru.ru_utime.tv_usec / 10000 +
1005             proc_table[LowProcIndex].p_ru.ru_stime.tv_sec * 100 +
1006             proc_table[LowProcIndex].p_ru.ru_stime.tv_usec / 10000;
1007 #else
1008         long_return = proc_table[LowProcIndex].p_utime.tv_sec * 100 +
1009             proc_table[LowProcIndex].p_utime.tv_usec / 10000 +
1010             proc_table[LowProcIndex].p_stime.tv_sec * 100 +
1011             proc_table[LowProcIndex].p_stime.tv_usec / 10000;
1012 #endif
1013         return (u_char *) & long_return;
1014     case HRSWRUNPERF_MEM:
1015 #ifdef HAVE_SYS_PSTAT_H
1016         long_return = (proc_buf.pst_rssize << PGSHIFT) / 1024;
1017 #elif defined(dynix)
1018         long_return = (lowpsinfo.pr_rssize * MMU_PAGESIZE) / 1024;
1019 #elif defined(solaris2)
1020 #if _SLASH_PROC_METHOD_
1021         long_return = proc_buf ? proc_buf->pr_rssize : 0;
1022 #else
1023         long_return = proc_buf->p_swrss;
1024 #endif
1025 #elif HAVE_KVM_GETPROCS
1026 #if defined(freebsd3) && !defined(darwin)
1027         long_return =
1028             proc_table[LowProcIndex].kp_eproc.e_vm.vm_map.size / 1024;
1029 #else
1030         long_return = proc_table[LowProcIndex].kp_eproc.e_vm.vm_tsize +
1031             proc_table[LowProcIndex].kp_eproc.e_vm.vm_ssize +
1032             proc_table[LowProcIndex].kp_eproc.e_vm.vm_dsize;
1033         long_return = long_return * (getpagesize() / 1024);
1034 #endif
1035 #elif defined(linux)
1036         sprintf(string, "/proc/%d/stat", pid);
1037         if ((fp = fopen(string, "r")) == NULL)
1038             return NULL;
1039         fgets(buf, sizeof(buf), fp);
1040         cp = buf;
1041         for (i = 0; i < 23; ++i) {      /* skip 23 fields */
1042             while (*cp != ' ')
1043                 ++cp;
1044             ++cp;
1045         }
1046         long_return = atoi(cp) * (getpagesize() / 1024);        /* rss */
1047         fclose(fp);
1048 #elif defined(cygwin)
1049         {
1050             DWORD           n = lowproc.dwProcessId;
1051             HANDLE          h =
1052                 OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
1053                             FALSE, n);
1054             PROCESS_MEMORY_COUNTERS pmc;
1055
1056             if (h) {
1057                 if (myGetProcessMemoryInfo
1058                     && myGetProcessMemoryInfo(h, &pmc, sizeof pmc))
1059                     long_return = pmc.WorkingSetSize / 1024;
1060                 else {
1061                     snmp_log(LOG_INFO, "no process times for %lu (%lu)\n",
1062                              lowproc.pid, n);
1063                     long_return = 0;
1064                 }
1065                 CloseHandle(h);
1066             } else {
1067                 snmp_log(LOG_INFO, "no process handle for %lu (%lu)\n",
1068                          lowproc.pid, n);
1069                 long_return = 0;
1070             }
1071         }
1072 #else
1073 #if NO_DUMMY_VALUES
1074         return NULL;
1075 #endif
1076         long_return = 16 * 1024;        /* XXX - 16M! */
1077 #endif
1078         return (u_char *) & long_return;
1079     default:
1080         DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_hrswrun\n",
1081                     vp->magic));
1082     }
1083     return NULL;
1084 }
1085
1086
1087         /*********************
1088          *
1089          *  Internal implementation functions
1090          *
1091          *********************/
1092
1093 #if defined(linux)
1094
1095 DIR            *procdir = NULL;
1096 struct dirent  *procentry_p;
1097
1098 void
1099 Init_HR_SWRun(void)
1100 {
1101     if (procdir != NULL)
1102         closedir(procdir);
1103     procdir = opendir("/proc");
1104 }
1105
1106 int
1107 Get_Next_HR_SWRun(void)
1108 {
1109     int             pid;
1110     procentry_p = readdir(procdir);
1111
1112     if (procentry_p == NULL)
1113         return -1;
1114
1115     pid = atoi(procentry_p->d_name);
1116     if (pid == 0)
1117         return (Get_Next_HR_SWRun());
1118     return pid;
1119 }
1120
1121 void
1122 End_HR_SWRun(void)
1123 {
1124     if (procdir)
1125         closedir(procdir);
1126     procdir = NULL;
1127 }
1128
1129 #elif defined(cygwin)
1130
1131 static pid_t    curpid;
1132
1133 void
1134 Init_HR_SWRun(void)
1135 {
1136     cygwin_internal(CW_LOCK_PINFO, 1000);
1137     curpid = 0;
1138 }
1139
1140 int
1141 Get_Next_HR_SWRun(void)
1142 {
1143     curproc =
1144         (struct external_pinfo *) cygwin_internal(query,
1145                                                   curpid | CW_NEXTPID);
1146     if (curproc)
1147         curpid = curproc->pid;
1148     else {
1149         curpid = -1;
1150     }
1151     return curpid;
1152 }
1153
1154 void
1155 End_HR_SWRun(void)
1156 {
1157     cygwin_internal(CW_UNLOCK_PINFO);
1158 }
1159
1160 #elif defined(dynix)
1161
1162 void
1163 Init_HR_SWRun(void)
1164 {
1165     nextproc = 0;
1166 }
1167
1168 int
1169 Get_Next_HR_SWRun(void)
1170 {
1171     getprpsinfo_t  *select = 0;
1172
1173     DEBUGMSGTL(("host/hr_swrun::GetNextHR_SWRun",
1174                 "nextproc == %d... &nextproc = %u\n", nextproc,
1175                 &nextproc));
1176     if ((nextproc = getprpsinfo(nextproc, select, &mypsinfo)) < 0) {
1177         return -1;
1178     } else {
1179         DEBUGMSGTL(("host/hr_swrun::GetNextHR_SWRun",
1180                     "getprpsinfo returned %d\n", nextproc));
1181         return mypsinfo.pr_pid;
1182     }
1183
1184 }
1185
1186 void
1187 End_HR_SWRun(void)
1188 {
1189     /*
1190      * just a stub... because it's declared 
1191      */
1192 }
1193
1194 #else                           /* linux */
1195
1196 static int      nproc;
1197
1198 void
1199 Init_HR_SWRun(void)
1200 {
1201     size_t          bytes;
1202     static time_t   iwhen = 0;
1203     time_t          now;
1204
1205     time(&now);
1206     if (now == iwhen) {
1207         current_proc_entry = 0;
1208         return;
1209     }
1210     iwhen = now;
1211
1212 #if defined(hpux10) || defined(hpux11)
1213     pstat_getdynamic(&pst_dyn, sizeof(struct pst_dynamic), 1, 0);
1214     nproc = pst_dyn.psd_activeprocs;
1215     bytes = nproc * sizeof(struct pst_status);
1216     if ((proc_table =
1217          (struct pst_status *) realloc(proc_table, bytes)) == NULL) {
1218         current_proc_entry = nproc + 1;
1219         return;
1220     }
1221     pstat_getproc(proc_table, sizeof(struct pst_status), nproc, 0);
1222
1223 #elif defined(solaris2)
1224     if (!getKstatInt("unix", "system_misc", "nproc", &nproc)) {
1225         current_proc_entry = nproc + 1;
1226         return;
1227     }
1228     bytes = nproc * sizeof(int);
1229     if ((proc_table = (int *) realloc(proc_table, bytes)) == NULL) {
1230         current_proc_entry = nproc + 1;
1231         return;
1232     }
1233     {
1234         DIR            *f;
1235         struct dirent  *dp;
1236 #if _SLASH_PROC_METHOD_ == 0
1237         if (kd == NULL) {
1238             current_proc_entry = nproc + 1;
1239             return;
1240         }
1241 #endif
1242         f = opendir("/proc");
1243         current_proc_entry = 0;
1244         while ((dp = readdir(f)) != NULL && current_proc_entry < nproc)
1245             if (dp->d_name[0] != '.')
1246                 proc_table[current_proc_entry++] = atoi(dp->d_name);
1247         closedir(f);
1248     }
1249 #elif HAVE_KVM_GETPROCS
1250     {
1251         if (kd == NULL) {
1252             nproc = 0;
1253             return;
1254         }
1255         proc_table = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nproc);
1256     }
1257 #else
1258
1259     current_proc_entry = 1;
1260 #ifndef bsdi2
1261     nproc = 0;
1262
1263     if (auto_nlist(NPROC_SYMBOL, (char *) &nproc, sizeof(int)) == 0) {
1264         snmp_log_perror("Init_HR_SWRun-auto_nlist NPROC");
1265         return;
1266     }
1267 #endif
1268     bytes = nproc * sizeof(struct proc);
1269
1270     if (proc_table)
1271         free((char *) proc_table);
1272     if ((proc_table = (struct proc *) malloc(bytes)) == NULL) {
1273         nproc = 0;
1274         snmp_log_perror("Init_HR_SWRun-malloc");
1275         return;
1276     }
1277
1278     {
1279         int             proc_table_base;
1280         if (auto_nlist
1281             (PROC_SYMBOL, (char *) &proc_table_base,
1282              sizeof(proc_table_base)) == 0) {
1283             nproc = 0;
1284             snmp_log_perror("Init_HR_SWRun-auto_nlist PROC");
1285             return;
1286         }
1287         if (klookup(proc_table_base, (char *) proc_table, bytes) == 0) {
1288             nproc = 0;
1289             snmp_log_perror("Init_HR_SWRun-klookup");
1290             return;
1291         }
1292     }
1293 #endif
1294     current_proc_entry = 0;
1295 }
1296
1297 int
1298 Get_Next_HR_SWRun(void)
1299 {
1300     while (current_proc_entry < nproc) {
1301 #if defined(hpux10) || defined(hpux11)
1302         return proc_table[current_proc_entry++].pst_pid;
1303 #elif defined(solaris2)
1304         return proc_table[current_proc_entry++];
1305 #elif HAVE_KVM_GETPROCS
1306         if (proc_table[current_proc_entry].kp_proc.p_stat != 0)
1307             return proc_table[current_proc_entry++].kp_proc.p_pid;
1308 #else
1309         if (proc_table[current_proc_entry].p_stat != 0)
1310             return proc_table[current_proc_entry++].p_pid;
1311         else
1312             ++current_proc_entry;
1313 #endif
1314
1315     }
1316     return -1;
1317 }
1318
1319 void
1320 End_HR_SWRun(void)
1321 {
1322     current_proc_entry = nproc + 1;
1323 }
1324 #endif
1325
1326 int
1327 count_processes(void)
1328 {
1329 #if !(defined(linux) || defined(cygwin)) || defined(hpux10) || defined(hpux11) || defined(solaris2) || HAVE_KVM_GETPROCS
1330     int             i;
1331 #endif
1332     int             total = 0;
1333
1334     Init_HR_SWRun();
1335 #if defined(hpux10) || defined(hpux11) || HAVE_KVM_GETPROCS || defined(solaris2)
1336     total = nproc;
1337 #else
1338 #if !defined(linux) && !defined(cygwin) && !defined(dynix)
1339     for (i = 0; i < nproc; ++i) {
1340         if (proc_table[i].p_stat != 0)
1341 #else
1342     while (Get_Next_HR_SWRun() != -1) {
1343 #endif
1344         ++total;
1345     }
1346 #endif                          /* !hpux10 && !hpux11 && !HAVE_KVM_GETPROCS && !solaris2 */
1347     End_HR_SWRun();
1348     return total;
1349 }