summaryrefslogtreecommitdiff
path: root/src/pmdas/mounts/mounts.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pmdas/mounts/mounts.c')
-rw-r--r--src/pmdas/mounts/mounts.c384
1 files changed, 384 insertions, 0 deletions
diff --git a/src/pmdas/mounts/mounts.c b/src/pmdas/mounts/mounts.c
new file mode 100644
index 0000000..44ec6d7
--- /dev/null
+++ b/src/pmdas/mounts/mounts.c
@@ -0,0 +1,384 @@
+/*
+ * Mounts, info on current mounts
+ *
+ * Copyright (c) 2012 Red Hat.
+ * Copyright (c) 2001,2003,2004 Silicon Graphics, Inc. All Rights Reserved.
+ * Copyright (c) 2001 Alan Bailey (bailey@mcs.anl.gov or abailey@ncsa.uiuc.edu)
+ * for the portions of the code supporting the initial agent functionality.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+#include "pmapi.h"
+#include "impl.h"
+#include "pmda.h"
+#include "domain.h"
+#include <dirent.h>
+#include <sys/stat.h>
+
+/*
+ * Mounts PMDA
+ *
+ * Metrics
+ * mounts.device
+ * The device which the mount is mounted on
+ * mounts.type
+ * The type of filesystem
+ * mounts.options
+ * The mounting options
+ * mounts.up
+ * always equals 1
+ */
+
+/*
+ * all metrics supported in this PMDA - one table entry for each
+ */
+
+#ifdef IS_SOLARIS
+#define MOUNT_FILE "/etc/vfstab"
+#else
+#define MOUNT_FILE "/proc/mounts"
+#endif
+
+static pmdaInstid *mounts;
+
+static pmdaIndom indomtab[] = {
+#define MOUNTS_INDOM 0
+ { MOUNTS_INDOM, 0, NULL }
+};
+
+static pmdaMetric metrictab[] = {
+/* mounts.device */
+ { NULL,
+ { PMDA_PMID(0,0), PM_TYPE_STRING, MOUNTS_INDOM, PM_SEM_INSTANT,
+ PMDA_PMUNITS(0,0,0,0,0,0) }, },
+/* mounts.type */
+ { NULL,
+ { PMDA_PMID(0,1), PM_TYPE_STRING, MOUNTS_INDOM, PM_SEM_INSTANT,
+ PMDA_PMUNITS(0,0,0,0,0,0) }, },
+/* mounts.options */
+ { NULL,
+ { PMDA_PMID(0,2), PM_TYPE_STRING, MOUNTS_INDOM, PM_SEM_INSTANT,
+ PMDA_PMUNITS(0,0,0,0,0,0) }, },
+/* mounts.up */
+ { NULL,
+ { PMDA_PMID(0,3), PM_TYPE_DOUBLE, MOUNTS_INDOM, PM_SEM_INSTANT,
+ PMDA_PMUNITS(0,0,0,0,0,0) }, },
+};
+
+typedef struct {
+ int up;
+ char device[100];
+ char type[100];
+ char options[100];
+} mountinfo;
+
+static mountinfo *mount_list;
+static struct stat file_change;
+static int isDSO = 1;
+static char mypath[MAXPATHLEN];
+static char *username;
+
+static void mounts_clear_config_info(void);
+static void mounts_grab_config_info(void);
+static void mounts_config_file_check(void);
+static void mounts_refresh_mounts(void);
+
+static void
+mounts_config_file_check(void)
+{
+ struct stat statbuf;
+ static int last_error;
+ int sep = __pmPathSeparator();
+
+ snprintf(mypath, sizeof(mypath), "%s%c" "mounts" "%c" "mounts.conf",
+ pmGetConfig("PCP_PMDAS_DIR"), sep, sep);
+ if (stat(mypath, &statbuf) == -1) {
+ if (oserror() != last_error) {
+ last_error = oserror();
+ __pmNotifyErr(LOG_WARNING, "stat failed on %s: %s\n",
+ mypath, pmErrStr(last_error));
+ }
+ } else {
+ last_error = 0;
+#if defined(HAVE_ST_MTIME_WITH_E)
+ if (statbuf.st_mtime != file_change.st_mtime)
+#elif defined(HAVE_ST_MTIME_WITH_SPEC)
+ if (statbuf.st_mtimespec.tv_sec != file_change.st_mtimespec.tv_sec ||
+ statbuf.st_mtimespec.tv_nsec != file_change.st_mtimespec.tv_nsec)
+#else
+ if (statbuf.st_mtim.tv_sec != file_change.st_mtim.tv_sec ||
+ statbuf.st_mtim.tv_nsec != file_change.st_mtim.tv_nsec)
+#endif
+ {
+ mounts_clear_config_info();
+ mounts_grab_config_info();
+ file_change = statbuf;
+ }
+ }
+}
+
+static void
+mounts_clear_config_info(void)
+{
+ int i;
+
+ /* Free the memory holding the mount name */
+ for (i = 0; i < indomtab[MOUNTS_INDOM].it_numinst; i++) {
+ free(mounts[i].i_name);
+ mounts[i].i_name = NULL;
+ }
+
+ /* Free the mounts structure */
+ if (mounts)
+ free(mounts);
+
+ /* Free the mount_list structure */
+ if (mount_list)
+ free(mount_list);
+
+ mount_list = NULL;
+ indomtab[MOUNTS_INDOM].it_set = mounts = NULL;
+ indomtab[MOUNTS_INDOM].it_numinst = 0;
+}
+
+/*
+ * This routine opens the config file and stores the information in the
+ * mounts structure. The mounts structure must be reallocated as
+ * necessary, and also the num_procs structure needs to be reallocated
+ * as we define new mounts. When all of that is done, we fill in the
+ * values in the indomtab structure, those being the number of instances
+ * and the pointer to the mounts structure.
+ */
+static void
+mounts_grab_config_info(void)
+{
+ FILE *fp;
+ char mount_name[MAXPATHLEN];
+ char *q;
+ size_t size;
+ int mount_number = 0;
+ int sep = __pmPathSeparator();
+
+ snprintf(mypath, sizeof(mypath), "%s%c" "mounts" "%c" "mounts.conf",
+ pmGetConfig("PCP_PMDAS_DIR"), sep, sep);
+ if ((fp = fopen(mypath, "r")) == NULL) {
+ __pmNotifyErr(LOG_ERR, "fopen on %s failed: %s\n",
+ mypath, pmErrStr(-oserror()));
+ if (mounts) {
+ free(mounts);
+ mounts = NULL;
+ mount_number = 0;
+ }
+ goto done;
+ }
+
+ while (fgets(mount_name, sizeof(mount_name), fp) != NULL) {
+ if (mount_name[0] == '#')
+ continue;
+ /* Remove the newline */
+ if ((q = strchr(mount_name, '\n')) != NULL) {
+ *q = '\0';
+ } else {
+ /* This means the line was too long */
+ __pmNotifyErr(LOG_WARNING, "line %d in the config file too long\n",
+ mount_number+1);
+ }
+ size = (mount_number + 1) * sizeof(pmdaInstid);
+ if ((mounts = realloc(mounts, size)) == NULL)
+ __pmNoMem("process", size, PM_FATAL_ERR);
+ mounts[mount_number].i_name = malloc(strlen(mount_name) + 1);
+ strcpy(mounts[mount_number].i_name, mount_name);
+ mounts[mount_number].i_inst = mount_number;
+ mount_number++;
+ }
+ fclose(fp);
+
+done:
+ if (mounts == NULL)
+ __pmNotifyErr(LOG_WARNING, "\"mounts\" instance domain is empty");
+ indomtab[MOUNTS_INDOM].it_set = mounts;
+ indomtab[MOUNTS_INDOM].it_numinst = mount_number;
+ mount_list = realloc(mount_list, (mount_number)*sizeof(mountinfo));
+}
+
+static void
+mounts_refresh_mounts(void)
+{
+ FILE *fd;
+ char device[100];
+ char mount[100];
+ char type[100];
+ char options[100];
+ char junk[10];
+ int item;
+ int mount_name;
+
+ /* Clear the variables */
+ for(item = 0; item < indomtab[MOUNTS_INDOM].it_numinst; item++) {
+ strcpy(mount_list[item].device, "none");
+ strcpy(mount_list[item].type, "none");
+ strcpy(mount_list[item].options, "none");
+ mount_list[item].up = 0;
+ }
+
+ if ((fd = fopen(MOUNT_FILE, "r")) != NULL) {
+#ifdef IS_SOLARIS
+ char device_to_fsck[100];
+ char fsck_pass[100];
+ char mount_at_boot[100];
+
+ while ((fscanf(fd, "%s %s %s %s %s %s %s",
+ device, device_to_fsck, mount, type, fsck_pass,
+ mount_at_boot, options)) == 7)
+#else
+ while ((fscanf(fd, "%s %s %s %s", device, mount, type, options)) == 4)
+#endif
+ {
+ if (fgets(junk, sizeof(junk), fd) == NULL) {
+ /* early EOF? will be caught in next iteration */
+ ;
+ }
+
+ for (mount_name = 0;
+ mount_name < indomtab[MOUNTS_INDOM].it_numinst;
+ mount_name++) {
+ if (strcmp(mount, (mounts[mount_name]).i_name) == 0) {
+ strcpy(mount_list[mount_name].device, device);
+ strcpy(mount_list[mount_name].type, type);
+ strcpy(mount_list[mount_name].options, options);
+ mount_list[mount_name].up = 1;
+ }
+ }
+ memset(device, 0, sizeof(device));
+ memset(mount, 0, sizeof(mount));
+ memset(type, 0, sizeof(type));
+ memset(options, 0, sizeof(options));
+ }
+ fclose(fd);
+ }
+}
+
+/*
+ * This is the wrapper over the pmdaFetch routine, to handle the problem
+ * of varying instance domains. All this does is delete the previous
+ * mount list, and then get the current one, by calling
+ * mounts_refresh_mounts.
+ */
+static int
+mounts_fetch(int numpmid, pmID pmidlist[], pmResult **resp, pmdaExt *pmda)
+{
+ mounts_config_file_check();
+ mounts_refresh_mounts();
+ return pmdaFetch(numpmid, pmidlist, resp, pmda);
+}
+
+/*
+ * callback provided to pmdaFetch
+ */
+static int
+mounts_fetchCallBack(pmdaMetric *mdesc, unsigned int inst, pmAtomValue *atom)
+{
+ __pmID_int *idp = (__pmID_int *)&(mdesc->m_desc.pmid);
+
+ if (idp->cluster != 0)
+ return PM_ERR_PMID;
+ if (inst >= indomtab[MOUNTS_INDOM].it_numinst)
+ return PM_ERR_INST;
+
+ if (idp->item == 0)
+ atom->cp = (mount_list[inst]).device;
+ else if (idp->item == 1)
+ atom->cp = (mount_list[inst]).type;
+ else if (idp->item == 2)
+ atom->cp = (mount_list[inst]).options;
+ else if (idp->item == 3)
+ atom->d = (mount_list[inst]).up;
+ else
+ return PM_ERR_PMID;
+ return 0;
+}
+
+/*
+ * Initialise the agent (both daemon and DSO).
+ */
+void
+mounts_init(pmdaInterface *dp)
+{
+ if (isDSO) {
+ int sep = __pmPathSeparator();
+ snprintf(mypath, sizeof(mypath), "%s%c" "mounts" "%c" "help",
+ pmGetConfig("PCP_PMDAS_DIR"), sep, sep);
+ pmdaDSO(dp, PMDA_INTERFACE_2, "mounts DSO", mypath);
+ } else {
+ __pmSetProcessIdentity(username);
+ }
+
+ if (dp->status != 0)
+ return;
+
+ dp->version.two.fetch = mounts_fetch;
+ pmdaSetFetchCallBack(dp, mounts_fetchCallBack);
+
+ pmdaInit(dp, indomtab, sizeof(indomtab)/sizeof(indomtab[0]),
+ metrictab, sizeof(metrictab)/sizeof(metrictab[0]));
+
+ /* Let's grab the info right away just to make sure it's there. */
+ mounts_grab_config_info();
+}
+
+pmLongOptions longopts[] = {
+ PMDA_OPTIONS_HEADER("Options"),
+ PMOPT_DEBUG,
+ PMDAOPT_DOMAIN,
+ PMDAOPT_LOGFILE,
+ PMDAOPT_USERNAME,
+ PMOPT_HELP,
+ PMDA_OPTIONS_END
+};
+
+pmdaOptions opts = {
+ .short_options = "D:d:l:U:?",
+ .long_options = longopts,
+};
+
+/*
+ * Set up the agent if running as a daemon.
+ */
+int
+main(int argc, char **argv)
+{
+ int sep = __pmPathSeparator();
+ pmdaInterface desc;
+
+ isDSO = 0;
+ __pmSetProgname(argv[0]);
+ __pmGetUsername(&username);
+
+ snprintf(mypath, sizeof(mypath), "%s%c" "mounts" "%c" "help",
+ pmGetConfig("PCP_PMDAS_DIR"), sep, sep);
+ pmdaDaemon(&desc, PMDA_INTERFACE_2, pmProgname, MOUNTS,
+ "mounts.log", mypath);
+
+ pmdaGetOptions(argc, argv, &opts, &desc);
+ if (opts.errors) {
+ pmdaUsageMessage(&opts);
+ exit(1);
+ }
+ if (opts.username)
+ username = opts.username;
+
+ pmdaOpenLog(&desc);
+ mounts_init(&desc);
+ pmdaConnect(&desc);
+ pmdaMain(&desc);
+ exit(0);
+}