summaryrefslogtreecommitdiffstats
path: root/usr.sbin/bsnmpd
diff options
context:
space:
mode:
authorharti <harti@FreeBSD.org>2006-01-09 12:33:45 +0000
committerharti <harti@FreeBSD.org>2006-01-09 12:33:45 +0000
commitaa4781a69e915cdc271b128fbccbfbbb7e90cfd6 (patch)
treee4a5220ecaf69631898484bfe7f2fe014a4775ec /usr.sbin/bsnmpd
parente318c6bf192ab12e966e1c9ed16504fa3bc5e0be (diff)
downloadFreeBSD-src-aa4781a69e915cdc271b128fbccbfbbb7e90cfd6.zip
FreeBSD-src-aa4781a69e915cdc271b128fbccbfbbb7e90cfd6.tar.gz
msg
Diffstat (limited to 'usr.sbin/bsnmpd')
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_hostres/BEGEMOT-HOSTRES-MIB.txt125
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_hostres/Makefile82
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_hostres/hostres_begemot.c171
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_hostres/hostres_device_tbl.c612
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_hostres/hostres_diskstorage_tbl.c626
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_hostres/hostres_fs_tbl.c440
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_hostres/hostres_network_tbl.c302
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_hostres/hostres_partition_tbl.c415
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_hostres/hostres_printer_tbl.c398
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_hostres/hostres_processor_tbl.c506
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_hostres/hostres_scalars.c514
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_hostres/hostres_snmp.c209
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_hostres/hostres_snmp.h301
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_hostres/hostres_storage_tbl.c648
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_hostres/hostres_swinstalled_tbl.c528
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_hostres/hostres_swrun_tbl.c751
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_hostres/hostres_tree.def292
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_hostres/snmp_hostres.385
18 files changed, 7005 insertions, 0 deletions
diff --git a/usr.sbin/bsnmpd/modules/snmp_hostres/BEGEMOT-HOSTRES-MIB.txt b/usr.sbin/bsnmpd/modules/snmp_hostres/BEGEMOT-HOSTRES-MIB.txt
new file mode 100644
index 0000000..ee8d284
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_hostres/BEGEMOT-HOSTRES-MIB.txt
@@ -0,0 +1,125 @@
+--
+-- Copyright (c) 2005-2006
+-- Hartmut Brandt
+-- All rights reserved.
+--
+-- Author: Harti Brandt <harti@freebsd.org>
+--
+-- Redistribution and use in source and binary forms, with or without
+-- modification, are permitted provided that the following conditions
+-- are met:
+-- 1. Redistributions of source code must retain the above copyright
+-- notice, this list of conditions and the following disclaimer.
+-- 2. Redistributions in binary form must reproduce the above copyright
+-- notice, this list of conditions and the following disclaimer in the
+-- documentation and/or other materials provided with the distribution.
+--
+-- THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+-- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+-- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+-- ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+-- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+-- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+-- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+-- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+-- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+-- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+-- SUCH DAMAGE.
+--
+-- $FreeBSD$
+--
+-- Additional stuff for the HOST-RESOURCES MIB.
+--
+BEGEMOT-HOSTRES-MIB DEFINITIONS ::= BEGIN
+
+IMPORTS
+ MODULE-IDENTITY, OBJECT-TYPE, TimeTicks
+ FROM SNMPv2-SMI
+ begemot
+ FROM BEGEMOT-MIB;
+
+begemotHostres MODULE-IDENTITY
+ LAST-UPDATED "200601030000Z"
+ ORGANIZATION "German Aerospace Center"
+ CONTACT-INFO
+ " Hartmut Brandt
+
+ Postal: German Aerospace Center
+ Oberpfaffenhofen
+ 82234 Wessling
+ Germany
+
+ Fax: +49 8153 28 2843
+
+ E-mail: harti@freebsd.org"
+ DESCRIPTION
+ "The MIB for additional HOST-RESOURCES data."
+ ::= { begemot 202 }
+
+begemotHostresObjects OBJECT IDENTIFIER ::= { begemotHostres 1 }
+
+begemotHrStorageUpdate OBJECT-TYPE
+ SYNTAX TimeTicks
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The maximum number of ticks the storage table is cached."
+ DEFVAL { 700 }
+ ::= { begemotHostresObjects 1 }
+
+begemotHrFSUpdate OBJECT-TYPE
+ SYNTAX TimeTicks
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The maximum number of ticks the FS table is cached."
+ DEFVAL { 700 }
+ ::= { begemotHostresObjects 2 }
+
+begemotHrDiskStorageUpdate OBJECT-TYPE
+ SYNTAX TimeTicks
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The maximum number of ticks the disk storage table is cached."
+ DEFVAL { 300 }
+ ::= { begemotHostresObjects 3 }
+
+begemotHrNetworkUpdate OBJECT-TYPE
+ SYNTAX TimeTicks
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The maximum number of ticks the network table is cached."
+ DEFVAL { 700 }
+ ::= { begemotHostresObjects 4 }
+
+begemotHrSWInstalledUpdate OBJECT-TYPE
+ SYNTAX TimeTicks
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The maximum number of ticks the hrSWInstalledTable is cached."
+ DEFVAL { 1200 }
+ ::= { begemotHostresObjects 5 }
+
+begemotHrSWRunUpdate OBJECT-TYPE
+ SYNTAX TimeTicks
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The maximum number of ticks the hrSWRunTable and
+ hrSWRunPerfTable are cached."
+ DEFVAL { 300 }
+ ::= { begemotHostresObjects 6 }
+
+begemotHrPkgDir OBJECT-TYPE
+ SYNTAX OCTET STRING
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The path to the package DB directory."
+ DEFVAL { "/var/db/pkg" }
+ ::= { begemotHostresObjects 7 }
+
+END
diff --git a/usr.sbin/bsnmpd/modules/snmp_hostres/Makefile b/usr.sbin/bsnmpd/modules/snmp_hostres/Makefile
new file mode 100644
index 0000000..475ad99
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_hostres/Makefile
@@ -0,0 +1,82 @@
+#
+# Copyright (c) 2005-2006 The FreeBSD Project
+# All rights reserved.
+# Author: Victor Cruceru <soc-victor@freebsd.org>
+#
+# Redistribution of this software and documentation and use in source and
+# binary forms, with or without modification, are permitted provided that
+# the following conditions are met:
+#
+# 1. Redistributions of source code or documentation must retain the above
+# copyright notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+#
+
+LPRSRC= ${.CURDIR}/../../../lpr/common_source
+.PATH: ${LPRSRC}
+
+MOD= hostres
+SRCS= hostres_begemot.c \
+ hostres_device_tbl.c \
+ hostres_diskstorage_tbl.c \
+ hostres_fs_tbl.c \
+ hostres_network_tbl.c \
+ hostres_partition_tbl.c \
+ hostres_printer_tbl.c \
+ hostres_processor_tbl.c \
+ hostres_scalars.c \
+ hostres_snmp.c \
+ hostres_storage_tbl.c \
+ hostres_swinstalled_tbl.c \
+ hostres_swrun_tbl.c \
+ printcap.c
+
+#Not having NDEBUG defined will enable assertions and a lot of output on stderr
+CFLAGS+= -DNDEBUG -I${LPRSRC}
+XSYM= host hrStorageOther hrStorageRam hrStorageVirtualMemory \
+ hrStorageFixedDisk hrStorageRemovableDisk hrStorageFloppyDisk \
+ hrStorageCompactDisc hrStorageRamDisk hrStorageFlashMemory \
+ hrStorageNetworkDisk hrDeviceOther hrDeviceUnknown \
+ hrDeviceProcessor hrDeviceNetwork hrDevicePrinter \
+ hrDeviceDiskStorage hrDeviceVideo hrDeviceAudio \
+ hrDeviceCoprocessor hrDeviceKeyboard hrDeviceModem \
+ hrDeviceParallelPort hrDevicePointing \
+ hrDeviceSerialPort hrDeviceTape hrDeviceClock \
+ hrDeviceVolatileMemory hrDeviceNonVolatileMemory \
+ hrFSOther hrFSUnknown hrFSBerkeleyFFS hrFSSys5FS hrFSFat\
+ hrFSHPFS hrFSHFS hrFSMFS hrFSNTFS hrFSVNode hrFSJournaled \
+ hrFSiso9660 hrFSRockRidge hrFSNFS hrFSNetware hrFSAFS hrFSDFS \
+ hrFSAppleshare hrFSRFS hrFSDGCFS hrFSBFS hrFSFAT32 hrFSLinuxExt2
+
+MAN= snmp_hostres.3
+
+DEFS= ${MOD}_tree.def
+BMIBS= BEGEMOT-HOSTRES-MIB.txt
+
+DPADD= ${LIBKVM} ${LIBDEVINFO} ${LIBM} ${LIBDISK} ${LIBMEMSTAT}
+LDADD= -lkvm -ldevinfo -lm -ldisk -lmemstat
+
+.include <bsd.snmpmod.mk>
+
+printcap.So: printcap.c
+ ${CC} ${PICFLAG} -DPIC ${CFLAGS:C/^-W.*//} -c ${.IMPSRC} -o ${.TARGET}
+
+smilint:
+ env SMIPATH=.:/usr/share/snmp/mibs:/usr/local/share/snmp/mibs \
+ smilint -c /dev/null -l6 -i group-membership BEGEMOT-HOSTRES-MIB
diff --git a/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_begemot.c b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_begemot.c
new file mode 100644
index 0000000..f1cc5e3
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_begemot.c
@@ -0,0 +1,171 @@
+/*-
+ * Copyright (c) 2005-2006.
+ * Hartmut Brandt.
+ * All rights reserved.
+ *
+ * Author: Hartmut Brandt <harti@freebsd.org>
+ *
+ * Redistribution of this software and documentation and use in source and
+ * binary forms, with or without modification, are permitted provided that
+ * the following conditions are met:
+ *
+ * 1. Redistributions of source code or documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <stdlib.h>
+
+#include "hostres_snmp.h"
+#include "hostres_oid.h"
+#include "hostres_tree.h"
+
+int
+op_begemot(struct snmp_context *ctx, struct snmp_value *value,
+ u_int sub, u_int iidx __unused, enum snmp_op op)
+{
+
+ switch (op) {
+
+ case SNMP_OP_GET:
+ switch (value->var.subs[sub - 1]) {
+
+ case LEAF_begemotHrStorageUpdate:
+ value->v.uint32 = storage_tbl_refresh;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotHrFSUpdate:
+ value->v.uint32 = fs_tbl_refresh;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotHrDiskStorageUpdate:
+ value->v.uint32 = disk_storage_tbl_refresh;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotHrNetworkUpdate:
+ value->v.uint32 = network_tbl_refresh;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotHrSWInstalledUpdate:
+ value->v.uint32 = swins_tbl_refresh;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotHrSWRunUpdate:
+ value->v.uint32 = swrun_tbl_refresh;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotHrPkgDir:
+ return (string_get(value, pkg_dir, -1));
+ }
+ abort();
+
+ case SNMP_OP_GETNEXT:
+ abort();
+
+ case SNMP_OP_SET:
+ switch (value->var.subs[sub - 1]) {
+
+ case LEAF_begemotHrStorageUpdate:
+ ctx->scratch->int1 = storage_tbl_refresh;
+ storage_tbl_refresh = value->v.uint32;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotHrFSUpdate:
+ ctx->scratch->int1 = fs_tbl_refresh;
+ fs_tbl_refresh = value->v.uint32;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotHrDiskStorageUpdate:
+ ctx->scratch->int1 = disk_storage_tbl_refresh;
+ disk_storage_tbl_refresh = value->v.uint32;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotHrNetworkUpdate:
+ ctx->scratch->int1 = network_tbl_refresh;
+ network_tbl_refresh = value->v.uint32;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotHrSWInstalledUpdate:
+ ctx->scratch->int1 = swins_tbl_refresh;
+ swins_tbl_refresh = value->v.uint32;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotHrSWRunUpdate:
+ ctx->scratch->int1 = swrun_tbl_refresh;
+ swrun_tbl_refresh = value->v.uint32;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotHrPkgDir:
+ return (string_save(value, ctx, -1, &pkg_dir));
+ }
+ abort();
+
+ case SNMP_OP_COMMIT:
+ switch (value->var.subs[sub - 1]) {
+
+ case LEAF_begemotHrStorageUpdate:
+ case LEAF_begemotHrFSUpdate:
+ case LEAF_begemotHrDiskStorageUpdate:
+ case LEAF_begemotHrNetworkUpdate:
+ case LEAF_begemotHrSWInstalledUpdate:
+ case LEAF_begemotHrSWRunUpdate:
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotHrPkgDir:
+ string_commit(ctx);
+ return (SNMP_ERR_NOERROR);
+ }
+ abort();
+
+ case SNMP_OP_ROLLBACK:
+ switch (value->var.subs[sub - 1]) {
+
+ case LEAF_begemotHrStorageUpdate:
+ storage_tbl_refresh = ctx->scratch->int1;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotHrFSUpdate:
+ fs_tbl_refresh = ctx->scratch->int1;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotHrDiskStorageUpdate:
+ disk_storage_tbl_refresh = ctx->scratch->int1;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotHrNetworkUpdate:
+ network_tbl_refresh = ctx->scratch->int1;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotHrSWInstalledUpdate:
+ swins_tbl_refresh = ctx->scratch->int1;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotHrSWRunUpdate:
+ swrun_tbl_refresh = ctx->scratch->int1;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotHrPkgDir:
+ string_rollback(ctx, &pkg_dir);
+ return (SNMP_ERR_NOERROR);
+ }
+ abort();
+ }
+
+ abort();
+}
diff --git a/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_device_tbl.c b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_device_tbl.c
new file mode 100644
index 0000000..eb1ad91
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_device_tbl.c
@@ -0,0 +1,612 @@
+ /*-
+ * Copyright (c) 2005-2006 The FreeBSD Project
+ * All rights reserved.
+ *
+ * Author: Victor Cruceru <soc-victor@freebsd.org>
+ *
+ * Redistribution of this software and documentation and use in source and
+ * binary forms, with or without modification, are permitted provided that
+ * the following conditions are met:
+ *
+ * 1. Redistributions of source code or documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Host Resources MIB: hrDeviceTable implementation for SNMPd.
+ */
+
+#include <sys/un.h>
+#include <sys/limits.h>
+
+#include <assert.h>
+#include <err.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include "hostres_snmp.h"
+#include "hostres_oid.h"
+#include "hostres_tree.h"
+
+/*
+ * Status of a device
+ */
+enum DeviceStatus {
+ DS_UNKNOWN = 1,
+ DS_RUNNING = 2,
+ DS_WARNING = 3,
+ DS_TESTING = 4,
+ DS_DOWN = 5
+};
+
+TAILQ_HEAD(device_tbl, device_entry);
+
+/* the head of the list with hrDeviceTable's entries */
+static struct device_tbl device_tbl = TAILQ_HEAD_INITIALIZER(device_tbl);
+
+/* Table used for consistent device table indexing. */
+struct device_map device_map = STAILQ_HEAD_INITIALIZER(device_map);
+
+/* next int available for indexing the hrDeviceTable */
+static uint32_t next_device_index = 1;
+
+/* last (agent) tick when hrDeviceTable was updated */
+static uint64_t device_tick = 0;
+
+/* maximum number of ticks between updates of device table */
+uint32_t device_tbl_refresh = 10 * 100;
+
+/* socket for /var/run/devd.pipe */
+static int devd_sock = -1;
+
+/* used to wait notifications from /var/run/devd.pipe */
+static void *devd_fd;
+
+/* some constants */
+static const struct asn_oid OIDX_hrDeviceProcessor_c = OIDX_hrDeviceProcessor;
+static const struct asn_oid OIDX_hrDeviceOther_c = OIDX_hrDeviceOther;
+
+/**
+ * Create a new entry out of thin air.
+ */
+struct device_entry *
+device_entry_create(const char *name, const char *location, const char *descr)
+{
+ struct device_entry *entry;
+ struct device_map_entry *map;
+
+ assert((name[0] != 0) || (location[0] != 0));
+
+ if (name[0] == 0 && location[0] == 0)
+ return (NULL);
+
+ if ((entry = malloc(sizeof(*entry))) == NULL) {
+ syslog(LOG_WARNING, "hrDeviceTable: %s: %m", __func__);
+ return (NULL);
+ }
+ memset(entry, 0, sizeof(*entry));
+
+ STAILQ_FOREACH(map, &device_map, link)
+ if (strcmp(map->name_key, name) == 0 &&
+ strcmp(map->location_key, location) == 0) {
+ entry->index = map->hrIndex;
+ map->entry_p = entry;
+ break;
+ }
+
+ if (map == NULL) {
+ /* new object - get a new index */
+ if (next_device_index > INT_MAX) {
+ syslog(LOG_ERR,
+ "%s: hrDeviceTable index wrap", __func__);
+ free(entry);
+ return (NULL);
+ }
+
+ if ((map = malloc(sizeof(*map))) == NULL) {
+ syslog(LOG_ERR, "hrDeviceTable: %s: %m", __func__ );
+ free(entry);
+ return (NULL);
+ }
+
+ map->hrIndex = next_device_index++;
+
+ strlcpy(map->name_key, name, sizeof(map->name_key));
+ strlcpy(map->location_key, location, sizeof(map->location_key));
+
+ map->entry_p = entry;
+
+ STAILQ_INSERT_TAIL(&device_map, map, link);
+ HRDBG("%s at %s added into hrDeviceMap at index=%d",
+ name, location, map->hrIndex);
+ } else {
+ HRDBG("%s at %s exists in hrDeviceMap index=%d",
+ name, location, map->hrIndex);
+ }
+
+ entry->index = map->hrIndex;
+
+ strlcpy(entry->name, name, sizeof(entry->name));
+ strlcpy(entry->location, location, sizeof(entry->location));
+
+ if (name[0] != '\0')
+ snprintf(entry->descr, sizeof(entry->descr), "%s: %s",
+ name, descr);
+ else
+ snprintf(entry->descr, sizeof(entry->descr),
+ "unknown at %s: %s", location, descr);
+
+ entry->id = oid_zeroDotZero; /* unknown id - FIXME */
+ entry->status = (u_int)DIS_ATTACHED;
+ entry->errors = 0;
+ entry->type = OIDX_hrDeviceOther_c;
+
+ INSERT_OBJECT_INT(entry, &device_tbl);
+
+ return (entry);
+}
+
+/**
+ * Create a new entry into the device table.
+ */
+static struct device_entry *
+device_entry_create_devinfo(const struct devinfo_dev *dev_p)
+{
+
+ assert(dev_p->dd_name != NULL);
+ assert(dev_p->dd_location != NULL);
+
+ return (device_entry_create(dev_p->dd_name, dev_p->dd_location,
+ dev_p->dd_desc));
+}
+
+/**
+ * Delete an entry from the device table.
+ */
+static void
+device_entry_delete(struct device_entry *entry)
+{
+ struct device_map_entry *map;
+
+ assert(entry != NULL);
+
+ TAILQ_REMOVE(&device_tbl, entry, link);
+
+ STAILQ_FOREACH(map, &device_map, link)
+ if (map->entry_p == entry) {
+ map->entry_p = NULL;
+ break;
+ }
+ free(entry);
+}
+
+/**
+ * Find an entry given its name and location
+ */
+static struct device_entry *
+device_find_by_dev(const struct devinfo_dev *dev_p)
+{
+ struct device_map_entry *map;
+
+ assert(dev_p != NULL);
+
+ STAILQ_FOREACH(map, &device_map, link)
+ if (strcmp(map->name_key, dev_p->dd_name) == 0 &&
+ strcmp(map->location_key, dev_p->dd_location) == 0)
+ return (map->entry_p);
+ return (NULL);
+}
+
+/**
+ * Find an entry given its index.
+ */
+struct device_entry *
+device_find_by_index(int32_t idx)
+{
+ struct device_entry *entry;
+
+ TAILQ_FOREACH(entry, &device_tbl, link)
+ if (entry->index == idx)
+ return (entry);
+ return (NULL);
+}
+
+/**
+ * Find an device entry given its name.
+ */
+struct device_entry *
+device_find_by_name(const char *dev_name)
+{
+ struct device_map_entry *map;
+
+ assert(dev_name != NULL);
+
+ STAILQ_FOREACH(map, &device_map, link)
+ if (strcmp(map->name_key, dev_name) == 0)
+ return (map->entry_p);
+
+ return (NULL);
+}
+
+/**
+ * Find out the type of device. CPU only currently.
+ */
+static void
+device_get_type(struct devinfo_dev *dev_p, struct asn_oid *out_type_p)
+{
+
+ assert(dev_p != NULL);
+ assert(out_type_p != NULL);
+
+ if (dev_p == NULL)
+ return;
+
+ if (strncmp(dev_p->dd_name, "cpu", strlen("cpu")) == 0 &&
+ strstr(dev_p->dd_location, ".CPU") != NULL) {
+ *out_type_p = OIDX_hrDeviceProcessor_c;
+ return;
+ }
+}
+
+/**
+ * Get the status of a device
+ */
+static enum DeviceStatus
+device_get_status(struct devinfo_dev *dev)
+{
+
+ assert(dev != NULL);
+
+ switch (dev->dd_state) {
+ case DIS_ALIVE: /* probe succeeded */
+ case DIS_NOTPRESENT: /* not probed or probe failed */
+ return (DS_DOWN);
+ case DIS_ATTACHED: /* attach method called */
+ case DIS_BUSY: /* device is open */
+ return (DS_RUNNING);
+ default:
+ return (DS_UNKNOWN);
+ }
+}
+
+/**
+ * Get the info for the given device and then recursively process all
+ * child devices.
+ */
+static int
+device_collector(struct devinfo_dev *dev, void *arg)
+{
+ struct device_entry *entry;
+
+ HRDBG("%llu/%llu name='%s' desc='%s' drivername='%s' location='%s'",
+ (unsigned long long)dev->dd_handle,
+ (unsigned long long)dev->dd_parent, dev->dd_name, dev->dd_desc,
+ dev->dd_drivername, dev->dd_location);
+
+ if (dev->dd_name[0] != '\0' || dev->dd_location[0] != '\0') {
+ HRDBG("ANALYZING dev %s at %s",
+ dev->dd_name, dev->dd_location);
+
+ if ((entry = device_find_by_dev(dev)) != NULL) {
+ entry->flags |= HR_DEVICE_FOUND;
+ entry->status = (u_int)device_get_status(dev);
+ } else if ((entry = device_entry_create_devinfo(dev)) != NULL) {
+ device_get_type(dev, &entry->type);
+
+ entry->flags |= HR_DEVICE_FOUND;
+ entry->status = (u_int)device_get_status(dev);
+ }
+ } else {
+ HRDBG("SKIPPED unknown device at location '%s'",
+ dev->dd_location );
+ }
+
+ return (devinfo_foreach_device_child(dev, device_collector, arg));
+}
+
+/**
+ * Create the socket to the device daemon.
+ */
+static int
+create_devd_socket(void)
+{
+ int d_sock;
+ struct sockaddr_un devd_addr;
+
+ bzero(&devd_addr, sizeof(struct sockaddr_un));
+
+ if ((d_sock = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) {
+ syslog(LOG_ERR, "Failed to create the socket for %s: %m",
+ PATH_DEVD_PIPE);
+ return (-1);
+ }
+
+ devd_addr.sun_family = PF_LOCAL;
+ devd_addr.sun_len = sizeof(devd_addr);
+ strlcpy(devd_addr.sun_path, PATH_DEVD_PIPE,
+ sizeof(devd_addr.sun_path) - 1);
+
+ if (connect(d_sock, (struct sockaddr *)&devd_addr,
+ sizeof(devd_addr)) == -1) {
+ syslog(LOG_ERR,"Failed to connect socket for %s: %m",
+ PATH_DEVD_PIPE);
+ if (close(d_sock) < 0 )
+ syslog(LOG_ERR,"Failed to close socket for %s: %m",
+ PATH_DEVD_PIPE);
+ return (-1);
+ }
+
+ return (d_sock);
+}
+
+/*
+ * Event on the devd socket.
+ **
+ * We should probably directly process entries here. For simplicity just
+ * call the refresh routine with the force flag for now.
+ */
+static void
+devd_socket_callback(int fd, void *arg __unused)
+{
+ char buf[512];
+ int read_len = -1;
+
+ assert(fd == devd_sock);
+
+ HRDBG("called");
+
+ read_len = read(fd, buf, sizeof(buf) - 1);
+ if (read_len < 0) {
+ if (errno == EBADF) {
+ devd_sock = -1;
+ if (devd_fd != NULL) {
+ fd_deselect(devd_fd);
+ devd_fd = NULL;
+ }
+ syslog(LOG_ERR, "Closing devd_fd, revert to "
+ "devinfo polling");
+ }
+
+ } else if (read_len == 0) {
+ syslog(LOG_ERR, "zero bytes read from devd pipe... "
+ "closing socket!");
+
+ if (close(devd_sock) < 0 )
+ syslog(LOG_ERR, "Failed to close devd socket: %m");
+
+ devd_sock = -1;
+ if (devd_fd != NULL) {
+ fd_deselect(devd_fd);
+ devd_fd = NULL;
+ }
+ syslog(LOG_ERR, "Closing devd_fd, revert to devinfo polling");
+
+ } else {
+ switch (buf[0]) {
+ case '+':
+ case '-':
+ case '?':
+ refresh_device_tbl(1);
+ return;
+ default:
+ syslog(LOG_ERR, "unknown message from devd socket");
+ }
+ }
+}
+
+/**
+ * Initialize and populate the device table.
+ */
+void
+init_device_tbl(void)
+{
+
+ /* initially populate table for the other tables */
+ refresh_device_tbl(1);
+
+ /* no problem if that fails - just use polling mode */
+ devd_sock = create_devd_socket();
+}
+
+/**
+ * Start devd(8) monitoring.
+ */
+void
+start_device_tbl(struct lmodule *mod)
+{
+
+ if (devd_sock > 0) {
+ devd_fd = fd_select(devd_sock, devd_socket_callback, NULL, mod);
+ if (devd_fd == NULL)
+ syslog(LOG_ERR, "fd_select failed on devd socket: %m");
+ }
+}
+
+/**
+ * Finalization routine for hrDeviceTable
+ * It destroys the lists and frees any allocated heap memory
+ */
+void
+fini_device_tbl(void)
+{
+ struct device_map_entry *n1;
+
+ if (devd_fd != NULL)
+ fd_deselect(devd_fd);
+
+ if (devd_sock != -1)
+ (void)close(devd_sock);
+
+ devinfo_free();
+
+ while ((n1 = STAILQ_FIRST(&device_map)) != NULL) {
+ STAILQ_REMOVE_HEAD(&device_map, link);
+ if (n1->entry_p != NULL) {
+ TAILQ_REMOVE(&device_tbl, n1->entry_p, link);
+ free(n1->entry_p);
+ }
+ free(n1);
+ }
+ assert(TAILQ_EMPTY(&device_tbl));
+}
+
+/**
+ * Refresh routine for hrDeviceTable. We don't refresh here if the devd socket
+ * is open, because in this case we have the actual information always. We
+ * also don't refresh when the table is new enough (if we don't have a devd
+ * socket). In either case a refresh can be forced by passing a non-zero value.
+ */
+void
+refresh_device_tbl(int force)
+{
+ struct device_entry *entry, *entry_tmp;
+ struct devinfo_dev *dev_root;
+ static int act = 0;
+
+ if (!force && (devd_sock >= 0 ||
+ (device_tick != 0 && this_tick - device_tick < device_tbl_refresh))){
+ HRDBG("no refresh needed");
+ return;
+ }
+
+ if (act) {
+ syslog(LOG_ERR, "%s: recursive call", __func__);
+ return;
+ }
+
+ if (devinfo_init() != 0) {
+ syslog(LOG_ERR,"%s: devinfo_init failed: %m", __func__);
+ return;
+ }
+
+ act = 1;
+ if ((dev_root = devinfo_handle_to_device(DEVINFO_ROOT_DEVICE)) == NULL){
+ syslog(LOG_ERR, "%s: can't get the root device: %m", __func__);
+ goto out;
+ }
+
+ /* mark each entry as missing */
+ TAILQ_FOREACH(entry, &device_tbl, link)
+ entry->flags &= ~HR_DEVICE_FOUND;
+
+ if (devinfo_foreach_device_child(dev_root, device_collector, NULL))
+ syslog(LOG_ERR, "%s: devinfo_foreach_device_child failed",
+ __func__);
+
+ /*
+ * Purge items that disappeared
+ */
+ TAILQ_FOREACH_SAFE(entry, &device_tbl, link, entry_tmp) {
+ /*
+ * If HR_DEVICE_IMMUTABLE bit is set then this means that
+ * this entry was not detected by the above
+ * devinfo_foreach_device() call. So we are not deleting
+ * it there.
+ */
+ if (!(entry->flags & HR_DEVICE_FOUND) &&
+ !(entry->flags & HR_DEVICE_IMMUTABLE))
+ device_entry_delete(entry);
+ }
+
+ device_tick = this_tick;
+
+ /*
+ * Force a refresh for the hrDiskStorageTable
+ * XXX Why not the other dependen tables?
+ */
+ refresh_disk_storage_tbl(1);
+
+ out:
+ devinfo_free();
+ act = 0;
+}
+
+/**
+ * This is the implementation for a generated (by a SNMP tool)
+ * function prototype, see hostres_tree.h
+ * It handles the SNMP operations for hrDeviceTable
+ */
+int
+op_hrDeviceTable(struct snmp_context *ctx __unused, struct snmp_value *value,
+ u_int sub, u_int iidx __unused, enum snmp_op curr_op)
+{
+ struct device_entry *entry;
+
+ refresh_device_tbl(0);
+
+ switch (curr_op) {
+
+ case SNMP_OP_GETNEXT:
+ if ((entry = NEXT_OBJECT_INT(&device_tbl,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ value->var.len = sub + 1;
+ value->var.subs[sub] = entry->index;
+ goto get;
+
+ case SNMP_OP_GET:
+ if ((entry = FIND_OBJECT_INT(&device_tbl,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ goto get;
+
+ case SNMP_OP_SET:
+ if ((entry = FIND_OBJECT_INT(&device_tbl,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NO_CREATION);
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ case SNMP_OP_ROLLBACK:
+ case SNMP_OP_COMMIT:
+ abort();
+ }
+ abort();
+
+ get:
+ switch (value->var.subs[sub - 1]) {
+
+ case LEAF_hrDeviceIndex:
+ value->v.integer = entry->index;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrDeviceType:
+ value->v.oid = entry->type;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrDeviceDescr:
+ return (string_get(value, entry->descr, -1));
+
+ case LEAF_hrDeviceID:
+ value->v.oid = entry->id;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrDeviceStatus:
+ value->v.integer = entry->status;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrDeviceErrors:
+ value->v.uint32 = entry->errors;
+ return (SNMP_ERR_NOERROR);
+ }
+ abort();
+}
diff --git a/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_diskstorage_tbl.c b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_diskstorage_tbl.c
new file mode 100644
index 0000000..e3d33a0
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_diskstorage_tbl.c
@@ -0,0 +1,626 @@
+/*-
+ * Copyright (c) 2005-2006 The FreeBSD Project
+ * All rights reserved.
+ *
+ * Author: Victor Cruceru <soc-victor@freebsd.org>
+ *
+ * Redistribution of this software and documentation and use in source and
+ * binary forms, with or without modification, are permitted provided that
+ * the following conditions are met:
+ *
+ * 1. Redistributions of source code or documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Host Resources MIB for SNMPd. Implementation for the hrDiskStorageTable
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/ata.h>
+#include <sys/disk.h>
+#include <sys/linker.h>
+#include <sys/mdioctl.h>
+#include <sys/module.h>
+#include <sys/sysctl.h>
+
+#include <assert.h>
+#include <err.h>
+#include <errno.h>
+#include <paths.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include "hostres_snmp.h"
+#include "hostres_oid.h"
+#include "hostres_tree.h"
+
+enum hrDiskStrorageAccess {
+ DS_READ_WRITE = 1,
+ DS_READ_ONLY = 2
+};
+
+enum hrDiskStrorageMedia {
+ DSM_OTHER = 1,
+ DSM_UNKNOWN = 2,
+ DSM_HARDDISK = 3,
+ DSM_FLOPPYDISK = 4,
+ DSM_OPTICALDISKROM= 5,
+ DSM_OPTICALDISKWORM= 6,
+ DSM_OPTICALDISKRW= 7,
+ DSM_RAMDISK = 8
+};
+
+/*
+ * This structure is used to hold a SNMP table entry for HOST-RESOURCES-MIB's
+ * hrDiskStorageTable. Note that index is external being allocated and
+ * maintained by the hrDeviceTable code.
+ *
+ * NOTE: according to MIB removable means removable media, not the
+ * device itself (like a USB card reader)
+ */
+struct disk_entry {
+ int32_t index;
+ int32_t access; /* enum hrDiskStrorageAccess */
+ int32_t media; /* enum hrDiskStrorageMedia*/
+ int32_t removable; /* enum snmpTCTruthValue*/
+ int32_t capacity;
+ TAILQ_ENTRY(disk_entry) link;
+ /*
+ * next items are not from the SNMP mib table, only to be used
+ * internally
+ */
+#define HR_DISKSTORAGE_FOUND 0x001
+#define HR_DISKSTORAGE_ATA 0x002 /* belongs to the ATA subsystem */
+#define HR_DISKSTORAGE_MD 0x004 /* it is a MD (memory disk) */
+ uint32_t flags;
+ uint64_t r_tick;
+ u_char dev_name[32]; /* device name, i.e. "ad4" or "acd0" */
+};
+TAILQ_HEAD(disk_tbl, disk_entry);
+
+/* the head of the list with hrDiskStorageTable's entries */
+static struct disk_tbl disk_tbl =
+ TAILQ_HEAD_INITIALIZER(disk_tbl);
+
+/* last tick when hrFSTable was updated */
+static uint64_t disk_storage_tick;
+
+/* minimum number of ticks between refreshs */
+uint32_t disk_storage_tbl_refresh = HR_DISK_TBL_REFRESH * 100;
+
+/* fd for "/dev/mdctl"*/
+static int md_fd = -1;
+
+/* buffer for sysctl("kern.disks") */
+static char *disk_list;
+static size_t disk_list_len;
+
+/* some constants */
+static const struct asn_oid OIDX_hrDeviceDiskStorage_c =
+ OIDX_hrDeviceDiskStorage;
+
+/**
+ * Load the MD driver if it isn't loaded already.
+ */
+static void
+mdmaybeload(void)
+{
+ char name1[64], name2[64];
+
+ snprintf(name1, sizeof(name1), "g_%s", MD_NAME);
+ snprintf(name2, sizeof(name2), "geom_%s", MD_NAME);
+ if (modfind(name1) == -1) {
+ /* Not present in kernel, try loading it. */
+ if (kldload(name2) == -1 || modfind(name1) == -1) {
+ if (errno != EEXIST) {
+ errx(EXIT_FAILURE,
+ "%s module not available!", name2);
+ }
+ }
+ }
+}
+
+/**
+ * Create a new entry into the DiskStorageTable.
+ */
+static struct disk_entry *
+disk_entry_create(const struct device_entry *devEntry)
+{
+ struct disk_entry *entry;
+
+ assert(devEntry != NULL);
+ if (devEntry == NULL)
+ return NULL;
+
+ if ((entry = malloc(sizeof(*entry))) == NULL) {
+ syslog(LOG_WARNING, "hrDiskStorageTable: %s: %m", __func__);
+ return (NULL);
+ }
+
+ memset(entry, 0, sizeof(*entry));
+ entry->index = devEntry->index;
+ INSERT_OBJECT_INT(entry, &disk_tbl);
+
+ return (entry);
+}
+
+/**
+ * Delete a disk table entry.
+ */
+static void
+disk_entry_delete(struct disk_entry *entry)
+{
+
+ assert(entry != NULL);
+
+ TAILQ_REMOVE(&disk_tbl, entry, link);
+ free(entry);
+}
+
+/**
+ * Find a disk storage entry given its index.
+ */
+static struct disk_entry *
+disk_find_by_index(int32_t idx)
+{
+ struct disk_entry *entry;
+
+ TAILQ_FOREACH(entry, &disk_tbl, link)
+ if (entry->index == idx)
+ return (entry);
+
+ return (NULL);
+}
+
+/**
+ * Get the disk parameters
+ */
+static void
+disk_query_disk(struct disk_entry *entry)
+{
+ char dev_path[128];
+ int fd;
+ off_t mediasize;
+
+ if (entry == NULL || entry->dev_name[0] == '\0')
+ return;
+
+ snprintf(dev_path, sizeof(dev_path),
+ "%s%s", _PATH_DEV, entry->dev_name);
+ entry->capacity = 0;
+
+ HRDBG("OPENING device %s", dev_path);
+ if ((fd = open(dev_path, O_RDONLY|O_NONBLOCK)) == -1) {
+ HRDBG("OPEN device %s failed: %s", dev_path, strerror(errno));
+ return;
+ }
+
+ if (ioctl(fd, DIOCGMEDIASIZE, &mediasize) < 0) {
+ HRDBG("DIOCGMEDIASIZE for device %s failed: %s",
+ dev_path, strerror(errno));
+ (void)close(fd);
+ return;
+ }
+
+ mediasize = mediasize / 1024;
+ entry->capacity = (mediasize > INT_MAX ? INT_MAX : mediasize);
+
+ if (entry->media == DSM_HARDDISK) {
+ /* XXX libdisk crashes if a empty cdrom device is opened */
+ partition_tbl_handle_disk(entry->index, entry->dev_name);
+ }
+ (void)close(fd);
+}
+
+/**
+ * Find all ATA disks in the device table.
+ */
+static void
+disk_OS_get_ATA_disks(void)
+{
+ struct device_map_entry *map;
+ struct device_entry *entry;
+ struct disk_entry *disk_entry;
+ const struct disk_entry *found;
+
+ /* Things we know are ata disks */
+ static const struct disk_entry lookup[] = {
+ {
+ .dev_name = "ad",
+ .media = DSM_HARDDISK,
+ .removable = SNMP_FALSE
+ },
+ {
+ .dev_name = "ar",
+ .media = DSM_OTHER,
+ .removable = SNMP_FALSE
+ },
+ {
+ .dev_name = "acd",
+ .media = DSM_OPTICALDISKROM,
+ .removable = SNMP_TRUE
+ },
+ {
+ .dev_name = "afd",
+ .media = DSM_FLOPPYDISK,
+ .removable = SNMP_TRUE
+ },
+ {
+ .dev_name = "ast",
+ .media = DSM_OTHER,
+ .removable = SNMP_TRUE
+ },
+
+ { .media = DSM_UNKNOWN }
+ };
+
+ /* Walk over the device table looking for ata disks */
+ STAILQ_FOREACH(map, &device_map, link) {
+ for (found = lookup; found->media != DSM_UNKNOWN; found++) {
+ if (strncmp(map->name_key, found->dev_name,
+ strlen(found->dev_name)) != 0)
+ continue;
+
+ /* First get the entry from the hrDeviceTbl */
+ entry = map->entry_p;
+ entry->type = OIDX_hrDeviceDiskStorage_c;
+
+ /* Then check hrDiskStorage table for this device */
+ disk_entry = disk_find_by_index(entry->index);
+ if (disk_entry == NULL) {
+ disk_entry = disk_entry_create(entry);
+ if (disk_entry == NULL)
+ continue;
+
+ disk_entry->access = DS_READ_WRITE;
+ strlcpy(disk_entry->dev_name, entry->name,
+ sizeof(disk_entry->dev_name));
+
+ disk_entry->media = found->media;
+ disk_entry->removable = found->removable;
+ }
+
+ disk_entry->flags |= HR_DISKSTORAGE_FOUND;
+ disk_entry->flags |= HR_DISKSTORAGE_ATA;
+
+ disk_query_disk(disk_entry);
+ disk_entry->r_tick = this_tick;
+ }
+ }
+}
+
+/**
+ * Find MD disks in the device table.
+ */
+static void
+disk_OS_get_MD_disks(void)
+{
+ struct device_map_entry *map;
+ struct device_entry *entry;
+ struct disk_entry *disk_entry;
+ struct md_ioctl mdio;
+ int unit;
+
+ /* Look for md devices */
+ STAILQ_FOREACH(map, &device_map, link) {
+ if (sscanf(map->name_key, "md%d", &unit) != 1)
+ continue;
+
+ /* First get the entry from the hrDeviceTbl */
+ entry = device_find_by_index(map->hrIndex);
+ entry->type = OIDX_hrDeviceDiskStorage_c;
+
+ /* Then check hrDiskStorage table for this device */
+ disk_entry = disk_find_by_index(entry->index);
+ if (disk_entry == NULL) {
+ disk_entry = disk_entry_create(entry);
+ if (disk_entry == NULL)
+ continue;
+
+ memset(&mdio, 0, sizeof(mdio));
+ mdio.md_version = MDIOVERSION;
+ mdio.md_unit = unit;
+
+ if (ioctl(md_fd, MDIOCQUERY, &mdio) < 0) {
+ syslog(LOG_ERR,
+ "hrDiskStorageTable: Couldnt ioctl");
+ continue;
+ }
+
+ if ((mdio.md_options & MD_READONLY) == MD_READONLY)
+ disk_entry->access = DS_READ_ONLY;
+ else
+ disk_entry->access = DS_READ_WRITE;
+
+ strlcpy(disk_entry->dev_name, entry->name,
+ sizeof(disk_entry->dev_name));
+
+ disk_entry->media = DSM_RAMDISK;
+ disk_entry->removable = SNMP_FALSE;
+ }
+
+ disk_entry->flags |= HR_DISKSTORAGE_FOUND;
+ disk_entry->flags |= HR_DISKSTORAGE_MD;
+ disk_entry->r_tick = this_tick;
+ }
+}
+
+/**
+ * Find rest of disks
+ */
+static void
+disk_OS_get_disks(void)
+{
+ size_t disk_cnt = 0;
+ struct device_entry *entry;
+ struct disk_entry *disk_entry;
+
+ size_t need = 0;
+
+ if (sysctlbyname("kern.disks", NULL, &need, NULL, 0) == -1) {
+ syslog(LOG_ERR, "%s: sysctl_1 kern.disks failed: %m", __func__);
+ return;
+ }
+
+ if (need == 0)
+ return;
+
+ if (disk_list_len != need + 1 || disk_list == NULL) {
+ disk_list_len = need + 1;
+ disk_list = reallocf(disk_list, disk_list_len);
+ }
+
+ if (disk_list == NULL) {
+ syslog(LOG_ERR, "%s: reallocf failed", __func__);
+ disk_list_len = 0;
+ return;
+ }
+
+ memset(disk_list, 0, disk_list_len);
+
+ if (sysctlbyname("kern.disks", disk_list, &need, NULL, 0) == -1 ||
+ disk_list[0] == 0) {
+ syslog(LOG_ERR, "%s: sysctl_2 kern.disks failed: %m", __func__);
+ return;
+ }
+
+ for (disk_cnt = 0; disk_cnt < need; disk_cnt++) {
+ char *disk = NULL;
+ char disk_device[128] = "";
+
+ disk = strsep(&disk_list, " ");
+ if (disk == NULL)
+ break;
+
+ snprintf(disk_device, sizeof(disk_device),
+ "%s%s", _PATH_DEV, disk);
+
+ /* First check if the disk is in the hrDeviceTable. */
+ if ((entry = device_find_by_name(disk)) == NULL) {
+ /*
+ * not found there - insert it as immutable
+ * XXX somehow we should remove it if it disappears
+ */
+ syslog(LOG_WARNING, "%s: device '%s' not in "
+ "device list", __func__, disk);
+
+ if ((entry = device_entry_create(disk, "", "")) == NULL)
+ continue;
+
+ entry->flags |= HR_DEVICE_IMMUTABLE;
+ }
+
+ entry->type = OIDX_hrDeviceDiskStorage_c;
+
+ /* Then check hrDiskStorage table for this device */
+ disk_entry = disk_find_by_index(entry->index);
+ if (disk_entry == NULL) {
+ disk_entry = disk_entry_create(entry);
+ if (disk_entry == NULL)
+ continue;
+ }
+
+ disk_entry->flags |= HR_DISKSTORAGE_FOUND;
+
+ if ((disk_entry->flags & HR_DISKSTORAGE_ATA) ||
+ (disk_entry->flags & HR_DISKSTORAGE_MD)) {
+ /*
+ * ATA/MD detection is running before this one,
+ * so don't waste the time here
+ */
+ continue;
+ }
+
+ disk_entry->access = DS_READ_WRITE;
+ disk_entry->media = DSM_UNKNOWN;
+ disk_entry->removable = SNMP_FALSE;
+
+ if (strncmp(disk_entry->dev_name, "da", 2) == 0) {
+ disk_entry->media = DSM_HARDDISK;
+ disk_entry->removable = SNMP_FALSE;
+ } else if (strncmp(disk_entry->dev_name, "cd", 2) == 0) {
+ disk_entry->media = DSM_OPTICALDISKROM;
+ disk_entry->removable = SNMP_TRUE;
+ } else {
+ disk_entry->media = DSM_UNKNOWN;
+ disk_entry->removable = SNMP_FALSE;
+ }
+
+ strlcpy((char *)disk_entry->dev_name, disk,
+ sizeof(disk_entry->dev_name));
+
+ disk_query_disk(disk_entry);
+ disk_entry->r_tick = this_tick;
+ }
+}
+
+/**
+ * Refresh routine for hrDiskStorageTable
+ * Usable for polling the system for any changes.
+ */
+void
+refresh_disk_storage_tbl(int force)
+{
+ struct disk_entry *entry, *entry_tmp;
+
+ if (disk_storage_tick != 0 && !force &&
+ this_tick - disk_storage_tick < disk_storage_tbl_refresh) {
+ HRDBG("no refresh needed");
+ return;
+ }
+
+ partition_tbl_pre_refresh();
+
+ /* mark each entry as missing */
+ TAILQ_FOREACH(entry, &disk_tbl, link)
+ entry->flags &= ~HR_DISKSTORAGE_FOUND;
+
+ disk_OS_get_ATA_disks(); /* this must be called first ! */
+ disk_OS_get_MD_disks();
+ disk_OS_get_disks();
+
+ /*
+ * Purge items that disappeared
+ */
+ TAILQ_FOREACH_SAFE(entry, &disk_tbl, link, entry_tmp)
+ if (!(entry->flags & HR_DISKSTORAGE_FOUND))
+ /* XXX remove IMMUTABLE entries that have disappeared */
+ disk_entry_delete(entry);
+
+ disk_storage_tick = this_tick;
+
+ partition_tbl_post_refresh();
+
+ HRDBG("refresh DONE");
+}
+
+/*
+ * Init the things for both of hrDiskStorageTable
+ */
+int
+init_disk_storage_tbl(void)
+{
+ char mddev[32] = "";
+
+ /* Try to load md.ko if not loaded already */
+ mdmaybeload();
+
+ md_fd = -1;
+ snprintf(mddev, sizeof(mddev) - 1, "%s%s", _PATH_DEV, MDCTL_NAME);
+ if ((md_fd = open(mddev, O_RDWR)) == -1) {
+ syslog(LOG_ERR, "open %s failed: %m", mddev);
+ return (-1);
+ }
+
+ refresh_disk_storage_tbl(1);
+
+ return (0);
+}
+
+/*
+ * Finalization routine for hrDiskStorageTable
+ * It destroys the lists and frees any allocated heap memory
+ */
+void
+fini_disk_storage_tbl(void)
+{
+ struct disk_entry *n1;
+
+ while ((n1 = TAILQ_FIRST(&disk_tbl)) != NULL) {
+ TAILQ_REMOVE(&disk_tbl, n1, link);
+ free(n1);
+ }
+
+ free(disk_list);
+
+ if (md_fd > 0) {
+ if (close(md_fd) == -1)
+ syslog(LOG_ERR,"close (/dev/mdctl) failed: %m");
+ md_fd = -1;
+ }
+}
+
+/*
+ * This is the implementation for a generated (by our SNMP "compiler" tool)
+ * function prototype, see hostres_tree.h
+ * It handles the SNMP operations for hrDiskStorageTable
+ */
+int
+op_hrDiskStorageTable(struct snmp_context *ctx __unused,
+ struct snmp_value *value, u_int sub, u_int iidx __unused,
+ enum snmp_op curr_op)
+{
+ struct disk_entry *entry;
+
+ refresh_disk_storage_tbl(0);
+
+ switch (curr_op) {
+
+ case SNMP_OP_GETNEXT:
+ if ((entry = NEXT_OBJECT_INT(&disk_tbl,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ value->var.len = sub + 1;
+ value->var.subs[sub] = entry->index;
+ goto get;
+
+ case SNMP_OP_GET:
+ if ((entry = FIND_OBJECT_INT(&disk_tbl,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ goto get;
+
+ case SNMP_OP_SET:
+ if ((entry = FIND_OBJECT_INT(&disk_tbl,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NO_CREATION);
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ case SNMP_OP_ROLLBACK:
+ case SNMP_OP_COMMIT:
+ abort();
+ }
+ abort();
+
+ get:
+ switch (value->var.subs[sub - 1]) {
+
+ case LEAF_hrDiskStorageAccess:
+ value->v.integer = entry->access;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrDiskStorageMedia:
+ value->v.integer = entry->media;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrDiskStorageRemoveble:
+ value->v.integer = entry->removable;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrDiskStorageCapacity:
+ value->v.integer = entry->capacity;
+ return (SNMP_ERR_NOERROR);
+ }
+ abort();
+}
diff --git a/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_fs_tbl.c b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_fs_tbl.c
new file mode 100644
index 0000000..51e7181
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_fs_tbl.c
@@ -0,0 +1,440 @@
+/*-
+ * Copyright (c) 2005-2006 The FreeBSD Project
+ * All rights reserved.
+ *
+ * Author: Victor Cruceru <soc-victor@freebsd.org>
+ *
+ * Redistribution of this software and documentation and use in source and
+ * binary forms, with or without modification, are permitted provided that
+ * the following conditions are met:
+ *
+ * 1. Redistributions of source code or documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Host Resources MIB for SNMPd. Implementation for hrFSTable
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <sys/mount.h>
+
+#include <assert.h>
+#include <err.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+
+#include "hostres_snmp.h"
+#include "hostres_oid.h"
+#include "hostres_tree.h"
+
+/*
+ * File system access enum
+ */
+enum hrFSAccess {
+ FS_READ_WRITE = 1,
+ FS_READ_ONLY = 2
+};
+
+/*
+ * This structure is used to hold a SNMP table entry
+ * for HOST-RESOURCES-MIB's hrFSTable
+ */
+struct fs_entry {
+ int32_t index;
+ u_char mountPoint[128 + 1];
+ u_char remoteMountPoint[128 + 1];
+ const struct asn_oid *type;
+ int32_t access; /* enum hrFSAccess, see above */
+ int32_t bootable; /* TruthValue */
+ int32_t storageIndex; /* hrStorageTblEntry::index */
+ u_char lastFullBackupDate[11];
+ u_char lastPartialBackupDate[11];
+#define HR_FS_FOUND 0x001
+ uint32_t flags; /* not in mib table, for internal use */
+ TAILQ_ENTRY(fs_entry) link;
+};
+TAILQ_HEAD(fs_tbl, fs_entry);
+
+/*
+ * Next structure is used to keep o list of mappings from a specific name
+ * (a_name) to an entry in the hrFSTblEntry. We are trying to keep the same
+ * index for a specific name at least for the duration of one SNMP agent run.
+ */
+struct fs_map_entry {
+ int32_t hrIndex; /* used for hrFSTblEntry::index */
+ u_char a_name[128 + 1];/* map key */
+
+ /* may be NULL if the respective hrFSTblEntry is (temporally) gone */
+ struct fs_entry *entry;
+ STAILQ_ENTRY(fs_map_entry) link;
+};
+STAILQ_HEAD(fs_map, fs_map_entry);
+
+/* head of the list with hrFSTable's entries */
+static struct fs_tbl fs_tbl = TAILQ_HEAD_INITIALIZER(fs_tbl);
+
+/* for consistent table indexing */
+static struct fs_map fs_map = STAILQ_HEAD_INITIALIZER(fs_map);
+
+/* next index available for hrFSTable */
+static uint32_t next_fs_index = 1;
+
+/* last tick when hrFSTable was updated */
+static uint64_t fs_tick;
+
+/* maximum number of ticks between refreshs */
+uint32_t fs_tbl_refresh = HR_FS_TBL_REFRESH * 100;
+
+/* some constants */
+static const struct asn_oid OIDX_hrFSBerkeleyFFS_c = OIDX_hrFSBerkeleyFFS;
+static const struct asn_oid OIDX_hrFSiso9660_c = OIDX_hrFSiso9660;
+static const struct asn_oid OIDX_hrFSNFS_c = OIDX_hrFSNFS;
+static const struct asn_oid OIDX_hrFSLinuxExt2_c = OIDX_hrFSLinuxExt2;
+static const struct asn_oid OIDX_hrFSOther_c = OIDX_hrFSOther;
+static const struct asn_oid OIDX_hrFSFAT32_c = OIDX_hrFSFAT32;
+static const struct asn_oid OIDX_hrFSNTFS_c = OIDX_hrFSNTFS;
+static const struct asn_oid OIDX_hrFSNetware_c = OIDX_hrFSNetware;
+static const struct asn_oid OIDX_hrFSHPFS_c = OIDX_hrFSHPFS;
+static const struct asn_oid OIDX_hrFSUnknown_c = OIDX_hrFSUnknown;
+
+/* file system type map */
+static const struct {
+ const char *str; /* the type string */
+ const struct asn_oid *oid; /* the OID to return */
+} fs_type_map[] = {
+ { "ufs", &OIDX_hrFSBerkeleyFFS_c },
+ { "cd9660", &OIDX_hrFSiso9660_c },
+ { "nfs", &OIDX_hrFSNFS_c },
+ { "ext2fs", &OIDX_hrFSLinuxExt2_c },
+ { "procfs", &OIDX_hrFSOther_c },
+ { "devfs", &OIDX_hrFSOther_c },
+ { "msdosfs", &OIDX_hrFSFAT32_c },
+ { "ntfs", &OIDX_hrFSNTFS_c },
+ { "nwfs", &OIDX_hrFSNetware_c },
+ { "hpfs", &OIDX_hrFSHPFS_c },
+ { "smbfs", &OIDX_hrFSOther_c },
+};
+#define N_FS_TYPE_MAP (sizeof(fs_type_map) / sizeof(fs_type_map[0]))
+
+/**
+ * Create an entry into the FS table and an entry in the map (if needed).
+ */
+static struct fs_entry *
+fs_entry_create(const char *name)
+{
+ struct fs_entry *entry;
+ struct fs_map_entry *map;
+
+ if ((entry = malloc(sizeof(*entry))) == NULL) {
+ syslog(LOG_WARNING, "%s: %m", __func__);
+ return (NULL);
+ }
+
+ strlcpy(entry->mountPoint, name, sizeof(entry->mountPoint));
+
+ STAILQ_FOREACH(map, &fs_map, link)
+ if (strncmp(map->a_name, entry->mountPoint,
+ sizeof(map->a_name) - 1) == 0) {
+ entry->index = map->hrIndex;
+ map->entry = entry;
+ break;
+ }
+
+ if (map == NULL) {
+ /* new object - get a new index */
+ if (next_fs_index > INT_MAX) {
+ /* XXX no other sensible reaction? */
+ syslog(LOG_ERR, "%s: hrFSTable index wrap", __func__);
+ return (NULL);
+ }
+
+ if ((map = malloc(sizeof(*map))) == NULL) {
+ syslog(LOG_ERR, "%s: %m", __func__);
+ free(entry);
+ return (NULL);
+ }
+
+ map->hrIndex = next_fs_index++;
+ strlcpy(map->a_name, entry->mountPoint, sizeof(map->a_name));
+ map->entry = entry;
+
+ STAILQ_INSERT_TAIL(&fs_map, map, link);
+
+ HRDBG("%s added into hrFSMap at index=%d", name, map->hrIndex);
+ } else {
+ HRDBG("%s exists in hrFSMap index=%d", name, map->hrIndex);
+ }
+
+ entry->index = map->hrIndex;
+
+ INSERT_OBJECT_INT(entry, &fs_tbl);
+
+ return (entry);
+}
+
+/**
+ * Delete an entry in the FS table.
+ */
+static void
+fs_entry_delete(struct fs_entry* entry)
+{
+ struct fs_map_entry *map;
+
+ TAILQ_REMOVE(&fs_tbl, entry, link);
+ STAILQ_FOREACH(map, &fs_map, link)
+ if (map->entry == entry) {
+ map->entry = NULL;
+ break;
+ }
+
+ free(entry);
+}
+
+/**
+ * Find a table entry by its name
+ */
+static struct fs_entry *
+fs_find_by_name(const char *name)
+{
+ struct fs_entry *entry;
+
+ TAILQ_FOREACH(entry, &fs_tbl, link)
+ if (strncmp(entry->mountPoint, name,
+ sizeof(entry->mountPoint) - 1) == 0)
+ return (entry);
+
+ return (NULL);
+}
+
+/**
+ * Get rid of all data
+ */
+void
+fini_fs_tbl(void)
+{
+ struct fs_map_entry *n1;
+
+ while ((n1 = STAILQ_FIRST(&fs_map)) != NULL) {
+ STAILQ_REMOVE_HEAD(&fs_map, link);
+ if (n1->entry != NULL) {
+ TAILQ_REMOVE(&fs_tbl, n1->entry, link);
+ free(n1->entry);
+ }
+ free(n1);
+ }
+ assert(TAILQ_EMPTY(&fs_tbl));
+}
+
+/**
+ * Called before the refreshing is started from the storage table.
+ */
+void
+fs_tbl_pre_refresh(void)
+{
+ struct fs_entry *entry;
+
+ /* mark each entry as missisng */
+ TAILQ_FOREACH(entry, &fs_tbl, link)
+ entry->flags &= ~HR_FS_FOUND;
+}
+
+/**
+ * Called after refreshing from the storage table.
+ */
+void
+fs_tbl_post_refresh(void)
+{
+ struct fs_entry *entry, *entry_tmp;
+
+ /*
+ * Purge items that disappeared
+ */
+ TAILQ_FOREACH_SAFE(entry, &fs_tbl, link, entry_tmp)
+ if (!(entry->flags & HR_FS_FOUND))
+ fs_entry_delete(entry);
+
+ fs_tick = this_tick;
+}
+
+/*
+ * Refresh the FS table. This is done by forcing a refresh of the storage table.
+ */
+void
+refresh_fs_tbl(void)
+{
+
+ if (fs_tick == 0 || this_tick - fs_tick >= fs_tbl_refresh) {
+ refresh_storage_tbl(1);
+ HRDBG("refresh DONE");
+ }
+}
+
+/**
+ * Get the type OID for a given file system
+ */
+const struct asn_oid *
+fs_get_type(const struct statfs *fs_p)
+{
+ u_int t;
+
+ assert(fs_p != NULL);
+
+ for (t = 0; t < N_FS_TYPE_MAP; t++)
+ if (strcmp(fs_type_map[t].str, fs_p->f_fstypename) == 0)
+ return (fs_type_map[t].oid);
+
+ return (&OIDX_hrFSUnknown_c);
+}
+
+/*
+ * Given information returned from statfs(2) either create a new entry into
+ * the fs_tbl or refresh the entry if it is already there.
+ */
+void
+fs_tbl_process_statfs_entry(const struct statfs *fs_p, int32_t storage_idx)
+{
+ struct fs_entry *entry;
+
+ assert(fs_p != 0);
+
+ HRDBG("for hrStorageEntry::index %d", storage_idx);
+
+ if (fs_p == NULL)
+ return;
+
+ if ((entry = fs_find_by_name(fs_p->f_mntonname)) != NULL ||
+ (entry = fs_entry_create(fs_p->f_mntonname)) != NULL) {
+ entry->flags |= HR_FS_FOUND;
+
+ strcpy(entry->mountPoint, fs_p->f_mntonname);
+
+ if (!(fs_p->f_flags & MNT_LOCAL))
+ /* this is a remote mount */
+ strcpy(entry->remoteMountPoint, fs_p->f_mntfromname);
+ else
+ entry->remoteMountPoint[0] = '\0';
+
+ entry->type = fs_get_type(fs_p);
+
+ if ((fs_p->f_flags & MNT_RDONLY) == MNT_RDONLY)
+ entry->access = FS_READ_ONLY;
+ else
+ entry->access = FS_READ_WRITE;
+
+ /* FIXME - bootable fs ?! */
+ entry->bootable = TRUTH_MK((fs_p->f_flags & MNT_ROOTFS)
+ == MNT_ROOTFS);
+
+ entry->storageIndex = storage_idx;
+
+ /* Info not available */
+ memset(entry->lastFullBackupDate, 0,
+ sizeof(entry->lastFullBackupDate));
+
+ /* Info not available */
+ memset(entry->lastPartialBackupDate, 0,
+ sizeof(entry->lastPartialBackupDate));
+
+ handle_partition_fs_index(fs_p->f_mntfromname, entry->index);
+ }
+}
+
+/*
+ * This is the implementation for a generated (by our SNMP "compiler" tool)
+ * function prototype, see hostres_tree.h
+ * It handles the SNMP operations for hrFSTable
+ */
+int
+op_hrFSTable(struct snmp_context *ctx __unused, struct snmp_value *value,
+ u_int sub, u_int iidx __unused, enum snmp_op curr_op)
+{
+ struct fs_entry *entry;
+
+ refresh_fs_tbl();
+
+ switch (curr_op) {
+
+ case SNMP_OP_GETNEXT:
+ if ((entry = NEXT_OBJECT_INT(&fs_tbl,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ value->var.len = sub + 1;
+ value->var.subs[sub] = entry->index;
+ goto get;
+
+ case SNMP_OP_GET:
+ if ((entry = FIND_OBJECT_INT(&fs_tbl,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ goto get;
+
+ case SNMP_OP_SET:
+ if ((entry = FIND_OBJECT_INT(&fs_tbl,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NO_CREATION);
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ case SNMP_OP_ROLLBACK:
+ case SNMP_OP_COMMIT:
+ abort();
+ }
+ abort();
+ get:
+ switch (value->var.subs[sub - 1]) {
+
+ case LEAF_hrFSIndex:
+ value->v.integer = entry->index;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrFSMountPoint:
+ return (string_get(value, entry->mountPoint, -1));
+
+ case LEAF_hrFSRemoteMountPoint:
+ return (string_get(value, entry->remoteMountPoint, -1));
+ break;
+
+ case LEAF_hrFSType:
+ value->v.oid = *entry->type;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrFSAccess:
+ value->v.integer = entry->access;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrFSBootable:
+ value->v.integer = entry->bootable;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrFSStorageIndex:
+ value->v.integer = entry->storageIndex;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrFSLastFullBackupDate:
+ return (string_get(value, entry->lastFullBackupDate, 8));
+
+ case LEAF_hrFSLastPartialBackupDate:
+ return (string_get(value, entry->lastPartialBackupDate, 8));
+ }
+ abort();
+}
diff --git a/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_network_tbl.c b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_network_tbl.c
new file mode 100644
index 0000000..a98241c
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_network_tbl.c
@@ -0,0 +1,302 @@
+/*-
+ * Copyright (c) 2005-2006 The FreeBSD Project
+ * All rights reserved.
+ *
+ * Author: Victor Cruceru <soc-victor@freebsd.org>
+ *
+ * Redistribution of this software and documentation and use in source and
+ * binary forms, with or without modification, are permitted provided that
+ * the following conditions are met:
+ *
+ * 1. Redistributions of source code or documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Host Resources MIB implementation for SNMPd: instrumentation for
+ * hrNetworkTable
+ */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+
+#include <net/if.h>
+#include <net/if_mib.h>
+
+#include <assert.h>
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <ifaddrs.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include "hostres_snmp.h"
+#include "hostres_oid.h"
+#include "hostres_tree.h"
+
+#include <bsnmp/snmp_mibII.h>
+
+/*
+ * This structure is used to hold a SNMP table entry
+ * for HOST-RESOURCES-MIB's hrNetworkTable
+ */
+struct network_entry {
+ int32_t index;
+ int32_t ifIndex;
+ TAILQ_ENTRY(network_entry) link;
+#define HR_NETWORK_FOUND 0x001
+ uint32_t flags;
+
+};
+TAILQ_HEAD(network_tbl, network_entry);
+
+/* the head of the list with hrNetworkTable's entries */
+static struct network_tbl network_tbl = TAILQ_HEAD_INITIALIZER(network_tbl);
+
+/* last (agent) tick when hrNetworkTable was updated */
+static uint64_t network_tick;
+
+/* maximum number of ticks between updates of network table */
+uint32_t network_tbl_refresh = HR_NETWORK_TBL_REFRESH * 100;
+
+/* Constants */
+static const struct asn_oid OIDX_hrDeviceNetwork_c = OIDX_hrDeviceNetwork;
+
+/**
+ * Create a new entry into the network table
+ */
+static struct network_entry *
+network_entry_create(const struct device_entry *devEntry)
+{
+ struct network_entry *entry;
+
+ assert(devEntry != NULL);
+ if (devEntry == NULL)
+ return (NULL);
+
+ if ((entry = malloc(sizeof(*entry))) == NULL) {
+ syslog(LOG_WARNING, "%s: %m", __func__);
+ return (NULL);
+ }
+
+ memset(entry, 0, sizeof(*entry));
+ entry->index = devEntry->index;
+ INSERT_OBJECT_INT(entry, &network_tbl);
+
+ return (entry);
+}
+
+/**
+ * Delete an entry in the network table
+ */
+static void
+network_entry_delete(struct network_entry* entry)
+{
+
+ TAILQ_REMOVE(&network_tbl, entry, link);
+ free(entry);
+}
+
+/**
+ * Fetch the interfaces from the mibII module, get their real name from the
+ * kernel and try to find it in the device table.
+ */
+static void
+network_get_interfaces(void)
+{
+ struct device_entry *dev;
+ struct network_entry *net;
+ struct mibif *ifp;
+ int name[6];
+ size_t len;
+ char *dname;
+
+ name[0] = CTL_NET;
+ name[1] = PF_LINK;
+ name[2] = NETLINK_GENERIC;
+ name[3] = IFMIB_IFDATA;
+ name[5] = IFDATA_DRIVERNAME;
+
+ for (ifp = mib_first_if(); ifp != NULL; ifp = mib_next_if(ifp)) {
+ HRDBG("%s %s", ifp->name, ifp->descr);
+
+ name[4] = ifp->sysindex;
+
+ /* get the original name */
+ len = 0;
+ if (sysctl(name, 6, NULL, &len, 0, 0) < 0) {
+ syslog(LOG_ERR, "sysctl(net.link.ifdata.%d."
+ "drivername): %m", ifp->sysindex);
+ continue;
+ }
+ if ((dname = malloc(len)) == NULL) {
+ syslog(LOG_ERR, "malloc: %m");
+ continue;
+ }
+ if (sysctl(name, 6, dname, &len, 0, 0) < 0) {
+ syslog(LOG_ERR, "sysctl(net.link.ifdata.%d."
+ "drivername): %m", ifp->sysindex);
+ free(dname);
+ continue;
+ }
+
+ HRDBG("got device %s (%s)", ifp->name, dname);
+
+ if ((dev = device_find_by_name(dname)) == NULL) {
+ HRDBG("%s not in hrDeviceTable", dname);
+ free(dname);
+ continue;
+ }
+ HRDBG("%s found in hrDeviceTable", dname);
+
+ dev->type = OIDX_hrDeviceNetwork_c;
+ dev->flags |= HR_DEVICE_IMMUTABLE;
+
+ free(dname);
+
+ /* Then check hrNetworkTable for this device */
+ TAILQ_FOREACH(net, &network_tbl, link)
+ if (net->index == dev->index)
+ break;
+
+ if (net == NULL && (net = network_entry_create(dev)) == NULL)
+ continue;
+
+ net->flags |= HR_NETWORK_FOUND;
+ net->ifIndex = ifp->index;
+ }
+
+ network_tick = this_tick;
+}
+
+/**
+ * Finalization routine for hrNetworkTable.
+ * It destroys the lists and frees any allocated heap memory.
+ */
+void
+fini_network_tbl(void)
+{
+ struct network_entry *n1;
+
+ while ((n1 = TAILQ_FIRST(&network_tbl)) != NULL) {
+ TAILQ_REMOVE(&network_tbl, n1, link);
+ free(n1);
+ }
+}
+
+/**
+ * Get the interface list from mibII only at this point to be sure that
+ * it is there already.
+ */
+void
+start_network_tbl(void)
+{
+
+ mib_refresh_iflist();
+ network_get_interfaces();
+}
+
+/**
+ * Refresh the table.
+ */
+static void
+refresh_network_tbl(void)
+{
+ struct network_entry *entry, *entry_tmp;
+
+ if (this_tick - network_tick < network_tbl_refresh) {
+ HRDBG("no refresh needed");
+ return;
+ }
+
+ /* mark each entry as missing */
+ TAILQ_FOREACH(entry, &network_tbl, link)
+ entry->flags &= ~HR_NETWORK_FOUND;
+
+ network_get_interfaces();
+
+ /*
+ * Purge items that disappeared
+ */
+ TAILQ_FOREACH_SAFE(entry, &network_tbl, link, entry_tmp) {
+ if (!(entry->flags & HR_NETWORK_FOUND))
+ network_entry_delete(entry);
+ }
+
+ HRDBG("refresh DONE");
+}
+
+/*
+ * This is the implementation for a generated (by our SNMP tool)
+ * function prototype, see hostres_tree.h
+ * It handles the SNMP operations for hrNetworkTable
+ */
+int
+op_hrNetworkTable(struct snmp_context *ctx __unused, struct snmp_value *value,
+ u_int sub, u_int iidx __unused, enum snmp_op curr_op)
+{
+ struct network_entry *entry;
+
+ refresh_network_tbl();
+
+ switch (curr_op) {
+
+ case SNMP_OP_GETNEXT:
+ if ((entry = NEXT_OBJECT_INT(&network_tbl,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ value->var.len = sub + 1;
+ value->var.subs[sub] = entry->index;
+ goto get;
+
+ case SNMP_OP_GET:
+ if ((entry = FIND_OBJECT_INT(&network_tbl,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ goto get;
+
+ case SNMP_OP_SET:
+ if ((entry = FIND_OBJECT_INT(&network_tbl,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NO_CREATION);
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ case SNMP_OP_ROLLBACK:
+ case SNMP_OP_COMMIT:
+ abort();
+ }
+ abort();
+
+ get:
+ switch (value->var.subs[sub - 1]) {
+
+ case LEAF_hrNetworkIfIndex:
+ value->v.integer = entry->ifIndex;
+ return (SNMP_ERR_NOERROR);
+
+ }
+ abort();
+}
diff --git a/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_partition_tbl.c b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_partition_tbl.c
new file mode 100644
index 0000000..d6e55c0
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_partition_tbl.c
@@ -0,0 +1,415 @@
+/*-
+ * Copyright (c) 2005-2006 The FreeBSD Project
+ * All rights reserved.
+ *
+ * Author: Victor Cruceru <soc-victor@freebsd.org>
+ *
+ * Redistribution of this software and documentation and use in source and
+ * binary forms, with or without modification, are permitted provided that
+ * the following conditions are met:
+ *
+ * 1. Redistributions of source code or documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Host Resources MIB: hrPartitionTable implementation for SNMPd.
+ */
+
+#include <sys/types.h>
+#include <sys/limits.h>
+
+#include <assert.h>
+#include <err.h>
+#include <libdisk.h>
+#include <paths.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+
+#include "hostres_snmp.h"
+#include "hostres_oid.h"
+#include "hostres_tree.h"
+
+/*
+ * One row in the hrPartitionTable
+ */
+struct partition_entry {
+ struct asn_oid index;
+ u_char label[128 + 1];
+ u_char id[128 + 1];
+ int32_t size;
+ int32_t fs_Index;
+ TAILQ_ENTRY(partition_entry) link;
+#define HR_PARTITION_FOUND 0x001
+ uint32_t flags;
+};
+TAILQ_HEAD(partition_tbl, partition_entry);
+
+/*
+ * This table is used to get a consistent indexing. It saves the name -> index
+ * mapping while we rebuild the partition table.
+ */
+struct partition_map_entry {
+ int32_t index; /* hrPartitionTblEntry::index */
+ u_char id[128 + 1];
+
+ /*
+ * next may be NULL if the respective partition_entry
+ * is (temporally) gone.
+ */
+ struct partition_entry *entry;
+ STAILQ_ENTRY(partition_map_entry) link;
+};
+STAILQ_HEAD(partition_map, partition_map_entry);
+
+/* Mapping table for consistent indexing */
+static struct partition_map partition_map =
+ STAILQ_HEAD_INITIALIZER(partition_map);
+
+/* THE partition table. */
+static struct partition_tbl partition_tbl =
+ TAILQ_HEAD_INITIALIZER(partition_tbl);
+
+/* next int available for indexing the hrPartitionTable */
+static uint32_t next_partition_index = 1;
+
+/**
+ * Create a new partition table entry
+ */
+static struct partition_entry *
+partition_entry_create(int32_t ds_index, const struct chunk *chunk)
+{
+ struct partition_entry *entry;
+ struct partition_map_entry *map = NULL;
+
+ /* sanity checks */
+ assert(chunk != NULL);
+ assert(chunk->name != NULL);
+ if (chunk == NULL || chunk->name == NULL || chunk->name[0] == '\0')
+ return (NULL);
+
+ if ((entry = malloc(sizeof(*entry))) == NULL) {
+ syslog(LOG_WARNING, "hrPartitionTable: %s: %m", __func__);
+ return (NULL);
+ }
+ memset(entry, 0, sizeof(*entry));
+
+ /* check whether we already have seen this partition */
+ STAILQ_FOREACH(map, &partition_map, link)
+ if (strcmp(map->id, chunk->name) == 0 ) {
+ map->entry = entry;
+ break;
+ }
+
+ if (map == NULL) {
+ /* new object - get a new index and create a map */
+ if (next_partition_index > INT_MAX) {
+ syslog(LOG_ERR, "%s: hrPartitionTable index wrap",
+ __func__);
+ errx(1, "hrPartitionTable index wrap");
+ }
+
+ if ((map = malloc(sizeof(*map))) == NULL) {
+ syslog(LOG_ERR, "hrPartitionTable: %s: %m", __func__);
+ free(entry);
+ return (NULL);
+ }
+
+ map->index = next_partition_index++;
+
+ memset(map->id, 0, sizeof(map->id));
+ strncpy(map->id, chunk->name, sizeof(map->id) - 1);
+
+ map->entry = entry;
+ STAILQ_INSERT_TAIL(&partition_map, map, link);
+
+ HRDBG("%s added into hrPartitionMap at index=%d",
+ chunk->name, map->index);
+
+ } else {
+ HRDBG("%s exists in hrPartitionMap index=%d",
+ chunk->name, map->index);
+ }
+
+ /* create the index */
+ entry->index.len = 2;
+ entry->index.subs[0] = ds_index;
+ entry->index.subs[1] = map->index;
+
+ memset(&entry->id[0], 0, sizeof(entry->id));
+ strncpy(entry->id, chunk->name, sizeof(entry->id) - 1);
+
+ snprintf(entry->label, sizeof(entry->label) - 1,
+ "%s%s", _PATH_DEV, chunk->name);
+
+ INSERT_OBJECT_OID(entry, &partition_tbl);
+
+ return (entry);
+}
+
+/**
+ * Delete a partition table entry but keep the map entry intact.
+ */
+static void
+partition_entry_delete(struct partition_entry *entry)
+{
+ struct partition_map_entry *map;
+
+ assert(entry != NULL);
+
+ TAILQ_REMOVE(&partition_tbl, entry, link);
+ STAILQ_FOREACH(map, &partition_map, link)
+ if (map->entry == entry) {
+ map->entry = NULL;
+ break;
+ }
+
+ free(entry);
+}
+
+/**
+ * Find a partition table entry by name. If none is found, return NULL.
+ */
+static struct partition_entry *
+partition_entry_find_by_name(const char *name)
+{
+ struct partition_entry *entry = NULL;
+
+ TAILQ_FOREACH(entry, &partition_tbl, link)
+ if (strcmp(entry->id, name) == 0)
+ return (entry);
+
+ return (NULL);
+}
+
+/**
+ * Find a partition table entry by label. If none is found, return NULL.
+ */
+static struct partition_entry *
+partition_entry_find_by_label(const char *name)
+{
+ struct partition_entry *entry = NULL;
+
+ TAILQ_FOREACH(entry, &partition_tbl, link)
+ if (strcmp(entry->label, name) == 0)
+ return (entry);
+
+ return (NULL);
+}
+
+/**
+ * Process a chunk from libdisk. A chunk is either a slice or a partition.
+ * If necessary create a new partition table entry for it. In any case
+ * set the size field of the entry and set the FOUND flag.
+ */
+static void
+handle_chunk(int32_t ds_index, const struct chunk* chunk,
+ const struct disk *disk)
+{
+ struct partition_entry *entry = NULL;
+ daddr_t k_size;
+
+ assert(chunk != NULL);
+ if (chunk == NULL)
+ return;
+
+ if (chunk->type == unused) {
+ HRDBG("SKIP unused chunk %s", chunk->name);
+ return;
+ }
+ HRDBG("ANALYZE chunk %s", chunk->name);
+
+ if ((entry = partition_entry_find_by_name(chunk->name)) == NULL)
+ if ((entry = partition_entry_create(ds_index, chunk)) == NULL)
+ return;
+
+ entry->flags |= HR_PARTITION_FOUND;
+
+ /* actual size may overflow the SNMP type */
+ k_size = chunk->size / (1024 / disk->sector_size);
+ entry->size = (k_size > (daddr_t)INT_MAX ? INT_MAX : k_size);
+}
+
+/**
+ * Start refreshing the partition table. A call to this function will
+ * be followed by a call to handleDiskStorage() for every disk, followed
+ * by a single call to the post_refresh function.
+ */
+void
+partition_tbl_pre_refresh(void)
+{
+ struct partition_entry *entry = NULL;
+
+ /* mark each entry as missing */
+ TAILQ_FOREACH(entry, &partition_tbl, link)
+ entry->flags &= ~HR_PARTITION_FOUND;
+}
+
+/**
+ * Called from the DiskStorage table for every row. Open the device and
+ * process all the partitions in it. ds_index is the index into the DiskStorage
+ * table.
+ */
+void
+partition_tbl_handle_disk(int32_t ds_index, const char *disk_dev_name)
+{
+ struct disk *disk;
+ struct chunk *chunk;
+ struct chunk *partt;
+
+ assert(disk_dev_name != NULL);
+ assert(ds_index > 0);
+
+ if ((disk = Open_Disk(disk_dev_name)) == NULL) {
+ syslog(LOG_ERR, "%s: cannot Open_Disk()", disk_dev_name);
+ return;
+ }
+
+ for (chunk = disk->chunks->part; chunk != NULL; chunk = chunk->next) {
+ handle_chunk(ds_index, chunk, disk);
+ for (partt = chunk->part; partt != NULL; partt = partt->next)
+ handle_chunk(ds_index, partt, disk);
+ }
+ Free_Disk(disk);
+}
+
+/**
+ * Finish refreshing the table.
+ */
+void
+partition_tbl_post_refresh(void)
+{
+ struct partition_entry *e, *etmp;
+
+ /*
+ * Purge items that disappeared
+ */
+ TAILQ_FOREACH_SAFE(e, &partition_tbl, link, etmp)
+ if (!(e->flags & HR_PARTITION_FOUND))
+ partition_entry_delete(e);
+}
+
+/*
+ * Finalization routine for hrPartitionTable
+ * It destroys the lists and frees any allocated heap memory
+ */
+void
+fini_partition_tbl(void)
+{
+ struct partition_map_entry *m;
+
+ while ((m = STAILQ_FIRST(&partition_map)) != NULL) {
+ STAILQ_REMOVE_HEAD(&partition_map, link);
+ if(m->entry != NULL) {
+ TAILQ_REMOVE(&partition_tbl, m->entry, link);
+ free(m->entry);
+ }
+ free(m);
+ }
+ assert(TAILQ_EMPTY(&partition_tbl));
+}
+
+/**
+ * Called from the file system code to insert the file system table index
+ * into the partition table entry. Note, that an partition table entry exists
+ * only for local file systems.
+ */
+void
+handle_partition_fs_index(const char *name, int32_t fs_idx)
+{
+ struct partition_entry *entry;
+
+ if ((entry = partition_entry_find_by_label(name)) == NULL) {
+ HRDBG("%s IS MISSING from hrPartitionTable", name);
+ return;
+ }
+ HRDBG("%s [FS index = %d] IS in hrPartitionTable", name, fs_idx);
+ entry->fs_Index = fs_idx;
+}
+
+/*
+ * This is the implementation for a generated (by our SNMP tool)
+ * function prototype, see hostres_tree.h
+ * It handles the SNMP operations for hrPartitionTable
+ */
+int
+op_hrPartitionTable(struct snmp_context *ctx __unused, struct snmp_value *value,
+ u_int sub, u_int iidx __unused, enum snmp_op op)
+{
+ struct partition_entry *entry;
+
+ /*
+ * Refresh the disk storage table (which refreshes the partition
+ * table) if necessary.
+ */
+ refresh_disk_storage_tbl(0);
+
+ switch (op) {
+
+ case SNMP_OP_GETNEXT:
+ if ((entry = NEXT_OBJECT_OID(&partition_tbl,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+
+ index_append(&value->var, sub, &entry->index);
+ goto get;
+
+ case SNMP_OP_GET:
+ if ((entry = FIND_OBJECT_OID(&partition_tbl,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ goto get;
+
+ case SNMP_OP_SET:
+ if ((entry = FIND_OBJECT_OID(&partition_tbl,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NOT_WRITEABLE);
+ return (SNMP_ERR_NO_CREATION);
+
+ case SNMP_OP_ROLLBACK:
+ case SNMP_OP_COMMIT:
+ abort();
+ }
+ abort();
+
+ get:
+ switch (value->var.subs[sub - 1]) {
+
+ case LEAF_hrPartitionIndex:
+ value->v.integer = entry->index.subs[1];
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrPartitionLabel:
+ return (string_get(value, entry->label, -1));
+
+ case LEAF_hrPartitionID:
+ return(string_get(value, entry->id, -1));
+
+ case LEAF_hrPartitionSize:
+ value->v.integer = entry->size;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrPartitionFSIndex:
+ value->v.integer = entry->fs_Index;
+ return (SNMP_ERR_NOERROR);
+ }
+ abort();
+}
diff --git a/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_printer_tbl.c b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_printer_tbl.c
new file mode 100644
index 0000000..c29b29b
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_printer_tbl.c
@@ -0,0 +1,398 @@
+/*-
+ * Copyright (c) 2005-2006 The FreeBSD Project
+ * All rights reserved.
+ *
+ * Author: Victor Cruceru <soc-victor@freebsd.org>
+ *
+ * Redistribution of this software and documentation and use in source and
+ * binary forms, with or without modification, are permitted provided that
+ * the following conditions are met:
+ *
+ * 1. Redistributions of source code or documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Host Resources MIB implementation for SNMPd: instrumentation for
+ * hrPrinterTable
+ */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <assert.h>
+#include <err.h>
+#include <errno.h>
+#include <paths.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include "hostres_snmp.h"
+#include "hostres_oid.h"
+#include "hostres_tree.h"
+
+#include <sys/dirent.h>
+#include "lp.h"
+
+/* Constants */
+static const struct asn_oid OIDX_hrDevicePrinter_c = OIDX_hrDevicePrinter;
+
+enum PrinterStatus {
+ PS_OTHER = 1,
+ PS_UNKNOWN = 2,
+ PS_IDLE = 3,
+ PS_PRINTING = 4,
+ PS_WARMUP = 5
+};
+
+/*
+ * This structure is used to hold a SNMP table entry
+ * for HOST-RESOURCES-MIB's hrPrinterTable.
+ */
+struct printer_entry {
+ int32_t index;
+ int32_t status; /* values from PrinterStatus enum above */
+ u_char detectedErrorState[2];
+ TAILQ_ENTRY(printer_entry) link;
+#define HR_PRINTER_FOUND 0x001
+ uint32_t flags;
+
+};
+TAILQ_HEAD(printer_tbl, printer_entry);
+
+/* the hrPrinterTable */
+static struct printer_tbl printer_tbl = TAILQ_HEAD_INITIALIZER(printer_tbl);
+
+/* last (agent) tick when hrPrinterTable was updated */
+static uint64_t printer_tick;
+
+/**
+ * Create entry into the printer table.
+ */
+static struct printer_entry *
+printer_entry_create(const struct device_entry *devEntry)
+{
+ struct printer_entry *entry = NULL;
+
+ assert(devEntry != NULL);
+ if (devEntry == NULL)
+ return (NULL);
+
+ if ((entry = malloc(sizeof(*entry))) == NULL) {
+ syslog(LOG_WARNING, "hrPrinterTable: %s: %m", __func__);
+ return (NULL);
+ }
+ memset(entry, 0, sizeof(*entry));
+ entry->index = devEntry->index;
+ INSERT_OBJECT_INT(entry, &printer_tbl);
+ return (entry);
+}
+
+/**
+ * Delete entry from the printer table.
+ */
+static void
+printer_entry_delete(struct printer_entry *entry)
+{
+
+ assert(entry != NULL);
+ if (entry == NULL)
+ return;
+
+ TAILQ_REMOVE(&printer_tbl, entry, link);
+ free(entry);
+}
+
+/**
+ * Find a printer by its index
+ */
+static struct printer_entry *
+printer_find_by_index(int32_t idx)
+{
+ struct printer_entry *entry;
+
+ TAILQ_FOREACH(entry, &printer_tbl, link)
+ if (entry->index == idx)
+ return (entry);
+
+ return (NULL);
+}
+
+/**
+ * Get the status of a printer
+ */
+static enum PrinterStatus
+get_printer_status(const struct printer *pp)
+{
+ char statfile[MAXPATHLEN];
+ char lockfile[MAXPATHLEN];
+ char fline[128];
+ int fd;
+ FILE *f = NULL;
+ enum PrinterStatus ps = PS_UNKNOWN;
+
+ if (pp->lock_file[0] == '/')
+ strlcpy(lockfile, pp->lock_file, sizeof(lockfile));
+ else
+ snprintf(lockfile, sizeof(lockfile), "%s/%s",
+ pp->spool_dir, pp->lock_file);
+
+ fd = open(lockfile, O_RDONLY);
+ if (fd < 0 || flock(fd, LOCK_SH | LOCK_NB) == 0) {
+ ps = PS_IDLE;
+ goto LABEL_DONE;
+ }
+
+ if (pp->status_file[0] == '/')
+ strlcpy(statfile, pp->status_file, sizeof(statfile));
+ else
+ snprintf(statfile, sizeof(statfile), "%s/%s",
+ pp->spool_dir, pp->status_file);
+
+ f = fopen(statfile, "r");
+ if (f == NULL) {
+ syslog(LOG_ERR, "cannot open status file: %s", strerror(errno));
+ ps = PS_UNKNOWN;
+ goto LABEL_DONE;
+ }
+
+ memset(&fline[0], '\0', sizeof(line));
+ if (fgets(fline, sizeof(fline) -1, f) == NULL) {
+ ps = PS_UNKNOWN;
+ goto LABEL_DONE;
+ }
+
+ if (strstr(fline, "is ready and printing") != NULL) {
+ ps = PS_PRINTING;
+ goto LABEL_DONE;
+ }
+
+ if (strstr(fline, "to become ready (offline?)") != NULL) {
+ ps = PS_OTHER;
+ goto LABEL_DONE;
+ }
+
+LABEL_DONE:
+ if (fd >= 0)
+ (void)close(fd); /* unlocks as well */
+
+ if (f != NULL)
+ (void)fclose(f);
+
+ return (ps);
+}
+
+/**
+ * Called for each printer found in /etc/printcap.
+ */
+static void
+handle_printer(struct printer *pp)
+{
+ struct device_entry *dev_entry;
+ struct printer_entry *printer_entry;
+ char dev_only[128];
+ struct stat sb;
+
+ if (pp->remote_host != NULL) {
+ HRDBG("skipped %s -- remote", pp->printer);
+ return;
+ }
+
+ if (strncmp(pp->lp, _PATH_DEV, strlen(_PATH_DEV)) != 0) {
+ HRDBG("skipped %s [device %s] -- remote", pp->printer, pp->lp);
+ return;
+ }
+
+ memset(dev_only, '\0', sizeof(dev_only));
+ snprintf(dev_only, sizeof(dev_only), "%s", pp->lp + strlen(_PATH_DEV));
+
+ HRDBG("printer %s has device %s", pp->printer, dev_only);
+
+ if (stat(pp->lp, &sb) < 0) {
+ if (errno == ENOENT) {
+ HRDBG("skipped %s -- device %s missing",
+ pp->printer, pp->lp);
+ return;
+ }
+ }
+
+ if ((dev_entry = device_find_by_name(dev_only)) == NULL) {
+ HRDBG("%s not in hrDeviceTable", pp->lp);
+ return;
+ }
+ HRDBG("%s found in hrDeviceTable", pp->lp);
+
+ dev_entry->type = OIDX_hrDevicePrinter_c;
+ dev_entry->flags |= HR_DEVICE_IMMUTABLE;
+
+ /* Then check hrPrinterTable for this device */
+ if ((printer_entry = printer_find_by_index(dev_entry->index)) == NULL &&
+ (printer_entry = printer_entry_create(dev_entry)) == NULL)
+ return;
+
+ printer_entry->flags |= HR_PRINTER_FOUND;
+ printer_entry->status = get_printer_status(pp);
+ memset(printer_entry->detectedErrorState, 0,
+ sizeof(printer_entry->detectedErrorState));
+}
+
+static void
+hrPrinter_get_OS_entries(void)
+{
+ int status, more;
+ struct printer myprinter, *pp = &myprinter;
+
+ init_printer(pp);
+ HRDBG("---->Getting printers .....");
+ more = firstprinter(pp, &status);
+ if (status)
+ goto errloop;
+
+ while (more) {
+ do {
+ HRDBG("---->Got printer %s", pp->printer);
+
+ handle_printer(pp);
+ more = nextprinter(pp, &status);
+errloop:
+ if (status)
+ syslog(LOG_WARNING,
+ "hrPrinterTable: printcap entry for %s "
+ "has errors, skipping",
+ pp->printer ? pp->printer : "<noname?>");
+ } while (more && status);
+ }
+
+ lastprinter();
+ printer_tick = this_tick;
+}
+
+/**
+ * Init the things for hrPrinterTable
+ */
+void
+init_printer_tbl(void)
+{
+
+ hrPrinter_get_OS_entries();
+}
+
+/**
+ * Finalization routine for hrPrinterTable
+ * It destroys the lists and frees any allocated heap memory
+ */
+void
+fini_printer_tbl(void)
+{
+ struct printer_entry *n1;
+
+ while ((n1 = TAILQ_FIRST(&printer_tbl)) != NULL) {
+ TAILQ_REMOVE(&printer_tbl, n1, link);
+ free(n1);
+ }
+}
+
+/**
+ * Refresh the printer table if needed.
+ */
+void
+refresh_printer_tbl(void)
+{
+ struct printer_entry *entry;
+ struct printer_entry *entry_tmp;
+
+ if (this_tick <= printer_tick) {
+ HRDBG("no refresh needed");
+ return;
+ }
+
+ /* mark each entry as missing */
+ TAILQ_FOREACH(entry, &printer_tbl, link)
+ entry->flags &= ~HR_PRINTER_FOUND;
+
+ hrPrinter_get_OS_entries();
+
+ /*
+ * Purge items that disappeared
+ */
+ entry = TAILQ_FIRST(&printer_tbl);
+ while (entry != NULL) {
+ entry_tmp = TAILQ_NEXT(entry, link);
+ if (!(entry->flags & HR_PRINTER_FOUND))
+ printer_entry_delete(entry);
+ entry = entry_tmp;
+ }
+
+ printer_tick = this_tick;
+
+ HRDBG("refresh DONE ");
+}
+
+int
+op_hrPrinterTable(struct snmp_context *ctx __unused, struct snmp_value *value,
+ u_int sub, u_int iidx __unused, enum snmp_op curr_op)
+{
+ struct printer_entry *entry;
+
+ refresh_printer_tbl();
+
+ switch (curr_op) {
+
+ case SNMP_OP_GETNEXT:
+ if ((entry = NEXT_OBJECT_INT(&printer_tbl, &value->var,
+ sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ value->var.len = sub + 1;
+ value->var.subs[sub] = entry->index;
+ goto get;
+
+ case SNMP_OP_GET:
+ if ((entry = FIND_OBJECT_INT(&printer_tbl, &value->var,
+ sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ goto get;
+
+ case SNMP_OP_SET:
+ if ((entry = FIND_OBJECT_INT(&printer_tbl, &value->var,
+ sub)) == NULL)
+ return (SNMP_ERR_NO_CREATION);
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ case SNMP_OP_ROLLBACK:
+ case SNMP_OP_COMMIT:
+ abort();
+ }
+ abort();
+
+ get:
+ switch (value->var.subs[sub - 1]) {
+
+ case LEAF_hrPrinterStatus:
+ value->v.integer = entry->status;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrPrinterDetectedErrorState:
+ return (string_get(value, entry->detectedErrorState,
+ sizeof(entry->detectedErrorState)));
+ }
+ abort();
+}
diff --git a/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_processor_tbl.c b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_processor_tbl.c
new file mode 100644
index 0000000..2df4d3e
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_processor_tbl.c
@@ -0,0 +1,506 @@
+/*-
+ * Copyright (c) 2005-2006 The FreeBSD Project
+ * All rights reserved.
+ *
+ * Author: Victor Cruceru <soc-victor@freebsd.org>
+ *
+ * Redistribution of this software and documentation and use in source and
+ * binary forms, with or without modification, are permitted provided that
+ * the following conditions are met:
+ *
+ * 1. Redistributions of source code or documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Host Resources MIB for SNMPd. Implementation for hrProcessorTable
+ */
+
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <sys/user.h>
+
+#include <assert.h>
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+
+#include "hostres_snmp.h"
+#include "hostres_oid.h"
+#include "hostres_tree.h"
+
+/*
+ * This structure is used to hold a SNMP table entry
+ * for HOST-RESOURCES-MIB's hrProcessorTable.
+ * Note that index is external being allocated & maintained
+ * by the hrDeviceTable code..
+ */
+struct processor_entry {
+ int32_t index;
+ struct asn_oid frwId;
+ int32_t load;
+ TAILQ_ENTRY(processor_entry) link;
+ u_char cpu_no; /* which cpu, counted from 0 */
+ pid_t idle_pid; /* PID of idle process for this CPU */
+
+ /* the samples from the last minute, as required by MIB */
+ double samples[MAX_CPU_SAMPLES];
+
+ /* current sample to fill in next time, must be < MAX_CPU_SAMPLES */
+ uint32_t cur_sample_idx;
+
+ /* number of useful samples */
+ uint32_t sample_cnt;
+};
+TAILQ_HEAD(processor_tbl, processor_entry);
+
+/* the head of the list with hrDeviceTable's entries */
+static struct processor_tbl processor_tbl =
+ TAILQ_HEAD_INITIALIZER(processor_tbl);
+
+/* number of processors in dev tbl */
+static int32_t detected_processor_count;
+
+/* sysctlbyname(hw.ncpu) */
+static int hw_ncpu;
+
+/* sysctlbyname(kern.{ccpu,fscale}) */
+static fixpt_t ccpu;
+static int fscale;
+
+/* tick of PDU where we have refreshed the processor table last */
+static uint64_t proctbl_tick;
+
+/* periodic timer used to get cpu load stats */
+static void *cpus_load_timer;
+
+/*
+ * Average the samples. The entire algorithm seems to be wrong XXX.
+ */
+static int
+get_avg_load(struct processor_entry *e)
+{
+ u_int i;
+ double sum = 0.0;
+
+ assert(e != NULL);
+
+ if (e->sample_cnt == 0)
+ return (0);
+
+ for (i = 0; i < e->sample_cnt; i++)
+ sum += e->samples[i];
+
+ return ((int)floor((double)sum/(double)e->sample_cnt));
+}
+
+/*
+ * Stolen from /usr/src/bin/ps/print.c. The idle process should never
+ * be swapped out :-)
+ */
+static double
+processor_getpcpu(struct kinfo_proc *ki_p)
+{
+
+ if (ccpu == 0 || fscale == 0)
+ return (0.0);
+
+#define fxtofl(fixpt) ((double)(fixpt) / fscale)
+ return (100.0 * fxtofl(ki_p->ki_pctcpu) /
+ (1.0 - exp(ki_p->ki_swtime * log(fxtofl(ccpu)))));
+}
+
+/**
+ * Save a new sample
+ */
+static void
+save_sample(struct processor_entry *e, struct kinfo_proc *kp)
+{
+
+ e->samples[e->cur_sample_idx] = 100.0 - processor_getpcpu(kp);
+ e->load = get_avg_load(e);
+ e->cur_sample_idx = (e->cur_sample_idx + 1) % MAX_CPU_SAMPLES;
+
+ if (++e->sample_cnt > MAX_CPU_SAMPLES)
+ e->sample_cnt = MAX_CPU_SAMPLES;
+}
+
+/**
+ * Create a new entry into the processor table.
+ */
+static struct processor_entry *
+proc_create_entry(u_int cpu_no, struct device_map_entry *map)
+{
+ struct device_entry *dev;
+ struct processor_entry *entry;
+ char name[128];
+
+ /*
+ * If there is no map entry create one by creating a device table
+ * entry.
+ */
+ if (map == NULL) {
+ snprintf(name, sizeof(name), "cpu%u", cpu_no);
+ if ((dev = device_entry_create(name, "", "")) == NULL)
+ return (NULL);
+ dev->flags |= HR_DEVICE_IMMUTABLE;
+ STAILQ_FOREACH(map, &device_map, link)
+ if (strcmp(map->name_key, name) == 0)
+ break;
+ if (map == NULL)
+ abort();
+ }
+
+ if ((entry = malloc(sizeof(*entry))) == NULL) {
+ syslog(LOG_ERR, "hrProcessorTable: %s malloc "
+ "failed: %m", __func__);
+ return (NULL);
+ }
+ memset(entry, 0, sizeof(*entry));
+
+ entry->index = map->hrIndex;
+ entry->load = 0;
+ entry->cpu_no = (u_char)cpu_no;
+ entry->idle_pid = 0;
+ entry->frwId = oid_zeroDotZero; /* unknown id FIXME */
+
+ INSERT_OBJECT_INT(entry, &processor_tbl);
+
+ HRDBG("CPU %d added with SNMP index=%d",
+ entry->cpu_no, entry->index);
+
+ return (entry);
+}
+
+/**
+ * Get the PIDs for the idle processes of the CPUs.
+ */
+static void
+processor_get_pids(void)
+{
+ struct kinfo_proc *plist, *kp;
+ int i;
+ int nproc;
+ int cpu;
+ int nchars;
+ struct processor_entry *entry;
+
+ plist = kvm_getprocs(hr_kd, KERN_PROC_ALL, 0, &nproc);
+ if (plist == NULL || nproc < 0) {
+ syslog(LOG_ERR, "hrProcessor: kvm_getprocs() failed: %m");
+ return;
+ }
+
+ for (i = 0, kp = plist; i < nproc; i++, kp++) {
+ if (!IS_KERNPROC(kp))
+ continue;
+
+ if (strcmp(kp->ki_ocomm, "idle") == 0) {
+ /* single processor system */
+ cpu = 0;
+ } else if (sscanf(kp->ki_ocomm, "idle: cpu%d%n", &cpu, &nchars)
+ == 1 && (u_int)nchars == strlen(kp->ki_ocomm)) {
+ /* MP system */
+ } else
+ /* not an idle process */
+ continue;
+
+ HRDBG("'%s' proc with pid %d is on CPU #%d (last on #%d)",
+ kp->ki_ocomm, kp->ki_pid, kp->ki_oncpu, kp->ki_lastcpu);
+
+ TAILQ_FOREACH(entry, &processor_tbl, link)
+ if (entry->cpu_no == kp->ki_lastcpu)
+ break;
+
+ if (entry == NULL) {
+ /* create entry on non-ACPI systems */
+ if ((entry = proc_create_entry(cpu, NULL)) == NULL)
+ continue;
+
+ detected_processor_count++;
+ }
+
+ entry->idle_pid = kp->ki_pid;
+ HRDBG("CPU no. %d with SNMP index=%d has idle PID %d",
+ entry->cpu_no, entry->index, entry->idle_pid);
+
+ save_sample(entry, plist);
+ }
+}
+
+/**
+ * Scan the device map table for CPUs and create an entry into the
+ * processor table for each CPU. Then fetch the idle PIDs for all CPUs.
+ */
+static void
+create_proc_table(void)
+{
+ struct device_map_entry *map;
+ struct processor_entry *entry;
+ int cpu_no;
+
+ detected_processor_count = 0;
+
+ /*
+ * Because hrProcessorTable depends on hrDeviceTable,
+ * the device detection must be performed at this point.
+ * If not, no entries will be present in the hrProcessor Table.
+ *
+ * For non-ACPI system the processors are not in the device table,
+ * therefor insert them when getting the idle pids. XXX
+ */
+ STAILQ_FOREACH(map, &device_map, link)
+ if (strncmp(map->name_key, "cpu", strlen("cpu")) == 0 &&
+ strstr(map->location_key, ".CPU") != NULL) {
+ if (sscanf(map->name_key,"cpu%d", &cpu_no) != 1) {
+ syslog(LOG_ERR, "hrProcessorTable: Failed to "
+ "get cpu no. from device named '%s'",
+ map->name_key);
+ continue;
+ }
+
+ if ((entry = proc_create_entry(cpu_no, map)) == NULL)
+ continue;
+
+ detected_processor_count++;
+ }
+
+ HRDBG("%d CPUs detected", detected_processor_count);
+
+ processor_get_pids();
+}
+
+/**
+ * Free the processor table
+ */
+static void
+free_proc_table(void)
+{
+ struct processor_entry *n1;
+
+ while ((n1 = TAILQ_FIRST(&processor_tbl)) != NULL) {
+ TAILQ_REMOVE(&processor_tbl, n1, link);
+ free(n1);
+ detected_processor_count--;
+ }
+
+ assert(detected_processor_count == 0);
+ detected_processor_count = 0;
+}
+
+/**
+ * Init the things for hrProcessorTable.
+ * Scan the device table for processor entries.
+ */
+void
+init_processor_tbl(void)
+{
+ size_t len;
+
+ /* get various parameters from the kernel */
+ len = sizeof(ccpu);
+ if (sysctlbyname("kern.ccpu", &ccpu, &len, NULL, 0) == -1) {
+ syslog(LOG_ERR, "hrProcessorTable: sysctl(kern.ccpu) failed");
+ ccpu = 0;
+ }
+
+ len = sizeof(fscale);
+ if (sysctlbyname("kern.fscale", &fscale, &len, NULL, 0) == -1) {
+ syslog(LOG_ERR, "hrProcessorTable: sysctl(kern.fscale) failed");
+ fscale = 0;
+ }
+
+ /* create the initial processor table */
+ create_proc_table();
+}
+
+/**
+ * Finalization routine for hrProcessorTable.
+ * It destroys the lists and frees any allocated heap memory.
+ */
+void
+fini_processor_tbl(void)
+{
+
+ if (cpus_load_timer != NULL) {
+ timer_stop(cpus_load_timer);
+ cpus_load_timer = NULL;
+ }
+
+ free_proc_table();
+}
+
+/**
+ * Make sure that the number of processors announced by the kernel hw.ncpu
+ * is equal to the number of processors we have found in the device table.
+ * If they differ rescan the device table.
+ */
+static void
+processor_refill_tbl(void)
+{
+
+ HRDBG("hw_ncpu=%d detected_processor_count=%d", hw_ncpu,
+ detected_processor_count);
+
+ if (hw_ncpu <= 0) {
+ size_t size = sizeof(hw_ncpu);
+
+ if (sysctlbyname("hw.ncpu", &hw_ncpu, &size, NULL, 0) == -1 ||
+ size != sizeof(hw_ncpu)) {
+ syslog(LOG_ERR, "hrProcessorTable: "
+ "sysctl(hw.ncpu) failed: %m");
+ hw_ncpu = 0;
+ return;
+ }
+ }
+
+ if (hw_ncpu != detected_processor_count) {
+ free_proc_table();
+ create_proc_table();
+ }
+}
+
+/**
+ * Refresh all values in the processor table. We call this once for
+ * every PDU that accesses the table.
+ */
+static void
+refresh_processor_tbl(void)
+{
+ struct processor_entry *entry;
+ int need_pids;
+ struct kinfo_proc *plist;
+ int nproc;
+
+ processor_refill_tbl();
+
+ need_pids = 0;
+ TAILQ_FOREACH(entry, &processor_tbl, link) {
+ if (entry->idle_pid <= 0) {
+ need_pids = 1;
+ continue;
+ }
+
+ assert(hrState_g.kd != NULL);
+
+ plist = kvm_getprocs(hr_kd, KERN_PROC_PID,
+ entry->idle_pid, &nproc);
+ if (plist == NULL || nproc != 1) {
+ syslog(LOG_ERR, "%s: missing item with "
+ "PID = %d for CPU #%d\n ", __func__,
+ entry->idle_pid, entry->cpu_no);
+ need_pids = 1;
+ continue;
+ }
+ save_sample(entry, plist);
+ }
+
+ if (need_pids == 1)
+ processor_get_pids();
+
+ proctbl_tick = this_tick;
+}
+
+/**
+ * This function is called MAX_CPU_SAMPLES times per minute to collect the
+ * CPU load.
+ */
+static void
+get_cpus_samples(void *arg __unused)
+{
+
+ HRDBG("[%llu] ENTER", get_ticks());
+ refresh_processor_tbl();
+ HRDBG("[%llu] EXIT", get_ticks());
+}
+
+/**
+ * Called to start this table. We need to start the periodic idle
+ * time collection.
+ */
+void
+start_processor_tbl(struct lmodule *mod)
+{
+
+ /*
+ * Start the cpu stats collector
+ * The semantics of timer_start parameters is in "SNMP ticks";
+ * we have 100 "SNMP ticks" per second, thus we are trying below
+ * to get MAX_CPU_SAMPLES per minute
+ */
+ cpus_load_timer = timer_start_repeat(100, 100 * 60 / MAX_CPU_SAMPLES,
+ get_cpus_samples, NULL, mod);
+}
+
+/**
+ * Access routine for the processor table.
+ */
+int
+op_hrProcessorTable(struct snmp_context *ctx __unused,
+ struct snmp_value *value, u_int sub, u_int iidx __unused,
+ enum snmp_op curr_op)
+{
+ struct processor_entry *entry;
+
+ if (this_tick != proctbl_tick)
+ refresh_processor_tbl();
+
+ switch (curr_op) {
+
+ case SNMP_OP_GETNEXT:
+ if ((entry = NEXT_OBJECT_INT(&processor_tbl,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ value->var.len = sub + 1;
+ value->var.subs[sub] = entry->index;
+ goto get;
+
+ case SNMP_OP_GET:
+ if ((entry = FIND_OBJECT_INT(&processor_tbl,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ goto get;
+
+ case SNMP_OP_SET:
+ if ((entry = FIND_OBJECT_INT(&processor_tbl,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NO_CREATION);
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ case SNMP_OP_ROLLBACK:
+ case SNMP_OP_COMMIT:
+ abort();
+ }
+ abort();
+
+ get:
+ switch (value->var.subs[sub - 1]) {
+
+ case LEAF_hrProcessorFrwID:
+ value->v.oid = entry->frwId;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrProcessorLoad:
+ value->v.integer = entry->load;
+ return (SNMP_ERR_NOERROR);
+ }
+ abort();
+}
diff --git a/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_scalars.c b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_scalars.c
new file mode 100644
index 0000000..f8f6b47
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_scalars.c
@@ -0,0 +1,514 @@
+/*-
+ * Copyright (c) 2005-2006 The FreeBSD Project
+ * All rights reserved.
+ *
+ * Author: Victor Cruceru <soc-victor@freebsd.org>
+ *
+ * Redistribution of this software and documentation and use in source and
+ * binary forms, with or without modification, are permitted provided that
+ * the following conditions are met:
+ *
+ * 1. Redistributions of source code or documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Host Resources MIB scalars implementation for SNMPd.
+ */
+
+#include <sys/types.h>
+#include <sys/sysctl.h>
+
+#include <assert.h>
+#include <pwd.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <syslog.h>
+#include <utmp.h>
+
+#include "hostres_snmp.h"
+#include "hostres_oid.h"
+#include "hostres_tree.h"
+
+/* file pointer to keep an open instance of utmp */
+static FILE *utmp_fp;
+
+/* boot timestamp in centi-seconds */
+static uint64_t kernel_boot;
+
+/* physical memory size in Kb */
+static uint64_t phys_mem_size;
+
+/* boot line (malloced) */
+static u_char *boot_line;
+
+/* maximum number of processes */
+static uint32_t max_proc;
+
+/**
+ * Free all static data
+ */
+void
+fini_scalars(void)
+{
+
+ free(boot_line);
+
+ if (utmp_fp != NULL)
+ (void)fclose(utmp_fp);
+}
+
+/**
+ * Get system uptime in hundredths of seconds since the epoch
+ * Returns 0 in case of an error
+ */
+static int
+OS_getSystemUptime(uint32_t *ut)
+{
+ struct timeval right_now;
+ uint64_t now;
+
+ if (kernel_boot == 0) {
+ /* first time, do the sysctl */
+ struct timeval kernel_boot_timestamp;
+ int mib[2] = { CTL_KERN, KERN_BOOTTIME };
+ size_t len = sizeof(kernel_boot_timestamp);
+
+ if (sysctl(mib, 2, &kernel_boot_timestamp,
+ &len, NULL, 0) == -1) {
+ syslog(LOG_ERR, "sysctl KERN_BOOTTIME failed: %m");
+ return (SNMP_ERR_GENERR);
+ }
+
+ HRDBG("boot timestamp from kernel: {%ld, %ld}",
+ kernel_boot_timestamp.tv_sec,
+ kernel_boot_timestamp.tv_usec);
+
+ kernel_boot = ((uint64_t)kernel_boot_timestamp.tv_sec * 100) +
+ (kernel_boot_timestamp.tv_usec / 10000);
+ }
+
+ if (gettimeofday(&right_now, NULL) < 0) {
+ syslog(LOG_ERR, "gettimeofday failed: %m");
+ return (SNMP_ERR_GENERR);
+ }
+ now = ((uint64_t)right_now.tv_sec * 100) + (right_now.tv_usec / 10000);
+
+ if (now - kernel_boot > UINT32_MAX)
+ *ut = UINT32_MAX;
+ else
+ *ut = now - kernel_boot;
+
+ return (SNMP_ERR_NOERROR);
+}
+
+/**
+ * Get system local date and time in a foramt suitable for DateAndTime TC:
+ * field octets contents range
+ * ----- ------ -------- -----
+ * 1 1-2 year* 0..65536
+ * 2 3 month 1..12
+ * 3 4 day 1..31
+ * 4 5 hour 0..23
+ * 5 6 minutes 0..59
+ * 6 7 seconds 0..60
+ * (use 60 for leap-second)
+ * 7 8 deci-seconds 0..9
+ * 8 9 direction from UTC '+' / '-'
+ * 9 10 hours from UTC* 0..13
+ * 10 11 minutes from UTC 0..59
+ *
+ * * Notes:
+ * - the value of year is in network-byte order
+ * - daylight saving time in New Zealand is +13
+ *
+ * For example, Tuesday May 26, 1992 at 1:30:15 PM EDT would be
+ * displayed as:
+ *
+ * 1992-5-26,13:30:15.0,-4:0
+ *
+ * Returns -1 in case of an error or the length of the string (8 or 11)
+ * Actually returns always 11 on freebsd
+ */
+static int
+OS_getSystemDate(struct snmp_value *value)
+{
+ u_char s_date_time[11];
+ struct tm tloc_tm;
+ time_t tloc_time_t;
+ struct timeval right_now;
+ int string_len;
+
+ if (gettimeofday(&right_now, NULL) < 0) {
+ syslog(LOG_ERR, "gettimeofday failed: %m");
+ return (SNMP_ERR_GENERR);
+ }
+
+ tloc_time_t = right_now.tv_sec;
+
+ if (localtime_r(&tloc_time_t, &tloc_tm) == NULL) {
+ syslog(LOG_ERR, "localtime_r() failed: %m ");
+ return (SNMP_ERR_GENERR);
+ }
+
+ string_len = make_date_time(s_date_time, &tloc_tm,
+ right_now.tv_usec / 100000);
+
+ return (string_get(value, s_date_time, string_len));
+}
+
+/**
+ * Get kernel boot path. For FreeBSD it seems that no arguments are
+ * present. Returns NULL if an error occured. The returned data is a
+ * pointer to a global strorage.
+ */
+int
+OS_getSystemInitialLoadParameters(u_char **params)
+{
+
+ if (boot_line == NULL) {
+ int mib[2] = { CTL_KERN, KERN_BOOTFILE };
+ char *buf;
+ size_t buf_len = 0;
+
+ /* get the needed buffer len */
+ if (sysctl(mib, 2, NULL, &buf_len, NULL, 0) != 0) {
+ syslog(LOG_ERR,
+ "sysctl({CTL_KERN,KERN_BOOTFILE}) failed: %m");
+ return (SNMP_ERR_GENERR);
+ }
+
+ if ((buf = malloc(buf_len)) == NULL) {
+ syslog(LOG_ERR, "malloc failed");
+ return (SNMP_ERR_GENERR);
+ }
+ if (sysctl(mib, 2, buf, &buf_len, NULL, 0)) {
+ syslog(LOG_ERR,
+ "sysctl({CTL_KERN,KERN_BOOTFILE}) failed: %m");
+ free(buf);
+ return (SNMP_ERR_GENERR);
+ }
+
+ boot_line = buf;
+ HRDBG("kernel boot file: %s", boot_line);
+ }
+
+ *params = boot_line;
+ return (SNMP_ERR_NOERROR);
+}
+
+/**
+ * Get number of current users which are logged in
+ */
+static int
+OS_getSystemNumUsers(uint32_t *nu)
+{
+ struct utmp utmp;
+ static int first_time = 1;
+
+ if (utmp_fp == NULL) {
+ if (!first_time)
+ return (SNMP_ERR_GENERR);
+ first_time = 0;
+ if ((utmp_fp = fopen(_PATH_UTMP, "r")) == NULL) {
+ syslog(LOG_ERR, "fopen(%s) failed: %m", _PATH_UTMP);
+ return (SNMP_ERR_GENERR);
+ }
+ }
+
+ /* start with the begining of the utmp file */
+ (void)rewind(utmp_fp);
+
+ *nu = 0;
+ while (fread(&utmp, sizeof(utmp), 1, utmp_fp) == 1) {
+ if (utmp.ut_name[0] != '\0' && utmp.ut_line[0] != '\0') {
+ if (getpwnam(utmp.ut_name) == NULL)
+ continue;
+ (*nu)++;
+ }
+ }
+
+ return (SNMP_ERR_NOERROR);
+}
+
+/**
+ * Get number of current processes existing into the system
+ */
+static int
+OS_getSystemProcesses(uint32_t *proc_count)
+{
+ int pc;
+
+ if (hr_kd == NULL)
+ return (SNMP_ERR_GENERR);
+
+ if (kvm_getprocs(hr_kd, KERN_PROC_ALL, 0, &pc) == NULL) {
+ syslog(LOG_ERR, "kvm_getprocs failed: %m");
+ return (SNMP_ERR_GENERR);
+ }
+
+ *proc_count = pc;
+ return (SNMP_ERR_NOERROR);
+}
+
+/**
+ * Get maximum number of processes allowed on this system
+ */
+static int
+OS_getSystemMaxProcesses(uint32_t *mproc)
+{
+
+ if (max_proc == 0) {
+ int mib[2] = { CTL_KERN, KERN_MAXPROC };
+ int mp;
+ size_t len = sizeof(mp);
+
+ if (sysctl(mib, 2, &mp, &len, NULL, 0) == -1) {
+ syslog(LOG_ERR, "sysctl KERN_MAXPROC failed: %m");
+ return (SNMP_ERR_GENERR);
+ }
+ max_proc = mp;
+ }
+
+ *mproc = max_proc;
+ return (SNMP_ERR_NOERROR);
+}
+
+/*
+ * Get the physical memeory size in Kbytes.
+ * Returns SNMP error code.
+ */
+static int
+OS_getMemorySize(uint32_t *ms)
+{
+
+ if (phys_mem_size == 0) {
+ int mib[2] = { CTL_HW, HW_PHYSMEM };
+ u_long physmem;
+ size_t len = sizeof(physmem);
+
+ if (sysctl(mib, 2, &physmem, &len, NULL, 0) == -1) {
+ syslog(LOG_ERR,
+ "sysctl({ CTL_HW, HW_PHYSMEM }) failed: %m");
+ return (SNMP_ERR_GENERR);
+ }
+
+ phys_mem_size = physmem / 1024;
+ }
+
+ if (phys_mem_size > UINT32_MAX)
+ *ms = UINT32_MAX;
+ else
+ *ms = phys_mem_size;
+ return (SNMP_ERR_NOERROR);
+}
+
+/*
+ * Try to use the s_date_time parameter as a DateAndTime TC to fill in
+ * the second parameter.
+ * Returns 0 on succes and -1 for an error.
+ * Bug: time zone info is not used
+ */
+static struct timeval *
+OS_checkSystemDateInput(const u_char *str, u_int len)
+{
+ struct tm tm_to_set;
+ time_t t;
+ struct timeval *tv;
+
+ if (len != 8 && len != 11)
+ return (NULL);
+
+ if (str[2] == 0 || str[2] > 12 ||
+ str[3] == 0 || str[3] > 31 ||
+ str[4] > 23 || str[5] > 59 || str[6] > 60 || str[7] > 9)
+ return (NULL);
+
+ tm_to_set.tm_year = ((str[0] << 8) + str[1]) - 1900;
+ tm_to_set.tm_mon = str[2] - 1;
+ tm_to_set.tm_mday = str[3];
+ tm_to_set.tm_hour = str[4];
+ tm_to_set.tm_min = str[5];
+ tm_to_set.tm_sec = str[6];
+ tm_to_set.tm_isdst = 0;
+
+ /* now make UTC from it */
+ if ((t = timegm(&tm_to_set)) == (time_t)-1)
+ return (NULL);
+
+ /* now apply timezone if specified */
+ if (len == 11) {
+ if (str[9] > 13 || str[10] > 59)
+ return (NULL);
+ if (str[8] == '+')
+ t += 3600 * str[9] + 60 * str[10];
+ else
+ t -= 3600 * str[9] + 60 * str[10];
+ }
+
+ if ((tv = malloc(sizeof(*tv))) == NULL)
+ return (NULL);
+
+ tv->tv_sec = t;
+ tv->tv_usec = (int32_t)str[7] * 100000;
+
+ return (tv);
+}
+
+/*
+ * Set system date and time. Timezone is not changed
+ */
+static int
+OS_setSystemDate(const struct timeval *timeval_to_set)
+{
+ if (settimeofday(timeval_to_set, NULL) == -1) {
+ syslog(LOG_ERR, "settimeofday failed: %m");
+ return (SNMP_ERR_GENERR);
+ }
+ return (SNMP_ERR_NOERROR);
+}
+
+/*
+ * prototype of this function was genrated by gensnmptree tool in header file
+ * hostres_tree.h
+ * Returns SNMP_ERR_NOERROR on success
+ */
+int
+op_hrSystem(struct snmp_context *ctx, struct snmp_value *value,
+ u_int sub, u_int iidx __unused, enum snmp_op curr_op)
+{
+ int err;
+ u_char *str;
+
+ switch (curr_op) {
+
+ case SNMP_OP_GET:
+ switch (value->var.subs[sub - 1]) {
+
+ case LEAF_hrSystemUptime:
+ return (OS_getSystemUptime(&value->v.uint32));
+
+ case LEAF_hrSystemDate:
+ return (OS_getSystemDate(value));
+
+ case LEAF_hrSystemInitialLoadDevice:
+ value->v.uint32 = 0; /* FIXME */
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrSystemInitialLoadParameters:
+ if ((err = OS_getSystemInitialLoadParameters(&str)) !=
+ SNMP_ERR_NOERROR)
+ return (err);
+ return (string_get(value, str, -1));
+
+ case LEAF_hrSystemNumUsers:
+ return (OS_getSystemNumUsers(&value->v.uint32));
+
+ case LEAF_hrSystemProcesses:
+ return (OS_getSystemProcesses(&value->v.uint32));
+
+ case LEAF_hrSystemMaxProcesses:
+ return (OS_getSystemMaxProcesses(&value->v.uint32));
+ }
+ abort();
+
+ case SNMP_OP_SET:
+ switch (value->var.subs[sub - 1]) {
+
+ case LEAF_hrSystemDate:
+ if ((ctx->scratch->ptr1 =
+ OS_checkSystemDateInput(value->v.octetstring.octets,
+ value->v.octetstring.len)) == NULL)
+ return (SNMP_ERR_WRONG_VALUE);
+
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrSystemInitialLoadDevice:
+ case LEAF_hrSystemInitialLoadParameters:
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ }
+ abort();
+
+ case SNMP_OP_ROLLBACK:
+ switch (value->var.subs[sub - 1]) {
+
+ case LEAF_hrSystemDate:
+ free(ctx->scratch->ptr1);
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrSystemInitialLoadDevice:
+ case LEAF_hrSystemInitialLoadParameters:
+ abort();
+ }
+ abort();
+
+ case SNMP_OP_COMMIT:
+ switch (value->var.subs[sub - 1]) {
+
+ case LEAF_hrSystemDate:
+ (void)OS_setSystemDate(ctx->scratch->ptr1);
+ free(ctx->scratch->ptr1);
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrSystemInitialLoadDevice:
+ case LEAF_hrSystemInitialLoadParameters:
+ abort();
+ }
+ abort();
+
+ case SNMP_OP_GETNEXT:
+ abort();
+ }
+ abort();
+}
+
+/*
+ * prototype of this function was genrated by gensnmptree tool
+ * in the header file hostres_tree.h
+ * Returns SNMP_ERR_NOERROR on success
+ */
+int
+op_hrStorage(struct snmp_context *ctx __unused, struct snmp_value *value,
+ u_int sub, u_int iidx __unused, enum snmp_op curr_op)
+{
+
+ /* only GET is possible */
+ switch (curr_op) {
+
+ case SNMP_OP_GET:
+ switch (value->var.subs[sub - 1]) {
+
+ case LEAF_hrMemorySize:
+ return (OS_getMemorySize(&value->v.uint32));
+ }
+ abort();
+
+ case SNMP_OP_SET:
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ case SNMP_OP_ROLLBACK:
+ case SNMP_OP_COMMIT:
+ case SNMP_OP_GETNEXT:
+ abort();
+ }
+ abort();
+}
diff --git a/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_snmp.c b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_snmp.c
new file mode 100644
index 0000000..47112da
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_snmp.c
@@ -0,0 +1,209 @@
+/*-
+ * Copyright (c) 2005-2006 The FreeBSD Project
+ * All rights reserved.
+ *
+ * Author: Victor Cruceru <soc-victor@freebsd.org>
+ *
+ * Redistribution of this software and documentation and use in source and
+ * binary forms, with or without modification, are permitted provided that
+ * the following conditions are met:
+ *
+ * 1. Redistributions of source code or documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This C file contains code developed by Poul-Henning Kamp under the
+ * following license:
+ *
+ * FreeBSD: src/sbin/mdconfig/mdconfig.c,v 1.33.2.1 2004/09/14 03:32:21 jmg Exp
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
+ * ----------------------------------------------------------------------------
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Host Resources MIB implementation for bsnmpd.
+ */
+
+#include <paths.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <utmp.h>
+
+#include "hostres_snmp.h"
+#include "hostres_oid.h"
+#include "hostres_tree.h"
+
+/* Internal id got after we'll register this module with the agent */
+static u_int host_registration_id = 0;
+
+/* This our hostres module */
+static struct lmodule *hostres_module;
+
+/* See the generated file hostres_oid.h */
+static const struct asn_oid oid_host = OIDX_host;
+
+/* descriptor to access kernel memory */
+kvm_t *hr_kd;
+
+/*
+ * HOST RESOURCES mib module finalization hook.
+ * Returns 0 on success, < 0 on error
+ */
+static int
+hostres_fini(void)
+{
+
+ if (hr_kd != NULL)
+ (void)kvm_close(hr_kd);
+
+ fini_storage_tbl();
+ fini_fs_tbl();
+ fini_processor_tbl();
+ fini_disk_storage_tbl();
+ fini_device_tbl();
+ fini_partition_tbl();
+ fini_network_tbl();
+ fini_printer_tbl();
+
+ fini_swrun_tbl();
+ fini_swins_tbl();
+
+ fini_scalars();
+
+ if (host_registration_id > 0)
+ or_unregister(host_registration_id);
+
+ HRDBG("done.");
+ return (0);
+}
+
+/*
+ * HOST RESOURCES mib module initialization hook.
+ * Returns 0 on success, < 0 on error
+ */
+static int
+hostres_init(struct lmodule *mod, int argc __unused, char *argv[] __unused)
+{
+
+ hostres_module = mod;
+
+ /*
+ * NOTE: order of these calls is important here!
+ */
+ if ((hr_kd = kvm_open(NULL, _PATH_DEVNULL, NULL, O_RDONLY,
+ "kvm_open")) == NULL) {
+ syslog(LOG_ERR, "kvm_open failed: %m ");
+ return (-1);
+ }
+
+ /*
+ * The order is relevant here, because some table depend on each other.
+ */
+ init_device_tbl();
+
+ /* populates partition table too */
+ if (init_disk_storage_tbl()) {
+ hostres_fini();
+ return (-1);
+ }
+ init_processor_tbl();
+ init_printer_tbl();
+
+ /*
+ * populate storage and FS tables. Must be done after device
+ * initialisation because the FS refresh code calls into the
+ * partition refresh code.
+ */
+ init_storage_tbl();
+
+
+ /* also the hrSWRunPerfTable's support is initialized here */
+ init_swrun_tbl();
+ init_swins_tbl();
+
+ HRDBG("done.");
+
+ return (0);
+}
+
+/*
+ * HOST RESOURCES mib module start operation
+ * returns nothing
+ */
+static void
+hostres_start(void)
+{
+
+ host_registration_id = or_register(&oid_host,
+ "The MIB module for Host Resource MIB (RFC 2790).",
+ hostres_module);
+
+ start_device_tbl(hostres_module);
+ start_processor_tbl(hostres_module);
+ start_network_tbl();
+
+ HRDBG("done.");
+}
+
+/* this identifies the HOST RESOURCES mib module */
+const struct snmp_module config = {
+ "This module implements the host resource mib (rfc 2790)",
+ hostres_init,
+ hostres_fini,
+ NULL, /* idle function, do not use it */
+ NULL,
+ NULL,
+ hostres_start,
+ NULL, /* proxy a PDU */
+ hostres_ctree, /* see the generated hostres_tree.h */
+ hostres_CTREE_SIZE, /* see the generated hostres_tree.h */
+ NULL
+};
+
+/**
+ * Make an SNMP DateAndTime from a struct tm. This should be in the library.
+ */
+int
+make_date_time(u_char *str, const struct tm *tm, u_int decisecs)
+{
+
+ str[0] = (u_char)((tm->tm_year + 1900) >> 8);
+ str[1] = (u_char)(tm->tm_year + 1900);
+ str[2] = tm->tm_mon + 1;
+ str[3] = tm->tm_mday;
+ str[4] = tm->tm_hour;
+ str[5] = tm->tm_min;
+ str[6] = tm->tm_sec;
+ str[7] = decisecs;
+ if (tm->tm_gmtoff < 0)
+ str[8] = '-';
+ else
+ str[8] = '+';
+
+ str[9] = (u_char)(abs(tm->tm_gmtoff) / 3600);
+ str[10] = (u_char)((abs(tm->tm_gmtoff) % 3600) / 60);
+
+ return (11);
+}
diff --git a/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_snmp.h b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_snmp.h
new file mode 100644
index 0000000..acac238
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_snmp.h
@@ -0,0 +1,301 @@
+/*
+ * Copyright (c) 2005-2006 The FreeBSD Project
+ * All rights reserved.
+ *
+ * Author: Victor Cruceru <soc-victor@freebsd.org>
+ *
+ * Redistribution of this software and documentation and use in source and
+ * binary forms, with or without modification, are permitted provided that
+ * the following conditions are met:
+ *
+ * 1. Redistributions of source code or documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Host Resources MIB for SNMPd.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef HOSTRES_SNMP_H_1132245017
+#define HOSTRES_SNMP_H_1132245017
+
+#include <sys/types.h>
+#include <sys/queue.h>
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <kvm.h>
+#include <devinfo.h>
+
+#include <bsnmp/asn1.h>
+#include <bsnmp/snmp.h>
+
+#include <bsnmp/snmpmod.h>
+
+/*
+ * Default package directory for hrSWInstalledTable. Can be overridden
+ * via SNMP or configuration file.
+ */
+#define PATH_PKGDIR "/var/db/pkg"
+
+/*
+ * These are the default maximum caching intervals for the various tables
+ * in seconds. They can be overridden from the configuration file.
+ */
+#define HR_STORAGE_TBL_REFRESH 7
+#define HR_FS_TBL_REFRESH 7
+#define HR_DISK_TBL_REFRESH 7
+#define HR_NETWORK_TBL_REFRESH 7
+#define HR_SWINS_TBL_REFRESH 120
+#define HR_SWRUN_TBL_REFRESH 3
+
+struct tm;
+struct statfs;
+
+/* a debug macro */
+#ifndef NDEBUG
+
+#define HRDBG(...) do { \
+ fprintf(stderr, "HRDEBUG: %s: ", __func__); \
+ fprintf(stderr, __VA_ARGS__); \
+ fprintf(stderr, "\n"); \
+ } while (0)
+
+#else
+
+#define HRDBG(...) do { } while (0)
+
+#endif /*NDEBUG*/
+
+/* path to devd(8) output pipe */
+#define PATH_DEVD_PIPE "/var/run/devd.pipe"
+
+#define IS_KERNPROC(kp) (((kp)->ki_flag & P_KTHREAD) == P_KTHREAD)
+
+enum snmpTCTruthValue {
+ SNMP_TRUE = 1,
+ SNMP_FALSE= 2
+};
+
+/* The number of CPU load samples per one minute, per each CPU */
+#define MAX_CPU_SAMPLES 4
+
+/*
+ * This structure is used to hold a SNMP table entry
+ * for HOST-RESOURCES-MIB's hrDeviceTable
+ */
+struct device_entry {
+ int32_t index;
+ struct asn_oid type;
+ u_char descr[64 + 1];
+ struct asn_oid id;
+ int32_t status; /* enum DeviceStatus */
+ uint32_t errors;
+
+#define HR_DEVICE_FOUND 0x001
+ /* not dectected by libdevice, so don't try to refresh it*/
+#define HR_DEVICE_IMMUTABLE 0x002
+
+ /* next 3 are not from the SNMP mib table, only to be used internally */
+ uint32_t flags;
+ u_char name[32 + 1];
+ u_char location[128 + 1];
+ TAILQ_ENTRY(device_entry) link;
+};
+
+/*
+ * Next structure is used to keep o list of mappings from a specific
+ * name (a_name) to an entry in the hrFSTblEntry;
+ * We are trying to keep the same index for a specific name at least
+ * for the duration of one SNMP agent run.
+ */
+struct device_map_entry {
+ int32_t hrIndex; /* used for hrDeviceTblEntry::index */
+
+ /* map key is the pair (name_key, location_key) */
+ u_char name_key[32 + 1]; /* copy of device name */
+ u_char location_key[128 + 1];
+
+ /*
+ * Next may be NULL if the respective hrDeviceTblEntry
+ * is (temporally) gone.
+ */
+ struct device_entry *entry_p;
+ STAILQ_ENTRY(device_map_entry) link;
+};
+STAILQ_HEAD(device_map, device_map_entry);
+
+/* descriptor to access kernel memory */
+extern kvm_t *hr_kd;
+
+/* Table used for consistent device table indexing. */
+extern struct device_map device_map;
+
+/* Maximum number of ticks between two updates for hrStorageTable */
+extern uint32_t storage_tbl_refresh;
+
+/* Maximum number of ticks between updated of FS table */
+extern uint32_t fs_tbl_refresh;
+
+/* maximum number of ticks between updates of SWRun and SWRunPerf table */
+extern uint32_t swrun_tbl_refresh;
+
+/* Maximum number of ticks between device table refreshs. */
+extern uint32_t device_tbl_refresh;
+
+/* maximum number of ticks between refreshs */
+extern uint32_t disk_storage_tbl_refresh;
+
+/* maximum number of ticks between updates of network table */
+extern uint32_t swins_tbl_refresh;
+
+/* maximum number of ticks between updates of network table */
+extern uint32_t network_tbl_refresh;
+
+/* package directory */
+extern u_char *pkg_dir;
+
+/* Initialize and populate storage table */
+void init_storage_tbl(void);
+
+/* Finalization routine for hrStorageTable. */
+void fini_storage_tbl(void);
+
+/* Refresh routine for hrStorageTable. */
+void refresh_storage_tbl(int);
+
+/*
+ * Get the type of filesystem referenced in a struct statfs * -
+ * used by FSTbl and StorageTbl functions.
+ */
+const struct asn_oid *fs_get_type(const struct statfs *);
+
+/*
+ * Because hrFSTable depends to hrStorageTable we are
+ * refreshing hrFSTable by refreshing hrStorageTable.
+ * When one entry "of type" fs from hrStorageTable is refreshed
+ * then the corresponding entry from hrFSTable is refreshed
+ * FS_tbl_pre_refresh_v() is called before refeshing fs part of hrStorageTable
+ */
+void fs_tbl_pre_refresh(void);
+void fs_tbl_process_statfs_entry(const struct statfs *, int32_t);
+
+/* Called after refreshing fs part of hrStorageTable */
+void fs_tbl_post_refresh(void);
+
+/* Refresh the FS table if neccessary. */
+void refresh_fs_tbl(void);
+
+/* Finalization routine for hrFSTable. */
+void fini_fs_tbl(void);
+
+/* Init the things for both of hrSWRunTable and hrSWRunPerfTable */
+void init_swrun_tbl(void);
+
+/* Finalization routine for both of hrSWRunTable and hrSWRunPerfTable */
+void fini_swrun_tbl(void);
+
+/* Init and populate hrDeviceTable */
+void init_device_tbl(void);
+
+/* start devd monitoring */
+void start_device_tbl(struct lmodule *);
+
+/* Finalization routine for hrDeviceTable */
+void fini_device_tbl(void);
+
+/* Refresh routine for hrDeviceTable. */
+void refresh_device_tbl(int);
+
+/* Find an item in hrDeviceTbl by its entry->index. */
+struct device_entry *device_find_by_index(int32_t);
+
+/* Find an item in hrDeviceTbl by name. */
+struct device_entry *device_find_by_name(const char *);
+
+/* Create a new entry out of thin air. */
+struct device_entry *device_entry_create(const char *, const char *,
+ const char *);
+
+/* Init the things for hrProcessorTable. */
+void init_processor_tbl(void);
+
+/* Finalization routine for hrProcessorTable. */
+void fini_processor_tbl(void);
+
+/* Start the processor table CPU load collector. */
+void start_processor_tbl(struct lmodule *);
+
+/* Init the things for hrDiskStorageTable */
+int init_disk_storage_tbl(void);
+
+/* Finalization routine for hrDiskStorageTable. */
+void fini_disk_storage_tbl(void);
+
+/* Refresh routine for hrDiskStorageTable. */
+void refresh_disk_storage_tbl(int);
+
+/* Finalization routine for hrPartitionTable. */
+void fini_partition_tbl(void);
+
+/* Finalization routine for hrNetworkTable. */
+void fini_network_tbl(void);
+
+/* populate network table */
+void start_network_tbl(void);
+
+/* initialize installed software table */
+void init_swins_tbl(void);
+
+/* finalize installed software table */
+void fini_swins_tbl(void);
+
+/* refresh the hrSWInstalledTable if necessary */
+void refresh_swins_tbl(void);
+
+/* Init the things for hrPrinterTable */
+void init_printer_tbl(void);
+
+/* Finalization routine for hrPrinterTable. */
+void fini_printer_tbl(void);
+
+/* Refresh printer table */
+void refresh_printer_tbl(void);
+
+/* get boot command line */
+int OS_getSystemInitialLoadParameters(u_char **);
+
+/* Start refreshing the partition table */
+void partition_tbl_post_refresh(void);
+
+/* Handle refresh for the given disk */
+void partition_tbl_handle_disk(int32_t, const char *);
+
+/* Finish refreshing the partition table. */
+void partition_tbl_pre_refresh(void);
+
+/* Set the FS index in a partition table entry */
+void handle_partition_fs_index(const char *, int32_t);
+
+/* Make an SNMP DateAndTime from a struct tm. */
+int make_date_time(u_char *, const struct tm *, u_int);
+
+/* Free all static data */
+void fini_scalars(void);
+
+#endif /* HOSTRES_SNMP_H_1132245017 */
diff --git a/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_storage_tbl.c b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_storage_tbl.c
new file mode 100644
index 0000000..851d0f7
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_storage_tbl.c
@@ -0,0 +1,648 @@
+/*-
+ * Copyright (c) 2005-2006 The FreeBSD Project
+ * All rights reserved.
+ *
+ * Author: Victor Cruceru <soc-victor@freebsd.org>
+ *
+ * Redistribution of this software and documentation and use in source and
+ * binary forms, with or without modification, are permitted provided that
+ * the following conditions are met:
+ *
+ * 1. Redistributions of source code or documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Host Resources MIB for SNMPd. Implementation for hrStorageTable
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <sys/vmmeter.h>
+#include <sys/mount.h>
+
+#include <vm/vm_param.h>
+
+#include <assert.h>
+#include <err.h>
+#include <limits.h>
+#include <memstat.h>
+#include <paths.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h> /*for getpagesize()*/
+
+#include "hostres_snmp.h"
+#include "hostres_oid.h"
+#include "hostres_tree.h"
+
+/*
+ * This structure is used to hold a SNMP table entry
+ * for HOST-RESOURCES-MIB's hrStorageTable
+ */
+struct storage_entry {
+ int32_t index;
+ struct asn_oid type;
+ u_char descr[255 + 1];
+ int32_t allocationUnits;
+ int32_t size;
+ int32_t used;
+ uint32_t allocationFailures;
+#define HR_STORAGE_FOUND 0x001
+ uint32_t flags; /* to be used internally*/
+ TAILQ_ENTRY(storage_entry) link;
+};
+TAILQ_HEAD(storage_tbl, storage_entry);
+
+/*
+ * Next structure is used to keep o list of mappings from a specific name
+ * (a_name) to an entry in the hrStorageTblEntry. We are trying to keep the
+ * same index for a specific name at least for the duration of one SNMP agent
+ * run.
+ */
+struct storage_map_entry {
+ int32_t hrIndex; /* used for hrStorageTblEntry::index */
+
+ /* map key, also used for hrStorageTblEntry::descr */
+ u_char a_name[255 + 1];
+
+ /*
+ * next may be NULL if the respective hrStorageTblEntry
+ * is (temporally) gone
+ */
+ struct storage_entry *entry;
+ STAILQ_ENTRY(storage_map_entry) link;
+};
+STAILQ_HEAD(storage_map, storage_map_entry);
+
+/* the head of the list with table's entries */
+static struct storage_tbl storage_tbl = TAILQ_HEAD_INITIALIZER(storage_tbl);
+
+/*for consistent table indexing*/
+static struct storage_map storage_map =
+ STAILQ_HEAD_INITIALIZER(storage_map);
+
+/* last (agent) tick when hrStorageTable was updated */
+static uint64_t storage_tick;
+
+/* maximum number of ticks between two refreshs */
+uint32_t storage_tbl_refresh = HR_STORAGE_TBL_REFRESH * 100;
+
+/* for kvm_getswapinfo, malloc'd */
+static struct kvm_swap *swap_devs;
+static size_t swap_devs_len; /* item count for swap_devs */
+
+/* for getfsstat, malloc'd */
+static struct statfs *fs_buf;
+static size_t fs_buf_count; /* item count for fs_buf */
+
+static struct vmtotal mem_stats;
+
+/* next int available for indexing the hrStorageTable */
+static uint32_t next_storage_index = 1;
+
+/* start of list for memory detailed stats */
+static struct memory_type_list *mt_list;
+
+/* Constants */
+static const struct asn_oid OIDX_hrStorageRam_c = OIDX_hrStorageRam;
+static const struct asn_oid OIDX_hrStorageVirtualMemory_c =
+ OIDX_hrStorageVirtualMemory;
+
+/**
+ * Create a new entry into the storage table and, if neccessary, an
+ * entry into the storage map.
+ */
+static struct storage_entry *
+storage_entry_create(const char *name)
+{
+ struct storage_entry *entry;
+ struct storage_map_entry *map;
+
+ if ((entry = malloc(sizeof(*entry))) == NULL) {
+ syslog(LOG_WARNING, "%s: %m", __func__);
+ return (NULL);
+ }
+
+ strlcpy(entry->descr, name, sizeof(entry->descr));
+
+ STAILQ_FOREACH(map, &storage_map, link)
+ if (strcmp(map->a_name, entry->descr) == 0) {
+ entry->index = map->hrIndex;
+ map->entry = entry;
+ break;
+ }
+
+ if (map == NULL) {
+ /* new object - get a new index */
+ if (next_storage_index > INT_MAX) {
+ syslog(LOG_ERR,
+ "%s: hrStorageTable index wrap", __func__);
+ free(entry);
+ return (NULL);
+ }
+
+ if ((map = malloc(sizeof(*map))) == NULL) {
+ syslog(LOG_ERR, "hrStorageTable: %s: %m", __func__ );
+ free(entry);
+ return (NULL);
+ }
+
+ map->hrIndex = next_storage_index ++;
+ strlcpy(map->a_name, entry->descr, sizeof(map->a_name));
+ map->entry = entry;
+
+ STAILQ_INSERT_TAIL(&storage_map, map, link);
+
+ HRDBG("%s added into hrStorageMap at index=%d",
+ name, map->hrIndex);
+ } else {
+ HRDBG("%s exists in hrStorageMap index=%d\n",
+ name, map->hrIndex);
+ }
+
+ entry->index = map->hrIndex;
+
+ INSERT_OBJECT_INT(entry, &storage_tbl);
+
+ return (entry);
+}
+
+/**
+ * Delete an entry from the storage table.
+ */
+static void
+storage_entry_delete(struct storage_entry *entry)
+{
+ struct storage_map_entry *map;
+
+ assert(entry != NULL);
+
+ TAILQ_REMOVE(&storage_tbl, entry, link);
+ STAILQ_FOREACH(map, &storage_map, link)
+ if (map->entry == entry) {
+ map->entry = NULL;
+ break;
+ }
+
+ free(entry);
+}
+
+/**
+ * Find a table entry by its name.
+ */
+static struct storage_entry *
+storage_find_by_name(const char *name)
+{
+ struct storage_entry *entry;
+
+ TAILQ_FOREACH(entry, &storage_tbl, link)
+ if (strncmp(entry->descr, name,
+ sizeof(entry->descr) - 1) == 0)
+ return (entry);
+
+ return (NULL);
+}
+
+/*
+ * VM info.
+ */
+static void
+storage_OS_get_vm(void)
+{
+ int mib[2] = { CTL_VM, VM_TOTAL };
+ size_t len = sizeof(mem_stats);
+ int page_size_bytes;
+ struct storage_entry *entry;
+
+ if (sysctl(mib, 2, &mem_stats, &len, NULL, 0) < 0) {
+ syslog(LOG_ERR,
+ "hrStoragetable: %s: sysctl({CTL_VM, VM_METER}) "
+ "failed: %m", __func__);
+ assert(0);
+ return;
+ }
+
+ page_size_bytes = getpagesize();
+
+ /* Real Memory Metrics */
+ if ((entry = storage_find_by_name("Real Memory Metrics")) == NULL &&
+ (entry = storage_entry_create("Real Memory Metrics")) == NULL)
+ return; /* I'm out of luck now, maybe next time */
+
+ entry->flags |= HR_STORAGE_FOUND;
+ entry->type = OIDX_hrStorageRam_c;
+ entry->allocationUnits = page_size_bytes;
+ entry->size = mem_stats.t_rm;
+ entry->used = mem_stats.t_arm; /* ACTIVE is not USED - FIXME */
+ entry->allocationFailures = 0;
+
+ /* Shared Real Memory Metrics */
+ if ((entry = storage_find_by_name("Shared Real Memory Metrics")) ==
+ NULL &&
+ (entry = storage_entry_create("Shared Real Memory Metrics")) ==
+ NULL)
+ return;
+
+ entry->flags |= HR_STORAGE_FOUND;
+ entry->type = OIDX_hrStorageRam_c;
+ entry->allocationUnits = page_size_bytes;
+ entry->size = mem_stats.t_rmshr;
+ /* ACTIVE is not USED - FIXME */
+ entry->used = mem_stats.t_armshr;
+ entry->allocationFailures = 0;
+}
+
+static void
+storage_OS_get_memstat(void)
+{
+ struct memory_type *mt_item;
+ struct storage_entry *entry;
+
+ if (mt_list == NULL) {
+ if ((mt_list = memstat_mtl_alloc()) == NULL)
+ /* again? we have a serious problem */
+ return;
+ }
+
+ if (memstat_sysctl_all(mt_list, 0) < 0) {
+ syslog(LOG_ERR, "memstat_sysctl_all failed: %s",
+ memstat_strerror(memstat_mtl_geterror(mt_list)) );
+ return;
+ }
+
+ if ((mt_item = memstat_mtl_first(mt_list)) == NULL) {
+ /* usually this is not an error, no errno for this failure*/
+ HRDBG("memstat_mtl_first failed");
+ return;
+ }
+
+ do {
+ const char *memstat_name;
+ uint64_t tmp_size;
+ int allocator;
+ char alloc_descr[255 + 1];
+
+ memstat_name = memstat_get_name(mt_item);
+
+ if (memstat_name == NULL || strlen(memstat_name) == 0)
+ continue;
+
+ switch (allocator = memstat_get_allocator(mt_item)) {
+
+ case ALLOCATOR_MALLOC:
+ snprintf(alloc_descr, sizeof(alloc_descr),
+ "MALLOC: %s", memstat_name);
+ break;
+
+ case ALLOCATOR_UMA:
+ snprintf(alloc_descr, sizeof(alloc_descr),
+ "UMA: %s", memstat_name);
+ break;
+
+ default:
+ snprintf(alloc_descr, sizeof(alloc_descr),
+ "UNKNOWN%d: %s", allocator, memstat_name);
+ break;
+ }
+
+ if ((entry = storage_find_by_name(alloc_descr)) == NULL &&
+ (entry = storage_entry_create(alloc_descr)) == NULL)
+ return;
+
+ entry->flags |= HR_STORAGE_FOUND;
+ entry->type = OIDX_hrStorageRam_c;
+
+ if ((tmp_size = memstat_get_size(mt_item)) == 0)
+ tmp_size = memstat_get_sizemask(mt_item);
+ entry->allocationUnits =
+ (tmp_size > INT_MAX ? INT_MAX : (int32_t)tmp_size);
+
+ tmp_size = memstat_get_countlimit(mt_item);
+ entry->size =
+ (tmp_size > INT_MAX ? INT_MAX : (int32_t)tmp_size);
+
+ tmp_size = memstat_get_count(mt_item);
+ entry->used =
+ (tmp_size > INT_MAX ? INT_MAX : (int32_t)tmp_size);
+
+ tmp_size = memstat_get_failures(mt_item);
+ entry->allocationFailures =
+ (tmp_size > INT_MAX ? INT_MAX : (int32_t)tmp_size);
+
+ } while((mt_item = memstat_mtl_next(mt_item)) != NULL);
+}
+
+/**
+ * Get swap info
+ */
+static void
+storage_OS_get_swap(void)
+{
+ int nswapdev = 0;
+ size_t len = sizeof(nswapdev);
+ struct storage_entry *entry;
+ char swap_w_prefix[255 + 1];
+
+ if (sysctlbyname("vm.nswapdev", &nswapdev, &len, NULL,0 ) < 0) {
+ syslog(LOG_ERR,
+ "hrStorageTable: sysctlbyname(\"vm.nswapdev\") "
+ "failed. %m");
+ assert(0);
+ return;
+ }
+
+ if (nswapdev <= 0) {
+ HRDBG("vm.nswapdev is %d", nswapdev);
+ return;
+ }
+
+ if (nswapdev + 1 != (int)swap_devs_len || swap_devs == NULL) {
+ swap_devs_len = nswapdev + 1;
+ swap_devs = reallocf(swap_devs,
+ swap_devs_len * sizeof(struct kvm_swap));
+
+ assert(swap_devs != NULL);
+ if (swap_devs == NULL) {
+ swap_devs_len = 0;
+ return;
+ }
+ }
+
+ nswapdev = kvm_getswapinfo(hr_kd, swap_devs, swap_devs_len, 0);
+ if (nswapdev < 0) {
+ syslog(LOG_ERR,
+ "hrStorageTable: kvm_getswapinfo failed. %m\n");
+ assert(0);
+ return;
+ }
+
+ for (len = 0; len < (size_t)nswapdev; len++) {
+ memset(&swap_w_prefix[0], '\0', sizeof(swap_w_prefix));
+ snprintf(swap_w_prefix, sizeof(swap_w_prefix) - 1,
+ "Swap:%s%s", _PATH_DEV, swap_devs[len].ksw_devname);
+
+ entry = storage_find_by_name(swap_w_prefix);
+ if (entry == NULL)
+ entry = storage_entry_create(swap_w_prefix);
+
+ assert (entry != NULL);
+ if (entry == NULL)
+ return; /* Out of luck */
+
+ entry->flags |= HR_STORAGE_FOUND;
+ entry->type = OIDX_hrStorageVirtualMemory_c;
+ entry->allocationUnits = getpagesize();
+ entry->size = swap_devs[len].ksw_total;
+ entry->used = swap_devs[len].ksw_used;
+ entry->allocationFailures = 0;
+ }
+}
+
+/**
+ * Query the underlaying OS for the mounted file systems
+ * anf fill in the respective lists (for hrStorageTable and for hrFSTable)
+ */
+static void
+storage_OS_get_fs(void)
+{
+ struct storage_entry *entry;
+ uint64_t used_blocks_count = 0;
+ char fs_string[255+1];
+ int mounted_fs_count;
+ int i = 0;
+
+ if ((mounted_fs_count = getfsstat(NULL, 0, MNT_NOWAIT)) < 0) {
+ syslog(LOG_ERR, "hrStorageTable: getfsstat() failed: %m");
+ return; /* out of luck this time */
+ }
+
+ if (mounted_fs_count != (int)fs_buf_count || fs_buf == NULL) {
+ fs_buf_count = mounted_fs_count;
+ fs_buf = reallocf(fs_buf, fs_buf_count * sizeof(struct statfs));
+ if (fs_buf == NULL) {
+ fs_buf_count = 0;
+ assert(0);
+ return;
+ }
+ }
+
+ if ((mounted_fs_count = getfsstat(fs_buf,
+ fs_buf_count * sizeof(struct statfs), MNT_NOWAIT)) < 0) {
+ syslog(LOG_ERR, "hrStorageTable: getfsstat() failed: %m");
+ return; /* out of luck this time */
+ }
+
+ HRDBG("got %d mounted FS", mounted_fs_count);
+
+ fs_tbl_pre_refresh();
+
+ for (i = 0; i < mounted_fs_count; i++) {
+ snprintf(fs_string, sizeof(fs_string),
+ "%s, type: %s, dev: %s", fs_buf[i].f_mntonname,
+ fs_buf[i].f_fstypename, fs_buf[i].f_mntfromname);
+
+ entry = storage_find_by_name(fs_string);
+ if (entry == NULL)
+ entry = storage_entry_create(fs_string);
+
+ assert (entry != NULL);
+ if (entry == NULL)
+ return; /* Out of luck */
+
+ entry->flags |= HR_STORAGE_FOUND;
+ entry->type = *fs_get_type(&fs_buf[i]);
+
+ if (fs_buf[i].f_bsize > INT_MAX)
+ entry->allocationUnits = INT_MAX;
+ else
+ entry->allocationUnits = fs_buf[i].f_bsize;
+
+ if (fs_buf[i].f_blocks > INT_MAX)
+ entry->size = INT_MAX;
+ else
+ entry->size = fs_buf[i].f_blocks;
+
+ used_blocks_count = fs_buf[i].f_blocks - fs_buf[i].f_bfree;
+
+ if (used_blocks_count > INT_MAX)
+ entry->used = INT_MAX;
+ else
+ entry->used = used_blocks_count;
+
+ entry->allocationFailures = 0;
+
+ /* take care of hrFSTable */
+ fs_tbl_process_statfs_entry(&fs_buf[i], entry->index);
+ }
+
+ fs_tbl_post_refresh();
+}
+
+/**
+ * Initialize storage table and populate it.
+ */
+void
+init_storage_tbl(void)
+{
+ if ((mt_list = memstat_mtl_alloc()) == NULL)
+ syslog(LOG_ERR,
+ "hrStorageTable: memstat_mtl_alloc() failed: %m");
+
+ refresh_storage_tbl(1);
+}
+
+void
+fini_storage_tbl(void)
+{
+ struct storage_map_entry *n1;
+
+ if (swap_devs != NULL) {
+ free(swap_devs);
+ swap_devs = NULL;
+ }
+ swap_devs_len = 0;
+
+ if (fs_buf != NULL) {
+ free(fs_buf);
+ fs_buf = NULL;
+ }
+ fs_buf_count = 0;
+
+ while ((n1 = STAILQ_FIRST(&storage_map)) != NULL) {
+ STAILQ_REMOVE_HEAD(&storage_map, link);
+ if (n1->entry != NULL) {
+ TAILQ_REMOVE(&storage_tbl, n1->entry, link);
+ free(n1->entry);
+ }
+ free(n1);
+ }
+ assert(TAILQ_EMPTY(&storage_tbl));
+}
+
+void
+refresh_storage_tbl(int force)
+{
+ struct storage_entry *entry, *entry_tmp;
+
+ if (!force && storage_tick != 0 &&
+ this_tick - storage_tick < storage_tbl_refresh) {
+ HRDBG("no refresh needed");
+ return;
+ }
+
+ /* mark each entry as missing */
+ TAILQ_FOREACH(entry, &storage_tbl, link)
+ entry->flags &= ~HR_STORAGE_FOUND;
+
+ storage_OS_get_vm();
+ storage_OS_get_swap();
+ storage_OS_get_fs();
+ storage_OS_get_memstat();
+
+ /*
+ * Purge items that disappeared
+ */
+ TAILQ_FOREACH_SAFE(entry, &storage_tbl, link, entry_tmp)
+ if (!(entry->flags & HR_STORAGE_FOUND))
+ storage_entry_delete(entry);
+
+ storage_tick = this_tick;
+
+ HRDBG("refresh DONE");
+}
+
+/*
+ * This is the implementation for a generated (by our SNMP tool)
+ * function prototype, see hostres_tree.h
+ * It handles the SNMP operations for hrStorageTable
+ */
+int
+op_hrStorageTable(struct snmp_context *ctx __unused, struct snmp_value *value,
+ u_int sub, u_int iidx __unused, enum snmp_op curr_op)
+{
+ struct storage_entry *entry;
+
+ refresh_storage_tbl(0);
+
+ switch (curr_op) {
+
+ case SNMP_OP_GETNEXT:
+ if ((entry = NEXT_OBJECT_INT(&storage_tbl,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+
+ value->var.len = sub + 1;
+ value->var.subs[sub] = entry->index;
+ goto get;
+
+ case SNMP_OP_GET:
+ if ((entry = FIND_OBJECT_INT(&storage_tbl,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ goto get;
+
+ case SNMP_OP_SET:
+ if ((entry = FIND_OBJECT_INT(&storage_tbl,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NO_CREATION);
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ case SNMP_OP_ROLLBACK:
+ case SNMP_OP_COMMIT:
+ abort();
+ }
+ abort();
+
+ get:
+ switch (value->var.subs[sub - 1]) {
+
+ case LEAF_hrStorageIndex:
+ value->v.integer = entry->index;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrStorageType:
+ value->v.oid = entry->type;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrStorageDescr:
+ return (string_get(value, entry->descr, -1));
+ break;
+
+ case LEAF_hrStorageAllocationUnits:
+ value->v.integer = entry->allocationUnits;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrStorageSize:
+ value->v.integer = entry->size;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrStorageUsed:
+ value->v.integer = entry->used;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrStorageAllocationFailures:
+ value->v.uint32 = entry->allocationFailures;
+ return (SNMP_ERR_NOERROR);
+ }
+ abort();
+}
diff --git a/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_swinstalled_tbl.c b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_swinstalled_tbl.c
new file mode 100644
index 0000000..1c21a9f
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_swinstalled_tbl.c
@@ -0,0 +1,528 @@
+/*
+ * Copyright (c) 2005-2006 The FreeBSD Project
+ * All rights reserved.
+ *
+ * Author: Victor Cruceru <soc-victor@freebsd.org>
+ *
+ * Redistribution of this software and documentation and use in source and
+ * binary forms, with or without modification, are permitted provided that
+ * the following conditions are met:
+ *
+ * 1. Redistributions of source code or documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ *
+ * Host Resources MIB implementation for SNMPd: instrumentation for
+ * hrSWInstalledTable
+ */
+
+#include <sys/limits.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <sys/utsname.h>
+
+#include <assert.h>
+#include <dirent.h>
+#include <err.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+
+#include "hostres_snmp.h"
+#include "hostres_oid.h"
+#include "hostres_tree.h"
+
+#define CONTENTS_FNAME "+CONTENTS"
+
+enum SWInstalledType {
+ SWI_UNKNOWN = 1,
+ SWI_OPERATING_SYSTEM = 2,
+ SWI_DEVICE_DRIVER = 3,
+ SWI_APPLICATION = 4
+};
+
+#define NAMELEN 64 /* w/o \0 */
+
+/*
+ * This structure is used to hold a SNMP table entry
+ * for HOST-RESOURCES-MIB's hrSWInstalledTable
+ */
+struct swins_entry {
+ int32_t index;
+ u_char name[NAMELEN + 1];
+ struct asn_oid id;
+ int32_t type; /* from enum SWInstalledType */
+ u_char date[11];
+ u_int date_len;
+
+#define HR_SWINSTALLED_FOUND 0x001
+#define HR_SWINSTALLED_IMMUTABLE 0x002
+ uint32_t flags;
+
+ TAILQ_ENTRY(swins_entry) link;
+};
+TAILQ_HEAD(swins_tbl, swins_entry);
+
+/*
+ * Table to keep a conistent mapping between software and indexes.
+ */
+struct swins_map_entry {
+ int32_t index; /* hrSWInstalledTblEntry::index */
+ u_char name[NAMELEN + 1]; /* map key */
+
+ /*
+ * next may be NULL if the respective hrSWInstalledTblEntry
+ * is (temporally) gone
+ */
+ struct swins_entry *entry;
+
+ STAILQ_ENTRY(swins_map_entry) link;
+};
+STAILQ_HEAD(swins_map, swins_map_entry);
+
+/* map for consistent indexing */
+static struct swins_map swins_map = STAILQ_HEAD_INITIALIZER(swins_map);
+
+/* the head of the list with hrSWInstalledTable's entries */
+static struct swins_tbl swins_tbl = TAILQ_HEAD_INITIALIZER(swins_tbl);
+
+/* next int available for indexing the hrSWInstalledTable */
+static uint32_t next_swins_index = 1;
+
+/* last (agent) tick when hrSWInstalledTable was updated */
+static uint64_t swins_tick;
+
+/* maximum number of ticks between updates of network table */
+uint32_t swins_tbl_refresh = HR_SWINS_TBL_REFRESH * 100;
+
+/* package directory */
+u_char *pkg_dir;
+
+/* last change of package list */
+static time_t os_pkg_last_change;
+
+/**
+ * Create a new entry into the hrSWInstalledTable
+ */
+static struct swins_entry *
+swins_entry_create(const char *name)
+{
+ struct swins_entry *entry;
+ struct swins_map_entry *map;
+
+ if ((entry = malloc(sizeof(*entry))) == NULL) {
+ syslog(LOG_WARNING, "%s: %m", __func__);
+ return (NULL);
+ }
+ memset(entry, 0, sizeof(*entry));
+ strlcpy((char*)entry->name, name, sizeof(entry->name));
+
+ STAILQ_FOREACH(map, &swins_map, link)
+ if (strcmp((const char *)map->name,
+ (const char *)entry->name) == 0)
+ break;
+
+ if (map == NULL) {
+ /* new object - get a new index */
+ if (next_swins_index > INT_MAX) {
+ syslog(LOG_ERR, "%s: hrSWInstalledTable index wrap",
+ __func__ );
+ free(entry);
+ return (NULL);
+ }
+
+ if ((map = malloc(sizeof(*map))) == NULL) {
+ syslog(LOG_ERR, "%s: %m", __func__ );
+ free(entry);
+ return (NULL);
+ }
+ map->index = next_swins_index++;
+ strcpy((char *)map->name, (const char *)entry->name);
+
+ STAILQ_INSERT_TAIL(&swins_map, map, link);
+
+ HRDBG("%s added into hrSWInstalled at %d", name, map->index);
+ }
+ entry->index = map->index;
+ map->entry = entry;
+
+ INSERT_OBJECT_INT(entry, &swins_tbl);
+
+ return (entry);
+}
+
+/**
+ * Delete an entry in the hrSWInstalledTable
+ */
+static void
+swins_entry_delete(struct swins_entry *entry)
+{
+ struct swins_map_entry *map;
+
+ assert(entry != NULL);
+
+ TAILQ_REMOVE(&swins_tbl, entry, link);
+
+ STAILQ_FOREACH(map, &swins_map, link)
+ if (map->entry == entry) {
+ map->entry = NULL;
+ break;
+ }
+
+ free(entry);
+}
+
+/**
+ * Find an entry given it's name
+ */
+static struct swins_entry *
+swins_find_by_name(const char *name)
+{
+ struct swins_entry *entry;
+
+ TAILQ_FOREACH(entry, &swins_tbl, link)
+ if (strncmp((const char*)entry->name, name,
+ sizeof(entry->name) - 1) == 0)
+ return (entry);
+ return (NULL);
+}
+
+/**
+ * Finalize this table
+ */
+void
+fini_swins_tbl(void)
+{
+ struct swins_map_entry *n1;
+
+ while ((n1 = STAILQ_FIRST(&swins_map)) != NULL) {
+ STAILQ_REMOVE_HEAD(&swins_map, link);
+ if (n1->entry != NULL) {
+ TAILQ_REMOVE(&swins_tbl, n1->entry, link);
+ free(n1->entry);
+ }
+ free(n1);
+ }
+ assert(TAILQ_EMPTY(&swins_tbl));
+}
+
+/**
+ * Get the *running* O/S identification
+ */
+static void
+swins_get_OS_ident(void)
+{
+ struct utsname os_id;
+ char os_string[NAMELEN + 1];
+ struct swins_entry *entry;
+ u_char *boot;
+ struct stat sb;
+ struct tm k_ts;
+
+ if (uname(&os_id) == -1)
+ return;
+
+ snprintf(os_string, sizeof(os_string), "%s: %s",
+ os_id.sysname, os_id.version);
+
+ if ((entry = swins_find_by_name(os_string)) != NULL ||
+ (entry = swins_entry_create(os_string)) == NULL)
+ return;
+
+ entry->flags |= (HR_SWINSTALLED_FOUND | HR_SWINSTALLED_IMMUTABLE);
+ entry->id = oid_zeroDotZero;
+ entry->type = (int32_t)SWI_OPERATING_SYSTEM;
+ memset(entry->date, 0, sizeof(entry->date));
+
+ if (OS_getSystemInitialLoadParameters(&boot) == SNMP_ERR_NOERROR &&
+ strlen(boot) > 0 && stat(boot, &sb) == 0 &&
+ localtime_r(&sb.st_ctime, &k_ts) != NULL)
+ entry->date_len = make_date_time(entry->date, &k_ts, 0);
+}
+
+/**
+ * Read the installed packages
+ */
+static int
+swins_get_packages(void)
+{
+ struct stat sb;
+ DIR *p_dir;
+ struct dirent *ent;
+ struct tm k_ts;
+ char *pkg_file;
+ struct swins_entry *entry;
+ int ret = 0;
+
+ if (pkg_dir == NULL)
+ /* initialisation may have failed */
+ return (-1);
+
+ if (stat(pkg_dir, &sb) != 0) {
+ syslog(LOG_ERR, "hrSWInstalledTable: stat(\"%s\") failed: %m",
+ pkg_dir);
+ return (-1);
+ }
+ if (!S_ISDIR(sb.st_mode)) {
+ syslog(LOG_ERR, "hrSWInstalledTable: \"%s\" is not a directory",
+ pkg_dir);
+ return (-1);
+ }
+ if (sb.st_ctime <= os_pkg_last_change) {
+ HRDBG("no need to rescan installed packages -- "
+ "directory time-stamp unmodified");
+
+ TAILQ_FOREACH(entry, &swins_tbl, link)
+ entry->flags |= HR_SWINSTALLED_FOUND;
+
+ return (0);
+ }
+
+ if ((p_dir = opendir(pkg_dir)) == NULL) {
+ syslog(LOG_ERR, "hrSWInstalledTable: opendir(\"%s\") failed: "
+ "%m", pkg_dir);
+ return (-1);
+ }
+
+ while (errno = 0, (ent = readdir(p_dir)) != NULL) {
+ HRDBG(" pkg file: %s", ent->d_name);
+
+ /* check that the contents file is a regular file */
+ if (asprintf(&pkg_file, "%s/%s/%s", pkg_dir, ent->d_name,
+ CONTENTS_FNAME) == -1)
+ continue;
+
+ if (stat(pkg_file, &sb) != 0 ) {
+ free(pkg_file);
+ continue;
+ }
+
+ if (!S_ISREG(sb.st_mode)) {
+ syslog(LOG_ERR, "hrSWInstalledTable: \"%s\" not a "
+ "regular file -- skipped", pkg_file);
+ free(pkg_file);
+ continue;
+ }
+ free(pkg_file);
+
+ /* read directory timestamp on package */
+ if (asprintf(&pkg_file, "%s/%s", pkg_dir, ent->d_name) == -1)
+ continue;
+
+ if (stat(pkg_file, &sb) == -1 ||
+ localtime_r(&sb.st_ctime, &k_ts) == NULL) {
+ free(pkg_file);
+ continue;
+ }
+ free(pkg_file);
+
+ /* update or create entry */
+ if ((entry = swins_find_by_name(ent->d_name)) == NULL &&
+ (entry = swins_entry_create(ent->d_name)) == NULL) {
+ ret = -1;
+ goto PKG_LOOP_END;
+ }
+
+ entry->flags |= HR_SWINSTALLED_FOUND;
+ entry->id = oid_zeroDotZero;
+ entry->type = (int32_t)SWI_APPLICATION;
+
+ entry->date_len = make_date_time(entry->date, &k_ts, 0);
+ }
+
+ if (errno != 0) {
+ syslog(LOG_ERR, "hrSWInstalledTable: readdir_r(\"%s\") failed:"
+ " %m", pkg_dir);
+ ret = -1;
+ } else {
+ /*
+ * save the timestamp of directory
+ * to avoid any further scanning
+ */
+ os_pkg_last_change = sb.st_ctime;
+ }
+ PKG_LOOP_END:
+ (void)closedir(p_dir);
+ return (ret);
+}
+
+/**
+ * Refresh the installed software table.
+ */
+void
+refresh_swins_tbl(void)
+{
+ int ret;
+ struct swins_entry *entry, *entry_tmp;
+
+ if (this_tick - swins_tick < swins_tbl_refresh) {
+ HRDBG("no refresh needed");
+ return;
+ }
+
+ /* mark each entry as missing */
+ TAILQ_FOREACH(entry, &swins_tbl, link)
+ entry->flags &= ~HR_SWINSTALLED_FOUND;
+
+ ret = swins_get_packages();
+
+ TAILQ_FOREACH_SAFE(entry, &swins_tbl, link, entry_tmp)
+ if (!(entry->flags & HR_SWINSTALLED_FOUND) &&
+ !(entry->flags & HR_SWINSTALLED_IMMUTABLE))
+ swins_entry_delete(entry);
+
+ if (ret == 0)
+ swins_tick = this_tick;
+}
+
+/**
+ * Create and populate the package table
+ */
+void
+init_swins_tbl(void)
+{
+
+ if ((pkg_dir = malloc(sizeof(PATH_PKGDIR))) == NULL) {
+ syslog(LOG_ERR, "%s: %m", __func__);
+ } else
+ strcpy(pkg_dir, PATH_PKGDIR);
+
+ swins_get_OS_ident();
+ refresh_swins_tbl();
+
+ HRDBG("init done");
+}
+
+/**
+ * SNMP handler
+ */
+int
+op_hrSWInstalledTable(struct snmp_context *ctx __unused,
+ struct snmp_value *value, u_int sub, u_int iidx __unused,
+ enum snmp_op curr_op)
+{
+ struct swins_entry *entry;
+
+ refresh_swins_tbl();
+
+ switch (curr_op) {
+
+ case SNMP_OP_GETNEXT:
+ if ((entry = NEXT_OBJECT_INT(&swins_tbl,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ value->var.len = sub + 1;
+ value->var.subs[sub] = entry->index;
+ goto get;
+
+ case SNMP_OP_GET:
+ if ((entry = FIND_OBJECT_INT(&swins_tbl,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ goto get;
+
+ case SNMP_OP_SET:
+ if ((entry = FIND_OBJECT_INT(&swins_tbl,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NO_CREATION);
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ case SNMP_OP_ROLLBACK:
+ case SNMP_OP_COMMIT:
+ abort();
+ }
+ abort();
+
+ get:
+ switch (value->var.subs[sub - 1]) {
+
+ case LEAF_hrSWInstalledIndex:
+ value->v.integer = entry->index;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrSWInstalledName:
+ return (string_get(value, entry->name, -1));
+ break;
+
+ case LEAF_hrSWInstalledID:
+ value->v.oid = entry->id;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrSWInstalledType:
+ value->v.integer = entry->type;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrSWInstalledDate:
+ return (string_get(value, entry->date, entry->date_len));
+ }
+ abort();
+}
+
+/**
+ * Scalars
+ */
+int
+op_hrSWInstalled(struct snmp_context *ctx __unused,
+ struct snmp_value *value __unused, u_int sub,
+ u_int iidx __unused, enum snmp_op curr_op)
+{
+
+ /* only SNMP GET is possible */
+ switch (curr_op) {
+
+ case SNMP_OP_GET:
+ goto get;
+
+ case SNMP_OP_SET:
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ case SNMP_OP_ROLLBACK:
+ case SNMP_OP_COMMIT:
+ case SNMP_OP_GETNEXT:
+ abort();
+ }
+ abort();
+
+ get:
+ switch (value->var.subs[sub - 1]) {
+
+ case LEAF_hrSWInstalledLastChange:
+ case LEAF_hrSWInstalledLastUpdateTime:
+ /*
+ * We always update the entire table so these two tick
+ * values should be equal.
+ */
+ refresh_swins_tbl();
+ if (swins_tick <= start_tick)
+ value->v.uint32 = 0;
+ else {
+ uint64_t lastChange = swins_tick - start_tick;
+
+ /* may overflow the SNMP type */
+ value->v.uint32 =
+ (lastChange > UINT_MAX ? UINT_MAX : lastChange);
+ }
+
+ return (SNMP_ERR_NOERROR);
+
+ default:
+ abort();
+ }
+}
diff --git a/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_swrun_tbl.c b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_swrun_tbl.c
new file mode 100644
index 0000000..bf9ecab
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_swrun_tbl.c
@@ -0,0 +1,751 @@
+/*
+ * Copyright (c) 2005-2006 The FreeBSD Project
+ * All rights reserved.
+ *
+ * Author: Victor Cruceru <soc-victor@freebsd.org>
+ *
+ * Redistribution of this software and documentation and use in source and
+ * binary forms, with or without modification, are permitted provided that
+ * the following conditions are met:
+ *
+ * 1. Redistributions of source code or documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ *
+ * Host Resources MIB for SNMPd. Implementation for hrSWRunTable
+ */
+
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/sysctl.h>
+#include <sys/user.h>
+#include <sys/linker.h>
+
+#include <assert.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+
+#include "hostres_snmp.h"
+#include "hostres_oid.h"
+#include "hostres_tree.h"
+
+
+/*
+ * Ugly thing: PID_MAX, NO_PID defined only in kernel
+ */
+#define NO_PID 100000
+
+enum SWRunType {
+ SRT_UNKNOWN = 1,
+ SRT_OPERATING_SYSTEM = 2,
+ SRT_DEVICE_DRIVER = 3,
+ SRT_APPLICATION = 4
+
+};
+
+enum SWRunStatus {
+ SRS_RUNNING = 1,
+ SRS_RUNNABLE = 2,
+ SRS_NOT_RUNNABLE = 3,
+ SRS_INVALID = 4
+};
+
+/*
+ * This structure is used to hold a SNMP table entry
+ * for both hrSWRunTable and hrSWRunPerfTable because
+ * hrSWRunPerfTable AUGMENTS hrSWRunTable
+ */
+struct swrun_entry {
+ int32_t index;
+ u_char name[64 + 1];
+ struct asn_oid id;
+ u_char path[128 + 1];
+ u_char parameters[128 + 1];
+ int32_t type; /* enum SWRunType */
+ int32_t status; /* enum SWRunStatus */
+ int32_t perfCPU;
+ int32_t perfMemory;
+#define HR_SWRUN_FOUND 0x001
+ uint32_t flags;
+ uint64_t r_tick; /* tick when entry refreshed */
+ TAILQ_ENTRY(swrun_entry) link;
+};
+TAILQ_HEAD(swrun_tbl, swrun_entry);
+
+/* the head of the list with hrSWRunTable's entries */
+static struct swrun_tbl swrun_tbl = TAILQ_HEAD_INITIALIZER(swrun_tbl);
+
+/* last (agent) tick when hrSWRunTable and hrSWRunPerTable was updated */
+static uint64_t swrun_tick;
+
+/* maximum number of ticks between updates of SWRun and SWRunPerf table */
+uint32_t swrun_tbl_refresh = HR_SWRUN_TBL_REFRESH * 100;
+
+/* the value of the MIB object with the same name */
+static int32_t SWOSIndex;
+
+/**
+ * Malloc a new entry and add it to the list
+ * associated to this table. The item identified by
+ * the index parameter must not exist in this list.
+ */
+static struct swrun_entry *
+swrun_entry_create(int32_t idx)
+{
+ struct swrun_entry *entry;
+
+ if ((entry = malloc(sizeof(*entry))) == NULL) {
+ syslog(LOG_WARNING, "%s: %m", __func__);
+ return (NULL);
+ }
+ memset(entry, 0, sizeof(*entry));
+ entry->index = idx;
+
+ INSERT_OBJECT_INT(entry, &swrun_tbl);
+ return (entry);
+}
+
+/**
+ * Unlink the entry from the list and then free its heap memory
+ */
+static void
+swrun_entry_delete(struct swrun_entry *entry)
+{
+
+ assert(entry != NULL);
+
+ TAILQ_REMOVE(&swrun_tbl, entry, link);
+
+ free(entry);
+}
+
+/**
+ * Search one item by its index, return NULL if none found
+ */
+static struct swrun_entry *
+swrun_entry_find_by_index(int32_t idx)
+{
+ struct swrun_entry *entry;
+
+ TAILQ_FOREACH(entry, &swrun_tbl, link)
+ if (entry->index == idx)
+ return (entry);
+ return (NULL);
+}
+
+/**
+ * Translate the kernel's process status to the SNMP one.
+ */
+static enum SWRunStatus
+swrun_OS_get_proc_status(const struct kinfo_proc *kp)
+{
+
+ assert(kp != NULL);
+ if(kp == NULL) {
+ return (SRS_INVALID);
+ }
+
+ /*
+ * I'm using the old style flags - they look cleaner to me,
+ * at least for the purpose of this SNMP table
+ */
+ switch (kp->ki_stat) {
+
+ case SSTOP:
+ return (SRS_NOT_RUNNABLE);
+
+ case SWAIT:
+ case SLOCK:
+ case SSLEEP:
+ return (SRS_RUNNABLE);
+
+ case SZOMB:
+ return (SRS_INVALID);
+
+ case SIDL:
+ case SRUN:
+ return (SRS_RUNNING);
+
+ default:
+ syslog(LOG_ERR,"Unknown process state: %d", kp->ki_stat);
+ return (SRS_INVALID);
+ }
+}
+
+/**
+ * Make an SNMP table entry from a kernel one.
+ */
+static void
+kinfo_proc_to_swrun_entry(const struct kinfo_proc *kp,
+ struct swrun_entry *entry)
+{
+ char **argv = NULL;
+ uint64_t cpu_time = 0;
+
+ strlcpy((char*)entry->name, kp->ki_ocomm, sizeof(entry->name));
+
+ entry->id = oid_zeroDotZero; /* unknown id - FIXME */
+
+ entry->path[0] = '\0';
+ entry->parameters[0] = '\0';
+
+ assert(hrState_g.kd != NULL);
+
+ argv = kvm_getargv(hr_kd, kp, sizeof(entry->parameters) - 1);
+ if(argv != NULL){
+ memset(entry->parameters, '\0', sizeof(entry->parameters));
+
+ /*
+ * FIXME
+ * Path seems to not be available.
+ * Try to hack the info in argv[0];
+ * this argv is under control of the program so this info
+ * is not realiable
+ */
+ if(*argv != NULL && (*argv)[0] == '/') {
+ memset(entry->path, '\0', sizeof(entry->path));
+ strlcpy((char*)entry->path, *argv, sizeof(entry->path));
+ }
+
+ argv++; /* skip the first one which was used for path */
+
+ while (argv != NULL && *argv != NULL ) {
+ if (entry->parameters[0] != 0) {
+ /*
+ * add a space between parameters,
+ * except before the first one
+ */
+ strlcat((char *)entry->parameters,
+ " ", sizeof(entry->parameters));
+ }
+ strlcat((char *)entry->parameters, *argv,
+ sizeof(entry->parameters));
+ argv++;
+ }
+ }
+
+ entry->type = (int32_t)(IS_KERNPROC(kp) ? SRT_OPERATING_SYSTEM :
+ SRT_APPLICATION);
+
+ entry->status = (int32_t)swrun_OS_get_proc_status(kp);
+ cpu_time = kp->ki_runtime / 100000; /* centi-seconds */
+
+ /* may overflow the snmp type */
+ entry->perfCPU = (cpu_time > (uint64_t)INT_MAX ? INT_MAX : cpu_time);
+ entry->perfMemory = kp->ki_size / 1024; /* in kilo-bytes */
+ entry->r_tick = get_ticks();
+}
+
+/**
+ * Create a table entry for a KLD
+ */
+static void
+kld_file_stat_to_swrun(const struct kld_file_stat *kfs,
+ struct swrun_entry *entry)
+{
+
+ assert(kfs != NULL);
+ assert(entry != NULL);
+
+ strlcpy((char *)entry->name, kfs->name, sizeof(entry->name));
+
+ /* FIXME: can we find the location where the module was loaded from? */
+ entry->path[0] = '\0';
+
+ /* no parameters for kernel files (.ko) of for the kernel */
+ entry->parameters[0] = '\0';
+
+ entry->id = oid_zeroDotZero; /* unknown id - FIXME */
+
+ if (strcmp(kfs->name, "kernel") == 0) {
+ entry->type = (int32_t)SRT_OPERATING_SYSTEM;
+ SWOSIndex = entry->index;
+ } else {
+ entry->type = (int32_t)SRT_DEVICE_DRIVER; /* well, not really */
+ }
+ entry->status = (int32_t)SRS_RUNNING;
+ entry->perfCPU = 0; /* Info not available */
+ entry->perfMemory = kfs->size / 1024; /* in kilo-bytes */
+ entry->r_tick = get_ticks();
+}
+
+/**
+ * Get all visible proceses including the kernel visible threads
+ */
+static void
+swrun_OS_get_procs(void)
+{
+ struct kinfo_proc *plist, *kp;
+ int i;
+ int nproc;
+ struct swrun_entry *entry;
+
+ plist = kvm_getprocs(hr_kd, KERN_PROC_ALL, 0, &nproc);
+ if (plist == NULL || nproc < 0) {
+ syslog(LOG_ERR, "kvm_getprocs() failed: %m");
+ return;
+ }
+ for (i = 0, kp = plist; i < nproc; i++, kp++) {
+ /*
+ * The SNMP table's index must begin from 1 (as specified by
+ * this table definition), the PIDs are starting from 0
+ * so we are translating the PIDs to +1
+ */
+ entry = swrun_entry_find_by_index((int32_t)kp->ki_pid + 1);
+ if (entry == NULL) {
+ /* new entry - get memory for it */
+ entry = swrun_entry_create((int32_t)kp->ki_pid + 1);
+ if (entry == NULL)
+ continue;
+ }
+ entry->flags |= HR_SWRUN_FOUND; /* mark it as found */
+
+ kinfo_proc_to_swrun_entry(kp, entry);
+ }
+}
+
+/*
+ * Get kernel items: first the kernel itself, then the loaded modules.
+ */
+static void
+swrun_OS_get_kinfo(void)
+{
+ int fileid;
+ struct swrun_entry *entry;
+ struct kld_file_stat stat;
+
+ for (fileid = kldnext(0); fileid > 0; fileid = kldnext(fileid)) {
+ stat.version = sizeof(struct kld_file_stat);
+ if (kldstat(fileid, &stat) < 0) {
+ syslog(LOG_ERR, "kldstat() failed: %m");
+ continue;
+ }
+
+ /*
+ * kernel and kernel files (*.ko) will be indexed starting with
+ * NO_PID + 1; NO_PID is PID_MAX + 1 thus it will be no risk to
+ * overlap with real PIDs which are in range of 1 .. NO_PID
+ */
+ entry = swrun_entry_find_by_index(NO_PID + 1 + stat.id);
+ if (entry == NULL) {
+ /* new entry - get memory for it */
+ entry = swrun_entry_create(NO_PID + 1 + stat.id);
+ if (entry == NULL)
+ continue;
+ }
+ entry->flags |= HR_SWRUN_FOUND; /* mark it as found */
+
+ kld_file_stat_to_swrun(&stat, entry);
+ }
+}
+
+/**
+ * Refresh the hrSWRun and hrSWRunPert tables.
+ */
+static void
+refresh_swrun_tbl(void)
+{
+
+ struct swrun_entry *entry, *entry_tmp;
+
+ if (this_tick - swrun_tick < swrun_tbl_refresh) {
+ HRDBG("no refresh needed ");
+ return;
+ }
+
+ /* mark each entry as missing */
+ TAILQ_FOREACH(entry, &swrun_tbl, link)
+ entry->flags &= ~HR_SWRUN_FOUND;
+
+ swrun_OS_get_procs();
+ swrun_OS_get_kinfo();
+
+ /*
+ * Purge items that disappeared
+ */
+ TAILQ_FOREACH_SAFE(entry, &swrun_tbl, link, entry_tmp)
+ if (!(entry->flags & HR_SWRUN_FOUND))
+ swrun_entry_delete(entry);
+
+ swrun_tick = this_tick;
+
+ HRDBG("refresh DONE");
+}
+
+/**
+ * Update the information in this entry
+ */
+static void
+fetch_swrun_entry(struct swrun_entry *entry)
+{
+ struct kinfo_proc *plist;
+ int nproc;
+ struct kld_file_stat stat;
+
+ assert(entry != NULL);
+
+ if (entry->index >= NO_PID + 1) {
+ /*
+ * kernel and kernel files (*.ko) will be indexed
+ * starting with NO_PID + 1; NO_PID is PID_MAX + 1
+ * thus it will be no risk to overlap with real PIDs
+ * which are in range of 1 .. NO_PID
+ */
+ stat.version = sizeof(stat);
+ if (kldstat(entry->index - NO_PID - 1, &stat) == -1) {
+ /*
+ * not found, it's gone. Mark it as invalid for now, it
+ * will be removed from the list at next global refersh
+ */
+ HRDBG("missing item with kid=%d",
+ entry->index - NO_PID - 1);
+ entry->status = (int32_t)SRS_INVALID;
+ } else
+ kld_file_stat_to_swrun(&stat, entry);
+
+ } else {
+ /* this is a process */
+ assert(hrState_g.kd != NULL);
+ plist = kvm_getprocs(hr_kd, KERN_PROC_PID,
+ entry->index - 1, &nproc);
+ if (plist == NULL || nproc != 1) {
+ HRDBG("missing item with PID=%d", entry->index - 1);
+ entry->status = (int32_t)SRS_INVALID;
+ } else
+ kinfo_proc_to_swrun_entry(plist, entry);
+ }
+}
+
+/**
+ * Invalidate entry. For KLDs we try to unload it, for processes we SIGKILL it.
+ */
+static int
+invalidate_swrun_entry(struct swrun_entry *entry, int commit)
+{
+ struct kinfo_proc *plist;
+ int nproc;
+ struct kld_file_stat stat;
+
+ assert(entry != NULL);
+
+ if (entry->index >= NO_PID + 1) {
+ /* this is a kernel item */
+ HRDBG("atempt to unload KLD %d",
+ entry->index - NO_PID - 1);
+
+ if (entry->index == SWOSIndex) {
+ /* can't invalidate the kernel itself */
+ return (SNMP_ERR_NOT_WRITEABLE);
+ }
+
+ stat.version = sizeof(stat);
+ if (kldstat(entry->index - NO_PID - 1, &stat) == -1) {
+ /*
+ * not found, it's gone. Mark it as invalid for now, it
+ * will be removed from the list at next global
+ * refresh
+ */
+ HRDBG("missing item with kid=%d",
+ entry->index - NO_PID - 1);
+ entry->status = (int32_t)SRS_INVALID;
+ return (SNMP_ERR_NOERROR);
+ }
+ /*
+ * There is no way to try to unload a module. There seems
+ * also no way to find out whether it is busy without unloading
+ * it. We can assume that it is busy, if the reference count
+ * is larger than 2, but if it is 1 nothing helps.
+ */
+ if (!commit) {
+ if (stat.refs > 1)
+ return (SNMP_ERR_NOT_WRITEABLE);
+ return (SNMP_ERR_NOERROR);
+ }
+ if (kldunload(stat.id) == -1) {
+ syslog(LOG_ERR,"kldunload for %d/%s failed: %m",
+ stat.id, stat.name);
+ if (errno == EBUSY)
+ return (SNMP_ERR_NOT_WRITEABLE);
+ else
+ return (SNMP_ERR_RES_UNAVAIL);
+ }
+ } else {
+ /* this is a process */
+ assert(hrState_g.kd != NULL);
+
+ plist = kvm_getprocs(hr_kd, KERN_PROC_PID,
+ entry->index - 1, &nproc);
+ if (plist == NULL || nproc != 1) {
+ HRDBG("missing item with PID=%d", entry->index - 1);
+ entry->status = (int32_t)SRS_INVALID;
+ return (SNMP_ERR_NOERROR);
+ }
+ if (IS_KERNPROC(plist)) {
+ /* you don't want to do this */
+ return (SNMP_ERR_NOT_WRITEABLE);
+ }
+ if (kill(entry->index - 1, commit ? SIGKILL : 0) < 0) {
+ syslog(LOG_ERR,"kill (%d, SIGKILL) failed: %m",
+ entry->index - 1);
+ if (errno == ESRCH) {
+ /* race: just gone */
+ entry->status = (int32_t)SRS_INVALID;
+ return (SNMP_ERR_NOERROR);
+ }
+ return (SNMP_ERR_GENERR);
+ }
+ }
+ return (SNMP_ERR_NOERROR);
+}
+
+/**
+ * Popuplate the hrSWRunTable.
+ */
+void
+init_swrun_tbl(void)
+{
+
+ refresh_swrun_tbl();
+ HRDBG("done");
+}
+
+/**
+ * Finalize the hrSWRunTable.
+ */
+void
+fini_swrun_tbl(void)
+{
+ struct swrun_entry *n1;
+
+ while ((n1 = TAILQ_FIRST(&swrun_tbl)) != NULL) {
+ TAILQ_REMOVE(&swrun_tbl, n1, link);
+ free(n1);
+ }
+}
+
+/*
+ * This is the implementation for a generated (by a SNMP tool)
+ * function prototype, see hostres_tree.h
+ * It hanldes the SNMP operations for hrSWRunTable
+ */
+int
+op_hrSWRunTable(struct snmp_context *ctx __unused, struct snmp_value *value,
+ u_int sub, u_int iidx __unused, enum snmp_op curr_op)
+{
+ struct swrun_entry *entry;
+ int ret;
+
+ refresh_swrun_tbl();
+
+ switch (curr_op) {
+
+ case SNMP_OP_GETNEXT:
+ if ((entry = NEXT_OBJECT_INT(&swrun_tbl,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ value->var.len = sub + 1;
+ value->var.subs[sub] = entry->index;
+ goto get;
+
+ case SNMP_OP_GET:
+ if ((entry = FIND_OBJECT_INT(&swrun_tbl,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ goto get;
+
+ case SNMP_OP_SET:
+ if ((entry = FIND_OBJECT_INT(&swrun_tbl,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NO_CREATION);
+
+ if (entry->r_tick < this_tick)
+ fetch_swrun_entry(entry);
+
+ switch (value->var.subs[sub - 1]) {
+
+ case LEAF_hrSWRunStatus:
+ if (value->v.integer != (int32_t)SRS_INVALID)
+ return (SNMP_ERR_WRONG_VALUE);
+
+ if (entry->status == (int32_t)SRS_INVALID)
+ return (SNMP_ERR_NOERROR);
+
+ /*
+ * Here we have a problem with the entire SNMP
+ * model: if we kill now, we cannot rollback.
+ * If we kill in the commit code, we cannot
+ * return an error. Because things may change between
+ * SET and COMMIT this is impossible to handle
+ * correctly.
+ */
+ return (invalidate_swrun_entry(entry, 0));
+ }
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ case SNMP_OP_ROLLBACK:
+ return (SNMP_ERR_NOERROR);
+
+ case SNMP_OP_COMMIT:
+ if ((entry = FIND_OBJECT_INT(&swrun_tbl,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NOERROR);
+
+ switch (value->var.subs[sub - 1]) {
+
+ case LEAF_hrSWRunStatus:
+ if (value->v.integer == (int32_t)SRS_INVALID &&
+ entry->status != (int32_t)SRS_INVALID)
+ (void)invalidate_swrun_entry(entry, 1);
+ return (SNMP_ERR_NOERROR);
+ }
+ abort();
+ }
+ abort();
+
+ get:
+ ret = SNMP_ERR_NOERROR;
+ switch (value->var.subs[sub - 1]) {
+
+ case LEAF_hrSWRunIndex:
+ value->v.integer = entry->index;
+ break;
+
+ case LEAF_hrSWRunName:
+ ret = string_get(value, entry->name, -1);
+ break;
+
+ case LEAF_hrSWRunID:
+ value->v.oid = entry->id;
+ break;
+
+ case LEAF_hrSWRunPath:
+ ret = string_get(value, entry->path, -1);
+ break;
+
+ case LEAF_hrSWRunParameters:
+ ret = string_get(value, entry->parameters, -1);
+ break;
+
+ case LEAF_hrSWRunType:
+ value->v.integer = entry->type;
+ break;
+
+ case LEAF_hrSWRunStatus:
+ value->v.integer = entry->status;
+ break;
+
+ default:
+ abort();
+ }
+ return (ret);
+}
+
+/**
+ * Scalar(s) in the SWRun group
+ */
+int
+op_hrSWRun(struct snmp_context *ctx __unused, struct snmp_value *value,
+ u_int sub, u_int iidx __unused, enum snmp_op curr_op)
+{
+
+ /* only SNMP GET is possible */
+ switch (curr_op) {
+
+ case SNMP_OP_GET:
+ goto get;
+
+ case SNMP_OP_SET:
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ case SNMP_OP_ROLLBACK:
+ case SNMP_OP_COMMIT:
+ case SNMP_OP_GETNEXT:
+ abort();
+ }
+ abort();
+
+ get:
+ switch (value->var.subs[sub - 1]) {
+
+ case LEAF_hrSWOSIndex:
+ value->v.uint32 = SWOSIndex;
+ return (SNMP_ERR_NOERROR);
+
+ default:
+ abort();
+ }
+}
+
+/*
+ * This is the implementation for a generated (by a SNMP tool)
+ * function prototype, see hostres_tree.h
+ * It handles the SNMP operations for hrSWRunPerfTable
+ */
+int
+op_hrSWRunPerfTable(struct snmp_context *ctx __unused,
+ struct snmp_value *value, u_int sub, u_int iidx __unused,
+ enum snmp_op curr_op )
+{
+ struct swrun_entry *entry;
+
+ refresh_swrun_tbl();
+
+ switch (curr_op) {
+
+ case SNMP_OP_GETNEXT:
+ if ((entry = NEXT_OBJECT_INT(&swrun_tbl,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ value->var.len = sub + 1;
+ value->var.subs[sub] = entry->index;
+ goto get;
+
+ case SNMP_OP_GET:
+ if ((entry = FIND_OBJECT_INT(&swrun_tbl,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ goto get;
+
+ case SNMP_OP_SET:
+ if ((entry = FIND_OBJECT_INT(&swrun_tbl,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NO_CREATION);
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ case SNMP_OP_ROLLBACK:
+ case SNMP_OP_COMMIT:
+ abort();
+ }
+ abort();
+
+ get:
+ switch (value->var.subs[sub - 1]) {
+
+ case LEAF_hrSWRunPerfCPU:
+ value->v.integer = entry->perfCPU;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrSWRunPerfMem:
+ value->v.integer = entry->perfMemory;
+ return (SNMP_ERR_NOERROR);
+ }
+ abort();
+}
diff --git a/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_tree.def b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_tree.def
new file mode 100644
index 0000000..e92d903
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_tree.def
@@ -0,0 +1,292 @@
+#
+# Copyright (c) 2005-2006 The FreeBSD Project
+# All rights reserved.
+#
+# Author: Victor Cruceru <soc-victor@freebsd.org>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+#
+# This is the .def file for both HOST-RESOURCES-MIB and HOST-RESOURCES-TYPES
+#
+
+(1 internet
+ (2 mgmt
+ (1 mib_2
+ (25 host
+ (1 hrSystem
+ (1 hrSystemUptime TIMETICKS op_hrSystem GET)
+ (2 hrSystemDate OCTETSTRING op_hrSystem GET SET)
+ (3 hrSystemInitialLoadDevice INTEGER op_hrSystem GET SET)
+ (4 hrSystemInitialLoadParameters OCTETSTRING op_hrSystem GET SET)
+ (5 hrSystemNumUsers GAUGE op_hrSystem GET)
+ (6 hrSystemProcesses GAUGE op_hrSystem GET)
+ (7 hrSystemMaxProcesses INTEGER op_hrSystem GET)
+ )
+ (2 hrStorage
+ (1 hrStorageTypes
+ (1 hrStorageOther
+ )
+ (2 hrStorageRam
+ )
+ (3 hrStorageVirtualMemory
+ )
+ (4 hrStorageFixedDisk
+ )
+ (5 hrStorageRemovableDisk
+ )
+ (6 hrStorageFloppyDisk
+ )
+ (7 hrStorageCompactDisc
+ )
+ (8 hrStorageRamDisk
+ )
+ (9 hrStorageFlashMemory
+ )
+ (10 hrStorageNetworkDisk
+ )
+ )
+ (2 hrMemorySize INTEGER op_hrStorage GET)
+ (3 hrStorageTable
+ (1 hrStorageEntry : INTEGER op_hrStorageTable
+ (1 hrStorageIndex INTEGER GET)
+ (2 hrStorageType OID GET)
+ (3 hrStorageDescr OCTETSTRING GET)
+ (4 hrStorageAllocationUnits INTEGER GET)
+ (5 hrStorageSize INTEGER GET SET)
+ (6 hrStorageUsed INTEGER GET)
+ (7 hrStorageAllocationFailures COUNTER GET)
+ )
+ )
+ )
+ (3 hrDevice
+ (1 hrDeviceTypes
+ (1 hrDeviceOther
+ )
+ (2 hrDeviceUnknown
+ )
+ (3 hrDeviceProcessor
+ )
+ (4 hrDeviceNetwork
+ )
+ (5 hrDevicePrinter
+ )
+ (6 hrDeviceDiskStorage
+ )
+ (10 hrDeviceVideo
+ )
+ (11 hrDeviceAudio
+ )
+ (12 hrDeviceCoprocessor
+ )
+ (13 hrDeviceKeyboard
+ )
+ (14 hrDeviceModem
+ )
+ (15 hrDeviceParallelPort
+ )
+ (16 hrDevicePointing
+ )
+ (17 hrDeviceSerialPort
+ )
+ (18 hrDeviceTape
+ )
+ (19 hrDeviceClock
+ )
+ (20 hrDeviceVolatileMemory
+ )
+ (21 hrDeviceNonVolatileMemory
+ )
+ )
+ (2 hrDeviceTable
+ (1 hrDeviceEntry : INTEGER op_hrDeviceTable
+ (1 hrDeviceIndex INTEGER GET)
+ (2 hrDeviceType OID GET)
+ (3 hrDeviceDescr OCTETSTRING GET)
+ (4 hrDeviceID OID GET)
+ (5 hrDeviceStatus INTEGER GET)
+ (6 hrDeviceErrors COUNTER GET)
+ )
+ )
+ (3 hrProcessorTable
+ (1 hrProcessorEntry : INTEGER op_hrProcessorTable
+ (1 hrProcessorFrwID OID GET)
+ (2 hrProcessorLoad INTEGER GET)
+ )
+ )
+ (4 hrNetworkTable
+ (1 hrNetworkEntry : INTEGER op_hrNetworkTable
+ (1 hrNetworkIfIndex INTEGER GET)
+ )
+ )
+ (5 hrPrinterTable
+ (1 hrPrinterEntry : INTEGER op_hrPrinterTable
+ (1 hrPrinterStatus INTEGER GET)
+ (2 hrPrinterDetectedErrorState OCTETSTRING GET)
+ )
+ )
+ (6 hrDiskStorageTable
+ (1 hrDiskStorageEntry : INTEGER op_hrDiskStorageTable
+ (1 hrDiskStorageAccess INTEGER GET)
+ (2 hrDiskStorageMedia INTEGER GET)
+ (3 hrDiskStorageRemoveble INTEGER GET)
+ (4 hrDiskStorageCapacity INTEGER GET)
+ )
+ )
+ (7 hrPartitionTable
+ (1 hrPartitionEntry : INTEGER INTEGER op_hrPartitionTable
+ (1 hrPartitionIndex INTEGER GET)
+ (2 hrPartitionLabel OCTETSTRING GET)
+ (3 hrPartitionID OCTETSTRING GET)
+ (4 hrPartitionSize INTEGER GET)
+ (5 hrPartitionFSIndex INTEGER GET)
+ )
+ )
+ (8 hrFSTable
+ (1 hrFSEntry : INTEGER op_hrFSTable
+ (1 hrFSIndex INTEGER GET)
+ (2 hrFSMountPoint OCTETSTRING GET)
+ (3 hrFSRemoteMountPoint OCTETSTRING GET)
+ (4 hrFSType OID GET)
+ (5 hrFSAccess INTEGER GET)
+ (6 hrFSBootable INTEGER GET)
+ (7 hrFSStorageIndex INTEGER GET)
+ (8 hrFSLastFullBackupDate OCTETSTRING GET SET)
+ (9 hrFSLastPartialBackupDate OCTETSTRING GET SET)
+ )
+ )
+ (9 hrFSTypes
+ (1 hrFSOther
+ )
+ (2 hrFSUnknown
+ )
+ (3 hrFSBerkeleyFFS
+ )
+ (4 hrFSSys5FS
+ )
+ (5 hrFSFat
+ )
+ (6 hrFSHPFS
+ )
+ (7 hrFSHFS
+ )
+ (8 hrFSMFS
+ )
+ (9 hrFSNTFS
+ )
+ (10 hrFSVNode
+ )
+ (11 hrFSJournaled
+ )
+ (12 hrFSiso9660
+ )
+ (13 hrFSRockRidge
+ )
+ (14 hrFSNFS
+ )
+ (15 hrFSNetware
+ )
+ (16 hrFSAFS
+ )
+ (17 hrFSDFS
+ )
+ (18 hrFSAppleshare
+ )
+ (19 hrFSRFS
+ )
+ (20 hrFSDGCFS
+ )
+ (21 hrFSBFS
+ )
+ (22 hrFSFAT32
+ )
+ (23 hrFSLinuxExt2
+ )
+ )
+ )
+ (4 hrSWRun
+ (1 hrSWOSIndex INTEGER op_hrSWRun GET)
+ (2 hrSWRunTable
+ (1 hrSWRunEntry : INTEGER op_hrSWRunTable
+ (1 hrSWRunIndex INTEGER GET)
+ (2 hrSWRunName OCTETSTRING GET)
+ (3 hrSWRunID OID GET)
+ (4 hrSWRunPath OCTETSTRING GET)
+ (5 hrSWRunParameters OCTETSTRING GET)
+ (6 hrSWRunType INTEGER GET)
+ (7 hrSWRunStatus INTEGER GET SET)
+ )
+ )
+ )
+ (5 hrSWRunPerf
+ (1 hrSWRunPerfTable
+ (1 hrSWRunPerfEntry : INTEGER op_hrSWRunPerfTable
+ (1 hrSWRunPerfCPU INTEGER GET)
+ (2 hrSWRunPerfMem INTEGER GET)
+ )
+ )
+ )
+ (6 hrSWInstalled
+ (1 hrSWInstalledLastChange TIMETICKS op_hrSWInstalled GET)
+ (2 hrSWInstalledLastUpdateTime TIMETICKS op_hrSWInstalled GET)
+ (3 hrSWInstalledTable
+ (1 hrSWInstalledEntry : INTEGER op_hrSWInstalledTable
+ (1 hrSWInstalledIndex INTEGER GET)
+ (2 hrSWInstalledName OCTETSTRING GET)
+ (3 hrSWInstalledID OID GET)
+ (4 hrSWInstalledType INTEGER GET)
+ (5 hrSWInstalledDate OCTETSTRING GET)
+ )
+ )
+ )
+ (7 hrMIBAdminInfo
+ (1 hostResourcesMibModule
+ )
+ (2 hrMIBCompliances
+ )
+ (3 hrMIBGroups
+ )
+ )
+ )
+ )
+ )
+ (4 private
+ (1 enterprises
+ (12325 fokus
+ (1 begemot
+ (202 begemotHostres
+ (1 begemotHostresObjects
+ (1 begemotHrStorageUpdate TIMETICKS op_begemot GET SET)
+ (2 begemotHrFSUpdate TIMETICKS op_begemot GET SET)
+ (3 begemotHrDiskStorageUpdate TIMETICKS op_begemot GET SET)
+ (4 begemotHrNetworkUpdate TIMETICKS op_begemot GET SET)
+ (5 begemotHrSWInstalledUpdate TIMETICKS op_begemot GET SET)
+ (6 begemotHrSWRunUpdate TIMETICKS op_begemot GET SET)
+ (7 begemotHrPkgDir OCTETSTRING op_begemot GET SET)
+ )
+ )
+ )
+ )
+ )
+ )
+)
diff --git a/usr.sbin/bsnmpd/modules/snmp_hostres/snmp_hostres.3 b/usr.sbin/bsnmpd/modules/snmp_hostres/snmp_hostres.3
new file mode 100644
index 0000000..5715fd0
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_hostres/snmp_hostres.3
@@ -0,0 +1,85 @@
+.\"
+.\" Copyright (C) 2005-2006
+.\" The FreeBSD Project.
+.\" All rights reserved.
+.\"
+.\" Author: Harti Brandt <harti@freebsd.org>
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd January 3, 2006
+.Dt snmp_hostres 3
+.Os
+.Sh NAME
+.Nm snmp_hostres
+.Nd "host resources module for snmpd.
+.Sh LIBRARY
+.Pq begemotSnmpdModulePath."hostres" = "/usr/lib/snmp_hostres.so"
+.Sh DESCRIPTION
+The
+.Nm snmp_hostres
+module implements the HOST-RESOURCES-MIB as standardized in RFC 2790.
+.Sh RESTRICTIONS
+Not all information in the MIB is meaningful in FreeBSD or is available.
+The following variables are not implemented or carry no information:
+.Bl -tag -width "XXXXXXXXX"
+.It Va hrFSType
+There are several types of file systems for which no appropriate OID
+exists yet which are supported by FreeBSD.
+For smbfs, procfs and devfs
+.Va hrFSOther
+is returned.
+In all other cases
+.Va hrFSUnknown .
+.It Va hrFSBootable
+It is questionable what bootable means here.
+Does it mean that the BIOS is available to start a boot on that file system
+or does it mean that there is something bootable?
+In either case this information isn't available so this variable returns True
+for the root file system (which is not necessarily correct) and False for
+all others.
+.It Va hrFSLastFullBackupDate
+.It Va hrFSLastPartialBackupDate
+This is not available and always returns an empty string.
+Theoretically this could be retrieved from /etc/dumpdates, which would
+hardly be correct given the different ways of doing backups.
+.It Va hrDiskStorageTable
+Floppy devices are currently not reported.
+Also the names of the disks are hard-coded in the module.
+.El
+.Sh FILES
+.Bl -tag -width "XXXXXXXXX"
+.It Pa /usr/share/snmp/defs/hostres_tree.def
+The description of the MIB tree implemented by
+.Nm .
+.It Pa /usr/share/snmp/mibs/HOST-RESOURCES-TYPES.txt
+.It Pa /usr/share/snmp/mibs/HOST-RESOURCES-MIB.txt
+.It Pa /usr/share/snmp/mibs/BEGEMOT-HOSTRES-MIB.txt
+This is the MIB that is implemented by this module.
+.El
+.Sh SEE ALSO
+.Xr gensnmptree 1 ,
+.Xr snmpmod 3
+.Sh AUTHORS
+.An Victor Cruceru Aq soc-victor@freebsd.org
OpenPOWER on IntegriCloud