This commit is contained in:
Hartmut Brandt 2006-01-09 12:33:45 +00:00
parent be0fee94a7
commit d76947f322
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=154133
18 changed files with 7005 additions and 0 deletions

View File

@ -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

View File

@ -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

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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);
}

View File

@ -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 */

View File

@ -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();
}

View File

@ -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();
}
}

View File

@ -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();
}

View File

@ -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)
)
)
)
)
)
)
)

View File

@ -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