Deleted Added
full compact
hostres_swrun_tbl.c (154860) hostres_swrun_tbl.c (160341)
1/*
2 * Copyright (c) 2005-2006 The FreeBSD Project
3 * All rights reserved.
4 *
5 * Author: Victor Cruceru <soc-victor@freebsd.org>
6 *
7 * Redistribution of this software and documentation and use in source and
8 * binary forms, with or without modification, are permitted provided that
9 * the following conditions are met:
10 *
11 * 1. Redistributions of source code or documentation must retain the above
12 * copyright notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
1/*
2 * Copyright (c) 2005-2006 The FreeBSD Project
3 * All rights reserved.
4 *
5 * Author: Victor Cruceru <soc-victor@freebsd.org>
6 *
7 * Redistribution of this software and documentation and use in source and
8 * binary forms, with or without modification, are permitted provided that
9 * the following conditions are met:
10 *
11 * 1. Redistributions of source code or documentation must retain the above
12 * copyright notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * $FreeBSD: head/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_swrun_tbl.c 154860 2006-01-26 12:19:10Z harti $
29 * $FreeBSD: head/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_swrun_tbl.c 160341 2006-07-14 09:07:56Z harti $
30 *
31 * Host Resources MIB for SNMPd. Implementation for hrSWRunTable
32 */
33
34#include <sys/param.h>
35#include <sys/proc.h>
36#include <sys/sysctl.h>
37#include <sys/user.h>
38#include <sys/linker.h>
39
40#include <assert.h>
41#include <signal.h>
42#include <stdlib.h>
43#include <string.h>
44#include <syslog.h>
45
46#include "hostres_snmp.h"
47#include "hostres_oid.h"
48#include "hostres_tree.h"
49
30 *
31 * Host Resources MIB for SNMPd. Implementation for hrSWRunTable
32 */
33
34#include <sys/param.h>
35#include <sys/proc.h>
36#include <sys/sysctl.h>
37#include <sys/user.h>
38#include <sys/linker.h>
39
40#include <assert.h>
41#include <signal.h>
42#include <stdlib.h>
43#include <string.h>
44#include <syslog.h>
45
46#include "hostres_snmp.h"
47#include "hostres_oid.h"
48#include "hostres_tree.h"
49
50
51/*
52 * Ugly thing: PID_MAX, NO_PID defined only in kernel
53 */
54#define NO_PID 100000
55
56enum SWRunType {
57 SRT_UNKNOWN = 1,
58 SRT_OPERATING_SYSTEM = 2,
59 SRT_DEVICE_DRIVER = 3,
60 SRT_APPLICATION = 4
61
62};
63
64enum SWRunStatus {
65 SRS_RUNNING = 1,
66 SRS_RUNNABLE = 2,
67 SRS_NOT_RUNNABLE = 3,
68 SRS_INVALID = 4
69};
70
50/*
51 * Ugly thing: PID_MAX, NO_PID defined only in kernel
52 */
53#define NO_PID 100000
54
55enum SWRunType {
56 SRT_UNKNOWN = 1,
57 SRT_OPERATING_SYSTEM = 2,
58 SRT_DEVICE_DRIVER = 3,
59 SRT_APPLICATION = 4
60
61};
62
63enum SWRunStatus {
64 SRS_RUNNING = 1,
65 SRS_RUNNABLE = 2,
66 SRS_NOT_RUNNABLE = 3,
67 SRS_INVALID = 4
68};
69
70/* Maximum lengths for the strings according to the MIB */
71#define SWR_NAME_MLEN (64 + 1)
72#define SWR_PATH_MLEN (128 + 1)
73#define SWR_PARAM_MLEN (128 + 1)
74
71/*
72 * This structure is used to hold a SNMP table entry
73 * for both hrSWRunTable and hrSWRunPerfTable because
74 * hrSWRunPerfTable AUGMENTS hrSWRunTable
75 */
76struct swrun_entry {
77 int32_t index;
75/*
76 * This structure is used to hold a SNMP table entry
77 * for both hrSWRunTable and hrSWRunPerfTable because
78 * hrSWRunPerfTable AUGMENTS hrSWRunTable
79 */
80struct swrun_entry {
81 int32_t index;
78 u_char name[64 + 1];
79 struct asn_oid id;
80 u_char path[128 + 1];
81 u_char parameters[128 + 1];
82 u_char *name; /* it may be NULL */
83 const struct asn_oid *id;
84 u_char *path; /* it may be NULL */
85 u_char *parameters; /* it may be NULL */
82 int32_t type; /* enum SWRunType */
83 int32_t status; /* enum SWRunStatus */
84 int32_t perfCPU;
85 int32_t perfMemory;
86 int32_t type; /* enum SWRunType */
87 int32_t status; /* enum SWRunStatus */
88 int32_t perfCPU;
89 int32_t perfMemory;
86#define HR_SWRUN_FOUND 0x001
90#define HR_SWRUN_FOUND 0x001
87 uint32_t flags;
88 uint64_t r_tick; /* tick when entry refreshed */
89 TAILQ_ENTRY(swrun_entry) link;
90};
91TAILQ_HEAD(swrun_tbl, swrun_entry);
92
93/* the head of the list with hrSWRunTable's entries */
94static struct swrun_tbl swrun_tbl = TAILQ_HEAD_INITIALIZER(swrun_tbl);
95
96/* last (agent) tick when hrSWRunTable and hrSWRunPerTable was updated */
97static uint64_t swrun_tick;
98
99/* maximum number of ticks between updates of SWRun and SWRunPerf table */
100uint32_t swrun_tbl_refresh = HR_SWRUN_TBL_REFRESH * 100;
101
102/* the value of the MIB object with the same name */
103static int32_t SWOSIndex;
104
105/**
106 * Malloc a new entry and add it to the list
107 * associated to this table. The item identified by
108 * the index parameter must not exist in this list.
109 */
110static struct swrun_entry *
111swrun_entry_create(int32_t idx)
112{
113 struct swrun_entry *entry;
114
115 if ((entry = malloc(sizeof(*entry))) == NULL) {
116 syslog(LOG_WARNING, "%s: %m", __func__);
117 return (NULL);
118 }
119 memset(entry, 0, sizeof(*entry));
120 entry->index = idx;
121
122 INSERT_OBJECT_INT(entry, &swrun_tbl);
123 return (entry);
124}
125
126/**
127 * Unlink the entry from the list and then free its heap memory
128 */
129static void
130swrun_entry_delete(struct swrun_entry *entry)
131{
132
133 assert(entry != NULL);
134
135 TAILQ_REMOVE(&swrun_tbl, entry, link);
136
91 uint32_t flags;
92 uint64_t r_tick; /* tick when entry refreshed */
93 TAILQ_ENTRY(swrun_entry) link;
94};
95TAILQ_HEAD(swrun_tbl, swrun_entry);
96
97/* the head of the list with hrSWRunTable's entries */
98static struct swrun_tbl swrun_tbl = TAILQ_HEAD_INITIALIZER(swrun_tbl);
99
100/* last (agent) tick when hrSWRunTable and hrSWRunPerTable was updated */
101static uint64_t swrun_tick;
102
103/* maximum number of ticks between updates of SWRun and SWRunPerf table */
104uint32_t swrun_tbl_refresh = HR_SWRUN_TBL_REFRESH * 100;
105
106/* the value of the MIB object with the same name */
107static int32_t SWOSIndex;
108
109/**
110 * Malloc a new entry and add it to the list
111 * associated to this table. The item identified by
112 * the index parameter must not exist in this list.
113 */
114static struct swrun_entry *
115swrun_entry_create(int32_t idx)
116{
117 struct swrun_entry *entry;
118
119 if ((entry = malloc(sizeof(*entry))) == NULL) {
120 syslog(LOG_WARNING, "%s: %m", __func__);
121 return (NULL);
122 }
123 memset(entry, 0, sizeof(*entry));
124 entry->index = idx;
125
126 INSERT_OBJECT_INT(entry, &swrun_tbl);
127 return (entry);
128}
129
130/**
131 * Unlink the entry from the list and then free its heap memory
132 */
133static void
134swrun_entry_delete(struct swrun_entry *entry)
135{
136
137 assert(entry != NULL);
138
139 TAILQ_REMOVE(&swrun_tbl, entry, link);
140
141 free(entry->name);
142 free(entry->path);
143 free(entry->parameters);
137 free(entry);
138}
139
140/**
141 * Search one item by its index, return NULL if none found
142 */
143static struct swrun_entry *
144swrun_entry_find_by_index(int32_t idx)
145{
146 struct swrun_entry *entry;
147
148 TAILQ_FOREACH(entry, &swrun_tbl, link)
149 if (entry->index == idx)
150 return (entry);
151 return (NULL);
152}
153
154/**
144 free(entry);
145}
146
147/**
148 * Search one item by its index, return NULL if none found
149 */
150static struct swrun_entry *
151swrun_entry_find_by_index(int32_t idx)
152{
153 struct swrun_entry *entry;
154
155 TAILQ_FOREACH(entry, &swrun_tbl, link)
156 if (entry->index == idx)
157 return (entry);
158 return (NULL);
159}
160
161/**
155 * Translate the kernel's process status to the SNMP one.
162 * Translate the kernel's process status to SNMP.
156 */
157static enum SWRunStatus
158swrun_OS_get_proc_status(const struct kinfo_proc *kp)
159{
160
161 assert(kp != NULL);
162 if(kp == NULL) {
163 return (SRS_INVALID);
164 }
165
166 /*
167 * I'm using the old style flags - they look cleaner to me,
168 * at least for the purpose of this SNMP table
169 */
170 switch (kp->ki_stat) {
171
172 case SSTOP:
173 return (SRS_NOT_RUNNABLE);
174
175 case SWAIT:
176 case SLOCK:
177 case SSLEEP:
178 return (SRS_RUNNABLE);
179
180 case SZOMB:
181 return (SRS_INVALID);
182
183 case SIDL:
184 case SRUN:
185 return (SRS_RUNNING);
186
187 default:
188 syslog(LOG_ERR,"Unknown process state: %d", kp->ki_stat);
189 return (SRS_INVALID);
190 }
191}
192
193/**
194 * Make an SNMP table entry from a kernel one.
195 */
196static void
197kinfo_proc_to_swrun_entry(const struct kinfo_proc *kp,
198 struct swrun_entry *entry)
199{
200 char **argv = NULL;
201 uint64_t cpu_time = 0;
163 */
164static enum SWRunStatus
165swrun_OS_get_proc_status(const struct kinfo_proc *kp)
166{
167
168 assert(kp != NULL);
169 if(kp == NULL) {
170 return (SRS_INVALID);
171 }
172
173 /*
174 * I'm using the old style flags - they look cleaner to me,
175 * at least for the purpose of this SNMP table
176 */
177 switch (kp->ki_stat) {
178
179 case SSTOP:
180 return (SRS_NOT_RUNNABLE);
181
182 case SWAIT:
183 case SLOCK:
184 case SSLEEP:
185 return (SRS_RUNNABLE);
186
187 case SZOMB:
188 return (SRS_INVALID);
189
190 case SIDL:
191 case SRUN:
192 return (SRS_RUNNING);
193
194 default:
195 syslog(LOG_ERR,"Unknown process state: %d", kp->ki_stat);
196 return (SRS_INVALID);
197 }
198}
199
200/**
201 * Make an SNMP table entry from a kernel one.
202 */
203static void
204kinfo_proc_to_swrun_entry(const struct kinfo_proc *kp,
205 struct swrun_entry *entry)
206{
207 char **argv = NULL;
208 uint64_t cpu_time = 0;
209 size_t pname_len;
202
210
203 strlcpy((char*)entry->name, kp->ki_comm, sizeof(entry->name));
211 pname_len = strlen(kp->ki_comm) + 1;
212 entry->name = reallocf(entry->name, pname_len);
213 if (entry->name != NULL)
214 strlcpy(entry->name, kp->ki_comm, pname_len);
204
215
205 entry->id = oid_zeroDotZero; /* unknown id - FIXME */
216 entry->id = &oid_zeroDotZero; /* unknown id - FIXME */
206
217
207 entry->path[0] = '\0';
208 entry->parameters[0] = '\0';
209
210 assert(hr_kd != NULL);
211
218 assert(hr_kd != NULL);
219
212 argv = kvm_getargv(hr_kd, kp, sizeof(entry->parameters) - 1);
220 argv = kvm_getargv(hr_kd, kp, SWR_PARAM_MLEN - 1);
213 if(argv != NULL){
221 if(argv != NULL){
214 memset(entry->parameters, '\0', sizeof(entry->parameters));
222 u_char param[SWR_PARAM_MLEN];
215
223
224 memset(param, '\0', sizeof(param));
225
216 /*
217 * FIXME
218 * Path seems to not be available.
219 * Try to hack the info in argv[0];
220 * this argv is under control of the program so this info
221 * is not realiable
222 */
223 if(*argv != NULL && (*argv)[0] == '/') {
226 /*
227 * FIXME
228 * Path seems to not be available.
229 * Try to hack the info in argv[0];
230 * this argv is under control of the program so this info
231 * is not realiable
232 */
233 if(*argv != NULL && (*argv)[0] == '/') {
224 memset(entry->path, '\0', sizeof(entry->path));
225 strlcpy((char*)entry->path, *argv, sizeof(entry->path));
234 size_t path_len;
235
236 path_len = strlen(*argv) + 1;
237 if (path_len > SWR_PATH_MLEN)
238 path_len = SWR_PATH_MLEN;
239
240 entry->path = reallocf(entry->path, path_len);
241 if (entry->path != NULL) {
242 memset(entry->path, '\0', path_len);
243 strlcpy((char*)entry->path, *argv, path_len);
244 }
226 }
227
228 argv++; /* skip the first one which was used for path */
229
230 while (argv != NULL && *argv != NULL ) {
245 }
246
247 argv++; /* skip the first one which was used for path */
248
249 while (argv != NULL && *argv != NULL ) {
231 if (entry->parameters[0] != 0) {
250 if (param[0] != 0) {
232 /*
233 * add a space between parameters,
234 * except before the first one
235 */
251 /*
252 * add a space between parameters,
253 * except before the first one
254 */
236 strlcat((char *)entry->parameters,
237 " ", sizeof(entry->parameters));
255 strlcat((char *)param, " ", sizeof(param));
238 }
256 }
239 strlcat((char *)entry->parameters, *argv,
240 sizeof(entry->parameters));
257 strlcat((char *)param, *argv, sizeof(param));
241 argv++;
242 }
258 argv++;
259 }
260 /* reuse pname_len */
261 pname_len = strlen(param) + 1;
262 if (pname_len > SWR_PARAM_MLEN)
263 pname_len = SWR_PARAM_MLEN;
264
265 entry->parameters = reallocf(entry->parameters, pname_len);
266 strlcpy(entry->parameters, param, pname_len);
243 }
244
245 entry->type = (int32_t)(IS_KERNPROC(kp) ? SRT_OPERATING_SYSTEM :
246 SRT_APPLICATION);
247
248 entry->status = (int32_t)swrun_OS_get_proc_status(kp);
249 cpu_time = kp->ki_runtime / 100000; /* centi-seconds */
250
251 /* may overflow the snmp type */
252 entry->perfCPU = (cpu_time > (uint64_t)INT_MAX ? INT_MAX : cpu_time);
253 entry->perfMemory = kp->ki_size / 1024; /* in kilo-bytes */
254 entry->r_tick = get_ticks();
255}
256
257/**
258 * Create a table entry for a KLD
259 */
260static void
261kld_file_stat_to_swrun(const struct kld_file_stat *kfs,
262 struct swrun_entry *entry)
263{
267 }
268
269 entry->type = (int32_t)(IS_KERNPROC(kp) ? SRT_OPERATING_SYSTEM :
270 SRT_APPLICATION);
271
272 entry->status = (int32_t)swrun_OS_get_proc_status(kp);
273 cpu_time = kp->ki_runtime / 100000; /* centi-seconds */
274
275 /* may overflow the snmp type */
276 entry->perfCPU = (cpu_time > (uint64_t)INT_MAX ? INT_MAX : cpu_time);
277 entry->perfMemory = kp->ki_size / 1024; /* in kilo-bytes */
278 entry->r_tick = get_ticks();
279}
280
281/**
282 * Create a table entry for a KLD
283 */
284static void
285kld_file_stat_to_swrun(const struct kld_file_stat *kfs,
286 struct swrun_entry *entry)
287{
288 size_t name_len;
264
265 assert(kfs != NULL);
266 assert(entry != NULL);
267
289
290 assert(kfs != NULL);
291 assert(entry != NULL);
292
268 strlcpy((char *)entry->name, kfs->name, sizeof(entry->name));
293 name_len = strlen(kfs->name) + 1;
294 if (name_len > SWR_NAME_MLEN)
295 name_len = SWR_NAME_MLEN;
269
296
297 entry->name = reallocf(entry->name, name_len);
298 if (entry->name != NULL)
299 strlcpy((char *)entry->name, kfs->name, name_len);
300
270 /* FIXME: can we find the location where the module was loaded from? */
301 /* FIXME: can we find the location where the module was loaded from? */
271 entry->path[0] = '\0';
302 entry->path = NULL;
272
273 /* no parameters for kernel files (.ko) of for the kernel */
303
304 /* no parameters for kernel files (.ko) of for the kernel */
274 entry->parameters[0] = '\0';
305 entry->parameters = NULL;
275
306
276 entry->id = oid_zeroDotZero; /* unknown id - FIXME */
307 entry->id = &oid_zeroDotZero; /* unknown id - FIXME */
277
278 if (strcmp(kfs->name, "kernel") == 0) {
279 entry->type = (int32_t)SRT_OPERATING_SYSTEM;
280 SWOSIndex = entry->index;
281 } else {
282 entry->type = (int32_t)SRT_DEVICE_DRIVER; /* well, not really */
283 }
284 entry->status = (int32_t)SRS_RUNNING;
285 entry->perfCPU = 0; /* Info not available */
286 entry->perfMemory = kfs->size / 1024; /* in kilo-bytes */
287 entry->r_tick = get_ticks();
288}
289
290/**
291 * Get all visible proceses including the kernel visible threads
292 */
293static void
294swrun_OS_get_procs(void)
295{
296 struct kinfo_proc *plist, *kp;
297 int i;
298 int nproc;
299 struct swrun_entry *entry;
300
301 plist = kvm_getprocs(hr_kd, KERN_PROC_ALL, 0, &nproc);
302 if (plist == NULL || nproc < 0) {
303 syslog(LOG_ERR, "kvm_getprocs() failed: %m");
304 return;
305 }
306 for (i = 0, kp = plist; i < nproc; i++, kp++) {
307 /*
308 * The SNMP table's index must begin from 1 (as specified by
309 * this table definition), the PIDs are starting from 0
310 * so we are translating the PIDs to +1
311 */
312 entry = swrun_entry_find_by_index((int32_t)kp->ki_pid + 1);
313 if (entry == NULL) {
314 /* new entry - get memory for it */
315 entry = swrun_entry_create((int32_t)kp->ki_pid + 1);
316 if (entry == NULL)
317 continue;
318 }
319 entry->flags |= HR_SWRUN_FOUND; /* mark it as found */
320
321 kinfo_proc_to_swrun_entry(kp, entry);
322 }
323}
324
325/*
326 * Get kernel items: first the kernel itself, then the loaded modules.
327 */
328static void
329swrun_OS_get_kinfo(void)
330{
331 int fileid;
332 struct swrun_entry *entry;
333 struct kld_file_stat stat;
334
335 for (fileid = kldnext(0); fileid > 0; fileid = kldnext(fileid)) {
336 stat.version = sizeof(struct kld_file_stat);
337 if (kldstat(fileid, &stat) < 0) {
338 syslog(LOG_ERR, "kldstat() failed: %m");
339 continue;
340 }
341
342 /*
343 * kernel and kernel files (*.ko) will be indexed starting with
344 * NO_PID + 1; NO_PID is PID_MAX + 1 thus it will be no risk to
345 * overlap with real PIDs which are in range of 1 .. NO_PID
346 */
347 entry = swrun_entry_find_by_index(NO_PID + 1 + stat.id);
348 if (entry == NULL) {
349 /* new entry - get memory for it */
350 entry = swrun_entry_create(NO_PID + 1 + stat.id);
351 if (entry == NULL)
352 continue;
353 }
354 entry->flags |= HR_SWRUN_FOUND; /* mark it as found */
355
356 kld_file_stat_to_swrun(&stat, entry);
357 }
358}
359
360/**
361 * Refresh the hrSWRun and hrSWRunPert tables.
362 */
363static void
364refresh_swrun_tbl(void)
365{
366
367 struct swrun_entry *entry, *entry_tmp;
368
369 if (this_tick - swrun_tick < swrun_tbl_refresh) {
370 HRDBG("no refresh needed ");
371 return;
372 }
373
374 /* mark each entry as missing */
375 TAILQ_FOREACH(entry, &swrun_tbl, link)
376 entry->flags &= ~HR_SWRUN_FOUND;
377
378 swrun_OS_get_procs();
379 swrun_OS_get_kinfo();
380
381 /*
382 * Purge items that disappeared
383 */
384 TAILQ_FOREACH_SAFE(entry, &swrun_tbl, link, entry_tmp)
385 if (!(entry->flags & HR_SWRUN_FOUND))
386 swrun_entry_delete(entry);
387
388 swrun_tick = this_tick;
389
390 HRDBG("refresh DONE");
391}
392
393/**
394 * Update the information in this entry
395 */
396static void
397fetch_swrun_entry(struct swrun_entry *entry)
398{
399 struct kinfo_proc *plist;
400 int nproc;
401 struct kld_file_stat stat;
402
403 assert(entry != NULL);
404
405 if (entry->index >= NO_PID + 1) {
406 /*
407 * kernel and kernel files (*.ko) will be indexed
408 * starting with NO_PID + 1; NO_PID is PID_MAX + 1
409 * thus it will be no risk to overlap with real PIDs
410 * which are in range of 1 .. NO_PID
411 */
412 stat.version = sizeof(stat);
413 if (kldstat(entry->index - NO_PID - 1, &stat) == -1) {
414 /*
415 * not found, it's gone. Mark it as invalid for now, it
416 * will be removed from the list at next global refersh
417 */
418 HRDBG("missing item with kid=%d",
419 entry->index - NO_PID - 1);
420 entry->status = (int32_t)SRS_INVALID;
421 } else
422 kld_file_stat_to_swrun(&stat, entry);
423
424 } else {
425 /* this is a process */
426 assert(hr_kd != NULL);
427 plist = kvm_getprocs(hr_kd, KERN_PROC_PID,
428 entry->index - 1, &nproc);
429 if (plist == NULL || nproc != 1) {
430 HRDBG("missing item with PID=%d", entry->index - 1);
431 entry->status = (int32_t)SRS_INVALID;
432 } else
433 kinfo_proc_to_swrun_entry(plist, entry);
434 }
435}
436
437/**
438 * Invalidate entry. For KLDs we try to unload it, for processes we SIGKILL it.
439 */
440static int
441invalidate_swrun_entry(struct swrun_entry *entry, int commit)
442{
443 struct kinfo_proc *plist;
444 int nproc;
445 struct kld_file_stat stat;
446
447 assert(entry != NULL);
448
449 if (entry->index >= NO_PID + 1) {
450 /* this is a kernel item */
451 HRDBG("atempt to unload KLD %d",
452 entry->index - NO_PID - 1);
453
454 if (entry->index == SWOSIndex) {
455 /* can't invalidate the kernel itself */
456 return (SNMP_ERR_NOT_WRITEABLE);
457 }
458
459 stat.version = sizeof(stat);
460 if (kldstat(entry->index - NO_PID - 1, &stat) == -1) {
461 /*
462 * not found, it's gone. Mark it as invalid for now, it
463 * will be removed from the list at next global
464 * refresh
465 */
466 HRDBG("missing item with kid=%d",
467 entry->index - NO_PID - 1);
468 entry->status = (int32_t)SRS_INVALID;
469 return (SNMP_ERR_NOERROR);
470 }
471 /*
472 * There is no way to try to unload a module. There seems
473 * also no way to find out whether it is busy without unloading
474 * it. We can assume that it is busy, if the reference count
475 * is larger than 2, but if it is 1 nothing helps.
476 */
477 if (!commit) {
478 if (stat.refs > 1)
479 return (SNMP_ERR_NOT_WRITEABLE);
480 return (SNMP_ERR_NOERROR);
481 }
482 if (kldunload(stat.id) == -1) {
483 syslog(LOG_ERR,"kldunload for %d/%s failed: %m",
484 stat.id, stat.name);
485 if (errno == EBUSY)
486 return (SNMP_ERR_NOT_WRITEABLE);
487 else
488 return (SNMP_ERR_RES_UNAVAIL);
489 }
490 } else {
491 /* this is a process */
492 assert(hr_kd != NULL);
493
494 plist = kvm_getprocs(hr_kd, KERN_PROC_PID,
495 entry->index - 1, &nproc);
496 if (plist == NULL || nproc != 1) {
497 HRDBG("missing item with PID=%d", entry->index - 1);
498 entry->status = (int32_t)SRS_INVALID;
499 return (SNMP_ERR_NOERROR);
500 }
501 if (IS_KERNPROC(plist)) {
502 /* you don't want to do this */
503 return (SNMP_ERR_NOT_WRITEABLE);
504 }
505 if (kill(entry->index - 1, commit ? SIGKILL : 0) < 0) {
506 syslog(LOG_ERR,"kill (%d, SIGKILL) failed: %m",
507 entry->index - 1);
508 if (errno == ESRCH) {
509 /* race: just gone */
510 entry->status = (int32_t)SRS_INVALID;
511 return (SNMP_ERR_NOERROR);
512 }
513 return (SNMP_ERR_GENERR);
514 }
515 }
516 return (SNMP_ERR_NOERROR);
517}
518
519/**
520 * Popuplate the hrSWRunTable.
521 */
522void
523init_swrun_tbl(void)
524{
525
526 refresh_swrun_tbl();
527 HRDBG("done");
528}
529
530/**
531 * Finalize the hrSWRunTable.
532 */
533void
534fini_swrun_tbl(void)
535{
536 struct swrun_entry *n1;
537
538 while ((n1 = TAILQ_FIRST(&swrun_tbl)) != NULL) {
539 TAILQ_REMOVE(&swrun_tbl, n1, link);
540 free(n1);
541 }
542}
543
544/*
545 * This is the implementation for a generated (by a SNMP tool)
546 * function prototype, see hostres_tree.h
547 * It hanldes the SNMP operations for hrSWRunTable
548 */
549int
550op_hrSWRunTable(struct snmp_context *ctx __unused, struct snmp_value *value,
551 u_int sub, u_int iidx __unused, enum snmp_op curr_op)
552{
553 struct swrun_entry *entry;
554 int ret;
555
556 refresh_swrun_tbl();
557
558 switch (curr_op) {
559
560 case SNMP_OP_GETNEXT:
561 if ((entry = NEXT_OBJECT_INT(&swrun_tbl,
562 &value->var, sub)) == NULL)
563 return (SNMP_ERR_NOSUCHNAME);
564 value->var.len = sub + 1;
565 value->var.subs[sub] = entry->index;
566 goto get;
567
568 case SNMP_OP_GET:
569 if ((entry = FIND_OBJECT_INT(&swrun_tbl,
570 &value->var, sub)) == NULL)
571 return (SNMP_ERR_NOSUCHNAME);
572 goto get;
573
574 case SNMP_OP_SET:
575 if ((entry = FIND_OBJECT_INT(&swrun_tbl,
576 &value->var, sub)) == NULL)
577 return (SNMP_ERR_NO_CREATION);
578
579 if (entry->r_tick < this_tick)
580 fetch_swrun_entry(entry);
581
582 switch (value->var.subs[sub - 1]) {
583
584 case LEAF_hrSWRunStatus:
585 if (value->v.integer != (int32_t)SRS_INVALID)
586 return (SNMP_ERR_WRONG_VALUE);
587
588 if (entry->status == (int32_t)SRS_INVALID)
589 return (SNMP_ERR_NOERROR);
590
591 /*
592 * Here we have a problem with the entire SNMP
593 * model: if we kill now, we cannot rollback.
594 * If we kill in the commit code, we cannot
595 * return an error. Because things may change between
596 * SET and COMMIT this is impossible to handle
597 * correctly.
598 */
599 return (invalidate_swrun_entry(entry, 0));
600 }
601 return (SNMP_ERR_NOT_WRITEABLE);
602
603 case SNMP_OP_ROLLBACK:
604 return (SNMP_ERR_NOERROR);
605
606 case SNMP_OP_COMMIT:
607 if ((entry = FIND_OBJECT_INT(&swrun_tbl,
608 &value->var, sub)) == NULL)
609 return (SNMP_ERR_NOERROR);
610
611 switch (value->var.subs[sub - 1]) {
612
613 case LEAF_hrSWRunStatus:
614 if (value->v.integer == (int32_t)SRS_INVALID &&
615 entry->status != (int32_t)SRS_INVALID)
616 (void)invalidate_swrun_entry(entry, 1);
617 return (SNMP_ERR_NOERROR);
618 }
619 abort();
620 }
621 abort();
622
623 get:
624 ret = SNMP_ERR_NOERROR;
625 switch (value->var.subs[sub - 1]) {
626
627 case LEAF_hrSWRunIndex:
628 value->v.integer = entry->index;
629 break;
630
631 case LEAF_hrSWRunName:
308
309 if (strcmp(kfs->name, "kernel") == 0) {
310 entry->type = (int32_t)SRT_OPERATING_SYSTEM;
311 SWOSIndex = entry->index;
312 } else {
313 entry->type = (int32_t)SRT_DEVICE_DRIVER; /* well, not really */
314 }
315 entry->status = (int32_t)SRS_RUNNING;
316 entry->perfCPU = 0; /* Info not available */
317 entry->perfMemory = kfs->size / 1024; /* in kilo-bytes */
318 entry->r_tick = get_ticks();
319}
320
321/**
322 * Get all visible proceses including the kernel visible threads
323 */
324static void
325swrun_OS_get_procs(void)
326{
327 struct kinfo_proc *plist, *kp;
328 int i;
329 int nproc;
330 struct swrun_entry *entry;
331
332 plist = kvm_getprocs(hr_kd, KERN_PROC_ALL, 0, &nproc);
333 if (plist == NULL || nproc < 0) {
334 syslog(LOG_ERR, "kvm_getprocs() failed: %m");
335 return;
336 }
337 for (i = 0, kp = plist; i < nproc; i++, kp++) {
338 /*
339 * The SNMP table's index must begin from 1 (as specified by
340 * this table definition), the PIDs are starting from 0
341 * so we are translating the PIDs to +1
342 */
343 entry = swrun_entry_find_by_index((int32_t)kp->ki_pid + 1);
344 if (entry == NULL) {
345 /* new entry - get memory for it */
346 entry = swrun_entry_create((int32_t)kp->ki_pid + 1);
347 if (entry == NULL)
348 continue;
349 }
350 entry->flags |= HR_SWRUN_FOUND; /* mark it as found */
351
352 kinfo_proc_to_swrun_entry(kp, entry);
353 }
354}
355
356/*
357 * Get kernel items: first the kernel itself, then the loaded modules.
358 */
359static void
360swrun_OS_get_kinfo(void)
361{
362 int fileid;
363 struct swrun_entry *entry;
364 struct kld_file_stat stat;
365
366 for (fileid = kldnext(0); fileid > 0; fileid = kldnext(fileid)) {
367 stat.version = sizeof(struct kld_file_stat);
368 if (kldstat(fileid, &stat) < 0) {
369 syslog(LOG_ERR, "kldstat() failed: %m");
370 continue;
371 }
372
373 /*
374 * kernel and kernel files (*.ko) will be indexed starting with
375 * NO_PID + 1; NO_PID is PID_MAX + 1 thus it will be no risk to
376 * overlap with real PIDs which are in range of 1 .. NO_PID
377 */
378 entry = swrun_entry_find_by_index(NO_PID + 1 + stat.id);
379 if (entry == NULL) {
380 /* new entry - get memory for it */
381 entry = swrun_entry_create(NO_PID + 1 + stat.id);
382 if (entry == NULL)
383 continue;
384 }
385 entry->flags |= HR_SWRUN_FOUND; /* mark it as found */
386
387 kld_file_stat_to_swrun(&stat, entry);
388 }
389}
390
391/**
392 * Refresh the hrSWRun and hrSWRunPert tables.
393 */
394static void
395refresh_swrun_tbl(void)
396{
397
398 struct swrun_entry *entry, *entry_tmp;
399
400 if (this_tick - swrun_tick < swrun_tbl_refresh) {
401 HRDBG("no refresh needed ");
402 return;
403 }
404
405 /* mark each entry as missing */
406 TAILQ_FOREACH(entry, &swrun_tbl, link)
407 entry->flags &= ~HR_SWRUN_FOUND;
408
409 swrun_OS_get_procs();
410 swrun_OS_get_kinfo();
411
412 /*
413 * Purge items that disappeared
414 */
415 TAILQ_FOREACH_SAFE(entry, &swrun_tbl, link, entry_tmp)
416 if (!(entry->flags & HR_SWRUN_FOUND))
417 swrun_entry_delete(entry);
418
419 swrun_tick = this_tick;
420
421 HRDBG("refresh DONE");
422}
423
424/**
425 * Update the information in this entry
426 */
427static void
428fetch_swrun_entry(struct swrun_entry *entry)
429{
430 struct kinfo_proc *plist;
431 int nproc;
432 struct kld_file_stat stat;
433
434 assert(entry != NULL);
435
436 if (entry->index >= NO_PID + 1) {
437 /*
438 * kernel and kernel files (*.ko) will be indexed
439 * starting with NO_PID + 1; NO_PID is PID_MAX + 1
440 * thus it will be no risk to overlap with real PIDs
441 * which are in range of 1 .. NO_PID
442 */
443 stat.version = sizeof(stat);
444 if (kldstat(entry->index - NO_PID - 1, &stat) == -1) {
445 /*
446 * not found, it's gone. Mark it as invalid for now, it
447 * will be removed from the list at next global refersh
448 */
449 HRDBG("missing item with kid=%d",
450 entry->index - NO_PID - 1);
451 entry->status = (int32_t)SRS_INVALID;
452 } else
453 kld_file_stat_to_swrun(&stat, entry);
454
455 } else {
456 /* this is a process */
457 assert(hr_kd != NULL);
458 plist = kvm_getprocs(hr_kd, KERN_PROC_PID,
459 entry->index - 1, &nproc);
460 if (plist == NULL || nproc != 1) {
461 HRDBG("missing item with PID=%d", entry->index - 1);
462 entry->status = (int32_t)SRS_INVALID;
463 } else
464 kinfo_proc_to_swrun_entry(plist, entry);
465 }
466}
467
468/**
469 * Invalidate entry. For KLDs we try to unload it, for processes we SIGKILL it.
470 */
471static int
472invalidate_swrun_entry(struct swrun_entry *entry, int commit)
473{
474 struct kinfo_proc *plist;
475 int nproc;
476 struct kld_file_stat stat;
477
478 assert(entry != NULL);
479
480 if (entry->index >= NO_PID + 1) {
481 /* this is a kernel item */
482 HRDBG("atempt to unload KLD %d",
483 entry->index - NO_PID - 1);
484
485 if (entry->index == SWOSIndex) {
486 /* can't invalidate the kernel itself */
487 return (SNMP_ERR_NOT_WRITEABLE);
488 }
489
490 stat.version = sizeof(stat);
491 if (kldstat(entry->index - NO_PID - 1, &stat) == -1) {
492 /*
493 * not found, it's gone. Mark it as invalid for now, it
494 * will be removed from the list at next global
495 * refresh
496 */
497 HRDBG("missing item with kid=%d",
498 entry->index - NO_PID - 1);
499 entry->status = (int32_t)SRS_INVALID;
500 return (SNMP_ERR_NOERROR);
501 }
502 /*
503 * There is no way to try to unload a module. There seems
504 * also no way to find out whether it is busy without unloading
505 * it. We can assume that it is busy, if the reference count
506 * is larger than 2, but if it is 1 nothing helps.
507 */
508 if (!commit) {
509 if (stat.refs > 1)
510 return (SNMP_ERR_NOT_WRITEABLE);
511 return (SNMP_ERR_NOERROR);
512 }
513 if (kldunload(stat.id) == -1) {
514 syslog(LOG_ERR,"kldunload for %d/%s failed: %m",
515 stat.id, stat.name);
516 if (errno == EBUSY)
517 return (SNMP_ERR_NOT_WRITEABLE);
518 else
519 return (SNMP_ERR_RES_UNAVAIL);
520 }
521 } else {
522 /* this is a process */
523 assert(hr_kd != NULL);
524
525 plist = kvm_getprocs(hr_kd, KERN_PROC_PID,
526 entry->index - 1, &nproc);
527 if (plist == NULL || nproc != 1) {
528 HRDBG("missing item with PID=%d", entry->index - 1);
529 entry->status = (int32_t)SRS_INVALID;
530 return (SNMP_ERR_NOERROR);
531 }
532 if (IS_KERNPROC(plist)) {
533 /* you don't want to do this */
534 return (SNMP_ERR_NOT_WRITEABLE);
535 }
536 if (kill(entry->index - 1, commit ? SIGKILL : 0) < 0) {
537 syslog(LOG_ERR,"kill (%d, SIGKILL) failed: %m",
538 entry->index - 1);
539 if (errno == ESRCH) {
540 /* race: just gone */
541 entry->status = (int32_t)SRS_INVALID;
542 return (SNMP_ERR_NOERROR);
543 }
544 return (SNMP_ERR_GENERR);
545 }
546 }
547 return (SNMP_ERR_NOERROR);
548}
549
550/**
551 * Popuplate the hrSWRunTable.
552 */
553void
554init_swrun_tbl(void)
555{
556
557 refresh_swrun_tbl();
558 HRDBG("done");
559}
560
561/**
562 * Finalize the hrSWRunTable.
563 */
564void
565fini_swrun_tbl(void)
566{
567 struct swrun_entry *n1;
568
569 while ((n1 = TAILQ_FIRST(&swrun_tbl)) != NULL) {
570 TAILQ_REMOVE(&swrun_tbl, n1, link);
571 free(n1);
572 }
573}
574
575/*
576 * This is the implementation for a generated (by a SNMP tool)
577 * function prototype, see hostres_tree.h
578 * It hanldes the SNMP operations for hrSWRunTable
579 */
580int
581op_hrSWRunTable(struct snmp_context *ctx __unused, struct snmp_value *value,
582 u_int sub, u_int iidx __unused, enum snmp_op curr_op)
583{
584 struct swrun_entry *entry;
585 int ret;
586
587 refresh_swrun_tbl();
588
589 switch (curr_op) {
590
591 case SNMP_OP_GETNEXT:
592 if ((entry = NEXT_OBJECT_INT(&swrun_tbl,
593 &value->var, sub)) == NULL)
594 return (SNMP_ERR_NOSUCHNAME);
595 value->var.len = sub + 1;
596 value->var.subs[sub] = entry->index;
597 goto get;
598
599 case SNMP_OP_GET:
600 if ((entry = FIND_OBJECT_INT(&swrun_tbl,
601 &value->var, sub)) == NULL)
602 return (SNMP_ERR_NOSUCHNAME);
603 goto get;
604
605 case SNMP_OP_SET:
606 if ((entry = FIND_OBJECT_INT(&swrun_tbl,
607 &value->var, sub)) == NULL)
608 return (SNMP_ERR_NO_CREATION);
609
610 if (entry->r_tick < this_tick)
611 fetch_swrun_entry(entry);
612
613 switch (value->var.subs[sub - 1]) {
614
615 case LEAF_hrSWRunStatus:
616 if (value->v.integer != (int32_t)SRS_INVALID)
617 return (SNMP_ERR_WRONG_VALUE);
618
619 if (entry->status == (int32_t)SRS_INVALID)
620 return (SNMP_ERR_NOERROR);
621
622 /*
623 * Here we have a problem with the entire SNMP
624 * model: if we kill now, we cannot rollback.
625 * If we kill in the commit code, we cannot
626 * return an error. Because things may change between
627 * SET and COMMIT this is impossible to handle
628 * correctly.
629 */
630 return (invalidate_swrun_entry(entry, 0));
631 }
632 return (SNMP_ERR_NOT_WRITEABLE);
633
634 case SNMP_OP_ROLLBACK:
635 return (SNMP_ERR_NOERROR);
636
637 case SNMP_OP_COMMIT:
638 if ((entry = FIND_OBJECT_INT(&swrun_tbl,
639 &value->var, sub)) == NULL)
640 return (SNMP_ERR_NOERROR);
641
642 switch (value->var.subs[sub - 1]) {
643
644 case LEAF_hrSWRunStatus:
645 if (value->v.integer == (int32_t)SRS_INVALID &&
646 entry->status != (int32_t)SRS_INVALID)
647 (void)invalidate_swrun_entry(entry, 1);
648 return (SNMP_ERR_NOERROR);
649 }
650 abort();
651 }
652 abort();
653
654 get:
655 ret = SNMP_ERR_NOERROR;
656 switch (value->var.subs[sub - 1]) {
657
658 case LEAF_hrSWRunIndex:
659 value->v.integer = entry->index;
660 break;
661
662 case LEAF_hrSWRunName:
632 ret = string_get(value, entry->name, -1);
633 break;
663 if (entry->name != NULL)
664 ret = string_get(value, entry->name, -1);
665 else
666 ret = string_get(value, "", -1);
667 break;
634
635 case LEAF_hrSWRunID:
668
669 case LEAF_hrSWRunID:
636 value->v.oid = entry->id;
637 break;
670 assert(entry->id != NULL);
671 value->v.oid = *entry->id;
672 break;
638
673
639 case LEAF_hrSWRunPath:
640 ret = string_get(value, entry->path, -1);
641 break;
674 case LEAF_hrSWRunPath:
675 if (entry->path != NULL)
676 ret = string_get(value, entry->path, -1);
677 else
678 ret = string_get(value, "", -1);
679 break;
642
643 case LEAF_hrSWRunParameters:
680
681 case LEAF_hrSWRunParameters:
644 ret = string_get(value, entry->parameters, -1);
645 break;
682 if (entry->parameters != NULL)
683 ret = string_get(value, entry->parameters, -1);
684 else
685 ret = string_get(value, "", -1);
686 break;
646
647 case LEAF_hrSWRunType:
687
688 case LEAF_hrSWRunType:
648 value->v.integer = entry->type;
689 value->v.integer = entry->type;
649 break;
650
651 case LEAF_hrSWRunStatus:
690 break;
691
692 case LEAF_hrSWRunStatus:
652 value->v.integer = entry->status;
693 value->v.integer = entry->status;
653 break;
654
655 default:
694 break;
695
696 default:
656 abort();
697 abort();
657 }
658 return (ret);
659}
660
661/**
662 * Scalar(s) in the SWRun group
663 */
664int
665op_hrSWRun(struct snmp_context *ctx __unused, struct snmp_value *value,
666 u_int sub, u_int iidx __unused, enum snmp_op curr_op)
667{
668
669 /* only SNMP GET is possible */
670 switch (curr_op) {
671
672 case SNMP_OP_GET:
673 goto get;
674
675 case SNMP_OP_SET:
676 return (SNMP_ERR_NOT_WRITEABLE);
677
678 case SNMP_OP_ROLLBACK:
679 case SNMP_OP_COMMIT:
680 case SNMP_OP_GETNEXT:
681 abort();
682 }
683 abort();
684
685 get:
686 switch (value->var.subs[sub - 1]) {
687
688 case LEAF_hrSWOSIndex:
689 value->v.uint32 = SWOSIndex;
690 return (SNMP_ERR_NOERROR);
691
692 default:
693 abort();
694 }
695}
696
697/*
698 * This is the implementation for a generated (by a SNMP tool)
699 * function prototype, see hostres_tree.h
700 * It handles the SNMP operations for hrSWRunPerfTable
701 */
702int
703op_hrSWRunPerfTable(struct snmp_context *ctx __unused,
704 struct snmp_value *value, u_int sub, u_int iidx __unused,
705 enum snmp_op curr_op )
706{
707 struct swrun_entry *entry;
708
709 refresh_swrun_tbl();
710
711 switch (curr_op) {
712
713 case SNMP_OP_GETNEXT:
714 if ((entry = NEXT_OBJECT_INT(&swrun_tbl,
715 &value->var, sub)) == NULL)
716 return (SNMP_ERR_NOSUCHNAME);
717 value->var.len = sub + 1;
718 value->var.subs[sub] = entry->index;
719 goto get;
720
721 case SNMP_OP_GET:
722 if ((entry = FIND_OBJECT_INT(&swrun_tbl,
723 &value->var, sub)) == NULL)
724 return (SNMP_ERR_NOSUCHNAME);
725 goto get;
726
727 case SNMP_OP_SET:
728 if ((entry = FIND_OBJECT_INT(&swrun_tbl,
729 &value->var, sub)) == NULL)
730 return (SNMP_ERR_NO_CREATION);
731 return (SNMP_ERR_NOT_WRITEABLE);
732
733 case SNMP_OP_ROLLBACK:
734 case SNMP_OP_COMMIT:
698 }
699 return (ret);
700}
701
702/**
703 * Scalar(s) in the SWRun group
704 */
705int
706op_hrSWRun(struct snmp_context *ctx __unused, struct snmp_value *value,
707 u_int sub, u_int iidx __unused, enum snmp_op curr_op)
708{
709
710 /* only SNMP GET is possible */
711 switch (curr_op) {
712
713 case SNMP_OP_GET:
714 goto get;
715
716 case SNMP_OP_SET:
717 return (SNMP_ERR_NOT_WRITEABLE);
718
719 case SNMP_OP_ROLLBACK:
720 case SNMP_OP_COMMIT:
721 case SNMP_OP_GETNEXT:
722 abort();
723 }
724 abort();
725
726 get:
727 switch (value->var.subs[sub - 1]) {
728
729 case LEAF_hrSWOSIndex:
730 value->v.uint32 = SWOSIndex;
731 return (SNMP_ERR_NOERROR);
732
733 default:
734 abort();
735 }
736}
737
738/*
739 * This is the implementation for a generated (by a SNMP tool)
740 * function prototype, see hostres_tree.h
741 * It handles the SNMP operations for hrSWRunPerfTable
742 */
743int
744op_hrSWRunPerfTable(struct snmp_context *ctx __unused,
745 struct snmp_value *value, u_int sub, u_int iidx __unused,
746 enum snmp_op curr_op )
747{
748 struct swrun_entry *entry;
749
750 refresh_swrun_tbl();
751
752 switch (curr_op) {
753
754 case SNMP_OP_GETNEXT:
755 if ((entry = NEXT_OBJECT_INT(&swrun_tbl,
756 &value->var, sub)) == NULL)
757 return (SNMP_ERR_NOSUCHNAME);
758 value->var.len = sub + 1;
759 value->var.subs[sub] = entry->index;
760 goto get;
761
762 case SNMP_OP_GET:
763 if ((entry = FIND_OBJECT_INT(&swrun_tbl,
764 &value->var, sub)) == NULL)
765 return (SNMP_ERR_NOSUCHNAME);
766 goto get;
767
768 case SNMP_OP_SET:
769 if ((entry = FIND_OBJECT_INT(&swrun_tbl,
770 &value->var, sub)) == NULL)
771 return (SNMP_ERR_NO_CREATION);
772 return (SNMP_ERR_NOT_WRITEABLE);
773
774 case SNMP_OP_ROLLBACK:
775 case SNMP_OP_COMMIT:
735 abort();
776 abort();
736 }
737 abort();
738
739 get:
740 switch (value->var.subs[sub - 1]) {
741
742 case LEAF_hrSWRunPerfCPU:
743 value->v.integer = entry->perfCPU;
744 return (SNMP_ERR_NOERROR);
745
746 case LEAF_hrSWRunPerfMem:
747 value->v.integer = entry->perfMemory;
777 }
778 abort();
779
780 get:
781 switch (value->var.subs[sub - 1]) {
782
783 case LEAF_hrSWRunPerfCPU:
784 value->v.integer = entry->perfCPU;
785 return (SNMP_ERR_NOERROR);
786
787 case LEAF_hrSWRunPerfMem:
788 value->v.integer = entry->perfMemory;
748 return (SNMP_ERR_NOERROR);
789 return (SNMP_ERR_NOERROR);
749 }
750 abort();
751}
790 }
791 abort();
792}