diff options
Diffstat (limited to 'contrib/fuse-util/fusermount.c')
| -rw-r--r-- | contrib/fuse-util/fusermount.c | 204 |
1 files changed, 136 insertions, 68 deletions
diff --git a/contrib/fuse-util/fusermount.c b/contrib/fuse-util/fusermount.c index ae779d3fb21..ff743f75a21 100644 --- a/contrib/fuse-util/fusermount.c +++ b/contrib/fuse-util/fusermount.c @@ -10,6 +10,11 @@ #include <config.h> #include "mount_util.h" + +#ifndef HAVE_UMOUNT2 +#include "mount-gluster-compat.h" +#endif + #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -19,15 +24,24 @@ #include <errno.h> #include <fcntl.h> #include <pwd.h> +#include <limits.h> +#if !defined(__NetBSD__) && !defined(GF_DARWIN_HOST_OS) #include <mntent.h> +#endif /* __NetBSD__ */ #include <sys/wait.h> #include <sys/stat.h> -#include <sys/mount.h> +#ifdef HAVE_SET_FSID #include <sys/fsuid.h> +#endif +#ifdef GF_DARWIN_HOST_OS +#include <sys/param.h> +#endif +#include <sys/mount.h> #include <sys/socket.h> #include <sys/utsname.h> #include <sched.h> +#define FUSE_DEVFD_ENV "_FUSE_DEVFD" #define FUSE_COMMFD_ENV "_FUSE_COMMFD" #define FUSE_DEV_OLD "/proc/fs/fuse/dev" @@ -61,22 +75,32 @@ static const char *get_user_name(void) } } +#ifdef HAVE_SET_FSID static uid_t oldfsuid; static gid_t oldfsgid; +#endif static void drop_privs(void) { if (getuid() != 0) { +#ifdef HAVE_SET_FSID oldfsuid = setfsuid(getuid()); oldfsgid = setfsgid(getgid()); +#else + fprintf(stderr, "%s: Implement alternative setfsuid/gid \n", progname); +#endif } } static void restore_privs(void) { if (getuid() != 0) { +#ifdef HAVE_SET_FSID setfsuid(oldfsuid); setfsgid(oldfsgid); +#else + fprintf(stderr, "%s: Implement alternative setfsuid/gid \n", progname); +#endif } } @@ -114,8 +138,16 @@ static int lock_umount(void) static void unlock_umount(int mtablock) { - lockf(mtablock, F_ULOCK, 0); - close(mtablock); + if (mtablock >= 0) { + int res; + + res = lockf(mtablock, F_ULOCK, 0); + if (res < 0) { + fprintf(stderr, "%s: error releasing lock: %s\n", + progname, strerror(errno)); + } + close(mtablock); + } } static int add_mount(const char *source, const char *mnt, const char *type, @@ -238,7 +270,7 @@ static int check_is_mount_child(void *p) } count = 0; - while ((entp = getmntent(fp)) != NULL) + while (getmntent(fp) != NULL) count++; endmntent(fp); @@ -325,7 +357,7 @@ static int check_is_mount(const char *last, const char *mnt) return 0; } -static int chdir_to_parent(char *copy, const char **lastp, int *currdir_fd) +static int chdir_to_parent(char *copy, const char **lastp) { char *tmp; const char *parent; @@ -350,14 +382,6 @@ static int chdir_to_parent(char *copy, const char **lastp, int *currdir_fd) parent = "/"; } - *currdir_fd = open(".", O_RDONLY); - if (*currdir_fd == -1) { - fprintf(stderr, - "%s: failed to open current directory: %s\n", - progname, strerror(errno)); - return -1; - } - res = chdir(parent); if (res == -1) { fprintf(stderr, "%s: failed to chdir to %s: %s\n", @@ -382,7 +406,6 @@ static int chdir_to_parent(char *copy, const char **lastp, int *currdir_fd) static int unmount_fuse_locked(const char *mnt, int quiet, int lazy) { - int currdir_fd = -1; char *copy; const char *last; int res; @@ -399,7 +422,7 @@ static int unmount_fuse_locked(const char *mnt, int quiet, int lazy) return -1; } - res = chdir_to_parent(copy, &last, &currdir_fd); + res = chdir_to_parent(copy, &last); if (res == -1) goto out; @@ -411,10 +434,6 @@ static int unmount_fuse_locked(const char *mnt, int quiet, int lazy) out: free(copy); - if (currdir_fd != -1) { - fchdir(currdir_fd); - close(currdir_fd); - } return res; } @@ -501,20 +520,22 @@ static void parse_line(char *line, int linenum) static void read_conf(void) { + int len; FILE *fp = fopen(FUSE_CONF, "r"); if (fp != NULL) { int linenum = 1; char line[256]; int isnewline = 1; while (fgets(line, sizeof(line), fp) != NULL) { + len = strlen (line); if (isnewline) { - if (line[strlen(line)-1] == '\n') { + if (len && line[len-1] == '\n') { strip_line(line); parse_line(line, linenum); } else { isnewline = 0; } - } else if(line[strlen(line)-1] == '\n') { + } else if (len && line[len-1] == '\n') { fprintf(stderr, "%s: reading %s: line %i too long\n", progname, FUSE_CONF, linenum); isnewline = 1; @@ -609,7 +630,7 @@ static int add_option(char **optsp, const char *opt, unsigned expand) static int get_mnt_opts(int flags, char *opts, char **mnt_optsp) { int i; - int l; + size_t l; if (!(flags & MS_RDONLY) && add_option(mnt_optsp, "rw", 0) == -1) return -1; @@ -624,7 +645,7 @@ static int get_mnt_opts(int flags, char *opts, char **mnt_optsp) return -1; /* remove comma from end of opts*/ l = strlen(*mnt_optsp); - if ((*mnt_optsp)[l-1] == ',') + if (l && (*mnt_optsp)[l-1] == ',') (*mnt_optsp)[l-1] = '\0'; if (getuid() != 0) { const char *user = get_user_name(); @@ -649,18 +670,26 @@ static int opt_eq(const char *s, unsigned len, const char *opt) static int get_string_opt(const char *s, unsigned len, const char *opt, char **val) { + int i; unsigned opt_len = strlen(opt); + char *d; - if (*val) - free(*val); + free(*val); *val = (char *) malloc(len - opt_len + 1); if (!*val) { fprintf(stderr, "%s: failed to allocate memory\n", progname); return 0; } - memcpy(*val, s + opt_len, len - opt_len); - (*val)[len - opt_len] = '\0'; + d = *val; + s += opt_len; + len -= opt_len; + for (i = 0; i < len; i++) { + if (s[i] == '\\' && i + 1 < len) + i++; + *d++ = s[i]; + } + *d = '\0'; return 1; } @@ -691,7 +720,12 @@ static int do_mount(const char *mnt, char **typep, mode_t rootmode, unsigned len; const char *fsname_str = "fsname="; const char *subtype_str = "subtype="; - for (len = 0; s[len] && s[len] != ','; len++); + for (len = 0; s[len]; len++) { + if (s[len] == '\\' && s[len + 1]) + len++; + else if (s[len] == ',') + break; + } if (begins_with(s, fsname_str)) { if (!get_string_opt(s, len, fsname_str, &fsname)) goto err; @@ -809,15 +843,14 @@ static int do_mount(const char *mnt, char **typep, mode_t rootmode, fprintf(stderr, "%s: mount failed: %s\n", progname, strerror(errno_save)); goto err; - } else { - *sourcep = source; - *typep = type; - *mnt_optsp = mnt_opts; } + *sourcep = source; + *typep = type; + *mnt_optsp = mnt_opts; free(fsname); free(optbuf); - return res; + return 0; err: free(fsname); @@ -860,8 +893,7 @@ static int check_version(const char *dev) return 0; } -static int check_perm(const char **mntp, struct stat *stbuf, int *currdir_fd, - int *mountpoint_fd) +static int check_perm(const char **mntp, struct stat *stbuf, int *mountpoint_fd) { int res; const char *mnt = *mntp; @@ -879,13 +911,6 @@ static int check_perm(const char **mntp, struct stat *stbuf, int *currdir_fd, return 0; if (S_ISDIR(stbuf->st_mode)) { - *currdir_fd = open(".", O_RDONLY); - if (*currdir_fd == -1) { - fprintf(stderr, - "%s: failed to open current directory: %s\n", - progname, strerror(errno)); - return -1; - } res = chdir(mnt); if (res == -1) { fprintf(stderr, @@ -1002,8 +1027,36 @@ static int open_fuse_device(char **devp) return -1; } +static int check_fuse_device(char *devfd, char **devp) +{ + int res; + char *devlink; -static int mount_fuse(const char *mnt, const char *opts) + res = asprintf(&devlink, "/proc/self/fd/%s", devfd); + if (res == -1) { + fprintf(stderr, "%s: failed to allocate memory\n", progname); + return -1; + } + + *devp = (char *) calloc(1, PATH_MAX + 1); + if (!*devp) { + fprintf(stderr, "%s: failed to allocate memory\n", progname); + free(devlink); + return -1; + } + + res = readlink (devlink, *devp, PATH_MAX); + free (devlink); + if (res == -1) { + fprintf(stderr, "%s: specified fuse fd is invalid\n", + progname); + return -1; + } + + return atoi(devfd); +} + +static int mount_fuse(const char *mnt, const char *opts, char *devfd) { int res; int fd; @@ -1013,10 +1066,9 @@ static int mount_fuse(const char *mnt, const char *opts) char *source = NULL; char *mnt_opts = NULL; const char *real_mnt = mnt; - int currdir_fd = -1; int mountpoint_fd = -1; - fd = open_fuse_device(&dev); + fd = devfd ? check_fuse_device(devfd, &dev) : open_fuse_device(&dev); if (fd == -1) return -1; @@ -1027,15 +1079,13 @@ static int mount_fuse(const char *mnt, const char *opts) int mount_count = count_fuse_fs(); if (mount_count >= mount_max) { fprintf(stderr, "%s: too many FUSE filesystems mounted; mount_max=N can be set in /etc/fuse.conf\n", progname); - close(fd); - return -1; + goto fail_close_fd; } } res = check_version(dev); if (res != -1) { - res = check_perm(&real_mnt, &stbuf, &currdir_fd, - &mountpoint_fd); + res = check_perm(&real_mnt, &stbuf, &mountpoint_fd); restore_privs(); if (res != -1) res = do_mount(real_mnt, &type, stbuf.st_mode & S_IFMT, @@ -1044,33 +1094,38 @@ static int mount_fuse(const char *mnt, const char *opts) } else restore_privs(); - if (currdir_fd != -1) { - fchdir(currdir_fd); - close(currdir_fd); - } if (mountpoint_fd != -1) close(mountpoint_fd); + if (res == -1) + goto fail_close_fd; + + res = chdir("/"); if (res == -1) { - close(fd); - return -1; + fprintf(stderr, "%s: failed to chdir to '/'\n", progname); + goto fail_close_fd; } if (geteuid() == 0) { res = add_mount(source, mnt, type, mnt_opts); if (res == -1) { - umount2(mnt, 2); /* lazy umount */ - close(fd); - return -1; + /* Can't clean up mount in a non-racy way */ + goto fail_close_fd; } } +out_free: free(source); free(type); free(mnt_opts); free(dev); return fd; + +fail_close_fd: + close(fd); + fd = -1; + goto out_free; } static int send_fd(int sock_fd, int fd) @@ -1140,6 +1195,7 @@ int main(int argc, char *argv[]) static int unmount = 0; static int lazy = 0; static int quiet = 0; + char *devfd; char *commfd; int cfd; const char *opts = ""; @@ -1208,6 +1264,13 @@ int main(int argc, char *argv[]) drop_privs(); mnt = fuse_mnt_resolve_path(progname, origmnt); + if (mnt != NULL) { + res = chdir("/"); + if (res == -1) { + fprintf(stderr, "%s: failed to chdir to '/'\n", progname); + exit(1); + } + } restore_privs(); if (mnt == NULL) exit(1); @@ -1228,21 +1291,26 @@ int main(int argc, char *argv[]) return 0; } - commfd = getenv(FUSE_COMMFD_ENV); - if (commfd == NULL) { - fprintf(stderr, "%s: old style mounting not supported\n", - progname); - exit(1); + devfd = getenv(FUSE_DEVFD_ENV); + if (devfd == NULL) { + commfd = getenv(FUSE_COMMFD_ENV); + if (commfd == NULL) { + fprintf(stderr, "%s: old style mounting not supported\n", + progname); + exit(1); + } } - fd = mount_fuse(mnt, opts); + fd = mount_fuse(mnt, opts, devfd); if (fd == -1) exit(1); - cfd = atoi(commfd); - res = send_fd(cfd, fd); - if (res == -1) - exit(1); + if (devfd == NULL) { + cfd = atoi(commfd); + res = send_fd(cfd, fd); + if (res == -1) + exit(1); + } return 0; } |
