From 76dc4d3055400e59c453ed1ffbfa70c0a28eae15 Mon Sep 17 00:00:00 2001 From: octo Date: Mon, 12 Dec 2005 07:36:03 +0000 Subject: [PATCH] Copied src/utils_mount.[ch] from quota-branch to trunk --- src/utils_mount.c | 694 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/utils_mount.h | 190 +++++++++++++++ 2 files changed, 884 insertions(+) create mode 100644 src/utils_mount.c create mode 100644 src/utils_mount.h diff --git a/src/utils_mount.c b/src/utils_mount.c new file mode 100644 index 00000000..ecfd0ec6 --- /dev/null +++ b/src/utils_mount.c @@ -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 +**/ + + + +#include "common.h" +#if HAVE_XFS_XQM_H +# include +#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 index 00000000..822f786e --- /dev/null +++ b/src/utils_mount.h @@ -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 +**/ + +/* 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 +#endif +#if HAVE_FSHELP_H +# include +#endif +#if HAVE_PATHS_H +# include +#endif +#if HAVE_MNTENT_H +# include +#endif +#if HAVE_MNTTAB_H +# include +#endif +#if HAVE_SYS_FSTYP_H +# include +#endif +#if HAVE_SYS_FS_TYPES_H +# include +#endif +#if HAVE_SYS_MNTENT_H +# include +#endif +#if HAVE_SYS_MNTTAB_H +# include +#endif +#if HAVE_SYS_MOUNT_H +# include +#endif +#if HAVE_SYS_STATFS_H +# include +#endif +#if HAVE_SYS_VFS_H +# include +#endif +#if HAVE_SYS_VFSTAB_H +# include +#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 */ + -- 2.11.0