fusermount
authorMiklos Szeredi <miklos@szeredi.hu>
Thu, 8 Nov 2001 14:56:53 +0000 (14:56 +0000)
committerMiklos Szeredi <miklos@szeredi.hu>
Thu, 8 Nov 2001 14:56:53 +0000 (14:56 +0000)
Makefile.am
configure.in
include/fuse.h
util/.cvsignore [new file with mode: 0644]
util/Makefile.am [new file with mode: 0644]
util/fusermount.c

index dc261451bdb0972303dfee2d4fd2464f985af3bf..027dd8a41efd65588242fe29b0bb2119ac000a3d 100644 (file)
@@ -1,3 +1,3 @@
 ## Process this file with automake to produce Makefile.in
 
-SUBDIRS = kernel lib example include
+SUBDIRS = kernel lib util example include
index 8f3b2793cd865f4c3de0980b6dd030b193e65584..247d1cf23f4ebd8ec4d1c44a5ba6feb6d0a27531 100644 (file)
@@ -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])
 
 
index 14b64516cab44fe0ceed9154720c1d7647dff9e2..8407f26deaa512d3594a177d9e3f1159fb3a2ca6 100644 (file)
@@ -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 (file)
index 0000000..5f7d28d
--- /dev/null
@@ -0,0 +1,4 @@
+Makefile.in
+Makefile
+.deps
+fusermount
diff --git a/util/Makefile.am b/util/Makefile.am
new file mode 100644 (file)
index 0000000..e40103e
--- /dev/null
@@ -0,0 +1,5 @@
+## Process this file with automake to produce Makefile.in
+
+bin_PROGRAMS = fusermount
+
+fusermount_SOURCES = fusermount.c
index 784fd472db68e2dea08b252b9a7e85426720e836..df3830716912522af597187fd40e015e51f9d518 100644 (file)
@@ -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>
 #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);
 }