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: stable/11/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_fs_tbl.c 317062 2017-04-17 18:55:54Z araujo $ 30154133Sharti */ 31154133Sharti 32154133Sharti/* 33154133Sharti * Host Resources MIB for SNMPd. Implementation for hrFSTable 34154133Sharti */ 35154133Sharti 36154133Sharti#include <sys/types.h> 37154133Sharti#include <sys/param.h> 38154133Sharti#include <sys/sysctl.h> 39154133Sharti#include <sys/mount.h> 40154133Sharti 41154133Sharti#include <assert.h> 42154133Sharti#include <err.h> 43154133Sharti#include <stdlib.h> 44154133Sharti#include <string.h> 45154133Sharti#include <syslog.h> 46160341Sharti#include <sysexits.h> 47154133Sharti 48154133Sharti#include "hostres_snmp.h" 49154133Sharti#include "hostres_oid.h" 50154133Sharti#include "hostres_tree.h" 51154133Sharti 52154133Sharti/* 53154133Sharti * File system access enum 54154133Sharti */ 55154133Shartienum hrFSAccess { 56154133Sharti FS_READ_WRITE = 1, 57154133Sharti FS_READ_ONLY = 2 58154133Sharti}; 59154133Sharti 60160341Sharti/* maximum length (according to MIB) for fs_entry::mountPoint */ 61160341Sharti#define FS_MP_MLEN (128 + 1) 62160341Sharti 63160341Sharti/* maximum length (according to MIB) for fs_entry::remoteMountPoint */ 64160341Sharti#define FS_RMP_MLEN (128 + 1) 65160341Sharti 66154133Sharti/* 67154133Sharti * This structure is used to hold a SNMP table entry 68154133Sharti * for HOST-RESOURCES-MIB's hrFSTable 69154133Sharti */ 70154133Shartistruct fs_entry { 71154133Sharti int32_t index; 72160341Sharti u_char *mountPoint; 73160341Sharti u_char *remoteMountPoint; 74154133Sharti const struct asn_oid *type; 75154133Sharti int32_t access; /* enum hrFSAccess, see above */ 76154133Sharti int32_t bootable; /* TruthValue */ 77154133Sharti int32_t storageIndex; /* hrStorageTblEntry::index */ 78154133Sharti u_char lastFullBackupDate[11]; 79154133Sharti u_char lastPartialBackupDate[11]; 80160341Sharti#define HR_FS_FOUND 0x001 81154133Sharti uint32_t flags; /* not in mib table, for internal use */ 82154133Sharti TAILQ_ENTRY(fs_entry) link; 83154133Sharti}; 84154133ShartiTAILQ_HEAD(fs_tbl, fs_entry); 85154133Sharti 86154133Sharti/* 87154133Sharti * Next structure is used to keep o list of mappings from a specific name 88154133Sharti * (a_name) to an entry in the hrFSTblEntry. We are trying to keep the same 89154133Sharti * index for a specific name at least for the duration of one SNMP agent run. 90154133Sharti */ 91154133Shartistruct fs_map_entry { 92160341Sharti int32_t hrIndex; /* used for fs_entry::index */ 93160341Sharti u_char *a_name; /* map key same as fs_entry::mountPoint */ 94154133Sharti 95154133Sharti /* may be NULL if the respective hrFSTblEntry is (temporally) gone */ 96154133Sharti struct fs_entry *entry; 97154133Sharti STAILQ_ENTRY(fs_map_entry) link; 98154133Sharti}; 99154133ShartiSTAILQ_HEAD(fs_map, fs_map_entry); 100154133Sharti 101154133Sharti/* head of the list with hrFSTable's entries */ 102154133Shartistatic struct fs_tbl fs_tbl = TAILQ_HEAD_INITIALIZER(fs_tbl); 103154133Sharti 104154133Sharti/* for consistent table indexing */ 105154133Shartistatic struct fs_map fs_map = STAILQ_HEAD_INITIALIZER(fs_map); 106154133Sharti 107154133Sharti/* next index available for hrFSTable */ 108154133Shartistatic uint32_t next_fs_index = 1; 109154133Sharti 110154133Sharti/* last tick when hrFSTable was updated */ 111154133Shartistatic uint64_t fs_tick; 112154133Sharti 113154133Sharti/* maximum number of ticks between refreshs */ 114154133Shartiuint32_t fs_tbl_refresh = HR_FS_TBL_REFRESH * 100; 115154133Sharti 116154133Sharti/* some constants */ 117154133Shartistatic const struct asn_oid OIDX_hrFSBerkeleyFFS_c = OIDX_hrFSBerkeleyFFS; 118154133Shartistatic const struct asn_oid OIDX_hrFSiso9660_c = OIDX_hrFSiso9660; 119154133Shartistatic const struct asn_oid OIDX_hrFSNFS_c = OIDX_hrFSNFS; 120154133Shartistatic const struct asn_oid OIDX_hrFSLinuxExt2_c = OIDX_hrFSLinuxExt2; 121154133Shartistatic const struct asn_oid OIDX_hrFSOther_c = OIDX_hrFSOther; 122154133Shartistatic const struct asn_oid OIDX_hrFSFAT32_c = OIDX_hrFSFAT32; 123154133Shartistatic const struct asn_oid OIDX_hrFSNTFS_c = OIDX_hrFSNTFS; 124154133Shartistatic const struct asn_oid OIDX_hrFSNetware_c = OIDX_hrFSNetware; 125154133Shartistatic const struct asn_oid OIDX_hrFSHPFS_c = OIDX_hrFSHPFS; 126154133Shartistatic const struct asn_oid OIDX_hrFSUnknown_c = OIDX_hrFSUnknown; 127154133Sharti 128154133Sharti/* file system type map */ 129154133Shartistatic const struct { 130154133Sharti const char *str; /* the type string */ 131154133Sharti const struct asn_oid *oid; /* the OID to return */ 132154133Sharti} fs_type_map[] = { 133154133Sharti { "ufs", &OIDX_hrFSBerkeleyFFS_c }, 134310899Sngie { "zfs", &OIDX_hrFSOther_c }, 135154133Sharti { "cd9660", &OIDX_hrFSiso9660_c }, 136154133Sharti { "nfs", &OIDX_hrFSNFS_c }, 137154133Sharti { "ext2fs", &OIDX_hrFSLinuxExt2_c }, 138154133Sharti { "procfs", &OIDX_hrFSOther_c }, 139154133Sharti { "devfs", &OIDX_hrFSOther_c }, 140154133Sharti { "msdosfs", &OIDX_hrFSFAT32_c }, 141154133Sharti { "ntfs", &OIDX_hrFSNTFS_c }, 142154133Sharti { "nwfs", &OIDX_hrFSNetware_c }, 143154133Sharti { "hpfs", &OIDX_hrFSHPFS_c }, 144154133Sharti { "smbfs", &OIDX_hrFSOther_c }, 145154133Sharti}; 146317062Saraujo#define N_FS_TYPE_MAP nitems(fs_type_map) 147154133Sharti 148154133Sharti/** 149154133Sharti * Create an entry into the FS table and an entry in the map (if needed). 150154133Sharti */ 151154133Shartistatic struct fs_entry * 152154133Shartifs_entry_create(const char *name) 153154133Sharti{ 154154133Sharti struct fs_entry *entry; 155154133Sharti struct fs_map_entry *map; 156154133Sharti 157160341Sharti assert(name != NULL); 158160341Sharti assert(strlen(name) > 0); 159154133Sharti 160154133Sharti STAILQ_FOREACH(map, &fs_map, link) 161160341Sharti if (strcmp(map->a_name, name) == 0) 162154133Sharti break; 163154133Sharti 164154133Sharti if (map == NULL) { 165160341Sharti size_t mount_point_len; 166160341Sharti 167154133Sharti /* new object - get a new index */ 168154133Sharti if (next_fs_index > INT_MAX) { 169160341Sharti /* Unrecoverable error - die clean and quicly*/ 170310899Sngie syslog(LOG_ERR, "%s: hrFSTable index wrap", __func__); 171160341Sharti errx(EX_SOFTWARE, "hrFSTable index wrap"); 172154133Sharti } 173154133Sharti 174154133Sharti if ((map = malloc(sizeof(*map))) == NULL) { 175154133Sharti syslog(LOG_ERR, "%s: %m", __func__); 176154133Sharti return (NULL); 177154133Sharti } 178154133Sharti 179160341Sharti mount_point_len = strlen(name) + 1; 180160341Sharti if (mount_point_len > FS_MP_MLEN) 181160341Sharti mount_point_len = FS_MP_MLEN; 182160341Sharti 183160341Sharti if ((map->a_name = malloc(mount_point_len)) == NULL) { 184160341Sharti syslog(LOG_ERR, "%s: %m", __func__); 185160341Sharti free(map); 186160341Sharti return (NULL); 187160341Sharti } 188160341Sharti 189160341Sharti strlcpy(map->a_name, name, mount_point_len); 190160341Sharti 191154133Sharti map->hrIndex = next_fs_index++; 192160341Sharti map->entry = NULL; 193154133Sharti STAILQ_INSERT_TAIL(&fs_map, map, link); 194154133Sharti 195154133Sharti HRDBG("%s added into hrFSMap at index=%d", name, map->hrIndex); 196154133Sharti } else { 197154133Sharti HRDBG("%s exists in hrFSMap index=%d", name, map->hrIndex); 198154133Sharti } 199154133Sharti 200160341Sharti if ((entry = malloc(sizeof(*entry))) == NULL) { 201160341Sharti syslog(LOG_WARNING, "%s: %m", __func__); 202160341Sharti return (NULL); 203160341Sharti } 204160341Sharti 205160341Sharti if ((entry->mountPoint = strdup(name)) == NULL) { 206160341Sharti syslog(LOG_ERR, "%s: %m", __func__); 207160341Sharti free(entry); 208160341Sharti return (NULL); 209160341Sharti } 210160341Sharti 211154133Sharti entry->index = map->hrIndex; 212160341Sharti map->entry = entry; 213154133Sharti 214154133Sharti INSERT_OBJECT_INT(entry, &fs_tbl); 215154133Sharti return (entry); 216154133Sharti} 217154133Sharti 218154133Sharti/** 219154133Sharti * Delete an entry in the FS table. 220154133Sharti */ 221154133Shartistatic void 222154133Shartifs_entry_delete(struct fs_entry* entry) 223154133Sharti{ 224154133Sharti struct fs_map_entry *map; 225154133Sharti 226160341Sharti assert(entry != NULL); 227160341Sharti 228154133Sharti TAILQ_REMOVE(&fs_tbl, entry, link); 229154133Sharti STAILQ_FOREACH(map, &fs_map, link) 230154133Sharti if (map->entry == entry) { 231154133Sharti map->entry = NULL; 232154133Sharti break; 233154133Sharti } 234160341Sharti free(entry->mountPoint); 235160341Sharti free(entry->remoteMountPoint); 236154133Sharti free(entry); 237154133Sharti} 238154133Sharti 239154133Sharti/** 240154133Sharti * Find a table entry by its name 241154133Sharti */ 242154133Shartistatic struct fs_entry * 243154133Shartifs_find_by_name(const char *name) 244154133Sharti{ 245154133Sharti struct fs_entry *entry; 246154133Sharti 247154133Sharti TAILQ_FOREACH(entry, &fs_tbl, link) 248160341Sharti if (strcmp(entry->mountPoint, name) == 0) 249154133Sharti return (entry); 250154133Sharti 251154133Sharti return (NULL); 252154133Sharti} 253154133Sharti 254154133Sharti/** 255154133Sharti * Get rid of all data 256154133Sharti */ 257154133Shartivoid 258154133Shartifini_fs_tbl(void) 259154133Sharti{ 260154133Sharti struct fs_map_entry *n1; 261154133Sharti 262154133Sharti while ((n1 = STAILQ_FIRST(&fs_map)) != NULL) { 263154133Sharti STAILQ_REMOVE_HEAD(&fs_map, link); 264154133Sharti if (n1->entry != NULL) { 265154133Sharti TAILQ_REMOVE(&fs_tbl, n1->entry, link); 266160341Sharti free(n1->entry->mountPoint); 267160341Sharti free(n1->entry->remoteMountPoint); 268154133Sharti free(n1->entry); 269154133Sharti } 270160341Sharti free(n1->a_name); 271154133Sharti free(n1); 272154133Sharti } 273154133Sharti assert(TAILQ_EMPTY(&fs_tbl)); 274154133Sharti} 275154133Sharti 276154133Sharti/** 277154133Sharti * Called before the refreshing is started from the storage table. 278154133Sharti */ 279154133Shartivoid 280154133Shartifs_tbl_pre_refresh(void) 281154133Sharti{ 282154133Sharti struct fs_entry *entry; 283154133Sharti 284154133Sharti /* mark each entry as missisng */ 285154133Sharti TAILQ_FOREACH(entry, &fs_tbl, link) 286154133Sharti entry->flags &= ~HR_FS_FOUND; 287154133Sharti} 288154133Sharti 289154133Sharti/** 290154133Sharti * Called after refreshing from the storage table. 291154133Sharti */ 292154133Shartivoid 293154133Shartifs_tbl_post_refresh(void) 294154133Sharti{ 295154133Sharti struct fs_entry *entry, *entry_tmp; 296154133Sharti 297154133Sharti /* 298154133Sharti * Purge items that disappeared 299154133Sharti */ 300154133Sharti TAILQ_FOREACH_SAFE(entry, &fs_tbl, link, entry_tmp) 301154133Sharti if (!(entry->flags & HR_FS_FOUND)) 302154133Sharti fs_entry_delete(entry); 303154133Sharti 304154133Sharti fs_tick = this_tick; 305154133Sharti} 306154133Sharti 307154133Sharti/* 308154133Sharti * Refresh the FS table. This is done by forcing a refresh of the storage table. 309154133Sharti */ 310154133Shartivoid 311154133Shartirefresh_fs_tbl(void) 312154133Sharti{ 313154133Sharti 314154133Sharti if (fs_tick == 0 || this_tick - fs_tick >= fs_tbl_refresh) { 315154133Sharti refresh_storage_tbl(1); 316154133Sharti HRDBG("refresh DONE"); 317154133Sharti } 318154133Sharti} 319154133Sharti 320154133Sharti/** 321154133Sharti * Get the type OID for a given file system 322154133Sharti */ 323154133Sharticonst struct asn_oid * 324154133Shartifs_get_type(const struct statfs *fs_p) 325154133Sharti{ 326154133Sharti u_int t; 327154133Sharti 328154133Sharti assert(fs_p != NULL); 329154133Sharti 330154133Sharti for (t = 0; t < N_FS_TYPE_MAP; t++) 331154133Sharti if (strcmp(fs_type_map[t].str, fs_p->f_fstypename) == 0) 332154133Sharti return (fs_type_map[t].oid); 333154133Sharti 334154133Sharti return (&OIDX_hrFSUnknown_c); 335154133Sharti} 336154133Sharti 337154133Sharti/* 338154133Sharti * Given information returned from statfs(2) either create a new entry into 339154133Sharti * the fs_tbl or refresh the entry if it is already there. 340154133Sharti */ 341154133Shartivoid 342154133Shartifs_tbl_process_statfs_entry(const struct statfs *fs_p, int32_t storage_idx) 343154133Sharti{ 344154133Sharti struct fs_entry *entry; 345154133Sharti 346154133Sharti assert(fs_p != 0); 347154133Sharti 348154133Sharti HRDBG("for hrStorageEntry::index %d", storage_idx); 349154133Sharti 350154133Sharti if (fs_p == NULL) 351154133Sharti return; 352154133Sharti 353154133Sharti if ((entry = fs_find_by_name(fs_p->f_mntonname)) != NULL || 354154133Sharti (entry = fs_entry_create(fs_p->f_mntonname)) != NULL) { 355154133Sharti entry->flags |= HR_FS_FOUND; 356154133Sharti 357160341Sharti if (!(fs_p->f_flags & MNT_LOCAL)) { 358154133Sharti /* this is a remote mount */ 359160341Sharti entry->remoteMountPoint = strdup(fs_p->f_mntfromname); 360160341Sharti /* if strdup failed, let it be NULL */ 361154133Sharti 362160341Sharti } else { 363160341Sharti entry->remoteMountPoint = strdup(""); 364160341Sharti /* if strdup failed, let it be NULL */ 365160341Sharti } 366160341Sharti 367154133Sharti entry->type = fs_get_type(fs_p); 368154133Sharti 369154133Sharti if ((fs_p->f_flags & MNT_RDONLY) == MNT_RDONLY) 370154133Sharti entry->access = FS_READ_ONLY; 371154133Sharti else 372154133Sharti entry->access = FS_READ_WRITE; 373154133Sharti 374154133Sharti /* FIXME - bootable fs ?! */ 375154133Sharti entry->bootable = TRUTH_MK((fs_p->f_flags & MNT_ROOTFS) 376154133Sharti == MNT_ROOTFS); 377154133Sharti 378154133Sharti entry->storageIndex = storage_idx; 379154133Sharti 380154133Sharti /* Info not available */ 381154133Sharti memset(entry->lastFullBackupDate, 0, 382154133Sharti sizeof(entry->lastFullBackupDate)); 383154133Sharti 384154133Sharti /* Info not available */ 385154133Sharti memset(entry->lastPartialBackupDate, 0, 386154133Sharti sizeof(entry->lastPartialBackupDate)); 387154133Sharti 388154133Sharti handle_partition_fs_index(fs_p->f_mntfromname, entry->index); 389154133Sharti } 390154133Sharti} 391154133Sharti 392154133Sharti/* 393154133Sharti * This is the implementation for a generated (by our SNMP "compiler" tool) 394154133Sharti * function prototype, see hostres_tree.h 395154133Sharti * It handles the SNMP operations for hrFSTable 396154133Sharti */ 397154133Shartiint 398154133Shartiop_hrFSTable(struct snmp_context *ctx __unused, struct snmp_value *value, 399154133Sharti u_int sub, u_int iidx __unused, enum snmp_op curr_op) 400154133Sharti{ 401154133Sharti struct fs_entry *entry; 402154133Sharti 403154133Sharti refresh_fs_tbl(); 404154133Sharti 405154133Sharti switch (curr_op) { 406154133Sharti 407154133Sharti case SNMP_OP_GETNEXT: 408154133Sharti if ((entry = NEXT_OBJECT_INT(&fs_tbl, 409154133Sharti &value->var, sub)) == NULL) 410154133Sharti return (SNMP_ERR_NOSUCHNAME); 411154133Sharti value->var.len = sub + 1; 412154133Sharti value->var.subs[sub] = entry->index; 413154133Sharti goto get; 414154133Sharti 415154133Sharti case SNMP_OP_GET: 416154133Sharti if ((entry = FIND_OBJECT_INT(&fs_tbl, 417154133Sharti &value->var, sub)) == NULL) 418154133Sharti return (SNMP_ERR_NOSUCHNAME); 419154133Sharti goto get; 420154133Sharti 421154133Sharti case SNMP_OP_SET: 422154133Sharti if ((entry = FIND_OBJECT_INT(&fs_tbl, 423154133Sharti &value->var, sub)) == NULL) 424154133Sharti return (SNMP_ERR_NO_CREATION); 425154133Sharti return (SNMP_ERR_NOT_WRITEABLE); 426154133Sharti 427154133Sharti case SNMP_OP_ROLLBACK: 428154133Sharti case SNMP_OP_COMMIT: 429154133Sharti abort(); 430154133Sharti } 431154133Sharti abort(); 432154133Sharti get: 433154133Sharti switch (value->var.subs[sub - 1]) { 434154133Sharti 435154133Sharti case LEAF_hrFSIndex: 436154133Sharti value->v.integer = entry->index; 437154133Sharti return (SNMP_ERR_NOERROR); 438154133Sharti 439154133Sharti case LEAF_hrFSMountPoint: 440154133Sharti return (string_get(value, entry->mountPoint, -1)); 441154133Sharti 442154133Sharti case LEAF_hrFSRemoteMountPoint: 443160341Sharti if (entry->remoteMountPoint == NULL) 444160341Sharti return (string_get(value, "", -1)); 445160341Sharti else 446160341Sharti return (string_get(value, entry->remoteMountPoint, -1)); 447154133Sharti break; 448154133Sharti 449154133Sharti case LEAF_hrFSType: 450160341Sharti assert(entry->type != NULL); 451160341Sharti value->v.oid = *(entry->type); 452154133Sharti return (SNMP_ERR_NOERROR); 453154133Sharti 454154133Sharti case LEAF_hrFSAccess: 455154133Sharti value->v.integer = entry->access; 456154133Sharti return (SNMP_ERR_NOERROR); 457154133Sharti 458154133Sharti case LEAF_hrFSBootable: 459154133Sharti value->v.integer = entry->bootable; 460154133Sharti return (SNMP_ERR_NOERROR); 461154133Sharti 462154133Sharti case LEAF_hrFSStorageIndex: 463154133Sharti value->v.integer = entry->storageIndex; 464154133Sharti return (SNMP_ERR_NOERROR); 465154133Sharti 466154133Sharti case LEAF_hrFSLastFullBackupDate: 467154133Sharti return (string_get(value, entry->lastFullBackupDate, 8)); 468154133Sharti 469154133Sharti case LEAF_hrFSLastPartialBackupDate: 470154133Sharti return (string_get(value, entry->lastPartialBackupDate, 8)); 471154133Sharti } 472154133Sharti abort(); 473154133Sharti} 474