1154133Sharti/* 2154133Sharti * Copyright (c) 2005-2006 The FreeBSD Project 3154133Sharti * All rights reserved. 4154133Sharti * 5154133Sharti * Author: Victor Cruceru <soc-victor@freebsd.org> 6154133Sharti * 7154133Sharti * Redistribution of this software and documentation and use in source and 8154133Sharti * binary forms, with or without modification, are permitted provided that 9154133Sharti * the following conditions are met: 10154133Sharti * 11154133Sharti * 1. Redistributions of source code or documentation must retain the above 12154133Sharti * copyright notice, this list of conditions and the following disclaimer. 13154133Sharti * 2. Redistributions in binary form must reproduce the above copyright 14154133Sharti * notice, this list of conditions and the following disclaimer in the 15154133Sharti * documentation and/or other materials provided with the distribution. 16154133Sharti * 17154133Sharti * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18154133Sharti * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19154133Sharti * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20154133Sharti * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21154133Sharti * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22154133Sharti * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23154133Sharti * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24154133Sharti * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25154133Sharti * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26154133Sharti * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27154133Sharti * SUCH DAMAGE. 28154133Sharti * 29154133Sharti * $FreeBSD: stable/10/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_swinstalled_tbl.c 310900 2016-12-31 10:30:56Z ngie $ 30154133Sharti * 31154133Sharti * Host Resources MIB implementation for SNMPd: instrumentation for 32154133Sharti * hrSWInstalledTable 33154133Sharti */ 34154133Sharti 35154133Sharti#include <sys/limits.h> 36154133Sharti#include <sys/stat.h> 37154133Sharti#include <sys/sysctl.h> 38154133Sharti#include <sys/utsname.h> 39154133Sharti 40154133Sharti#include <assert.h> 41154133Sharti#include <dirent.h> 42154133Sharti#include <err.h> 43154133Sharti#include <errno.h> 44154133Sharti#include <stdlib.h> 45154133Sharti#include <string.h> 46154133Sharti#include <syslog.h> 47160341Sharti#include <sysexits.h> 48154133Sharti 49154133Sharti#include "hostres_snmp.h" 50154133Sharti#include "hostres_oid.h" 51154133Sharti#include "hostres_tree.h" 52154133Sharti 53310900Sngie#define CONTENTS_FNAME "+CONTENTS" 54154133Sharti 55154133Shartienum SWInstalledType { 56154133Sharti SWI_UNKNOWN = 1, 57154133Sharti SWI_OPERATING_SYSTEM = 2, 58154133Sharti SWI_DEVICE_DRIVER = 3, 59154133Sharti SWI_APPLICATION = 4 60154133Sharti}; 61154133Sharti 62160341Sharti#define SW_NAME_MLEN (64 + 1) 63154133Sharti 64154133Sharti/* 65154133Sharti * This structure is used to hold a SNMP table entry 66154133Sharti * for HOST-RESOURCES-MIB's hrSWInstalledTable 67154133Sharti */ 68154133Shartistruct swins_entry { 69154133Sharti int32_t index; 70160341Sharti u_char *name; /* max len for this is SW_NAME_MLEN */ 71160341Sharti const struct asn_oid *id; 72160341Sharti int32_t type; /* from enum SWInstalledType */ 73154133Sharti u_char date[11]; 74154133Sharti u_int date_len; 75154133Sharti 76160341Sharti#define HR_SWINSTALLED_FOUND 0x001 77160341Sharti#define HR_SWINSTALLED_IMMUTABLE 0x002 78154133Sharti uint32_t flags; 79154133Sharti 80154133Sharti TAILQ_ENTRY(swins_entry) link; 81154133Sharti}; 82154133ShartiTAILQ_HEAD(swins_tbl, swins_entry); 83154133Sharti 84154133Sharti/* 85154133Sharti * Table to keep a conistent mapping between software and indexes. 86154133Sharti */ 87154133Shartistruct swins_map_entry { 88160341Sharti int32_t index; /* swins_entry::index */ 89160341Sharti u_char *name; /* map key,a copy of swins_entry::name*/ 90154133Sharti 91154133Sharti /* 92154133Sharti * next may be NULL if the respective hrSWInstalledTblEntry 93154133Sharti * is (temporally) gone 94154133Sharti */ 95154133Sharti struct swins_entry *entry; 96154133Sharti 97160341Sharti STAILQ_ENTRY(swins_map_entry) link; 98154133Sharti}; 99154133ShartiSTAILQ_HEAD(swins_map, swins_map_entry); 100154133Sharti 101154133Sharti/* map for consistent indexing */ 102154133Shartistatic struct swins_map swins_map = STAILQ_HEAD_INITIALIZER(swins_map); 103154133Sharti 104154133Sharti/* the head of the list with hrSWInstalledTable's entries */ 105154133Shartistatic struct swins_tbl swins_tbl = TAILQ_HEAD_INITIALIZER(swins_tbl); 106154133Sharti 107154133Sharti/* next int available for indexing the hrSWInstalledTable */ 108154133Shartistatic uint32_t next_swins_index = 1; 109154133Sharti 110154133Sharti/* last (agent) tick when hrSWInstalledTable was updated */ 111154133Shartistatic uint64_t swins_tick; 112154133Sharti 113154133Sharti/* maximum number of ticks between updates of network table */ 114154133Shartiuint32_t swins_tbl_refresh = HR_SWINS_TBL_REFRESH * 100; 115154133Sharti 116154133Sharti/* package directory */ 117154133Shartiu_char *pkg_dir; 118154133Sharti 119154133Sharti/* last change of package list */ 120154133Shartistatic time_t os_pkg_last_change; 121154133Sharti 122154133Sharti/** 123154133Sharti * Create a new entry into the hrSWInstalledTable 124154133Sharti */ 125154133Shartistatic struct swins_entry * 126154133Shartiswins_entry_create(const char *name) 127154133Sharti{ 128154133Sharti struct swins_entry *entry; 129154133Sharti struct swins_map_entry *map; 130154133Sharti 131154133Sharti STAILQ_FOREACH(map, &swins_map, link) 132160341Sharti if (strcmp((const char *)map->name, name) == 0) 133154133Sharti break; 134154133Sharti 135154133Sharti if (map == NULL) { 136160341Sharti size_t name_len; 137154133Sharti /* new object - get a new index */ 138154133Sharti if (next_swins_index > INT_MAX) { 139310900Sngie syslog(LOG_ERR, "%s: hrSWInstalledTable index wrap", 140154133Sharti __func__ ); 141160341Sharti /* There isn't much we can do here. 142160341Sharti * If the next_swins_index is consumed 143160341Sharti * then we can't add entries to this table 144160341Sharti * So it is better to exit - if the table is sparsed 145160341Sharti * at the next agent run we can fill it fully. 146160341Sharti */ 147160341Sharti errx(EX_SOFTWARE, "hrSWInstalledTable index wrap"); 148154133Sharti } 149154133Sharti 150154133Sharti if ((map = malloc(sizeof(*map))) == NULL) { 151154133Sharti syslog(LOG_ERR, "%s: %m", __func__ ); 152154133Sharti return (NULL); 153154133Sharti } 154160341Sharti 155160341Sharti name_len = strlen(name) + 1; 156160341Sharti if (name_len > SW_NAME_MLEN) 157160341Sharti name_len = SW_NAME_MLEN; 158160341Sharti 159160341Sharti if ((map->name = malloc(name_len)) == NULL) { 160160341Sharti syslog(LOG_WARNING, "%s: %m", __func__); 161160341Sharti free(map); 162160341Sharti return (NULL); 163160341Sharti } 164160341Sharti 165154133Sharti map->index = next_swins_index++; 166160341Sharti strlcpy((char *)map->name, name, name_len); 167154133Sharti 168154133Sharti STAILQ_INSERT_TAIL(&swins_map, map, link); 169154133Sharti 170154133Sharti HRDBG("%s added into hrSWInstalled at %d", name, map->index); 171154133Sharti } 172160341Sharti 173160341Sharti if ((entry = malloc(sizeof(*entry))) == NULL) { 174160341Sharti syslog(LOG_WARNING, "%s: %m", __func__); 175160341Sharti return (NULL); 176160341Sharti } 177160341Sharti memset(entry, 0, sizeof(*entry)); 178160341Sharti 179160341Sharti if ((entry->name = strdup(map->name)) == NULL) { 180160341Sharti syslog(LOG_WARNING, "%s: %m", __func__); 181160341Sharti free(entry); 182160341Sharti return (NULL); 183160341Sharti } 184160341Sharti 185154133Sharti entry->index = map->index; 186154133Sharti map->entry = entry; 187154133Sharti 188154133Sharti INSERT_OBJECT_INT(entry, &swins_tbl); 189154133Sharti 190154133Sharti return (entry); 191154133Sharti} 192154133Sharti 193154133Sharti/** 194154133Sharti * Delete an entry in the hrSWInstalledTable 195154133Sharti */ 196154133Shartistatic void 197154133Shartiswins_entry_delete(struct swins_entry *entry) 198154133Sharti{ 199154133Sharti struct swins_map_entry *map; 200154133Sharti 201154133Sharti assert(entry != NULL); 202154133Sharti 203154133Sharti TAILQ_REMOVE(&swins_tbl, entry, link); 204154133Sharti 205154133Sharti STAILQ_FOREACH(map, &swins_map, link) 206154133Sharti if (map->entry == entry) { 207154133Sharti map->entry = NULL; 208154133Sharti break; 209154133Sharti } 210154133Sharti 211160341Sharti free(entry->name); 212154133Sharti free(entry); 213154133Sharti} 214154133Sharti 215154133Sharti/** 216154133Sharti * Find an entry given it's name 217154133Sharti */ 218154133Shartistatic struct swins_entry * 219154133Shartiswins_find_by_name(const char *name) 220154133Sharti{ 221154133Sharti struct swins_entry *entry; 222154133Sharti 223154133Sharti TAILQ_FOREACH(entry, &swins_tbl, link) 224160341Sharti if (strcmp((const char*)entry->name, name) == 0) 225154133Sharti return (entry); 226154133Sharti return (NULL); 227154133Sharti} 228154133Sharti 229154133Sharti/** 230154133Sharti * Finalize this table 231154133Sharti */ 232154133Shartivoid 233154133Shartifini_swins_tbl(void) 234154133Sharti{ 235154133Sharti struct swins_map_entry *n1; 236154133Sharti 237154133Sharti while ((n1 = STAILQ_FIRST(&swins_map)) != NULL) { 238154133Sharti STAILQ_REMOVE_HEAD(&swins_map, link); 239154133Sharti if (n1->entry != NULL) { 240154133Sharti TAILQ_REMOVE(&swins_tbl, n1->entry, link); 241160341Sharti free(n1->entry->name); 242154133Sharti free(n1->entry); 243154133Sharti } 244160341Sharti free(n1->name); 245154133Sharti free(n1); 246160341Sharti } 247154133Sharti assert(TAILQ_EMPTY(&swins_tbl)); 248154133Sharti} 249154133Sharti 250154133Sharti/** 251154133Sharti * Get the *running* O/S identification 252154133Sharti */ 253154133Shartistatic void 254154133Shartiswins_get_OS_ident(void) 255154133Sharti{ 256154133Sharti struct utsname os_id; 257160341Sharti char os_string[SW_NAME_MLEN] = ""; 258154133Sharti struct swins_entry *entry; 259154133Sharti u_char *boot; 260154133Sharti struct stat sb; 261154133Sharti struct tm k_ts; 262154133Sharti 263160341Sharti if (uname(&os_id) == -1) { 264160341Sharti syslog(LOG_WARNING, "%s: %m", __func__); 265154133Sharti return; 266160341Sharti } 267154133Sharti 268154133Sharti snprintf(os_string, sizeof(os_string), "%s: %s", 269154133Sharti os_id.sysname, os_id.version); 270154133Sharti 271154133Sharti if ((entry = swins_find_by_name(os_string)) != NULL || 272154133Sharti (entry = swins_entry_create(os_string)) == NULL) 273154133Sharti return; 274154133Sharti 275154133Sharti entry->flags |= (HR_SWINSTALLED_FOUND | HR_SWINSTALLED_IMMUTABLE); 276160341Sharti entry->id = &oid_zeroDotZero; 277154133Sharti entry->type = (int32_t)SWI_OPERATING_SYSTEM; 278154133Sharti memset(entry->date, 0, sizeof(entry->date)); 279154133Sharti 280154133Sharti if (OS_getSystemInitialLoadParameters(&boot) == SNMP_ERR_NOERROR && 281154133Sharti strlen(boot) > 0 && stat(boot, &sb) == 0 && 282154133Sharti localtime_r(&sb.st_ctime, &k_ts) != NULL) 283154133Sharti entry->date_len = make_date_time(entry->date, &k_ts, 0); 284154133Sharti} 285154133Sharti 286154133Sharti/** 287154133Sharti * Read the installed packages 288154133Sharti */ 289154133Shartistatic int 290154133Shartiswins_get_packages(void) 291154133Sharti{ 292154133Sharti struct stat sb; 293154133Sharti DIR *p_dir; 294154133Sharti struct dirent *ent; 295310900Sngie struct tm k_ts; 296160341Sharti char *pkg_file; 297154133Sharti struct swins_entry *entry; 298154133Sharti int ret = 0; 299154133Sharti 300154133Sharti if (pkg_dir == NULL) 301154133Sharti /* initialisation may have failed */ 302154133Sharti return (-1); 303154133Sharti 304154133Sharti if (stat(pkg_dir, &sb) != 0) { 305154133Sharti syslog(LOG_ERR, "hrSWInstalledTable: stat(\"%s\") failed: %m", 306154133Sharti pkg_dir); 307154133Sharti return (-1); 308154133Sharti } 309154133Sharti if (!S_ISDIR(sb.st_mode)) { 310154133Sharti syslog(LOG_ERR, "hrSWInstalledTable: \"%s\" is not a directory", 311154133Sharti pkg_dir); 312154133Sharti return (-1); 313154133Sharti } 314154133Sharti if (sb.st_ctime <= os_pkg_last_change) { 315154133Sharti HRDBG("no need to rescan installed packages -- " 316154133Sharti "directory time-stamp unmodified"); 317154133Sharti 318154133Sharti TAILQ_FOREACH(entry, &swins_tbl, link) 319154133Sharti entry->flags |= HR_SWINSTALLED_FOUND; 320154133Sharti 321154133Sharti return (0); 322154133Sharti } 323154133Sharti 324160341Sharti if ((p_dir = opendir(pkg_dir)) == NULL) { 325160341Sharti syslog(LOG_ERR, "hrSWInstalledTable: opendir(\"%s\") failed: " 326154133Sharti "%m", pkg_dir); 327154133Sharti return (-1); 328160341Sharti } 329154133Sharti 330310900Sngie while (errno = 0, (ent = readdir(p_dir)) != NULL) { 331160341Sharti HRDBG(" pkg file: %s", ent->d_name); 332154133Sharti 333154133Sharti /* check that the contents file is a regular file */ 334160341Sharti if (asprintf(&pkg_file, "%s/%s/%s", pkg_dir, ent->d_name, 335154133Sharti CONTENTS_FNAME) == -1) 336154133Sharti continue; 337154133Sharti 338160341Sharti if (stat(pkg_file, &sb) != 0 ) { 339154133Sharti free(pkg_file); 340160341Sharti continue; 341154133Sharti } 342154133Sharti 343154133Sharti if (!S_ISREG(sb.st_mode)) { 344154133Sharti syslog(LOG_ERR, "hrSWInstalledTable: \"%s\" not a " 345154133Sharti "regular file -- skipped", pkg_file); 346154133Sharti free(pkg_file); 347154133Sharti continue; 348154133Sharti } 349154133Sharti free(pkg_file); 350154133Sharti 351154133Sharti /* read directory timestamp on package */ 352154133Sharti if (asprintf(&pkg_file, "%s/%s", pkg_dir, ent->d_name) == -1) 353154133Sharti continue; 354154133Sharti 355154133Sharti if (stat(pkg_file, &sb) == -1 || 356154133Sharti localtime_r(&sb.st_ctime, &k_ts) == NULL) { 357154133Sharti free(pkg_file); 358154133Sharti continue; 359154133Sharti } 360154133Sharti free(pkg_file); 361154133Sharti 362154133Sharti /* update or create entry */ 363160341Sharti if ((entry = swins_find_by_name(ent->d_name)) == NULL && 364160341Sharti (entry = swins_entry_create(ent->d_name)) == NULL) { 365154133Sharti ret = -1; 366160341Sharti goto PKG_LOOP_END; 367154133Sharti } 368154133Sharti 369154133Sharti entry->flags |= HR_SWINSTALLED_FOUND; 370160341Sharti entry->id = &oid_zeroDotZero; 371154133Sharti entry->type = (int32_t)SWI_APPLICATION; 372154133Sharti 373154133Sharti entry->date_len = make_date_time(entry->date, &k_ts, 0); 374310900Sngie } 375154133Sharti 376154133Sharti if (errno != 0) { 377154133Sharti syslog(LOG_ERR, "hrSWInstalledTable: readdir_r(\"%s\") failed:" 378154133Sharti " %m", pkg_dir); 379154133Sharti ret = -1; 380154133Sharti } else { 381154133Sharti /* 382154133Sharti * save the timestamp of directory 383160341Sharti * to avoid any further scanning 384154133Sharti */ 385154133Sharti os_pkg_last_change = sb.st_ctime; 386154133Sharti } 387154133Sharti PKG_LOOP_END: 388154133Sharti (void)closedir(p_dir); 389154133Sharti return (ret); 390154133Sharti} 391154133Sharti 392154133Sharti/** 393154133Sharti * Refresh the installed software table. 394154133Sharti */ 395154133Shartivoid 396154133Shartirefresh_swins_tbl(void) 397154133Sharti{ 398154133Sharti int ret; 399154133Sharti struct swins_entry *entry, *entry_tmp; 400154133Sharti 401154133Sharti if (this_tick - swins_tick < swins_tbl_refresh) { 402154133Sharti HRDBG("no refresh needed"); 403154133Sharti return; 404154133Sharti } 405154133Sharti 406154133Sharti /* mark each entry as missing */ 407154133Sharti TAILQ_FOREACH(entry, &swins_tbl, link) 408154133Sharti entry->flags &= ~HR_SWINSTALLED_FOUND; 409154133Sharti 410154133Sharti ret = swins_get_packages(); 411154133Sharti 412154133Sharti TAILQ_FOREACH_SAFE(entry, &swins_tbl, link, entry_tmp) 413154133Sharti if (!(entry->flags & HR_SWINSTALLED_FOUND) && 414154133Sharti !(entry->flags & HR_SWINSTALLED_IMMUTABLE)) 415154133Sharti swins_entry_delete(entry); 416154133Sharti 417154133Sharti if (ret == 0) 418154133Sharti swins_tick = this_tick; 419154133Sharti} 420154133Sharti 421154133Sharti/** 422154133Sharti * Create and populate the package table 423154133Sharti */ 424154133Shartivoid 425154133Shartiinit_swins_tbl(void) 426154133Sharti{ 427154133Sharti 428160341Sharti if ((pkg_dir = malloc(sizeof(PATH_PKGDIR))) == NULL) 429154133Sharti syslog(LOG_ERR, "%s: %m", __func__); 430160341Sharti else 431154133Sharti strcpy(pkg_dir, PATH_PKGDIR); 432154133Sharti 433154133Sharti swins_get_OS_ident(); 434154133Sharti refresh_swins_tbl(); 435154133Sharti 436154133Sharti HRDBG("init done"); 437154133Sharti} 438154133Sharti 439154133Sharti/** 440154133Sharti * SNMP handler 441154133Sharti */ 442154133Shartiint 443154133Shartiop_hrSWInstalledTable(struct snmp_context *ctx __unused, 444154133Sharti struct snmp_value *value, u_int sub, u_int iidx __unused, 445154133Sharti enum snmp_op curr_op) 446154133Sharti{ 447154133Sharti struct swins_entry *entry; 448154133Sharti 449154133Sharti refresh_swins_tbl(); 450154133Sharti 451154133Sharti switch (curr_op) { 452154133Sharti 453154133Sharti case SNMP_OP_GETNEXT: 454154133Sharti if ((entry = NEXT_OBJECT_INT(&swins_tbl, 455154133Sharti &value->var, sub)) == NULL) 456154133Sharti return (SNMP_ERR_NOSUCHNAME); 457154133Sharti value->var.len = sub + 1; 458154133Sharti value->var.subs[sub] = entry->index; 459154133Sharti goto get; 460154133Sharti 461154133Sharti case SNMP_OP_GET: 462154133Sharti if ((entry = FIND_OBJECT_INT(&swins_tbl, 463154133Sharti &value->var, sub)) == NULL) 464154133Sharti return (SNMP_ERR_NOSUCHNAME); 465154133Sharti goto get; 466154133Sharti 467154133Sharti case SNMP_OP_SET: 468154133Sharti if ((entry = FIND_OBJECT_INT(&swins_tbl, 469154133Sharti &value->var, sub)) == NULL) 470154133Sharti return (SNMP_ERR_NO_CREATION); 471154133Sharti return (SNMP_ERR_NOT_WRITEABLE); 472154133Sharti 473154133Sharti case SNMP_OP_ROLLBACK: 474154133Sharti case SNMP_OP_COMMIT: 475160341Sharti abort(); 476154133Sharti } 477154133Sharti abort(); 478154133Sharti 479154133Sharti get: 480154133Sharti switch (value->var.subs[sub - 1]) { 481154133Sharti 482154133Sharti case LEAF_hrSWInstalledIndex: 483154133Sharti value->v.integer = entry->index; 484154133Sharti return (SNMP_ERR_NOERROR); 485154133Sharti 486154133Sharti case LEAF_hrSWInstalledName: 487160341Sharti return (string_get(value, entry->name, -1)); 488160341Sharti break; 489154133Sharti 490160341Sharti case LEAF_hrSWInstalledID: 491160341Sharti assert(entry->id != NULL); 492160341Sharti value->v.oid = *entry->id; 493160341Sharti return (SNMP_ERR_NOERROR); 494154133Sharti 495154133Sharti case LEAF_hrSWInstalledType: 496160341Sharti value->v.integer = entry->type; 497160341Sharti return (SNMP_ERR_NOERROR); 498154133Sharti 499154133Sharti case LEAF_hrSWInstalledDate: 500154133Sharti return (string_get(value, entry->date, entry->date_len)); 501154133Sharti } 502154133Sharti abort(); 503154133Sharti} 504154133Sharti 505154133Sharti/** 506154133Sharti * Scalars 507154133Sharti */ 508154133Shartiint 509154133Shartiop_hrSWInstalled(struct snmp_context *ctx __unused, 510154133Sharti struct snmp_value *value __unused, u_int sub, 511154133Sharti u_int iidx __unused, enum snmp_op curr_op) 512154133Sharti{ 513154133Sharti 514154133Sharti /* only SNMP GET is possible */ 515154133Sharti switch (curr_op) { 516154133Sharti 517154133Sharti case SNMP_OP_GET: 518154133Sharti goto get; 519154133Sharti 520154133Sharti case SNMP_OP_SET: 521154133Sharti return (SNMP_ERR_NOT_WRITEABLE); 522154133Sharti 523154133Sharti case SNMP_OP_ROLLBACK: 524154133Sharti case SNMP_OP_COMMIT: 525154133Sharti case SNMP_OP_GETNEXT: 526154133Sharti abort(); 527154133Sharti } 528154133Sharti abort(); 529154133Sharti 530154133Sharti get: 531154133Sharti switch (value->var.subs[sub - 1]) { 532154133Sharti 533154133Sharti case LEAF_hrSWInstalledLastChange: 534154133Sharti case LEAF_hrSWInstalledLastUpdateTime: 535154133Sharti /* 536154133Sharti * We always update the entire table so these two tick 537154133Sharti * values should be equal. 538154133Sharti */ 539154133Sharti refresh_swins_tbl(); 540154133Sharti if (swins_tick <= start_tick) 541154133Sharti value->v.uint32 = 0; 542154133Sharti else { 543154133Sharti uint64_t lastChange = swins_tick - start_tick; 544154133Sharti 545154133Sharti /* may overflow the SNMP type */ 546154133Sharti value->v.uint32 = 547154133Sharti (lastChange > UINT_MAX ? UINT_MAX : lastChange); 548154133Sharti } 549154133Sharti 550154133Sharti return (SNMP_ERR_NOERROR); 551154133Sharti 552154133Sharti default: 553154133Sharti abort(); 554154133Sharti } 555154133Sharti} 556