+ return ret;
+}
+
+/* Execute `fusermount -u', which is installed setuid root, to unmount the WIM.
+ *
+ * FUSE does not yet implement synchronous unmounts. This means that fusermount
+ * -u will return before the filesystem daemon returns from wimfs_destroy().
+ * This is partly what we want, because we need to send a message from this
+ * process to the filesystem daemon telling whether --commit was specified or
+ * not. However, after that, the unmount process must wait for the filesystem
+ * daemon to finish writing the WIM file.
+ */
+static int execute_fusermount(const char *dir)
+{
+ pid_t pid;
+ int ret;
+ int status;
+
+ pid = fork();
+ if (pid == -1) {
+ ERROR_WITH_ERRNO("Failed to fork()");
+ return WIMLIB_ERR_FORK;
+ }
+ if (pid == 0) {
+ /* Child */
+ execlp("fusermount", "fusermount", "-u", dir, NULL);
+ ERROR_WITH_ERRNO("Failed to execute `fusermount'");
+ exit(WIMLIB_ERR_FUSERMOUNT);
+ }
+
+ /* Parent */
+ ret = wait(&status);
+ if (ret == -1) {
+ ERROR_WITH_ERRNO("Failed to wait for fusermount process to "
+ "terminate");
+ return WIMLIB_ERR_FUSERMOUNT;
+ }
+
+ if (status != 0) {
+ if (status == WIMLIB_ERR_FUSERMOUNT)
+ ERROR("Could not find the `fusermount' program");
+ else
+ ERROR("fusermount exited with status %d", status);
+
+ /* 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. */
+
+ pid = fork();
+ if (pid == -1) {
+ ERROR_WITH_ERRNO("Failed to fork()");
+ return WIMLIB_ERR_FORK;
+ }
+ if (pid == 0) {
+ /* Child */
+ execlp("umount", "umount", dir, NULL);
+ ERROR_WITH_ERRNO("Failed to execute `umount'");
+ exit(WIMLIB_ERR_FUSERMOUNT);
+ }
+
+ /* Parent */
+ 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;
+ }
+ }
+ return 0;
+}
+
+/* Called when the filesystem is unmounted. */
+static void wimfs_destroy(void *p)
+{
+ /* The `imagex unmount' command, which is running in a separate process
+ * and is executing the wimlib_unmount() function, will send this
+ * process a `struct unmount_request' through a message queue that
+ * specifies some unmount options, such as other to commit changes or
+ * not. */
+
+ int ret;
+ int unmount_flags;
+ struct wimfs_context *ctx;
+ int status;
+
+ ctx = wimfs_get_context();
+ if (open_message_queues(ctx, true))
+ return;
+
+ ret = receive_unmount_request(ctx, &unmount_flags);
+ status = ret;
+ if (ret == 0) {
+ if (ctx->mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) {
+ if (unmount_flags & WIMLIB_UNMOUNT_FLAG_COMMIT) {
+ int write_flags;
+ if (unmount_flags & WIMLIB_UNMOUNT_FLAG_CHECK_INTEGRITY)
+ write_flags = WIMLIB_WRITE_FLAG_CHECK_INTEGRITY;
+ else
+ write_flags = 0;
+ status = rebuild_wim(ctx, write_flags);
+ }
+ ret = delete_staging_dir(ctx);
+ if (ret != 0) {
+ ERROR("Failed to delete the staging directory");
+ if (status == 0)
+ status = ret;
+ }
+ } else {
+ DEBUG("Read-only mount");
+ }
+ }
+ send_unmount_response(ctx, status);