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