hostres_fs_tbl.c revision 154137
1/*- 2 * Copyright (c) 2005-2006 The FreeBSD Project 3 * All rights reserved. 4 * 5 * Author: Victor Cruceru <soc-victor@freebsd.org> 6 * 7 * Redistribution of this software and documentation and use in source and 8 * binary forms, with or without modification, are permitted provided that 9 * the following conditions are met: 10 * 11 * 1. Redistributions of source code or documentation must retain the above 12 * copyright notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * $FreeBSD: head/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_fs_tbl.c 154133 2006-01-09 12:33:45Z harti $ 30 */ 31 32/* 33 * Host Resources MIB for SNMPd. Implementation for hrFSTable 34 */ 35 36#include <sys/types.h> 37#include <sys/param.h> 38#include <sys/sysctl.h> 39#include <sys/mount.h> 40 41#include <assert.h> 42#include <err.h> 43#include <stdlib.h> 44#include <string.h> 45#include <syslog.h> 46 47#include "hostres_snmp.h" 48#include "hostres_oid.h" 49#include "hostres_tree.h" 50 51/* 52 * File system access enum 53 */ 54enum hrFSAccess { 55 FS_READ_WRITE = 1, 56 FS_READ_ONLY = 2 57}; 58 59/* 60 * This structure is used to hold a SNMP table entry 61 * for HOST-RESOURCES-MIB's hrFSTable 62 */ 63struct fs_entry { 64 int32_t index; 65 u_char mountPoint[128 + 1]; 66 u_char remoteMountPoint[128 + 1]; 67 const struct asn_oid *type; 68 int32_t access; /* enum hrFSAccess, see above */ 69 int32_t bootable; /* TruthValue */ 70 int32_t storageIndex; /* hrStorageTblEntry::index */ 71 u_char lastFullBackupDate[11]; 72 u_char lastPartialBackupDate[11]; 73#define HR_FS_FOUND 0x001 74 uint32_t flags; /* not in mib table, for internal use */ 75 TAILQ_ENTRY(fs_entry) link; 76}; 77TAILQ_HEAD(fs_tbl, fs_entry); 78 79/* 80 * Next structure is used to keep o list of mappings from a specific name 81 * (a_name) to an entry in the hrFSTblEntry. We are trying to keep the same 82 * index for a specific name at least for the duration of one SNMP agent run. 83 */ 84struct fs_map_entry { 85 int32_t hrIndex; /* used for hrFSTblEntry::index */ 86 u_char a_name[128 + 1];/* map key */ 87 88 /* may be NULL if the respective hrFSTblEntry is (temporally) gone */ 89 struct fs_entry *entry; 90 STAILQ_ENTRY(fs_map_entry) link; 91}; 92STAILQ_HEAD(fs_map, fs_map_entry); 93 94/* head of the list with hrFSTable's entries */ 95static struct fs_tbl fs_tbl = TAILQ_HEAD_INITIALIZER(fs_tbl); 96 97/* for consistent table indexing */ 98static struct fs_map fs_map = STAILQ_HEAD_INITIALIZER(fs_map); 99 100/* next index available for hrFSTable */ 101static uint32_t next_fs_index = 1; 102 103/* last tick when hrFSTable was updated */ 104static uint64_t fs_tick; 105 106/* maximum number of ticks between refreshs */ 107uint32_t fs_tbl_refresh = HR_FS_TBL_REFRESH * 100; 108 109/* some constants */ 110static const struct asn_oid OIDX_hrFSBerkeleyFFS_c = OIDX_hrFSBerkeleyFFS; 111static const struct asn_oid OIDX_hrFSiso9660_c = OIDX_hrFSiso9660; 112static const struct asn_oid OIDX_hrFSNFS_c = OIDX_hrFSNFS; 113static const struct asn_oid OIDX_hrFSLinuxExt2_c = OIDX_hrFSLinuxExt2; 114static const struct asn_oid OIDX_hrFSOther_c = OIDX_hrFSOther; 115static const struct asn_oid OIDX_hrFSFAT32_c = OIDX_hrFSFAT32; 116static const struct asn_oid OIDX_hrFSNTFS_c = OIDX_hrFSNTFS; 117static const struct asn_oid OIDX_hrFSNetware_c = OIDX_hrFSNetware; 118static const struct asn_oid OIDX_hrFSHPFS_c = OIDX_hrFSHPFS; 119static const struct asn_oid OIDX_hrFSUnknown_c = OIDX_hrFSUnknown; 120 121/* file system type map */ 122static const struct { 123 const char *str; /* the type string */ 124 const struct asn_oid *oid; /* the OID to return */ 125} fs_type_map[] = { 126 { "ufs", &OIDX_hrFSBerkeleyFFS_c }, 127 { "cd9660", &OIDX_hrFSiso9660_c }, 128 { "nfs", &OIDX_hrFSNFS_c }, 129 { "ext2fs", &OIDX_hrFSLinuxExt2_c }, 130 { "procfs", &OIDX_hrFSOther_c }, 131 { "devfs", &OIDX_hrFSOther_c }, 132 { "msdosfs", &OIDX_hrFSFAT32_c }, 133 { "ntfs", &OIDX_hrFSNTFS_c }, 134 { "nwfs", &OIDX_hrFSNetware_c }, 135 { "hpfs", &OIDX_hrFSHPFS_c }, 136 { "smbfs", &OIDX_hrFSOther_c }, 137}; 138#define N_FS_TYPE_MAP (sizeof(fs_type_map) / sizeof(fs_type_map[0])) 139 140/** 141 * Create an entry into the FS table and an entry in the map (if needed). 142 */ 143static struct fs_entry * 144fs_entry_create(const char *name) 145{ 146 struct fs_entry *entry; 147 struct fs_map_entry *map; 148 149 if ((entry = malloc(sizeof(*entry))) == NULL) { 150 syslog(LOG_WARNING, "%s: %m", __func__); 151 return (NULL); 152 } 153 154 strlcpy(entry->mountPoint, name, sizeof(entry->mountPoint)); 155 156 STAILQ_FOREACH(map, &fs_map, link) 157 if (strncmp(map->a_name, entry->mountPoint, 158 sizeof(map->a_name) - 1) == 0) { 159 entry->index = map->hrIndex; 160 map->entry = entry; 161 break; 162 } 163 164 if (map == NULL) { 165 /* new object - get a new index */ 166 if (next_fs_index > INT_MAX) { 167 /* XXX no other sensible reaction? */ 168 syslog(LOG_ERR, "%s: hrFSTable index wrap", __func__); 169 return (NULL); 170 } 171 172 if ((map = malloc(sizeof(*map))) == NULL) { 173 syslog(LOG_ERR, "%s: %m", __func__); 174 free(entry); 175 return (NULL); 176 } 177 178 map->hrIndex = next_fs_index++; 179 strlcpy(map->a_name, entry->mountPoint, sizeof(map->a_name)); 180 map->entry = entry; 181 182 STAILQ_INSERT_TAIL(&fs_map, map, link); 183 184 HRDBG("%s added into hrFSMap at index=%d", name, map->hrIndex); 185 } else { 186 HRDBG("%s exists in hrFSMap index=%d", name, map->hrIndex); 187 } 188 189 entry->index = map->hrIndex; 190 191 INSERT_OBJECT_INT(entry, &fs_tbl); 192 193 return (entry); 194} 195 196/** 197 * Delete an entry in the FS table. 198 */ 199static void 200fs_entry_delete(struct fs_entry* entry) 201{ 202 struct fs_map_entry *map; 203 204 TAILQ_REMOVE(&fs_tbl, entry, link); 205 STAILQ_FOREACH(map, &fs_map, link) 206 if (map->entry == entry) { 207 map->entry = NULL; 208 break; 209 } 210 211 free(entry); 212} 213 214/** 215 * Find a table entry by its name 216 */ 217static struct fs_entry * 218fs_find_by_name(const char *name) 219{ 220 struct fs_entry *entry; 221 222 TAILQ_FOREACH(entry, &fs_tbl, link) 223 if (strncmp(entry->mountPoint, name, 224 sizeof(entry->mountPoint) - 1) == 0) 225 return (entry); 226 227 return (NULL); 228} 229 230/** 231 * Get rid of all data 232 */ 233void 234fini_fs_tbl(void) 235{ 236 struct fs_map_entry *n1; 237 238 while ((n1 = STAILQ_FIRST(&fs_map)) != NULL) { 239 STAILQ_REMOVE_HEAD(&fs_map, link); 240 if (n1->entry != NULL) { 241 TAILQ_REMOVE(&fs_tbl, n1->entry, link); 242 free(n1->entry); 243 } 244 free(n1); 245 } 246 assert(TAILQ_EMPTY(&fs_tbl)); 247} 248 249/** 250 * Called before the refreshing is started from the storage table. 251 */ 252void 253fs_tbl_pre_refresh(void) 254{ 255 struct fs_entry *entry; 256 257 /* mark each entry as missisng */ 258 TAILQ_FOREACH(entry, &fs_tbl, link) 259 entry->flags &= ~HR_FS_FOUND; 260} 261 262/** 263 * Called after refreshing from the storage table. 264 */ 265void 266fs_tbl_post_refresh(void) 267{ 268 struct fs_entry *entry, *entry_tmp; 269 270 /* 271 * Purge items that disappeared 272 */ 273 TAILQ_FOREACH_SAFE(entry, &fs_tbl, link, entry_tmp) 274 if (!(entry->flags & HR_FS_FOUND)) 275 fs_entry_delete(entry); 276 277 fs_tick = this_tick; 278} 279 280/* 281 * Refresh the FS table. This is done by forcing a refresh of the storage table. 282 */ 283void 284refresh_fs_tbl(void) 285{ 286 287 if (fs_tick == 0 || this_tick - fs_tick >= fs_tbl_refresh) { 288 refresh_storage_tbl(1); 289 HRDBG("refresh DONE"); 290 } 291} 292 293/** 294 * Get the type OID for a given file system 295 */ 296const struct asn_oid * 297fs_get_type(const struct statfs *fs_p) 298{ 299 u_int t; 300 301 assert(fs_p != NULL); 302 303 for (t = 0; t < N_FS_TYPE_MAP; t++) 304 if (strcmp(fs_type_map[t].str, fs_p->f_fstypename) == 0) 305 return (fs_type_map[t].oid); 306 307 return (&OIDX_hrFSUnknown_c); 308} 309 310/* 311 * Given information returned from statfs(2) either create a new entry into 312 * the fs_tbl or refresh the entry if it is already there. 313 */ 314void 315fs_tbl_process_statfs_entry(const struct statfs *fs_p, int32_t storage_idx) 316{ 317 struct fs_entry *entry; 318 319 assert(fs_p != 0); 320 321 HRDBG("for hrStorageEntry::index %d", storage_idx); 322 323 if (fs_p == NULL) 324 return; 325 326 if ((entry = fs_find_by_name(fs_p->f_mntonname)) != NULL || 327 (entry = fs_entry_create(fs_p->f_mntonname)) != NULL) { 328 entry->flags |= HR_FS_FOUND; 329 330 strcpy(entry->mountPoint, fs_p->f_mntonname); 331 332 if (!(fs_p->f_flags & MNT_LOCAL)) 333 /* this is a remote mount */ 334 strcpy(entry->remoteMountPoint, fs_p->f_mntfromname); 335 else 336 entry->remoteMountPoint[0] = '\0'; 337 338 entry->type = fs_get_type(fs_p); 339 340 if ((fs_p->f_flags & MNT_RDONLY) == MNT_RDONLY) 341 entry->access = FS_READ_ONLY; 342 else 343 entry->access = FS_READ_WRITE; 344 345 /* FIXME - bootable fs ?! */ 346 entry->bootable = TRUTH_MK((fs_p->f_flags & MNT_ROOTFS) 347 == MNT_ROOTFS); 348 349 entry->storageIndex = storage_idx; 350 351 /* Info not available */ 352 memset(entry->lastFullBackupDate, 0, 353 sizeof(entry->lastFullBackupDate)); 354 355 /* Info not available */ 356 memset(entry->lastPartialBackupDate, 0, 357 sizeof(entry->lastPartialBackupDate)); 358 359 handle_partition_fs_index(fs_p->f_mntfromname, entry->index); 360 } 361} 362 363/* 364 * This is the implementation for a generated (by our SNMP "compiler" tool) 365 * function prototype, see hostres_tree.h 366 * It handles the SNMP operations for hrFSTable 367 */ 368int 369op_hrFSTable(struct snmp_context *ctx __unused, struct snmp_value *value, 370 u_int sub, u_int iidx __unused, enum snmp_op curr_op) 371{ 372 struct fs_entry *entry; 373 374 refresh_fs_tbl(); 375 376 switch (curr_op) { 377 378 case SNMP_OP_GETNEXT: 379 if ((entry = NEXT_OBJECT_INT(&fs_tbl, 380 &value->var, sub)) == NULL) 381 return (SNMP_ERR_NOSUCHNAME); 382 value->var.len = sub + 1; 383 value->var.subs[sub] = entry->index; 384 goto get; 385 386 case SNMP_OP_GET: 387 if ((entry = FIND_OBJECT_INT(&fs_tbl, 388 &value->var, sub)) == NULL) 389 return (SNMP_ERR_NOSUCHNAME); 390 goto get; 391 392 case SNMP_OP_SET: 393 if ((entry = FIND_OBJECT_INT(&fs_tbl, 394 &value->var, sub)) == NULL) 395 return (SNMP_ERR_NO_CREATION); 396 return (SNMP_ERR_NOT_WRITEABLE); 397 398 case SNMP_OP_ROLLBACK: 399 case SNMP_OP_COMMIT: 400 abort(); 401 } 402 abort(); 403 get: 404 switch (value->var.subs[sub - 1]) { 405 406 case LEAF_hrFSIndex: 407 value->v.integer = entry->index; 408 return (SNMP_ERR_NOERROR); 409 410 case LEAF_hrFSMountPoint: 411 return (string_get(value, entry->mountPoint, -1)); 412 413 case LEAF_hrFSRemoteMountPoint: 414 return (string_get(value, entry->remoteMountPoint, -1)); 415 break; 416 417 case LEAF_hrFSType: 418 value->v.oid = *entry->type; 419 return (SNMP_ERR_NOERROR); 420 421 case LEAF_hrFSAccess: 422 value->v.integer = entry->access; 423 return (SNMP_ERR_NOERROR); 424 425 case LEAF_hrFSBootable: 426 value->v.integer = entry->bootable; 427 return (SNMP_ERR_NOERROR); 428 429 case LEAF_hrFSStorageIndex: 430 value->v.integer = entry->storageIndex; 431 return (SNMP_ERR_NOERROR); 432 433 case LEAF_hrFSLastFullBackupDate: 434 return (string_get(value, entry->lastFullBackupDate, 8)); 435 436 case LEAF_hrFSLastPartialBackupDate: 437 return (string_get(value, entry->lastPartialBackupDate, 8)); 438 } 439 abort(); 440} 441