1154133Sharti /*- 2154133Sharti * Copyright (c) 2005-2006 The FreeBSD Project 3154133Sharti * All rights reserved. 4154133Sharti * 5154133Sharti * Author: Victor Cruceru <soc-victor@freebsd.org> 6154133Sharti * 7154133Sharti * Redistribution of this software and documentation and use in source and 8154133Sharti * binary forms, with or without modification, are permitted provided that 9154133Sharti * the following conditions are met: 10154133Sharti * 11154133Sharti * 1. Redistributions of source code or documentation must retain the above 12154133Sharti * copyright notice, this list of conditions and the following disclaimer. 13154133Sharti * 2. Redistributions in binary form must reproduce the above copyright 14154133Sharti * notice, this list of conditions and the following disclaimer in the 15154133Sharti * documentation and/or other materials provided with the distribution. 16154133Sharti * 17154133Sharti * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18154133Sharti * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19154133Sharti * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20154133Sharti * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21154133Sharti * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22154133Sharti * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23154133Sharti * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24154133Sharti * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25154133Sharti * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26154133Sharti * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27154133Sharti * SUCH DAMAGE. 28154133Sharti * 29154133Sharti * $FreeBSD: releng/10.3/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_device_tbl.c 228990 2011-12-30 10:58:14Z uqs $ 30154133Sharti */ 31154133Sharti 32154133Sharti/* 33154133Sharti * Host Resources MIB: hrDeviceTable implementation for SNMPd. 34154133Sharti */ 35154133Sharti 36154133Sharti#include <sys/un.h> 37154133Sharti#include <sys/limits.h> 38154133Sharti 39154133Sharti#include <assert.h> 40154133Sharti#include <err.h> 41154133Sharti#include <errno.h> 42154133Sharti#include <stdlib.h> 43154133Sharti#include <string.h> 44154133Sharti#include <syslog.h> 45154133Sharti#include <unistd.h> 46160341Sharti#include <sysexits.h> 47154133Sharti 48154133Sharti#include "hostres_snmp.h" 49154133Sharti#include "hostres_oid.h" 50154133Sharti#include "hostres_tree.h" 51154133Sharti 52160341Sharti#define FREE_DEV_STRUCT(entry_p) do { \ 53160341Sharti free(entry_p->name); \ 54160341Sharti free(entry_p->location); \ 55160341Sharti free(entry_p->descr); \ 56160341Sharti free(entry_p); \ 57160341Sharti} while (0) 58160341Sharti 59154133Sharti/* 60154133Sharti * Status of a device 61154133Sharti */ 62154133Shartienum DeviceStatus { 63154133Sharti DS_UNKNOWN = 1, 64154133Sharti DS_RUNNING = 2, 65154133Sharti DS_WARNING = 3, 66154133Sharti DS_TESTING = 4, 67154133Sharti DS_DOWN = 5 68154133Sharti}; 69154133Sharti 70154133ShartiTAILQ_HEAD(device_tbl, device_entry); 71154133Sharti 72154133Sharti/* the head of the list with hrDeviceTable's entries */ 73154133Shartistatic struct device_tbl device_tbl = TAILQ_HEAD_INITIALIZER(device_tbl); 74154133Sharti 75154133Sharti/* Table used for consistent device table indexing. */ 76154133Shartistruct device_map device_map = STAILQ_HEAD_INITIALIZER(device_map); 77154133Sharti 78154133Sharti/* next int available for indexing the hrDeviceTable */ 79154133Shartistatic uint32_t next_device_index = 1; 80154133Sharti 81154133Sharti/* last (agent) tick when hrDeviceTable was updated */ 82154133Shartistatic uint64_t device_tick = 0; 83154133Sharti 84154133Sharti/* maximum number of ticks between updates of device table */ 85154133Shartiuint32_t device_tbl_refresh = 10 * 100; 86154133Sharti 87154133Sharti/* socket for /var/run/devd.pipe */ 88154133Shartistatic int devd_sock = -1; 89154133Sharti 90154133Sharti/* used to wait notifications from /var/run/devd.pipe */ 91154133Shartistatic void *devd_fd; 92154133Sharti 93154133Sharti/* some constants */ 94154133Shartistatic const struct asn_oid OIDX_hrDeviceProcessor_c = OIDX_hrDeviceProcessor; 95154133Shartistatic const struct asn_oid OIDX_hrDeviceOther_c = OIDX_hrDeviceOther; 96154133Sharti 97154133Sharti/** 98154133Sharti * Create a new entry out of thin air. 99154133Sharti */ 100154133Shartistruct device_entry * 101154133Shartidevice_entry_create(const char *name, const char *location, const char *descr) 102154133Sharti{ 103160341Sharti struct device_entry *entry = NULL; 104160341Sharti struct device_map_entry *map = NULL; 105160341Sharti size_t name_len; 106160341Sharti size_t location_len; 107154133Sharti 108154133Sharti assert((name[0] != 0) || (location[0] != 0)); 109154133Sharti 110154133Sharti if (name[0] == 0 && location[0] == 0) 111154133Sharti return (NULL); 112154133Sharti 113160341Sharti STAILQ_FOREACH(map, &device_map, link) { 114160341Sharti assert(map->name_key != NULL); 115160341Sharti assert(map->location_key != NULL); 116154133Sharti 117154133Sharti if (strcmp(map->name_key, name) == 0 && 118154133Sharti strcmp(map->location_key, location) == 0) { 119154133Sharti break; 120154133Sharti } 121160341Sharti } 122154133Sharti 123154133Sharti if (map == NULL) { 124154133Sharti /* new object - get a new index */ 125154133Sharti if (next_device_index > INT_MAX) { 126154133Sharti syslog(LOG_ERR, 127154133Sharti "%s: hrDeviceTable index wrap", __func__); 128160341Sharti /* There isn't much we can do here. 129160341Sharti * If the next_swins_index is consumed 130160341Sharti * then we can't add entries to this table 131160341Sharti * So it is better to exit - if the table is sparsed 132160341Sharti * at the next agent run we can fill it fully. 133160341Sharti */ 134160341Sharti errx(EX_SOFTWARE, "hrDeviceTable index wrap"); 135160341Sharti /* not reachable */ 136154133Sharti } 137154133Sharti 138154133Sharti if ((map = malloc(sizeof(*map))) == NULL) { 139154133Sharti syslog(LOG_ERR, "hrDeviceTable: %s: %m", __func__ ); 140154133Sharti return (NULL); 141154133Sharti } 142154133Sharti 143160341Sharti map->entry_p = NULL; 144160341Sharti 145160341Sharti name_len = strlen(name) + 1; 146160341Sharti if (name_len > DEV_NAME_MLEN) 147160341Sharti name_len = DEV_NAME_MLEN; 148160341Sharti 149160341Sharti if ((map->name_key = malloc(name_len)) == NULL) { 150160341Sharti syslog(LOG_ERR, "hrDeviceTable: %s: %m", __func__ ); 151160341Sharti free(map); 152160341Sharti return (NULL); 153160341Sharti } 154160341Sharti 155160341Sharti location_len = strlen(location) + 1; 156160341Sharti if (location_len > DEV_LOC_MLEN) 157160341Sharti location_len = DEV_LOC_MLEN; 158160341Sharti 159160341Sharti if ((map->location_key = malloc(location_len )) == NULL) { 160160341Sharti syslog(LOG_ERR, "hrDeviceTable: %s: %m", __func__ ); 161160341Sharti free(map->name_key); 162160341Sharti free(map); 163160341Sharti return (NULL); 164160341Sharti } 165160341Sharti 166154133Sharti map->hrIndex = next_device_index++; 167154133Sharti 168160341Sharti strlcpy(map->name_key, name, name_len); 169160341Sharti strlcpy(map->location_key, location, location_len); 170154133Sharti 171154133Sharti STAILQ_INSERT_TAIL(&device_map, map, link); 172154133Sharti HRDBG("%s at %s added into hrDeviceMap at index=%d", 173154133Sharti name, location, map->hrIndex); 174154133Sharti } else { 175154133Sharti HRDBG("%s at %s exists in hrDeviceMap index=%d", 176154133Sharti name, location, map->hrIndex); 177154133Sharti } 178154133Sharti 179160341Sharti if ((entry = malloc(sizeof(*entry))) == NULL) { 180160341Sharti syslog(LOG_WARNING, "hrDeviceTable: %s: %m", __func__); 181160341Sharti return (NULL); 182160341Sharti } 183160341Sharti memset(entry, 0, sizeof(*entry)); 184160341Sharti 185154133Sharti entry->index = map->hrIndex; 186160341Sharti map->entry_p = entry; 187154133Sharti 188160341Sharti if ((entry->name = strdup(map->name_key)) == NULL) { 189160341Sharti syslog(LOG_ERR, "hrDeviceTable: %s: %m", __func__ ); 190160341Sharti free(entry); 191160341Sharti return (NULL); 192160341Sharti } 193154133Sharti 194160341Sharti if ((entry->location = strdup(map->location_key)) == NULL) { 195160341Sharti syslog(LOG_ERR, "hrDeviceTable: %s: %m", __func__ ); 196160341Sharti free(entry->name); 197160341Sharti free(entry); 198160341Sharti return (NULL); 199160341Sharti } 200160341Sharti 201160341Sharti /* 202160341Sharti * From here till the end of this function we reuse name_len 203228990Suqs * for a different purpose - for device_entry::descr 204160341Sharti */ 205154133Sharti if (name[0] != '\0') 206160341Sharti name_len = strlen(name) + strlen(descr) + 207160341Sharti strlen(": ") + 1; 208154133Sharti else 209160341Sharti name_len = strlen(location) + strlen(descr) + 210160341Sharti strlen("unknown at : ") + 1; 211160341Sharti 212160341Sharti if (name_len > DEV_DESCR_MLEN) 213160341Sharti name_len = DEV_DESCR_MLEN; 214160341Sharti 215160341Sharti if ((entry->descr = malloc(name_len )) == NULL) { 216160341Sharti syslog(LOG_ERR, "hrDeviceTable: %s: %m", __func__ ); 217160341Sharti free(entry->name); 218160341Sharti free(entry->location); 219160341Sharti free(entry); 220160341Sharti return (NULL); 221160341Sharti } 222160341Sharti 223160341Sharti memset(&entry->descr[0], '\0', name_len); 224160341Sharti 225160341Sharti if (name[0] != '\0') 226160341Sharti snprintf(entry->descr, name_len, 227160341Sharti "%s: %s", name, descr); 228160341Sharti else 229160341Sharti snprintf(entry->descr, name_len, 230154133Sharti "unknown at %s: %s", location, descr); 231154133Sharti 232160341Sharti entry->id = &oid_zeroDotZero; /* unknown id - FIXME */ 233160341Sharti entry->status = (u_int)DS_UNKNOWN; 234154133Sharti entry->errors = 0; 235160341Sharti entry->type = &OIDX_hrDeviceOther_c; 236154133Sharti 237154133Sharti INSERT_OBJECT_INT(entry, &device_tbl); 238154133Sharti 239154133Sharti return (entry); 240154133Sharti} 241154133Sharti 242154133Sharti/** 243154133Sharti * Create a new entry into the device table. 244154133Sharti */ 245154133Shartistatic struct device_entry * 246154133Shartidevice_entry_create_devinfo(const struct devinfo_dev *dev_p) 247154133Sharti{ 248154133Sharti 249154133Sharti assert(dev_p->dd_name != NULL); 250154133Sharti assert(dev_p->dd_location != NULL); 251154133Sharti 252154133Sharti return (device_entry_create(dev_p->dd_name, dev_p->dd_location, 253154133Sharti dev_p->dd_desc)); 254154133Sharti} 255154133Sharti 256154133Sharti/** 257154133Sharti * Delete an entry from the device table. 258154133Sharti */ 259160341Shartivoid 260154133Shartidevice_entry_delete(struct device_entry *entry) 261154133Sharti{ 262154133Sharti struct device_map_entry *map; 263154133Sharti 264154133Sharti assert(entry != NULL); 265154133Sharti 266154133Sharti TAILQ_REMOVE(&device_tbl, entry, link); 267154133Sharti 268154133Sharti STAILQ_FOREACH(map, &device_map, link) 269154133Sharti if (map->entry_p == entry) { 270154133Sharti map->entry_p = NULL; 271154133Sharti break; 272154133Sharti } 273160341Sharti 274160341Sharti FREE_DEV_STRUCT(entry); 275154133Sharti} 276154133Sharti 277154133Sharti/** 278154133Sharti * Find an entry given its name and location 279154133Sharti */ 280154133Shartistatic struct device_entry * 281154133Shartidevice_find_by_dev(const struct devinfo_dev *dev_p) 282154133Sharti{ 283154133Sharti struct device_map_entry *map; 284154133Sharti 285154133Sharti assert(dev_p != NULL); 286154133Sharti 287154133Sharti STAILQ_FOREACH(map, &device_map, link) 288154133Sharti if (strcmp(map->name_key, dev_p->dd_name) == 0 && 289154133Sharti strcmp(map->location_key, dev_p->dd_location) == 0) 290154133Sharti return (map->entry_p); 291154133Sharti return (NULL); 292154133Sharti} 293154133Sharti 294154133Sharti/** 295154133Sharti * Find an entry given its index. 296154133Sharti */ 297154133Shartistruct device_entry * 298154133Shartidevice_find_by_index(int32_t idx) 299154133Sharti{ 300154133Sharti struct device_entry *entry; 301154133Sharti 302154133Sharti TAILQ_FOREACH(entry, &device_tbl, link) 303154133Sharti if (entry->index == idx) 304154133Sharti return (entry); 305154133Sharti return (NULL); 306154133Sharti} 307154133Sharti 308154133Sharti/** 309154133Sharti * Find an device entry given its name. 310154133Sharti */ 311154133Shartistruct device_entry * 312154133Shartidevice_find_by_name(const char *dev_name) 313154133Sharti{ 314154133Sharti struct device_map_entry *map; 315154133Sharti 316154133Sharti assert(dev_name != NULL); 317154133Sharti 318154133Sharti STAILQ_FOREACH(map, &device_map, link) 319154133Sharti if (strcmp(map->name_key, dev_name) == 0) 320154133Sharti return (map->entry_p); 321154133Sharti 322154133Sharti return (NULL); 323154133Sharti} 324154133Sharti 325154133Sharti/** 326154133Sharti * Find out the type of device. CPU only currently. 327154133Sharti */ 328154133Shartistatic void 329160341Shartidevice_get_type(struct devinfo_dev *dev_p, const struct asn_oid **out_type_p) 330154133Sharti{ 331154133Sharti 332154133Sharti assert(dev_p != NULL); 333154133Sharti assert(out_type_p != NULL); 334154133Sharti 335154133Sharti if (dev_p == NULL) 336154133Sharti return; 337154133Sharti 338154133Sharti if (strncmp(dev_p->dd_name, "cpu", strlen("cpu")) == 0 && 339154133Sharti strstr(dev_p->dd_location, ".CPU") != NULL) { 340160341Sharti *out_type_p = &OIDX_hrDeviceProcessor_c; 341154133Sharti return; 342154133Sharti } 343154133Sharti} 344154133Sharti 345154133Sharti/** 346154133Sharti * Get the status of a device 347154133Sharti */ 348154133Shartistatic enum DeviceStatus 349154133Shartidevice_get_status(struct devinfo_dev *dev) 350154133Sharti{ 351154133Sharti 352154133Sharti assert(dev != NULL); 353154133Sharti 354154133Sharti switch (dev->dd_state) { 355199291Sattilio case DS_ALIVE: /* probe succeeded */ 356199291Sattilio case DS_NOTPRESENT: /* not probed or probe failed */ 357154133Sharti return (DS_DOWN); 358199291Sattilio case DS_ATTACHED: /* attach method called */ 359199291Sattilio case DS_BUSY: /* device is open */ 360154133Sharti return (DS_RUNNING); 361154133Sharti default: 362154133Sharti return (DS_UNKNOWN); 363154133Sharti } 364154133Sharti} 365154133Sharti 366154133Sharti/** 367154133Sharti * Get the info for the given device and then recursively process all 368154133Sharti * child devices. 369154133Sharti */ 370154133Shartistatic int 371154133Shartidevice_collector(struct devinfo_dev *dev, void *arg) 372154133Sharti{ 373154133Sharti struct device_entry *entry; 374154133Sharti 375154133Sharti HRDBG("%llu/%llu name='%s' desc='%s' drivername='%s' location='%s'", 376154133Sharti (unsigned long long)dev->dd_handle, 377154133Sharti (unsigned long long)dev->dd_parent, dev->dd_name, dev->dd_desc, 378154133Sharti dev->dd_drivername, dev->dd_location); 379154133Sharti 380154133Sharti if (dev->dd_name[0] != '\0' || dev->dd_location[0] != '\0') { 381154133Sharti HRDBG("ANALYZING dev %s at %s", 382154133Sharti dev->dd_name, dev->dd_location); 383154133Sharti 384154133Sharti if ((entry = device_find_by_dev(dev)) != NULL) { 385154133Sharti entry->flags |= HR_DEVICE_FOUND; 386154133Sharti entry->status = (u_int)device_get_status(dev); 387154133Sharti } else if ((entry = device_entry_create_devinfo(dev)) != NULL) { 388154133Sharti device_get_type(dev, &entry->type); 389154133Sharti 390154133Sharti entry->flags |= HR_DEVICE_FOUND; 391154133Sharti entry->status = (u_int)device_get_status(dev); 392154133Sharti } 393154133Sharti } else { 394154133Sharti HRDBG("SKIPPED unknown device at location '%s'", 395154133Sharti dev->dd_location ); 396154133Sharti } 397154133Sharti 398154133Sharti return (devinfo_foreach_device_child(dev, device_collector, arg)); 399154133Sharti} 400154133Sharti 401154133Sharti/** 402154133Sharti * Create the socket to the device daemon. 403154133Sharti */ 404154133Shartistatic int 405154133Sharticreate_devd_socket(void) 406154133Sharti{ 407154133Sharti int d_sock; 408154133Sharti struct sockaddr_un devd_addr; 409154133Sharti 410154133Sharti bzero(&devd_addr, sizeof(struct sockaddr_un)); 411154133Sharti 412154133Sharti if ((d_sock = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) { 413154133Sharti syslog(LOG_ERR, "Failed to create the socket for %s: %m", 414154133Sharti PATH_DEVD_PIPE); 415154133Sharti return (-1); 416154133Sharti } 417154133Sharti 418154133Sharti devd_addr.sun_family = PF_LOCAL; 419154133Sharti devd_addr.sun_len = sizeof(devd_addr); 420154133Sharti strlcpy(devd_addr.sun_path, PATH_DEVD_PIPE, 421154133Sharti sizeof(devd_addr.sun_path) - 1); 422154133Sharti 423154133Sharti if (connect(d_sock, (struct sockaddr *)&devd_addr, 424154133Sharti sizeof(devd_addr)) == -1) { 425154133Sharti syslog(LOG_ERR,"Failed to connect socket for %s: %m", 426154133Sharti PATH_DEVD_PIPE); 427154133Sharti if (close(d_sock) < 0 ) 428154133Sharti syslog(LOG_ERR,"Failed to close socket for %s: %m", 429154133Sharti PATH_DEVD_PIPE); 430154133Sharti return (-1); 431154133Sharti } 432154133Sharti 433154133Sharti return (d_sock); 434154133Sharti} 435154133Sharti 436154133Sharti/* 437154133Sharti * Event on the devd socket. 438160341Sharti * 439154133Sharti * We should probably directly process entries here. For simplicity just 440154133Sharti * call the refresh routine with the force flag for now. 441154133Sharti */ 442154133Shartistatic void 443154133Shartidevd_socket_callback(int fd, void *arg __unused) 444154133Sharti{ 445154133Sharti char buf[512]; 446154133Sharti int read_len = -1; 447154133Sharti 448154133Sharti assert(fd == devd_sock); 449154133Sharti 450154133Sharti HRDBG("called"); 451154133Sharti 452223933Saeagain: 453223933Sae read_len = read(fd, buf, sizeof(buf)); 454154133Sharti if (read_len < 0) { 455154133Sharti if (errno == EBADF) { 456154133Sharti devd_sock = -1; 457154133Sharti if (devd_fd != NULL) { 458154133Sharti fd_deselect(devd_fd); 459154133Sharti devd_fd = NULL; 460154133Sharti } 461154133Sharti syslog(LOG_ERR, "Closing devd_fd, revert to " 462154133Sharti "devinfo polling"); 463154133Sharti } 464154133Sharti 465154133Sharti } else if (read_len == 0) { 466154133Sharti syslog(LOG_ERR, "zero bytes read from devd pipe... " 467154133Sharti "closing socket!"); 468154133Sharti 469154133Sharti if (close(devd_sock) < 0 ) 470154133Sharti syslog(LOG_ERR, "Failed to close devd socket: %m"); 471154133Sharti 472154133Sharti devd_sock = -1; 473154133Sharti if (devd_fd != NULL) { 474154133Sharti fd_deselect(devd_fd); 475154133Sharti devd_fd = NULL; 476154133Sharti } 477154133Sharti syslog(LOG_ERR, "Closing devd_fd, revert to devinfo polling"); 478154133Sharti 479154133Sharti } else { 480223933Sae if (read_len == sizeof(buf)) 481223933Sae goto again; 482223933Sae refresh_device_tbl(1); 483154133Sharti } 484154133Sharti} 485154133Sharti 486154133Sharti/** 487154133Sharti * Initialize and populate the device table. 488154133Sharti */ 489154133Shartivoid 490154133Shartiinit_device_tbl(void) 491154133Sharti{ 492154133Sharti 493154133Sharti /* initially populate table for the other tables */ 494154133Sharti refresh_device_tbl(1); 495154133Sharti 496154133Sharti /* no problem if that fails - just use polling mode */ 497154133Sharti devd_sock = create_devd_socket(); 498154133Sharti} 499154133Sharti 500154133Sharti/** 501154133Sharti * Start devd(8) monitoring. 502154133Sharti */ 503154133Shartivoid 504154133Shartistart_device_tbl(struct lmodule *mod) 505154133Sharti{ 506154133Sharti 507154133Sharti if (devd_sock > 0) { 508154133Sharti devd_fd = fd_select(devd_sock, devd_socket_callback, NULL, mod); 509154133Sharti if (devd_fd == NULL) 510154133Sharti syslog(LOG_ERR, "fd_select failed on devd socket: %m"); 511154133Sharti } 512154133Sharti} 513154133Sharti 514154133Sharti/** 515154133Sharti * Finalization routine for hrDeviceTable 516154133Sharti * It destroys the lists and frees any allocated heap memory 517154133Sharti */ 518154133Shartivoid 519154133Shartifini_device_tbl(void) 520154133Sharti{ 521154133Sharti struct device_map_entry *n1; 522154133Sharti 523154133Sharti if (devd_fd != NULL) 524154133Sharti fd_deselect(devd_fd); 525154133Sharti 526154133Sharti if (devd_sock != -1) 527154133Sharti (void)close(devd_sock); 528154133Sharti 529154133Sharti devinfo_free(); 530154133Sharti 531154133Sharti while ((n1 = STAILQ_FIRST(&device_map)) != NULL) { 532154133Sharti STAILQ_REMOVE_HEAD(&device_map, link); 533154133Sharti if (n1->entry_p != NULL) { 534154133Sharti TAILQ_REMOVE(&device_tbl, n1->entry_p, link); 535160341Sharti FREE_DEV_STRUCT(n1->entry_p); 536154133Sharti } 537160341Sharti free(n1->name_key); 538160341Sharti free(n1->location_key); 539154133Sharti free(n1); 540154133Sharti } 541154133Sharti assert(TAILQ_EMPTY(&device_tbl)); 542154133Sharti} 543154133Sharti 544154133Sharti/** 545154133Sharti * Refresh routine for hrDeviceTable. We don't refresh here if the devd socket 546154133Sharti * is open, because in this case we have the actual information always. We 547154133Sharti * also don't refresh when the table is new enough (if we don't have a devd 548154133Sharti * socket). In either case a refresh can be forced by passing a non-zero value. 549154133Sharti */ 550154133Shartivoid 551154133Shartirefresh_device_tbl(int force) 552154133Sharti{ 553154133Sharti struct device_entry *entry, *entry_tmp; 554154133Sharti struct devinfo_dev *dev_root; 555154133Sharti static int act = 0; 556154133Sharti 557154133Sharti if (!force && (devd_sock >= 0 || 558154133Sharti (device_tick != 0 && this_tick - device_tick < device_tbl_refresh))){ 559154133Sharti HRDBG("no refresh needed"); 560154133Sharti return; 561154133Sharti } 562154133Sharti 563154133Sharti if (act) { 564154133Sharti syslog(LOG_ERR, "%s: recursive call", __func__); 565154133Sharti return; 566154133Sharti } 567154133Sharti 568154133Sharti if (devinfo_init() != 0) { 569154133Sharti syslog(LOG_ERR,"%s: devinfo_init failed: %m", __func__); 570154133Sharti return; 571154133Sharti } 572154133Sharti 573154133Sharti act = 1; 574154133Sharti if ((dev_root = devinfo_handle_to_device(DEVINFO_ROOT_DEVICE)) == NULL){ 575154133Sharti syslog(LOG_ERR, "%s: can't get the root device: %m", __func__); 576154133Sharti goto out; 577154133Sharti } 578154133Sharti 579154133Sharti /* mark each entry as missing */ 580154133Sharti TAILQ_FOREACH(entry, &device_tbl, link) 581154133Sharti entry->flags &= ~HR_DEVICE_FOUND; 582154133Sharti 583154133Sharti if (devinfo_foreach_device_child(dev_root, device_collector, NULL)) 584154133Sharti syslog(LOG_ERR, "%s: devinfo_foreach_device_child failed", 585154133Sharti __func__); 586154133Sharti 587154133Sharti /* 588154133Sharti * Purge items that disappeared 589154133Sharti */ 590154133Sharti TAILQ_FOREACH_SAFE(entry, &device_tbl, link, entry_tmp) { 591154133Sharti /* 592154133Sharti * If HR_DEVICE_IMMUTABLE bit is set then this means that 593154133Sharti * this entry was not detected by the above 594154133Sharti * devinfo_foreach_device() call. So we are not deleting 595154133Sharti * it there. 596154133Sharti */ 597154133Sharti if (!(entry->flags & HR_DEVICE_FOUND) && 598154133Sharti !(entry->flags & HR_DEVICE_IMMUTABLE)) 599154133Sharti device_entry_delete(entry); 600154133Sharti } 601154133Sharti 602154133Sharti device_tick = this_tick; 603154133Sharti 604154133Sharti /* 605154133Sharti * Force a refresh for the hrDiskStorageTable 606154133Sharti * XXX Why not the other dependen tables? 607154133Sharti */ 608154133Sharti refresh_disk_storage_tbl(1); 609154133Sharti 610154133Sharti out: 611154133Sharti devinfo_free(); 612154133Sharti act = 0; 613154133Sharti} 614154133Sharti 615154133Sharti/** 616154133Sharti * This is the implementation for a generated (by a SNMP tool) 617154133Sharti * function prototype, see hostres_tree.h 618154133Sharti * It handles the SNMP operations for hrDeviceTable 619154133Sharti */ 620154133Shartiint 621154133Shartiop_hrDeviceTable(struct snmp_context *ctx __unused, struct snmp_value *value, 622154133Sharti u_int sub, u_int iidx __unused, enum snmp_op curr_op) 623154133Sharti{ 624154133Sharti struct device_entry *entry; 625154133Sharti 626154133Sharti refresh_device_tbl(0); 627154133Sharti 628154133Sharti switch (curr_op) { 629154133Sharti 630154133Sharti case SNMP_OP_GETNEXT: 631154133Sharti if ((entry = NEXT_OBJECT_INT(&device_tbl, 632154133Sharti &value->var, sub)) == NULL) 633154133Sharti return (SNMP_ERR_NOSUCHNAME); 634154133Sharti value->var.len = sub + 1; 635154133Sharti value->var.subs[sub] = entry->index; 636154133Sharti goto get; 637154133Sharti 638154133Sharti case SNMP_OP_GET: 639154133Sharti if ((entry = FIND_OBJECT_INT(&device_tbl, 640154133Sharti &value->var, sub)) == NULL) 641154133Sharti return (SNMP_ERR_NOSUCHNAME); 642154133Sharti goto get; 643154133Sharti 644154133Sharti case SNMP_OP_SET: 645154133Sharti if ((entry = FIND_OBJECT_INT(&device_tbl, 646154133Sharti &value->var, sub)) == NULL) 647154133Sharti return (SNMP_ERR_NO_CREATION); 648154133Sharti return (SNMP_ERR_NOT_WRITEABLE); 649154133Sharti 650154133Sharti case SNMP_OP_ROLLBACK: 651154133Sharti case SNMP_OP_COMMIT: 652154133Sharti abort(); 653154133Sharti } 654154133Sharti abort(); 655154133Sharti 656154133Sharti get: 657154133Sharti switch (value->var.subs[sub - 1]) { 658154133Sharti 659154133Sharti case LEAF_hrDeviceIndex: 660154133Sharti value->v.integer = entry->index; 661154133Sharti return (SNMP_ERR_NOERROR); 662154133Sharti 663154133Sharti case LEAF_hrDeviceType: 664160341Sharti assert(entry->type != NULL); 665160341Sharti value->v.oid = *(entry->type); 666154133Sharti return (SNMP_ERR_NOERROR); 667154133Sharti 668154133Sharti case LEAF_hrDeviceDescr: 669154133Sharti return (string_get(value, entry->descr, -1)); 670154133Sharti 671154133Sharti case LEAF_hrDeviceID: 672160341Sharti value->v.oid = *(entry->id); 673154133Sharti return (SNMP_ERR_NOERROR); 674154133Sharti 675154133Sharti case LEAF_hrDeviceStatus: 676154133Sharti value->v.integer = entry->status; 677154133Sharti return (SNMP_ERR_NOERROR); 678154133Sharti 679154133Sharti case LEAF_hrDeviceErrors: 680154133Sharti value->v.uint32 = entry->errors; 681154133Sharti return (SNMP_ERR_NOERROR); 682154133Sharti } 683154133Sharti abort(); 684154133Sharti} 685