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 } 793