diff options
Diffstat (limited to 'usr.sbin/bsnmpd/modules/snmp_hostres/hostres_device_tbl.c')
-rw-r--r-- | usr.sbin/bsnmpd/modules/snmp_hostres/hostres_device_tbl.c | 690 |
1 files changed, 0 insertions, 690 deletions
diff --git a/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_device_tbl.c b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_device_tbl.c deleted file mode 100644 index cb38145..0000000 --- a/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_device_tbl.c +++ /dev/null @@ -1,690 +0,0 @@ - /*- - * 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 <sysexits.h> - -#include "hostres_snmp.h" -#include "hostres_oid.h" -#include "hostres_tree.h" - -#define FREE_DEV_STRUCT(entry_p) do { \ - free(entry_p->name); \ - free(entry_p->location); \ - free(entry_p->descr); \ - free(entry_p); \ -} while (0) - -/* - * 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 = NULL; - struct device_map_entry *map = NULL; - size_t name_len; - size_t location_len; - - assert((name[0] != 0) || (location[0] != 0)); - - if (name[0] == 0 && location[0] == 0) - return (NULL); - - STAILQ_FOREACH(map, &device_map, link) { - assert(map->name_key != NULL); - assert(map->location_key != NULL); - - if (strcmp(map->name_key, name) == 0 && - strcmp(map->location_key, location) == 0) { - break; - } - } - - if (map == NULL) { - /* new object - get a new index */ - if (next_device_index > INT_MAX) { - syslog(LOG_ERR, - "%s: hrDeviceTable index wrap", __func__); - /* There isn't much we can do here. - * If the next_swins_index is consumed - * then we can't add entries to this table - * So it is better to exit - if the table is sparsed - * at the next agent run we can fill it fully. - */ - errx(EX_SOFTWARE, "hrDeviceTable index wrap"); - /* not reachable */ - } - - if ((map = malloc(sizeof(*map))) == NULL) { - syslog(LOG_ERR, "hrDeviceTable: %s: %m", __func__ ); - return (NULL); - } - - map->entry_p = NULL; - - name_len = strlen(name) + 1; - if (name_len > DEV_NAME_MLEN) - name_len = DEV_NAME_MLEN; - - if ((map->name_key = malloc(name_len)) == NULL) { - syslog(LOG_ERR, "hrDeviceTable: %s: %m", __func__ ); - free(map); - return (NULL); - } - - location_len = strlen(location) + 1; - if (location_len > DEV_LOC_MLEN) - location_len = DEV_LOC_MLEN; - - if ((map->location_key = malloc(location_len )) == NULL) { - syslog(LOG_ERR, "hrDeviceTable: %s: %m", __func__ ); - free(map->name_key); - free(map); - return (NULL); - } - - map->hrIndex = next_device_index++; - - strlcpy(map->name_key, name, name_len); - strlcpy(map->location_key, location, location_len); - - 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); - } - - if ((entry = malloc(sizeof(*entry))) == NULL) { - syslog(LOG_WARNING, "hrDeviceTable: %s: %m", __func__); - return (NULL); - } - memset(entry, 0, sizeof(*entry)); - - entry->index = map->hrIndex; - map->entry_p = entry; - - if ((entry->name = strdup(map->name_key)) == NULL) { - syslog(LOG_ERR, "hrDeviceTable: %s: %m", __func__ ); - free(entry); - return (NULL); - } - - if ((entry->location = strdup(map->location_key)) == NULL) { - syslog(LOG_ERR, "hrDeviceTable: %s: %m", __func__ ); - free(entry->name); - free(entry); - return (NULL); - } - - /* - * From here till the end of this function we reuse name_len - * for a diferrent purpose - for device_entry::descr - */ - if (name[0] != '\0') - name_len = strlen(name) + strlen(descr) + - strlen(": ") + 1; - else - name_len = strlen(location) + strlen(descr) + - strlen("unknown at : ") + 1; - - if (name_len > DEV_DESCR_MLEN) - name_len = DEV_DESCR_MLEN; - - if ((entry->descr = malloc(name_len )) == NULL) { - syslog(LOG_ERR, "hrDeviceTable: %s: %m", __func__ ); - free(entry->name); - free(entry->location); - free(entry); - return (NULL); - } - - memset(&entry->descr[0], '\0', name_len); - - if (name[0] != '\0') - snprintf(entry->descr, name_len, - "%s: %s", name, descr); - else - snprintf(entry->descr, name_len, - "unknown at %s: %s", location, descr); - - entry->id = &oid_zeroDotZero; /* unknown id - FIXME */ - entry->status = (u_int)DS_UNKNOWN; - 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. - */ -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_DEV_STRUCT(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, const 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 DS_ALIVE: /* probe succeeded */ - case DS_NOTPRESENT: /* not probed or probe failed */ - return (DS_DOWN); - case DS_ATTACHED: /* attach method called */ - case DS_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 '?': - 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_DEV_STRUCT(n1->entry_p); - } - free(n1->name_key); - free(n1->location_key); - 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: - assert(entry->type != NULL); - 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(); -} |