+ }
+ wimfs_ctx->status = status;
+ wimfs_ctx->have_status = true;
+ return MSG_BREAK_LOOP;
+}
+
+static int
+msg_daemon_info_handler(const void *_msg, void *_handler_ctx)
+{
+ const struct msg_daemon_info *msg = _msg;
+ struct unmount_msg_handler_context *handler_ctx = _handler_ctx;
+
+ DEBUG("Handling daemon info msg");
+ if (msg->hdr.msg_size < sizeof(*msg))
+ return WIMLIB_ERR_INVALID_UNMOUNT_MESSAGE;
+ handler_ctx->daemon_pid = msg->daemon_pid;
+ handler_ctx->mount_flags = msg->mount_flags;
+ handler_ctx->hdr.timeout_seconds = 1;
+ DEBUG("pid of daemon is %d; mount flags were %#x",
+ handler_ctx->daemon_pid,
+ handler_ctx->mount_flags);
+ return 0;
+}
+
+static int
+msg_write_streams_progress_handler(const void *_msg, void *_handler_ctx)
+{
+ const struct msg_write_streams_progress *msg = _msg;
+ struct unmount_msg_handler_context *handler_ctx = _handler_ctx;
+
+ if (msg->hdr.msg_size < sizeof(*msg))
+ return WIMLIB_ERR_INVALID_UNMOUNT_MESSAGE;
+ if (handler_ctx->progress_func) {
+ handler_ctx->progress_func(WIMLIB_PROGRESS_MSG_WRITE_STREAMS,
+ &msg->info);
+ }
+ return 0;
+}
+
+static int
+msg_unmount_finished_handler(const void *_msg, void *_handler_ctx)
+{
+ const struct msg_unmount_finished *msg = _msg;
+ struct unmount_msg_handler_context *handler_ctx = _handler_ctx;
+
+ DEBUG("Handling unmount finished message");
+ if (msg->hdr.msg_size < sizeof(*msg))
+ return WIMLIB_ERR_INVALID_UNMOUNT_MESSAGE;
+ handler_ctx->status = msg->status;
+ DEBUG("status is %d", handler_ctx->status);
+ return MSG_BREAK_LOOP;
+}
+
+static int
+unmount_timed_out_cb(void *_handler_ctx)
+{
+ const struct unmount_msg_handler_context *handler_ctx = _handler_ctx;
+
+ if (handler_ctx->daemon_pid == 0 ||
+ (kill(handler_ctx->daemon_pid, 0) != 0 && errno == ESRCH))
+ {
+ ERROR("The filesystem daemon has crashed! Changes to the "
+ "WIM may not have been commited.");
+ return WIMLIB_ERR_FILESYSTEM_DAEMON_CRASHED;
+ }
+
+ DEBUG("Filesystem daemon is still alive... "
+ "Waiting another %d seconds", handler_ctx->hdr.timeout_seconds);
+ return 0;
+}
+
+static int
+daemon_timed_out_cb(void *_handler_ctx)
+{
+ ERROR("Timed out waiting for unmount request! "
+ "Changes to the mounted WIM will not be committed.");
+ return WIMLIB_ERR_TIMEOUT;
+}
+
+typedef int (*msg_handler_t)(const void *_msg, void *_handler_ctx);
+
+struct msg_handler_callbacks {
+ int (*timed_out)(void * _handler_ctx);
+ msg_handler_t msg_handlers[MSG_TYPE_MAX];
+};
+
+static const struct msg_handler_callbacks unmount_msg_handler_callbacks = {
+ .timed_out = unmount_timed_out_cb,
+ .msg_handlers = {
+ [MSG_TYPE_DAEMON_INFO] = msg_daemon_info_handler,
+ [MSG_TYPE_WRITE_STREAMS_PROGRESS] = msg_write_streams_progress_handler,
+ [MSG_TYPE_UNMOUNT_FINISHED] = msg_unmount_finished_handler,
+ },
+};
+
+static const struct msg_handler_callbacks daemon_msg_handler_callbacks = {
+ .timed_out = daemon_timed_out_cb,
+ .msg_handlers = {
+ [MSG_TYPE_UNMOUNT_REQUEST] = msg_unmount_request_handler,
+ },
+};
+
+static int
+receive_message(mqd_t mq,
+ struct msg_handler_context_hdr *handler_ctx,
+ const msg_handler_t msg_handlers[],
+ long mailbox_size, void *mailbox)
+{
+ struct timeval now;
+ struct timespec timeout;
+ ssize_t bytes_received;
+ struct unmount_msg_hdr *hdr;
+ int ret;
+
+ gettimeofday(&now, NULL);
+ timeout.tv_sec = now.tv_sec + handler_ctx->timeout_seconds;
+ timeout.tv_nsec = now.tv_usec * 1000;
+
+ bytes_received = mq_timedreceive(mq, mailbox,
+ mailbox_size, NULL, &timeout);
+ hdr = mailbox;
+ if (bytes_received == -1) {
+ if (errno == ETIMEDOUT) {
+ ret = WIMLIB_ERR_TIMEOUT;
+ } else {
+ ERROR_WITH_ERRNO("mq_timedreceive()");
+ ret = WIMLIB_ERR_MQUEUE;
+ }
+ } else if (bytes_received < sizeof(*hdr) ||
+ bytes_received != hdr->msg_size) {
+ ret = WIMLIB_ERR_INVALID_UNMOUNT_MESSAGE;
+ } else if (WIMLIB_VERSION_CODE < hdr->min_version) {
+ /*ERROR("Cannot understand the received message. "*/
+ /*"Please upgrade wimlib to at least v%d.%d.%d",*/
+ /*WIMLIB_GET_MAJOR_VERSION(hdr->min_version),*/
+ /*WIMLIB_GET_MINOR_VERSION(hdr->min_version),*/
+ /*WIMLIB_GET_PATCH_VERSION(hdr->min_version));*/
+ ret = MSG_VERSION_TOO_HIGH;
+ } else if (hdr->msg_type >= MSG_TYPE_MAX) {
+ ret = WIMLIB_ERR_INVALID_UNMOUNT_MESSAGE;
+ } else if (msg_handlers[hdr->msg_type] == NULL) {
+ ret = WIMLIB_ERR_INVALID_UNMOUNT_MESSAGE;