21ab4e
From fbbaf1139ab9b76b4fe30781e1e045a1bdc08bc0 Mon Sep 17 00:00:00 2001
3604df
From: Amar Tumballi <amarts@redhat.com>
3604df
Date: Mon, 29 May 2017 17:20:55 +0530
21ab4e
Subject: [PATCH 475/486] libglusterfs: extract some functionality to functions
3604df
3604df
- code in run.c to close all file descriptors,
3604df
  except for specified ones is extracted to
3604df
3604df
    int close_fds_except (int *fdv, size_t count);
3604df
3604df
- tokenizing and editing a string that consists
3604df
  of comma-separated tokens (as done eg. in
3604df
  mount_param_to_flag() of contrib/fuse/mount.c
3604df
  is abstacted into the following API:
3604df
3604df
    char *token_iter_init (char *str, char sep, token_iter_t *tit);
3604df
    gf_boolean_t next_token (char **tokenp, token_iter_t *tit);
3604df
    void drop_token (char *token, token_iter_t *tit);
3604df
3604df
Also contains minimum changes from https://review.gluster.org/16313
3604df
which is used for resolving the conflicts.
3604df
3604df
Upstream:
3604df
> Change-Id: I7cb5bda38f680f08882e2a7ef84f9142ffaa54eb
3604df
> Signed-off-by: Csaba Henk <csaba@redhat.com>
3604df
> Reviewed-on: https://review.gluster.org/17229
3604df
> Smoke: Gluster Build System <jenkins@build.gluster.org>
3604df
> NetBSD-regression: NetBSD Build System <jenkins@build.gluster.org>
3604df
> CentOS-regression: Gluster Build System <jenkins@build.gluster.org>
3604df
> Reviewed-by: Amar Tumballi <amarts@redhat.com>
3604df
21ab4e
BUG: 1424680
3604df
Change-Id: Ia4e500ae40cc3029136bcb4f2f1a0dd81d813e04
3604df
Signed-off-by: Amar Tumballi <amarts@redhat.com>
21ab4e
Reviewed-on: https://code.engineering.redhat.com/gerrit/107570
3604df
Reviewed-by: Atin Mukherjee <amukherj@redhat.com>
3604df
---
3604df
 contrib/fuse-lib/mount.c        | 102 ++++++++++++++++++--
3604df
 libglusterfs/src/common-utils.c | 208 ++++++++++++++++++++++++++++++++++++++++
3604df
 libglusterfs/src/common-utils.h |  10 ++
3604df
 libglusterfs/src/run.c          |  30 +-----
3604df
 4 files changed, 317 insertions(+), 33 deletions(-)
3604df
3604df
diff --git a/contrib/fuse-lib/mount.c b/contrib/fuse-lib/mount.c
3604df
index 1edde86..5e0b4dd 100644
3604df
--- a/contrib/fuse-lib/mount.c
3604df
+++ b/contrib/fuse-lib/mount.c
3604df
@@ -224,19 +224,107 @@ build_iovec_argf(struct iovec **iov, int *iovlen, const char *name,
3604df
 }
3604df
 #endif /* __FreeBSD__ */
3604df
 
3604df
+
3604df
+#ifdef GF_LINUX_HOST_OS
3604df
+typedef unsigned long mount_flag_t;
3604df
+#endif
3604df
+
3604df
+struct mount_flags {
3604df
+        const char *opt;
3604df
+        mount_flag_t flag;
3604df
+        int on;
3604df
+} mount_flags[] = {
3604df
+        /* We provide best effort cross platform support for mount flags by
3604df
+         * defining the ones which are commonly used in Unix-like OS-es.
3604df
+         */
3604df
+        {"ro",      MS_RDONLY,      1},
3604df
+        {"nosuid",  MS_NOSUID,      1},
3604df
+        {"nodev",   MS_NODEV,       1},
3604df
+        {"noatime", MS_NOATIME,     1},
3604df
+        {"noexec",  MS_NOEXEC,      1},
3604df
+#ifdef GF_LINUX_HOST_OS
3604df
+        {"rw",      MS_RDONLY,      0},
3604df
+        {"suid",    MS_NOSUID,      0},
3604df
+        {"dev",     MS_NODEV,       0},
3604df
+        {"exec",    MS_NOEXEC,      0},
3604df
+        {"async",   MS_SYNCHRONOUS, 0},
3604df
+        {"sync",    MS_SYNCHRONOUS, 1},
3604df
+        {"atime",   MS_NOATIME,     0},
3604df
+        {"dirsync", MS_DIRSYNC,     1},
3604df
+#endif
3604df
+        {NULL,      0,              0}
3604df
+};
3604df
+
3604df
+
3604df
+static int
3604df
+mount_param_to_flag (char *mnt_param, mount_flag_t *mntflags,
3604df
+                     char **mnt_param_new)
3604df
+{
3604df
+        gf_boolean_t found = _gf_false;
3604df
+        struct mount_flags *flag = NULL;
3604df
+        char *param_tok = NULL;
3604df
+        token_iter_t tit = {0,};
3604df
+        gf_boolean_t iter_end = _gf_false;
3604df
+
3604df
+        /* Allocate a buffer that will hold the mount parameters remaining
3604df
+         * after the ones corresponding to mount flags are processed and
3604df
+         * removed.The length of the original params are a good upper bound
3604df
+         * of the size needed.
3604df
+         */
3604df
+        *mnt_param_new = strdup (mnt_param);
3604df
+        if (!*mnt_param_new)
3604df
+                return -1;
3604df
+
3604df
+        for (param_tok = token_iter_init (*mnt_param_new, ',', &tit) ;;) {
3604df
+                iter_end = next_token (&param_tok, &tit;;
3604df
+
3604df
+                found = _gf_false;
3604df
+                for (flag = mount_flags; flag->opt; flag++) {
3604df
+                        /* Compare the mount flag name to the param
3604df
+                         * name at hand.
3604df
+                         */
3604df
+                        if (strcmp (flag->opt, param_tok) == 0) {
3604df
+                                /* If there is a match, adjust mntflags
3604df
+                                 * accordingly and break.
3604df
+                                 */
3604df
+                                if (flag->on) {
3604df
+                                        *mntflags |= flag->flag;
3604df
+                                } else {
3604df
+                                        *mntflags &= ~flag->flag;
3604df
+                                }
3604df
+                                found = _gf_true;
3604df
+                                break;
3604df
+                        }
3604df
+                }
3604df
+                /* Exclude flag names from new parameter list. */
3604df
+                if (found)
3604df
+                        drop_token (param_tok, &tit;;
3604df
+
3604df
+                if (iter_end)
3604df
+                        break;
3604df
+        }
3604df
+
3604df
+        return 0;
3604df
+}
3604df
+
3604df
 static int
3604df
 fuse_mount_sys (const char *mountpoint, char *fsname,
3604df
-                unsigned long mountflags, char *mnt_param, int fd)
3604df
+                unsigned long dummy, char *mnt_param, int fd)
3604df
 {
3604df
         int ret = -1;
3604df
         unsigned mounted = 0;
3604df
         char *mnt_param_mnt = NULL;
3604df
         char *fstype = "fuse.glusterfs";
3604df
         char *source = fsname;
3604df
-
3604df
-        ret = asprintf (&mnt_param_mnt,
3604df
-                        "%s,fd=%i,rootmode=%o,user_id=%i,group_id=%i",
3604df
-                        mnt_param, fd, S_IFDIR, getuid (), getgid ());
3604df
+        mount_flag_t mountflags = 0;
3604df
+        char *mnt_param_new = NULL;
3604df
+
3604df
+        ret = mount_param_to_flag (mnt_param, &mountflags, &mnt_param_new);
3604df
+        if (ret == 0) {
3604df
+                ret = asprintf (&mnt_param_mnt,
3604df
+                                "%s,fd=%i,rootmode=%o,user_id=%i,group_id=%i",
3604df
+                                mnt_param_new, fd, S_IFDIR, getuid (), getgid ());
3604df
+        }
3604df
         if (ret == -1) {
3604df
                 GFFUSE_LOGERR ("Out of memory");
3604df
 
3604df
@@ -295,7 +383,7 @@ fuse_mount_sys (const char *mountpoint, char *fsname,
3604df
 
3604df
                 ret = asprintf (&mnt_param_mtab, "%s%s",
3604df
                                 mountflags & MS_RDONLY ? "ro," : "",
3604df
-                                mnt_param);
3604df
+                                mnt_param_new);
3604df
                 if (ret == -1)
3604df
                         GFFUSE_LOGERR ("Out of memory");
3604df
                 else {
3604df
@@ -320,6 +408,8 @@ out:
3604df
                         umount2 (mountpoint, 2); /* lazy umount */
3604df
         }
3604df
         FREE (mnt_param_mnt);
3604df
+        FREE (mnt_param_new);
3604df
+
3604df
         if (source != fsname)
3604df
                 FREE (source);
3604df
 
3604df
diff --git a/libglusterfs/src/common-utils.c b/libglusterfs/src/common-utils.c
21ab4e
index 0cc8f91..a8f6d13 100644
3604df
--- a/libglusterfs/src/common-utils.c
3604df
+++ b/libglusterfs/src/common-utils.c
3604df
@@ -50,6 +50,10 @@
3604df
 #include <ifaddrs.h>
3604df
 #include "libglusterfs-messages.h"
3604df
 
3604df
+#ifndef GF_LINUX_HOST_OS
3604df
+#include <sys/resource.h>
3604df
+#endif
3604df
+
3604df
 #ifndef AI_ADDRCONFIG
3604df
 #define AI_ADDRCONFIG 0
3604df
 #endif /* AI_ADDRCONFIG */
3604df
@@ -2140,6 +2144,150 @@ get_nth_word (const char *str, int n)
3604df
         return word;
3604df
 }
3604df
 
3604df
+/**
3604df
+ * token_iter_init -- initialize tokenization
3604df
+ *
3604df
+ * @str: string to be tokenized
3604df
+ * @sep: token separator character
3604df
+ * @tit: pointer to iteration state
3604df
+ *
3604df
+ * @return: token string
3604df
+ *
3604df
+ * The returned token string and tit are
3604df
+ * not to be used directly, but through
3604df
+ * next_token().
3604df
+ */
3604df
+char *
3604df
+token_iter_init (char *str, char sep, token_iter_t *tit)
3604df
+{
3604df
+        tit->end = str + strlen (str);
3604df
+        tit->sep = sep;
3604df
+
3604df
+        return str;
3604df
+}
3604df
+
3604df
+/**
3604df
+ * next_token -- fetch next token in tokenization
3604df
+ * inited by token_iter_init().
3604df
+ *
3604df
+ * @tokenp: pointer to token
3604df
+ * @tit:    pointer to iteration state
3604df
+ *
3604df
+ * @return: true if iteration ends, else false
3604df
+ *
3604df
+ * The token pointed by @tokenp can be used
3604df
+ * after a call to next_token(). When next_token()
3604df
+ * returns true the iteration is to be stopped
3604df
+ * and the string with which the tokenization
3604df
+ * was inited (see token_iter_init() is restored,
3604df
+ * apart from dropped tokens (see drop_token()).
3604df
+ */
3604df
+gf_boolean_t
3604df
+next_token (char **tokenp, token_iter_t *tit)
3604df
+{
3604df
+        char        *cursor  = NULL;
3604df
+        gf_boolean_t is_last = _gf_false;
3604df
+
3604df
+        for (cursor = *tokenp; *cursor; cursor++)
3604df
+                ;
3604df
+        if (cursor < tit->end) {
3604df
+                /*
3604df
+                 * We detect that in between current token and end a zero
3604df
+                 * marker has already been inserted. This means that the
3604df
+                 * token has already been returned. We restore the
3604df
+                 * separator and move ahead.
3604df
+                 */
3604df
+                *cursor = tit->sep;
3604df
+                *tokenp = cursor + 1;
3604df
+        }
3604df
+
3604df
+        for (cursor = *tokenp; *cursor && *cursor != tit->sep; cursor++)
3604df
+                ;
3604df
+        /* If the cursor ended up on a zero byte, then it's the last token. */
3604df
+        is_last = !*cursor;
3604df
+        /* Zero-terminate the token. */
3604df
+        *cursor = 0;
3604df
+
3604df
+        return is_last;
3604df
+}
3604df
+
3604df
+/*
3604df
+ * drop_token -- drop a token during iterated calls of next_token().
3604df
+ *
3604df
+ * Sample program that uses these functions to tokenize
3604df
+ * a comma-separated first argument while dropping the
3604df
+ * rest of the arguments if they occur as token:
3604df
+ *
3604df
+ * #include <stdio.h>
3604df
+ * #include <stdlib.h>
3604df
+ * #include <string.h>
3604df
+ * #include "common-utils.h"
3604df
+ *
3604df
+ * int
3604df
+ * main (int argc, char **argv)
3604df
+ * {
3604df
+ *         char *buf;
3604df
+ *         char *token;
3604df
+ *         token_iter_t tit;
3604df
+ *         int i;
3604df
+ *         gf_boolean_t iter_end;
3604df
+ *
3604df
+ *         if (argc <= 1)
3604df
+ *                 abort();
3604df
+ *
3604df
+ *         buf = strdup (argv[1]);
3604df
+ *         if (!buf)
3604df
+ *                 abort();
3604df
+ *
3604df
+ *         for (token = token_iter_init (buf, ',', &tit) ;;) {
3604df
+ *                 iter_end = next_token (&token, &tit;;
3604df
+ *                 printf("found token: '%s'\n", token);
3604df
+ *                 for (i = 2; i < argc; i++) {
3604df
+ *                         if (strcmp (argv[i], token) == 0) {
3604df
+ *                                 printf ("%s\n", "dropping token!");
3604df
+ *                                 drop_token (token, &tit;;
3604df
+ *                                 break;
3604df
+ *                          }
3604df
+ *                 }
3604df
+ *                 if (iter_end)
3604df
+ *                         break;
3604df
+ *         }
3604df
+ *
3604df
+ *         printf ("finally: '%s'\n", buf);
3604df
+ *
3604df
+ *         return 0;
3604df
+ * }
3604df
+ */
3604df
+void
3604df
+drop_token (char *token, token_iter_t *tit)
3604df
+{
3604df
+        char *cursor = NULL;
3604df
+
3604df
+        for (cursor = token; *cursor; cursor++)
3604df
+                ;
3604df
+        if (cursor < tit->end) {
3604df
+                /*
3604df
+                 * We detect a zero inserted by next_token().
3604df
+                 * Step the cursor and copy what comes after
3604df
+                 * to token.
3604df
+                 */
3604df
+                for (cursor++; cursor < tit->end; *token++ = *cursor++)
3604df
+                        ;
3604df
+        }
3604df
+
3604df
+        /*
3604df
+         * Zero out the remainder of the buffer.
3604df
+         * It would be enough to insert just a single zero,
3604df
+         * but we continue 'till the end to have cleaner
3604df
+         * memory content.
3604df
+         */
3604df
+        for (cursor = token; cursor < tit->end; *cursor++ = 0)
3604df
+                ;
3604df
+
3604df
+        /* Adjust the end to point to the new terminating zero. */
3604df
+        tit->end = token;
3604df
+}
3604df
+
3604df
 /* Syntax formed according to RFC 1912 (RFC 1123 & 952 are more restrictive)  *
3604df
    <hname> ::= <gen-name>*["."<gen-name>]                                     *
3604df
    <gen-name> ::= <let-or-digit> <[*[<let-or-digit-or-hyphen>]<let-or-digit>] */
21ab4e
@@ -4645,3 +4793,63 @@ is_virtual_xattr (const char *k)
3604df
 
3604df
         return ret;
3604df
 }
3604df
+
3604df
+int
3604df
+close_fds_except (int *fdv, size_t count)
3604df
+{
3604df
+        int          i            = 0;
3604df
+        size_t       j            = 0;
3604df
+        gf_boolean_t should_close = _gf_true;
3604df
+#ifdef GF_LINUX_HOST_OS
3604df
+        DIR           *d          = NULL;
3604df
+        struct dirent *de         = NULL;
3604df
+        struct dirent  scratch[2] = {{0,},};
3604df
+        char          *e          = NULL;
3604df
+
3604df
+        d = sys_opendir ("/proc/self/fd");
3604df
+        if (!d)
3604df
+                return -1;
3604df
+
3604df
+        for (;;) {
3604df
+                should_close = _gf_true;
3604df
+
3604df
+                errno = 0;
3604df
+                de = sys_readdir (d);
3604df
+                if (!de || errno != 0)
3604df
+                        break;
3604df
+                i = strtoul (de->d_name, &e, 10);
3604df
+                if (*e != '\0' || i == dirfd (d))
3604df
+                        continue;
3604df
+
3604df
+                for (j = 0; j < count; j++) {
3604df
+                        if (i == fdv[j]) {
3604df
+                                should_close = _gf_false;
3604df
+                                break;
3604df
+                        }
3604df
+               }
3604df
+               if (should_close)
3604df
+                        sys_close (i);
3604df
+        }
3604df
+        sys_closedir (d);
3604df
+#else /* !GF_LINUX_HOST_OS */
3604df
+        struct rlimit rl;
3604df
+        int ret = -1;
3604df
+
3604df
+        ret = getrlimit (RLIMIT_NOFILE, &rl);
3604df
+        if (ret)
3604df
+                return ret;
3604df
+
3604df
+        for (i = 0; i < rl.rlim_cur; i++) {
3604df
+                should_close = _gf_true;
3604df
+                for (j = 0; j < count; j++) {
3604df
+                        if (i == fdv[j]) {
3604df
+                                should_close = _gf_false;
3604df
+                                break;
3604df
+                        }
3604df
+                }
3604df
+                if (should_close)
3604df
+                        sys_close (i);
3604df
+        }
3604df
+#endif /* !GF_LINUX_HOST_OS */
3604df
+        return 0;
3604df
+}
3604df
diff --git a/libglusterfs/src/common-utils.h b/libglusterfs/src/common-utils.h
21ab4e
index d71cb22..1af9529 100644
3604df
--- a/libglusterfs/src/common-utils.h
3604df
+++ b/libglusterfs/src/common-utils.h
21ab4e
@@ -764,6 +764,14 @@ void skip_word (char **str);
3604df
 /* returns a new string with nth word of given string. n>=1 */
3604df
 char *get_nth_word (const char *str, int n);
3604df
 
3604df
+typedef struct token_iter {
3604df
+        char *end;
3604df
+        char sep;
3604df
+} token_iter_t;
3604df
+char *token_iter_init (char *str, char sep, token_iter_t *tit);
3604df
+gf_boolean_t next_token (char **tokenp, token_iter_t *tit);
3604df
+void drop_token (char *token, token_iter_t *tit);
3604df
+
3604df
 gf_boolean_t mask_match (const uint32_t a, const uint32_t b, const uint32_t m);
3604df
 gf_boolean_t gf_is_ip_in_net (const char *network, const char *ip_str);
3604df
 char valid_host_name (char *address, int length);
21ab4e
@@ -893,4 +901,6 @@ gf_bits_index (uint64_t n);
3604df
 char *
3604df
 get_ip_from_addrinfo (struct addrinfo *addr, char **ip);
3604df
 
3604df
+int
3604df
+close_fds_except (int *fdv, size_t count);
3604df
 #endif /* _COMMON_UTILS_H */
3604df
diff --git a/libglusterfs/src/run.c b/libglusterfs/src/run.c
3604df
index c625a5b..a7d98af 100644
3604df
--- a/libglusterfs/src/run.c
3604df
+++ b/libglusterfs/src/run.c
3604df
@@ -23,7 +23,6 @@
3604df
 #include <assert.h>
3604df
 #include <signal.h>
3604df
 #include <sys/wait.h>
3604df
-#include <sys/resource.h>
3604df
 #include "syscall.h"
3604df
 
3604df
 #ifdef RUN_STANDALONE
3604df
@@ -274,32 +273,9 @@ runner_start (runner_t *runner)
3604df
                 }
3604df
 
3604df
                 if (ret != -1 ) {
3604df
-#ifdef GF_LINUX_HOST_OS
3604df
-                        DIR *d = NULL;
3604df
-                        struct dirent *de = NULL;
3604df
-                        char *e = NULL;
3604df
-
3604df
-                        d = sys_opendir ("/proc/self/fd");
3604df
-                        if (d) {
3604df
-                                while ((de = sys_readdir (d))) {
3604df
-                                        i = strtoul (de->d_name, &e, 10);
3604df
-                                        if (*e == '\0' && i > 2 &&
3604df
-                                            i != dirfd (d) && i != xpi[1])
3604df
-                                                sys_close (i);
3604df
-                                }
3604df
-                                sys_closedir (d);
3604df
-                        } else
3604df
-                                ret = -1;
3604df
-#else /* !GF_LINUX_HOST_OS */
3604df
-                        struct rlimit rl;
3604df
-                        ret = getrlimit (RLIMIT_NOFILE, &rl);
3604df
-                        GF_ASSERT (ret == 0);
3604df
-
3604df
-                        for (i = 3; i < rl.rlim_cur; i++) {
3604df
-                                if (i != xpi[1])
3604df
-                                        sys_close (i);
3604df
-                        }
3604df
-#endif /* !GF_LINUX_HOST_OS */
3604df
+                        int fdv[4] = {0, 1, 2, xpi[1]};
3604df
+
3604df
+                        ret = close_fds_except(fdv, sizeof (fdv) / sizeof (*fdv));
3604df
                 }
3604df
 
3604df
                 if (ret != -1) {
3604df
-- 
3604df
1.8.3.1
3604df