mirror of
https://git.FreeBSD.org/src.git
synced 2025-01-18 15:30:21 +00:00
msg
This commit is contained in:
parent
be0fee94a7
commit
d76947f322
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=154133
125
usr.sbin/bsnmpd/modules/snmp_hostres/BEGEMOT-HOSTRES-MIB.txt
Normal file
125
usr.sbin/bsnmpd/modules/snmp_hostres/BEGEMOT-HOSTRES-MIB.txt
Normal 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
|
82
usr.sbin/bsnmpd/modules/snmp_hostres/Makefile
Normal file
82
usr.sbin/bsnmpd/modules/snmp_hostres/Makefile
Normal 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
|
171
usr.sbin/bsnmpd/modules/snmp_hostres/hostres_begemot.c
Normal file
171
usr.sbin/bsnmpd/modules/snmp_hostres/hostres_begemot.c
Normal 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();
|
||||
}
|
612
usr.sbin/bsnmpd/modules/snmp_hostres/hostres_device_tbl.c
Normal file
612
usr.sbin/bsnmpd/modules/snmp_hostres/hostres_device_tbl.c
Normal 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();
|
||||
}
|
626
usr.sbin/bsnmpd/modules/snmp_hostres/hostres_diskstorage_tbl.c
Normal file
626
usr.sbin/bsnmpd/modules/snmp_hostres/hostres_diskstorage_tbl.c
Normal 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();
|
||||
}
|
440
usr.sbin/bsnmpd/modules/snmp_hostres/hostres_fs_tbl.c
Normal file
440
usr.sbin/bsnmpd/modules/snmp_hostres/hostres_fs_tbl.c
Normal 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();
|
||||
}
|
302
usr.sbin/bsnmpd/modules/snmp_hostres/hostres_network_tbl.c
Normal file
302
usr.sbin/bsnmpd/modules/snmp_hostres/hostres_network_tbl.c
Normal 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();
|
||||
}
|
415
usr.sbin/bsnmpd/modules/snmp_hostres/hostres_partition_tbl.c
Normal file
415
usr.sbin/bsnmpd/modules/snmp_hostres/hostres_partition_tbl.c
Normal 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();
|
||||
}
|
398
usr.sbin/bsnmpd/modules/snmp_hostres/hostres_printer_tbl.c
Normal file
398
usr.sbin/bsnmpd/modules/snmp_hostres/hostres_printer_tbl.c
Normal 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();
|
||||
}
|
506
usr.sbin/bsnmpd/modules/snmp_hostres/hostres_processor_tbl.c
Normal file
506
usr.sbin/bsnmpd/modules/snmp_hostres/hostres_processor_tbl.c
Normal 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();
|
||||
}
|
514
usr.sbin/bsnmpd/modules/snmp_hostres/hostres_scalars.c
Normal file
514
usr.sbin/bsnmpd/modules/snmp_hostres/hostres_scalars.c
Normal 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();
|
||||
}
|
209
usr.sbin/bsnmpd/modules/snmp_hostres/hostres_snmp.c
Normal file
209
usr.sbin/bsnmpd/modules/snmp_hostres/hostres_snmp.c
Normal 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);
|
||||
}
|
301
usr.sbin/bsnmpd/modules/snmp_hostres/hostres_snmp.h
Normal file
301
usr.sbin/bsnmpd/modules/snmp_hostres/hostres_snmp.h
Normal 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 */
|
648
usr.sbin/bsnmpd/modules/snmp_hostres/hostres_storage_tbl.c
Normal file
648
usr.sbin/bsnmpd/modules/snmp_hostres/hostres_storage_tbl.c
Normal 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();
|
||||
}
|
528
usr.sbin/bsnmpd/modules/snmp_hostres/hostres_swinstalled_tbl.c
Normal file
528
usr.sbin/bsnmpd/modules/snmp_hostres/hostres_swinstalled_tbl.c
Normal 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();
|
||||
}
|
||||
}
|
751
usr.sbin/bsnmpd/modules/snmp_hostres/hostres_swrun_tbl.c
Normal file
751
usr.sbin/bsnmpd/modules/snmp_hostres/hostres_swrun_tbl.c
Normal 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();
|
||||
}
|
292
usr.sbin/bsnmpd/modules/snmp_hostres/hostres_tree.def
Normal file
292
usr.sbin/bsnmpd/modules/snmp_hostres/hostres_tree.def
Normal 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)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
85
usr.sbin/bsnmpd/modules/snmp_hostres/snmp_hostres.3
Normal file
85
usr.sbin/bsnmpd/modules/snmp_hostres/snmp_hostres.3
Normal 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
|
Loading…
Reference in New Issue
Block a user