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