summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configure.ac1
-rw-r--r--src/Makefile.am12
-rw-r--r--src/usersfs.c87
-rw-r--r--src/volumefs.c0
-rw-r--r--src/volumesfs.c162
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);
+}