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