diff options
-rw-r--r-- | configure.ac | 1 | ||||
-rw-r--r-- | src/Makefile.am | 12 | ||||
-rw-r--r-- | src/usersfs.c | 87 | ||||
-rw-r--r-- | src/volumefs.c | 0 | ||||
-rw-r--r-- | src/volumesfs.c | 162 |
5 files changed, 257 insertions, 5 deletions
diff --git a/configure.ac b/configure.ac index 9bb9136..9ffe466 100644 --- a/configure.ac +++ b/configure.ac @@ -20,7 +20,6 @@ GLIB_GSETTINGS # Checks for libraries. PKG_CHECK_MODULES([FUSE], [fuse]) PKG_CHECK_MODULES([UDISKS2], [udisks2]) -PKG_CHECK_MODULES([GIO], [gio-unix-2.0]) # Output files AC_CONFIG_FILES([ diff --git a/src/Makefile.am b/src/Makefile.am index bbfd1a6..de90afd 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,5 +1,9 @@ -sbin_PROGRAMS = volumefs +sbin_PROGRAMS = volumesfs usersfs -volumefs_SOURCES = volumefs.c -volumefs_CPPFLAGS = $(FUSE_CFLAGS) $(UDISKS2_CFLAGS) -volumefs_LDADD = $(FUSE_LIBS) $(UDISKS2_LIBS) +volumesfs_SOURCES = volumesfs.c +volumesfs_CPPFLAGS = $(FUSE_CFLAGS) $(UDISKS2_CFLAGS) +volumesfs_LDADD = $(FUSE_LIBS) $(UDISKS2_LIBS) + +usersfs_SOURCES = usersfs.c +usersfs_CPPFLAGS = $(FUSE_CFLAGS) +usersfs_LDADD = $(FUSE_LIBS) diff --git a/src/usersfs.c b/src/usersfs.c new file mode 100644 index 0000000..52b9f05 --- /dev/null +++ b/src/usersfs.c @@ -0,0 +1,87 @@ +#define FUSE_USE_VERSION 30 + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include <pwd.h> + +#include <fuse.h> + +static void * usersfs_init(struct fuse_conn_info *conn) +{ + +} + +static void usersfs_destroy(void *user_data) +{ + +} + +static int usersfs_getattr(const char *path, struct stat *stbuf) +{ + if (strcmp(path, "/") == 0) { + stbuf->st_mode = S_IFDIR | 0755; + stbuf->st_nlink = 2; + } else { + struct passwd *pwent = getpwnam(path + 1); + if (pwent && pwent->pw_dir) { + stbuf->st_mode = S_IFLNK | 0444; + stbuf->st_nlink = 1; + } else { + return -ENOENT; + } + } + return 0; +} + +static int usersfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, + off_t offset, struct fuse_file_info *fi) +{ + if (strcmp(path, "/") != 0) { + return -ENOENT; + } + + (void) offset; + (void) fi; + + filler(buf, ".", NULL, 0); + filler(buf, "..", NULL, 0); + + struct passwd *pwent; + setpwent(); + while (pwent = getpwent()) { + if ((pwent->pw_uid == 0 || pwent->pw_uid >= 1000) && pwent->pw_name && pwent->pw_dir) { + filler(buf, pwent->pw_name, NULL, 0); + } + } + setpwent(); + +} + +static int usersfs_readlink(const char *path, char *buf, size_t size) +{ + if (strcmp(path, "/") == 0) { + return -EINVAL; + } + + struct passwd *pwent = getpwnam(path + 1); + if (pwent && pwent->pw_dir) { + strcpy(buf, pwent->pw_dir); + return 0; + } else { + return -ENOENT; + } +} + +static struct fuse_operations usersfs_oper = { + .getattr = usersfs_getattr, + .readdir = usersfs_readdir, + .readlink = usersfs_readlink +}; + +int main(int argc, char *argv[]) +{ + return fuse_main(argc, argv, &usersfs_oper, NULL); +} diff --git a/src/volumefs.c b/src/volumefs.c deleted file mode 100644 index e69de29..0000000 --- a/src/volumefs.c +++ /dev/null diff --git a/src/volumesfs.c b/src/volumesfs.c new file mode 100644 index 0000000..dc67f77 --- /dev/null +++ b/src/volumesfs.c @@ -0,0 +1,162 @@ +#define FUSE_USE_VERSION 30 + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include <fuse.h> + +#include <udisks/udisks.h> + +static GMainLoop *main_loop; +static GThread *sub_thread; +static UDisksClient *client; + +static GHashTable *mounts; +G_LOCK_DEFINE_STATIC(mounts); + +static void udisks_changed(UDisksClient *client, gpointer user_data) +{ + GDBusObjectManager *manager = udisks_client_get_object_manager(client); + GList *objs = g_dbus_object_manager_get_objects(manager); + + G_LOCK(mounts); + + g_debug("udisks changed"); + + g_hash_table_remove_all(mounts); + + for (GList *l = objs; l; l = g_list_next(l)) { + UDisksObject *obj = UDISKS_OBJECT(l->data); + UDisksFilesystem *filesys = udisks_object_get_filesystem(obj); + UDisksBlock *block = udisks_object_get_block(obj); + if (block && filesys) { + const gchar *name = udisks_block_get_id_label(block); + if (!name || strlen(name) == 0) { + name = udisks_block_get_id_uuid(block); + } + + const gchar * const * mpoints = udisks_filesystem_get_mount_points(filesys); + const gchar * mountpoint = mpoints && mpoints[0] ? mpoints[0] : NULL; + + if (name && mountpoint) { + g_debug("%s -> %s", name, mountpoint); + g_hash_table_insert(mounts, g_strdup(name), g_strdup(mountpoint)); + } + } + if (filesys) g_object_unref(filesys); + if (block) g_object_unref(block); + } + + G_UNLOCK(mounts); + + g_list_free_full(objs, g_object_unref); +} + +static gpointer sub_thread_main(gpointer user_data) +{ + GError *error = NULL; + + client = udisks_client_new_sync(NULL, &error); + if (!client) { + g_printerr("Could not connect to UDisks2 service: %s", error->message); + g_error_free(error); + } + + g_signal_connect(client, "changed", + G_CALLBACK(udisks_changed), NULL); + + udisks_changed(client, NULL); + + g_main_loop_run(main_loop); +} + +static void * volumesfs_init(struct fuse_conn_info *conn) +{ + main_loop = g_main_loop_new(NULL, FALSE); + + mounts = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); + + sub_thread = g_thread_new("volumesfs-sub-thread", sub_thread_main, NULL); +} + +static void volumesfs_destroy(void *user_data) +{ + g_main_loop_quit(main_loop); + + g_thread_join(sub_thread); + + g_object_unref(client); + g_hash_table_destroy(mounts); + g_object_unref(main_loop); +} + +static int volumesfs_getattr(const char *path, struct stat *stbuf) +{ + if (strcmp(path, "/") == 0) { + stbuf->st_mode = S_IFDIR | 0755; + stbuf->st_nlink = 2; + } else { + stbuf->st_mode = S_IFLNK | 0444; + stbuf->st_nlink = 1; + } + return 0; +} + +static int volumesfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, + off_t offset, struct fuse_file_info *fi) +{ + if (strcmp(path, "/") != 0) { + return -ENOENT; + } + + G_LOCK(mounts); + + (void) offset; + (void) fi; + + filler(buf, ".", NULL, 0); + filler(buf, "..", NULL, 0); + + + GHashTableIter iter; + gchar *name; + g_hash_table_iter_init(&iter, mounts); + while (g_hash_table_iter_next(&iter, (void**)&name, NULL)) { + filler(buf, name, NULL, 0); + } + + G_UNLOCK(mounts); +} + +static int volumesfs_readlink(const char *path, char *buf, size_t size) +{ + if (strcmp(path, "/") == 0) { + return -EINVAL; + } + + G_LOCK(mounts); + gchar *mountpoint = g_hash_table_lookup(mounts, path + 1); + G_UNLOCK(mounts); + + if (mountpoint) { + strcpy(buf, mountpoint); + return 0; + } else { + return -ENOENT; + } +} + +static struct fuse_operations volumesfs_oper = { + .init = volumesfs_init, + .destroy = volumesfs_destroy, + .getattr = volumesfs_getattr, + .readdir = volumesfs_readdir, + .readlink = volumesfs_readlink +}; + +int main(int argc, char *argv[]) +{ + return fuse_main(argc, argv, &volumesfs_oper, NULL); +} |