summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiklos Szeredi <miklos@szeredi.hu>2004-11-20 10:53:22 +0000
committerMiklos Szeredi <miklos@szeredi.hu>2004-11-20 10:53:22 +0000
commitf208f8989f2f11d95eb8e92dd6be012f1364c3df (patch)
treef2c189b709d2a4007f2b64e42a534fdecdf6416b
parent9122de58740319853f64b537264dd38e8a61ea3c (diff)
downloadfuse-f208f8989f2f11d95eb8e92dd6be012f1364c3df.tar.gz
-rw-r--r--ChangeLog6
-rw-r--r--lib/fuse.c18
-rw-r--r--util/fusermount.c260
3 files changed, 232 insertions, 52 deletions
diff --git a/ChangeLog b/ChangeLog
index 0235fbf..da2b471 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2004-11-19 Miklos Szeredi <miklos@szeredi.hu>
+
+ * Make libfuse and fusermount compatible with future versions
+
+ * fusermount: properly add mount options to /etc/mtab
+
2004-11-15 Miklos Szeredi <miklos@szeredi.hu>
* fusermount: do not resolve last component of mountpoint on if it
diff --git a/lib/fuse.c b/lib/fuse.c
index 22d6509..236a018 100644
--- a/lib/fuse.c
+++ b/lib/fuse.c
@@ -233,6 +233,7 @@ static struct node *find_node(struct fuse *f, fino_t parent, char *name,
hash_ino(f, node);
out:
+ attr->_user_ino = node->ino;
node->version = version;
out_err:
pthread_mutex_unlock(&f->lock);
@@ -660,6 +661,7 @@ static void do_getattr(struct fuse *f, struct fuse_in_header *in)
memset(&arg, 0, sizeof(struct fuse_attr_out));
arg.attr_valid = ATTR_REVALIDATE_TIME;
arg.attr_valid_nsec = 0;
+ arg.attr._user_ino = in->ino;
convert_stat(&buf, &arg.attr);
}
@@ -747,6 +749,7 @@ static void do_setattr(struct fuse *f, struct fuse_in_header *in,
memset(&outarg, 0, sizeof(struct fuse_attr_out));
outarg.attr_valid = ATTR_REVALIDATE_TIME;
outarg.attr_valid_nsec = 0;
+ outarg.attr._user_ino = in->ino;
convert_stat(&buf, &outarg.attr);
}
}
@@ -1686,16 +1689,21 @@ void __fuse_set_getcontext_func(struct fuse_context *(*func)(void))
static int check_version(struct fuse *f)
{
int res;
- FILE *vf = fopen(FUSE_VERSION_FILE, "r");
+ const char *version_file = FUSE_VERSION_FILE;
+ FILE *vf = fopen(version_file, "r");
if (vf == NULL) {
- fprintf(stderr, "fuse: kernel interface too old, need >= %i.%i\n",
- FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
- return -1;
+ version_file = "/sys/fs/fuse/version";
+ vf = fopen(version_file, "r");
+ if (vf == NULL) {
+ fprintf(stderr, "fuse: kernel interface too old, need >= %i.%i\n",
+ FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
+ return -1;
+ }
}
res = fscanf(vf, "%i.%i", &f->majorver, &f->minorver);
fclose(vf);
if (res != 2) {
- fprintf(stderr, "fuse: error reading %s\n", FUSE_VERSION_FILE);
+ fprintf(stderr, "fuse: error reading %s\n", version_file);
return -1;
}
if (f->majorver != FUSE_KERNEL_VERSION) {
diff --git a/util/fusermount.c b/util/fusermount.c
index a25eccf..39eb478 100644
--- a/util/fusermount.c
+++ b/util/fusermount.c
@@ -37,6 +37,10 @@
#define FUSE_COMMFD_ENV "_FUSE_COMMFD"
+#define FUSE_DEV_OLD "/proc/fs/fuse/dev"
+#define FUSE_DEV_NEW "/dev/fuse"
+#define FUSE_SYS_DEV "/sys/class/misc/fuse/dev"
+
const char *progname;
static const char *get_user_name()
@@ -77,13 +81,13 @@ static void unlock_mtab(int mtablock)
}
}
-static int add_mount(const char *fsname, const char *mnt, const char *type)
+static int add_mount(const char *fsname, const char *mnt, const char *type,
+ const char *opts)
{
int res;
const char *mtab = _PATH_MOUNTED;
struct mntent ent;
FILE *fp;
- char *opts;
fp = setmntent(mtab, "a");
if (fp == NULL) {
@@ -92,27 +96,10 @@ static int add_mount(const char *fsname, const char *mnt, const char *type)
return -1;
}
- if (getuid() != 0) {
- const char *user = get_user_name();
- if (user == NULL)
- return -1;
-
- opts = malloc(strlen(user) + 128);
- if (opts != NULL)
- sprintf(opts, "rw,nosuid,nodev,user=%s", user);
- }
- else
- opts = strdup("rw,nosuid,nodev");
-
- if (opts == NULL) {
- fprintf(stderr, "%s: failed to allocate memory\n", progname);
- return -1;
- }
-
ent.mnt_fsname = (char *) fsname;
ent.mnt_dir = (char *) mnt;
ent.mnt_type = (char *) type;
- ent.mnt_opts = opts;
+ ent.mnt_opts = (char *) opts;
ent.mnt_freq = 0;
ent.mnt_passno = 0;
res = addmntent(fp, &ent);
@@ -352,12 +339,66 @@ static int find_mount_flag(const char *s, unsigned len, int *on, int *flag)
return 0;
}
+static int add_option(char **optsp, const char *opt, unsigned expand)
+{
+ char *newopts;
+ if (*optsp == NULL)
+ newopts = strdup(opt);
+ else {
+ unsigned oldsize = strlen(*optsp);
+ unsigned newsize = oldsize + 1 + strlen(opt) + expand + 1;
+ newopts = realloc(*optsp, newsize);
+ if (newopts)
+ sprintf(newopts + oldsize, ",%s", opt);
+ }
+ if (newopts == NULL) {
+ fprintf(stderr, "%s: failed to allocate memory\n", progname);
+ return -1;
+ }
+ *optsp = newopts;
+ return 0;
+}
+
+static int get_mnt_opts(int flags, char *opts, char **mnt_optsp)
+{
+ int i;
+ int l;
+
+ if (!(flags & MS_RDONLY) && add_option(mnt_optsp, "rw", 0) == -1)
+ return -1;
+
+ for (i = 0; mount_flags[i].opt != NULL; i++) {
+ if (mount_flags[i].on && (flags & mount_flags[i].flag) &&
+ add_option(mnt_optsp, mount_flags[i].opt, 0) == -1)
+ return -1;
+ }
+
+ if (add_option(mnt_optsp, opts, 0) == -1)
+ return -1;
+ /* remove comma from end of opts*/
+ l = strlen(*mnt_optsp);
+ if ((*mnt_optsp)[l-1] == ',')
+ (*mnt_optsp)[l-1] = '\0';
+ if (getuid() != 0) {
+ const char *user = get_user_name();
+ if (user == NULL)
+ return -1;
+
+ if (add_option(mnt_optsp, "user=", strlen(user)) == -1)
+ return -1;
+ strcat(*mnt_optsp, user);
+ }
+ return 0;
+}
+
static int do_mount(const char *mnt, const char *type, mode_t rootmode,
- int fd, const char *opts, char **fsnamep)
+ int fd, const char *opts, const char *dev, char **fsnamep,
+ char **mnt_optsp)
{
int res;
int flags = MS_NOSUID | MS_NODEV;
char *optbuf;
+ char *mnt_opts = NULL;
const char *s;
char *d;
char *fsname = NULL;
@@ -404,9 +445,15 @@ static int do_mount(const char *mnt, const char *type, mode_t rootmode,
if (*s)
s++;
}
+ res = get_mnt_opts(flags, optbuf, &mnt_opts);
+ if (res == -1) {
+ free(mnt_opts);
+ free(optbuf);
+ return -1;
+ }
sprintf(d, "fd=%i,rootmode=%o,uid=%i", fd, rootmode, getuid());
if (fsname == NULL) {
- fsname = strdup(FUSE_DEV);
+ fsname = strdup(dev);
if (!fsname) {
fprintf(stderr, "%s: failed to allocate memory\n", progname);
free(optbuf);
@@ -415,12 +462,15 @@ static int do_mount(const char *mnt, const char *type, mode_t rootmode,
}
res = mount(fsname, mnt, type, flags, optbuf);
- free(optbuf);
if (res == -1) {
fprintf(stderr, "%s: mount failed: %s\n", progname, strerror(errno));
free(fsname);
+ free(mnt_opts);
+ } else {
+ *fsnamep = fsname;
+ *mnt_optsp = mnt_opts;
}
- *fsnamep = fsname;
+ free(optbuf);
return res;
}
@@ -430,15 +480,20 @@ static int check_version(void)
int res;
int majorver;
int minorver;
- FILE *vf = fopen(FUSE_VERSION_FILE, "r");
+ const char *version_file = FUSE_VERSION_FILE;
+ FILE *vf = fopen(version_file, "r");
if (vf == NULL) {
- fprintf(stderr, "%s: kernel interface too old\n", progname);
- return -1;
+ version_file = "/sys/fs/fuse/version";
+ vf = fopen(version_file, "r");
+ if (vf == NULL) {
+ fprintf(stderr, "%s: kernel interface too old\n", progname);
+ return -1;
+ }
}
res = fscanf(vf, "%i.%i", &majorver, &minorver);
fclose(vf);
if (res != 2) {
- fprintf(stderr, "%s: error reading %s\n", progname, FUSE_VERSION_FILE);
+ fprintf(stderr, "%s: error reading %s\n", progname, version_file);
return -1;
}
if (majorver < 3) {
@@ -506,20 +561,106 @@ static int check_perm(const char **mntp, struct stat *stbuf, int *currdir_fd)
return 0;
}
-static int mount_fuse(const char *mnt, const char *opts)
+static int try_open(const char *dev, char **devp, int silent)
+{
+ int fd = open(dev, O_RDWR);
+ if (fd != -1) {
+ *devp = strdup(dev);
+ if (*devp == NULL) {
+ fprintf(stderr, "%s: failed to allocate memory\n", progname);
+ close(fd);
+ fd = -1;
+ }
+ } else if (!silent) {
+ fprintf(stderr, "%s: failed to open %s: %s\n", progname, dev,
+ strerror(errno));
+ }
+ return fd;
+}
+
+#define FUSE_TMP_DIRNAME "/tmp/.fuse_devXXXXXX"
+#define FUSE_TMP_DEVNAME "/fuse"
+
+static int try_open_new_temp(unsigned devnum, char **devp)
{
int res;
int fd;
- const char *dev = FUSE_DEV;
- const char *type = "fuse";
+ char dirname[] = FUSE_TMP_DIRNAME;
+ char filename[] = FUSE_TMP_DIRNAME FUSE_TMP_DEVNAME;
+ if (mkdtemp(dirname) == NULL) {
+ fprintf(stderr, "%s: failed to create temporary device directory: %s\n",
+ progname, strerror(errno));
+ return -1;
+ }
+ sprintf(filename, "%s%s", dirname, FUSE_TMP_DEVNAME);
+ res = mknod(filename, S_IFCHR | 0600, devnum);
+ if (res == -1) {
+ fprintf(stderr, "%s: failed to create device node: %s\n", progname,
+ strerror(errno));
+ rmdir(dirname);
+ return -1;
+ }
+ fd = try_open(filename, devp, 0);
+ unlink(filename);
+ rmdir(dirname);
+ return fd;
+}
+
+static int try_open_new(char **devp)
+{
+ const char *dev;
+ unsigned minor;
+ unsigned major;
+ int res;
struct stat stbuf;
- int mtablock;
- char *fsname;
- const char *real_mnt = mnt;
- int currdir_fd = -1;
+ unsigned devnum;
+ char buf[256];
+ int fd = open(FUSE_SYS_DEV, O_RDONLY);
+ if (fd == -1)
+ return -2;
- fd = open(dev, O_RDWR);
- if (fd == -1
+ res = read(fd, buf, sizeof(buf)-1);
+ close(fd);
+ if (res == -1) {
+ fprintf(stderr, "%s: failed to read from %s: %s\n", progname,
+ FUSE_SYS_DEV, strerror(errno));
+ return -1;
+ }
+
+ buf[res] = '\0';
+ if (sscanf(buf, "%u:%u", &major, &minor) != 2) {
+ fprintf(stderr, "%s: parse error reading from %s\n", progname,
+ FUSE_SYS_DEV);
+ return -1;
+ }
+
+ devnum = (major << 8) + (minor & 0xff) + ((minor & 0xff00) << 12);
+ dev = FUSE_DEV_NEW;
+ res = stat(dev, &stbuf);
+ if (res == -1)
+ return try_open_new_temp(devnum, devp);
+
+ if ((stbuf.st_mode & S_IFMT) != S_IFCHR || stbuf.st_rdev != devnum) {
+ fprintf(stderr, "%s: %s exists but has wrong attributes\n", progname,
+ dev);
+ return -1;
+ }
+ return try_open(dev, devp, 0);
+}
+
+static int open_fuse_device(char **devp)
+{
+ int fd;
+
+ fd = try_open_new(devp);
+ if (fd != -2)
+ return fd;
+
+ fd = try_open(FUSE_DEV_OLD, devp, 1);
+ if (fd != -1)
+ return fd;
+
+ if (1
#ifndef AUTO_MODPROBE
&& getuid() == 0
#endif
@@ -534,13 +675,37 @@ static int mount_fuse(const char *mnt, const char *opts)
if (pid != -1)
waitpid(pid, &status, 0);
- fd = open(dev, O_RDWR);
+ fd = try_open_new(devp);
+ if (fd != -2)
+ return fd;
+
+ fd = try_open(FUSE_DEV_OLD, devp, 1);
+ if (fd != -1)
+ return fd;
+
}
- if (fd == -1) {
- fprintf(stderr, "%s: unable to open fuse device %s: %s\n", progname,
- dev, strerror(errno));
+
+ fprintf(stderr, "fuse device not found, try 'modprobe fuse' first\n");
+ return -1;
+}
+
+
+static int mount_fuse(const char *mnt, const char *opts)
+{
+ int res;
+ int fd;
+ char *dev;
+ const char *type = "fuse";
+ struct stat stbuf;
+ int mtablock;
+ char *fsname;
+ char *mnt_opts;
+ const char *real_mnt = mnt;
+ int currdir_fd = -1;
+
+ fd = open_fuse_device(&dev);
+ if (fd == -1)
return -1;
- }
if (getuid() != 0) {
res = drop_privs();
@@ -553,7 +718,7 @@ static int mount_fuse(const char *mnt, const char *opts)
res = check_perm(&real_mnt, &stbuf, &currdir_fd);
if (res != -1)
res = do_mount(real_mnt, type, stbuf.st_mode & S_IFMT, fd, opts,
- &fsname);
+ dev, &fsname, &mnt_opts);
}
if (getuid() != 0)
@@ -569,15 +734,16 @@ static int mount_fuse(const char *mnt, const char *opts)
if (geteuid() == 0) {
mtablock = lock_mtab();
- res = add_mount(fsname, mnt, type);
- free(fsname);
+ res = add_mount(fsname, mnt, type, mnt_opts);
unlock_mtab(mtablock);
if (res == -1) {
umount2(mnt, 2); /* lazy umount */
return -1;
}
- } else
- free(fsname);
+ }
+ free(fsname);
+ free(mnt_opts);
+ free(dev);
return fd;
}