From 912c3b58717f03453fedbb6c15482c052bdcd847 Mon Sep 17 00:00:00 2001 From: Xavier Hernandez Date: Tue, 10 Jan 2017 11:21:06 +0100 Subject: cli: keep 'gluster volume status detail' consistent The output of the command 'gluster volume status detail' is not consistent between operating systems. On linux hosts it shows the file system type, the device name, mount options and inode size of each brick. However the same command executed on a FreeBSD host doesn't show all this information, even for bricks stored on a linux. Additionally, for hosts other than linux, this information is shown as 'N/A' many times. This has been fixed to show as much information as it can be retrieved from the operating system. The file contrib/mount/mntent.c has been mostly rewriten because it contained many errors that caused mount information to not be retrieved on some operating systems. > Change-Id: Icb6e19e8af6ec82255e7792ad71914ef679fc316 > BUG: 1411334 > Signed-off-by: Xavier Hernandez > Reviewed-on: http://review.gluster.org/16371 > Smoke: Gluster Build System > NetBSD-regression: NetBSD Build System > CentOS-regression: Gluster Build System > Reviewed-by: Atin Mukherjee > Reviewed-by: Kaleb KEITHLEY Change-Id: Ic1a40546eef3befb16310ab5e022d83bbbc946d5 BUG: 1415133 Signed-off-by: Xavier Hernandez Reviewed-on: https://review.gluster.org/16443 Smoke: Gluster Build System CentOS-regression: Gluster Build System Reviewed-by: Kaleb KEITHLEY NetBSD-regression: NetBSD Build System --- cli/src/cli-cmd-volume.c | 6 -- cli/src/cli-xml-output.c | 8 +- cli/src/cli.h | 2 - contrib/mount/mntent.c | 266 +++++++++++++++++++++++++++-------------------- 4 files changed, 157 insertions(+), 125 deletions(-) diff --git a/cli/src/cli-cmd-volume.c b/cli/src/cli-cmd-volume.c index 52d80fffb70..a26c2977a99 100644 --- a/cli/src/cli-cmd-volume.c +++ b/cli/src/cli-cmd-volume.c @@ -1980,13 +1980,11 @@ cli_get_detail_status (dict_t *dict, int i, cli_volume_status_t *status) if (!status->total) goto out; -#ifdef GF_LINUX_HOST_OS memset (key, 0, sizeof (key)); snprintf (key, sizeof (key), "brick%d.device", i); ret = dict_get_str (dict, key, &(status->device)); if (ret) status->device = NULL; -#endif memset (key, 0, sizeof (key)); snprintf (key, sizeof (key), "brick%d.block_size", i); @@ -1996,7 +1994,6 @@ cli_get_detail_status (dict_t *dict, int i, cli_volume_status_t *status) status->block_size = 0; } -#ifdef GF_LINUX_HOST_OS memset (key, 0, sizeof (key)); snprintf (key, sizeof (key), "brick%d.mnt_options", i); ret = dict_get_str (dict, key, &(status->mount_options)); @@ -2016,7 +2013,6 @@ cli_get_detail_status (dict_t *dict, int i, cli_volume_status_t *status) ret = dict_get_str (dict, key, &(status->inode_size)); if (ret) status->inode_size = NULL; -#endif /* GF_LINUX_HOST_OS */ memset (key, 0, sizeof (key)); snprintf (key, sizeof (key), "brick%d.total_inodes", i); @@ -2054,7 +2050,6 @@ cli_print_detailed_status (cli_volume_status_t *status) cli_out ("%-20s : %-20c", "Online", (status->online) ? 'Y' : 'N'); cli_out ("%-20s : %-20s", "Pid", status->pid_str); -#ifdef GF_LINUX_HOST_OS if (status->fs_name) cli_out ("%-20s : %-20s", "File System", status->fs_name); else @@ -2078,7 +2073,6 @@ cli_print_detailed_status (cli_volume_status_t *status) } else { cli_out ("%-20s : %-20s", "Inode Size", "N/A"); } -#endif if (status->free) cli_out ("%-20s : %-20s", "Disk Space Free", status->free); else diff --git a/cli/src/cli-xml-output.c b/cli/src/cli-xml-output.c index cdce2d79870..b682848b15c 100644 --- a/cli/src/cli-xml-output.c +++ b/cli/src/cli-xml-output.c @@ -438,12 +438,6 @@ cli_xml_output_vol_status_detail (xmlTextWriterPtr writer, dict_t *dict, (xmlChar *)"fsName", "%s", fs_name); - /* inode details are only available for ext 2/3/4 & xfs */ - if (!fs_name || !IS_EXT_FS(fs_name) || strcmp (fs_name, "xfs")) { - ret = 0; - goto out; - } - memset (key, 0, sizeof (key)); snprintf (key, sizeof (key), "brick%d.inode_size", brick_index); ret = dict_get_str (dict, key, &inode_size); @@ -467,6 +461,8 @@ cli_xml_output_vol_status_detail (xmlTextWriterPtr writer, dict_t *dict, ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"inodesFree", "%"PRIu64, inodes_free); + else + ret = 0; out: gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); diff --git a/cli/src/cli.h b/cli/src/cli.h index 7d9a1d40e6d..b5c5d756f17 100644 --- a/cli/src/cli.h +++ b/cli/src/cli.h @@ -175,12 +175,10 @@ struct cli_volume_status { char *pid_str; char *free; char *total; -#ifdef GF_LINUX_HOST_OS char *fs_name; char *mount_options; char *device; char *inode_size; -#endif }; struct snap_config_opt_vals_ { diff --git a/contrib/mount/mntent.c b/contrib/mount/mntent.c index e9b448845a7..9a7e5f39bdb 100644 --- a/contrib/mount/mntent.c +++ b/contrib/mount/mntent.c @@ -36,6 +36,7 @@ */ #if !defined(GF_LINUX_HOST_OS) + #include #include #include @@ -49,166 +50,209 @@ typedef struct statvfs gf_statfs_t; typedef struct statfs gf_statfs_t; #endif -static int pos = -1; -static int mntsize = -1; -static struct mntent _mntent; +typedef struct _mntent_state { + struct mntent mntent; + gf_statfs_t *statfs; + int count; + int pos; + /* A buffer big enough to store all defined flags as a string. + * Increase it if necessary when more flags are defined. */ + char buf[256]; +} mntent_state_t; + +typedef struct _mntflag { + unsigned long value; + const char *on; + const char *off; +} mntflag_t; + +static mntflag_t mntflags[] = { + { MNT_RDONLY, "ro", "rw" }, + { MNT_SYNCHRONOUS, "sync", NULL }, + { MNT_NOEXEC, "noexec", NULL }, + { MNT_NOSUID, "nosuid", NULL }, +#if !defined(__FreeBSD__) + { MNT_NODEV, "nodev", NULL }, +#endif /* __FreeBSD__ */ + { MNT_UNION, "union", NULL }, + { MNT_ASYNC, "async", NULL }, +#if !defined(GF_DARWIN_HOST_OS) + { MNT_NOATIME, "noatime", NULL }, +#if !defined(__NetBSD__) + { MNT_NOCLUSTERR, "noclusterr", NULL }, + { MNT_NOCLUSTERW, "noclusterw", NULL }, + { MNT_NOSYMFOLLOW, "nosymfollow", NULL }, + { MNT_SUIDDIR, "suiddir", NULL }, +#endif /* !__NetBSD__ */ +#endif /* !GF_DARWIN_HOST_OS */ + { 0, NULL, NULL } +}; char * hasmntopt (const struct mntent *mnt, const char *option) { - int found; char *opt, *optbuf; + int len; optbuf = strdup(mnt->mnt_opts); - found = 0; - for (opt = optbuf; (opt = strtok(opt, " ")) != NULL; opt = NULL) { - if (!strcasecmp(opt, option)) { - opt = opt - optbuf + mnt->mnt_opts; - free (optbuf); - return (opt); + if (optbuf == NULL) { + return NULL; + } + + opt = optbuf; + len = 0; + while (*opt) { + while (opt[len] != 0) { + if (opt[len] == ' ') { + opt[len++] = 0; + break; + } + len++; + } + if ((*opt != 0) && (strcasecmp(opt, option) == 0)) { + break; } + opt += len; + len = 0; } - free (optbuf); - return (NULL); + free(optbuf); + if (len == 0) { + return NULL; + } + + return opt - optbuf + mnt->mnt_opts; } -static char * -concatopt (char *s0, const char *s1) +static int +writeopt(const char *text, char *buf, int buflen, int pos) { - size_t i; - char *cp; - - if (s1 == NULL || *s1 == '\0') - return s0; - if (s0 && *s0) { - i = strlen(s0) + strlen(s1) + 1 + 1; - if ((cp = (char *)malloc(i)) == NULL) - return (NULL); - (void)snprintf(cp, i, "%s %s", s0, s1); - } else - cp = strdup(s1); - - if (s0) - free(s0); - return (cp); -} + int len; + + /* buflen must be > 0 */ + + if (text == NULL) { + return pos; + } + + buf += pos; + if (pos > 0) { + /* We are sure we have at least one byte to store the space. + * We don't need to check buflen here. */ + *buf++ = ' '; + pos++; + } + len = strlen(text) + 1; + pos += len; + if (pos >= buflen) { + /* There won't be enough space for the text and the + * terminating null character. We copy as much as we can + * of the text and mark the end of the string with '...' */ + memcpy(buf, text, buflen - pos + len); + if (buflen > 3) { + strcpy(buf + buflen - 4, "..."); + } else { + strncpy(buf, "...", buflen - 1); + buf[buflen - 1] = 0; + } + pos = buflen; + } else { + memcpy(buf, text, len); + } + return pos; +} static char * -flags2opts (int flags) +flags2opts (int flags, char *buf, int buflen) { - char *res; - res = NULL; - res = concatopt(res, (flags & MNT_RDONLY) ? "ro" : "rw"); - if (flags & MNT_SYNCHRONOUS) res = concatopt(res, "sync"); - if (flags & MNT_NOEXEC) res = concatopt(res, "noexec"); - if (flags & MNT_NOSUID) res = concatopt(res, "nosuid"); -#if !defined(__FreeBSD__) - if (flags & MNT_NODEV) res = concatopt(res, "nodev"); -#endif /* __FreeBSD__ */ - if (flags & MNT_UNION) res = concatopt(res, "union"); - if (flags & MNT_ASYNC) res = concatopt(res, "async"); -#if !defined(GF_DARWIN_HOST_OS) - if (flags & MNT_NOATIME) res = concatopt(res, "noatime"); -#if !defined(__NetBSD__) - if (flags & MNT_NOCLUSTERR) res = concatopt(res, "noclusterr"); - if (flags & MNT_NOCLUSTERW) res = concatopt(res, "noclusterw"); - if (flags & MNT_NOSYMFOLLOW) res = concatopt(res, "nosymfollow"); - if (flags & MNT_SUIDDIR) res = concatopt(res, "suiddir"); -#endif /* !__NetBSD__ */ -#endif /* !GF_DARWIN_HOS_OS */ - return res; + char other[16]; + mntflag_t *flg; + int pos; + + if (buflen == 0) { + return NULL; + } + + pos = 0; + for (flg = mntflags; flg->value != 0; flg++) { + pos = writeopt((flags & flg->value) == 0 ? flg->off : flg->on, + buf, buflen, pos); + flags &= ~flg->value; + } + + if (flags != 0) { + sprintf(other, "[0x%x]", flags); + writeopt(other, buf, buflen, pos); + } + + return buf; } -static struct mntent * -statfs_to_mntent (gf_statfs_t *mntbuf) +static void +statfs_to_mntent (struct mntent *mntent, gf_statfs_t *mntbuf, char *buf, + int buflen) { - static char opts_buf[40], *tmp; int f_flags; - _mntent.mnt_fsname = mntbuf->f_mntfromname; - _mntent.mnt_dir = mntbuf->f_mntonname; - _mntent.mnt_type = mntbuf->f_fstypename; + mntent->mnt_fsname = mntbuf->f_mntfromname; + mntent->mnt_dir = mntbuf->f_mntonname; + mntent->mnt_type = mntbuf->f_fstypename; #ifdef __NetBSD__ f_flags = mntbuf->f_flag; #else f_flags = mntbuf->f_flags; #endif - tmp = flags2opts (f_flags); - if (tmp) { - opts_buf[sizeof(opts_buf)-1] = '\0'; - strncpy (opts_buf, tmp, sizeof(opts_buf)-1); - free (tmp); - } else { - *opts_buf = '\0'; - } - _mntent.mnt_opts = opts_buf; - _mntent.mnt_freq = _mntent.mnt_passno = 0; - return (&_mntent); + mntent->mnt_opts = flags2opts (f_flags, buf, buflen); + + mntent->mnt_freq = mntent->mnt_passno = 0; } struct mntent * -getmntent (FILE *fp) +getmntent_r (FILE *fp, struct mntent *mntent, char *buf, int buflen) { - gf_statfs_t *mntbuf; + mntent_state_t *state = (mntent_state_t *)fp; - if (!fp) + if (state->pos >= state->count) { return NULL; - - if (pos == -1 || mntsize == -1) - mntsize = getmntinfo (&mntbuf, MNT_NOWAIT); - - ++pos; - if (pos == mntsize) { - pos = mntsize = -1; - return (NULL); } - return (statfs_to_mntent (&mntbuf[pos])); + statfs_to_mntent(mntent, &state->statfs[state->pos++], buf, buflen); + + return mntent; } -/* - Careful using this function ``buffer`` and ``bufsize`` are - ignored since there is no stream with strings to populate - them on OSX or NetBSD, if one wishes to populate them then - perhaps a new function should be written in this source file - which uses 'getmntinfo()' to stringify the mntent's -*/ - -struct mntent *getmntent_r (FILE *fp, struct mntent *result, - char *buffer, int bufsize) +struct mntent * +getmntent (FILE *fp) { - struct mntent *ment = NULL; - - if (!fp) - return NULL; + mntent_state_t *state = (mntent_state_t *)fp; - flockfile (fp); - ment = getmntent (fp); - memcpy (result, ment, sizeof(*ment)); - funlockfile (fp); - - return result; + return getmntent_r(fp, &state->mntent, state->buf, + sizeof(state->buf)); } FILE * setmntent (const char *filename, const char *type) { - FILE *fp = NULL; -#ifdef GF_DARWIN_HOST_OS - fp = fopen (filename, "w"); -#else - fp = fopen (filename, type); -#endif - return fp; + mntent_state_t *state; + + /* We don't really need to access any file so we'll use the FILE* as + * a fake file to store state information. + */ + + state = malloc(sizeof(mntent_state_t)); + if (state != NULL) { + state->pos = 0; + state->count = getmntinfo(&state->statfs, MNT_NOWAIT); + } + + return (FILE *)state; } int endmntent (FILE *fp) { - if (fp) - fclose (fp); + free(fp); return 1; /* endmntent() always returns 1 */ } -- cgit