[hackers] [skvm] Code cleanup. Fixed typo in HACKING. || Dimitrios Papastamos

From: <hg_AT_suckless.org>
Date: Wed, 29 Apr 2009 17:58:04 +0000 (UTC)

changeset: 3:5a0c07eba218
tag: tip
user: Dimitrios Papastamos <stateless [at] archlinux.us>
date: Wed Apr 29 18:57:39 2009 -0700
files: HACKING README skvm.1 skvm.c
description:
Code cleanup. Fixed typo in HACKING.

diff -r bd7cfb8e4d21 -r 5a0c07eba218 HACKING
--- a/HACKING Wed Apr 29 01:46:42 2009 -0700
+++ b/HACKING Wed Apr 29 18:57:39 2009 -0700
@@ -1,8 +1,8 @@
 Coding style and project aims
 =============================
 
-If you plan to hack this code, please follow the coding convetions
+If you plan to hack this code, please follow the coding conventions
 used in the current code. Use format.sh and the latest version of astyle
 to format the code. This project does not aim to be portable as it is
-mainly used on Linux. Make sure the code is secure as skvm is meant
+mainly used on GNU/Linux. Make sure the code is secure as skvm is meant
 to execute as root.
diff -r bd7cfb8e4d21 -r 5a0c07eba218 README
--- a/README Wed Apr 29 01:46:42 2009 -0700
+++ b/README Wed Apr 29 18:57:39 2009 -0700
@@ -2,7 +2,7 @@
 
 What is it?
 ===========
-SKVM is a lightweight volume manager for Linux. It depends on hal and dbus.
+SKVM is a lightweight volume manager for GNU/Linux. It depends on hal and dbus.
 It is meant to be simple to use, efficient and functional. It has
 been tested and working on Arch linux and Debian, however the init script
 needs to be adapted when used on Debian.
diff -r bd7cfb8e4d21 -r 5a0c07eba218 skvm.1
--- a/skvm.1 Wed Apr 29 01:46:42 2009 -0700
+++ b/skvm.1 Wed Apr 29 18:57:39 2009 -0700
@@ -6,7 +6,7 @@
 .B skvm
 .RB [OPTIONS]
 .SH DESCRIPTION
-skvm is a lightweight volume manager for Linux. It depends on hal and dbus.
+skvm is a lightweight volume manager for GNU/Linux. It depends on hal and dbus.
 It is meant to be simple to use, efficient and functional.
 .SH OPTIONS
 .TP
