aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am2
-rw-r--r--configure.in2
-rw-r--r--include/fuse.h1
-rw-r--r--util/.cvsignore4
-rw-r--r--util/Makefile.am5
-rw-r--r--util/fusermount.c244
6 files changed, 218 insertions, 40 deletions
diff --git a/Makefile.am b/Makefile.am
index dc26145..027dd8a 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,3 +1,3 @@
## Process this file with automake to produce Makefile.in
-SUBDIRS = kernel lib example include
+SUBDIRS = kernel lib util example include
diff --git a/configure.in b/configure.in
index 8f3b279..247d1cf 100644
--- a/configure.in
+++ b/configure.in
@@ -49,6 +49,6 @@ AC_SUBST(KERNINCLUDE)
kmoduledir=/lib/modules/$kernsrcver
AC_SUBST(kmoduledir)
-AC_OUTPUT([Makefile kernel/Makefile lib/Makefile example/Makefile include/Makefile include/linux/Makefile])
+AC_OUTPUT([Makefile kernel/Makefile lib/Makefile util/Makefile example/Makefile include/Makefile include/linux/Makefile])
diff --git a/include/fuse.h b/include/fuse.h
index 14b6451..8407f26 100644
--- a/include/fuse.h
+++ b/include/fuse.h
@@ -27,6 +27,7 @@ struct fuse_cred {
uid_t uid;
gid_t gid;
/* FIXME: supplementary groups should also be included */
+ /* (And capabilities???) */
};
/**
diff --git a/util/.cvsignore b/util/.cvsignore
new file mode 100644
index 0000000..5f7d28d
--- /dev/null
+++ b/util/.cvsignore
@@ -0,0 +1,4 @@
+Makefile.in
+Makefile
+.deps
+fusermount
diff --git a/util/Makefile.am b/util/Makefile.am
new file mode 100644
index 0000000..e40103e
--- /dev/null
+++ b/util/Makefile.am
@@ -0,0 +1,5 @@
+## Process this file with automake to produce Makefile.in
+
+bin_PROGRAMS = fusermount
+
+fusermount_SOURCES = fusermount.c
diff --git a/util/fusermount.c b/util/fusermount.c
index 784fd47..df38307 100644
--- a/util/fusermount.c
+++ b/util/fusermount.c
@@ -12,6 +12,7 @@
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
+#include <pwd.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/mount.h>
@@ -21,6 +22,164 @@
#define FUSE_DEV "/proc/fs/fuse/dev"
const char *progname;
+const char *fusermnt = "/etc/fusermnt";
+const char *fusermnt_temp = "/etc/fusermnt~";
+
+#define FUSE_USERNAME_MAX 256
+#define FUSE_PATH_MAX 4096
+#define FUSEMNT_LINE_MAX (FUSE_USERNAME_MAX + 1 + FUSE_PATH_MAX + 1)
+
+static const char *get_user_name()
+{
+ struct passwd *pw = getpwuid(getuid());
+ if(pw != NULL && pw->pw_name != NULL)
+ return pw->pw_name;
+ else {
+ fprintf(stderr, "%s: could not determine username\n", progname);
+ return NULL;
+ }
+}
+
+static int fusermnt_lock()
+{
+ int res;
+ const char *lockfile = fusermnt;
+ int fd = open(lockfile, O_WRONLY | O_CREAT, 0644);
+ if(fd == -1) {
+ fprintf(stderr, "%s: failed to open lockfile %s: %s\n", progname,
+ lockfile, strerror(errno));
+ return -1;
+ }
+ res = lockf(fd, F_LOCK, 0);
+ if(res == -1) {
+ fprintf(stderr, "%s: failed to lock file %s: %s\n", progname,
+ lockfile, strerror(errno));
+ close(fd);
+ return -1;
+ }
+
+ return fd;
+}
+
+static void fusermnt_unlock(int fd)
+{
+ lockf(fd, F_UNLCK, 0);
+ close(fd);
+}
+
+
+static int add_mount(const char *mnt)
+{
+ FILE *fp;
+ int lockfd;
+ const char *user = get_user_name();
+ if(user == NULL)
+ return -1;
+
+ lockfd = fusermnt_lock();
+ if(lockfd == -1)
+ return -1;
+
+ fp = fopen(fusermnt, "a");
+ if(fp == NULL) {
+ fprintf(stderr, "%s: could not open %s for writing: %s\n", progname,
+ fusermnt, strerror(errno));
+ return -1;
+ }
+ fprintf(fp, "%s %s\n", user, mnt);
+ fclose(fp);
+
+ fusermnt_unlock(lockfd);
+ return 0;
+}
+
+static int remove_mount(const char *mnt)
+{
+ FILE *fp;
+ FILE *newfp;
+ int lockfd;
+ int found;
+ char buf[FUSEMNT_LINE_MAX + 1];
+ const char *user = get_user_name();
+ if(user == NULL)
+ return -1;
+
+ lockfd = fusermnt_lock();
+ if(lockfd == -1)
+ return -1;
+
+ fp = fopen(fusermnt, "r");
+ if(fp == NULL) {
+ fprintf(stderr, "%s: could not open %s for reading: %s\n", progname,
+ fusermnt, strerror(errno));
+ fusermnt_unlock(lockfd);
+ return -1;
+ }
+
+ newfp = fopen(fusermnt_temp, "w");
+ if(newfp == NULL) {
+ fprintf(stderr, "%s: could not open %s for writing: %s\n", progname,
+ fusermnt_temp, strerror(errno));
+ fclose(fp);
+ fusermnt_unlock(lockfd);
+ return -1;
+ }
+
+ found = 0;
+ while(fgets(buf, sizeof(buf), fp) != NULL) {
+ char *end = buf + strlen(buf) - 1;
+ char *p;
+ if(*end != '\n') {
+ fprintf(stderr, "%s: line too long in file %s\n", progname,
+ fusermnt);
+ while(fgets(buf, sizeof(buf), fp) != NULL) {
+ char *end = buf + strlen(buf) - 1;
+ if(*end == '\n')
+ break;
+ }
+ continue;
+ }
+ *end = '\0';
+
+ for(p = buf; *p != '\0' && *p != ' '; p++);
+ if(*p == '\0') {
+ fprintf(stderr, "%s: malformed line in file %s\n", progname,
+ fusermnt);
+ continue;
+ }
+ *p = '\0';
+ p++;
+ if(strcmp(user, buf) == 0 && strcmp(mnt, p) == 0)
+ found = 1;
+ else
+ fprintf(newfp, "%s %s\n", buf, p);
+ }
+
+ fclose(fp);
+ fclose(newfp);
+
+ if(found) {
+ int res;
+ res = rename(fusermnt_temp, fusermnt);
+ if(res == -1) {
+ fprintf(stderr, "%s: failed to rename %s to %s: %s\n",
+ progname, fusermnt_temp, fusermnt, strerror(errno));
+ fusermnt_unlock(lockfd);
+ return -1;
+ }
+ }
+ else {
+ fprintf(stderr, "%s: entry for %s not found in %s\n", progname, mnt,
+ fusermnt);
+ unlink(fusermnt_temp);
+ fusermnt_unlock(lockfd);
+ return -1;
+ }
+
+ fusermnt_unlock(lockfd);
+ return 0;
+}
+
static int do_mount(const char *dev, const char *mnt, const char *type,
mode_t rootmode, int fd)
@@ -99,15 +258,34 @@ static int mount_fuse(const char *mnt)
if(res == -1)
return -1;
+ res = add_mount(mnt);
+ if(res == -1) {
+ umount(mnt);
+ return -1;
+ }
+
return fd;
}
+static int do_umount(const char *mnt)
+{
+ int res;
+
+ res = remove_mount(mnt);
+ if(res == -1)
+ return -1;
+
+ umount(mnt);
+ return 0;
+}
+
static void usage()
{
fprintf(stderr,
- "%s: [options] mountpoint program [args ...]\n"
+ "%s: [options] mountpoint [program [args ...]]\n"
"Options:\n"
- " -h print help\n",
+ " -h print help\n"
+ " -u umount\n",
progname);
exit(1);
}
@@ -115,12 +293,11 @@ static void usage()
int main(int argc, char *argv[])
{
int a;
- const char *mnt = NULL;
- char **userprog;
- pid_t pid;
int fd;
- int status;
int res;
+ const char *mnt = NULL;
+ int umount = 0;
+ char **userprog;
progname = argv[0];
@@ -132,6 +309,10 @@ int main(int argc, char *argv[])
case 'h':
usage();
break;
+
+ case 'u':
+ umount = 1;
+ break;
default:
fprintf(stderr, "%s: Unknown option %s\n", progname, argv[a]);
@@ -146,6 +327,14 @@ int main(int argc, char *argv[])
mnt = argv[a++];
+ if(umount) {
+ res = do_umount(mnt);
+ if(res == -1)
+ exit(1);
+
+ return 0;
+ }
+
if(a == argc) {
fprintf(stderr, "%s: Missing program argument\n", progname);
exit(1);
@@ -162,38 +351,17 @@ int main(int argc, char *argv[])
dup2(fd, 0);
close(fd);
}
-
- pid = fork();
- if(pid == -1) {
- fprintf(stderr, "%s: Unable to fork: %s\n", progname, strerror(errno));
- umount(mnt);
- exit(1);
- }
-
- if(pid == 0) {
- /* Drop setuid/setgid permissions */
- setuid(getuid());
- setgid(getgid());
-
- execv(userprog[0], userprog);
- fprintf(stderr, "%s: failed to exec %s: %s\n", progname, userprog[0],
- strerror(errno));
- exit(1);
- }
- close(0);
- res = waitpid(pid, &status, 0);
- if(res == -1) {
- fprintf(stderr, "%s: failed to wait for child: %s\n", progname,
- strerror(errno));
- exit(1);
- }
- res = umount(mnt);
- if(res == -1) {
- fprintf(stderr, "%s: failed to unmount %s: %s\n", progname, mnt,
- strerror(errno));
- exit(1);
- }
+ /* Drop setuid/setgid permissions */
+ setuid(getuid());
+ setgid(getgid());
- return 0;
+ execv(userprog[0], userprog);
+ fprintf(stderr, "%s: failed to exec %s: %s\n", progname, userprog[0],
+ strerror(errno));
+
+ execl("/proc/self/exe", progname, "-u", mnt, NULL);
+ fprintf(stderr, "%s: failed to exec self: %s\n", progname,
+ strerror(errno));
+ exit(1);
}