/* * Host Resources MIB - File System device group implementation (HAL rewrite) - hrh_filesys.c * */ /* Portions of this file are subject to the following copyright(s). See * the Net-SNMP's COPYING file for more details and other copyrights * that may apply: */ /* * Portions of this file are copyrighted by: * Copyright (C) 2007 Apple, Inc. All rights reserved. * Use is subject to license terms specified in the COPYING file * distributed with the Net-SNMP package. */ #include #include #include #include #include #include #include "host_res.h" #include "hrh_filesys.h" #include "hrh_storage.h" #include "hr_disk.h" #include "hr_filesys.h" #include #if HAVE_MNTENT_H #include #endif #if HAVE_SYS_MNTENT_H #include #endif #if HAVE_SYS_MNTTAB_H #include #endif #if HAVE_SYS_STATVFS_H #include #endif #if HAVE_SYS_VFS_H #include #endif #ifdef HAVE_SYS_PARAM_H #include #endif #ifdef HAVE_SYS_MOUNT_H #include #endif #include #if HAVE_STRING_H #include #endif #if HAVE_STDLIB_H #include #endif #if defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7) #include #include #include #endif netsnmp_feature_require(date_n_time) netsnmp_feature_require(ctime_to_timet) #define HRFS_MONOTONICALLY_INCREASING /********************* * * Kernel & interface information, * and internal forward declarations * *********************/ netsnmp_fsys_info *HRFS_entry; #define FULL_DUMP 0 #define PART_DUMP 1 static u_char *when_dumped(char *filesys, int level, size_t * length); int header_hrhfilesys(struct variable *, oid *, size_t *, int, size_t *, WriteMethod **); /********************* * * Initialisation & common implementation functions * *********************/ #define HRFSYS_INDEX 1 #define HRFSYS_MOUNT 2 #define HRFSYS_RMOUNT 3 #define HRFSYS_TYPE 4 #define HRFSYS_ACCESS 5 #define HRFSYS_BOOT 6 #define HRFSYS_STOREIDX 7 #define HRFSYS_FULLDUMP 8 #define HRFSYS_PARTDUMP 9 struct variable4 hrfsys_variables[] = { {HRFSYS_INDEX, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, var_hrhfilesys, 2, {1, 1}}, {HRFSYS_MOUNT, ASN_OCTET_STR, NETSNMP_OLDAPI_RONLY, var_hrhfilesys, 2, {1, 2}}, {HRFSYS_RMOUNT, ASN_OCTET_STR, NETSNMP_OLDAPI_RONLY, var_hrhfilesys, 2, {1, 3}}, {HRFSYS_TYPE, ASN_OBJECT_ID, NETSNMP_OLDAPI_RONLY, var_hrhfilesys, 2, {1, 4}}, {HRFSYS_ACCESS, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, var_hrhfilesys, 2, {1, 5}}, {HRFSYS_BOOT, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, var_hrhfilesys, 2, {1, 6}}, {HRFSYS_STOREIDX, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, var_hrhfilesys, 2, {1, 7}}, {HRFSYS_FULLDUMP, ASN_OCTET_STR, NETSNMP_OLDAPI_RONLY, var_hrhfilesys, 2, {1, 8}}, {HRFSYS_PARTDUMP, ASN_OCTET_STR, NETSNMP_OLDAPI_RONLY, var_hrhfilesys, 2, {1, 9}}, }; oid hrfsys_variables_oid[] = { 1, 3, 6, 1, 2, 1, 25, 3, 8 }; void init_hrh_filesys(void) { REGISTER_MIB("host/hr_filesys", hrfsys_variables, variable4, hrfsys_variables_oid); } /* * header_hrhfilesys(... * Arguments: * vp IN - pointer to variable entry that points here * name IN/OUT - IN/name requested, OUT/name found * length IN/OUT - length of IN/OUT oid's * exact IN - TRUE if an exact match was requested * var_len OUT - length of variable or 0 if function returned * write_method * */ int header_hrhfilesys(struct variable *vp, oid * name, size_t * length, int exact, size_t * var_len, WriteMethod ** write_method) { #define HRFSYS_ENTRY_NAME_LENGTH 11 oid newname[MAX_OID_LEN]; int fsys_idx, LowIndex = -1; int result; DEBUGMSGTL(("host/hr_filesys", "var_hrhfilesys: ")); DEBUGMSGOID(("host/hr_filesys", name, *length)); DEBUGMSG(("host/hr_filesys", " %d\n", exact)); memcpy((char *) newname, (char *) vp->name, vp->namelen * sizeof(oid)); /* * Find "next" file system entry */ Init_HR_FileSys(); for (;;) { fsys_idx = Get_Next_HR_FileSys(); if (fsys_idx == -1) break; newname[HRFSYS_ENTRY_NAME_LENGTH] = fsys_idx; result = snmp_oid_compare(name, *length, newname, vp->namelen + 1); if (exact && (result == 0)) { LowIndex = fsys_idx; break; } if ((!exact && (result < 0)) && (LowIndex == -1 || fsys_idx < LowIndex)) { LowIndex = fsys_idx; #ifdef HRFS_MONOTONICALLY_INCREASING break; #endif } } if (LowIndex == -1) { DEBUGMSGTL(("host/hr_filesys", "... index out of range\n")); return (MATCH_FAILED); } memcpy((char *) name, (char *) newname, (vp->namelen + 1) * sizeof(oid)); *length = vp->namelen + 1; *write_method = NULL; *var_len = sizeof(long); /* default to 'long' results */ DEBUGMSGTL(("host/hr_filesys", "... get filesys stats ")); DEBUGMSGOID(("host/hr_filesys", name, *length)); DEBUGMSG(("host/hr_filesys", "\n")); return LowIndex; } oid fsys_type_id[] = { 1, 3, 6, 1, 2, 1, 25, 3, 9, 1 }; /* hrFSOther */ int fsys_type_len = sizeof(fsys_type_id) / sizeof(fsys_type_id[0]); /********************* * * System specific implementation functions * *********************/ u_char * var_hrhfilesys(struct variable *vp, oid * name, size_t * length, int exact, size_t * var_len, WriteMethod ** write_method) { int fsys_idx; static char *string; fsys_idx = header_hrhfilesys(vp, name, length, exact, var_len, write_method); if (fsys_idx == MATCH_FAILED) return NULL; switch (vp->magic) { case HRFSYS_INDEX: long_return = fsys_idx; return (u_char *) & long_return; case HRFSYS_MOUNT: free(string); string = NULL; *var_len = 0; if (asprintf(&string, "%s", HRFS_entry->path) >= 0) *var_len = strlen(string); return (u_char *) string; case HRFSYS_RMOUNT: free(string); if (HRFS_entry->flags & NETSNMP_FS_FLAG_REMOTE) { if (asprintf(&string, "%s", HRFS_entry->device) < 0) string = NULL; } else { string = strdup(""); } *var_len = string ? strlen(string) : 0; return (u_char *) string; case HRFSYS_TYPE: fsys_type_id[fsys_type_len - 1] = (HRFS_entry->type > _NETSNMP_FS_TYPE_LOCAL ? NETSNMP_FS_TYPE_OTHER : HRFS_entry->type); *var_len = sizeof(fsys_type_id); return (u_char *) fsys_type_id; case HRFSYS_ACCESS: long_return = HRFS_entry->flags & NETSNMP_FS_FLAG_RONLY ? 2 : 1; return (u_char *) & long_return; case HRFSYS_BOOT: long_return = HRFS_entry->flags & NETSNMP_FS_FLAG_BOOTABLE ? 1 : 2; return (u_char *) & long_return; case HRFSYS_STOREIDX: long_return = fsys_idx + NETSNMP_MEM_TYPE_MAX; return (u_char *) & long_return; case HRFSYS_FULLDUMP: return when_dumped(HRFS_entry->path, FULL_DUMP, var_len); case HRFSYS_PARTDUMP: return when_dumped(HRFS_entry->path, PART_DUMP, var_len); default: DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_hrhfilesys\n", vp->magic)); } return NULL; } /********************* * * Internal implementation functions * *********************/ static int HRFS_index; void Init_HR_FileSys(void) { netsnmp_cache *c = netsnmp_fsys_get_cache(); netsnmp_cache_check_and_reload( c ); HRFS_entry = NULL; HRFS_index = 0; } int Get_Next_HR_FileSys(void) { if ( HRFS_entry ) { HRFS_entry = netsnmp_fsys_get_next( HRFS_entry ); } else { HRFS_entry = netsnmp_fsys_get_first(); } /* Skip "inactive" entries */ while ( HRFS_entry && !(HRFS_entry->flags & NETSNMP_FS_FLAG_ACTIVE)) HRFS_entry = netsnmp_fsys_get_next( HRFS_entry ); HRFS_index = (HRFS_entry ? HRFS_entry->idx.oids[0] : -1 ); return HRFS_index; } static u_char * when_dumped(char *filesys, int level, size_t * length) { time_t dumpdate = 0, tmp; FILE *dump_fp; char line[1024]; char *cp1, *cp2, *cp3; /* * Look for the relevent entries in /etc/dumpdates * * This is complicated by the fact that disks are * mounted using block devices, but dumps are * done via the raw character devices. * Thus the device names in /etc/dumpdates and * /etc/mnttab don't match. * These comparisons are therefore made using the * final portion of the device name only. */ if (*filesys == '\0') /* No filesystem name? */ return date_n_time(NULL, length); cp1 = strrchr(filesys, '/'); /* Find the last element of the current FS */ if (cp1 == NULL) cp1 = filesys; if ((dump_fp = fopen("/etc/dumpdates", "r")) == NULL) return date_n_time(NULL, length); while (fgets(line, sizeof(line), dump_fp) != NULL) { cp2 = strchr(line, ' '); /* Start by looking at the device name only */ if (cp2 != NULL) { *cp2 = '\0'; cp3 = strrchr(line, '/'); /* and find the last element */ if (cp3 == NULL) cp3 = line; if (strcmp(cp1, cp3) != 0) /* Wrong FS */ continue; ++cp2; while (isspace(0xFF & *cp2)) ++cp2; /* Now find the dump level */ if (level == FULL_DUMP) { if (*(cp2++) != '0') continue; /* Not interested in partial dumps */ while (isspace(0xFF & *cp2)) ++cp2; dumpdate = ctime_to_timet(cp2); fclose(dump_fp); return date_n_time(&dumpdate, length); } else { /* Partial Dump */ if (*(cp2++) == '0') continue; /* Not interested in full dumps */ while (isspace(0xFF & *cp2)) ++cp2; tmp = ctime_to_timet(cp2); if (tmp > dumpdate) dumpdate = tmp; /* Remember the 'latest' partial dump */ } } } fclose(dump_fp); return date_n_time(&dumpdate, length); } #define RAW_DEVICE_PREFIX "/dev/rdsk" #define COOKED_DEVICE_PREFIX "/dev/dsk" char * cook_device(char *dev) { static char cooked_dev[SNMP_MAXPATH+1]; if (!strncmp(dev, RAW_DEVICE_PREFIX, strlen(RAW_DEVICE_PREFIX))) { strlcpy(cooked_dev, COOKED_DEVICE_PREFIX, sizeof(cooked_dev)); strlcat(cooked_dev, dev + strlen(RAW_DEVICE_PREFIX), sizeof(cooked_dev)); } else { strlcpy(cooked_dev, dev, sizeof(cooked_dev)); } return cooked_dev; } int Get_FSIndex(char *dev) { netsnmp_fsys_info *fsys; fsys = netsnmp_fsys_by_device( dev, NETSNMP_FS_FIND_EXIST ); return (fsys ? fsys->idx.oids[0] : -1 ); } long Get_FSSize(char *dev) { netsnmp_fsys_info *fsys; fsys = netsnmp_fsys_by_device( dev, NETSNMP_FS_FIND_EXIST ); if ( fsys ) return netsnmp_fsys_size( fsys ); else return -1; } int Check_HR_FileSys_NFS (void) { return (HRFS_entry->flags & NETSNMP_FS_FLAG_REMOTE) ? 1 : 0; } int Check_HR_FileSys_AutoFs (void) { return (HRFS_entry->type == (NETSNMP_FS_TYPE_AUTOFS)) ? 1 : 0; }