Code

Copied src/utils_mount.[ch] from quota-branch to trunk
authorocto <octo>
Mon, 12 Dec 2005 07:36:03 +0000 (07:36 +0000)
committerocto <octo>
Mon, 12 Dec 2005 07:36:03 +0000 (07:36 +0000)
src/utils_mount.c [new file with mode: 0644]
src/utils_mount.h [new file with mode: 0644]

diff --git a/src/utils_mount.c b/src/utils_mount.c
new file mode 100644 (file)
index 0000000..ecfd0ec
--- /dev/null
@@ -0,0 +1,694 @@
+/**
+ * collectd - src/utils_mount.c
+ * Copyright (C) 2005  Niki W. Waibel
+ *
+ * This program is free software; you can redistribute it and/
+ * or modify it under the terms of the GNU General Public Li-
+ * cence as published by the Free Software Foundation; either
+ * version 2 of the Licence, or any later version.
+ *
+ * This program is distributed in the hope that it will be use-
+ * ful, but WITHOUT ANY WARRANTY; without even the implied war-
+ * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public Licence for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * Licence along with this program; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+ * USA.
+ *
+ * Author:
+ *   Niki W. Waibel <niki.waibel@gmx.net>
+**/
+
+
+
+#include "common.h"
+#if HAVE_XFS_XQM_H
+# include <xfs/xqm.h>
+#define XFS_SUPER_MAGIC_STR "XFSB"
+#define XFS_SUPER_MAGIC2_STR "BSFX"
+#endif
+#include "utils_debug.h"
+#include "utils_mount.h"
+
+
+
+/* *** *** *** ********************************************* *** *** *** */
+/* *** *** *** *** *** ***   private functions   *** *** *** *** *** *** */
+/* *** *** *** ********************************************* *** *** *** */
+
+
+
+/* stolen from quota-3.13 (quota-tools) */
+
+#define PROC_PARTITIONS "/proc/partitions"
+#define DEVLABELDIR     "/dev"
+#define UUID   1
+#define VOL    2
+
+static struct uuidCache_s {
+       struct uuidCache_s *next;
+       char uuid[16];
+       char *label;
+       char *device;
+} *uuidCache = NULL;
+
+#define EXT2_SUPER_MAGIC 0xEF53
+struct ext2_super_block {
+       unsigned char s_dummy1[56];
+       unsigned char s_magic[2];
+       unsigned char s_dummy2[46];
+       unsigned char s_uuid[16];
+       char s_volume_name[16];
+};
+#define ext2magic(s) ((unsigned int)s.s_magic[0] \
+       + (((unsigned int)s.s_magic[1]) << 8))
+
+#if HAVE_XFS_XQM_H
+struct xfs_super_block {
+       unsigned char s_magic[4];
+       unsigned char s_dummy[28];
+       unsigned char s_uuid[16];
+       unsigned char s_dummy2[60];
+       char s_fsname[12];
+};
+#endif /* HAVE_XFS_XQM_H */
+
+#define REISER_SUPER_MAGIC "ReIsEr2Fs"
+struct reiserfs_super_block {
+       unsigned char s_dummy1[52];
+       unsigned char s_magic[10];
+       unsigned char s_dummy2[22];
+       unsigned char s_uuid[16];
+       char s_volume_name[16];
+};
+
+/* for now, only ext2 and xfs are supported */
+static int
+get_label_uuid(const char *device, char **label, char *uuid)
+{
+       /* start with ext2 and xfs tests, taken from mount_guess_fstype */
+       /* should merge these later */
+       int fd, rv = 1;
+       size_t namesize;
+       struct ext2_super_block e2sb;
+#if HAVE_XFS_XQM_H
+       struct xfs_super_block xfsb;
+#endif
+       struct reiserfs_super_block reisersb;
+
+       fd = open(device, O_RDONLY);
+       if(fd == -1) {
+               return rv;
+       }
+
+       if(lseek(fd, 1024, SEEK_SET) == 1024
+       && read(fd, (char *)&e2sb, sizeof(e2sb)) == sizeof(e2sb)
+       && ext2magic(e2sb) == EXT2_SUPER_MAGIC) {
+               memcpy(uuid, e2sb.s_uuid, sizeof(e2sb.s_uuid));
+               namesize = sizeof(e2sb.s_volume_name);
+               *label = smalloc(namesize + 1);
+               sstrncpy(*label, e2sb.s_volume_name, namesize);
+               rv = 0;
+#if HAVE_XFS_XQM_H
+       } else if(lseek(fd, 0, SEEK_SET) == 0
+       && read(fd, (char *)&xfsb, sizeof(xfsb)) == sizeof(xfsb)
+       && (strncmp((char *)&xfsb.s_magic, XFS_SUPER_MAGIC_STR, 4) == 0 ||
+       strncmp((char *)&xfsb.s_magic, XFS_SUPER_MAGIC2_STR, 4) == 0)) {
+               memcpy(uuid, xfsb.s_uuid, sizeof(xfsb.s_uuid));
+               namesize = sizeof(xfsb.s_fsname);
+               *label = smalloc(namesize + 1);
+               sstrncpy(*label, xfsb.s_fsname, namesize);
+               rv = 0;
+#endif /* HAVE_XFS_XQM_H */
+       } else if(lseek(fd, 65536, SEEK_SET) == 65536
+       && read(fd, (char *)&reisersb, sizeof(reisersb)) == sizeof(reisersb)
+       && !strncmp((char *)&reisersb.s_magic, REISER_SUPER_MAGIC, 9)) {
+               memcpy(uuid, reisersb.s_uuid, sizeof(reisersb.s_uuid));
+               namesize = sizeof(reisersb.s_volume_name);
+               *label = smalloc(namesize + 1);
+               sstrncpy(*label, reisersb.s_volume_name, namesize);
+               rv = 0;
+       }
+       close(fd);
+       return rv;
+}
+
+static void
+uuidcache_addentry(char *device, char *label, char *uuid)
+{
+       struct uuidCache_s *last;
+
+       if(!uuidCache) {
+               last = uuidCache = smalloc(sizeof(*uuidCache));
+       } else {
+               for(last = uuidCache; last->next; last = last->next);
+               last->next = smalloc(sizeof(*uuidCache));
+               last = last->next;
+       }
+       last->next = NULL;
+       last->device = device;
+       last->label = label;
+       memcpy(last->uuid, uuid, sizeof(last->uuid));
+}
+
+static void
+uuidcache_init(void)
+{
+       char line[100];
+       char *s;
+       int ma, mi, sz;
+       static char ptname[100];
+       FILE *procpt;
+       char uuid[16], *label = NULL;
+       char device[110];
+       int firstPass;
+       int handleOnFirst;
+
+       if(uuidCache) {
+               return;
+       }
+
+       procpt = fopen(PROC_PARTITIONS, "r");
+       if(procpt == NULL) {
+               return;
+       }
+
+       for(firstPass = 1; firstPass >= 0; firstPass--) {
+               fseek(procpt, 0, SEEK_SET);
+               while(fgets(line, sizeof(line), procpt)) {
+                       if(sscanf(line, " %d %d %d %[^\n ]",
+                               &ma, &mi, &sz, ptname) != 4)
+                       {
+                               continue;
+                       }
+
+                       /* skip extended partitions (heuristic: size 1) */
+                       if(sz == 1) {
+                               continue;
+                       }
+
+                       /* look only at md devices on first pass */
+                       handleOnFirst = !strncmp(ptname, "md", 2);
+                       if(firstPass != handleOnFirst) {
+                               continue;
+                       }
+
+                       /* skip entire disk (minor 0, 64, ... on ide;
+                       0, 16, ... on sd) */
+                       /* heuristic: partition name ends in a digit */
+
+                       for(s = ptname; *s; s++);
+
+                       if(isdigit((int)s[-1])) {
+                       /*
+                       * Note: this is a heuristic only - there is no reason
+                       * why these devices should live in /dev.
+                       * Perhaps this directory should be specifiable by option.
+                       * One might for example have /devlabel with links to /dev
+                       * for the devices that may be accessed in this way.
+                       * (This is useful, if the cdrom on /dev/hdc must not
+                       * be accessed.)
+                       */
+                               snprintf(device, sizeof(device), "%s/%s",
+                                       DEVLABELDIR, ptname);
+                               if(!get_label_uuid(device, &label, uuid)) {
+                                       uuidcache_addentry(sstrdup(device),
+                                               label, uuid);
+                               }
+                       }
+               }
+       }
+       fclose(procpt);
+}
+
+static unsigned char
+fromhex(char c)
+{
+       if(isdigit((int)c)) {
+               return (c - '0');
+       } else if(islower((int)c)) {
+               return (c - 'a' + 10);
+       } else {
+               return (c - 'A' + 10);
+       }
+}
+
+static char *
+get_spec_by_x(int n, const char *t)
+{
+       struct uuidCache_s *uc;
+
+       uuidcache_init();
+       uc = uuidCache;
+
+       while(uc) {
+               switch(n) {
+               case UUID:
+                       if(!memcmp(t, uc->uuid, sizeof(uc->uuid))) {
+                               return sstrdup(uc->device);
+                       }
+                       break;
+               case VOL:
+                       if(!strcmp(t, uc->label)) {
+                               return sstrdup(uc->device);
+                       }
+                       break;
+               }
+               uc = uc->next;
+       }
+       return NULL;
+}
+
+static char *
+get_spec_by_uuid(const char *s)
+{
+       char uuid[16];
+       int i;
+
+       if(strlen(s) != 36
+       || s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-') {
+               goto bad_uuid;
+       }
+
+       for(i=0; i<16; i++) {
+               if(*s == '-') {
+                       s++;
+               }
+               if(!isxdigit((int)s[0]) || !isxdigit((int)s[1])) {
+                       goto bad_uuid;
+               }
+               uuid[i] = ((fromhex(s[0]) << 4) | fromhex(s[1]));
+               s += 2;
+       }
+       return get_spec_by_x(UUID, uuid);
+
+       bad_uuid:
+               DBG("Found an invalid UUID: %s", s);
+       return NULL;
+}
+
+static char *
+get_spec_by_volume_label(const char *s)
+{
+        return get_spec_by_x(VOL, s);
+}
+
+static char *
+get_device_name(const char *item)
+{
+       char *rc;
+
+       if(!strncmp(item, "UUID=", 5)) {
+               DBG("TODO: check UUID= code!");
+               rc = get_spec_by_uuid(item + 5);
+       } else if(!strncmp(item, "LABEL=", 6)) {
+               DBG("TODO: check LABEL= code!");
+               rc = get_spec_by_volume_label(item + 6);
+       } else {
+               rc = sstrdup(item);
+       }
+       if(!rc) {
+               DBG("Error checking device name: %s", item);
+       }
+       return rc;
+}
+
+
+
+#if HAVE_GETVFSENT
+static void
+cu_mount_getvfsmnt(FILE *mntf, cu_mount_t **list)
+{
+       DBG("TODO: getvfsmnt");
+       *list = NULL;
+}
+#endif /* HAVE_GETVFSENT */
+
+
+
+#if HAVE_LISTMNTENT
+static cu_mount_t *
+cu_mount_listmntent(struct tabmntent *mntlist, cu_mount_t **list)
+{
+       cu_mount_t *last = *list;
+       struct tabmntent *p;
+       struct mntent *mnt;
+
+       for(p = mntlist; p; p = p->next) {
+               char *loop = NULL, *device = NULL;
+
+               mnt = p->ment;
+               loop = cu_mount_getoptionvalue(mnt->mnt_opts, "loop=");
+               if(loop == NULL) {   /* no loop= mount */
+                       device = get_device_name(mnt->mnt_fsname);
+                       if(device == NULL) {
+                               DBG("can't get devicename for fs (%s) %s (%s)"
+                                       ": ignored", mnt->mnt_type,
+                                       mnt->mnt_dir, mnt->mnt_fsname);
+                               continue;
+                       }
+               } else {
+                       device = loop;
+               }
+               if(*list == NULL) {
+                       *list = (cu_mount_t *)smalloc(sizeof(cu_mount_t));
+                       last = *list;
+               } else {
+                       while(last->next != NULL) { /* is last really last? */
+                               last = last->next;
+                       }
+                       last->next = (cu_mount_t *)smalloc(sizeof(cu_mount_t));
+                       last = last->next;
+               }
+               last->dir = sstrdup(mnt->mnt_dir);
+               last->spec_device = sstrdup(mnt->mnt_fsname);
+               last->device = device;
+               last->type = sstrdup(mnt->mnt_type);
+               last->options = sstrdup(mnt->mnt_opts);
+               last->next = NULL;
+       } /* for(p = mntlist; p; p = p->next) */
+
+       return(last);
+} /* static cu_mount_t *cu_mount_listmntent(struct tabmntent *mntlist,
+       cu_mount_t **list) */
+#endif /* HAVE_LISTMNTENT */
+
+
+
+#if HAVE_GETMNTENT
+static cu_mount_t *
+cu_mount_getmntent(FILE *mntf, cu_mount_t **list)
+{
+       cu_mount_t *last = *list;
+#if HAVE_GETMNTENT1
+       struct mntent *mnt = NULL;
+#endif
+#if HAVE_GETMNTENT2
+       struct mntent real_mnt;
+       struct mntent *mnt = &real_mnt;
+#endif
+
+#if HAVE_GETMNTENT1
+       while((mnt = getmntent(mntf)) != NULL) {
+#endif
+#if HAVE_GETMNTENT2
+       while(getmntent(mntf, &real_mnt) == 0) {
+#endif
+               char *loop = NULL, *device = NULL;
+
+#if 0
+               DBG("------------------ BEGIN");
+               DBG("mnt->mnt_fsname %s", mnt->mnt_fsname);
+               DBG("mnt->mnt_dir    %s", mnt->mnt_dir);
+               DBG("mnt->mnt_type   %s", mnt->mnt_type);
+               DBG("mnt->mnt_opts   %s", mnt->mnt_opts);
+               DBG("mnt->mnt_freq   %d", mnt->mnt_freq);
+               DBG("mnt->mnt_passno %d", mnt->mnt_passno);
+#endif
+
+               loop = cu_mount_getoptionvalue(mnt->mnt_opts, "loop=");
+               if(loop == NULL) {   /* no loop= mount */
+                       device = get_device_name(mnt->mnt_fsname);
+                       if(device == NULL) {
+                               DBG("can't get devicename for fs (%s) %s (%s)"
+                                       ": ignored", mnt->mnt_type,
+                                       mnt->mnt_dir, mnt->mnt_fsname);
+                               continue;
+                       }
+               } else {
+                       device = loop;
+               }
+
+#if 0
+               DBG("device: %s", device);
+               DBG("------------------ END");
+#endif
+               if(*list == NULL) {
+                       *list = (cu_mount_t *)smalloc(sizeof(cu_mount_t));
+                       last = *list;
+               } else {
+                       while(last->next != NULL) { /* is last really last? */
+                               last = last->next;
+                       }
+                       last->next = (cu_mount_t *)smalloc(sizeof(cu_mount_t));
+                       last = last->next;
+               }
+               last->dir = sstrdup(mnt->mnt_dir);
+               last->spec_device = sstrdup(mnt->mnt_fsname);
+               last->device = device;
+               last->type = sstrdup(mnt->mnt_type);
+               last->options = sstrdup(mnt->mnt_opts);
+               last->next = NULL;
+#if HAVE_GETMNTENT2
+       } /* while(getmntent(mntf, &real_mnt) == 0) */
+#endif
+#if HAVE_GETMNTENT1
+       } /* while((mnt = getmntent(mntf)) != NULL) */
+#endif
+
+       return last;
+} /* static cu_mount_t *cu_mount_getmntent(FILE *mntf, cu_mount_t **list) */
+#endif /* HAVE_GETMNTENT */
+
+
+
+/* *** *** *** ******************************************** *** *** *** */
+/* *** *** *** *** *** ***   public functions   *** *** *** *** *** *** */
+/* *** *** *** ******************************************** *** *** *** */
+
+
+
+cu_mount_t *
+cu_mount_getlist(cu_mount_t **list)
+{
+       cu_mount_t *last = NULL;
+
+       /* see lib/mountlist.c of coreutils for all (ugly) details! */
+
+/*
+   there are two implementations of getmntent():
+     * one argument getmntent:
+           FILE *setmntent(const char *filename, const char *type);
+           struct mntent *getmntent(FILE *fp);
+           int endmntent(FILE *fp);
+     * two argument getmntent:
+           FILE *fopen(const char *path, const char *mode);
+           int getmntent(FILE *fp, struct mnttab *mnt);
+           int fclose(FILE *fp);
+   and a third (linux/gnu style) version called getmntent_r, which is not used
+   here (enough trouble with the two versions above).
+*/
+#if HAVE_GETMNTENT
+# if HAVE_GETMNTENT1
+#  define setmntent setmntent
+#  define endmntent endmntent
+# else
+#  if HAVE_GETMNTENT2
+#   define setmntent fopen
+#   define endmntent fclose
+#  else
+#   error HAVE_GETMNTENT defined, but neither HAVE_GETMNTENT1 nor HAVE_GETMNTENT2
+#  endif /* HAVE_GETMNTENT2 */
+# endif /* HAVE_GETMNTENT1 */
+#endif /* HAVE_GETMNTENT */
+
+       /* the indentation is wrong. is there a better way to do this? */
+
+#if HAVE_GETMNTENT && defined(_PATH_MOUNTED)
+       {
+       FILE *mntf = NULL;
+       if((mntf = setmntent(_PATH_MOUNTED, "r")) == NULL) {
+               DBG("opening %s failed: %s", _PATH_MOUNTED, strerror(errno));
+#endif
+#if HAVE_GETMNTENT && defined(MNT_MNTTAB)
+       {
+       FILE *mntf = NULL;
+       if((mntf = setmntent(MNT_MNTTAB, "r")) == NULL) {
+               DBG("opening %s failed: %s", MNT_MNTTAB, strerror(errno));
+#endif
+#if HAVE_GETMNTENT && defined(MNTTABNAME)
+       {
+       FILE *mntf = NULL;
+       if((mntf = setmntent(MNTTABNAME, "r")) == NULL) {
+               DBG("opening %s failed: %s", MNTTABNAME, strerror(errno));
+#endif
+#if HAVE_LISTMNTENT
+       {
+       struct tabmntent *mntlist;
+       if(listmntent(&mntlist, KMTAB, NULL, NULL) < 0) {
+               DBG("calling listmntent() failed: %s", strerror(errno));
+#endif
+#if HAVE_GETVFSENT && defined(VFSTAB)
+       /* this is as bad as the next one, read next comment */
+       {
+       FILE *mntf = NULL;
+       if((mntf = fopen(VFSTAB, "r")) == NULL) {
+               DBG("opening %s failed: %s", VFSTAB, strerror(errno));
+#endif
+#if HAVE_GETMNTENT && defined(_PATH_MNTTAB)
+       /* _PATH_MNTTAB is usually /etc/fstab and so this should be really
+          the very last thing to try, because it does not provide a list
+          of currently mounted filesystems... */
+       {
+       FILE *mntf = NULL;
+       if((mntf = setmntent(_PATH_MNTTAB, "r")) == NULL) {
+               DBG("opening %s failed: %s", _PATH_MNTTAB, strerror(errno));
+#endif
+
+       /* give up */
+       DBG("failed get local mountpoints");
+       return(NULL);
+
+#if HAVE_GETMNTENT && defined(_PATH_MNTTAB)
+       } else { last = cu_mount_getmntent(mntf, list); }
+       (void)endmntent(mntf);
+       }
+#endif
+#if HAVE_GETVFSENT && defined(VFSTAB)
+       } else { last = cu_mount_getvfsmnt(mntf, list); }
+       (void)fclose(mntf);
+       }
+#endif
+#if HAVE_LISTMNTENT
+       } else { last = cu_mount_listmntent(mntlist, list); }
+       freemntlist(mntlist);
+       }
+#endif
+#if HAVE_GETMNTENT && defined(MNTTABNAME)
+       } else { last = cu_mount_getmntent(mntf, list); }
+       (void)endmntent(mntf);
+       }
+#endif
+#if HAVE_GETMNTENT && defined(MNT_MNTTAB)
+       } else { last = cu_mount_getmntent(mntf, list); }
+       (void)endmntent(mntf);
+       }
+#endif
+#if HAVE_GETMNTENT && defined(_PATH_MOUNTED)
+       } else { last = cu_mount_getmntent(mntf, list); }
+       (void)endmntent(mntf);
+       }
+#endif
+       return(last);
+} /* cu_mount_t *cu_mount_getlist(cu_mount_t **list) */
+
+
+
+void
+cu_mount_freelist(cu_mount_t *list)
+{
+       cu_mount_t *l = list, *p = NULL;
+
+       while(l != NULL) {
+               while(l->next != NULL) {
+                       p = l;
+                       l = l->next;
+               }
+               if(p != NULL) {
+                       p->next = NULL;
+               }
+               sfree(l->dir);
+               sfree(l->spec_device);
+               sfree(l->device);
+               sfree(l->type);
+               sfree(l->options);
+               p = NULL;
+               if(l != list) {
+                       sfree(l);
+                       l = list;
+               } else {
+                       sfree(l);
+                       l = NULL; /* done by sfree already */
+               }
+       } /* while(l != NULL) */
+} /* void cu_mount_freelist(cu_mount_t *list) */
+
+
+
+char *
+cu_mount_checkoption(char *line, char *keyword, int full)
+{
+       char *line2, *l2;
+       int l = strlen(keyword);
+       char *p1, *p2;
+
+       if(line == NULL || keyword == NULL) {
+               return NULL;
+       }
+       if(full != 0) {
+               full = 1;
+       }
+
+       line2 = sstrdup(line);
+       l2 = line2;
+       while(*l2 != '\0') {
+               if(*l2 == ',') {
+                       *l2 = '\0';
+               }
+               l2++;
+       }
+
+       p1 = line - 1;
+       p2 = strchr(line, ',');
+       do {
+               if(strncmp(line2+(p1-line)+1, keyword, l+full) == 0) {
+                       free(line2);
+                       return p1+1;
+               }
+               p1 = p2;
+               if(p1 != NULL) {
+                       p2 = strchr(p1+1, ',');
+               }
+       } while(p1 != NULL);
+
+       free(line2);
+       return NULL;
+} /* char *cu_mount_checkoption(char *line, char *keyword, int full) */
+
+
+
+char *
+cu_mount_getoptionvalue(char *line, char *keyword)
+{
+       char *r;
+
+       r = cu_mount_checkoption(line, keyword, 0);
+       if(r != NULL) {
+               char *p;
+               r += strlen(keyword);
+               p = strchr(r, ',');
+               if(p == NULL) {
+                       if(strlen(r) == 0) {
+                               return NULL;
+                       }
+                       return sstrdup(r);
+               } else {
+                       char *m;
+                       if((p-r) == 1) {
+                               return NULL;
+                       }
+                       m = (char *)smalloc(p-r+1);
+                       sstrncpy(m, r, p-r+1);
+                       return m;
+               }
+       }
+       return r;
+} /* char *cu_mount_getoptionvalue(char *line, char *keyword) */
+
+
+
+int
+cu_mount_type(const char *type)
+{
+       if(strcmp(type, "ext3") == 0) return CUMT_EXT3;
+       if(strcmp(type, "ext2") == 0) return CUMT_EXT2;
+       if(strcmp(type, "ufs")  == 0) return CUMT_UFS;
+       if(strcmp(type, "vxfs") == 0) return CUMT_VXFS;
+       if(strcmp(type, "zfs")  == 0) return CUMT_ZFS;
+       return CUMT_UNKNOWN;
+} /* int cu_mount_type(const char *type) */
+
+
+
diff --git a/src/utils_mount.h b/src/utils_mount.h
new file mode 100644 (file)
index 0000000..822f786
--- /dev/null
@@ -0,0 +1,190 @@
+/**
+ * collectd - src/utils_mount.h
+ * Copyright (C) 2005  Niki W. Waibel
+ *
+ * This program is free software; you can redistribute it and/
+ * or modify it under the terms of the GNU General Public Li-
+ * cence as published by the Free Software Foundation; either
+ * version 2 of the Licence, or any later version.
+ *
+ * This program is distributed in the hope that it will be use-
+ * ful, but WITHOUT ANY WARRANTY; without even the implied war-
+ * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public Licence for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * Licence along with this program; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+ * USA.
+ *
+ * Author:
+ *   Niki W. Waibel <niki.waibel@gmx.net>
+**/
+
+/* See below for instructions how to use the public functions. */
+
+#if !COLLECTD_UTILS_MOUNT_H
+#define COLLECTD_UTILS_MOUNT_H 1
+
+#include "common.h"
+
+#if HAVE_FS_INFO_H
+# include <fs_info.h>
+#endif
+#if HAVE_FSHELP_H
+# include <fshelp.h>
+#endif
+#if HAVE_PATHS_H
+# include <paths.h>
+#endif
+#if HAVE_MNTENT_H
+# include <mntent.h>
+#endif
+#if HAVE_MNTTAB_H
+# include <mnttab.h>
+#endif
+#if HAVE_SYS_FSTYP_H
+# include <sys/fstyp.h>
+#endif
+#if HAVE_SYS_FS_TYPES_H
+# include <sys/fs_types.h>
+#endif
+#if HAVE_SYS_MNTENT_H
+# include <sys/mntent.h>
+#endif
+#if HAVE_SYS_MNTTAB_H
+# include <sys/mnttab.h>
+#endif
+#if HAVE_SYS_MOUNT_H
+# include <sys/mount.h>
+#endif
+#if HAVE_SYS_STATFS_H
+# include <sys/statfs.h>
+#endif
+#if HAVE_SYS_VFS_H
+# include <sys/vfs.h>
+#endif
+#if HAVE_SYS_VFSTAB_H
+# include <sys/vfstab.h>
+#endif
+
+/* Collectd Utils Mount Type */
+#define CUMT_UNKNOWN (0)
+#define CUMT_EXT2    (1)
+#define CUMT_EXT3    (2)
+#define CUMT_XFS     (3)
+#define CUMT_UFS     (4)
+#define CUMT_VXFS    (5)
+#define CUMT_ZFS     (6)
+
+typedef struct _cu_mount_t cu_mount_t;
+struct _cu_mount_t {
+       char *dir;         /* "/sys" or "/" */
+       char *spec_device; /* "LABEL=/" or "none" or "proc" or "/dev/hda1" */
+       char *device;      /* "none" or "proc" or "/dev/hda1" */
+       char *type;        /* "sysfs" or "ext3" */
+       char *options;     /* "rw,noatime,commit=600,quota,grpquota" */
+       cu_mount_t *next;
+};
+
+cu_mount_t *cu_mount_getlist(cu_mount_t **list);
+/*
+  DESCRIPTION
+       The cu_mount_getlist() function creates a list
+       of all mountpoints.
+
+       If *list is NULL, a new list is created and *list is
+       set to point to the first entry.
+
+       If *list is not NULL, the list of mountpoints is appended
+       and *list is not changed.
+
+  RETURN VALUE
+       The cu_mount_getlist() function returns a pointer to
+       the last entry of the list, or NULL if an error has
+       occured.
+
+  NOTES
+       In case of an error, *list is not modified.
+*/
+
+void cu_mount_freelist(cu_mount_t *list);
+/*
+  DESCRIPTION
+       The cu_mount_freelist() function free()s all memory
+       allocated by *list and *list itself as well.
+*/
+
+char *cu_mount_checkoption(char *line, char *keyword, int full);
+/*
+  DESCRIPTION
+       The cu_mount_checkoption() function is a replacement of
+       char *hasmntopt(const struct mntent *mnt, const char *opt).
+       In fact hasmntopt() just looks for the first occurence of the
+       characters at opt in mnt->mnt_opts. cu_mount_checkoption()
+       checks for the *option* keyword in line, starting at the
+       first character of line or after a ','.
+
+       If full is not 0 then also the end of keyword has to match
+       either the end of line or a ',' after keyword.
+
+  RETURN VALUE
+       The cu_mount_checkoption() function returns a pointer into
+       string line if a match of keyword is found. If no match is
+       found cu_mount_checkoption() returns NULL.
+
+  NOTES
+       Do *not* try to free() the pointer which is returned! It is
+       just part of the string line.
+
+       full should be set to 0 when matching options like: rw, quota,
+       noatime. Set full to 1 when matching options like: loop=,
+       gid=, commit=.
+
+  EXAMPLES
+       If line is "rw,usrquota,grpquota", keyword is "quota", NULL
+       will be returned (independend of full).
+
+       If line is "rw,usrquota,grpquota", keyword is "usrquota",
+       a pointer to "usrquota,grpquota" is returned (independend
+       of full).
+
+       If line is "rw,loop=/dev/loop1,quota", keyword is "loop="
+       and full is 0, then a pointer to "loop=/dev/loop1,quota"
+       is returned. If full is not 0 then NULL is returned. But
+       maybe you might want to try cu_mount_getoptionvalue()...
+*/
+
+char *cu_mount_getoptionvalue(char *line, char *keyword);
+/*
+  DESCRIPTION
+       The cu_mount_getoptionvalue() function can be used to grab
+       a VALUE out of a mount option (line) like:
+               loop=VALUE
+       whereas "loop=" is the keyword.
+
+  RETURN VALUE
+       If the cu_mount_getoptionvalue() function can find the option
+       keyword in line, then memory is allocated for the value of
+       that option and a pointer to that value is returned.
+
+       If the option keyword is not found, cu_mount_getoptionvalue()
+       returns NULL;
+
+  NOTES
+       Internally it calls cu_mount_checkoption(), then it
+       allocates memory for VALUE and returns a pointer to that
+       string. So *do not forget* to free() the memory returned
+       after use!!!
+*/
+
+int cu_mount_type(const char *type);
+/*
+  DESCRIPTION
+
+  RETURN VALUE
+*/
+
+
+#endif /* !COLLECTD_UTILS_MOUNT_H */
+