/* * Host Resources MIB - disk device group implementation - hr_disk.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 "host_res.h" #include "hr_disk.h" #if HAVE_STRING_H #include #else #include #endif #include #if HAVE_UNISTD_H #include #endif #if HAVE_KVM_H #include #endif #if HAVE_DIRENT_H #include #else # define dirent direct # if HAVE_SYS_NDIR_H # include # endif # if HAVE_SYS_DIR_H # include # endif # if HAVE_NDIR_H # include # endif #endif #if HAVE_SYS_IOCTL_H #include #endif #if HAVE_SYS_DKIO_H #include #endif #if HAVE_SYS_DISKIO_H /* HP-UX only ? */ #include #endif #if HAVE_LINUX_HDREG_H #include #endif #if HAVE_SYS_DISKLABEL_H #define DKTYPENAMES #include #ifndef dragonfly #include #endif #endif #if TIME_WITH_SYS_TIME # include # include #else # if HAVE_SYS_TIME_H # include # else # include # endif #endif #if defined(HAVE_REGEX_H) && defined(HAVE_REGCOMP) #include #endif #if HAVE_LIMITS_H #include #endif #ifdef HAVE_UNISTD_H #include #endif #ifdef darwin #include #include #include #include #include #include #endif #ifdef linux /* * define BLKGETSIZE from : * Note: cannot include this file completely due to errors with redefinition * of structures (at least with older linux versions) --jsf */ #define BLKGETSIZE _IO(0x12,96) /* return device size */ #endif #include #include #define HRD_MONOTONICALLY_INCREASING /************************************************************* * constants for enums for the MIB node * hrDiskStorageAccess (INTEGER / ASN_INTEGER) */ #define HRDISKSTORAGEACCESS_READWRITE 1 #define HRDISKSTORAGEACCESS_READONLY 2 /************************************************************* * constants for enums for the MIB node * hrDiskStorageMedia (INTEGER / ASN_INTEGER) */ #define HRDISKSTORAGEMEDIA_OTHER 1 #define HRDISKSTORAGEMEDIA_UNKNOWN 2 #define HRDISKSTORAGEMEDIA_HARDDISK 3 #define HRDISKSTORAGEMEDIA_FLOPPYDISK 4 #define HRDISKSTORAGEMEDIA_OPTICALDISKROM 5 #define HRDISKSTORAGEMEDIA_OPTICALDISKWORM 6 #define HRDISKSTORAGEMEDIA_OPTICALDISKRW 7 #define HRDISKSTORAGEMEDIA_RAMDISK 8 /********************* * * Kernel & interface information, * and internal forward declarations * *********************/ #if !(defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7)) static void Add_HR_Disk_entry(const char *, int, int, int, int, const char *, int, int); #endif static void Save_HR_Disk_General(void); static void Save_HR_Disk_Specific(void); static int Query_Disk(int, const char *); static int Is_It_Writeable(void); static int What_Type_Disk(void); static int Is_It_Removeable(void); static const char *describe_disk(int); int header_hrdisk(struct variable *, oid *, size_t *, int, size_t *, WriteMethod **); static int HRD_type_index; static int HRD_index; static char HRD_savedModel[40]; static long HRD_savedCapacity = 1044; #if defined(DIOC_DESCRIBE) || defined(DKIOCINFO) || defined(HAVE_LINUX_HDREG_H) static int HRD_savedFlags; #endif static time_t HRD_history[HRDEV_TYPE_MASK + 1]; #ifdef DIOC_DESCRIBE static disk_describe_type HRD_info; static capacity_type HRD_cap; static int HRD_savedIntf_type; static int HRD_savedDev_type; #endif #ifdef DKIOCINFO static struct dk_cinfo HRD_info; static struct dk_geom HRD_cap; static int HRD_savedCtrl_type; #endif #ifdef HAVE_LINUX_HDREG_H static struct hd_driveid HRD_info; #endif #if defined(DIOCGDINFO) || defined(DIOCGMEDIASIZE) static struct disklabel HRD_info; #endif #ifdef darwin static int64_t HRD_cap; static int HRD_access; static int HRD_type; static int HRD_removeble; static char HRD_model[40]; static int HRD_saved_access; static int HRD_saved_type; static int HRD_saved_removeble; static int _get_type_from_protocol( const char *prot ); static int _get_type_value( const char *str_type ); #endif static void parse_disk_config(const char *, char *); static void free_disk_config(void); #ifdef linux static void Add_LVM_Disks(void); static void Remove_LVM_Disks(void); #endif /********************* * * Initialisation & common implementation functions * *********************/ #define HRDISK_ACCESS 1 #define HRDISK_MEDIA 2 #define HRDISK_REMOVEABLE 3 #define HRDISK_CAPACITY 4 struct variable4 hrdisk_variables[] = { {HRDISK_ACCESS, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, var_hrdisk, 2, {1, 1}}, {HRDISK_MEDIA, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, var_hrdisk, 2, {1, 2}}, {HRDISK_REMOVEABLE, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, var_hrdisk, 2, {1, 3}}, {HRDISK_CAPACITY, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, var_hrdisk, 2, {1, 4}} }; oid hrdisk_variables_oid[] = { 1, 3, 6, 1, 2, 1, 25, 3, 6 }; void init_hr_disk(void) { int i; init_device[HRDEV_DISK] = Init_HR_Disk; next_device[HRDEV_DISK] = Get_Next_HR_Disk; save_device[HRDEV_DISK] = Save_HR_Disk_General; #ifdef HRD_MONOTONICALLY_INCREASING dev_idx_inc[HRDEV_DISK] = 1; #endif #if defined(linux) Add_HR_Disk_entry("/dev/hd%c%d", -1, -1, 'a', 'l', "/dev/hd%c", 1, 15); Add_HR_Disk_entry("/dev/sd%c%d", -1, -1, 'a', 'p', "/dev/sd%c", 1, 15); Add_HR_Disk_entry("/dev/md%d", -1, -1, 0, 3, "/dev/md%d", 0, 0); Add_HR_Disk_entry("/dev/fd%d", -1, -1, 0, 1, "/dev/fd%d", 0, 0); Add_LVM_Disks(); #elif defined(hpux) #if defined(hpux10) || defined(hpux11) Add_HR_Disk_entry("/dev/rdsk/c%dt%xd%d", 0, 1, 0, 15, "/dev/rdsk/c%dt%xd0", 0, 4); #else /* hpux9 */ Add_HR_Disk_entry("/dev/rdsk/c%dd%xs%d", 201, 201, 0, 15, "/dev/rdsk/c%dd%xs0", 0, 4); #endif #elif defined(solaris2) Add_HR_Disk_entry("/dev/rdsk/c%dt%dd0s%d", 0, 7, 0, 15, "/dev/rdsk/c%dt%dd0s0", 0, 7); Add_HR_Disk_entry("/dev/rdsk/c%dd%ds%d", 0, 7, 0, 15, "/dev/rdsk/c%dd%ds0", 0, 7); #elif defined(darwin) Add_HR_Disk_entry("/dev/disk%ds%d", -1, -1, 0, 32, "/dev/disk%d", 1, 32); #elif defined(freebsd4) || defined(freebsd5) Add_HR_Disk_entry("/dev/ad%ds%d%c", 0, 1, 1, 4, "/dev/ad%ds%d", 'a', 'h'); Add_HR_Disk_entry("/dev/da%ds%d%c", 0, 1, 1, 4, "/dev/da%ds%d", 'a', 'h'); #elif defined(freebsd3) Add_HR_Disk_entry("/dev/wd%ds%d%c", 0, 1, 1, 4, "/dev/wd%ds%d", 'a', 'h'); Add_HR_Disk_entry("/dev/sd%ds%d%c", 0, 1, 1, 4, "/dev/sd%ds%d", 'a', 'h'); #elif defined(freebsd2) Add_HR_Disk_entry("/dev/wd%d%c", -1, -1, 0, 3, "/dev/wd%d", 'a', 'h'); Add_HR_Disk_entry("/dev/sd%d%c", -1, -1, 0, 3, "/dev/sd%d", 'a', 'h'); #elif defined(netbsd6) Add_HR_Disk_entry("/dev/wd%d%c", -1, -1, 0, 3, "/dev/rwd%da", 'a', 'h'); Add_HR_Disk_entry("/dev/sd%d%c", -1, -1, 0, 3, "/dev/rsd%da", 'a', 'h'); #elif defined(netbsd1) Add_HR_Disk_entry("/dev/wd%d%c", -1, -1, 0, 3, "/dev/wd%dc", 'a', 'h'); Add_HR_Disk_entry("/dev/sd%d%c", -1, -1, 0, 3, "/dev/sd%dc", 'a', 'h'); #endif device_descr[HRDEV_DISK] = describe_disk; HRD_savedModel[0] = '\0'; HRD_savedCapacity = 0; for (i = 0; i < HRDEV_TYPE_MASK; ++i) HRD_history[i] = -1; REGISTER_MIB("host/hr_disk", hrdisk_variables, variable4, hrdisk_variables_oid); snmpd_register_config_handler("ignoredisk", parse_disk_config, free_disk_config, "name"); } void shutdown_hr_disk(void) { #ifdef linux Remove_LVM_Disks(); #endif } #define ITEM_STRING 1 #define ITEM_SET 2 #define ITEM_STAR 3 #define ITEM_ANY 4 typedef unsigned char details_set[32]; typedef struct _conf_disk_item { int item_type; /* ITEM_STRING, ITEM_SET, ITEM_STAR, ITEM_ANY */ void *item_details; /* content depends upon item_type */ struct _conf_disk_item *item_next; } conf_disk_item; typedef struct _conf_disk_list { conf_disk_item *list_item; struct _conf_disk_list *list_next; } conf_disk_list; static conf_disk_list *conf_list = NULL; static int match_disk_config(const char *); static int match_disk_config_item(const char *, conf_disk_item *); static void parse_disk_config(const char *token, char *cptr) { conf_disk_list *d_new = NULL; conf_disk_item *di_curr = NULL; details_set *d_set = NULL; char *name = NULL, *p = NULL, *d_str = NULL, c; unsigned int i, neg, c1, c2; char *st = NULL; name = strtok_r(cptr, " \t", &st); if (!name) { config_perror("Missing NAME parameter"); return; } d_new = (conf_disk_list *) malloc(sizeof(conf_disk_list)); if (!d_new) { config_perror("Out of memory"); return; } di_curr = (conf_disk_item *) malloc(sizeof(conf_disk_item)); if (!di_curr) { SNMP_FREE(d_new); config_perror("Out of memory"); return; } d_new->list_item = di_curr; /* XXX: on error/return conditions we need to free the entire new list, not just the last node like this is doing! */ for (;;) { if (*name == '?') { di_curr->item_type = ITEM_ANY; di_curr->item_details = (void *) 0; name++; } else if (*name == '*') { di_curr->item_type = ITEM_STAR; di_curr->item_details = (void *) 0; name++; } else if (*name == '[') { d_set = (details_set *) calloc(sizeof(details_set), 1); if (!d_set) { config_perror("Out of memory"); SNMP_FREE(d_new); SNMP_FREE(di_curr); SNMP_FREE(d_set); SNMP_FREE(d_str); return; } name++; if (*name == '^' || *name == '!') { neg = 1; name++; } else { neg = 0; } while (*name && *name != ']') { c1 = ((unsigned int) *name++) & 0xff; if (*name == '-' && *(name + 1) != ']') { name++; c2 = ((unsigned int) *name++) & 0xff; } else { c2 = c1; } for (i = c1; i <= c2; i++) (*d_set)[i / 8] |= (unsigned char) (1 << (i % 8)); } if (*name != ']') { config_perror ("Syntax error in NAME: invalid set specified"); SNMP_FREE(d_new); SNMP_FREE(di_curr); SNMP_FREE(d_set); SNMP_FREE(d_str); return; } if (neg) { for (i = 0; i < sizeof(details_set); i++) (*d_set)[i] = (*d_set)[i] ^ (unsigned char) 0xff; } di_curr->item_type = ITEM_SET; di_curr->item_details = (void *) d_set; name++; } else { for (p = name; *p != '\0' && *p != '?' && *p != '*' && *p != '['; p++); c = *p; *p = '\0'; d_str = strdup(name); if (!d_str) { SNMP_FREE(d_new); SNMP_FREE(d_str); SNMP_FREE(di_curr); SNMP_FREE(d_set); config_perror("Out of memory"); return; } *p = c; di_curr->item_type = ITEM_STRING; di_curr->item_details = (void *) d_str; name = p; } if (!*name) { di_curr->item_next = (conf_disk_item *) 0; break; } di_curr->item_next = (conf_disk_item *) malloc(sizeof(conf_disk_item)); if (!di_curr->item_next) { SNMP_FREE(di_curr->item_next); SNMP_FREE(d_new); SNMP_FREE(di_curr); SNMP_FREE(d_set); SNMP_FREE(d_str); config_perror("Out of memory"); return; } di_curr = di_curr->item_next; } d_new->list_next = conf_list; conf_list = d_new; } static void free_disk_config(void) { conf_disk_list *d_ptr = conf_list, *d_next; conf_disk_item *di_ptr, *di_next; while (d_ptr) { d_next = d_ptr->list_next; di_ptr = d_ptr->list_item; while (di_ptr) { di_next = di_ptr->item_next; if (di_ptr->item_details) free(di_ptr->item_details); free((void *) di_ptr); di_ptr = di_next; } free((void *) d_ptr); d_ptr = d_next; } conf_list = (conf_disk_list *) 0; } static int match_disk_config_item(const char *name, conf_disk_item * di_ptr) { int result = 0; size_t len; details_set *d_set; unsigned int c; if (di_ptr) { switch (di_ptr->item_type) { case ITEM_STRING: len = strlen((const char *) di_ptr->item_details); if (!strncmp(name, (const char *) di_ptr->item_details, len)) result = match_disk_config_item(name + len, di_ptr->item_next); break; case ITEM_SET: if (*name) { d_set = (details_set *) di_ptr->item_details; c = ((unsigned int) *name) & 0xff; if ((*d_set)[c / 8] & (unsigned char) (1 << (c % 8))) result = match_disk_config_item(name + 1, di_ptr->item_next); } break; case ITEM_STAR: if (di_ptr->item_next) { for (; !result && *name; name++) result = match_disk_config_item(name, di_ptr->item_next); } else { result = 1; } break; case ITEM_ANY: if (*name) result = match_disk_config_item(name + 1, di_ptr->item_next); break; } } else { if (*name == '\0') result = 1; } return result; } static int match_disk_config(const char *name) { conf_disk_list *d_ptr = conf_list; while (d_ptr) { if (match_disk_config_item(name, d_ptr->list_item)) return 1; /* match found in ignorelist */ d_ptr = d_ptr->list_next; } /* * no match in ignorelist */ return 0; } /* * header_hrdisk(... * 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_hrdisk(struct variable *vp, oid * name, size_t * length, int exact, size_t * var_len, WriteMethod ** write_method) { #define HRDISK_ENTRY_NAME_LENGTH 11 oid newname[MAX_OID_LEN]; int disk_idx, LowIndex = -1; int result; DEBUGMSGTL(("host/hr_disk", "var_hrdisk: ")); DEBUGMSGOID(("host/hr_disk", name, *length)); DEBUGMSG(("host/hr_disk", " %d\n", exact)); memcpy((char *) newname, (char *) vp->name, (int) vp->namelen * sizeof(oid)); /* * Find "next" disk entry */ Init_HR_Disk(); for (;;) { disk_idx = Get_Next_HR_Disk(); DEBUGMSGTL(("host/hr_disk", "... index %d\n", disk_idx)); if (disk_idx == -1) break; newname[HRDISK_ENTRY_NAME_LENGTH] = disk_idx; result = snmp_oid_compare(name, *length, newname, (int) vp->namelen + 1); if (exact && (result == 0)) { LowIndex = disk_idx; Save_HR_Disk_Specific(); break; } if ((!exact && (result < 0)) && (LowIndex == -1 || disk_idx < LowIndex)) { LowIndex = disk_idx; Save_HR_Disk_Specific(); #ifdef HRD_MONOTONICALLY_INCREASING break; #endif } } if (LowIndex == -1) { DEBUGMSGTL(("host/hr_disk", "... index out of range\n")); return (MATCH_FAILED); } newname[HRDISK_ENTRY_NAME_LENGTH] = LowIndex; memcpy((char *) name, (char *) newname, ((int) vp->namelen + 1) * sizeof(oid)); *length = vp->namelen + 1; *write_method = (WriteMethod*)0; *var_len = sizeof(long); /* default to 'long' results */ DEBUGMSGTL(("host/hr_disk", "... get disk stats ")); DEBUGMSGOID(("host/hr_disk", name, *length)); DEBUGMSG(("host/hr_disk", "\n")); return LowIndex; } /********************* * * System specific implementation functions * *********************/ u_char * var_hrdisk(struct variable * vp, oid * name, size_t * length, int exact, size_t * var_len, WriteMethod ** write_method) { int disk_idx; disk_idx = header_hrdisk(vp, name, length, exact, var_len, write_method); if (disk_idx == MATCH_FAILED) return NULL; switch (vp->magic) { case HRDISK_ACCESS: long_return = Is_It_Writeable(); return (u_char *) & long_return; case HRDISK_MEDIA: long_return = What_Type_Disk(); return (u_char *) & long_return; case HRDISK_REMOVEABLE: long_return = Is_It_Removeable(); return (u_char *) & long_return; case HRDISK_CAPACITY: long_return = HRD_savedCapacity; return (u_char *) & long_return; default: DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_hrdisk\n", vp->magic)); } return NULL; } /********************* * * Internal implementation functions * *********************/ #define MAX_NUMBER_DISK_TYPES 16 /* probably should be a variable */ #define MAX_DISKS_PER_TYPE 15 /* SCSI disks - not a hard limit */ #define HRDISK_TYPE_SHIFT 4 /* log2 (MAX_DISKS_PER_TYPE+1) */ typedef struct { const char *disk_devpart_string; /* printf() format disk part. name */ short disk_controller; /* controller id or -1 if NA */ short disk_device_first; /* first device id */ short disk_device_last; /* last device id */ const char *disk_devfull_string; /* printf() format full disk name */ short disk_partition_first; /* first partition id */ short disk_partition_last; /* last partition id */ } HRD_disk_t; static HRD_disk_t disk_devices[MAX_NUMBER_DISK_TYPES]; static int HR_number_disk_types = 0; #if !(defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7)) static void Add_HR_Disk_entry(const char *devpart_string, int first_ctl, int last_ctl, int first_dev, int last_dev, const char *devfull_string, int first_partn, int last_partn) { int lodev, hidev, nbr_created = 0; while (first_ctl <= last_ctl) { for (lodev = first_dev; lodev <= last_dev && MAX_NUMBER_DISK_TYPES > HR_number_disk_types; lodev += (1+MAX_DISKS_PER_TYPE), HR_number_disk_types++) { nbr_created++; /* * Split long runs of disks into separate "types" */ hidev = lodev + MAX_DISKS_PER_TYPE; if (last_dev < hidev) hidev = last_dev; disk_devices[HR_number_disk_types].disk_devpart_string = devpart_string; disk_devices[HR_number_disk_types].disk_controller = first_ctl; disk_devices[HR_number_disk_types].disk_device_first = lodev; disk_devices[HR_number_disk_types].disk_device_last = hidev; disk_devices[HR_number_disk_types].disk_devfull_string = devfull_string; disk_devices[HR_number_disk_types].disk_partition_first = first_partn; disk_devices[HR_number_disk_types].disk_partition_last = last_partn; #if DEBUG_TEST DEBUGMSGTL(("host/hr_disk", "Add_HR %02d '%s' first=%d last=%d\n", HR_number_disk_types, devpart_string, lodev, hidev)); #endif } first_ctl++; } if (nbr_created == 0 || MAX_NUMBER_DISK_TYPES < HR_number_disk_types) { HR_number_disk_types = MAX_NUMBER_DISK_TYPES; DEBUGMSGTL(("host/hr_disk", "WARNING! Add_HR_Disk_entry '%s' incomplete, %d created\n", devpart_string, nbr_created)); } #if DEBUG_TEST else DEBUGMSGTL(("host/hr_disk", "Add_HR_Disk_entry '%s' completed, %d created\n", devpart_string, nbr_created)); #endif } #endif void Init_HR_Disk(void) { HRD_type_index = 0; HRD_index = -1; DEBUGMSGTL(("host/hr_disk", "Init_Disk\n")); } int Get_Next_HR_Disk(void) { char string[PATH_MAX+1]; int fd, result; int iindex; int max_disks; time_t now; HRD_index++; time(&now); DEBUGMSGTL(("host/hr_disk", "Next_Disk type %d of %d\n", HRD_type_index, HR_number_disk_types)); while (HRD_type_index < HR_number_disk_types) { max_disks = disk_devices[HRD_type_index].disk_device_last - disk_devices[HRD_type_index].disk_device_first + 1; DEBUGMSGTL(("host/hr_disk", "Next_Disk max %d of type %d\n", max_disks, HRD_type_index)); while (HRD_index < max_disks) { iindex = (HRD_type_index << HRDISK_TYPE_SHIFT) + HRD_index; /* * Check to see whether this device * has been probed for 'recently' * and skip if so. * This has a *major* impact on run * times (by a factor of 10!) */ if ((HRD_history[iindex] > 0) && ((now - HRD_history[iindex]) < 60)) { HRD_index++; continue; } /* * Construct the full device name in "string" */ if (disk_devices[HRD_type_index].disk_controller != -1) { snprintf(string, sizeof(string)-1, disk_devices[HRD_type_index].disk_devfull_string, disk_devices[HRD_type_index].disk_controller, disk_devices[HRD_type_index].disk_device_first + HRD_index); } else if (disk_devices[HRD_type_index].disk_device_first == disk_devices[HRD_type_index].disk_device_last) { /* exact device name */ snprintf(string, sizeof(string)-1, "%s", disk_devices[HRD_type_index].disk_devfull_string); } else { snprintf(string, sizeof(string)-1, disk_devices[HRD_type_index].disk_devfull_string, disk_devices[HRD_type_index].disk_device_first + HRD_index); } string[ sizeof(string)-1 ] = 0; DEBUGMSGTL(("host/hr_disk", "Get_Next_HR_Disk: %s (%d/%d)\n", string, HRD_type_index, HRD_index)); if (HRD_history[iindex] == -1) { /* * check whether this device is in the "ignoredisk" list in * the config file. if yes this device will be marked as * invalid for the future, i.e. it won't ever be checked * again. */ if (match_disk_config(string)) { /* * device name matches entry in ignoredisk list */ DEBUGMSGTL(("host/hr_disk", "Get_Next_HR_Disk: %s ignored\n", string)); HRD_history[iindex] = (time_t)LONG_MAX; HRD_index++; continue; } } /* * use O_NDELAY to avoid CDROM spin-up and media detection * * (too slow) --okir */ /* * at least with HP-UX 11.0 this doesn't seem to work properly * * when accessing an empty CDROM device --jsf */ #ifdef O_NDELAY /* I'm sure everything has it, but just in case... --Wes */ fd = open(string, O_RDONLY | O_NDELAY); #else fd = open(string, O_RDONLY); #endif if (fd != -1) { result = Query_Disk(fd, string); close(fd); if (result != -1) { HRD_history[iindex] = 0; return ((HRDEV_DISK << HRDEV_TYPE_SHIFT) + iindex); } DEBUGMSGTL(("host/hr_disk", "Get_Next_HR_Disk: can't query %s\n", string)); } else { DEBUGMSGTL(("host/hr_disk", "Get_Next_HR_Disk: can't open %s\n", string)); } HRD_history[iindex] = now; HRD_index++; } HRD_type_index++; HRD_index = 0; } HRD_index = -1; return -1; } int Get_Next_HR_Disk_Partition(char *string, size_t str_len, int HRP_index) { DEBUGMSGTL(("host/hr_disk", "Next_Partition type %d/%d:%d\n", HRD_type_index, HRD_index, HRP_index)); /* * no more partition names => return -1 */ if (disk_devices[HRD_type_index].disk_partition_last - disk_devices[HRD_type_index].disk_partition_first + 1 <= HRP_index) { return -1; } /* * Construct the partition name in "string" */ if (disk_devices[HRD_type_index].disk_controller != -1) { snprintf(string, str_len-1, disk_devices[HRD_type_index].disk_devpart_string, disk_devices[HRD_type_index].disk_controller, disk_devices[HRD_type_index].disk_device_first + HRD_index, disk_devices[HRD_type_index].disk_partition_first + HRP_index); } else { snprintf(string, str_len-1, disk_devices[HRD_type_index].disk_devpart_string, disk_devices[HRD_type_index].disk_device_first + HRD_index, disk_devices[HRD_type_index].disk_partition_first + HRP_index); } string[ str_len-1 ] = 0; DEBUGMSGTL(("host/hr_disk", "Get_Next_HR_Disk_Partition: %s (%d/%d:%d)\n", string, HRD_type_index, HRD_index, HRP_index)); return 0; } #ifdef darwin int Get_HR_Disk_Label(char *string, size_t str_len, const char *devfull) { DASessionRef sess_ref; DADiskRef disk; CFDictionaryRef desc; CFStringRef str_ref; CFStringEncoding sys_encoding = CFStringGetSystemEncoding(); DEBUGMSGTL(("host/hr_disk", "Disk Label type %s\n", devfull)); sess_ref = DASessionCreate( NULL ); if (NULL == sess_ref) { strlcpy(string, devfull, str_len); return -1; } disk = DADiskCreateFromBSDName( NULL, sess_ref, devfull ); if (NULL == disk) { CFRelease(sess_ref); strlcpy(string, devfull, str_len); return -1; } desc = DADiskCopyDescription( disk ); if (NULL == desc) { snmp_log(LOG_ERR, "diskmgr: couldn't get disk description for %s, skipping\n", devfull); CFRelease(disk); CFRelease(sess_ref); strlcpy(string, devfull, str_len); return -1; } /** model */ str_ref = (CFStringRef) CFDictionaryGetValue(desc, kDADiskDescriptionMediaNameKey); if (str_ref) { strlcpy(string, CFStringGetCStringPtr(str_ref, sys_encoding), str_len); DEBUGMSGTL(("verbose:diskmgr:darwin", " name %s\n", string)); } else { strlcpy(string, devfull, str_len); } CFRelease(disk); CFRelease(desc); CFRelease(sess_ref); return 0; } #endif static void Save_HR_Disk_Specific(void) { #ifdef DIOC_DESCRIBE HRD_savedIntf_type = HRD_info.intf_type; HRD_savedDev_type = HRD_info.dev_type; HRD_savedFlags = HRD_info.flags; HRD_savedCapacity = HRD_cap.lba / 2; #endif #ifdef DKIOCINFO HRD_savedCtrl_type = HRD_info.dki_ctype; HRD_savedFlags = HRD_info.dki_flags; HRD_savedCapacity = HRD_cap.dkg_ncyl * HRD_cap.dkg_nhead * HRD_cap.dkg_nsect / 2; /* ??? */ #endif #ifdef HAVE_LINUX_HDREG_H HRD_savedCapacity = HRD_info.lba_capacity / 2; HRD_savedFlags = HRD_info.config; #endif #ifdef DIOCGDINFO HRD_savedCapacity = HRD_info.d_secperunit / 2; #endif #ifdef darwin HRD_savedCapacity = HRD_cap / 1024; HRD_saved_access = HRD_access; HRD_saved_type = HRD_type; HRD_saved_removeble = HRD_removeble; #endif } static void Save_HR_Disk_General(void) { #ifdef DIOC_DESCRIBE strlcpy(HRD_savedModel, HRD_info.model_num, sizeof(HRD_savedModel)); #endif #ifdef DKIOCINFO strlcpy(HRD_savedModel, HRD_info.dki_dname, sizeof(HRD_savedModel)); #endif #ifdef HAVE_LINUX_HDREG_H strlcpy(HRD_savedModel, (const char *) HRD_info.model, sizeof(HRD_savedModel)); #endif #ifdef DIOCGDINFO strlcpy(HRD_savedModel, dktypenames[HRD_info.d_type], sizeof(HRD_savedModel)); #endif #ifdef darwin strlcpy(HRD_savedModel, HRD_model, sizeof(HRD_savedModel)); #endif } static const char * describe_disk(int idx) { if (HRD_savedModel[0] == '\0') return ("some sort of disk"); else return (HRD_savedModel); } static int Query_Disk(int fd, const char *devfull) { int result = -1; #ifdef DIOC_DESCRIBE result = ioctl(fd, DIOC_DESCRIBE, &HRD_info); if (result != -1) result = ioctl(fd, DIOC_CAPACITY, &HRD_cap); #endif #ifdef DKIOCINFO result = ioctl(fd, DKIOCINFO, &HRD_info); if (result != -1) result = ioctl(fd, DKIOCGGEOM, &HRD_cap); #endif #ifdef HAVE_LINUX_HDREG_H if (HRD_type_index == 0) /* IDE hard disk */ result = ioctl(fd, HDIO_GET_IDENTITY, &HRD_info); else if (HRD_type_index != 3) { /* SCSI hard disk, md and LVM devices */ long h; result = ioctl(fd, BLKGETSIZE, &h); if (result != -1 && HRD_type_index == 2 && h == 0L) result = -1; /* ignore empty md devices */ if (result != -1) { HRD_info.lba_capacity = h; if (HRD_type_index == 1) snprintf( (char *) HRD_info.model, sizeof(HRD_info.model)-1, "SCSI disk (%s)", devfull); else if (HRD_type_index >= 4) snprintf( (char *) HRD_info.model, sizeof(HRD_info.model)-1, "LVM volume (%s)", devfull + strlen("/dev/mapper/")); else snprintf( (char *) HRD_info.model, sizeof(HRD_info.model)-1, "RAID disk (%s)", devfull); HRD_info.model[ sizeof(HRD_info.model)-1 ] = 0; HRD_info.config = 0; } } #endif #if defined(DIOCGMEDIASIZE) unsigned long long size64; if (ioctl(fd, DIOCGMEDIASIZE, &size64) < 0) result = -1; HRD_info.d_secperunit = size64 / 512; result = 0; #elif defined(DIOCGDINFO) result = ioctl(fd, DIOCGDINFO, &HRD_info); #endif #ifdef darwin DASessionRef sess_ref; DADiskRef disk; CFDictionaryRef desc; CFStringRef str_ref; CFNumberRef number_ref; CFBooleanRef bool_ref; CFStringEncoding sys_encoding = CFStringGetSystemEncoding(); sess_ref = DASessionCreate( NULL ); if (NULL == sess_ref) return -1; disk = DADiskCreateFromBSDName( NULL, sess_ref, devfull ); if (NULL == disk) { CFRelease(sess_ref); return -1; } desc = DADiskCopyDescription( disk ); if (NULL == desc) { CFRelease(disk); CFRelease(sess_ref); return -1; } number_ref = (CFNumberRef) CFDictionaryGetValue(desc, kDADiskDescriptionMediaSizeKey); if (number_ref) CFNumberGetValue(number_ref, kCFNumberSInt64Type, &HRD_cap); else HRD_cap = 0; DEBUGMSGTL(("verbose:diskmgr:darwin", " size %lld\n", HRD_cap)); /** writable? */ bool_ref = (CFBooleanRef) CFDictionaryGetValue(desc, kDADiskDescriptionMediaWritableKey); if (bool_ref) { HRD_access = CFBooleanGetValue(bool_ref); } else HRD_access = 0; DEBUGMSGTL(("verbose:diskmgr:darwin", " writable %d\n", HRD_access)); /** removable? */ bool_ref = (CFBooleanRef) CFDictionaryGetValue(desc, kDADiskDescriptionMediaRemovableKey); if (bool_ref) { HRD_removeble = CFBooleanGetValue(bool_ref); } else HRD_removeble = 0; DEBUGMSGTL(("verbose:diskmgr:darwin", " removable %d\n", HRD_removeble)); /** get type */ str_ref = (CFStringRef) CFDictionaryGetValue(desc, kDADiskDescriptionMediaTypeKey); if (str_ref) { HRD_type = _get_type_value(CFStringGetCStringPtr(str_ref, sys_encoding)); DEBUGMSGTL(("verbose:diskmgr:darwin", " type %s / %d\n", CFStringGetCStringPtr(str_ref, sys_encoding), HRD_type)); } else { str_ref = (CFStringRef) CFDictionaryGetValue(desc, kDADiskDescriptionDeviceProtocolKey); if (str_ref) { HRD_type = _get_type_from_protocol(CFStringGetCStringPtr(str_ref, sys_encoding)); DEBUGMSGTL(("verbose:diskmgr:darwin", " type %s / %d\n", CFStringGetCStringPtr(str_ref, sys_encoding), HRD_type)); } else HRD_type = HRDISKSTORAGEMEDIA_UNKNOWN; } /** model */ str_ref = (CFStringRef) CFDictionaryGetValue(desc, kDADiskDescriptionDeviceModelKey); if (str_ref) { strlcpy(HRD_model, CFStringGetCStringPtr(str_ref, sys_encoding), sizeof(HRD_model)); DEBUGMSGTL(("verbose:diskmgr:darwin", " model %s\n", HRD_model)); } else HRD_model[0] = 0; CFRelease(disk); CFRelease(desc); CFRelease(sess_ref); result = 0; #endif return (result); } static int Is_It_Writeable(void) { #ifdef DIOC_DESCRIBE if ((HRD_savedFlags & WRITE_PROTECT_FLAG) || (HRD_savedDev_type == CDROM_DEV_TYPE)) return (2); /* read only */ #endif #ifdef DKIOCINFO if (HRD_savedCtrl_type == DKC_CDROM) return (2); /* read only */ #endif #ifdef darwin if (!HRD_access) return (2); #endif return (1); /* read-write */ } static int What_Type_Disk(void) { #ifdef DIOC_DESCRIBE switch (HRD_savedDev_type) { case DISK_DEV_TYPE: if (HRD_savedIntf_type == PC_FDC_INTF) return (4); /* Floppy Disk */ else return (3); /* Hard Disk */ break; case CDROM_DEV_TYPE: return (5); /* Optical RO */ break; case WORM_DEV_TYPE: return (6); /* Optical WORM */ break; case MO_DEV_TYPE: return (7); /* Optical R/W */ break; default: return (2); /* Unknown */ break; } #endif #ifdef DKIOCINFO switch (HRD_savedCtrl_type) { case DKC_WDC2880: case DKC_DSD5215: #ifdef DKC_XY450 case DKC_XY450: #endif case DKC_ACB4000: case DKC_MD21: #ifdef DKC_XD7053 case DKC_XD7053: #endif case DKC_SCSI_CCS: #ifdef DKC_PANTHER case DKC_PANTHER: #endif #ifdef DKC_CDC_9057 case DKC_CDC_9057: #endif #ifdef DKC_FJ_M1060 case DKC_FJ_M1060: #endif case DKC_DIRECT: case DKC_PCMCIA_ATA: return (3); /* Hard Disk */ break; case DKC_NCRFLOPPY: case DKC_SMSFLOPPY: case DKC_INTEL82077: return (4); /* Floppy Disk */ break; case DKC_CDROM: return (5); /* Optical RO */ break; case DKC_PCMCIA_MEM: return (8); /* RAM disk */ break; case DKC_MD: /* "meta-disk" driver */ return (1); /* Other */ break; } #endif #ifdef darwin return HRD_type; #endif return (2); /* Unknown */ } static int Is_It_Removeable(void) { #ifdef DIOC_DESCRIBE if ((HRD_savedIntf_type == PC_FDC_INTF) || (HRD_savedDev_type == WORM_DEV_TYPE) || (HRD_savedDev_type == MO_DEV_TYPE) || (HRD_savedDev_type == CDROM_DEV_TYPE)) return (1); /* true */ #endif #ifdef DKIOCINFO if ((HRD_savedCtrl_type == DKC_CDROM) || (HRD_savedCtrl_type == DKC_NCRFLOPPY) || (HRD_savedCtrl_type == DKC_SMSFLOPPY) || (HRD_savedCtrl_type == DKC_INTEL82077) || (HRD_savedCtrl_type == DKC_PCMCIA_MEM) || (HRD_savedCtrl_type == DKC_PCMCIA_ATA)) return (1); /* true */ #endif #ifdef HAVE_LINUX_HDREG_H if (HRD_savedFlags & 0x80) return (1); /* true */ #endif #ifdef darwin if (HRD_removeble) return (1); #endif return (2); /* false */ } #ifdef darwin typedef struct type_value_map_s { const char *type; uint32_t value; } type_value_map; static type_value_map media_type_map[] = { { "CD-ROM", HRDISKSTORAGEMEDIA_OPTICALDISKROM}, { "DVD-R", HRDISKSTORAGEMEDIA_OPTICALDISKWORM}, { "DVD+R", HRDISKSTORAGEMEDIA_OPTICALDISKWORM}, }; static int media_types = sizeof(media_type_map)/sizeof(media_type_map[0]); static int _get_type_value( const char *str_type ) { int i, len; if (NULL == str_type) return HRDISKSTORAGEMEDIA_UNKNOWN; len = strlen(str_type); for(i=0; i < media_types; ++i) { if (0 == strcmp(media_type_map[i].type, str_type)) return media_type_map[i].value; } return HRDISKSTORAGEMEDIA_UNKNOWN; } static type_value_map proto_map[] = { { "ATA", HRDISKSTORAGEMEDIA_HARDDISK}, { "ATAPI", HRDISKSTORAGEMEDIA_OPTICALDISKROM} }; static int proto_maps = sizeof(proto_map)/sizeof(proto_map[0]); static int _get_type_from_protocol( const char *prot ) { int i, len; if (NULL == prot) return TV_FALSE; len = strlen(prot); for(i=0; i < proto_maps; ++i) { if (0 == strcmp(proto_map[i].type, prot)) return proto_map[i].value; } return HRDISKSTORAGEMEDIA_UNKNOWN; } #endif #ifdef linux #if defined(HAVE_REGEX_H) && defined(HAVE_REGCOMP) static char *lvm_device_names[MAX_NUMBER_DISK_TYPES]; static int lvm_device_count; #endif static void Add_LVM_Disks(void) { #if defined(HAVE_REGEX_H) && defined(HAVE_REGCOMP) /* * LVM devices are harder because their name can be almost anything (see * regexp below). Each logical volume is interpreted as its own device with * one partition, even if two logical volumes share common volume group. */ regex_t lvol; int res; DIR *dir; struct dirent *d; res = regcomp(&lvol, "[0-9a-zA-Z+_\\.-]+-[0-9a-zA-Z+_\\.-]+", REG_EXTENDED | REG_NOSUB); if (res != 0) { char error[200]; regerror(res, &lvol, error, sizeof(error)-1); DEBUGMSGTL(("host/hr_disk", "Add_LVM_Disks: cannot compile regexp: %s", error)); return; } dir = opendir("/dev/mapper/"); if (dir == NULL) { DEBUGMSGTL(("host/hr_disk", "Add_LVM_Disks: cannot open /dev/mapper")); regfree(&lvol); return; } while ((d = readdir(dir)) != NULL) { res = regexec(&lvol, d->d_name, 0, NULL, 0); if (res == 0) { char *path = (char*)malloc(PATH_MAX + 1); if (path == NULL) { DEBUGMSGTL(("host/hr_disk", "Add_LVM_Disks: cannot allocate memory for device %s", d->d_name)); break; } snprintf(path, PATH_MAX-1, "/dev/mapper/%s", d->d_name); Add_HR_Disk_entry(path, -1, -1, 0, 0, path, 0, 0); /* * store the device name so we can free it in Remove_LVM_Disks */ lvm_device_names[lvm_device_count] = path; ++lvm_device_count; if (lvm_device_count >= MAX_NUMBER_DISK_TYPES) { DEBUGMSGTL(("host/hr_disk", "Add_LVM_Disks: maximum count of LVM devices reached")); break; } } } closedir(dir); regfree(&lvol); #endif } static void Remove_LVM_Disks(void) { #if defined(HAVE_REGEX_H) && defined(HAVE_REGCOMP) /* * just free the device names allocated in add_lvm_disks */ int i; for (i = 0; i < lvm_device_count; i++) { free(lvm_device_names[i]); lvm_device_names[i] = NULL; } lvm_device_count = 0; #endif } #endif