diff -r bd7cfb8e4d21 -r 5a0c07eba218 skvm.c
--- a/skvm.c Wed Apr 29 01:46:42 2009 -0700
+++ b/skvm.c Wed Apr 29 18:57:39 2009 -0700
@@ -1,642 +1,653 @@
-/* See LICENSE file for copyright and license details. */
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <signal.h>
-#include <stdint.h>
-
-#include <mntent.h>
-#include <getopt.h>
-#include <unistd.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/file.h>
-#include <dirent.h>
-#include <syslog.h>
-#include <fcntl.h>
-
-#include <dbus/dbus.h>
-#include <dbus/dbus-glib.h>
-#include <dbus/dbus-glib-lowlevel.h>
-
-#include <hal/libhal.h>
-#include <hal/libhal-storage.h>
-
-/* ============================
- * = Macros
- * ============================
- */
-
-/* feel free to alter these to your liking */
-#define MOUNT_CMD_PATH "/bin/mount"
-#define DEFAULT_MNT_OPTIONS "noexec,nosuid"
-#define BASE_MNT_DIR "/media/"
-
-/* not user controlled */
-#define LOCKFILE "/var/run/skvm.pid"
-#define LOCKMODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
-#define FREE_WRAP(ptr) do { free(ptr); ptr = NULL; } while (0)
-#define INIT_NODE(p1, p2) \
- do { \
- p1->mountp = p2->mountp; \
- p1->did = p2->did; \
- p1->dev = p2->dev; \
- p1->label = p2->label; \
- p1->fstype = p2->fstype; \
- p1->opt = p2->opt; \
- p1->volume = p2->volume; \
- p1->drive = p2->drive; \
- } while (0)
-
-/* ============================
- * = Structs
- * ============================
- */
-
-struct device_t {
- char *args[8]; /* arguments to mount for this device */
- char *mountp; /* mount point */
- char *did; /* volume's unique id */
- char *dev; /* device associated with this volume */
- char *label; /* volume's label */
- char *fstype; /* filesystem type */
- char *opt; /* mount options */
- LibHalVolume *volume;
- LibHalDrive *drive;
- struct device_t *next;
-};
-
-/* ============================
- * = Globals
- * ============================
- */
-
-/* the dbus connection handler */
-static DBusConnection *dbus_conn = NULL;
-/* the main hal context handler */
-static LibHalContext *hal_ctx = NULL;
-/* the head of a linked list of currently mounted devices */
-static struct device_t *head = NULL;
-static struct device_t *tail = NULL;
-/* the main loop handler */
-static GMainLoop *loop = NULL;
-/* file descriptor for LOCKFILE */
-static int pid_fd = -1;
-/* flag used for debugging */
-static int debug_mode_flag = 0;
-
-/* ============================
- * = Function declarations
- * ============================
- */
-
-/* (de)/initialization functions */
-static int init_skvm(void);
-static int init_dbus(DBusError *error);
-static int init_hal(void);
-static void deinit(void);
-
-/* callback functions */
-static void device_added(LibHalContext *context, const char *did);
-static void device_removed(LibHalContext *context, const char *did);
-
-/* functions related to the device list */
-static struct device_t *get_device(char *mountp, const char *did,
- char *dev, char *label,
- const char *fstype,
- LibHalVolume *volume,
- LibHalDrive *drive);
-static void add_to_device_list(struct device_t *device);
-static void remove_from_device_list(struct device_t *prev,
- struct device_t *curr);
-static void free_device(struct device_t *device);
-
-/* functions related to how the volume manager behaves when
- * a new device is inserted */
-static int is_mounted(const char *dev);
-static char *get_mount_point(const char *dev, const char *label);
-static int resolve_symlink(const char *f, char *d, size_t d_len);
-static void consider_fstab(struct device_t *device);
-static void do_args(struct device_t *device);
-static int do_mount(struct device_t *device);
-
-/* general function helpers */
-static int file_exists(const char *path);
-static void cleanup(int sig);
-static int is_running(void);
-static void debug_dump_device(const struct device_t *device);
-
-int
-main(int argc, char *argv[]) {
- int c;
-
- static struct option long_options[] = {
- { "debug", 0, (int *)NULL, 'd' }
- };
-
- while ((c = getopt_long(argc, argv, "d", long_options,
- (int *)NULL)) != -1) {
- switch (c) {
- case 'd':
- debug_mode_flag = 1;
- break;
- }
- }
-
- if (debug_mode_flag)
- setvbuf(stdout, (char *)NULL, _IONBF, 0); /* avoid surprises */
-
- if (init_skvm() < 0)
- return EXIT_FAILURE;
-
- openlog(argv[0], LOG_PID, LOG_DAEMON);
- signal(SIGTERM, cleanup);
-
- if (!debug_mode_flag) {
- if (daemon(0, 0) < 0)
- return EXIT_FAILURE;
- if (is_running()) {
- deinit();
- return EXIT_FAILURE;
- }
- }
-
- loop = g_main_loop_new((GMainContext *)NULL, FALSE);
- g_main_run(loop);
-
- deinit();
- return EXIT_SUCCESS;
-}
-
-static int
-init_skvm(void) {
- DBusError error;
-
- dbus_error_init(&error);
- if (init_dbus(&error) < 0) {
- if (dbus_error_is_set(&error)) {
- syslog(LOG_ERR, "%s:%d: %s:%s", __FILE__, __LINE__,
- error.name, error.message);
- dbus_error_free(&error);
- return -1;
- }
- }
-
- return init_hal();
-}
-
-static int
-init_dbus(DBusError *error) {
- if (!(dbus_conn = dbus_bus_get(DBUS_BUS_SYSTEM, error)))
- return -1;
- dbus_connection_setup_with_g_main (dbus_conn, (GMainContext *)NULL);
- dbus_connection_flush(dbus_conn);
- return 0;
-}
-
-static int
-init_hal(void) {
- DBusError error;
-
- if (!(hal_ctx = libhal_ctx_new()))
- return -1;
-
- libhal_ctx_set_dbus_connection (hal_ctx, dbus_conn);
-
- libhal_ctx_set_device_added(hal_ctx, device_added);
- libhal_ctx_set_device_removed(hal_ctx, device_removed);
-
- dbus_error_init(&error);
- if (!libhal_device_property_watch_all(hal_ctx, &error)) {
- if (dbus_error_is_set(&error)) {
- syslog(LOG_ERR, "%s:%d: %s:%s", __FILE__, __LINE__,
- error.name, error.message);
- dbus_error_free (&error);
- libhal_ctx_free (hal_ctx);
- return -1;
- }
- }
-
- if (!libhal_ctx_init(hal_ctx, &error)) {
- if (dbus_error_is_set(&error)) {
- syslog(LOG_ERR, "%s:%d: %s:%s", __FILE__, __LINE__,
- error.name, error.message);
- dbus_error_free(&error);
- libhal_ctx_free(hal_ctx);
- return -1;
- }
- }
-
- return 0;
-}
-
-static void
-deinit(void) {
- struct device_t *iter, *tmp;
-
- closelog();
- libhal_ctx_shutdown(hal_ctx, (DBusError *)NULL);
- libhal_ctx_free(hal_ctx);
- dbus_connection_unref(dbus_conn);
-
- iter = head;
-
- while (iter) {
- tmp = iter;
- iter = iter->next;
- free_device(tmp);
- }
-
- if (pid_fd >= 0)
- close(pid_fd); /* releases lock */
-}
-
-/* Callback function, called when a new device has been inserted. */
-static void
-device_added(LibHalContext *context, const char *did) {
- const char *dudi, *fstype;
- char *dev, *mountp, *mountable, *label;
- LibHalVolume *volume;
- LibHalDrive *drive;
- struct device_t *device;
-
- if (!libhal_device_query_capability(context, did, "volume",
- (DBusError *)NULL))
- return;
- label = libhal_device_get_property_string(context, did, "volume.label",
- (DBusError *)NULL);
- if (!(mountable = libhal_device_get_property_string(
- context, did, "volume.fsusage", (DBusError *)NULL))
- || strcmp(mountable, "filesystem"))
- goto fail;
- if (!(volume = libhal_volume_from_udi(context, did)))
- goto fail;
- if (!(dudi = libhal_volume_get_storage_device_udi(volume)))
- goto fail;
- if (!(drive = libhal_drive_from_udi(context, dudi)))
- goto fail;
- if (!libhal_drive_is_hotpluggable(drive)
- && !libhal_drive_uses_removable_media(drive))
- goto fail;
- if (!(fstype = libhal_volume_get_fstype(volume)))
- goto fail;
- if (!(dev = libhal_device_get_property_string(context, did, "block.device",
- (DBusError *)NULL)))
- goto fail;
- mountp = get_mount_point(dev, label);
- if (!mountp)
- goto fail;
- device = get_device(mountp, did, dev, label, fstype, volume, drive);
- if (!device)
- goto fail;
- consider_fstab(device);
- if (file_exists(device->mountp) < 0)
- mkdir(device->mountp, 0750);
- do_mount(device) < 0 ? free_device(device) : add_to_device_list(device);
-
- if (debug_mode_flag && device)
- debug_dump_device(device);
-
-fail:
- if (mountable)
- libhal_free_string(mountable);
- if (label)
- libhal_free_string(label);
-}
-
-/* Callback function, called when a device has been removed. */
-static void
-device_removed(LibHalContext *context __attribute__ ((unused)),
- const char *did) {
- char *mountp = NULL;
- struct device_t *iter = head, *prev = NULL;
-
- while (iter) {
- if (!strcmp(did, iter->did)) {
- mountp = iter->mountp;
- if (!file_exists(mountp)) {
- if (rmdir(mountp) < 0)
- syslog(LOG_WARNING, "%s:%d: %s", __FILE__, __LINE__,
- strerror(errno));
- remove_from_device_list(prev, iter);
- }
- return;
- }
- prev = iter;
- iter = iter->next;
- }
-}
-
-static struct device_t *
-get_device(char *mountp, const char *did, char *dev, char *label,
- const char *fstype, LibHalVolume *volume, LibHalDrive *drive) {
- struct device_t *device = malloc(sizeof(*device));
-
- if (device) {
- device->mountp = mountp;
- device->did = strdup(did);
- device->dev = dev;
- device->label = strdup(label);
- device->fstype = strdup(fstype);
- device->opt = NULL;
- device->volume = volume;
- device->drive = drive;
- device->next = NULL;
- if (!device->did || !device->label || !device->fstype) {
- free_device(device);
- device = NULL;
- }
- }
-
- return device;
-}
-
-static void
-add_to_device_list(struct device_t *device) {
- if (!device)
- return;
-
- if (!head) {
- head = device;
- tail = head;
- INIT_NODE(head, device);
- } else {
- tail->next = device;
- tail = tail->next;
- INIT_NODE(tail, device);
- }
-}
-
-static void
-remove_from_device_list(struct device_t *prev, struct device_t *curr) {
- struct device_t *tmp = NULL;
-
- if (!curr)
- return;
-
- if (curr == head) {
- tmp = curr;
- head = curr->next;
- } else if (curr == tail) {
- tmp = curr;
- tail = prev;
- tail->next = NULL;
- } else {
- tmp = curr;
- prev->next = curr->next;
- }
-
- free_device(tmp);
-}
-
-static void
-free_device(struct device_t *device) {
- if (!device)
- return;
-
- FREE_WRAP(device->mountp);
- FREE_WRAP(device->did);
- if (device->dev)
- libhal_free_string(device->dev);
- FREE_WRAP(device->label);
- FREE_WRAP(device->fstype);
- FREE_WRAP(device->opt);
- if (device->volume)
- libhal_volume_free(device->volume);
- if (device->drive)
- libhal_drive_free(device->drive);
-
- FREE_WRAP(device);
-}
-
-static int
-is_mounted(const char *dev) {
- FILE *mtab;
- struct mntent *entry;
-
- mtab = setmntent("/etc/mtab", "r");
- if (!mtab)
- return -1;
-
- while ((entry = getmntent(mtab))) {
- if (!strcmp(entry->mnt_fsname, dev)) {
- endmntent(mtab);
- return 0;
- }
- }
-
- endmntent(mtab);
- return -1;
-}
-
-static char *
-get_mount_point(const char *dev, const char *label) {
- const char *extra;
- char *mountp;
- size_t len;
- struct dirent *dirent;
- DIR *dir;
-
- if (!is_mounted(dev))
- return NULL;
-
- len = strlen(strrchr(dev, '/') + 1) + 1 + strlen(BASE_MNT_DIR);
- extra = strrchr(dev, '/') + 1;
- if (label && strcmp(label, "")) {
- if ((dir = opendir(BASE_MNT_DIR))) {
- dirent = readdir(dir);
- while (dirent) {
- if (!strcmp(dirent->d_name, label))
- goto out;
- dirent = readdir(dir);
- }
- }
-
- len = strlen(label) + 1 + strlen(BASE_MNT_DIR);
- extra = label;
- }
-
-out:
- mountp = malloc(len);
- if (mountp)
- snprintf(mountp, len, "%s%s", BASE_MNT_DIR, extra);
- return mountp;
-}
-
-/*
- * This function will fail if the last symlink points
- * to a file whose path is defined relative to the symlink.
- */
-static int
-resolve_symlink(const char *restrict f, char *restrict d, size_t d_len) {
- char file[d_len], buf[d_len];
- ssize_t len;
- size_t f_len = strlen(f) + 1;
- struct stat bf;
-
- if (f_len > d_len)
- return -1;
- memcpy(file, f, f_len);
- do {
- len = readlink(file, buf, sizeof(buf) - 1);
- if (len < 0) {
- if (lstat(file, &bf) < 0)
- return -1;
- if (!file_exists(file) && !S_ISLNK(bf.st_mode))
- break;
- return -1;
- }
- buf[len] = '\0';
- memcpy(file, buf, len + 1);
- } while (1);
-
- memcpy(d, file, strlen(file) + 1);
- return 0;
-}
-
-/*
- * Open /etc/fstab and check if the inserted device
- * has a rule and if it does, change the mount point
- * and options associated with it. If it is a mount
- * point for another device do not use it. If it does
- * not have a rule, the device is not altered.
- */
-static void
-consider_fstab(struct device_t *device) {
- FILE *fp, *mtab;
- struct mntent *entry, *i;
- char rlink[1024], *tmp, *str;
- size_t len;
-
- fp = setmntent("/etc/fstab", "r");
- if (!fp)
- return;
-
- while ((entry = getmntent(fp))) {
- if (!strcmp(device->dev, entry->mnt_fsname)
- || strstr(entry->mnt_fsname,
- strchr(strstr(strrchr(device->did, '/') + 1,
- "uuid"), '_') + 1)
- || (strstr(entry->mnt_fsname, "LABEL=")
- && strstr(entry->mnt_fsname, device->label))
- || (!resolve_symlink(entry->mnt_fsname, rlink, 1024)
- && !strcmp(rlink, device->dev))) {
- tmp = device->mountp;
- device->mountp = strdup(entry->mnt_dir);
- device->opt = strdup(entry->mnt_opts);
- if (!device->opt || !device->mountp) {
- FREE_WRAP(device->mountp);
- FREE_WRAP(device->opt);
- device->mountp = tmp;
- } else {
- mtab = setmntent("/etc/mtab", "r");
- if (!mtab)
- goto out;
- while ((i = getmntent(mtab))) {
- if (!strcmp(i->mnt_dir, device->mountp)) {
- tmp = device->mountp;
- str = strrchr(device->dev, '/') + 1;
- len = strlen(str) + 1 + strlen(BASE_MNT_DIR);
- device->mountp = malloc(len);
- if (!device->mountp) {
- device->mountp = tmp;
- } else {
- snprintf(device->mountp, len, "%s%s", BASE_MNT_DIR, str);
- }
- break;
- }
- }
- endmntent(mtab);
- }
- break;
- }
- }
-out:
- endmntent(fp);
-}
-
-static void
-do_args(struct device_t *device) {
- int i = 0;
-
- device->args[i++] = MOUNT_CMD_PATH;
- device->args[i++] = "-t";
- device->args[i++] = device->fstype;
- device->args[i++] = "-o";
- device->args[i++] = (!device->opt) ? DEFAULT_MNT_OPTIONS : device->opt;
- device->args[i++] = device->dev;
- device->args[i++] = device->mountp;
- device->args[i] = NULL;
-}
-
-static int
-do_mount(struct device_t *device) {
- do_args(device);
- return (g_spawn_sync(
- "/",
- device->args,
- (gchar **)NULL,
- 0,
- (GSpawnChildSetupFunc)NULL,
- (gpointer)NULL,
- (gchar **)NULL,
- (gchar **)NULL,
- (gint *)NULL,
- (GError **)NULL) ? 0 : -1);
-}
-
-static int
-file_exists(const char *s) {
- struct stat sb;
- return ((stat(s, &sb) < 0 && errno == ENOENT) ? -ENOENT : 0);
-}
-
-static void
-cleanup(int sig __attribute__ ((unused))) {
- g_main_loop_quit(loop);
-}
-
-/*
- * Check if skvm is already running, the caller has to make sure that the log
- * file has been opened and the new instance has been daemonized.
- */
-static int
-is_running(void) {
- char buf[16];
-
- pid_fd = open(LOCKFILE, O_RDWR | O_CREAT, LOCKMODE);
- if (pid_fd < 0) {
- syslog(LOG_ERR, "%s:%d %s", __FILE__, __LINE__,
- strerror(errno));
- return -1;
- }
-
- if (flock(pid_fd, LOCK_EX | LOCK_NB) < 0) {
- close(pid_fd);
- pid_fd = -1;
- syslog(LOG_ERR, "%s:%d can't lock %s: %s", __FILE__, __LINE__,
- LOCKFILE, strerror(errno));
- return -1;
- }
-
- ftruncate(pid_fd, 0);
- snprintf(buf, sizeof(buf), "%jd\n", (intmax_t)getpid());
- write(pid_fd, buf, strlen(buf));
- return 0;
-}
-
-static void
-debug_dump_device(const struct device_t *device) {
- printf("~~~ Device dump ~~~\n");
- printf("Volume info: %s\n", (!device->did) ? "(null)" : device->did);
- printf("Device: %s\n", (!device->dev) ? "(null)" : device->dev);
- printf("Label: %s\n", (!device->label) ? "(null)" : device->label);
- printf("Filesystem type: %s\n",
- (!device->fstype) ? "(null)" : device->fstype);
- printf("Mount options: %s\n",
- (!device->opt) ? DEFAULT_MNT_OPTIONS : device->opt);
- printf("~~~~~~~~~~~~~~~~~~~\n");
-}
-
+/* See LICENSE file for copyright and license details. */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdint.h>
+
+#include <mntent.h>
+#include <getopt.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <dirent.h>
+#include <syslog.h>
+#include <fcntl.h>
+
+#include <dbus/dbus.h>
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+#include <hal/libhal.h>
+#include <hal/libhal-storage.h>
+
+/* ============================
+ * = Macros
+ * ============================
+ */
+
+/* feel free to alter these to your liking */
+#define MOUNT_CMD_PATH "/bin/mount"
+#define DEFAULT_MNT_OPTIONS "noexec,nosuid"
+#define BASE_MNT_DIR "/media/"
+
+/* not user controlled */
+#define LOCKFILE "/var/run/skvm.pid"
+#define LOCKMODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
+#define FREE_WRAP(ptr) do { free(ptr); ptr = NULL; } while (0)
+#define INIT_NODE(p1, p2) \
+ do { \
+ p1->mountp = p2->mountp; \
+ p1->did = p2->did; \
+ p1->dev = p2->dev; \
+ p1->label = p2->label; \
+ p1->fstype = p2->fstype; \
+ p1->opt = p2->opt; \
+ p1->volume = p2->volume; \
+ p1->drive = p2->drive; \
+ } while (0)
+
+/* ============================
+ * = Structs
+ * ============================
+ */
+
+struct device_t {
+ char *args[8]; /* arguments to mount for this device */
+ char *mountp; /* mount point */
+ char *did; /* volume's unique id */
+ char *dev; /* device associated with this volume */
+ char *label; /* volume's label */
+ char *fstype; /* filesystem type */
+ char *opt; /* mount options */
+ LibHalVolume *volume;
+ LibHalDrive *drive;
+ struct device_t *next;
+};
+
+/* ============================
+ * = Globals
+ * ============================
+ */
+
+/* the dbus connection handler */
+static DBusConnection *dbus_conn = NULL;
+/* the main hal context handler */
+static LibHalContext *hal_ctx = NULL;
+/* the head of a linked list of currently mounted devices */
+static struct device_t *head = NULL;
+static struct device_t *tail = NULL;
+/* the main loop handler */
+static GMainLoop *loop = NULL;
+/* file descriptor for LOCKFILE */
+static int pid_fd = -1;
+/* flag used for debugging */
+static int debug_mode_flag = 0;
+
+/* ============================
+ * = Function declarations
+ * ============================
+ */
+
+/* (de)/initialization functions */
+static int init_skvm(void);
+static int init_dbus(DBusError *error);
+static int init_hal(void);
+static void deinit(void);
+
+/* callback functions */
+static void device_added(LibHalContext *context, const char *did);
+static void device_removed(LibHalContext *context, const char *did);
+
+/* functions related to the device list */
+static struct device_t *get_device(char *mountp, const char *did,
+ char *dev, char *label,
+ const char *fstype,
+ LibHalVolume *volume,
+ LibHalDrive *drive);
+static void add_to_device_list(struct device_t *device);
+static void remove_from_device_list(struct device_t *prev,
+ struct device_t *curr);
+static void free_device(struct device_t *device);
+
+/* functions related to how the volume manager behaves when
+ * a new device is inserted */
+static int is_mounted(const char *dev);
+static char *get_mount_point(const char *dev, const char *label);
+static int resolve_symlink(const char *f, char *d, size_t d_len);
+static void consider_fstab(struct device_t *device);
+static void do_args(struct device_t *device);
+static int do_mount(struct device_t *device);
+
+/* general function helpers */
+static int file_exists(const char *path);
+static void cleanup(int sig);
+static int is_running(void);
+static void debug_dump_device(const struct device_t *device);
+
+int
+main(int argc, char *argv[]) {
+ int c;
+
+ static struct option long_options[] = {
+ { "debug", 0, (int *)NULL, 'd' }
+ };
+
+ while ((c = getopt_long(argc, argv, "d", long_options,
+ (int *)NULL)) != -1) {
+ switch (c) {
+ case 'd':
+ debug_mode_flag = 1;
+ break;
+ }
+ }
+
+ if (debug_mode_flag)
+ setvbuf(stdout, (char *)NULL, _IONBF, 0); /* avoid surprises */
+
+ if (init_skvm() < 0)
+ return EXIT_FAILURE;
+
+ openlog(argv[0], LOG_PID, LOG_DAEMON);
+ signal(SIGTERM, cleanup);
+
+ if (!debug_mode_flag) {
+ if (daemon(0, 0) < 0)
+ return EXIT_FAILURE;
+ if (is_running()) {
+ deinit();
+ return EXIT_FAILURE;
+ }
+ }
+
+ loop = g_main_loop_new((GMainContext *)NULL, FALSE);
+ g_main_run(loop);
+
+ deinit();
+ return EXIT_SUCCESS;
+}
+
+static int
+init_skvm(void) {
+ DBusError error;
+
+ dbus_error_init(&error);
+ if (init_dbus(&error) < 0) {
+ if (dbus_error_is_set(&error)) {
+ syslog(LOG_ERR, "%s:%d: %s:%s", __FILE__, __LINE__,
+ error.name, error.message);
+ dbus_error_free(&error);
+ return -1;
+ }
+ }
+
+ return init_hal();
+}
+
+static int
+init_dbus(DBusError *error) {
+ if (!(dbus_conn = dbus_bus_get(DBUS_BUS_SYSTEM, error)))
+ return -1;
+ dbus_connection_setup_with_g_main (dbus_conn, (GMainContext *)NULL);
+ dbus_connection_flush(dbus_conn);
+ return 0;
+}
+
+static int
+init_hal(void) {
+ DBusError error;
+
+ if (!(hal_ctx = libhal_ctx_new()))
+ return -1;
+
+ libhal_ctx_set_dbus_connection (hal_ctx, dbus_conn);
+
+ libhal_ctx_set_device_added(hal_ctx, device_added);
+ libhal_ctx_set_device_removed(hal_ctx, device_removed);
+
+ dbus_error_init(&error);
+ if (!libhal_device_property_watch_all(hal_ctx, &error)) {
+ if (dbus_error_is_set(&error)) {
+ syslog(LOG_ERR, "%s:%d: %s:%s", __FILE__, __LINE__,
+ error.name, error.message);
+ dbus_error_free (&error);
+ libhal_ctx_free (hal_ctx);
+ return -1;
+ }
+ }
+
+ if (!libhal_ctx_init(hal_ctx, &error)) {
+ if (dbus_error_is_set(&error)) {
+ syslog(LOG_ERR, "%s:%d: %s:%s", __FILE__, __LINE__,
+ error.name, error.message);
+ dbus_error_free(&error);
+ libhal_ctx_free(hal_ctx);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static void
+deinit(void) {
+ struct device_t *iter, *tmp;
+
+ closelog();
+ libhal_ctx_shutdown(hal_ctx, (DBusError *)NULL);
+ libhal_ctx_free(hal_ctx);
+ dbus_connection_unref(dbus_conn);
+
+ iter = head;
+
+ while (iter) {
+ tmp = iter;
+ iter = iter->next;
+ free_device(tmp);
+ }
+
+ if (pid_fd >= 0)
+ close(pid_fd); /* releases lock */
+}
+
+/* Callback function, called when a new device has been inserted. */
+static void
+device_added(LibHalContext *context, const char *did) {
+ const char *dudi, *fstype;
+ char *dev, *mountp, *mountable, *label;
+ LibHalVolume *volume;
+ LibHalDrive *drive;
+ struct device_t *device;
+
+ if (!libhal_device_query_capability(context, did, "volume",
+ (DBusError *)NULL))
+ return;
+ label = libhal_device_get_property_string(context, did, "volume.label",
+ (DBusError *)NULL);
+ if (!(mountable = libhal_device_get_property_string(
+ context, did, "volume.fsusage", (DBusError *)NULL))
+ || strcmp(mountable, "filesystem"))
+ goto out;
+ if (!(volume = libhal_volume_from_udi(context, did)))
+ goto out;
+ if (!(dudi = libhal_volume_get_storage_device_udi(volume)))
+ goto out;
+ if (!(drive = libhal_drive_from_udi(context, dudi)))
+ goto out;
+ if (!libhal_drive_is_hotpluggable(drive)
+ && !libhal_drive_uses_removable_media(drive))
+ goto out;
+ if (!(fstype = libhal_volume_get_fstype(volume)))
+ goto out;
+ if (!(dev = libhal_device_get_property_string(context, did, "block.device",
+ (DBusError *)NULL)))
+ goto out;
+ mountp = get_mount_point(dev, label);
+ if (!mountp)
+ goto out;
+ device = get_device(mountp, did, dev, label, fstype, volume, drive);
+ if (!device)
+ goto out;
+ consider_fstab(device);
+ if (file_exists(device->mountp) < 0)
+ mkdir(device->mountp, 0750);
+ do_mount(device) < 0 ? free_device(device) : add_to_device_list(device);
+
+ if (debug_mode_flag && device)
+ debug_dump_device(device);
+
+out:
+ if (mountable)
+ libhal_free_string(mountable);
+ if (label)
+ libhal_free_string(label);
+}
+
+/* Callback function, called when a device has been removed. */
+static void
+device_removed(LibHalContext *context __attribute__ ((unused)),
+ const char *did) {
+ char *mountp = NULL;
+ struct device_t *iter = head, *prev = NULL;
+
+ while (iter) {
+ if (!strcmp(did, iter->did)) {
+ mountp = iter->mountp;
+ if (!file_exists(mountp)) {
+ if (rmdir(mountp) < 0)
+ syslog(LOG_WARNING, "%s:%d: %s", __FILE__, __LINE__,
+ strerror(errno));
+ remove_from_device_list(prev, iter);
+ }
+ return;
+ }
+ prev = iter;
+ iter = iter->next;
+ }
+}
+
+static struct device_t *
+get_device(char *mountp, const char *did, char *dev, char *label,
+ const char *fstype, LibHalVolume *volume, LibHalDrive *drive) {
+ struct device_t *device = malloc(sizeof(*device));
+
+ if (device) {
+ device->mountp = mountp;
+ device->did = strdup(did);
+ device->dev = dev;
+ device->label = strdup(label);
+ device->fstype = strdup(fstype);
+ device->opt = NULL;
+ device->volume = volume;
+ device->drive = drive;
+ device->next = NULL;
+ if (!device->did || !device->label || !device->fstype) {
+ free_device(device);
+ device = NULL;
+ }
+ }
+
+ return device;
+}
+
+static void
+add_to_device_list(struct device_t *device) {
+ if (!device)
+ return;
+
+ if (!head) {
+ head = device;
+ tail = head;
+ INIT_NODE(head, device);
+ } else {
+ tail->next = device;
+ tail = tail->next;
+ INIT_NODE(tail, device);
+ }
+}
+
+static void
+remove_from_device_list(struct device_t *prev, struct device_t *curr) {
+ if (!curr)
+ return;
+
+ if (curr == head) {
+ head = curr->next;
+ } else if (curr == tail) {
+ tail = prev;
+ tail->next = NULL;
+ } else {
+ if (!prev)
+ return;
+ prev->next = curr->next;
+ }
+
+ free_device(curr);
+}
+
+static void
+free_device(struct device_t *device) {
+ if (!device)
+ return;
+
+ FREE_WRAP(device->mountp);
+ FREE_WRAP(device->did);
+ if (device->dev)
+ libhal_free_string(device->dev);
+ FREE_WRAP(device->label);
+ FREE_WRAP(device->fstype);
+ FREE_WRAP(device->opt);
+ if (device->volume)
+ libhal_volume_free(device->volume);
+ if (device->drive)
+ libhal_drive_free(device->drive);
+
+ FREE_WRAP(device);
+}
+
+static int
+is_mounted(const char *dev) {
+ FILE *mtab;
+ struct mntent *entry;
+
+ mtab = setmntent("/etc/mtab", "r");
+ if (!mtab)
+ return -1;
+
+ while ((entry = getmntent(mtab))) {
+ if (!strcmp(entry->mnt_fsname, dev)) {
+ endmntent(mtab);
+ return 0;
+ }
+ }
+
+ endmntent(mtab);
+ return -1;
+}
+
+static char *
+get_mount_point(const char *dev, const char *label) {
+ const char *extra;
+ char *mountp;
+ size_t len;
+ struct dirent *dirent;
+ DIR *dir;
+
+ if (!is_mounted(dev))
+ return NULL;
+
+ len = strlen(strrchr(dev, '/') + 1) + 1 + strlen(BASE_MNT_DIR);
+ extra = strrchr(dev, '/') + 1;
+ if (label && strcmp(label, "")) {
+ if ((dir = opendir(BASE_MNT_DIR))) {
+ dirent = readdir(dir);
+ while (dirent) {
+ if (!strcmp(dirent->d_name, label))
+ goto out;
+ dirent = readdir(dir);
+ }
+ }
+
+ len = strlen(label) + 1 + strlen(BASE_MNT_DIR);
+ extra = label;
+ }
+
+out:
+ mountp = malloc(len);
+ if (mountp)
+ snprintf(mountp, len, "%s%s", BASE_MNT_DIR, extra);
+ return mountp;
+}
+
+/*
+ * This function will fail if the last symlink points
+ * to a file whose path is defined relative to the symlink.
+ */
+static int
+resolve_symlink(const char *restrict f, char *restrict d, size_t d_len) {
+ char file[d_len], buf[d_len];
+ ssize_t len;
+ size_t f_len = strlen(f) + 1;
+ struct stat bf;
+
+ if (f_len > d_len)
+ return -1;
+ memcpy(file, f, f_len);
+ do {
+ len = readlink(file, buf, sizeof(buf) - 1);
+ if (len < 0) {
+ if (lstat(file, &bf) < 0)
+ return -1;
+ if (!file_exists(file) && !S_ISLNK(bf.st_mode))
+ break;
+ return -1;
+ }
+ buf[len] = '\0';
+ memcpy(file, buf, len + 1);
+ } while (1);
+
+ memcpy(d, file, strlen(file) + 1);
+ return 0;
+}
+
+/*
+ * Open /etc/fstab and check if the inserted device
+ * has a rule and if it does, change the mount point
+ * and options associated with it. If it is a mount
+ * point for another device do not use it. If it does
+ * not have a rule, the device is not altered.
+ */
+static void
+consider_fstab(struct device_t *device) {
+ FILE *fp, *mtab;
+ struct mntent *entry, *i;
+ char rlink[1024], *tmp, *str;
+ size_t len;
+
+ if (!device)
+ return;
+
+ fp = setmntent("/etc/fstab", "r");
+ if (!fp)
+ return;
+
+ while ((entry = getmntent(fp))) {
+ if (!strcmp(device->dev, entry->mnt_fsname)
+ || strstr(entry->mnt_fsname,
+ strchr(strstr(strrchr(device->did, '/') + 1,
+ "uuid"), '_') + 1)
+ || (strstr(entry->mnt_fsname, "LABEL=")
+ && strstr(entry->mnt_fsname, device->label))
+ || (!resolve_symlink(entry->mnt_fsname, rlink, 1024)
+ && !strcmp(rlink, device->dev))) {
+ tmp = device->mountp;
+ device->mountp = strdup(entry->mnt_dir);
+ device->opt = strdup(entry->mnt_opts);
+ if (!device->opt || !device->mountp) {
+ FREE_WRAP(device->mountp);
+ FREE_WRAP(device->opt);
+ device->mountp = tmp;
+ } else {
+ mtab = setmntent("/etc/mtab", "r");
+ if (!mtab)
+ goto out;
+ while ((i = getmntent(mtab))) {
+ if (!strcmp(i->mnt_dir, device->mountp)) {
+ tmp = device->mountp;
+ str = strrchr(device->dev, '/') + 1;
+ len = strlen(str) + 1 + strlen(BASE_MNT_DIR);
+ device->mountp = malloc(len);
+ if (!device->mountp) {
+ device->mountp = tmp;
+ } else {
+ snprintf(device->mountp, len, "%s%s", BASE_MNT_DIR, str);
+ }
+ break;
+ }
+ }
+ endmntent(mtab);
+ }
+ break;
+ }
+ }
+out:
+ endmntent(fp);
+}
+
+static void
+do_args(struct device_t *device) {
+ int i = 0;
+
+ if (!device)
+ return;
+
+ device->args[i++] = MOUNT_CMD_PATH;
+ device->args[i++] = "-t";
+ device->args[i++] = device->fstype;
+ device->args[i++] = "-o";
+ device->args[i++] = (!device->opt) ? DEFAULT_MNT_OPTIONS : device->opt;
+ device->args[i++] = device->dev;
+ device->args[i++] = device->mountp;
+ device->args[i] = NULL;
+}
+
+static int
+do_mount(struct device_t *device) {
+ if (!device)
+ return -1;
+
+ do_args(device);
+ return (g_spawn_sync(
+ "/",
+ device->args,
+ (gchar **)NULL,
+ 0,
+ (GSpawnChildSetupFunc)NULL,
+ (gpointer)NULL,
+ (gchar **)NULL,
+ (gchar **)NULL,
+ (gint *)NULL,
+ (GError **)NULL) ? 0 : -1);
+}
+
+static int
+file_exists(const char *s) {
+ struct stat sb;
+ return ((stat(s, &sb) < 0 && errno == ENOENT) ? -ENOENT : 0);
+}
+
+static void
+cleanup(int sig __attribute__ ((unused))) {
+ g_main_loop_quit(loop);
+}
+
+/*
+ * Check if skvm is already running, the caller has to make sure that the log
+ * file has been opened and the new instance has been daemonized.
+ */
+static int
+is_running(void) {
+ char buf[16];
+
+ pid_fd = open(LOCKFILE, O_RDWR | O_CREAT, LOCKMODE);
+ if (pid_fd < 0)
+ goto out;
+
+ if (flock(pid_fd, LOCK_EX | LOCK_NB) < 0)
+ goto out;
+
+ if (ftruncate(pid_fd, 0) < 0)
+ goto out;
+
+ snprintf(buf, sizeof(buf), "%jd\n", (intmax_t)getpid());
+ write(pid_fd, buf, strlen(buf));
+ return 0;
+
+out:
+ if (pid_fd != -1)
+ close(pid_fd);
+ pid_fd = -1;
+ syslog(LOG_ERR, "%s:%d %s", __FILE__, __LINE__,
+ strerror(errno));
+ return -1;
+}
+
+static void
+debug_dump_device(const struct device_t *device) {
+ if (!device)
+ return;
+
+ printf("~~~ Device dump ~~~\n");
+ printf("Volume info: %s\n", (!device->did) ? "(null)" : device->did);
+ printf("Device: %s\n", (!device->dev) ? "(null)" : device->dev);
+ printf("Label: %s\n", (!device->label) ? "(null)" : device->label);
+ printf("Filesystem type: %s\n",
+ (!device->fstype) ? "(null)" : device->fstype);
+ printf("Mount options: %s\n",
+ (!device->opt) ? DEFAULT_MNT_OPTIONS : device->opt);
+ printf("~~~~~~~~~~~~~~~~~~~\n");
+}
+
Received on Wed Apr 29 2009 - 17:58:04 UTC

This archive was generated by hypermail 2.2.0 : Wed Apr 29 2009 - 18:00:06 UTC