Path: blob/main/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_fs_tbl.c
108574 views
/*-1* Copyright (c) 2005-2006 The FreeBSD Project2* All rights reserved.3*4* Author: Victor Cruceru <[email protected]>5*6* Redistribution of this software and documentation and use in source and7* binary forms, with or without modification, are permitted provided that8* the following conditions are met:9*10* 1. Redistributions of source code or documentation must retain the above11* copyright notice, this list of conditions and the following disclaimer.12* 2. Redistributions in binary form must reproduce the above copyright13* notice, this list of conditions and the following disclaimer in the14* documentation and/or other materials provided with the distribution.15*16* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND17* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE18* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE19* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE20* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL21* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS22* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)23* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT24* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY25* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF26* SUCH DAMAGE.27*/2829/*30* Host Resources MIB for SNMPd. Implementation for hrFSTable31*/3233#include <sys/types.h>34#include <sys/param.h>35#include <sys/sysctl.h>36#include <sys/mount.h>3738#include <assert.h>39#include <err.h>40#include <stdlib.h>41#include <string.h>42#include <syslog.h>43#include <sysexits.h>4445#include "hostres_snmp.h"46#include "hostres_oid.h"47#include "hostres_tree.h"4849/*50* File system access enum51*/52enum hrFSAccess {53FS_READ_WRITE = 1,54FS_READ_ONLY = 255};5657/* maximum length (according to MIB) for fs_entry::mountPoint */58#define FS_MP_MLEN (128 + 1)5960/* maximum length (according to MIB) for fs_entry::remoteMountPoint */61#define FS_RMP_MLEN (128 + 1)6263/*64* This structure is used to hold a SNMP table entry65* for HOST-RESOURCES-MIB's hrFSTable66*/67struct fs_entry {68int32_t index;69u_char *mountPoint;70u_char *remoteMountPoint;71const struct asn_oid *type;72int32_t access; /* enum hrFSAccess, see above */73int32_t bootable; /* TruthValue */74int32_t storageIndex; /* hrStorageTblEntry::index */75u_char lastFullBackupDate[11];76u_char lastPartialBackupDate[11];77#define HR_FS_FOUND 0x00178uint32_t flags; /* not in mib table, for internal use */79TAILQ_ENTRY(fs_entry) link;80};81TAILQ_HEAD(fs_tbl, fs_entry);8283/*84* Next structure is used to keep o list of mappings from a specific name85* (a_name) to an entry in the hrFSTblEntry. We are trying to keep the same86* index for a specific name at least for the duration of one SNMP agent run.87*/88struct fs_map_entry {89int32_t hrIndex; /* used for fs_entry::index */90u_char *a_name; /* map key same as fs_entry::mountPoint */9192/* may be NULL if the respective hrFSTblEntry is (temporally) gone */93struct fs_entry *entry;94STAILQ_ENTRY(fs_map_entry) link;95};96STAILQ_HEAD(fs_map, fs_map_entry);9798/* head of the list with hrFSTable's entries */99static struct fs_tbl fs_tbl = TAILQ_HEAD_INITIALIZER(fs_tbl);100101/* for consistent table indexing */102static struct fs_map fs_map = STAILQ_HEAD_INITIALIZER(fs_map);103104/* next index available for hrFSTable */105static uint32_t next_fs_index = 1;106107/* last tick when hrFSTable was updated */108static uint64_t fs_tick;109110/* maximum number of ticks between refreshs */111uint32_t fs_tbl_refresh = HR_FS_TBL_REFRESH * 100;112113/* some constants */114static const struct asn_oid OIDX_hrFSBerkeleyFFS_c = OIDX_hrFSBerkeleyFFS;115static const struct asn_oid OIDX_hrFSiso9660_c = OIDX_hrFSiso9660;116static const struct asn_oid OIDX_hrFSNFS_c = OIDX_hrFSNFS;117static const struct asn_oid OIDX_hrFSLinuxExt2_c = OIDX_hrFSLinuxExt2;118static const struct asn_oid OIDX_hrFSOther_c = OIDX_hrFSOther;119static const struct asn_oid OIDX_hrFSFAT32_c = OIDX_hrFSFAT32;120static const struct asn_oid OIDX_hrFSNTFS_c = OIDX_hrFSNTFS;121static const struct asn_oid OIDX_hrFSNetware_c = OIDX_hrFSNetware;122static const struct asn_oid OIDX_hrFSHPFS_c = OIDX_hrFSHPFS;123static const struct asn_oid OIDX_hrFSUnknown_c = OIDX_hrFSUnknown;124125/* file system type map */126static const struct {127const char *str; /* the type string */128const struct asn_oid *oid; /* the OID to return */129} fs_type_map[] = {130{ "ufs", &OIDX_hrFSBerkeleyFFS_c },131{ "zfs", &OIDX_hrFSOther_c },132{ "cd9660", &OIDX_hrFSiso9660_c },133{ "nfs", &OIDX_hrFSNFS_c },134{ "ext2fs", &OIDX_hrFSLinuxExt2_c },135{ "procfs", &OIDX_hrFSOther_c },136{ "devfs", &OIDX_hrFSOther_c },137{ "msdosfs", &OIDX_hrFSFAT32_c },138{ "ntfs", &OIDX_hrFSNTFS_c },139{ "nwfs", &OIDX_hrFSNetware_c },140{ "hpfs", &OIDX_hrFSHPFS_c },141{ "smbfs", &OIDX_hrFSOther_c },142};143#define N_FS_TYPE_MAP nitems(fs_type_map)144145/**146* Create an entry into the FS table and an entry in the map (if needed).147*/148static struct fs_entry *149fs_entry_create(const char *name)150{151struct fs_entry *entry;152struct fs_map_entry *map;153154assert(name != NULL);155assert(strlen(name) > 0);156157STAILQ_FOREACH(map, &fs_map, link)158if (strcmp(map->a_name, name) == 0)159break;160161if (map == NULL) {162size_t mount_point_len;163164/* new object - get a new index */165if (next_fs_index > INT_MAX) {166/* Unrecoverable error - die clean and quicly*/167syslog(LOG_ERR, "%s: hrFSTable index wrap", __func__);168errx(EX_SOFTWARE, "hrFSTable index wrap");169}170171if ((map = malloc(sizeof(*map))) == NULL) {172syslog(LOG_ERR, "%s: %m", __func__);173return (NULL);174}175176mount_point_len = strlen(name) + 1;177if (mount_point_len > FS_MP_MLEN)178mount_point_len = FS_MP_MLEN;179180if ((map->a_name = malloc(mount_point_len)) == NULL) {181syslog(LOG_ERR, "%s: %m", __func__);182free(map);183return (NULL);184}185186strlcpy(map->a_name, name, mount_point_len);187188map->hrIndex = next_fs_index++;189map->entry = NULL;190STAILQ_INSERT_TAIL(&fs_map, map, link);191192HRDBG("%s added into hrFSMap at index=%d", name, map->hrIndex);193} else {194HRDBG("%s exists in hrFSMap index=%d", name, map->hrIndex);195}196197if ((entry = malloc(sizeof(*entry))) == NULL) {198syslog(LOG_WARNING, "%s: %m", __func__);199return (NULL);200}201202if ((entry->mountPoint = strdup(name)) == NULL) {203syslog(LOG_ERR, "%s: %m", __func__);204free(entry);205return (NULL);206}207208entry->index = map->hrIndex;209map->entry = entry;210211INSERT_OBJECT_INT(entry, &fs_tbl);212return (entry);213}214215/**216* Delete an entry in the FS table.217*/218static void219fs_entry_delete(struct fs_entry* entry)220{221struct fs_map_entry *map;222223assert(entry != NULL);224225TAILQ_REMOVE(&fs_tbl, entry, link);226STAILQ_FOREACH(map, &fs_map, link)227if (map->entry == entry) {228map->entry = NULL;229break;230}231free(entry->mountPoint);232free(entry->remoteMountPoint);233free(entry);234}235236/**237* Find a table entry by its name238*/239static struct fs_entry *240fs_find_by_name(const char *name)241{242struct fs_entry *entry;243244TAILQ_FOREACH(entry, &fs_tbl, link)245if (strcmp(entry->mountPoint, name) == 0)246return (entry);247248return (NULL);249}250251/**252* Get rid of all data253*/254void255fini_fs_tbl(void)256{257struct fs_map_entry *n1;258259while ((n1 = STAILQ_FIRST(&fs_map)) != NULL) {260STAILQ_REMOVE_HEAD(&fs_map, link);261if (n1->entry != NULL) {262TAILQ_REMOVE(&fs_tbl, n1->entry, link);263free(n1->entry->mountPoint);264free(n1->entry->remoteMountPoint);265free(n1->entry);266}267free(n1->a_name);268free(n1);269}270assert(TAILQ_EMPTY(&fs_tbl));271}272273/**274* Called before the refreshing is started from the storage table.275*/276void277fs_tbl_pre_refresh(void)278{279struct fs_entry *entry;280281/* mark each entry as missisng */282TAILQ_FOREACH(entry, &fs_tbl, link)283entry->flags &= ~HR_FS_FOUND;284}285286/**287* Called after refreshing from the storage table.288*/289void290fs_tbl_post_refresh(void)291{292struct fs_entry *entry, *entry_tmp;293294/*295* Purge items that disappeared296*/297TAILQ_FOREACH_SAFE(entry, &fs_tbl, link, entry_tmp)298if (!(entry->flags & HR_FS_FOUND))299fs_entry_delete(entry);300301fs_tick = this_tick;302}303304/*305* Refresh the FS table. This is done by forcing a refresh of the storage table.306*/307void308refresh_fs_tbl(void)309{310311if (fs_tick == 0 || this_tick - fs_tick >= fs_tbl_refresh) {312refresh_storage_tbl(1);313HRDBG("refresh DONE");314}315}316317/**318* Get the type OID for a given file system319*/320const struct asn_oid *321fs_get_type(const struct statfs *fs_p)322{323u_int t;324325assert(fs_p != NULL);326327for (t = 0; t < N_FS_TYPE_MAP; t++)328if (strcmp(fs_type_map[t].str, fs_p->f_fstypename) == 0)329return (fs_type_map[t].oid);330331return (&OIDX_hrFSUnknown_c);332}333334/*335* Given information returned from statfs(2) either create a new entry into336* the fs_tbl or refresh the entry if it is already there.337*/338void339fs_tbl_process_statfs_entry(const struct statfs *fs_p, int32_t storage_idx)340{341struct fs_entry *entry;342343assert(fs_p != 0);344345HRDBG("for hrStorageEntry::index %d", storage_idx);346347if (fs_p == NULL)348return;349350if ((entry = fs_find_by_name(fs_p->f_mntonname)) != NULL ||351(entry = fs_entry_create(fs_p->f_mntonname)) != NULL) {352entry->flags |= HR_FS_FOUND;353354if (!(fs_p->f_flags & MNT_LOCAL)) {355/* this is a remote mount */356entry->remoteMountPoint = strdup(fs_p->f_mntfromname);357/* if strdup failed, let it be NULL */358359} else {360entry->remoteMountPoint = strdup("");361/* if strdup failed, let it be NULL */362}363364entry->type = fs_get_type(fs_p);365366if ((fs_p->f_flags & MNT_RDONLY) == MNT_RDONLY)367entry->access = FS_READ_ONLY;368else369entry->access = FS_READ_WRITE;370371/* FIXME - bootable fs ?! */372entry->bootable = TRUTH_MK((fs_p->f_flags & MNT_ROOTFS)373== MNT_ROOTFS);374375entry->storageIndex = storage_idx;376377/* Info not available */378memset(entry->lastFullBackupDate, 0,379sizeof(entry->lastFullBackupDate));380381/* Info not available */382memset(entry->lastPartialBackupDate, 0,383sizeof(entry->lastPartialBackupDate));384385handle_partition_fs_index(fs_p->f_mntfromname, entry->index);386}387}388389/*390* This is the implementation for a generated (by our SNMP "compiler" tool)391* function prototype, see hostres_tree.h392* It handles the SNMP operations for hrFSTable393*/394int395op_hrFSTable(struct snmp_context *ctx __unused, struct snmp_value *value,396u_int sub, u_int iidx __unused, enum snmp_op curr_op)397{398struct fs_entry *entry;399400refresh_fs_tbl();401402switch (curr_op) {403404case SNMP_OP_GETNEXT:405if ((entry = NEXT_OBJECT_INT(&fs_tbl,406&value->var, sub)) == NULL)407return (SNMP_ERR_NOSUCHNAME);408value->var.len = sub + 1;409value->var.subs[sub] = entry->index;410goto get;411412case SNMP_OP_GET:413if ((entry = FIND_OBJECT_INT(&fs_tbl,414&value->var, sub)) == NULL)415return (SNMP_ERR_NOSUCHNAME);416goto get;417418case SNMP_OP_SET:419if ((entry = FIND_OBJECT_INT(&fs_tbl,420&value->var, sub)) == NULL)421return (SNMP_ERR_NO_CREATION);422return (SNMP_ERR_NOT_WRITEABLE);423424case SNMP_OP_ROLLBACK:425case SNMP_OP_COMMIT:426abort();427}428abort();429get:430switch (value->var.subs[sub - 1]) {431432case LEAF_hrFSIndex:433value->v.integer = entry->index;434return (SNMP_ERR_NOERROR);435436case LEAF_hrFSMountPoint:437return (string_get(value, entry->mountPoint, -1));438439case LEAF_hrFSRemoteMountPoint:440if (entry->remoteMountPoint == NULL)441return (string_get(value, "", -1));442else443return (string_get(value, entry->remoteMountPoint, -1));444break;445446case LEAF_hrFSType:447assert(entry->type != NULL);448value->v.oid = *(entry->type);449return (SNMP_ERR_NOERROR);450451case LEAF_hrFSAccess:452value->v.integer = entry->access;453return (SNMP_ERR_NOERROR);454455case LEAF_hrFSBootable:456value->v.integer = entry->bootable;457return (SNMP_ERR_NOERROR);458459case LEAF_hrFSStorageIndex:460value->v.integer = entry->storageIndex;461return (SNMP_ERR_NOERROR);462463case LEAF_hrFSLastFullBackupDate:464return (string_get(value, entry->lastFullBackupDate, 8));465466case LEAF_hrFSLastPartialBackupDate:467return (string_get(value, entry->lastPartialBackupDate, 8));468}469abort();470}471472473