From 35fe5c7c2f2e5054abd93a7b755c2c670ee476da Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 2 Sep 2012 14:33:26 -0500 Subject: [PATCH] Make WIM mounting work on FreeBSD - Fallback to `umount' if `fusermount' is not available. - Place message in message queue before executing `umount'. This is needed in case the unmount occurs synchronously. --- README | 8 +++--- src/list.h | 4 +++ src/mount.c | 74 ++++++++++++++++++++++++++++++++++++----------------- 3 files changed, 58 insertions(+), 28 deletions(-) diff --git a/README b/README index 640432bb..2fa925e9 100644 --- a/README +++ b/README @@ -184,13 +184,11 @@ wimlib has mostly been developed and tested on x86_64 (64-bit) GNU/Linux. It has been tested on x86 (32-bit) GNU/Linux occasionally. -wimlib may work on FreeBSD. However, this not well tested. If you do not have -libntfs-3g 2011-4-12 or later available, you may have to configure with +wimlib may work on FreeBSD. However, this is not well tested. If you do not +have libntfs-3g 2011-4-12 or later available, you must configure with --without-ntfs-3g. Also, GNU coreutils is needed to run the test suite. Before mounting a WIM you need to load the POSIX message queue module (run `kldload -mqueuefs'). There is no `fusermount' command on FreeBSD, so you must use -`umount' rather than `imagex unmount' to unmount a mounted WIM, but this won't -allow you to commit changes to a read-write mounted WIM... +mqueuefs'). wimlib should work on big endian machines but it has not been tested. diff --git a/src/list.h b/src/list.h index ffce6570..e21f6d17 100644 --- a/src/list.h +++ b/src/list.h @@ -66,6 +66,10 @@ struct stream_list_head { #define LIST_HEAD_INIT(name) { &(name), &(name) } +#ifdef LIST_HEAD /* BSD sys/queue.h defines this... */ +#undef LIST_HEAD +#endif + #define LIST_HEAD(name) \ struct list_head name = LIST_HEAD_INIT(name) diff --git a/src/mount.c b/src/mount.c index f152fcd7..6efe84c6 100644 --- a/src/mount.c +++ b/src/mount.c @@ -29,6 +29,7 @@ #include "wimlib_internal.h" #ifdef WITH_FUSE + #include "sha1.h" #include "lookup_table.h" #include "xml.h" @@ -2030,6 +2031,30 @@ WIMLIBAPI int wimlib_unmount(const char *dir, int flags) int msgsize; int errno_save; + mount_dir = dir; + + /* Open message queues between the unmount process and the + * filesystem daemon. */ + ret = open_message_queues(false); + if (ret != 0) + return ret; + + /* Send a message to the filesystem saying whether to commit or + * not. */ + msg[0] = (flags & WIMLIB_UNMOUNT_FLAG_COMMIT) ? 1 : 0; + msg[1] = (flags & WIMLIB_UNMOUNT_FLAG_CHECK_INTEGRITY) ? 1 : 0; + + DEBUG("Sending message: %s, %s", + (msg[0] == 0) ? "don't commit" : "commit", + (msg[1] == 0) ? "don't check" : "check"); + ret = mq_send(unmount_to_daemon_mq, msg, 2, 1); + if (ret == -1) { + ERROR("Failed to notify filesystem daemon whether we want to " + "commit changes or not"); + close_message_queues(); + return WIMLIB_ERR_MQUEUE; + } + /* Execute `fusermount -u', which is installed setuid root, to unmount * the WIM. * @@ -2042,7 +2067,6 @@ WIMLIBAPI int wimlib_unmount(const char *dir, int flags) * the WIM file. */ - mount_dir = dir; pid = fork(); if (pid == -1) { @@ -2052,10 +2076,10 @@ WIMLIBAPI int wimlib_unmount(const char *dir, int flags) if (pid == 0) { execlp("fusermount", "fusermount", "-u", dir, NULL); ERROR_WITH_ERRNO("Failed to execute `fusermount'"); - return WIMLIB_ERR_FUSERMOUNT; + exit(WIMLIB_ERR_FUSERMOUNT); } - ret = waitpid(pid, &status, 0); + ret = wait(&status); if (ret == -1) { ERROR_WITH_ERRNO("Failed to wait for fusermount process to " "terminate"); @@ -2064,31 +2088,35 @@ WIMLIBAPI int wimlib_unmount(const char *dir, int flags) if (status != 0) { ERROR("fusermount exited with status %d", status); - return WIMLIB_ERR_FUSERMOUNT; - } - /* Open message queues between the unmount process and the - * filesystem daemon. */ - ret = open_message_queues(false); - if (ret != 0) - return ret; + /* Try again, but with the `umount' program. This is required + * on other FUSE implementations such as FreeBSD's that do not + * have a `fusermount' program. */ - /* Send a message to the filesystem saying whether to commit or - * not. */ - msg[0] = (flags & WIMLIB_UNMOUNT_FLAG_COMMIT) ? 1 : 0; - msg[1] = (flags & WIMLIB_UNMOUNT_FLAG_CHECK_INTEGRITY) ? 1 : 0; + pid = fork(); + if (pid == -1) { + ERROR_WITH_ERRNO("Failed to fork()"); + return WIMLIB_ERR_FORK; + } + if (pid == 0) { + execlp("umount", "umount", dir, NULL); + ERROR_WITH_ERRNO("Failed to execute `umount'"); + exit(WIMLIB_ERR_FUSERMOUNT); + } - DEBUG("Sending message: %s, %s", - (msg[0] == 0) ? "don't commit" : "commit", - (msg[1] == 0) ? "don't check" : "check"); - ret = mq_send(unmount_to_daemon_mq, msg, 2, 1); - if (ret == -1) { - ERROR("Failed to notify filesystem daemon whether we want to " - "commit changes or not"); - close_message_queues(); - return WIMLIB_ERR_MQUEUE; + ret = wait(&status); + if (ret == -1) { + ERROR_WITH_ERRNO("Failed to wait for `umount' process to " + "terminate"); + return WIMLIB_ERR_FUSERMOUNT; + } + if (status != 0) { + ERROR("`umount' exited with failure status"); + return WIMLIB_ERR_FUSERMOUNT; + } } + /* Wait for a message from the filesytem daemon indicating whether the * filesystem was unmounted successfully (0) or an error occurred (1). * This may take a long time if a big WIM file needs to be rewritten. */ -- 2.43.0