Index: head/usr.sbin/bsnmpd/modules/new_hostres/hostres_device_tbl.c =================================================================== --- head/usr.sbin/bsnmpd/modules/new_hostres/hostres_device_tbl.c (revision 228149) +++ head/usr.sbin/bsnmpd/modules/new_hostres/hostres_device_tbl.c (working copy) @@ -1,9 +1,9 @@ /*- * Copyright (c) 2005-2006 The FreeBSD Project + * Copyright (c) 2005-2006 Victor Cruceru + * Copyright (c) 2011 Andrey V. Elsukov * All rights reserved. * - * Author: Victor Cruceru - * * 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: @@ -33,30 +33,66 @@ * Host Resources MIB: hrDeviceTable implementation for SNMPd. */ +#include +#include #include -#include #include #include #include +#include #include #include #include #include #include +#include + #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) +/* + * This structure describes HrDeviceEntry - an entry for one device + * contained by the host. Actually, there are devices reported by libdevinfo + * and GEOM providers as storage devices. + */ +struct device_entry { + int32_t index; + const struct asn_oid *type; + u_char *descr; + const struct asn_oid *id; + int32_t status; + uint32_t errors; + /* next are not from the SNMP mib table, only to be used internally */ + uint32_t flags; +#define HR_DEVICE_FOUND 0x001 +#define HR_DEVICE_IMMUTABLE 0x002 + u_char *name; + u_char *location; + TAILQ_ENTRY(device_entry) link; +}; +TAILQ_HEAD(device_tbl, device_entry); + /* + * Next structure is used to keep a list of mappings from a specific + * name and location to device index. We are trying to keep the same index + * for a specific name at least for the duration of one SNMP agent run. + * So, if some device gone and appears again with the same name and at the + * same location, then it will have the same hrDeviceIndex. + */ +struct device_map_entry { + int32_t index; + u_char *name; + u_char *location; + struct device_entry *entry; + SLIST_ENTRY(device_map_entry) link; +}; +SLIST_HEAD(device_map, device_map_entry); + +/* * Status of a device */ enum DeviceStatus { @@ -67,13 +103,11 @@ enum DeviceStatus { 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); +static struct device_map device_map = SLIST_HEAD_INITIALIZER(device_map); /* next int available for indexing the hrDeviceTable */ static uint32_t next_device_index = 1; @@ -82,7 +116,7 @@ static uint32_t next_device_index = 1; static uint64_t device_tick = 0; /* maximum number of ticks between updates of device table */ -uint32_t device_tbl_refresh = 10 * 100; +uint32_t device_tbl_refresh_rate = 10 * 100; /* socket for /var/run/devd.pipe */ static int devd_sock = -1; @@ -91,243 +125,409 @@ static int devd_sock = -1; static void *devd_fd; /* some constants */ +static const struct asn_oid OIDX_hrDeviceAudio_c = OIDX_hrDeviceAudio; +static const struct asn_oid OIDX_hrDeviceDiskStorage_c = + OIDX_hrDeviceDiskStorage; +static const struct asn_oid OIDX_hrDeviceNetwork_c = OIDX_hrDeviceNetwork; +static const struct asn_oid OIDX_hrDeviceOther_c = OIDX_hrDeviceOther; +static const struct asn_oid OIDX_hrDevicePrinter_c = OIDX_hrDevicePrinter; static const struct asn_oid OIDX_hrDeviceProcessor_c = OIDX_hrDeviceProcessor; -static const struct asn_oid OIDX_hrDeviceOther_c = OIDX_hrDeviceOther; +static const struct asn_oid OIDX_hrDeviceVideo_c = OIDX_hrDeviceVideo; -/** - * Create a new entry out of thin air. +/* + * Find an entry given its index. */ -struct device_entry * -device_entry_create(const char *name, const char *location, const char *descr) +static struct device_entry * +device_find_by_index(int32_t idx) { - struct device_entry *entry = NULL; - struct device_map_entry *map = NULL; - size_t name_len; - size_t location_len; + struct device_entry *entry; - assert((name[0] != 0) || (location[0] != 0)); + TAILQ_FOREACH(entry, &device_tbl, link) + if (entry->index == idx) + return (entry); + return (NULL); +} - if (name[0] == 0 && location[0] == 0) - return (NULL); +/* + * Find a device entry given its name. + */ +static struct device_entry * +device_find_by_name(const char *dev_name) +{ + struct device_map_entry *map; - STAILQ_FOREACH(map, &device_map, link) { - assert(map->name_key != NULL); - assert(map->location_key != NULL); + assert(dev_name != NULL && dev_name[0] != '\0'); + SLIST_FOREACH(map, &device_map, link) + if (strcmp(map->name, dev_name) == 0) + return (map->entry); + return (NULL); +} - if (strcmp(map->name_key, name) == 0 && - strcmp(map->location_key, location) == 0) { - break; - } - } +/* + * Find a device map entry given its name and location. + */ +static struct device_map_entry * +device_map_find(const char *name, const char *location) +{ + struct device_map_entry *map; - 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 */ - } + assert(name != NULL && name[0] != '\0'); + assert(location != NULL && location[0] != '\0'); - if ((map = malloc(sizeof(*map))) == NULL) { - syslog(LOG_ERR, "hrDeviceTable: %s: %m", __func__ ); - return (NULL); - } + if (name == NULL || name[0] == '\0' || + location == NULL || location[0] == '\0') + return (NULL); - map->entry_p = NULL; + SLIST_FOREACH(map, &device_map, link) + if (strcmp(map->name, name) == 0 && + strcmp(map->location, location) == 0) + return (map); + return (NULL); +} - name_len = strlen(name) + 1; - if (name_len > DEV_NAME_MLEN) - name_len = DEV_NAME_MLEN; +/* + * Create new device map entry. + */ +static struct device_map_entry * +device_map_create(const char *name, const char *location) +{ + struct device_map_entry *map; - if ((map->name_key = malloc(name_len)) == NULL) { - syslog(LOG_ERR, "hrDeviceTable: %s: %m", __func__ ); - free(map); - return (NULL); - } + assert(name != NULL && name[0] != '\0'); + assert(location != NULL && location[0] != '\0'); - location_len = strlen(location) + 1; - if (location_len > DEV_LOC_MLEN) - location_len = DEV_LOC_MLEN; + if (name == NULL || name[0] == '\0' || + location == NULL || location[0] == '\0') + return (NULL); - if ((map->location_key = malloc(location_len )) == NULL) { - syslog(LOG_ERR, "hrDeviceTable: %s: %m", __func__ ); - free(map->name_key); - free(map); - return (NULL); - } + /* new object - get a new index */ + if (next_device_index == INT32_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"); + } + if ((map = calloc(1, sizeof(*map))) == NULL) { + syslog(LOG_ERR, "hrDeviceTable: %s: %m", __func__ ); + return (NULL); + } + if ((map->name = strdup(name)) == NULL) { + syslog(LOG_ERR, "hrDeviceTable: %s: %m", __func__ ); + free(map); + return (NULL); + } + if ((map->location = strdup(location)) == NULL) { + syslog(LOG_ERR, "hrDeviceTable: %s: %m", __func__ ); + free(map->name); + free(map); + return (NULL); + } + map->index = next_device_index++; + SLIST_INSERT_HEAD(&device_map, map, link); + HRDBG("%s at %s added into hrDeviceMap at index=%d", name, + location, map->index); + return (map); +} - map->hrIndex = next_device_index++; +/* + * Create a new device entry. + */ +static struct device_entry * +device_entry_create(struct device_map_entry *map, const char *descr) +{ + struct device_entry *entry; - strlcpy(map->name_key, name, name_len); - strlcpy(map->location_key, location, location_len); + assert(map != NULL); + assert(map->entry == NULL); - 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) { + if ((entry = calloc(1, 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) { + if ((entry->name = strdup(map->name)) == NULL) { syslog(LOG_ERR, "hrDeviceTable: %s: %m", __func__ ); free(entry); return (NULL); } - - if ((entry->location = strdup(map->location_key)) == NULL) { + if ((entry->location = strdup(map->location)) == 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) { + if (descr != NULL) { + entry->descr = strndup(descr, DEV_DESCR_MLEN); + } else { + if ((entry->descr = malloc(DEV_DESCR_MLEN)) != NULL) + snprintf(entry->descr, DEV_DESCR_MLEN, "%s: %s", + map->name, map->location); + } + if (entry->descr == NULL) { syslog(LOG_ERR, "hrDeviceTable: %s: %m", __func__ ); + free(entry->location); 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; + map->entry = entry; + entry->index = map->index; + entry->id = &oid_zeroDotZero; + entry->status = (uint32_t)DS_UNKNOWN; 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) +static void +device_entry_free(struct device_entry *entry) { - 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)); + TAILQ_REMOVE(&device_tbl, entry, link); + free(entry->descr); + free(entry->location); + free(entry->name); + free(entry); } -/** +/* * Delete an entry from the device table. */ -void +static void device_entry_delete(struct device_entry *entry) { struct device_map_entry *map; assert(entry != NULL); + SLIST_FOREACH(map, &device_map, link) + if (map->entry == entry) { + map->entry = NULL; + break; + } + device_entry_free(entry); +} - TAILQ_REMOVE(&device_tbl, entry, link); +/* + * Create new disk storage device in the hrDeviceTable and return its + * hrDeviceIndex. + */ +int32_t +device_disk_add(const char *name, const char *location, const char *descr) +{ + struct device_map_entry *map; + struct device_entry *entry; - STAILQ_FOREACH(map, &device_map, link) - if (map->entry_p == entry) { - map->entry_p = NULL; - break; + map = device_map_find(name, location); + if (map != NULL) { + assert(map->entry == NULL); + if (map->entry != NULL) { + syslog(LOG_ERR, "disk %s already exists at %s in " + "hrDeviceTable index=%d", name, location, + map->index); + return (map->index); /* XXX */ } + } else { + map = device_map_create(name, location); + if (map == NULL) + return (-1); + } + entry = device_entry_create(map, descr); + if (entry == NULL) + return (-1); + entry->type = &OIDX_hrDeviceDiskStorage_c; + entry->status = (uint32_t)DS_RUNNING; + entry->flags |= HR_DEVICE_IMMUTABLE; + return (map->index); +} - FREE_DEV_STRUCT(entry); +void +device_disk_delete(int32_t idx) +{ + struct device_entry *entry; + + entry = device_find_by_index(idx); + if (entry == NULL) + return; + + assert(entry->type == &OIDX_hrDeviceDiskStorage_c); + if (entry->type == &OIDX_hrDeviceDiskStorage_c) + device_entry_delete(entry); } -/** - * Find an entry given its name and location +/* + * Create new processor device in the hrDeviceTable and return its + * hrDeviceIndex. It may already exists, if so, then mark it as + * immutable and set type to hrDeviceProcessor. */ -static struct device_entry * -device_find_by_dev(const struct devinfo_dev *dev_p) +int32_t +device_processor_add(const char *name, const char *location, const char *descr) { - struct device_map_entry *map; + struct device_map_entry *map; + struct device_entry *entry; - assert(dev_p != NULL); + map = device_map_find(name, location); + if (map == NULL) { + map = device_map_create(name, location); + if (map == NULL) + return (-1); + } + entry = map->entry; + if (entry == NULL) { + entry = device_entry_create(map, descr); + if (entry == NULL) + return (-1); + } + entry->type = &OIDX_hrDeviceProcessor_c; + entry->status = (uint32_t)DS_RUNNING; + entry->flags |= HR_DEVICE_IMMUTABLE; + return (map->index); +} - 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); +void +device_processor_delete(int32_t idx) +{ + struct device_entry *entry; + + entry = device_find_by_index(idx); + if (entry == NULL) + return; + + assert(entry->type == &OIDX_hrDeviceProcessor_c); + if (entry->type == &OIDX_hrDeviceProcessor_c) + device_entry_delete(entry); } -/** - * Find an entry given its index. +/* + * Create new network device entry in the hrDeviceTable and return its + * hrDeviceIndex. It may already exists, if so, then mark it as + * immutable and set type to hrDeviceNetwork. */ -struct device_entry * -device_find_by_index(int32_t idx) +int32_t +device_network_add(const char *name, const char *location, const char *descr, + int status) { + struct device_map_entry *map; struct device_entry *entry; - TAILQ_FOREACH(entry, &device_tbl, link) - if (entry->index == idx) - return (entry); - return (NULL); + switch (status) { + case 1: /* up */ + status = DS_RUNNING; + break; + case 2: /* down */ + status = DS_DOWN; + break; + default:/* dormant */ + status = DS_UNKNOWN; + } + entry = device_find_by_name(name); + if (entry != NULL && entry->type == &OIDX_hrDeviceNetwork_c) { + entry->status = (uint32_t)status; + entry->flags = HR_DEVICE_IMMUTABLE; + return (entry->index); + } + map = device_map_find(name, location); + if (map == NULL) { + map = device_map_create(name, location); + if (map == NULL) + return (-1); + } + entry = map->entry; + if (entry == NULL) { + entry = device_entry_create(map, descr); + if (entry == NULL) + return (-1); + } + entry->type = &OIDX_hrDeviceNetwork_c; + entry->status = (uint32_t)status; + entry->flags |= HR_DEVICE_IMMUTABLE; + return (map->index); } -/** - * Find an device entry given its name. +void +device_network_delete(int32_t idx) +{ + struct device_entry *entry; + + entry = device_find_by_index(idx); + if (entry == NULL) + return; + + assert(entry->type == &OIDX_hrDeviceNetwork_c); + if (entry->type == &OIDX_hrDeviceNetwork_c) + device_entry_delete(entry); +} + +/* + * Create new printer device entry in the hrDeviceTable and return its + * hrDeviceIndex. It may already exists, if so, then mark it as + * immutable and set type to hrDevicePrinter. */ -struct device_entry * -device_find_by_name(const char *dev_name) +int32_t +device_printer_add(const char *name, const char *location, const char *descr, + int status) { struct device_map_entry *map; + struct device_entry *entry; - assert(dev_name != NULL); + map = device_map_find(name, location); + if (map == NULL) { + map = device_map_create(name, location); + if (map == NULL) + return (-1); + } + entry = map->entry; + if (entry == NULL) { + entry = device_entry_create(map, descr); + if (entry == NULL) + return (-1); + } + entry->type = &OIDX_hrDevicePrinter_c; + /* idle, printing, warmup = running */ + if (status >= 3 && status <= 5) + entry->status = (uint32_t)DS_RUNNING; + else + entry->status = (uint32_t)DS_UNKNOWN; + entry->flags |= HR_DEVICE_IMMUTABLE; + return (map->index); +} - STAILQ_FOREACH(map, &device_map, link) - if (strcmp(map->name_key, dev_name) == 0) - return (map->entry_p); +void +device_printer_delete(int32_t idx) +{ + struct device_entry *entry; - return (NULL); + entry = device_find_by_index(idx); + if (entry == NULL) + return; + + assert(entry->type == &OIDX_hrDevicePrinter_c); + if (entry->type == &OIDX_hrDevicePrinter_c) + device_entry_delete(entry); } -/** - * Find out the type of device. CPU only currently. + +int32_t +device_get_index(const char *name, const char *location) +{ + struct device_map_entry *map; + + map = device_map_find(name, location); + if (map != NULL && map->entry != NULL) + return (map->index); + return (-1); +} + +/* + * Find out the type of device. */ static void device_get_type(struct devinfo_dev *dev_p, const struct asn_oid **out_type_p) { + char *p; + uint32_t value; assert(dev_p != NULL); assert(out_type_p != NULL); @@ -335,15 +535,42 @@ device_get_type(struct devinfo_dev *dev_p, const s 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; + if (dev_p->dd_pnpinfo[0] == '\0') return; + + p = strstr(dev_p->dd_pnpinfo, "class="); + if (p == NULL) + return; + + p += sizeof("class=") - 1; + value = (uint32_t)strtol(p, NULL, 16); + switch((value >> 16) & 0xFF) { + case PCIC_NETWORK: + /* + * XXX: there could be some devices with no driver attached. + * E.g. if a driver failed attach to a device, but since + * device is already probed it will have some name. + */ + *out_type_p = &OIDX_hrDeviceNetwork_c; + return; + case PCIC_DISPLAY: + *out_type_p = &OIDX_hrDeviceVideo_c; + return; + case PCIC_MULTIMEDIA: + switch ((value >> 8) & 0xFF) { + case PCIS_MULTIMEDIA_VIDEO: + *out_type_p = &OIDX_hrDeviceVideo_c; + return; + case PCIS_MULTIMEDIA_AUDIO: + case PCIS_MULTIMEDIA_HDA: + *out_type_p = &OIDX_hrDeviceAudio_c; + return; + } } } -/** - * Get the status of a device +/* + * Get the status of a device. */ static enum DeviceStatus device_get_status(struct devinfo_dev *dev) @@ -363,13 +590,14 @@ device_get_status(struct devinfo_dev *dev) } } -/** +/* * 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_map_entry *map; struct device_entry *entry; HRDBG("%llu/%llu name='%s' desc='%s' drivername='%s' location='%s'", @@ -377,60 +605,61 @@ device_collector(struct devinfo_dev *dev, void *ar (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", + if (dev->dd_name[0] != '\0' && dev->dd_location[0] != '\0') { + HRDBG("hrDeviceTable: analyzing dev %s at %s", dev->dd_name, dev->dd_location); - - if ((entry = device_find_by_dev(dev)) != NULL) { + entry = NULL; + map = device_map_find(dev->dd_name, dev->dd_location); + if (map == NULL) { + map = device_map_create(dev->dd_name, + dev->dd_location); + if (map != NULL) + entry = device_entry_create(map, dev->dd_desc); + if (entry != NULL) + device_get_type(dev, &entry->type); + } + if (entry != 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); + entry->status = (int32_t)device_get_status(dev); } } else { - HRDBG("SKIPPED unknown device at location '%s'", - dev->dd_location ); + /* + * XXX: probably we can handle unknown devices too. + */ + HRDBG("SKIPPED unknown device"); } - 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; + 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", + if ((d_sock = socket(AF_UNIX, 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", + return (-1); + } + bzero(&devd_addr, sizeof(struct sockaddr_un)); + devd_addr.sun_family = AF_UNIX; + strlcpy(devd_addr.sun_path, PATH_DEVD_PIPE, + sizeof(devd_addr.sun_path)); + devd_addr.sun_len = SUN_LEN(&devd_addr); + if (connect(d_sock, (struct sockaddr *)&devd_addr, + sizeof(devd_addr)) < 0) { + 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", + if (close(d_sock) < 0 ) + syslog(LOG_ERR,"Failed to close socket for %s: %m", PATH_DEVD_PIPE); return (-1); - } - - return (d_sock); + } + return (d_sock); } /* @@ -461,13 +690,12 @@ again: 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"); + syslog(LOG_ERR, "Failed to close devd socket: %m"); devd_sock = -1; if (devd_fd != NULL) { @@ -475,33 +703,32 @@ again: devd_fd = NULL; } syslog(LOG_ERR, "Closing devd_fd, revert to devinfo polling"); - } else { if (read_len == sizeof(buf)) goto again; - refresh_device_tbl(1); + device_tbl_refresh(1); } } -/** +/* * Initialize and populate the device table. */ void -init_device_tbl(void) +device_tbl_init(void) { /* initially populate table for the other tables */ - refresh_device_tbl(1); + device_tbl_refresh(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) +device_tbl_start(struct lmodule *mod) { if (devd_sock > 0) { @@ -511,14 +738,14 @@ void } } -/** +/* * Finalization routine for hrDeviceTable * It destroys the lists and frees any allocated heap memory */ void -fini_device_tbl(void) +device_tbl_fini(void) { - struct device_map_entry *n1; + struct device_map_entry *map; if (devd_fd != NULL) fd_deselect(devd_fd); @@ -527,53 +754,45 @@ void (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); - } + while (!SLIST_EMPTY(&device_map)) { + map = SLIST_FIRST(&device_map); + SLIST_REMOVE_HEAD(&device_map, link); + if (map->entry != NULL) + device_entry_free(map->entry); + free(map->name); + free(map->location); + free(map); + } 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) +device_tbl_refresh(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"); + if (!force && this_tick - device_tick < device_tbl_refresh_rate){ + HRDBG("hrDeviceTable: 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){ + dev_root = devinfo_handle_to_device(DEVINFO_ROOT_DEVICE); + if (dev_root == NULL){ syslog(LOG_ERR, "%s: can't get the root device: %m", __func__); - goto out; + devinfo_free(); + return; } /* mark each entry as missing */ @@ -584,35 +803,23 @@ void syslog(LOG_ERR, "%s: devinfo_foreach_device_child failed", __func__); - /* - * Purge items that disappeared - */ + /* 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 + * devinfo_foreach_device() call, or this entry was added + * from another device table handler. So we are not deleting * it there. */ - if (!(entry->flags & HR_DEVICE_FOUND) && - !(entry->flags & HR_DEVICE_IMMUTABLE)) + if ((entry->flags & HR_DEVICE_FOUND) == 0 && + (entry->flags & HR_DEVICE_IMMUTABLE) == 0) 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 @@ -623,10 +830,8 @@ op_hrDeviceTable(struct snmp_context *ctx __unused { struct device_entry *entry; - refresh_device_tbl(0); - + device_tbl_refresh(0); switch (curr_op) { - case SNMP_OP_GETNEXT: if ((entry = NEXT_OBJECT_INT(&device_tbl, &value->var, sub)) == NULL) @@ -653,32 +858,31 @@ op_hrDeviceTable(struct snmp_context *ctx __unused } abort(); - get: +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); + value->v.oid = *(entry->type); + return (SNMP_ERR_NOERROR); case LEAF_hrDeviceDescr: - return (string_get(value, entry->descr, -1)); + return (string_get(value, entry->descr, -1)); case LEAF_hrDeviceID: value->v.oid = *(entry->id); - return (SNMP_ERR_NOERROR); + return (SNMP_ERR_NOERROR); case LEAF_hrDeviceStatus: - value->v.integer = entry->status; - return (SNMP_ERR_NOERROR); + value->v.integer = entry->status; + return (SNMP_ERR_NOERROR); case LEAF_hrDeviceErrors: - value->v.uint32 = entry->errors; - return (SNMP_ERR_NOERROR); + value->v.uint32 = entry->errors; + return (SNMP_ERR_NOERROR); } abort(); } Index: head/usr.sbin/bsnmpd/modules/new_hostres/hostres_fs_tbl.c =================================================================== --- head/usr.sbin/bsnmpd/modules/new_hostres/hostres_fs_tbl.c (revision 228149) +++ head/usr.sbin/bsnmpd/modules/new_hostres/hostres_fs_tbl.c (working copy) @@ -89,20 +89,20 @@ TAILQ_HEAD(fs_tbl, fs_entry); * index for a specific name at least for the duration of one SNMP agent run. */ struct fs_map_entry { - int32_t hrIndex; /* used for fs_entry::index */ - u_char *a_name; /* map key same as fs_entry::mountPoint */ + int32_t index; /* used for fs_entry::index */ + u_char *name; /* map key same as fs_entry::mountPoint */ /* may be NULL if the respective hrFSTblEntry is (temporally) gone */ struct fs_entry *entry; - STAILQ_ENTRY(fs_map_entry) link; + SLIST_ENTRY(fs_map_entry) link; }; -STAILQ_HEAD(fs_map, fs_map_entry); +SLIST_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); +static struct fs_map fs_map = SLIST_HEAD_INITIALIZER(fs_map); /* next index available for hrFSTable */ static uint32_t next_fs_index = 1; @@ -111,7 +111,7 @@ static uint32_t next_fs_index = 1; static uint64_t fs_tick; /* maximum number of ticks between refreshs */ -uint32_t fs_tbl_refresh = HR_FS_TBL_REFRESH * 100; +uint32_t fs_tbl_refresh_rate = HR_FS_TBL_REFRESH * 100; /* some constants */ static const struct asn_oid OIDX_hrFSBerkeleyFFS_c = OIDX_hrFSBerkeleyFFS; @@ -145,7 +145,7 @@ static const struct { }; #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 * @@ -215,7 +215,7 @@ fs_entry_create(const char *name) return (entry); } -/** +/* * Delete an entry in the FS table. */ static void @@ -236,7 +236,7 @@ fs_entry_delete(struct fs_entry* entry) free(entry); } -/** +/* * Find a table entry by its name */ static struct fs_entry * @@ -251,15 +251,15 @@ fs_find_by_name(const char *name) return (NULL); } -/** +/* * Get rid of all data */ void -fini_fs_tbl(void) +fs_tbl_fini(void) { struct fs_map_entry *n1; - while ((n1 = STAILQ_FIRST(&fs_map)) != NULL) { + while ((n1 = STAILQ_FIRST(&fs_map)) != NULL) { STAILQ_REMOVE_HEAD(&fs_map, link); if (n1->entry != NULL) { TAILQ_REMOVE(&fs_tbl, n1->entry, link); @@ -269,11 +269,11 @@ void } free(n1->a_name); free(n1); - } + } assert(TAILQ_EMPTY(&fs_tbl)); } -/** +/* * Called before the refreshing is started from the storage table. */ void @@ -308,11 +308,11 @@ fs_tbl_post_refresh(void) * Refresh the FS table. This is done by forcing a refresh of the storage table. */ void -refresh_fs_tbl(void) +fs_tbl_refresh(void) { if (fs_tick == 0 || this_tick - fs_tick >= fs_tbl_refresh) { - refresh_storage_tbl(1); + storage_tbl_refresh(1); HRDBG("refresh DONE"); } } @@ -400,10 +400,8 @@ op_hrFSTable(struct snmp_context *ctx __unused, st { struct fs_entry *entry; - refresh_fs_tbl(); - + fs_tbl_refresh(); switch (curr_op) { - case SNMP_OP_GETNEXT: if ((entry = NEXT_OBJECT_INT(&fs_tbl, &value->var, sub)) == NULL) @@ -431,7 +429,6 @@ op_hrFSTable(struct snmp_context *ctx __unused, st abort(); get: switch (value->var.subs[sub - 1]) { - case LEAF_hrFSIndex: value->v.integer = entry->index; return (SNMP_ERR_NOERROR); Index: head/usr.sbin/bsnmpd/modules/new_hostres/hostres_diskstorage_tbl.c =================================================================== --- head/usr.sbin/bsnmpd/modules/new_hostres/hostres_diskstorage_tbl.c (revision 228149) +++ head/usr.sbin/bsnmpd/modules/new_hostres/hostres_diskstorage_tbl.c (working copy) @@ -1,9 +1,9 @@ /*- * Copyright (c) 2005-2006 The FreeBSD Project + * Copyright (c) 2005-2006 Victor Cruceru + * Copyright (c) 2011 Andrey V. Elsukov * All rights reserved. * - * Author: Victor Cruceru - * * 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: @@ -33,22 +33,12 @@ * Host Resources MIB for SNMPd. Implementation for the hrDiskStorageTable */ -#include -#include -#include -#include -#include -#include -#include -#include - #include -#include -#include -#include -#include +#include +#include #include #include +#include #include #include @@ -66,9 +56,9 @@ enum hrDiskStrorageMedia { DSM_UNKNOWN = 2, DSM_HARDDISK = 3, DSM_FLOPPYDISK = 4, - DSM_OPTICALDISKROM= 5, - DSM_OPTICALDISKWORM= 6, - DSM_OPTICALDISKRW= 7, + DSM_OPTICALDISKROM = 5, + DSM_OPTICALDISKWORM = 6, + DSM_OPTICALDISKRW = 7, DSM_RAMDISK = 8 }; @@ -84,114 +74,65 @@ struct disk_entry { int32_t index; int32_t access; /* enum hrDiskStrorageAccess */ int32_t media; /* enum hrDiskStrorageMedia*/ - int32_t removable; /* enum snmpTCTruthValue*/ + 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) */ +#define HR_DISKSTORAGE_FOUND 0x001 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); +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; +uint32_t disk_storage_tbl_refresh_rate = HR_DISK_TBL_REFRESH * 100; -/* fd for "/dev/mdctl"*/ -static int md_fd = -1; +/* the list of GEOM class names */ +static StringList *disk_classes = NULL; -/* 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. +/* + * GEOM helpers. */ -static void -mdmaybeload(void) +struct gclass * +geom_find_class(struct gmesh *mesh, const char *name) { - char name1[64], name2[64]; + struct gclass *classp; - 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); - } - } + assert(mesh != NULL); + assert(name != NULL); + + LIST_FOREACH(classp, &mesh->lg_class, lg_class) { + if (strcmp(classp->lg_name, name) == 0) + return (classp); } + return (NULL); } -/** - * Create a new entry into the DiskStorageTable. - */ -static struct disk_entry * -disk_entry_create(const struct device_entry *devEntry) +const char * +geom_find_provcfg(struct gprovider *pp, const char *cfg) { - struct disk_entry *entry; + static const char *empty = ""; + struct gconfig *gc; - assert(devEntry != NULL); - if (devEntry == NULL) - return NULL; + assert(pp != NULL); + assert(cfg != NULL); - if ((entry = malloc(sizeof(*entry))) == NULL) { - syslog(LOG_WARNING, "hrDiskStorageTable: %s: %m", __func__); - return (NULL); + LIST_FOREACH(gc, &pp->lg_config, lg_config) { + if (!strcmp(gc->lg_name, cfg)) + return (gc->lg_val); } - - memset(entry, 0, sizeof(*entry)); - entry->index = devEntry->index; - INSERT_OBJECT_INT(entry, &disk_tbl); - - return (entry); + return (empty); } -/** - * Delete a disk table entry. - */ -static void -disk_entry_delete(struct disk_entry *entry) -{ - struct device_entry *devEntry; - - assert(entry != NULL); - TAILQ_REMOVE(&disk_tbl, entry, link); - - devEntry = device_find_by_index(entry->index); - - free(entry); - - /* - * Also delete the respective device entry - - * this is needed for disk devices that are not - * detected by libdevinfo - */ - if (devEntry != NULL && - (devEntry->flags & HR_DEVICE_IMMUTABLE) == HR_DEVICE_IMMUTABLE) - device_entry_delete(devEntry); -} - -/** +/* * Find a disk storage entry given its index. */ static struct disk_entry * @@ -202,360 +143,207 @@ disk_find_by_index(int32_t idx) TAILQ_FOREACH(entry, &disk_tbl, link) if (entry->index == idx) return (entry); - return (NULL); } -/** - * Get the disk parameters +/* + * Create a new entry into the hrDiskStorageTable. */ -static void -disk_query_disk(struct disk_entry *entry) +static struct disk_entry * +disk_entry_create(int32_t idx) { - char dev_path[128]; - int fd; - off_t mediasize; + struct disk_entry *entry; - 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; + assert(idx > 0); + if ((entry = calloc(1, sizeof(*entry))) == NULL) { + syslog(LOG_WARNING, "hrDiskStorageTable: %s: %m", __func__); + return (NULL); } - - 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); - partition_tbl_handle_disk(entry->index, entry->dev_name); - - (void)close(fd); + entry->index = idx; + INSERT_OBJECT_INT(entry, &disk_tbl); + return (entry); } -/** - * Find all ATA disks in the device table. +/* + * Delete a disk table entry. */ static void -disk_OS_get_ATA_disks(void) +disk_entry_delete(struct disk_entry *entry) { - struct device_map_entry *map; - struct device_entry *entry; - struct disk_entry *disk_entry; - const struct disk_entry *found; + assert(entry != NULL); - /* 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; - - /* - * Avoid false disk devices. For example adw(4) and - * adv(4) - they are not disks! - */ - if (strlen(map->name_key) > strlen(found->dev_name) && - !isdigit(map->name_key[strlen(found->dev_name)])) - 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; - } - } + TAILQ_REMOVE(&disk_tbl, entry, link); + device_disk_delete(entry->index); + free(entry); } -/** - * Find MD disks in the device table. +/* + * Collect storage devices for the given GEOM class name. */ static void -disk_OS_get_MD_disks(void) +disk_geom_class_handle(struct gmesh *mesh, const char *name) { - struct device_map_entry *map; - struct device_entry *entry; - struct disk_entry *disk_entry; - struct md_ioctl mdio; - int unit; + struct gclass *cp; + struct ggeom *gp; + struct gprovider *pp; + struct disk_entry *entry; + off_t size; + int32_t idx; - if (md_fd <= 0) + cp = geom_find_class(mesh, name); + if (cp == NULL) return; - - /* 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; + LIST_FOREACH(gp, &cp->lg_geom, lg_geom) { + LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { + /* + * Get the hrDeviceIndex of this storage device. + * As device name use provider's name and class + * name of its geom as device location. + */ + idx = device_get_index(pp->lg_name, + gp->lg_class->lg_name); + if (idx == -1) { + idx = device_disk_add(pp->lg_name, + gp->lg_class->lg_name, + geom_find_provcfg(pp, "descr")); + if (idx == -1) { + syslog(LOG_ERR, "Could not create " + "new disk device entry for %s.", + pp->lg_name); + 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; + entry = disk_find_by_index(idx); + if (entry == NULL) { + entry = disk_entry_create(idx); + if (entry == NULL) + continue; + } + entry->flags |= HR_DISKSTORAGE_FOUND; + size = pp->lg_mediasize / 1024; + entry->capacity = size > INT32_MAX ? INT32_MAX: size; + entry->access = DS_READ_WRITE; /* XXX */ + entry->removable = SNMP_FALSE; + if (strcmp(name, "DISK") == 0) { + if (strncmp(pp->lg_name, "cd", 2) == 0 || + strncmp(pp->lg_name, "acd", 3) == 0) { + entry->media = DSM_OPTICALDISKROM; + entry->removable = SNMP_TRUE; + } else + entry->media = DSM_HARDDISK; + } else if (strcmp(name, "MD") == 0){ + entry->media = DSM_RAMDISK; + if (strcmp(geom_find_provcfg(pp, "access"), + "read-only") == 0) + entry->access = DS_READ_ONLY; + } else + entry->media = DSM_OTHER; } - - disk_entry->flags |= HR_DISKSTORAGE_FOUND; - disk_entry->flags |= HR_DISKSTORAGE_MD; - disk_entry->r_tick = this_tick; } } -/** - * Find rest of disks +/* + * Create new disk storage device and return its hrDeviceIndex. */ -static void -disk_OS_get_disks(void) +int32_t +disk_storage_add(struct gmesh *mesh, struct gprovider *pp) { - size_t disk_cnt = 0; - struct device_entry *entry; - struct disk_entry *disk_entry; + char *p; + int32_t idx; - 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; + /* get hrDeviceIndex for this storage device */ + idx = device_get_index(pp->lg_name, pp->lg_geom->lg_class->lg_name); + if (idx > 0) + return (idx); + if (sl_find(disk_classes, pp->lg_geom->lg_class->lg_name) == NULL) { + /* add geom class name to the list of known storage classes. */ + p = strdup(pp->lg_geom->lg_class->lg_name); + if (p == NULL) + return (-1); + if (sl_add(disk_classes, p) != 0) { + free(p); + return (-1); + } + HRDBG("hrDiskStorageTable: new storage class %s", p); } - - 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); + /* handle all providers of this (new?) storage class */ + disk_geom_class_handle(mesh, pp->lg_geom->lg_class->lg_name); + /* and try again get hrDeviceIndex */ + idx = device_get_index(pp->lg_name, pp->lg_geom->lg_class->lg_name); + if (idx < 0) { + syslog(LOG_ERR, "hrDiskStorageTable: %s:%s not found in the " + "hrDeviceTable", pp->lg_name, + pp->lg_geom->lg_class->lg_name); + return (-1); } - - 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 - */ - syslog(LOG_WARNING, "%s: adding device '%s' to " - "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 || - strncmp(disk_entry->dev_name, "ada", 3) == 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; - } + return (idx); } -/** +/* * Refresh routine for hrDiskStorageTable * Usable for polling the system for any changes. */ void -refresh_disk_storage_tbl(int force) +disk_storage_tbl_refresh(int force) { + struct gmesh mesh; struct disk_entry *entry, *entry_tmp; + size_t i; - if (disk_storage_tick != 0 && !force && - this_tick - disk_storage_tick < disk_storage_tbl_refresh) { - HRDBG("no refresh needed"); + if (!force && + this_tick - disk_storage_tick < disk_storage_tbl_refresh_rate) { + HRDBG("hrDiskStorageTable: 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(); + if (geom_gettree(&mesh) == 0) { + for (i = 0; i < disk_classes->sl_cur; i++) { + assert(disk_classes->sl_str[i] != NULL); + disk_geom_class_handle(&mesh, disk_classes->sl_str[i]); + } + geom_deletetree(&mesh); + } - /* - * Purge items that disappeared - */ + /* 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 */ + if ((entry->flags & HR_DISKSTORAGE_FOUND) == 0) disk_entry_delete(entry); disk_storage_tick = this_tick; - - partition_tbl_post_refresh(); - - HRDBG("refresh DONE"); + HRDBG("hrDiskStorageTable: refresh DONE"); } /* * Init the things for both of hrDiskStorageTable */ int -init_disk_storage_tbl(void) +disk_storage_tbl_init(void) { - char mddev[32] = ""; + const char *classes[] = {"DISK", "MD"}; + char *p; + size_t i; - /* 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 - will not include md(4) " - "info: %m", mddev); + disk_classes = sl_init(); + if (disk_classes == NULL) + return (-1); + for (i = 0; i < sizeof(classes) / sizeof(classes[0]); i++) { + p = strdup(classes[i]); + if (p != NULL) { + if (sl_add(disk_classes, p) == 0) + continue; + free(p); + } + break; } - - refresh_disk_storage_tbl(1); - + if (disk_classes->sl_cur == 0) { + sl_free(disk_classes, 0); + return (-1); + } + disk_storage_tbl_refresh(1); return (0); } @@ -564,22 +352,13 @@ int * It destroys the lists and frees any allocated heap memory */ void -fini_disk_storage_tbl(void) +disk_storage_tbl_fini(void) { - struct disk_entry *n1; + struct disk_entry *entry; - 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; - } + while ((entry = TAILQ_FIRST(&disk_tbl)) != NULL) + disk_entry_delete(entry); + sl_free(disk_classes, 1); } /* @@ -594,10 +373,8 @@ op_hrDiskStorageTable(struct snmp_context *ctx __u { struct disk_entry *entry; - refresh_disk_storage_tbl(0); - + disk_storage_tbl_refresh(0); switch (curr_op) { - case SNMP_OP_GETNEXT: if ((entry = NEXT_OBJECT_INT(&disk_tbl, &value->var, sub)) == NULL) @@ -620,28 +397,27 @@ op_hrDiskStorageTable(struct snmp_context *ctx __u case SNMP_OP_ROLLBACK: case SNMP_OP_COMMIT: - abort(); + abort(); } abort(); get: switch (value->var.subs[sub - 1]) { - case LEAF_hrDiskStorageAccess: - value->v.integer = entry->access; - return (SNMP_ERR_NOERROR); + value->v.integer = entry->access; + return (SNMP_ERR_NOERROR); case LEAF_hrDiskStorageMedia: - value->v.integer = entry->media; - return (SNMP_ERR_NOERROR); + value->v.integer = entry->media; + return (SNMP_ERR_NOERROR); case LEAF_hrDiskStorageRemovable: - value->v.integer = entry->removable; - return (SNMP_ERR_NOERROR); + value->v.integer = entry->removable; + return (SNMP_ERR_NOERROR); case LEAF_hrDiskStorageCapacity: - value->v.integer = entry->capacity; - return (SNMP_ERR_NOERROR); + value->v.integer = entry->capacity; + return (SNMP_ERR_NOERROR); } abort(); } Index: head/usr.sbin/bsnmpd/modules/new_hostres/hostres_processor_tbl.c =================================================================== --- head/usr.sbin/bsnmpd/modules/new_hostres/hostres_processor_tbl.c (revision 228149) +++ head/usr.sbin/bsnmpd/modules/new_hostres/hostres_processor_tbl.c (working copy) @@ -1,9 +1,9 @@ /*- * Copyright (c) 2005-2006 The FreeBSD Project + * Copyright (c) 2005-2006 Victor Cruceru + * Copyright (c) 2011 Andrey V. Elsukov * All rights reserved. * - * Author: Victor Cruceru - * * 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: @@ -33,7 +33,7 @@ * Host Resources MIB for SNMPd. Implementation for hrProcessorTable */ -#include +#include #include #include @@ -60,7 +60,7 @@ struct processor_entry { int32_t sample_cnt; /* number of usage samples */ int32_t cur_sample_idx; /* current valid sample */ TAILQ_ENTRY(processor_entry) link; - u_char cpu_no; /* which cpu, counted from 0 */ + int cpu_no; /* which cpu, counted from 0 */ /* the samples from the last minute, as required by MIB */ double samples[MAX_CPU_SAMPLES]; @@ -72,15 +72,12 @@ TAILQ_HEAD(processor_tbl, processor_entry); 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.cp_times) */ static int cpmib[2]; -static size_t cplen; +static long *cp_times; /* periodic timer used to get cpu load stats */ static void *cpus_load_timer; @@ -101,7 +98,7 @@ get_avg_load(struct processor_entry *e) assert(e != NULL); /* Need two samples to perform delta calculation. */ - if (e->sample_cnt <= 1) + if (e->sample_cnt < 2) return (0); /* Oldest usable index, we wrap around. */ @@ -116,12 +113,14 @@ get_avg_load(struct processor_entry *e) delta -= e->states[oldest][i]; } if (delta == 0) - return 0; + return (0); - /* Take idle time from the last element and convert to - * percent usage by contrasting with total ticks delta. */ - usage = (double)(e->states[e->cur_sample_idx][CPUSTATES-1] - - e->states[oldest][CPUSTATES-1]) / delta; + /* + * Take idle time from the last element and convert to + * percent usage by contrasting with total ticks delta. + */ + usage = (double)(e->states[e->cur_sample_idx][CP_IDLE] - + e->states[oldest][CP_IDLE]) / delta; usage = 100 - (usage * 100); HRDBG("CPU no. %d, delta ticks %ld, pct usage %.2f", e->cpu_no, delta, usage); @@ -129,194 +128,94 @@ get_avg_load(struct processor_entry *e) return ((int)(usage)); } -/** +/* * Save a new sample to proc entry and get the average usage. * * Samples are stored in a ringbuffer from 0..(MAX_CPU_SAMPLES-1) */ static void -save_sample(struct processor_entry *e, long *cp_times) +save_sample(struct processor_entry *e, long *cp_time) { int i; e->cur_sample_idx = (e->cur_sample_idx + 1) % MAX_CPU_SAMPLES; - for (i = 0; cp_times != NULL && i < CPUSTATES; i++) - e->states[e->cur_sample_idx][i] = cp_times[i]; + for (i = 0; cp_time != NULL && i < CPUSTATES; i++) + e->states[e->cur_sample_idx][i] = cp_time[i]; - e->sample_cnt++; - if (e->sample_cnt > MAX_CPU_SAMPLES) - e->sample_cnt = MAX_CPU_SAMPLES; + if (e->sample_cnt < MAX_CPU_SAMPLES) + e->sample_cnt++; HRDBG("sample count for CPU no. %d went to %d", e->cpu_no, e->sample_cnt); e->load = get_avg_load(e); } -/** +/* * Create a new entry into the processor table. */ static struct processor_entry * -proc_create_entry(u_int cpu_no, struct device_map_entry *map) +processor_entry_create(int32_t idx, int cpu_no) { - 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 " + if ((entry = calloc(1, sizeof(*entry))) == NULL) { + syslog(LOG_ERR, "hrProcessorTable: %s calloc " "failed: %m", __func__); return (NULL); } - memset(entry, 0, sizeof(*entry)); - - entry->index = map->hrIndex; + entry->index = idx; entry->load = 0; entry->sample_cnt = 0; entry->cur_sample_idx = -1; - entry->cpu_no = (u_char)cpu_no; - entry->frwId = &oid_zeroDotZero; /* unknown id FIXME */ + entry->cpu_no = cpu_no; + entry->frwId = &oid_zeroDotZero; INSERT_OBJECT_INT(entry, &processor_tbl); - HRDBG("CPU %d added with SNMP index=%d", entry->cpu_no, entry->index); - return (entry); } -/** - * Scan the device map table for CPUs and create an entry into the - * processor table for each CPU. - * - * 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. +/* + * Free the processor table */ static void -create_proc_table(void) +processor_tbl_free(void) { - struct device_map_entry *map; struct processor_entry *entry; - int cpu_no; - size_t len; - 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, - * therefore insert them after checking hw.ncpu. - */ - 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++; - } - - len = sizeof(hw_ncpu); - if (sysctlbyname("hw.ncpu", &hw_ncpu, &len, NULL, 0) == -1 || - len != sizeof(hw_ncpu)) { - syslog(LOG_ERR, "hrProcessorTable: sysctl(hw.ncpu) failed"); - hw_ncpu = 0; + while ((entry = TAILQ_FIRST(&processor_tbl)) != NULL) { + TAILQ_REMOVE(&processor_tbl, entry, link); + device_processor_delete(entry->index); + free(entry); } - - HRDBG("%d CPUs detected via device table; hw.ncpu is %d", - detected_processor_count, hw_ncpu); - - /* XXX Can happen on non-ACPI systems? Create entries by hand. */ - for (; detected_processor_count < hw_ncpu; detected_processor_count++) - proc_create_entry(detected_processor_count, NULL); - - len = 2; - if (sysctlnametomib("kern.cp_times", cpmib, &len)) { - syslog(LOG_ERR, "hrProcessorTable: sysctlnametomib(kern.cp_times) failed"); - cpmib[0] = 0; - cpmib[1] = 0; - cplen = 0; - } else if (sysctl(cpmib, 2, NULL, &len, NULL, 0)) { - syslog(LOG_ERR, "hrProcessorTable: sysctl(kern.cp_times) length query failed"); - cplen = 0; - } else { - cplen = len / sizeof(long); - } - HRDBG("%zu entries for kern.cp_times", cplen); - } -/** - * 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; -} - -/** +/* * Refresh all values in the processor table. We call this once for * every PDU that accesses the table. */ static void -refresh_processor_tbl(void) +processor_tbl_refresh(void) { struct processor_entry *entry; size_t size; - long pcpu_cp_times[cplen]; - memset(pcpu_cp_times, 0, sizeof(pcpu_cp_times)); - - size = cplen * sizeof(long); - if (sysctl(cpmib, 2, pcpu_cp_times, &size, NULL, 0) == -1 && - !(errno == ENOMEM && size >= cplen * sizeof(long))) { - syslog(LOG_ERR, "hrProcessorTable: sysctl(kern.cp_times) failed"); + size = hw_ncpu * CPUSTATES * sizeof(long); + if (sysctl(cpmib, 2, cp_times, &size, NULL, 0) != 0) { + syslog(LOG_ERR, + "hrProcessorTable: sysctl(kern.cp_times) failed"); return; } TAILQ_FOREACH(entry, &processor_tbl, link) { - assert(hr_kd != NULL); - save_sample(entry, &pcpu_cp_times[entry->cpu_no * CPUSTATES]); + save_sample(entry, &cp_times[entry->cpu_no * CPUSTATES]); } } -/** +/* * This function is called MAX_CPU_SAMPLES times per minute to collect the * CPU load. */ @@ -325,7 +224,7 @@ get_cpus_samples(void *arg __unused) { HRDBG("[%llu] ENTER", (unsigned long long)get_ticks()); - refresh_processor_tbl(); + processor_tbl_refresh(); HRDBG("[%llu] EXIT", (unsigned long long)get_ticks()); } @@ -334,7 +233,7 @@ get_cpus_samples(void *arg __unused) * time collection. */ void -start_processor_tbl(struct lmodule *mod) +processor_tbl_start(struct lmodule *mod) { /* @@ -347,18 +246,63 @@ void get_cpus_samples, NULL, mod); } -/** +/* * Init the things for hrProcessorTable. - * Scan the device table for processor entries. */ -void -init_processor_tbl(void) +int +processor_tbl_init(void) { + struct processor_entry *entry; + char name[BUFSIZ], desc[BUFSIZ], location[BUFSIZ]; + size_t len; + int32_t idx; + int cpu, error; + /* get the number of processors */ + len = sizeof(hw_ncpu); + if (sysctlbyname("hw.ncpu", &hw_ncpu, &len, NULL, 0) == -1 || + len != sizeof(hw_ncpu)) { + syslog(LOG_ERR, "hrProcessorTable: sysctl(hw.ncpu) failed"); + return (-1) + } + HRDBG("hrProcessorTable: %d CPUs detected", hw_ncpu); + /* create the initial processor table */ - create_proc_table(); - /* and get first samples */ - refresh_processor_tbl(); + for (cpu = 0; cpu < hw_ncpu; cpu++) { + len = sizeof(desc); + snprintf(name, sizeof(name), "dev.cpu.%d.%%desc", cpu); + error = sysctlbyname(name, desc, &len, NULL, 0); + if (error != 0 || len == 0) + goto fail; + len = sizeof(location); + snprintf(name, sizeof(name), "dev.cpu.%d.%%location", cpu); + error = sysctlbyname(name, location, &len, NULL, 0); + if (error != 0 || len == 0) + goto fail; + snprintf(name, sizeof(name), "cpu%d", cpu); + idx = device_processor_add(name, location, desc); + if (idx < 1) + goto fail; + entry = processor_entry_create(idx, cpu); + if (entry == NULL) + goto fail; + } + + len = 2; + error = sysctlnametomib("kern.cp_times", cpmib, &len); + if (error != 0) + goto fail; + cp_times = calloc(hw_ncpu * CPUSTATES, sizeof(long)); + if (cp_times == NULL) + goto fail; + + /* get first samples */ + processor_tbl_refresh(); + return (0); +fail: + syslog(LOG_ERR, "hrProcessorTable: initialization failed"); + processor_tbl_free(); + return (-1); } /** @@ -366,15 +310,15 @@ void * It destroys the lists and frees any allocated heap memory. */ void -fini_processor_tbl(void) +processor_tbl_fini(void) { if (cpus_load_timer != NULL) { timer_stop(cpus_load_timer); cpus_load_timer = NULL; } - - free_proc_table(); + processor_tbl_free(); + free(cp_times); } /** @@ -388,7 +332,6 @@ op_hrProcessorTable(struct snmp_context *ctx __unu struct processor_entry *entry; switch (curr_op) { - case SNMP_OP_GETNEXT: if ((entry = NEXT_OBJECT_INT(&processor_tbl, &value->var, sub)) == NULL) @@ -417,7 +360,6 @@ op_hrProcessorTable(struct snmp_context *ctx __unu get: switch (value->var.subs[sub - 1]) { - case LEAF_hrProcessorFrwID: assert(entry->frwId != NULL); value->v.oid = *entry->frwId; Index: head/usr.sbin/bsnmpd/modules/new_hostres/hostres_begemot.c =================================================================== --- head/usr.sbin/bsnmpd/modules/new_hostres/hostres_begemot.c (revision 228149) +++ head/usr.sbin/bsnmpd/modules/new_hostres/hostres_begemot.c (working copy) @@ -42,32 +42,31 @@ op_begemot(struct snmp_context *ctx, struct snmp_v { switch (op) { - case SNMP_OP_GET: switch (value->var.subs[sub - 1]) { case LEAF_begemotHrStorageUpdate: - value->v.uint32 = storage_tbl_refresh; + value->v.uint32 = storage_tbl_refresh_rate; return (SNMP_ERR_NOERROR); case LEAF_begemotHrFSUpdate: - value->v.uint32 = fs_tbl_refresh; + value->v.uint32 = fs_tbl_refresh_rate; return (SNMP_ERR_NOERROR); case LEAF_begemotHrDiskStorageUpdate: - value->v.uint32 = disk_storage_tbl_refresh; + value->v.uint32 = disk_storage_tbl_refresh_rate; return (SNMP_ERR_NOERROR); case LEAF_begemotHrNetworkUpdate: - value->v.uint32 = network_tbl_refresh; + value->v.uint32 = network_tbl_refresh_rate; return (SNMP_ERR_NOERROR); case LEAF_begemotHrSWInstalledUpdate: - value->v.uint32 = swins_tbl_refresh; + value->v.uint32 = swins_tbl_refresh_rate; return (SNMP_ERR_NOERROR); case LEAF_begemotHrSWRunUpdate: - value->v.uint32 = swrun_tbl_refresh; + value->v.uint32 = swrun_tbl_refresh_rate; return (SNMP_ERR_NOERROR); case LEAF_begemotHrPkgDir: @@ -82,33 +81,33 @@ op_begemot(struct snmp_context *ctx, struct snmp_v switch (value->var.subs[sub - 1]) { case LEAF_begemotHrStorageUpdate: - ctx->scratch->int1 = storage_tbl_refresh; - storage_tbl_refresh = value->v.uint32; + ctx->scratch->int1 = storage_tbl_refresh_rate; + storage_tbl_refresh_rate = value->v.uint32; return (SNMP_ERR_NOERROR); case LEAF_begemotHrFSUpdate: - ctx->scratch->int1 = fs_tbl_refresh; - fs_tbl_refresh = value->v.uint32; + ctx->scratch->int1 = fs_tbl_refresh_rate; + fs_tbl_refresh_rate = value->v.uint32; return (SNMP_ERR_NOERROR); case LEAF_begemotHrDiskStorageUpdate: - ctx->scratch->int1 = disk_storage_tbl_refresh; - disk_storage_tbl_refresh = value->v.uint32; + ctx->scratch->int1 = disk_storage_tbl_refresh_rate; + disk_storage_tbl_refresh_rate = value->v.uint32; return (SNMP_ERR_NOERROR); case LEAF_begemotHrNetworkUpdate: - ctx->scratch->int1 = network_tbl_refresh; - network_tbl_refresh = value->v.uint32; + ctx->scratch->int1 = network_tbl_refresh_rate; + network_tbl_refresh_rate = value->v.uint32; return (SNMP_ERR_NOERROR); case LEAF_begemotHrSWInstalledUpdate: - ctx->scratch->int1 = swins_tbl_refresh; - swins_tbl_refresh = value->v.uint32; + ctx->scratch->int1 = swins_tbl_refresh_rate; + swins_tbl_refresh_rate = value->v.uint32; return (SNMP_ERR_NOERROR); case LEAF_begemotHrSWRunUpdate: - ctx->scratch->int1 = swrun_tbl_refresh; - swrun_tbl_refresh = value->v.uint32; + ctx->scratch->int1 = swrun_tbl_refresh_rate; + swrun_tbl_refresh_rate = value->v.uint32; return (SNMP_ERR_NOERROR); case LEAF_begemotHrPkgDir: @@ -137,27 +136,27 @@ op_begemot(struct snmp_context *ctx, struct snmp_v switch (value->var.subs[sub - 1]) { case LEAF_begemotHrStorageUpdate: - storage_tbl_refresh = ctx->scratch->int1; + storage_tbl_refresh_rate = ctx->scratch->int1; return (SNMP_ERR_NOERROR); case LEAF_begemotHrFSUpdate: - fs_tbl_refresh = ctx->scratch->int1; + fs_tbl_refresh_rate = ctx->scratch->int1; return (SNMP_ERR_NOERROR); case LEAF_begemotHrDiskStorageUpdate: - disk_storage_tbl_refresh = ctx->scratch->int1; + disk_storage_tbl_refresh_rate = ctx->scratch->int1; return (SNMP_ERR_NOERROR); case LEAF_begemotHrNetworkUpdate: - network_tbl_refresh = ctx->scratch->int1; + network_tbl_refresh_rate = ctx->scratch->int1; return (SNMP_ERR_NOERROR); case LEAF_begemotHrSWInstalledUpdate: - swins_tbl_refresh = ctx->scratch->int1; + swins_tbl_refresh_rate = ctx->scratch->int1; return (SNMP_ERR_NOERROR); case LEAF_begemotHrSWRunUpdate: - swrun_tbl_refresh = ctx->scratch->int1; + swrun_tbl_refresh_rate = ctx->scratch->int1; return (SNMP_ERR_NOERROR); case LEAF_begemotHrPkgDir: Index: head/usr.sbin/bsnmpd/modules/new_hostres/Makefile =================================================================== --- head/usr.sbin/bsnmpd/modules/new_hostres/Makefile (revision 228149) +++ head/usr.sbin/bsnmpd/modules/new_hostres/Makefile (working copy) @@ -29,6 +29,7 @@ # LPRSRC= ${.CURDIR}/../../../lpr/common_source +PCIHDR= ${.CURDIR}/../../../../sys .PATH: ${LPRSRC} MOD= hostres @@ -48,7 +49,7 @@ SRCS= hostres_begemot.c \ printcap.c #Not having NDEBUG defined will enable assertions and a lot of output on stderr -CFLAGS+= -DNDEBUG -I${LPRSRC} +CFLAGS+= -DNDEBUG -I${LPRSRC} -I${PCIHDR} XSYM= host hrStorageOther hrStorageRam hrStorageVirtualMemory \ hrStorageFixedDisk hrStorageRemovableDisk hrStorageFloppyDisk \ hrStorageCompactDisc hrStorageRamDisk hrStorageFlashMemory \ Index: head/usr.sbin/bsnmpd/modules/new_hostres/hostres_scalars.c =================================================================== --- head/usr.sbin/bsnmpd/modules/new_hostres/hostres_scalars.c (revision 228149) +++ head/usr.sbin/bsnmpd/modules/new_hostres/hostres_scalars.c (working copy) @@ -59,17 +59,17 @@ static u_char *boot_line; /* maximum number of processes */ static uint32_t max_proc; -/** +/* * Free all static data */ void -fini_scalars(void) +scalars_fini(void) { free(boot_line); } -/** +/* * Get system uptime in hundredths of seconds since the epoch * Returns 0 in case of an error */ Index: head/usr.sbin/bsnmpd/modules/new_hostres/hostres_network_tbl.c =================================================================== --- head/usr.sbin/bsnmpd/modules/new_hostres/hostres_network_tbl.c (revision 228149) +++ head/usr.sbin/bsnmpd/modules/new_hostres/hostres_network_tbl.c (working copy) @@ -1,9 +1,9 @@ /*- * Copyright (c) 2005-2006 The FreeBSD Project + * Copyright (c) 2005-2006 Victor Cruceru + * Copyright (c) 2011 Andrey V. Elsukov * All rights reserved. * - * Author: Victor Cruceru - * * 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: @@ -35,15 +35,12 @@ */ #include -#include -#include #include #include #include #include -#include #include #include #include @@ -80,36 +77,27 @@ static struct network_tbl network_tbl = TAILQ_HEAD static uint64_t network_tick; /* maximum number of ticks between updates of network table */ -uint32_t network_tbl_refresh = HR_NETWORK_TBL_REFRESH * 100; +uint32_t network_tbl_refresh_rate = 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) +network_entry_create(int32_t idx) { struct network_entry *entry; - assert(devEntry != NULL); - if (devEntry == NULL) + if ((entry = calloc(1, sizeof(*entry))) == NULL) { + syslog(LOG_WARNING, "hrNetworkTable: %s: %m", __func__); 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; + entry->index = idx; INSERT_OBJECT_INT(entry, &network_tbl); - return (entry); } -/** +/* * Delete an entry in the network table */ static void @@ -117,117 +105,116 @@ network_entry_delete(struct network_entry* entry) { TAILQ_REMOVE(&network_tbl, entry, link); + device_network_delete(entry->index); free(entry); } -/** +/* + * Find an entry in the hrNetworkTable by the hrDeviceIndex. + */ +static struct network_entry* +network_entry_find(int32_t idx) +{ + struct network_entry *entry; + + TAILQ_FOREACH(entry, &network_tbl, link) + if (entry->index == idx) + return (entry); + return (NULL); +} + +/* * 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 network_entry *entry; struct mibif *ifp; - int name[6]; + char dname[64]; + int mib[6], status; + int32_t idx; 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; + mib[0] = CTL_NET; + mib[1] = PF_LINK; + mib[2] = NETLINK_GENERIC; + mib[3] = IFMIB_IFDATA; + mib[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) { + mib[4] = ifp->sysindex; + len = sizeof(dname); + if (sysctl(mib, 6, dname, &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); + if (ifp->mib.ifmd_flags & IFF_RUNNING) { + if (ifp->mib.ifmd_data.ifi_link_state != LINK_STATE_UP) + status = 5; /* dormant */ + else + status = 1; /* up */ + } else + status = 2; /* down */ + idx = device_network_add(dname, "mibII", ifp->descr, status); + if (idx < 0) { + syslog(LOG_ERR, "device_network_add failed."); 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) + entry = network_entry_find(idx); + if (entry == NULL && + (entry = network_entry_create(idx)) == NULL) { + device_network_delete(idx); continue; - - net->flags |= HR_NETWORK_FOUND; - net->ifIndex = ifp->index; + } + entry->flags |= HR_NETWORK_FOUND; + entry->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) +network_tbl_fini(void) { - struct network_entry *n1; + struct network_entry *entry; - while ((n1 = TAILQ_FIRST(&network_tbl)) != NULL) { - TAILQ_REMOVE(&network_tbl, n1, link); - free(n1); + while ((entry = TAILQ_FIRST(&network_tbl)) != NULL) { + TAILQ_REMOVE(&network_tbl, entry, link); + free(entry); } } -/** +/* * Get the interface list from mibII only at this point to be sure that * it is there already. */ void -start_network_tbl(void) +network_tbl_start(void) { mib_refresh_iflist(); network_get_interfaces(); } -/** +/* * Refresh the table. */ static void -refresh_network_tbl(void) +network_tbl_refresh(void) { struct network_entry *entry, *entry_tmp; - if (this_tick - network_tick < network_tbl_refresh) { + if (this_tick - network_tick < network_tbl_refresh_rate) { HRDBG("no refresh needed"); return; } @@ -245,7 +232,7 @@ static void if (!(entry->flags & HR_NETWORK_FOUND)) network_entry_delete(entry); } - + network_tick = this_tick; HRDBG("refresh DONE"); } @@ -260,10 +247,8 @@ op_hrNetworkTable(struct snmp_context *ctx __unuse { struct network_entry *entry; - refresh_network_tbl(); - + network_tbl_refresh(); switch (curr_op) { - case SNMP_OP_GETNEXT: if ((entry = NEXT_OBJECT_INT(&network_tbl, &value->var, sub)) == NULL) @@ -292,7 +277,6 @@ op_hrNetworkTable(struct snmp_context *ctx __unuse get: switch (value->var.subs[sub - 1]) { - case LEAF_hrNetworkIfIndex: value->v.integer = entry->ifIndex; return (SNMP_ERR_NOERROR); Index: head/usr.sbin/bsnmpd/modules/new_hostres/hostres_storage_tbl.c =================================================================== --- head/usr.sbin/bsnmpd/modules/new_hostres/hostres_storage_tbl.c (revision 228149) +++ head/usr.sbin/bsnmpd/modules/new_hostres/hostres_storage_tbl.c (working copy) @@ -1,9 +1,9 @@ /*- * Copyright (c) 2005-2006 The FreeBSD Project + * Copyright (c) 2005-2006 Victor Cruceru + * Copyright (c) 2011 Andrey V. Elsukov * All rights reserved. * - * Author: Victor Cruceru - * * 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: @@ -49,7 +49,7 @@ #include #include #include -#include /* for getpagesize() */ +#include #include #include "hostres_snmp.h" @@ -71,7 +71,8 @@ struct storage_entry { int32_t size; int32_t used; uint32_t allocationFailures; -#define HR_STORAGE_FOUND 0x001 +#define HR_STORAGE_FOUND 0x001 +#define HR_STORAGE_IMMUTABLE 0x002 uint32_t flags; /* to be used internally*/ TAILQ_ENTRY(storage_entry) link; }; @@ -79,37 +80,33 @@ 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. + * to an entry in the hrStorageTable. 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 storage_entry::index */ - - /* map key, also used for storage_entry::descr */ - u_char *a_name; - + int32_t index; + u_char *name; /* * next may be NULL if the respective storage_entry * is (temporally) gone */ struct storage_entry *entry; - STAILQ_ENTRY(storage_map_entry) link; + SLIST_ENTRY(storage_map_entry) link; }; -STAILQ_HEAD(storage_map, storage_map_entry); +SLIST_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); + SLIST_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; +uint32_t storage_tbl_refresh_rate = HR_STORAGE_TBL_REFRESH * 100; /* for kvm_getswapinfo, malloc'd */ static struct kvm_swap *swap_devs; @@ -128,83 +125,89 @@ static uint32_t next_storage_index = 1; static struct memory_type_list *mt_list; /* Constants */ +static const struct asn_oid OIDX_hrStorageOther_c = OIDX_hrStorageOther; static const struct asn_oid OIDX_hrStorageRam_c = OIDX_hrStorageRam; static const struct asn_oid OIDX_hrStorageVirtualMemory_c = OIDX_hrStorageVirtualMemory; +static const struct asn_oid OIDX_hrStorageFixedDisk_c = OIDX_hrStorageFixedDisk; +static const struct asn_oid OIDX_hrStorageCompactDisc_c = + OIDX_hrStorageCompactDisc; +static const struct asn_oid OIDX_hrStorageRamDisk_c = OIDX_hrStorageRamDisk; +static const struct asn_oid OIDX_hrStorageNetworkDisk_c = + OIDX_hrStorageNetworkDisk; -/** - * 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) + +static struct storage_map_entry* +storage_map_find(const char *name) { - struct storage_entry *entry; struct storage_map_entry *map; - size_t name_len; - assert(name != NULL); - assert(strlen(name) > 0); + SLIST_FOREACH(map, &storage_map, link) + if (strcmp(map->name, name) == 0) + return (map); + return (NULL); +} - STAILQ_FOREACH(map, &storage_map, link) - if (strcmp(map->a_name, name) == 0) - break; +static struct storage_map_entry* +storage_map_create(const char *name) +{ + struct storage_map_entry *map; - if (map == NULL) { - /* new object - get a new index */ - if (next_storage_index > INT_MAX) { - syslog(LOG_ERR, - "%s: hrStorageTable index wrap", __func__); - errx(EX_SOFTWARE, "hrStorageTable index wrap"); - } + if (next_storage_index == INT32_MAX) { + syslog(LOG_ERR, "%s: hrStorageTable index wrap", __func__); + errx(EX_SOFTWARE, "hrStorageTable index wrap"); + } + if ((map = calloc(1, sizeof(*map))) == NULL) { + syslog(LOG_ERR, "hrStorageTable: %s: %m", __func__ ); + return (NULL); + } + if ((map->name = strndup(name, SE_DESC_MLEN)) == NULL) { + syslog(LOG_ERR, "hrStorageTable: %s: %m", __func__ ); + free(map); + return (NULL); + } + map->index = next_storage_index++; + SLIST_INSERT_HEAD(&storage_map, map, link); + HRDBG("%s added into StorageMap at index=%d", name, map->index); + return (map); +} - if ((map = malloc(sizeof(*map))) == NULL) { - syslog(LOG_ERR, "hrStorageTable: %s: %m", __func__ ); - return (NULL); - } +/* + * Create a new entry into the storage table. + */ +static struct storage_entry * +storage_entry_create(struct storage_map_entry *map) +{ + struct storage_entry *entry; - name_len = strlen(name) + 1; - if (name_len > SE_DESC_MLEN) - name_len = SE_DESC_MLEN; + assert(map != NULL); + assert(map->entry == NULL); - if ((map->a_name = malloc(name_len)) == NULL) { - free(map); - return (NULL); - } - - strlcpy(map->a_name, name, name_len); - map->hrIndex = next_storage_index++; - - 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); - } - - if ((entry = malloc(sizeof(*entry))) == NULL) { - syslog(LOG_WARNING, "%s: %m", __func__); + if ((entry = calloc(1, sizeof(*entry))) == NULL) { + syslog(LOG_WARNING, "hrStorageTable: %s: %m", __func__); return (NULL); } - memset(entry, 0, sizeof(*entry)); - - entry->index = map->hrIndex; - - if ((entry->descr = strdup(map->a_name)) == NULL) { + if ((entry->descr = strdup(map->name)) == NULL) { + syslog(LOG_ERR, "hrStorageTable: %s: %m", __func__ ); free(entry); return (NULL); } - map->entry = entry; - + entry->index = map->index; + entry->type = &OIDX_hrStorageOther_c; INSERT_OBJECT_INT(entry, &storage_tbl); - return (entry); } -/** +static void +storage_entry_free(struct storage_entry *entry) +{ + + TAILQ_REMOVE(&storage_tbl, entry, link); + free(entry->descr); + free(entry); +} +/* * Delete an entry from the storage table. */ static void @@ -213,18 +216,15 @@ 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) + SLIST_FOREACH(map, &storage_map, link) if (map->entry == entry) { map->entry = NULL; break; } - free(entry->descr); - free(entry); + storage_entry_free(entry); } -/** +/* * Find a table entry by its name. */ static struct storage_entry * @@ -235,7 +235,6 @@ storage_find_by_name(const char *name) TAILQ_FOREACH(entry, &storage_tbl, link) if (strcmp(entry->descr, name) == 0) return (entry); - return (NULL); } @@ -252,7 +251,7 @@ storage_OS_get_vm(void) if (sysctl(mib, 2, &mem_stats, &len, NULL, 0) < 0) { syslog(LOG_ERR, - "hrStoragetable: %s: sysctl({CTL_VM, VM_METER}) " + "hrStorageTable: %s: sysctl({CTL_VM, VM_METER}) " "failed: %m", __func__); assert(0); return; @@ -368,7 +367,7 @@ storage_OS_get_memstat(void) } while((mt_item = memstat_mtl_next(mt_item)) != NULL); } -/** +/* * Get swap info */ static void @@ -434,7 +433,7 @@ storage_OS_get_swap(void) } } -/** +/* * Query the underlaying OS for the mounted file systems * anf fill in the respective lists (for hrStorageTable and for hrFSTable) */ @@ -514,11 +513,11 @@ storage_OS_get_fs(void) fs_tbl_post_refresh(); } -/** +/* * Initialize storage table and populate it. */ void -init_storage_tbl(void) +storage_tbl_init(void) { if ((mt_list = memstat_mtl_alloc()) == NULL) syslog(LOG_ERR, @@ -528,42 +527,27 @@ void } void -fini_storage_tbl(void) +storage_tbl_fini(void) { - struct storage_map_entry *n1; + struct storage_map_entry *map; - if (swap_devs != NULL) { - free(swap_devs); - swap_devs = NULL; + while (!SLIST_EMPTY(&storage_map)) { + map = SLIST_FIRST(&storage_map); + SLIST_REMOVE_HEAD(&storage_map, link); + if (map->entry != NULL) + storage_entry_free(map->entry); + free(map->name); + free(map); } - 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->descr); - free(n1->entry); - } - free(n1->a_name); - free(n1); - } assert(TAILQ_EMPTY(&storage_tbl)); } void -refresh_storage_tbl(int force) +storage_tbl_refresh(int force) { struct storage_entry *entry, *entry_tmp; - if (!force && storage_tick != 0 && - this_tick - storage_tick < storage_tbl_refresh) { + if (!force && this_tick - storage_tick < storage_tbl_refresh_rate) { HRDBG("no refresh needed"); return; } @@ -574,18 +558,20 @@ void 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)) + /* Purge items that disappeared */ + TAILQ_FOREACH_SAFE(entry, &storage_tbl, link, entry_tmp) { + /* + * If HR_STORAGE_IMMUTABLE bit is set then this means that + * this entry was addded from another table handler. So we are + * not deleting it here. + */ + if ((entry->flags & HR_STORAGE_FOUND) == 0 && + (entry->flags & HR_STORAGE_IMMUTABLE) == 0) storage_entry_delete(entry); - + } storage_tick = this_tick; - HRDBG("refresh DONE"); } @@ -600,10 +586,8 @@ op_hrStorageTable(struct snmp_context *ctx __unuse { struct storage_entry *entry; - refresh_storage_tbl(0); - + storage_tbl_refresh(0); switch (curr_op) { - case SNMP_OP_GETNEXT: if ((entry = NEXT_OBJECT_INT(&storage_tbl, &value->var, sub)) == NULL) @@ -633,7 +617,6 @@ op_hrStorageTable(struct snmp_context *ctx __unuse get: switch (value->var.subs[sub - 1]) { - case LEAF_hrStorageIndex: value->v.integer = entry->index; return (SNMP_ERR_NOERROR); Index: head/usr.sbin/bsnmpd/modules/new_hostres/hostres_partition_tbl.c =================================================================== --- head/usr.sbin/bsnmpd/modules/new_hostres/hostres_partition_tbl.c (revision 228149) +++ head/usr.sbin/bsnmpd/modules/new_hostres/hostres_partition_tbl.c (working copy) @@ -1,9 +1,9 @@ /*- * Copyright (c) 2005-2006 The FreeBSD Project + * Copyright (c) 2005-2006 Victor Cruceru + * Copyright (c) 2011 Andrey V. Elsukov * All rights reserved. * - * Author: Victor Cruceru - * * 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: @@ -33,14 +33,10 @@ * Host Resources MIB: hrPartitionTable implementation for SNMPd. */ -#include -#include - #include #include #include #include -#include #include #include #include @@ -50,12 +46,6 @@ #include "hostres_oid.h" #include "hostres_tree.h" -#ifdef PC98 -#define HR_FREEBSD_PART_TYPE 0xc494 -#else -#define HR_FREEBSD_PART_TYPE 165 -#endif - /* Maximum length for label and id including \0 */ #define PART_STR_MLEN (128 + 1) @@ -64,8 +54,10 @@ */ struct partition_entry { asn_subid_t index[2]; - u_char *label; /* max allocated len will be PART_STR_MLEN */ - u_char *id; /* max allocated len will be PART_STR_MLEN */ +#define hrDeviceIndex index[0] +#define hrPartIndex index[1] + u_char *label; + u_char *id; int32_t size; int32_t fs_Index; TAILQ_ENTRY(partition_entry) link; @@ -75,32 +67,39 @@ struct partition_entry { TAILQ_HEAD(partition_tbl, partition_entry); /* + * Keep the last allocated partition index for each device entry. + */ +struct device_map_entry { + int32_t index[2]; + SLIST_ENTRY(device_map_entry) link; +}; +SLIST_HEAD(device_map, device_map_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; /* partition_entry::index */ - u_char *id; /* max allocated len will be PART_STR_MLEN */ + int32_t index[2]; + u_char *id; - /* - * next may be NULL if the respective partition_entry - * is (temporally) gone. - */ struct partition_entry *entry; - STAILQ_ENTRY(partition_map_entry) link; + SLIST_ENTRY(partition_map_entry) link; }; -STAILQ_HEAD(partition_map, partition_map_entry); +SLIST_HEAD(partition_map, partition_map_entry); +static struct device_map device_map = SLIST_HEAD_INITIALIZER(device_map); + /* Mapping table for consistent indexing */ static struct partition_map partition_map = - STAILQ_HEAD_INITIALIZER(partition_map); + SLIST_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; +uint32_t partition_tbl_refresh_rate = 10 * 100; +static uint64_t partition_tick; /* * Partition_entry_cmp is used for INSERT_OBJECT_FUNC_LINK @@ -113,18 +112,14 @@ partition_entry_cmp(const struct partition_entry * assert(a != NULL); assert(b != NULL); - if (a->index[0] < b->index[0]) + if (a->hrDeviceIndex < b->hrDeviceIndex) return (-1); - - if (a->index[0] > b->index[0]) + if (a->hrDeviceIndex > b->hrDeviceIndex) return (+1); - - if (a->index[1] < b->index[1]) + if (a->hrPartIndex < b->hrPartIndex) return (-1); - - if (a->index[1] > b->index[1]) + if (a->hrPartIndex > b->hrPartIndex) return (+1); - return (0); } @@ -152,128 +147,140 @@ partition_idx_cmp(const struct asn_oid *oid, u_int return (0); } -/** - * Create a new partition table entry - */ -static struct partition_entry * -partition_entry_create(int32_t ds_index, const char *chunk_name) +static struct device_map_entry* +partition_device_map_find(int32_t idx) { - struct partition_entry *entry; - struct partition_map_entry *map; - size_t id_len; + struct device_map_entry *dmap; - /* sanity checks */ - assert(chunk_name != NULL); - if (chunk_name == NULL || chunk_name[0] == '\0') + SLIST_FOREACH(dmap, &device_map, link) { + if (dmap->hrDeviceIndex == idx) + return (dmap); + } + return (NULL); +} + +static struct device_map_entry* +partition_device_map_create(int32_t idx) +{ + struct device_map_entry *dmap; + + assert(partition_device_map_find(idx) == NULL); + dmap = calloc(1, sizeof(*dmap)); + if (dmap == NULL) return (NULL); - /* check whether we already have seen this partition */ - STAILQ_FOREACH(map, &partition_map, link) - if (strcmp(map->id, chunk_name) == 0) - break; + dmap->hrDeviceIndex = idx; + SLIST_INSERT_HEAD(&device_map, dmap, link); + return (dmap); +} - if (map == NULL) { - /* new object - get a new index and create a map */ +static struct partition_map_entry* +partition_map_find(int32_t idx, const char *name) +{ + struct partition_map_entry *pmap; - if (next_partition_index > INT_MAX) { - /* Unrecoverable error - die clean and quicly*/ - syslog(LOG_ERR, "%s: hrPartitionTable index wrap", - __func__); - errx(EX_SOFTWARE, "hrPartitionTable index wrap"); - } + SLIST_FOREACH(pmap, &partition_map, link) { + if (pmap->hrDeviceIndex == idx && strcmp(pmap->id, name) == 0) + return (pmap); + } + return (NULL); +} - if ((map = malloc(sizeof(*map))) == NULL) { - syslog(LOG_ERR, "hrPartitionTable: %s: %m", __func__); - return (NULL); - } +static struct partition_map_entry* +partition_map_create(int32_t idx, const char *name) +{ + struct partition_map_entry *pmap; + struct device_map_entry *dmap; - id_len = strlen(chunk_name) + 1; - if (id_len > PART_STR_MLEN) - id_len = PART_STR_MLEN; - - if ((map->id = malloc(id_len)) == NULL) { - free(map); + pmap = calloc(1, sizeof(*pmap)); + if (pmap == NULL) + return (NULL); + if ((pmap->id = strdup(name)) == NULL) { + free(pmap); + return (NULL); + } + dmap = partition_device_map_find(idx); + if (dmap == NULL) { + dmap = partition_device_map_create(idx); + if (dmap == NULL) { + free(pmap->id); + free(pmap); return (NULL); } + } + pmap->hrDeviceIndex = idx; + pmap->hrPartIndex = ++dmap->hrPartIndex; - map->index = next_partition_index++; + SLIST_INSERT_HEAD(&partition_map, pmap, link); + return (pmap); +} - strlcpy(map->id, chunk_name, id_len); +/* + * Create a new partition table entry + */ +static struct partition_entry * +partition_entry_create(struct partition_map_entry *pmap, struct gprovider *pp) +{ + struct partition_entry *entry; + const char *p; + off_t mediasize; - map->entry = NULL; - - 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); - } - - if ((entry = malloc(sizeof(*entry))) == NULL) { + if ((entry = calloc(1, sizeof(*entry))) == NULL) { syslog(LOG_WARNING, "hrPartitionTable: %s: %m", __func__); return (NULL); } - memset(entry, 0, sizeof(*entry)); - - /* create the index */ - entry->index[0] = ds_index; - entry->index[1] = map->index; - - map->entry = entry; - - if ((entry->id = strdup(map->id)) == NULL) { + p = geom_find_provcfg(pp, "label"); + if ((entry->label = strndup(p, PART_STR_MLEN)) == NULL) { + syslog(LOG_ERR, "hrPartitionTable: %s: %m", __func__); free(entry); return (NULL); } - - /* - * reuse id_len from here till the end of this function - * for partition_entry::label - */ - id_len = strlen(_PATH_DEV) + strlen(chunk_name) + 1; - - if (id_len > PART_STR_MLEN) - id_len = PART_STR_MLEN; - - if ((entry->label = malloc(id_len )) == NULL) { - free(entry->id); + p = geom_find_provcfg(pp, "type"); + if ((entry->id = strdup(p)) == NULL) { + syslog(LOG_ERR, "hrPartitionTable: %s: %m", __func__); + free(entry->label); free(entry); return (NULL); } + mediasize = pp->lg_mediasize / 1024; + entry->size = (mediasize > INT32_MAX) ? INT32_MAX: mediasize; + entry->hrDeviceIndex = pmap->hrDeviceIndex; + entry->hrPartIndex = pmap->hrPartIndex; + pmap->entry = entry; - snprintf(entry->label, id_len, "%s%s", _PATH_DEV, chunk_name); - INSERT_OBJECT_FUNC_LINK(entry, &partition_tbl, link, partition_entry_cmp); - return (entry); } -/** +static void +partition_entry_free(struct partition_entry *entry) +{ + + TAILQ_REMOVE(&partition_tbl, entry, link); + free(entry->id); + free(entry->label); + free(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; + struct partition_map_entry *pmap; assert(entry != NULL); - - TAILQ_REMOVE(&partition_tbl, entry, link); - STAILQ_FOREACH(map, &partition_map, link) - if (map->entry == entry) { - map->entry = NULL; + SLIST_FOREACH(pmap, &partition_map, link) + if (pmap->entry == entry) { + pmap->entry = NULL; break; } - free(entry->id); - free(entry->label); - free(entry); + partition_entry_free(entry); } -/** +/* * Find a partition table entry by name. If none is found, return NULL. */ static struct partition_entry * @@ -288,232 +295,102 @@ partition_entry_find_by_name(const char *name) 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) +static struct gprovider* +geom_parent_provider_get(struct ggeom *gp) { - struct partition_entry *entry = NULL; + struct gconsumer *cp; - TAILQ_FOREACH(entry, &partition_tbl, link) - if (strcmp(entry->label, name) == 0) - return (entry); - - return (NULL); + cp = LIST_FIRST(&gp->lg_consumer); + assert(cp != NULL); + /* skip geom LABEL class */ + if (strcmp(cp->lg_provider->lg_geom->lg_class->lg_name, "LABEL") == 0) + return (geom_parent_provider_get(cp->lg_provider->lg_geom)); + /* + * if parent provider has the same class, then skip it and + * go to the next upper level. + */ + if (strcmp(cp->lg_provider->lg_geom->lg_class->lg_name, + gp->lg_class->lg_name) == 0) + return (geom_parent_provider_get(cp->lg_provider->lg_geom)); + return (cp->lg_provider); } -/** - * Process a chunk from libgeom(4). 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 char *chunk_name, off_t chunk_size) +partition_geom_classe_handle(struct gmesh *mesh) { + struct partition_map_entry *pmap; struct partition_entry *entry; - daddr_t k_size; + struct gprovider *pp; + struct gclass *cp; + struct ggeom *gp; + int32_t idx; - assert(chunk_name != NULL); - assert(chunk_name[0] != '\0'); - if (chunk_name == NULL || chunk_name == '\0') + cp = geom_find_class(mesh, "PART"); + if (cp == NULL) 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_name)) == NULL) - return; - - entry->flags |= HR_PARTITION_FOUND; - - /* actual size may overflow the SNMP type */ - k_size = chunk_size / 1024; - entry->size = (k_size > (off_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; - - /* mark each entry as missing */ - TAILQ_FOREACH(entry, &partition_tbl, link) - entry->flags &= ~HR_PARTITION_FOUND; -} - -/** - * Try to find a geom(4) class by its name. Returns a pointer to that - * class if found NULL otherways. - */ -static struct gclass * -find_class(struct gmesh *mesh, const char *name) -{ - struct gclass *classp; - - LIST_FOREACH(classp, &mesh->lg_class, lg_class) - if (strcmp(classp->lg_name, name) == 0) - return (classp); - return (NULL); -} - -/** - * Process all MBR-type partitions from the given disk. - */ -static void -get_mbr(struct gclass *classp, int32_t ds_index, const char *disk_dev_name) -{ - struct ggeom *gp; - struct gprovider *pp; - struct gconfig *conf; - long part_type; - - LIST_FOREACH(gp, &classp->lg_geom, lg_geom) { - /* We are only interested in partitions from this disk */ - if (strcmp(gp->lg_name, disk_dev_name) != 0) + LIST_FOREACH(gp, &cp->lg_geom, lg_geom) { + idx = disk_storage_add(mesh, geom_parent_provider_get(gp)); + if (idx < 0) continue; - - /* - * Find all the non-BSD providers (these are handled in get_bsd) - */ LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { - LIST_FOREACH(conf, &pp->lg_config, lg_config) { - if (conf->lg_name == NULL || - conf->lg_val == NULL || - strcmp(conf->lg_name, "type") != 0) + pmap = partition_map_find(idx, pp->lg_name); + if (pmap == NULL) { + pmap = partition_map_create(idx, pp->lg_name); + if (pmap == NULL) continue; - - /* - * We are not interested in BSD partitions - * (ie ad0s1 is not interesting at this point). - * We'll take care of them in detail (slice - * by slice) in get_bsd. - */ - part_type = strtol(conf->lg_val, NULL, 10); - if (part_type == HR_FREEBSD_PART_TYPE) - break; - HRDBG("-> MBR PROVIDER Name: %s", pp->lg_name); - HRDBG("Mediasize: %jd", - (intmax_t)pp->lg_mediasize / 1024); - HRDBG("Sectorsize: %u", pp->lg_sectorsize); - HRDBG("Mode: %s", pp->lg_mode); - HRDBG("CONFIG: %s: %s", - conf->lg_name, conf->lg_val); - - handle_chunk(ds_index, pp->lg_name, - pp->lg_mediasize); } + entry = pmap->entry; + if (entry == NULL) { + entry = partition_entry_create(pmap, pp); + if (entry == NULL) + continue; + } + entry->flags |= HR_PARTITION_FOUND; + /* XXX: update label and id */ } } + /* + * XXX: collect information about obsolete GEOM partitioning classes: + * MBR, BSD, SUN,... + */ } -/** - * Process all BSD-type partitions from the given disk. - */ -static void -get_bsd_sun(struct gclass *classp, int32_t ds_index, const char *disk_dev_name) -{ - struct ggeom *gp; - struct gprovider *pp; - - LIST_FOREACH(gp, &classp->lg_geom, lg_geom) { - /* - * We are only interested in those geoms starting with - * the disk_dev_name passed as parameter to this function. - */ - if (strncmp(gp->lg_name, disk_dev_name, - strlen(disk_dev_name)) != 0) - continue; - - LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { - if (pp->lg_name == NULL) - continue; - handle_chunk(ds_index, pp->lg_name, pp->lg_mediasize); - } - } -} - -/** - * Called from the DiskStorage table for every row. Open the GEOM(4) framework - * and process all the partitions in it. - * ds_index is the index into the DiskStorage table. - * This is done in two steps: for non BSD partitions the geom class "MBR" is - * used, for our BSD slices the "BSD" geom class. - */ void -partition_tbl_handle_disk(int32_t ds_index, const char *disk_dev_name) +partition_tbl_refresh(int force) { - struct gmesh mesh; /* GEOM userland tree */ - struct gclass *classp; - int error; + struct gmesh mesh; + struct partition_entry *entry, *entry_tmp; - assert(disk_dev_name != NULL); - assert(ds_index > 0); - - HRDBG("===> getting partitions for %s <===", disk_dev_name); - - /* try to construct the GEOM tree */ - if ((error = geom_gettree(&mesh)) != 0) { - syslog(LOG_WARNING, "cannot get GEOM tree: %m"); + if (!force && this_tick - partition_tick < partition_tbl_refresh_rate) { + HRDBG("hrPartitionTable: no refresh needed"); return; } - /* - * First try the GEOM "MBR" class. - * This is needed for non-BSD slices (aka partitions) - * on PC architectures. - */ - if ((classp = find_class(&mesh, "MBR")) != NULL) { - get_mbr(classp, ds_index, disk_dev_name); - } else { - HRDBG("cannot find \"MBR\" geom class"); - } + /* mark each entry as missing */ + TAILQ_FOREACH(entry, &partition_tbl, link) + entry->flags &= ~HR_PARTITION_FOUND; - /* - * Get the "BSD" GEOM class. - * Here we'll find all the info needed about the BSD slices. - */ - if ((classp = find_class(&mesh, "BSD")) != NULL) { - get_bsd_sun(classp, ds_index, disk_dev_name); - } else { - /* no problem on sparc64 */ - HRDBG("cannot find \"BSD\" geom class"); + if (geom_gettree(&mesh) == 0) { + partition_geom_class_handle(&mesh); + geom_deletetree(&mesh); } - /* - * Get the "SUN" GEOM class. - * Here we'll find all the info needed about the BSD slices. - */ - if ((classp = find_class(&mesh, "SUN")) != NULL) { - get_bsd_sun(classp, ds_index, disk_dev_name); - } else { - /* no problem on i386 */ - HRDBG("cannot find \"SUN\" geom class"); - } - - geom_deletetree(&mesh); + /* Purge items that disappeared */ + TAILQ_FOREACH_SAFE(entry, &partition_tbl, link, entry_tmp) + if ((entry->flags & HR_PARTITION_FOUND) == 0) + partition_entry_delete(entry); + partition_tick = this_tick; } -/** - * Finish refreshing the table. +/* + * Init the things for both of hrPartitionTable */ void -partition_tbl_post_refresh(void) +partition_tbl_init(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); + partition_tbl_refresh(1); } /* @@ -521,31 +398,34 @@ void * It destroys the lists and frees any allocated heap memory */ void -fini_partition_tbl(void) +partition_tbl_fini(void) { - struct partition_map_entry *m; + struct partition_map_entry *pmap; + struct device_map_entry *dmap; - 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->id); - free(m->entry->label); - free(m->entry); - } - free(m->id); - free(m); + while (!SLIST_EMPTY(&partition_map)) { + pmap = SLIST_FIRST(&partition_map); + SLIST_REMOVE_HEAD(&partition_map, link); + if(pmap->entry != NULL) + partition_entry_free(pmap->entry); + free(pmap->id); + free(pmap); } + while (!SLIST_EMPTY(&device_map)) { + dmap = SLIST_FIRST(&device_map); + SLIST_REMOVE_HEAD(&device_map, link); + free(dmap); + } 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) +partition_tbl_fsindex_handle(const char *name, int32_t fs_idx) { struct partition_entry *entry; @@ -568,22 +448,16 @@ op_hrPartitionTable(struct snmp_context *ctx __unu { struct partition_entry *entry; - /* - * Refresh the disk storage table (which refreshes the partition - * table) if necessary. - */ - refresh_disk_storage_tbl(0); - + refresh_partition_tbl(0); switch (op) { - case SNMP_OP_GETNEXT: if ((entry = NEXT_OBJECT_FUNC(&partition_tbl, &value->var, sub, partition_idx_cmp)) == NULL) return (SNMP_ERR_NOSUCHNAME); value->var.len = sub + 2; - value->var.subs[sub] = entry->index[0]; - value->var.subs[sub + 1] = entry->index[1]; + value->var.subs[sub] = entry->hrDeviceIndex; + value->var.subs[sub + 1] = entry->hrPartIndex; goto get; @@ -607,9 +481,8 @@ op_hrPartitionTable(struct snmp_context *ctx __unu get: switch (value->var.subs[sub - 1]) { - case LEAF_hrPartitionIndex: - value->v.integer = entry->index[1]; + value->v.integer = entry->hrPartIndex; return (SNMP_ERR_NOERROR); case LEAF_hrPartitionLabel: Index: head/usr.sbin/bsnmpd/modules/new_hostres/hostres_snmp.c =================================================================== --- head/usr.sbin/bsnmpd/modules/new_hostres/hostres_snmp.c (revision 228149) +++ head/usr.sbin/bsnmpd/modules/new_hostres/hostres_snmp.c (working copy) @@ -81,7 +81,6 @@ hostres_fini(void) fini_fs_tbl(); fini_processor_tbl(); fini_disk_storage_tbl(); - fini_device_tbl(); fini_partition_tbl(); fini_network_tbl(); fini_printer_tbl(); @@ -118,32 +117,35 @@ hostres_init(struct lmodule *mod, int argc __unuse } /* - * The order is relevant here, because some table depend on each other. + * The order is relevant here: + * 1) hrDeviceTable; + * 2) hrProcessorTable; + * 3) hrNetworkTable initialization is delayed to the start routine; + * 4) hrPrinterTable; + * 5) hrDiskStorageTable; + * 6) hrPartitionTable; + * + * Now we can initialize hrStorageTable. */ - init_device_tbl(); + device_tbl_init(); + processor_tbl_init(); + printer_tbl_init(); + disk_storage_tbl_init(); + partition_tbl_init(); - /* 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(); + storage_tbl_init(); + fs_tbl_init(); - /* also the hrSWRunPerfTable's support is initialized here */ - init_swrun_tbl(); - init_swins_tbl(); + swrun_tbl_init(); + swins_tbl_init(); HRDBG("done."); - return (0); } Index: head/usr.sbin/bsnmpd/modules/new_hostres/hostres_snmp.h =================================================================== --- head/usr.sbin/bsnmpd/modules/new_hostres/hostres_snmp.h (revision 228149) +++ head/usr.sbin/bsnmpd/modules/new_hostres/hostres_snmp.h (working copy) @@ -1,9 +1,9 @@ /* * Copyright (c) 2005-2006 The FreeBSD Project + * Copyright (c) 2005-2006 Victor Cruceru + * Copyright (c) 2011 Andrey V. Elsukov * All rights reserved. * - * Author: Victor Cruceru - * * 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: @@ -95,230 +95,105 @@ enum snmpTCTruthValue { /* The number of CPU load samples per one minute, per each CPU */ #define MAX_CPU_SAMPLES 4 - /* * max len (including '\0'), for device_entry::descr field below, * according to MIB */ #define DEV_DESCR_MLEN (64 + 1) -/* - * max len (including '\0'), for device_entry::name and - * device_map_entry::name_key fields below, according to MIB - */ -#define DEV_NAME_MLEN (32 + 1) +/* GEOM helper functions */ +struct gmesh; +struct gprovider; +struct gclass *geom_find_class(struct gmesh *, const char *); +const char *geom_find_provcfg(struct gprovider *, const char *); -/* - * max len (including '\0'), for device_entry::location and - * device_map_entry::location_key fields below, according to MIB - */ -#define DEV_LOC_MLEN (128 + 1) +/* descriptor to access kernel memory */ +extern kvm_t *hr_kd; -/* - * This structure is used to hold a SNMP table entry - * for HOST-RESOURCES-MIB's hrDeviceTable - */ -struct device_entry { - int32_t index; - const struct asn_oid *type; - u_char *descr; - const struct asn_oid *id; /* only oid_zeroDotZero as (*id) value*/ - int32_t status; /* enum DeviceStatus */ - uint32_t errors; +/* hrDeviceTable declarations */ +extern uint32_t device_tbl_refresh_rate; +void device_tbl_fini(void); +void device_tbl_init(void); +void device_tbl_refresh(int); +void device_tbl_start(struct lmodule *); -#define HR_DEVICE_FOUND 0x001 - /* not dectected by libdevice, so don't try to refresh it*/ -#define HR_DEVICE_IMMUTABLE 0x002 +int32_t device_get_index(const char *, const char *); +int32_t device_disk_add(const char *, const char *, const char *); +void device_disk_delete(int32_t); +int32_t device_processor_add(const char *, const char *, const char *); +void device_processor_delete(int32_t); +int32_t device_network_add(const char *, const char *, const char *, int); +void device_network_delete(int32_t); +int32_t device_printer_add(const char *, const char *, const char *, + int); +void device_printer_delete(int32_t); - /* next 3 are not from the SNMP mib table, only to be used internally */ - uint32_t flags; +/* hrProcessorTable declarations */ +void processor_tbl_fini(void); +int processor_tbl_init(void); +void processor_tbl_start(struct lmodule *); - u_char *name; - u_char *location; - TAILQ_ENTRY(device_entry) link; -}; +/* hrNetworkTable declarations */ +extern uint32_t network_tbl_refresh_rate; +void network_tbl_fini(void); +void network_tbl_start(void); -/* - * 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 */ +/* hrPrinterTable declarations */ +extern uint32_t printer_tbl_refresh_rate; +void printer_tbl_fini(void); +void printer_tbl_init(void); +void printer_tbl_refresh(void); - /* map key is the pair (name_key, location_key) */ - u_char *name_key; /* copy of device name */ - u_char *location_key; +/* hrDiskStorageTable declarations */ +extern uint32_t disk_storage_tbl_refresh_rate; +int32_t disk_storage_add(struct gmesh *, struct gprovider *); +void disk_storage_tbl_fini(void); +int disk_storage_tbl_init(void); +void disk_storage_tbl_refresh(int); - /* - * 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); +/* hrPartitionTable declarations */ +extern uint32_t partition_tbl_refresh_rate; +void partition_tbl_fini(void); +void partition_tbl_fsindex_handle(const char *, int32_t); +void partition_tbl_init(void); +void partition_tbl_refresh(int); -/* descriptor to access kernel memory */ -extern kvm_t *hr_kd; +/* hrStorageTable declarations */ +extern uint32_t storage_tbl_refresh_rate; +void storage_tbl_fini(void); +void storage_tbl_init(void); +void storage_tbl_refresh(int); -/* Table used for consistent device table indexing. */ -extern struct device_map device_map; +/* hrFSTable declarations */ +extern uint32_t fs_tbl_refresh_rate; -/* Maximum number of ticks between two updates for hrStorageTable */ -extern uint32_t storage_tbl_refresh; +/* hrSWRunTable declarations */ +extern uint32_t swrun_tbl_refresh_rate; +void swrun_tbl_fini(void); +void swrun_tbl_init(void); -/* Maximum number of ticks between updated of FS table */ -extern uint32_t fs_tbl_refresh; +/* hrSWInstalledTable declarations */ +extern uint32_t swins_tbl_refresh_rate; +void swins_tbl_fini(void); +void swins_tbl_init(void); +void swins_tbl_refresh(void); -/* 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); - +/* scalars objects declarations */ +void scalars_fini(void); /* * 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 *); - -/* Delete an entry from hrDeviceTbl */ -void device_entry_delete(struct device_entry *entry); - -/* 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 */ Index: head/usr.sbin/bsnmpd/modules/new_hostres/hostres_printer_tbl.c =================================================================== --- head/usr.sbin/bsnmpd/modules/new_hostres/hostres_printer_tbl.c (revision 228149) +++ head/usr.sbin/bsnmpd/modules/new_hostres/hostres_printer_tbl.c (working copy) @@ -53,9 +53,6 @@ #include #include "lp.h" -/* Constants */ -static const struct asn_oid OIDX_hrDevicePrinter_c = OIDX_hrDevicePrinter; - enum PrinterStatus { PS_OTHER = 1, PS_UNKNOWN = 2, @@ -85,59 +82,53 @@ static struct printer_tbl printer_tbl = TAILQ_HEAD /* last (agent) tick when hrPrinterTable was updated */ static uint64_t printer_tick; -/** +/* maximum number of ticks between updates of printer table */ +uint32_t printer_tbl_refresh_rate = 10 * 100; + +/* * Create entry into the printer table. */ static struct printer_entry * -printer_entry_create(const struct device_entry *devEntry) +printer_entry_create(int32_t idx) { struct printer_entry *entry = NULL; - assert(devEntry != NULL); - if (devEntry == NULL) - return (NULL); - - if ((entry = malloc(sizeof(*entry))) == NULL) { + if ((entry = calloc(1, sizeof(*entry))) == NULL) { syslog(LOG_WARNING, "hrPrinterTable: %s: %m", __func__); return (NULL); } - memset(entry, 0, sizeof(*entry)); - entry->index = devEntry->index; + entry->index = idx; 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); + device_printer_delete(entry->index); free(entry); } -/** +/* * Find a printer by its index */ static struct printer_entry * -printer_find_by_index(int32_t idx) +printer_entry_find(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 @@ -201,32 +192,25 @@ LABEL_DONE: 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 printer_entry *entry; + enum PrinterStatus status; struct stat sb; + int32_t idx; 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", @@ -234,25 +218,18 @@ handle_printer(struct printer *pp) return; } } - - if ((dev_entry = device_find_by_name(dev_only)) == NULL) { + status = get_printer_status(pp); + idx = device_printer_add(pp->lp, "LPR", pp->printer, (int)status); + if (idx < 0) + return; + entry = printer_entry_find(idx); + if (entry == NULL && (entry = printer_entry_create(idx)) == NULL) { HRDBG("%s not in hrDeviceTable", pp->lp); + device_printer_delete(idx); 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)); + entry->flags |= HR_PRINTER_FOUND; + entry->status = (int32_t)status; } static void @@ -283,44 +260,42 @@ errloop: } lastprinter(); - printer_tick = this_tick; } -/** +/* * Init the things for hrPrinterTable */ void -init_printer_tbl(void) +printer_tbl_init(void) { hrPrinter_get_OS_entries(); } -/** +/* * Finalization routine for hrPrinterTable * It destroys the lists and frees any allocated heap memory */ void -fini_printer_tbl(void) +printer_tbl_fini(void) { - struct printer_entry *n1; + struct printer_entry *entry; - while ((n1 = TAILQ_FIRST(&printer_tbl)) != NULL) { - TAILQ_REMOVE(&printer_tbl, n1, link); - free(n1); + while ((entry = TAILQ_FIRST(&printer_tbl)) != NULL) { + printer_entry_delete(entry); } } -/** +/* * Refresh the printer table if needed. */ void -refresh_printer_tbl(void) +printer_tbl_refresh(void) { struct printer_entry *entry; struct printer_entry *entry_tmp; - if (this_tick <= printer_tick) { + if (this_tick - printer_tick < printer_tbl_refresh_rate) { HRDBG("no refresh needed"); return; } @@ -334,16 +309,12 @@ void /* * Purge items that disappeared */ - entry = TAILQ_FIRST(&printer_tbl); - while (entry != NULL) { - entry_tmp = TAILQ_NEXT(entry, link); + TAILQ_FOREACH_SAFE(entry, &printer_tbl, link, entry_tmp) { if (!(entry->flags & HR_PRINTER_FOUND)) printer_entry_delete(entry); - entry = entry_tmp; } printer_tick = this_tick; - HRDBG("refresh DONE "); } @@ -353,10 +324,8 @@ op_hrPrinterTable(struct snmp_context *ctx __unuse { struct printer_entry *entry; - refresh_printer_tbl(); - + printer_tbl_refresh(); switch (curr_op) { - case SNMP_OP_GETNEXT: if ((entry = NEXT_OBJECT_INT(&printer_tbl, &value->var, sub)) == NULL) @@ -385,7 +354,6 @@ op_hrPrinterTable(struct snmp_context *ctx __unuse get: switch (value->var.subs[sub - 1]) { - case LEAF_hrPrinterStatus: value->v.integer = entry->status; return (SNMP_ERR_NOERROR);