[hackers] [skvm] initial commit || Dimitrios Papastamos

From: <hg_AT_suckless.org>
Date: Tue, 28 Apr 2009 11:59:10 +0000 (UTC)

changeset: 0:cd5dd6134ab9
tag: tip
user: Dimitrios Papastamos <stateless [at] archlinux.us>
date: Tue Apr 28 12:58:45 2009 -0700
files: .astylerc AUTHORS ChangeLog LICENSE Makefile PKGBUILD README TODO format.sh init/skvm skvm.1 skvm.c
description:
initial commit

diff -r 000000000000 -r cd5dd6134ab9 .astylerc
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/.astylerc Tue Apr 28 12:58:45 2009 -0700
@@ -0,0 +1,12 @@
+indent=spaces=3
+indent-switches
+indent-classes
+indent-cases
+indent-namespaces
+indent-preprocessor
+max-instatement-indent=80
+suffix=none
+brackets=attach
+pad=oper
+one-line=keep-statements
+convert-tabs
diff -r 000000000000 -r cd5dd6134ab9 AUTHORS
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/AUTHORS Tue Apr 28 12:58:45 2009 -0700
@@ -0,0 +1,2 @@
+Author and maintainer of all source files:
+ Dimitris Papastamos <stateless [at] archlinux.us>
diff -r 000000000000 -r cd5dd6134ab9 ChangeLog
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ChangeLog Tue Apr 28 12:58:45 2009 -0700
@@ -0,0 +1,5 @@
+skvm
+----
+
+2009-04-25 (v0.1) Dimitrios Papastamos <stateless [at] archlinux.us>
+ * v0.1 has been released
diff -r 000000000000 -r cd5dd6134ab9 LICENSE
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/LICENSE Tue Apr 28 12:58:45 2009 -0700
@@ -0,0 +1,21 @@
+MIT/X Consortium License
+
+Copyright (C) 2009 Dimitrios Papastamos <stateless at archlinux dot us>
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff -r 000000000000 -r cd5dd6134ab9 Makefile
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Makefile Tue Apr 28 12:58:45 2009 -0700
@@ -0,0 +1,48 @@
+bin = skvm
+ver = 0.1
+src = skvm.c
+inc = -I/usr/include -I/usr/include/hal
+
+CC = gcc
+CFLAGS += -Wall -Wextra -std=gnu99 -Wformat-security -Wshadow \
+ -Wunreachable-code -Wpointer-arith -ggdb \
+ $(shell pkg-config --cflags glib-2.0 dbus-glib-1)
+LDFLAGS += -lhal -lhal-storage $(shell pkg-config --libs glib-2.0 dbus-glib-1)
+
+all: $(bin)
+
+%: %.c
+ $(CC) -o $(bin) $(src) $(inc) $(CFLAGS) $(LDFLAGS)
+
+clean:
+ @rm -rf $(bin) skvm-${ver}.tar.bz2
+
+dist: clean
+ @mkdir -p skvm-${ver}
+ @cp -R AUTHORS ChangeLog PKGBUILD README skvm.1 ${src} \
+ LICENSE Makefile TODO init skvm-${ver}
+ @tar -cf skvm-${ver}.tar skvm-${ver}
+ @bzip2 skvm-${ver}.tar
+ @rm -rf skvm-${ver}
+
+install: all
+ @echo installing executable file to /usr/bin
+ @cp -f $(bin) /usr/bin
+ @chmod 755 /usr/bin/$(bin)
+ @echo installing init script to /etc/rc.d
+ @cp -f init/$(bin) /etc/rc.d
+ @chmod 755 /etc/rc.d/$(bin)
+ @echo installing manpage at /usr/local/share/man/man1
+ @mkdir -p /usr/local/share/man/man1
+ @sed "s/VERSION/${ver}/g" < skvm.1 > /usr/local/share/man/man1/skvm.1
+ @chmod 644 /usr/local/share/man/man1/skvm.1
+
+uninstall:
+ @echo removing /usr/bin/$(bin)
+ @rm -f /usr/bin/$(bin)
+ @echo removing /etc/rc.d/$(bin)
+ @rm -f /etc/rc.d/$(bin)
+ @echo removing /usr/local/share/man/man1/skvm.1
+ @rm -f /usr/local/share/man/man1/skvm.1
+
+.PHONY: all clean dist install uninstall
diff -r 000000000000 -r cd5dd6134ab9 PKGBUILD
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/PKGBUILD Tue Apr 28 12:58:45 2009 -0700
@@ -0,0 +1,45 @@
+# Contributor: Ondrej Martinak <omartinak_AT_gmail.com>
+
+pkgname=skvm-git
+pkgver=20090415
+pkgrel=1
+pkgdesc="Lightweight volume manager"
+arch=('i686' 'x86_64')
+url="http://github.com/dimigon/skvm/tree/master"
+license=('GPL')
+depends=('hal' 'dbus')
+makedepends=('git')
+conflicts=('skvm')
+provides=('skvm')
+
+_gitroot="git://github.com/dimigon/skvm.git"
+_gitname="skvm"
+
+build() {
+ cd ${srcdir}
+
+ msg "Connecting to GIT server..."
+
+ if [ -d $_gitname ]; then
+ cd $_gitname && git pull origin
+ cd ..
+ msg "The local files are updated."
+ else
+ git clone $_gitroot
+ fi
+
+ msg "GIT checkout done or server timeout"
+ msg "Starting make..."
+
+ rm -rf $_gitname-build
+ cp -r $_gitname $_gitname-build
+ cd $_gitname-build
+
+ make || return 1
+
+ mkdir -p ${startdir}/pkg/usr/bin
+ mkdir -p ${startdir}/pkg/etc/rc.d
+
+ install -m 755 skvm ${startdir}/pkg/usr/bin/skvm
+ install -m 755 init/skvm ${startdir}/pkg/etc/rc.d/skvm
+}
diff -r 000000000000 -r cd5dd6134ab9 README
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/README Tue Apr 28 12:58:45 2009 -0700
@@ -0,0 +1,23 @@
+skvm v0.1
+
+What is it?
+===========
+SKVM is a lightweight volume manager for 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.
+
+Installation
+============
+* make
+* make install
+
+* Do not forget to alter your /etc/rc.conf to include 'skvm' in the
+ DAEMONS section. If you are using Arch linux use the supplied PKGBUILD
+ for a clean installation.
+
+How to use it
+=============
+* sudo /etc/rc.d/skvm start
+* sudo /etc/rc.d/skvm restart
+* sudo /etc/rc.d/skvm stop
diff -r 000000000000 -r cd5dd6134ab9 TODO
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/TODO Tue Apr 28 12:58:45 2009 -0700
@@ -0,0 +1,4 @@
+SKVM --- TODO
+
+ * add support for LUKS.
+ * better error reporting.
diff -r 000000000000 -r cd5dd6134ab9 format.sh
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/format.sh Tue Apr 28 12:58:45 2009 -0700
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+i=0
+for file in $(find . -maxdepth 2 -type f -iname "*.cpp" -or -iname "*.hpp" -or -iname "*.h" -or -iname "*.c"); do
+ astyle --options=.astylerc $file | grep -i "formatted"
+ if [ $? -eq 0 ]; then
+ let i=i+1
+ fi
+done
+
+if [ $i -gt 0 ]; then
+ echo "Beautified" $i "files."
+else
+ echo "The source tree has been left unchanged, no source formatting needs to be done."
+fi
diff -r 000000000000 -r cd5dd6134ab9 init/skvm
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/init/skvm Tue Apr 28 12:58:45 2009 -0700
@@ -0,0 +1,36 @@
+#!/bin/bash
+
+. /etc/rc.conf
+. /etc/rc.d/functions
+
+PID=`pidof -o %PPID /usr/bin/skvm`
+case "$1" in
+ start)
+ stat_busy "Starting SKVM Daemon"
+ [ -z "$PID" ] && /usr/bin/skvm &>/dev/null
+ if [ $? -gt 0 ]; then
+ stat_fail
+ else
+ add_daemon skvm
+ stat_done
+ fi
+ ;;
+ stop)
+ stat_busy "Stopping SKVM Daemon"
+ [ ! -z "$PID" ] && kill $PID &> /dev/null
+ if [ $? -gt 0 ]; then
+ stat_fail
+ else
+ rm_daemon skvm
+ stat_done
+ fi
+ ;;
+ restart)
+ $0 stop
+ sleep 3
+ $0 start
+ ;;
+ *)
+ echo "usage: $0 {start|stop|restart}"
+esac
+exit 0
diff -r 000000000000 -r cd5dd6134ab9 skvm.1
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/skvm.1 Tue Apr 28 12:58:45 2009 -0700
@@ -0,0 +1,19 @@
+.\" Consulted the dwm manual as a reference for this manpage.
+.TH SKVM 1 skvm\-VERSION
+.SH NAME
+skvm \- lightweight volume manager
+.SH SYNOPSIS
+.B skvm
+.RB [OPTIONS]
+.SH DESCRIPTION
+skvm is a lightweight volume manager for Linux. It depends on hal and dbus.
+It is meant to be simple to use, efficient and functional.
+.SH OPTIONS
+.TP
+.B \-d, \-\-debug
+executes skvm in debug mode (not as a daemon).
+.SH CUSTOMIZATION
+skvm is customized by altering the preprocessor directives in its source
+file and (re)compiling the source code. This keeps it fast, secure and simple.
+.SH AUTHOR
+skvm was written by Dimitrios Papastamos <stateless [at] archlinux.us>.
diff -r 000000000000 -r cd5dd6134ab9 skvm.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/skvm.c Tue Apr 28 12:58:45 2009 -0700
@@ -0,0 +1,595 @@
+/* See LICENSE file for copyright and license details. */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include <signal.h>
+
+#include <mntent.h>
+#include <getopt.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <syslog.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/"
+
+#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;
+/* flag used for debugging */
+static int debug_mode_flag = 0;
+
+/* ============================
+ * = Function declarations
+ * ============================
+ */
+
+static int init_skvm(void);
+static int init_dbus(DBusError *error);
+static int init_hal(void);
+
+static void register_hal_callbacks(void);
+static void device_added(LibHalContext *context, const char *did);
+static void device_removed(LibHalContext *context, const char *did);
+
+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);
+
+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);
+static int file_exists(const char *path);
+static void cleanup(int sig);
+static void debug_dump_device(const struct device_t *device);
+
+int
+main(int argc, char *argv[]) {
+ struct device_t *iter, *tmp;
+ 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);
+
+ 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 (debug_mode_flag) {
+ printf("Base mount directory: %s\n", BASE_MNT_DIR);
+ printf("Default mount options: %s\n", DEFAULT_MNT_OPTIONS);
+ }
+
+ loop = g_main_loop_new((GMainContext *)NULL, FALSE);
+ g_main_run(loop);
+
+ 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);
+ }
+
+ 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);
+ register_hal_callbacks();
+
+ 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
+register_hal_callbacks(void) {
+ libhal_ctx_set_device_added(hal_ctx, device_added);
+ libhal_ctx_set_device_removed(hal_ctx, device_removed);
+}
+
+/* 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);
+}
+
+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");
+}
+
Received on Tue Apr 28 2009 - 11:59:10 UTC

This archive was generated by hypermail 2.2.0 : Tue Apr 28 2009 - 12:00:07 UTC