]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - usr.sbin/bsnmpd/modules/snmp_hostres/hostres_swrun_tbl.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / usr.sbin / bsnmpd / modules / snmp_hostres / hostres_swrun_tbl.c
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$
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  * Ugly thing: PID_MAX, NO_PID defined only in kernel
52  */
53 #define NO_PID          100000
54
55 enum SWRunType {
56         SRT_UNKNOWN             = 1,
57         SRT_OPERATING_SYSTEM    = 2,
58         SRT_DEVICE_DRIVER       = 3,
59         SRT_APPLICATION         = 4
60
61 };
62
63 enum 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
75 /*
76  * This structure is used to hold a SNMP table entry
77  * for both hrSWRunTable and hrSWRunPerfTable because
78  * hrSWRunPerfTable AUGMENTS hrSWRunTable
79  */
80 struct swrun_entry {
81         int32_t         index;
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 */
86         int32_t         type;           /* enum SWRunType */
87         int32_t         status;         /* enum SWRunStatus */
88         int32_t         perfCPU;
89         int32_t         perfMemory;
90 #define HR_SWRUN_FOUND 0x001
91         uint32_t        flags;
92         uint64_t        r_tick;         /* tick when entry refreshed */
93         TAILQ_ENTRY(swrun_entry) link;
94 };
95 TAILQ_HEAD(swrun_tbl, swrun_entry);
96
97 /* the head of the list with hrSWRunTable's entries */
98 static struct swrun_tbl swrun_tbl = TAILQ_HEAD_INITIALIZER(swrun_tbl);
99
100 /* last (agent) tick when hrSWRunTable and hrSWRunPerTable was updated */
101 static uint64_t swrun_tick;
102
103 /* maximum number of ticks between updates of SWRun and SWRunPerf table */
104 uint32_t swrun_tbl_refresh = HR_SWRUN_TBL_REFRESH * 100;
105
106 /* the value of the MIB object with the same name */
107 static 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  */
114 static struct swrun_entry *
115 swrun_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  */
133 static void
134 swrun_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);
144         free(entry);
145 }
146
147 /**
148  * Search one item by its index, return NULL if none found
149  */
150 static struct swrun_entry *
151 swrun_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 /**
162  * Translate the kernel's process status to SNMP.
163  */
164 static enum SWRunStatus
165 swrun_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  */
203 static void
204 kinfo_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;
210
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);
215
216         entry->id = &oid_zeroDotZero; /* unknown id - FIXME */
217
218         assert(hr_kd != NULL);
219
220         argv = kvm_getargv(hr_kd, kp, SWR_PARAM_MLEN - 1);
221         if(argv != NULL){
222                 u_char param[SWR_PARAM_MLEN];
223
224                 memset(param, '\0', sizeof(param));
225
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] == '/') {
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                         }
245                 }
246
247                 argv++; /* skip the first one which was used for path */
248
249                 while (argv != NULL && *argv != NULL ) {
250                         if (param[0] != 0)  {
251                                 /*
252                                  * add a space between parameters,
253                                  * except before the first one
254                                  */
255                                 strlcat((char *)param, " ", sizeof(param));
256                         }
257                         strlcat((char *)param, *argv, sizeof(param));
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);
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  */
284 static void
285 kld_file_stat_to_swrun(const struct kld_file_stat *kfs,
286     struct swrun_entry *entry)
287 {
288         size_t name_len;
289
290         assert(kfs != NULL);
291         assert(entry != NULL);
292
293         name_len = strlen(kfs->name) + 1;
294         if (name_len > SWR_NAME_MLEN)
295                 name_len = SWR_NAME_MLEN;
296
297         entry->name = reallocf(entry->name, name_len);
298         if (entry->name != NULL)
299                 strlcpy((char *)entry->name, kfs->name, name_len);
300
301         /* FIXME: can we find the location where the module was loaded from? */
302         entry->path = NULL;
303
304         /* no parameters for kernel files (.ko) of for the kernel */
305         entry->parameters = NULL;
306
307         entry->id = &oid_zeroDotZero; /* unknown id - FIXME */
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  */
324 static void
325 swrun_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  */
359 static void
360 swrun_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  */
394 static void
395 refresh_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  */
427 static void
428 fetch_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  */
471 static int
472 invalidate_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  */
553 void
554 init_swrun_tbl(void)
555 {
556
557         refresh_swrun_tbl();
558         HRDBG("done");
559 }
560
561 /**
562  * Finalize the hrSWRunTable.
563  */
564 void
565 fini_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  */
580 int
581 op_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:
663                 if (entry->name != NULL)
664                         ret = string_get(value, entry->name, -1);
665                 else
666                         ret = string_get(value, "", -1);
667                 break;
668
669           case LEAF_hrSWRunID:
670                 assert(entry->id != NULL);
671                 value->v.oid = *entry->id;
672                 break;
673
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;
680
681           case LEAF_hrSWRunParameters:
682                 if (entry->parameters != NULL)
683                         ret = string_get(value, entry->parameters, -1);
684                 else
685                         ret = string_get(value, "", -1);
686                 break;
687
688           case LEAF_hrSWRunType:
689                 value->v.integer = entry->type;
690                 break;
691
692           case LEAF_hrSWRunStatus:
693                 value->v.integer = entry->status;
694                 break;
695
696           default:
697                 abort();
698         }
699         return (ret);
700 }
701
702 /**
703  * Scalar(s) in the SWRun group
704  */
705 int
706 op_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  */
743 int
744 op_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:
776                 abort();
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;
789                 return (SNMP_ERR_NOERROR);
790         }
791         abort();
792 }