From 4ba53d756e2ebd69fc30ec23117f4e8545af5231 Mon Sep 17 00:00:00 2001 From: Packit Date: Sep 10 2020 11:07:37 +0000 Subject: Apply patch net-snmp-5.8-dskTable-dynamic.patch patch_name: net-snmp-5.8-dskTable-dynamic.patch present_in_specfile: true --- diff --git a/agent/mibgroup/ucd-snmp/disk.c b/agent/mibgroup/ucd-snmp/disk.c index d827dcc..e8e8923 100644 --- a/agent/mibgroup/ucd-snmp/disk.c +++ b/agent/mibgroup/ucd-snmp/disk.c @@ -153,9 +153,10 @@ static void disk_free_config(void); static void disk_parse_config(const char *, char *); static void disk_parse_config_all(const char *, char *); #if HAVE_FSTAB_H || HAVE_GETMNTENT || HAVE_STATFS -static void find_and_add_allDisks(int minpercent); +static void refresh_disk_table(int addNewDisks, int minpercent); static void add_device(char *path, char *device, - int minspace, int minpercent, int override); + int minspace, int minpercent, int addNewDisks, + int override); static void modify_disk_parameters(int index, int minspace, int minpercent); static int disk_exists(char *path); @@ -167,6 +168,7 @@ struct diskpart { char path[STRMAX]; int minimumspace; int minpercent; + int alive; }; #define MAX_INT_32 0x7fffffff @@ -174,6 +176,7 @@ struct diskpart { unsigned int numdisks; int allDisksIncluded = 0; +int allDisksMinPercent = 0; unsigned int maxdisks = 0; struct diskpart *disks; @@ -238,6 +241,7 @@ init_disk(void) disk_free_config, "minpercent%"); allDisksIncluded = 0; + allDisksMinPercent = 0; } static void @@ -253,6 +257,7 @@ disk_free_config(void) disks[i].minpercent = -1; } allDisksIncluded = 0; + allDisksMinPercent = 0; } static void @@ -313,7 +318,7 @@ disk_parse_config(const char *token, char *cptr) * check if the disk already exists, if so then modify its * parameters. if it does not exist then add it */ - add_device(path, find_device(path), minspace, minpercent, 1); + add_device(path, find_device(path), minspace, minpercent, 1, 1); #endif /* HAVE_FSTAB_H || HAVE_GETMNTENT || HAVE_STATFS */ } @@ -372,7 +377,7 @@ disk_parse_config_all(const char *token, char *cptr) #if HAVE_FSTAB_H || HAVE_GETMNTENT || HAVE_STATFS static void -add_device(char *path, char *device, int minspace, int minpercent, int override) +add_device(char *path, char *device, int minspace, int minpercent, int addNewDisks, int override) { int index; @@ -402,10 +407,16 @@ add_device(char *path, char *device, int minspace, int minpercent, int override) } index = disk_exists(path); - if((index != -1) && (index < maxdisks) && (override==1)) { - modify_disk_parameters(index, minspace, minpercent); + if((index != -1) && (index < maxdisks)) { + /* the path is already in the table */ + disks[index].alive = 1; + /* -> update its device */ + strlcpy(disks[index].device, device, sizeof(disks[index].device)); + if (override == 1) { + modify_disk_parameters(index, minspace, minpercent); + } } - else if(index == -1){ + else if(index == -1 && addNewDisks){ /* add if and only if the device was found */ if(device[0] != 0) { /* The following buffers are cleared above, no need to add '\0' */ @@ -413,6 +424,7 @@ add_device(char *path, char *device, int minspace, int minpercent, int override) strlcpy(disks[numdisks].device, device, sizeof(disks[numdisks].device)); disks[numdisks].minimumspace = minspace; disks[numdisks].minpercent = minpercent; + disks[numdisks].alive = 1; numdisks++; } else { @@ -420,6 +432,7 @@ add_device(char *path, char *device, int minspace, int minpercent, int override) disks[numdisks].minpercent = -1; disks[numdisks].path[0] = 0; disks[numdisks].device[0] = 0; + disks[numdisks].alive = 0; } } } @@ -444,7 +457,7 @@ int disk_exists(char *path) } static void -find_and_add_allDisks(int minpercent) +refresh_disk_table(int addNewDisks, int minpercent) { #if HAVE_GETMNTENT #if HAVE_SYS_MNTTAB_H @@ -480,7 +493,7 @@ find_and_add_allDisks(int minpercent) return; } while (mntfp && NULL != (mntent = getmntent(mntfp))) { - add_device(mntent->mnt_dir, mntent->mnt_fsname, -1, minpercent, 0); + add_device(mntent->mnt_dir, mntent->mnt_fsname, -1, minpercent, addNewDisks, 0); dummy = 1; } if (mntfp) @@ -497,7 +510,7 @@ find_and_add_allDisks(int minpercent) return; } while ((i = getmntent(mntfp, &mnttab)) == 0) { - add_device(mnttab.mnt_mountp, mnttab.mnt_special, -1, minpercent, 0); + add_device(mnttab.mnt_mountp, mnttab.mnt_special, -1, minpercent, addNewDisks, 0); dummy = 1; } fclose(mntfp); @@ -510,7 +523,7 @@ find_and_add_allDisks(int minpercent) #elif HAVE_FSTAB_H setfsent(); /* open /etc/fstab */ while((fstab1 = getfsent()) != NULL) { - add_device(fstab1->fs_file, fstab1->fs_spec, -1, minpercent, 0); + add_device(fstab1->fs_file, fstab1->fs_spec, -1, minpercent, addNewDisks, 0); dummy = 1; } endfsent(); /* close /etc/fstab */ @@ -521,7 +534,7 @@ find_and_add_allDisks(int minpercent) mntsize = getmntinfo(&mntbuf, MNT_NOWAIT); for (i = 0; i < mntsize; i++) { if (strncmp(mntbuf[i].f_fstypename, "zfs", 3) == 0) { - add_device(mntbuf[i].f_mntonname, mntbuf[i].f_mntfromname, -1, minpercent, 0); + add_device(mntbuf[i].f_mntonname, mntbuf[i].f_mntfromname, -1, minpercent, addNewDisks, 0); } } } @@ -537,7 +550,7 @@ find_and_add_allDisks(int minpercent) * statfs we default to the root partition "/" */ if (statfs("/", &statf) == 0) { - add_device("/", statf.f_mntfromname, -1, minpercent, 0); + add_device("/", statf.f_mntfromname, -1, minpercent, addNewDisks, 0); } #endif else { @@ -696,6 +709,10 @@ fill_dsk_entry(int disknum, struct dsk_entry *entry) #endif #endif + if (disks[disknum].alive == 0){ + return -1; + } + entry->dskPercentInode = -1; #if defined(HAVE_STATVFS) || defined(HAVE_STATFS) @@ -826,6 +843,13 @@ var_extensible_disk(struct variable *vp, static long long_ret; static char *errmsg; + int i; + for (i = 0; i < numdisks; i++){ + disks[i].alive = 0; + } + /* dynamically add new disks + update alive flag */ + refresh_disk_table(allDisksIncluded, allDisksMinPercent); + tryAgain: if (header_simple_table (vp, name, length, exact, var_len, write_method, numdisks)) diff --git a/agent/mibgroup/ucd-snmp/disk.c.dskTable-dynamic b/agent/mibgroup/ucd-snmp/disk.c.dskTable-dynamic new file mode 100644 index 0000000..d827dcc --- /dev/null +++ b/agent/mibgroup/ucd-snmp/disk.c.dskTable-dynamic @@ -0,0 +1,932 @@ +/* + * disk.c + */ + +#include + +/* workaround for bug in autoconf 2.60b and 2.61 */ +#ifdef HAVE_GETMNTENT +#undef HAVE_GETMNTENT +#define HAVE_GETMNTENT 1 /* previously might be only "#define HAVE_GETMNTENT" */ +#endif + +#include + +#if HAVE_STDLIB_H +#include +#endif +#if HAVE_UNISTD_H +#include +#endif +#if HAVE_FCNTL_H +#include +#endif +#include +#if HAVE_MACHINE_PARAM_H +#include +#endif +#if HAVE_SYS_VMMETER_H +#if !(defined(bsdi2) || defined(netbsd1)) +#include +#endif +#endif +#if HAVE_SYS_PARAM_H +#include +#endif +#if HAVE_SYS_CONF_H +#include +#endif +#if HAVE_ASM_PAGE_H +#include +#endif +#if HAVE_SYS_SWAP_H +#include +#endif +#if HAVE_SYS_FS_H +#include +#else +#if HAVE_UFS_FS_H +#include +#else +#ifdef HAVE_SYS_STAT_H +#include +#endif +#if !defined(dragonfly) +#ifdef HAVE_SYS_VNODE_H +#include +#endif +#endif +#ifdef HAVE_UFS_UFS_QUOTA_H +#include +#endif +#ifdef HAVE_UFS_UFS_INODE_H +#include +#endif +#if HAVE_UFS_FFS_FS_H +#include +#endif +#endif +#endif +#if HAVE_MTAB_H +#include +#endif +#include +#include +#if HAVE_SYS_STATFS_H +#include +#endif +#if HAVE_SYS_STATVFS_H +#include +#endif +#if HAVE_SYS_VFS_H +#include +#endif +#if defined(__FreeBSD__) && __FreeBSD_version >= 700055 /* Or HAVE_SYS_UCRED_H */ +#include +#endif +#if defined(HAVE_STATFS) +#if HAVE_SYS_MOUNT_H +#include +#endif +#if HAVE_SYS_SYSCTL_H +#include +#endif +#if !defined(HAVE_STATVFS) +#define statvfs statfs +#endif +#endif +#if HAVE_VM_VM_H +#include +#endif +#if HAVE_VM_SWAP_PAGER_H +#include +#endif +#if HAVE_SYS_FIXPOINT_H +#include +#endif +#if HAVE_MALLOC_H +#include +#endif +#if HAVE_STRING_H +#include +#endif +#if HAVE_FSTAB_H +#include +#endif +#if HAVE_MNTENT_H +#include +#endif +#if HAVE_SYS_MNTTAB_H +#include +#endif +#if HAVE_NETINET_IN_H +#include +#endif +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif + +#include +#include +#include + +#include "struct.h" +#include "disk.h" +#include "util_funcs/header_simple_table.h" +#if USING_UCD_SNMP_ERRORMIB_MODULE +#include "errormib.h" +#else +#define setPerrorstatus(x) snmp_log_perror(x) +#endif + +/* + * * config file parsing routines + * */ +static void disk_free_config(void); +static void disk_parse_config(const char *, char *); +static void disk_parse_config_all(const char *, char *); +#if HAVE_FSTAB_H || HAVE_GETMNTENT || HAVE_STATFS +static void find_and_add_allDisks(int minpercent); +static void add_device(char *path, char *device, + int minspace, int minpercent, int override); +static void modify_disk_parameters(int index, int minspace, + int minpercent); +static int disk_exists(char *path); +static char *find_device(char *path); +#endif + +struct diskpart { + char device[STRMAX]; + char path[STRMAX]; + int minimumspace; + int minpercent; +}; + +#define MAX_INT_32 0x7fffffff +#define MAX_UINT_32 0xffffffff + +unsigned int numdisks; +int allDisksIncluded = 0; +unsigned int maxdisks = 0; +struct diskpart *disks; + +struct variable2 extensible_disk_variables[] = { + {MIBINDEX, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, + var_extensible_disk, 1, {MIBINDEX}}, + {ERRORNAME, ASN_OCTET_STR, NETSNMP_OLDAPI_RONLY, + var_extensible_disk, 1, {ERRORNAME}}, + {DISKDEVICE, ASN_OCTET_STR, NETSNMP_OLDAPI_RONLY, + var_extensible_disk, 1, {DISKDEVICE}}, + {DISKMINIMUM, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, + var_extensible_disk, 1, {DISKMINIMUM}}, + {DISKMINPERCENT, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, + var_extensible_disk, 1, {DISKMINPERCENT}}, + {DISKTOTAL, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, + var_extensible_disk, 1, {DISKTOTAL}}, + {DISKAVAIL, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, + var_extensible_disk, 1, {DISKAVAIL}}, + {DISKUSED, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, + var_extensible_disk, 1, {DISKUSED}}, + {DISKPERCENT, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, + var_extensible_disk, 1, {DISKPERCENT}}, + {DISKPERCENTNODE, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, + var_extensible_disk, 1, {DISKPERCENTNODE}}, + {ERRORFLAG, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, + var_extensible_disk, 1, {ERRORFLAG}}, + {ERRORMSG, ASN_OCTET_STR, NETSNMP_OLDAPI_RONLY, + var_extensible_disk, 1, {ERRORMSG}}, + {DISKTOTALLOW, ASN_UNSIGNED, NETSNMP_OLDAPI_RONLY, + var_extensible_disk, 1, {DISKTOTALLOW}}, + {DISKTOTALHIGH, ASN_UNSIGNED, NETSNMP_OLDAPI_RONLY, + var_extensible_disk, 1, {DISKTOTALHIGH}}, + {DISKAVAILLOW, ASN_UNSIGNED, NETSNMP_OLDAPI_RONLY, + var_extensible_disk, 1, {DISKAVAILLOW}}, + {DISKAVAILHIGH, ASN_UNSIGNED, NETSNMP_OLDAPI_RONLY, + var_extensible_disk, 1, {DISKAVAILHIGH}}, + {DISKUSEDLOW, ASN_UNSIGNED, NETSNMP_OLDAPI_RONLY, + var_extensible_disk, 1, {DISKUSEDLOW}}, + {DISKUSEDHIGH, ASN_UNSIGNED, NETSNMP_OLDAPI_RONLY, + var_extensible_disk, 1, {DISKUSEDHIGH}}, +}; + +/* + * Define the OID pointer to the top of the mib tree that we're + * registering underneath + */ +oid disk_variables_oid[] = { NETSNMP_UCDAVIS_MIB, NETSNMP_DISKMIBNUM, 1 }; + +void +init_disk(void) +{ + /* + * register ourselves with the agent to handle our mib tree + */ + REGISTER_MIB("ucd-snmp/disk", extensible_disk_variables, variable2, + disk_variables_oid); + + snmpd_register_config_handler("disk", disk_parse_config, + disk_free_config, + "path [ minspace | minpercent% ]"); + snmpd_register_config_handler("includeAllDisks", disk_parse_config_all, + disk_free_config, + "minpercent%"); + allDisksIncluded = 0; +} + +static void +disk_free_config(void) +{ + unsigned int i; + + numdisks = 0; + for (i = 0; i < maxdisks; i++) { /* init/erase disk db */ + disks[i].device[0] = 0; + disks[i].path[0] = 0; + disks[i].minimumspace = -1; + disks[i].minpercent = -1; + } + allDisksIncluded = 0; +} + +static void +disk_parse_config(const char *token, char *cptr) +{ +#if HAVE_FSTAB_H || HAVE_GETMNTENT || HAVE_STATFS + char path[STRMAX]; + int minpercent; + int minspace; + + if (numdisks == maxdisks) { + if (maxdisks == 0) { + maxdisks = 50; + disks = (struct diskpart *)malloc(maxdisks * sizeof(struct diskpart)); + if (!disks) { + config_perror("malloc failed for new disk allocation."); + netsnmp_config_error("\tignoring: %s", cptr); + return; + } + memset(disks, 0, maxdisks * sizeof(struct diskpart)); + } else { + maxdisks *= 2; + disks = (struct diskpart *)realloc(disks, maxdisks * sizeof(struct diskpart)); + if (!disks) { + config_perror("malloc failed for new disk allocation."); + netsnmp_config_error("\tignoring: %s", cptr); + return; + } + memset(disks + maxdisks/2, 0, maxdisks/2 * sizeof(struct diskpart)); + } + } + + /* + * read disk path (eg, /1 or /usr) + */ + copy_nword(cptr, path, sizeof(path)); + cptr = skip_not_white(cptr); + cptr = skip_white(cptr); + + /* + * read optional minimum disk usage spec + */ + if(cptr != NULL) { + if(strchr(cptr, '%') == NULL) { + minspace = atoi(cptr); + minpercent = -1; + } + else { + minspace = -1; + minpercent = atoi(cptr); + } + } else { + minspace = NETSNMP_DEFDISKMINIMUMSPACE; + minpercent = -1; + } + + /* + * check if the disk already exists, if so then modify its + * parameters. if it does not exist then add it + */ + add_device(path, find_device(path), minspace, minpercent, 1); +#endif /* HAVE_FSTAB_H || HAVE_GETMNTENT || HAVE_STATFS */ +} + +static void +disk_parse_config_all(const char *token, char *cptr) +{ +#if HAVE_FSTAB_H || HAVE_GETMNTENT || HAVE_STATFS + int minpercent = DISKMINPERCENT; + + if (numdisks == maxdisks) { + if (maxdisks == 0) { + maxdisks = 50; + disks = (struct diskpart *)malloc(maxdisks * sizeof(struct diskpart)); + if (!disks) { + config_perror("malloc failed for new disk allocation."); + netsnmp_config_error("\tignoring: %s", cptr); + return; + } + memset(disks, 0, maxdisks * sizeof(struct diskpart)); + } else { + maxdisks *= 2; + disks = (struct diskpart *)realloc(disks, maxdisks * sizeof(struct diskpart)); + if (!disks) { + config_perror("malloc failed for new disk allocation."); + netsnmp_config_error("\tignoring: %s", cptr); + return; + } + memset(disks + maxdisks/2, 0, maxdisks/2 * sizeof(struct diskpart)); + } + } + /* + * read the minimum disk usage percent + */ + if(cptr != NULL) { + if(strchr(cptr, '%') != NULL) { + minpercent = atoi(cptr); + } + } + /* + * if we have already seen the "includeAllDisks" directive + * then search for the disk in the "disks" array and modify + * the values. if we havent seen the "includeAllDisks" + * directive then include this disk + */ + if(allDisksIncluded) { + config_perror("includeAllDisks already specified."); + netsnmp_config_error("\tignoring: includeAllDisks %s", cptr); + } + else { + allDisksIncluded = 1; + find_and_add_allDisks(minpercent); + } +#endif /* HAVE_FSTAB_H || HAVE_GETMNTENT || HAVE_STATFS */ +} + + +#if HAVE_FSTAB_H || HAVE_GETMNTENT || HAVE_STATFS +static void +add_device(char *path, char *device, int minspace, int minpercent, int override) +{ + int index; + + if (!path || !strcmp(path, "none")) { + DEBUGMSGTL(("ucd-snmp/disk", "Skipping null path device (%s)\n", device)); + return; + } + if (numdisks == maxdisks) { + if (maxdisks == 0) { + maxdisks = 50; + disks = (struct diskpart *)malloc(maxdisks * sizeof(struct diskpart)); + if (!disks) { + netsnmp_config_error("\tignoring: %s", device); + return; + } + memset(disks, 0, maxdisks * sizeof(struct diskpart)); + } else { + maxdisks *= 2; + disks = (struct diskpart *)realloc(disks, maxdisks * sizeof(struct diskpart)); + if (!disks) { + config_perror("malloc failed for new disk allocation."); + netsnmp_config_error("\tignoring: %s", device); + return; + } + memset(disks + maxdisks/2, 0, maxdisks/2 * sizeof(struct diskpart)); + } + } + + index = disk_exists(path); + if((index != -1) && (index < maxdisks) && (override==1)) { + modify_disk_parameters(index, minspace, minpercent); + } + else if(index == -1){ + /* add if and only if the device was found */ + if(device[0] != 0) { + /* The following buffers are cleared above, no need to add '\0' */ + strlcpy(disks[numdisks].path, path, sizeof(disks[numdisks].path)); + strlcpy(disks[numdisks].device, device, sizeof(disks[numdisks].device)); + disks[numdisks].minimumspace = minspace; + disks[numdisks].minpercent = minpercent; + numdisks++; + } + else { + disks[numdisks].minimumspace = -1; + disks[numdisks].minpercent = -1; + disks[numdisks].path[0] = 0; + disks[numdisks].device[0] = 0; + } + } +} + +void +modify_disk_parameters(int index, int minspace, int minpercent) +{ + disks[index].minimumspace = minspace; + disks[index].minpercent = minpercent; +} + +int disk_exists(char *path) +{ + unsigned int index; + for(index = 0; index < numdisks; index++) { + DEBUGMSGTL(("ucd-snmp/disk", "Checking for %s. Found %s at %d\n", path, disks[index].path, index)); + if(strcmp(path, disks[index].path) == 0) { + return index; + } + } + return -1; +} + +static void +find_and_add_allDisks(int minpercent) +{ +#if HAVE_GETMNTENT +#if HAVE_SYS_MNTTAB_H + struct mnttab mnttab; +#else + struct mntent *mntent; +#endif + FILE *mntfp; +#elif HAVE_FSTAB_H + struct fstab *fstab1; +#elif HAVE_STATFS + struct statfs statf; +#endif +#if defined(HAVE_GETMNTENT) && !defined(HAVE_SETMNTENT) + int i; +#endif + +#if defined(HAVE_GETMNTENT) || defined(HAVE_FSTAB_H) + int dummy = 0; +#endif + + /* + * find the device for the path and copy the device into the + * string declared above and at the end of the routine return it + * to the caller + */ +#if HAVE_FSTAB_H || HAVE_GETMNTENT || HAVE_STATFS +#if HAVE_GETMNTENT +#if HAVE_SETMNTENT + mntfp = setmntent(ETC_MNTTAB, "r"); + if (!mntfp) { + netsnmp_config_error("Can't open %s (setmntent)\n", ETC_MNTTAB); + return; + } + while (mntfp && NULL != (mntent = getmntent(mntfp))) { + add_device(mntent->mnt_dir, mntent->mnt_fsname, -1, minpercent, 0); + dummy = 1; + } + if (mntfp) + endmntent(mntfp); + if(dummy != 0) { + /* + * dummy clause for else below + */ + } +#else /* getmentent but not setmntent */ + mntfp = fopen(ETC_MNTTAB, "r"); + if (!mntfp) { + netsnmp_config_error("Can't open %s (fopen)\n", ETC_MNTTAB); + return; + } + while ((i = getmntent(mntfp, &mnttab)) == 0) { + add_device(mnttab.mnt_mountp, mnttab.mnt_special, -1, minpercent, 0); + dummy = 1; + } + fclose(mntfp); + if(dummy != 0) { + /* + * dummy clause for else below + */ + } +#endif /* HAVE_SETMNTENT */ +#elif HAVE_FSTAB_H + setfsent(); /* open /etc/fstab */ + while((fstab1 = getfsent()) != NULL) { + add_device(fstab1->fs_file, fstab1->fs_spec, -1, minpercent, 0); + dummy = 1; + } + endfsent(); /* close /etc/fstab */ +#if defined(__FreeBSD__) && __FreeBSD_version >= 700055 + { + struct statfs *mntbuf; + size_t i, mntsize; + mntsize = getmntinfo(&mntbuf, MNT_NOWAIT); + for (i = 0; i < mntsize; i++) { + if (strncmp(mntbuf[i].f_fstypename, "zfs", 3) == 0) { + add_device(mntbuf[i].f_mntonname, mntbuf[i].f_mntfromname, -1, minpercent, 0); + } + } + } +#endif + if(dummy != 0) { + /* + * dummy clause for else below + */ + } +#elif HAVE_STATFS + /* + * since there is no way to get all the mounted systems with just + * statfs we default to the root partition "/" + */ + if (statfs("/", &statf) == 0) { + add_device("/", statf.f_mntfromname, -1, minpercent, 0); + } +#endif + else { + if (numdisks == maxdisks) { + return; + } + netsnmp_config_warn("Couldn't find device for disk %s", + disks[numdisks].path); + disks[numdisks].minimumspace = -1; + disks[numdisks].minpercent = -1; + disks[numdisks].path[0] = 0; + } +#else + config_perror("'disk' checks not supported on this architecture."); +#endif /* HAVE_FSTAB_H || HAVE_GETMNTENT || HAVE_STATFS */ + +} + +static char * +find_device(char *path) +{ +#if HAVE_GETMNTENT +#if HAVE_SYS_MNTTAB_H + struct mnttab mnttab; +#else + struct mntent *mntent; +#endif + FILE *mntfp; +#elif HAVE_FSTAB_H + struct fstab *fstab; +#elif HAVE_STATFS + struct statfs statf; +#endif + static char device[STRMAX]; +#if defined(HAVE_GETMNTENT) && !defined(HAVE_SETMNTENT) + int i; +#endif + + device[0] = '\0'; /* null terminate the device */ + + + /* find the device for the path and copy the device into the + * string declared above and at the end of the routine return it + * to the caller + */ +#if HAVE_FSTAB_H || HAVE_GETMNTENT || HAVE_STATFS +#if HAVE_GETMNTENT +#if HAVE_SETMNTENT + mntfp = setmntent(ETC_MNTTAB, "r"); + if (!mntfp) { + netsnmp_config_error("Can't open %s (setmntent)\n", ETC_MNTTAB); + return NULL; + } + while (mntfp && NULL != (mntent = getmntent(mntfp))) + if (strcmp(path, mntent->mnt_dir) == 0) { + strlcpy(device, mntent->mnt_fsname, sizeof(device)); + DEBUGMSGTL(("ucd-snmp/disk", "Disk: %s\n", + mntent->mnt_fsname)); + break; + } else { + DEBUGMSGTL(("ucd-snmp/disk", " %s != %s\n", + path, mntent->mnt_dir)); + } + if (mntfp) + endmntent(mntfp); +#else /* getmentent but not setmntent */ + mntfp = fopen(ETC_MNTTAB, "r"); + if (!mntfp) { + netsnmp_config_error("Can't open %s (fopen)\n", ETC_MNTTAB); + return NULL; + } + while ((i = getmntent(mntfp, &mnttab)) == 0) + if (strcmp(path, mnttab.mnt_mountp) == 0) + break; + else { + DEBUGMSGTL(("ucd-snmp/disk", " %s != %s\n", + path, mnttab.mnt_mountp)); + } + fclose(mntfp); + if (i == 0) + strlcpy(device, mnttab.mnt_special, sizeof(device)); +#endif /* HAVE_SETMNTENT */ +#elif HAVE_FSTAB_H + setfsent(); + if ((fstab = getfsfile(path))) + strlcpy(device, fstab->fs_spec, sizeof(device)); + endfsent(); + if (device[0] != '\0') { + /* + * dummy clause for else below + */ + } + +#elif HAVE_STATFS + if (statfs(path, &statf) == 0) { + strlcpy(device, statf.f_mntfromname, sizeof(device)); + DEBUGMSGTL(("ucd-snmp/disk", "Disk: %s\n", + statf.f_mntfromname)); + } +#endif + else { + netsnmp_config_warn("Couldn't find device for disk %s", path); + } +#else + config_perror("'disk' checks not supported on this architecture."); +#endif /* HAVE_FSTAB_H || HAVE_GETMNTENT || HAVE_STATFS */ + return device; +} +#endif + +/* + * Part of UCD-SNMP-MIB::dskEntry, which is so hard to fill + * (i.e. platform dependent parts). + */ +struct dsk_entry { + unsigned long long dskTotal; + unsigned long long dskUsed; + unsigned long long dskAvail; + unsigned long dskPercent; + unsigned long dskPercentInode; + unsigned long dskErrorFlag; +}; + +/** + * Fill in the provided dsk_entry structure. + * Returns -1 on error, 0 on success. + */ + +static int +fill_dsk_entry(int disknum, struct dsk_entry *entry) +{ +#if defined(HAVE_STATVFS) || defined(HAVE_STATFS) + float multiplier; +#endif +#if defined(HAVE_FSTAB_H) && !defined(HAVE_SYS_STATVFS_H) && !defined(HAVE_STATFS) + double totalblks, free, used, avail, availblks; +#endif + +#if defined(HAVE_STATVFS) || defined(HAVE_STATFS) +#ifdef STAT_STATFS_FS_DATA + struct fs_data fsd; + struct { + u_int f_blocks, f_bfree, f_bavail, f_bsize; + } vfs; +#else + struct statvfs vfs; +#endif +#else +#if HAVE_FSTAB_H + int file; + union { + struct fs iu_fs; + char dummy[SBSIZE]; + } sb; +#define filesys sb.iu_fs +#endif +#endif + + entry->dskPercentInode = -1; + +#if defined(HAVE_STATVFS) || defined(HAVE_STATFS) +#ifdef STAT_STATFS_FS_DATA + if (statvfs(disks[disknum].path, &fsd) == -1) +#else + if (statvfs(disks[disknum].path, &vfs) == -1) +#endif + { + snmp_log(LOG_ERR, "Couldn't open device %s\n", + disks[disknum].device); + setPerrorstatus("statvfs dev/disk"); + return -1; + } +#ifdef STAT_STATFS_FS_DATA + vfs.f_blocks = fsd.fd_btot; + vfs.f_bfree = fsd.fd_bfree; + vfs.f_bavail = fsd.fd_bfreen; + vfs.f_bsize = 1024; /* Ultrix f_bsize is a VM parameter apparently. */ +#endif +#if defined(HAVE_ODS) + vfs.f_blocks = vfs.f_spare[0]; + vfs.f_bfree = vfs.f_spare[1]; + vfs.f_bavail = vfs.f_spare[2]; +#endif + + multiplier = (float)vfs.f_bsize / (float)1024.0; +#ifdef HAVE_STRUCT_STATVFS_F_FRSIZE + if (vfs.f_frsize > 255) + multiplier = (float)vfs.f_frsize / (float)1024.0; +#endif + + entry->dskTotal = (unsigned long long)(vfs.f_blocks * multiplier); + entry->dskAvail = (unsigned long long)(vfs.f_bavail * multiplier); + entry->dskUsed = (unsigned long long)((vfs.f_blocks - vfs.f_bfree) * multiplier); + + entry->dskPercent = + vfs.f_blocks == 0 ? 0 : + vfs.f_bavail <= 0 ? 100 : + (int) ((double) (vfs.f_blocks - vfs.f_bfree) / + (double) (vfs.f_blocks - + (vfs.f_bfree - vfs.f_bavail)) * 100.0 + 0.5); + +#if defined(HAVE_STRUCT_STATVFS_F_FILES) || defined HAVE_STRUCT_STATFS_F_FAVAIL + entry->dskPercentInode = vfs.f_favail <= 0 ? 100 : + (int) ((double) (vfs.f_files - vfs.f_ffree) / + (double) (vfs.f_files - + (vfs.f_ffree - vfs.f_favail)) * 100.0 + 0.5); +#else +#if defined(HAVE_STRUCT_STATFS_F_FILES) && defined(HAVE_STRUCT_STATFS_F_FFREE) + entry->dskPercentInode = vfs.f_files == 0 ? 100.0 : + (int) ((double) (vfs.f_files - vfs.f_ffree) / + (double) (vfs.f_files) * 100.0 + 0.5); +#endif +#endif /* defined(HAVE_STRUCT_STATVFS_F_FILES) */ + +#elif HAVE_FSTAB_H + /* + * read the disk information + */ + if ((file = open(disks[disknum].device, 0)) < 0) { + snmp_log(LOG_ERR, "Couldn't open device %s\n", + disks[disknum].device); + setPerrorstatus("open dev/disk"); + return -1; + } + lseek(file, (long) (SBLOCK * DEV_BSIZE), 0); + if (read(file, (char *) &filesys, SBSIZE) != SBSIZE) { + setPerrorstatus("open dev/disk"); + snmp_log(LOG_ERR, "Error reading device %s\n", + disks[disknum].device); + close(file); + return -1; + } + close(file); + + totalblks = filesys.fs_dsize; + free = filesys.fs_cstotal.cs_nbfree * filesys.fs_frag + + filesys.fs_cstotal.cs_nffree; + used = totalblks - free; + availblks = totalblks * (100 - filesys.fs_minfree) / 100; + avail = availblks > used ? availblks - used : 0; + entry->dskPercent = + totalblks == 0 ? 0 : + availblks == 0 ? 100 : + (int) ((double) used / (double) totalblks * 100.0 + 0.5); + multiplier = (float)filesys.fs_fsize / (float)1024.0; + entry->dskTotal = (unsigned long long)(totalblks * multiplier); + entry->dskAvail = (unsigned long long)(avail * multiplier); + entry->dskUsed = (unsigned long long)(used * multiplier); +#else + /* MinGW */ + entry->dskPercent = 0; + entry->dskTotal = 0; + entry->dskAvail = 0; + entry->dskUsed = 0; +#endif + + entry->dskErrorFlag = + (disks[disknum].minimumspace >= 0 + ? entry->dskAvail < (unsigned long long)disks[disknum].minimumspace + : 100 - entry->dskPercent <= (unsigned int)disks[disknum].minpercent) ? 1 : 0; + + return 0; +} + +/* + * var_extensible_disk(... + * 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 + * + */ +u_char * +var_extensible_disk(struct variable *vp, + oid * name, + size_t * length, + int exact, + size_t * var_len, WriteMethod ** write_method) +{ + int ret; + unsigned int disknum = 0; + struct dsk_entry entry; + static long long_ret; + static char *errmsg; + +tryAgain: + if (header_simple_table + (vp, name, length, exact, var_len, write_method, numdisks)) + return (NULL); + disknum = name[*length - 1] - 1; + if (disknum > maxdisks) + return NULL; + switch (vp->magic) { + case MIBINDEX: + long_ret = disknum + 1; + return ((u_char *) (&long_ret)); + case ERRORNAME: /* DISKPATH */ + *var_len = strlen(disks[disknum].path); + return ((u_char *) disks[disknum].path); + case DISKDEVICE: + *var_len = strlen(disks[disknum].device); + return ((u_char *) disks[disknum].device); + case DISKMINIMUM: + long_ret = disks[disknum].minimumspace; + return ((u_char *) (&long_ret)); + case DISKMINPERCENT: + long_ret = disks[disknum].minpercent; + return ((u_char *) (&long_ret)); + } + + ret = fill_dsk_entry(disknum, &entry); + if (ret < 0) { + if (!exact) + goto tryAgain; + return NULL; + } + + switch (vp->magic) { + case DISKTOTAL: + if (entry.dskTotal > MAX_INT_32) + long_ret = MAX_INT_32; + else + long_ret = (long)(entry.dskTotal); + return ((u_char *) (&long_ret)); + case DISKTOTALLOW: + long_ret = entry.dskTotal & MAX_UINT_32; + return ((u_char *) (&long_ret)); + case DISKTOTALHIGH: + long_ret = entry.dskTotal >> 32; + return ((u_char *) (&long_ret)); + + case DISKAVAIL: + if (entry.dskAvail > MAX_INT_32) + long_ret = MAX_INT_32; + else + long_ret = (long)(entry.dskAvail); + return ((u_char *) (&long_ret)); + case DISKAVAILLOW: + long_ret = entry.dskAvail & MAX_UINT_32; + return ((u_char *) (&long_ret)); + case DISKAVAILHIGH: + long_ret = entry.dskAvail >> 32; + return ((u_char *) (&long_ret)); + + case DISKUSED: + if (entry.dskUsed > MAX_INT_32) + long_ret = MAX_INT_32; + else + long_ret = (long)(entry.dskUsed); + return ((u_char *) (&long_ret)); + case DISKUSEDLOW: + long_ret = entry.dskUsed & MAX_UINT_32; + return ((u_char *) (&long_ret)); + case DISKUSEDHIGH: + long_ret = entry.dskUsed >> 32; + return ((u_char *) (&long_ret)); + + case DISKPERCENT: + long_ret = entry.dskPercent; + return ((u_char *) (&long_ret)); + + case DISKPERCENTNODE: + long_ret = entry.dskPercentInode; + return ((u_char *) (&long_ret)); + + case ERRORFLAG: + long_ret = entry.dskErrorFlag; + return ((u_char *) (&long_ret)); + + case ERRORMSG: + free(errmsg); + errmsg = NULL; + *var_len = 0; + if (entry.dskErrorFlag) { + if ((disks[disknum].minimumspace >= 0 && + asprintf(&errmsg, "%s: less than %d free (= %d)", + disks[disknum].path, disks[disknum].minimumspace, + (int) entry.dskAvail) >= 0) || + (disks[disknum].minimumspace < 0 && + asprintf(&errmsg, "%s: less than %d%% free (= %d%%)", + disks[disknum].path, disks[disknum].minpercent, + (int)entry.dskPercent) >= 0)) { + *var_len = strlen(errmsg); + } + } + return (u_char *) (errmsg); + } + return NULL; +}