summaryrefslogtreecommitdiff
path: root/agent/mibgroup/host/data_access/swrun_kinfo.c
blob: b13ea3ae7a226853958dacd33e9948eedfda49ad (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
/*
 * swrun_kinfo.c:
 *     hrSWRunTable data access:
 *     kvm_getprocs() interface - FreeBSD, NetBSD, OpenBSD
 *
 * NB: later FreeBSD uses a different kinfo_proc structure
 */
#include <net-snmp/net-snmp-config.h>

#include <stdio.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#else
#include <strings.h>
#endif

#ifdef HAVE_KVM_H
#include <kvm.h>
#endif
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
#ifdef HAVE_SYS_SYSCTL_H
#include <sys/sysctl.h>
#endif
#ifdef HAVE_SYS_USER_H
#include <sys/user.h>
#endif
#ifdef HAVE_UVM_UVM_EXTERNAL_H
#include <uvm/uvm_external.h>
#endif

#include <net-snmp/net-snmp-includes.h>
#include <net-snmp/agent/net-snmp-agent-includes.h>
#include <net-snmp/library/container.h>
#include <net-snmp/library/snmp_debug.h>
#include <net-snmp/data_access/swrun.h>

extern kvm_t *kd;


#if defined(freebsd5) && __FreeBSD_version >= 500014
    /*
     * later FreeBSD kinfo_proc field names
     */
#define SWRUN_TABLE	kinfo_proc
#define SWRUN_K_STAT	ki_stat
#define SWRUN_K_PID	ki_pid
#define SWRUN_K_COMM	ki_comm
#define SWRUN_K_FLAG	ki_flag
#define SWRUN_K_CLASS	ki_pri.pri_class

#elif HAVE_KVM_GETPROC2
    /*
     * newer NetBSD, OpenBSD kinfo_proc2 field names
     */
#define SWRUN_TABLE	kinfo_proc2
#define SWRUN_K_STAT	p_stat
#define SWRUN_K_PID	p_pid
#define SWRUN_K_COMM	p_comm
#define SWRUN_K_FLAG	p_flag
/*      SWRUN_K_CLASS	not defined     */

#elif defined(dragonfly)
    /*
     * DragonFly is different ...
     */
#define SWRUN_TABLE	kinfo_proc
#define SWRUN_K_STAT	kp_stat
#define SWRUN_K_PID 	kp_pid
#define SWRUN_K_COMM	kp_comm
#define SWRUN_K_FLAG	kp_flags
/*      SWRUN_K_CLASS	not defined     */

#else
    /*
     * early FreeBSD, NetBSD, OpenBSD kinfo_proc field names
     */
#define SWRUN_TABLE	kinfo_proc
#define SWRUN_K_STAT	kp_proc.p_stat
#define SWRUN_K_PID	kp_proc.p_pid
#define SWRUN_K_COMM	kp_proc.p_comm
#define SWRUN_K_FLAG	kp_proc.p_flag
/*      SWRUN_K_CLASS	not defined     */
#endif

/*
 *  Define dummy values if not already provided by the system
 */

#ifndef SRUN
#define SRUN	200	/* Defined by FreeBSD/OpenBSD, missing in  NetBSD */
#endif
#ifndef SACTIVE
#define SACTIVE	201	/* Defined by  NetBSD, missing in FreeBSD/OpenBSD */
#endif
#ifndef SSLEEP
#define SSLEEP	202	/* Defined by FreeBSD/OpenBSD, missing in  NetBSD */
#endif
#ifndef SWAIT
#define SWAIT	203	/* Defined by FreeBSD, missing in  NetBSD/OpenBSD */
#endif
#ifndef SSTOP
#define SSTOP	204	/* Defined by FreeBSD/NetBSD/OpenBSD */
#endif
#ifndef SLOCK
#define SLOCK	205	/* Defined by FreeBSD, missing in NetBSD/OpenBSD */
#endif
#ifndef SIDL
#define SIDL	206	/* Defined by FreeBSD/NetBSD/OpenBSD */
#endif
#ifndef SZOMB
#define SZOMB	207	/* Defined by FreeBSD/NetBSD/OpenBSD */
#endif
#ifndef SDEAD
#define SDEAD	208	/* Defined by OpenBSD, missing in FreeBSD/NetBSD */
#endif
#ifndef SONPROC
#define SONPROC	209	/* Defined by OpenBSD, missing in FreeBSD/NetBSD */
#endif

/* ---------------------------------------------------------------------
 */
void
netsnmp_arch_swrun_init(void)
{
#if NETSNMP_CAN_USE_SYSCTL && defined(CTL_KERN) && defined(KERN_MAXPROC)
    extern int _swrun_max;
    size_t max_size = sizeof(_swrun_max);
    int maxproc_mib[] = { CTL_KERN, KERN_MAXPROC };
    sysctl(maxproc_mib, 2, &_swrun_max, &max_size, NULL, 0);
#endif
    
    return;
}

/* ---------------------------------------------------------------------
 */
int
netsnmp_arch_swrun_container_load( netsnmp_container *container, u_int flags)
{
    struct SWRUN_TABLE  *proc_table;
    int                  nprocs, i, rc;
    char                 buf[BUFSIZ], **argv;
    netsnmp_swrun_entry *entry;

    if ( 0 == kd ) {
        DEBUGMSGTL(("swrun:load:arch"," Can't query kvm info\n"));
        return 1;     /* No handle for retrieving process table */
    }
#if HAVE_KVM_GETPROC2
    proc_table = kvm_getproc2(kd, KERN_PROC_ALL, 0, sizeof(struct kinfo_proc2), &nprocs );
#elif defined(KERN_PROC_PROC)
    proc_table = kvm_getprocs(kd, KERN_PROC_PROC, 0, &nprocs );
#else
    proc_table = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nprocs );
#endif
    for ( i=0 ; i<nprocs; i++ ) {
        if ( 0 == proc_table[i].SWRUN_K_STAT )
            continue;
        entry = netsnmp_swrun_entry_create(proc_table[i].SWRUN_K_PID);
        if (NULL == entry)
            continue;   /* error already logged by function */
        rc = CONTAINER_INSERT(container, entry);

        /*
         * There are two possible sources for the command being run:
         *   - SWRUN_K_COMM  (from the proc_table entry directly)
         *   - running kvm_getargv on the process entry.
         *
         * We'll use argv[0] (if set) for hrSWRunPath,
         *   since that might potentially contain the
         *   absolute path to the running binary.
         * We'll use SWRUN_K_COMM for hrSWRunName,
         *   and as an alternative for hrSWRunPath
         */
#if HAVE_KVM_GETPROC2
        argv = kvm_getargv2( kd, &(proc_table[i]), 0);
#else
        argv = kvm_getargv(  kd, &(proc_table[i]), 0);
#endif

        entry->hrSWRunName_len = snprintf(entry->hrSWRunName,
                                   sizeof(entry->hrSWRunName)-1,
                                          "%s", proc_table[i].SWRUN_K_COMM);

        if ( argv && *argv)
            entry->hrSWRunPath_len = snprintf(entry->hrSWRunPath,
                                       sizeof(entry->hrSWRunPath)-1,
                                              "%s", argv[0]);
        else {
            memcpy( entry->hrSWRunPath, entry->hrSWRunName,
                                        entry->hrSWRunName_len );
            entry->hrSWRunPath_len = entry->hrSWRunName_len;
        }

        /*
         * Stitch together the rest of argv[] to build hrSWRunParameters
         *
         * Note:
         *   We add a separating space before each argv[] parameter,
         *   *including* the first one.  So we need to skip this
         *   leading space (buf[0]) when setting hrSWRunParameters.
         * This is also why we cleared the first *two* characters
         *   in the buffer initially. If there were no command-line
         *   arguments, then buf[1] would still be a null string.
         */
        buf[0] = '\0';
        buf[1] = '\0';
        if (argv)
            argv++;    /* Skip argv[0] */
        while ( argv && *argv ) {
            strcat(buf, " ");
            strcat(buf, *argv);
            argv++;
        }
        entry->hrSWRunParameters_len = snprintf(entry->hrSWRunParameters,
                                         sizeof(entry->hrSWRunParameters)-1,
                                          "%s", buf+1);

        entry->hrSWRunType = (P_SYSTEM & proc_table[i].SWRUN_K_FLAG) 
#ifdef SWRUN_K_CLASS
                             ? ((PRI_ITHD == proc_table[i].SWRUN_K_CLASS)
                                ? 3  /* device driver    */
                                : 2  /* operating system */
                               )
                             : 4  /*  application     */
#else
                             ? 2  /* operating system */
                             : 4  /*  application     */
#endif
                             ;

#ifdef netbsd5
        switch (proc_table[i].SWRUN_K_STAT) {
	case LSONPROC:
        case LSRUN:   entry->hrSWRunStatus = HRSWRUNSTATUS_RUNNING;
                      break;
        case LSSLEEP: entry->hrSWRunStatus = HRSWRUNSTATUS_RUNNABLE;
                      break;
        case LSIDL:
	case LSSUSPENDED:
        case LSSTOP:  entry->hrSWRunStatus = HRSWRUNSTATUS_NOTRUNNABLE;
                      break;
	case LSDEAD:
        case LSZOMB:  entry->hrSWRunStatus = HRSWRUNSTATUS_INVALID;
		      break;
        default:   
		      entry->hrSWRunStatus = HRSWRUNSTATUS_INVALID;
		      snmp_log(LOG_ERR, "Bad process status %c (0x%x)\n", proc_table[i].SWRUN_K_STAT, proc_table[i].SWRUN_K_STAT);
                      break;
        }
#else
        switch (proc_table[i].SWRUN_K_STAT & 0xFF) {
        case SONPROC:
        case SRUN:    entry->hrSWRunStatus = HRSWRUNSTATUS_RUNNING;
                      break;
        case SSLEEP:
        case SWAIT:   entry->hrSWRunStatus = HRSWRUNSTATUS_RUNNABLE;
                      break;
        case SIDL:
        case SSTOP:
        case SLOCK:   entry->hrSWRunStatus = HRSWRUNSTATUS_NOTRUNNABLE;
                      break;

        case SDEAD:
        case SZOMB:   entry->hrSWRunStatus = HRSWRUNSTATUS_INVALID;   /* i.e. "not loaded" */
                      break;

        default:      entry->hrSWRunStatus = HRSWRUNSTATUS_INVALID;   /* Actually invalid  */
		      snmp_log(LOG_ERR, "Bad process status %c (0x%x)\n", proc_table[i].SWRUN_K_STAT, proc_table[i].SWRUN_K_STAT);
                      break;
        }
#endif
        
#if defined(freebsd5) && __FreeBSD_version >= 500014
         entry->hrSWRunPerfCPU  = (proc_table[i].ki_rusage.ru_utime.tv_sec*1000000 + proc_table[i].ki_rusage.ru_utime.tv_usec) / 10000;
	 entry->hrSWRunPerfCPU += (proc_table[i].ki_rusage.ru_stime.tv_sec*1000000 + proc_table[i].ki_rusage.ru_stime.tv_usec) / 10000;
	 entry->hrSWRunPerfCPU += (proc_table[i].ki_rusage_ch.ru_utime.tv_sec*1000000 + proc_table[i].ki_rusage_ch.ru_utime.tv_usec) / 10000;
	 entry->hrSWRunPerfCPU += (proc_table[i].ki_rusage_ch.ru_stime.tv_sec*1000000 + proc_table[i].ki_rusage_ch.ru_stime.tv_usec) / 10000;
	 entry->hrSWRunPerfMem  = proc_table[i].ki_rssize * (getpagesize()/1024);  /* in kB */
#elif defined(HAVE_KVM_GETPROC2)
        /*
         * newer NetBSD, OpenBSD
         */
        entry->hrSWRunPerfCPU  = proc_table[i].p_uticks;
        entry->hrSWRunPerfCPU += proc_table[i].p_sticks;
        entry->hrSWRunPerfCPU += proc_table[i].p_iticks;
        entry->hrSWRunPerfMem  = proc_table[i].p_vm_rssize;
        entry->hrSWRunPerfMem *= (getpagesize() / 1024);
#elif defined(dragonfly) && __DragonFly_version >= 190000
	entry->hrSWRunPerfCPU  = proc_table[i].kp_lwp.kl_uticks;
	entry->hrSWRunPerfCPU += proc_table[i].kp_lwp.kl_sticks;
	entry->hrSWRunPerfCPU += proc_table[i].kp_lwp.kl_iticks;
	entry->hrSWRunPerfMem  = proc_table[i].kp_vm_map_size / 1024;
#elif defined(dragonfly)
	entry->hrSWRunPerfCPU  = proc_table[i].kp_eproc.e_uticks;
	entry->hrSWRunPerfCPU += proc_table[i].kp_eproc.e_sticks;
	entry->hrSWRunPerfCPU += proc_table[i].kp_eproc.e_iticks;
	entry->hrSWRunPerfMem  = proc_table[i].kp_vm_map_size / 1024;

#else
        /*
         * early FreeBSD, NetBSD, OpenBSD
         */
        entry->hrSWRunPerfCPU  = proc_table[i].kp_proc.p_uticks;
        entry->hrSWRunPerfCPU += proc_table[i].kp_proc.p_sticks;
        entry->hrSWRunPerfCPU += proc_table[i].kp_proc.p_iticks;
        entry->hrSWRunPerfMem  = proc_table[i].kp_eproc.e_vm.vm_rssize;
        entry->hrSWRunPerfMem *= (getpagesize() / 1024);
#endif
    }
    /*
     * 'proc_table' is owned by the kvm library,
     *   so shouldn't be freed here.
     */

    DEBUGMSGTL(("swrun:load:arch","loaded %d entries\n",
                (int)CONTAINER_SIZE(container)));

    return 0;
}