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 * 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 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 * 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 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 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 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 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 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 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 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 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 552 init_swrun_tbl(void) 553 { 554 555 refresh_swrun_tbl(); 556 HRDBG("done"); 557 } 558 559 /** 560 * Finalize the hrSWRunTable. 561 */ 562 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 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 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 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