From 8be1daeb4187fb729b3c642c5c7d0b7483329edc Mon Sep 17 00:00:00 2001 From: Mattias Axelsson Date: Thu, 4 Apr 2024 16:05:23 +0200 Subject: [PATCH 1/2] Listen to SD card availability using AXStorage --- app/Makefile | 9 +- app/dockerdwrapperwithcompose.c | 34 ++++--- app/sd_disk_storage.c | 163 ++++++++++++++++++++++++++++++++ app/sd_disk_storage.h | 10 ++ 4 files changed, 200 insertions(+), 16 deletions(-) create mode 100644 app/sd_disk_storage.c create mode 100644 app/sd_disk_storage.h diff --git a/app/Makefile b/app/Makefile index 9d6f55c..52a5963 100644 --- a/app/Makefile +++ b/app/Makefile @@ -1,8 +1,7 @@ -PROG1 = dockerdwrapperwithcompose -OBJS1 = $(PROG1).c +PROG1 = dockerdwrapper +OBJS1 = $(PROG1).o sd_disk_storage.o -PKGS = gio-2.0 glib-2.0 axparameter -DOCKS = docker dockerd docker-compose docker-init docker-proxy +PKGS = gio-2.0 glib-2.0 axparameter axstorage CFLAGS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) pkg-config --cflags $(PKGS)) LDLIBS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) pkg-config --libs $(PKGS)) @@ -16,6 +15,8 @@ all: $(PROG1) $(PROG1): $(OBJS1) $(CC) $(CFLAGS) $(LDFLAGS) $^ $(LIBS) $(LDLIBS) -o $@ +$(PROG1).o sd_disk_storage.o: sd_disk_storage.h + clean: mv package.conf.orig package.conf || : rm -f $(PROG1) docker dockerd docker_binaries.tgz docker-compose docker-init docker-proxy *.o *.eap diff --git a/app/dockerdwrapperwithcompose.c b/app/dockerdwrapperwithcompose.c index 0f40d60..9a7a715 100644 --- a/app/dockerdwrapperwithcompose.c +++ b/app/dockerdwrapperwithcompose.c @@ -25,6 +25,7 @@ #include #include #include +#include "sd_disk_storage.h" #define APP_DIRECTORY "/usr/local/packages/" APP_NAME #define APP_LOCALDATA APP_DIRECTORY "/localdata" @@ -532,16 +533,15 @@ start_dockerd(const struct settings *settings, struct app_state *app_state) return return_value; } -static bool +static void read_settings_and_start_dockerd(struct app_state *app_state) { struct settings settings = {0}; - bool success = read_settings(&settings, app_state) && - start_dockerd(&settings, app_state); + if (read_settings(&settings, app_state)) + start_dockerd(&settings, app_state); free(settings.data_root); - return success; } /** @@ -674,12 +674,20 @@ setup_axparameter(void) return ax_parameter; } +static void +sd_card_callback(const char *sd_card_area, void *app_state_void_ptr) +{ + struct app_state *app_state = app_state_void_ptr; + if (!sd_card_area) + stop_dockerd(); // Block here until dockerd has stopped using the SD card. + app_state->sd_card_area = sd_card_area ? strdup(sd_card_area) : NULL; + g_main_loop_quit(loop); // Trigger a restart of dockerd from main() +} + int main(void) { struct app_state app_state = {0}; - app_state.sd_card_area = strdup("/var/spool/storage/SD_DISK/dockerd"); - AXParameter *ax_parameter = NULL; openlog(NULL, LOG_PID, LOG_USER); @@ -690,6 +698,9 @@ main(void) // Setup signal handling. init_signals(); + struct sd_disk_storage *sd_disk_storage = + sd_disk_storage_init(sd_card_callback, &app_state); + // Setup ax_parameter ax_parameter = setup_axparameter(); if (ax_parameter == NULL) { @@ -698,12 +709,10 @@ main(void) } while (application_exit_code == EX_KEEP_RUNNING) { - if (dockerd_process_pid == -1 && - !read_settings_and_start_dockerd(&app_state)) { - quit_program(EX_SOFTWARE); - } else { - g_main_loop_run(loop); - } + if (dockerd_process_pid == -1) + read_settings_and_start_dockerd(&app_state); + + g_main_loop_run(loop); if (!stop_dockerd()) syslog(LOG_WARNING, "Failed to shut down dockerd."); @@ -722,6 +731,7 @@ main(void) ax_parameter_free(ax_parameter); } + sd_disk_storage_free(sd_disk_storage); free(app_state.sd_card_area); return application_exit_code; } diff --git a/app/sd_disk_storage.c b/app/sd_disk_storage.c new file mode 100644 index 0000000..35e1c24 --- /dev/null +++ b/app/sd_disk_storage.c @@ -0,0 +1,163 @@ +#include "sd_disk_storage.h" +#include +#include +#include +#include +#include + +struct sd_disk_storage { + SdDiskCallback callback; + void *user_data; + uint subscription_id; + AXStorage *handle; +}; + +static bool +event_status_or_log(gchar *storage_id, AXStorageStatusEventId event) +{ + GError *error = NULL; + bool value = ax_storage_get_status(storage_id, event, &error); + if (error) { + syslog(LOG_WARNING, "Could not read ax_storage status: %s", error->message); + g_clear_error(&error); + } + return value; +} + +static void +setup_cb(AXStorage *handle, gpointer storage_void_ptr, GError *error) +{ + struct sd_disk_storage *storage = storage_void_ptr; + if (handle) + storage->handle = handle; + + if (error) { + syslog(LOG_WARNING, "setup_cb error: %s", error->message); + g_clear_error(&error); + storage->callback(NULL, storage->user_data); + return; + } + + g_autofree char *path = ax_storage_get_path(handle, &error); + if (!path) { + syslog(LOG_WARNING, "Failed to get storage path: %s", error->message); + g_clear_error(&error); + storage->callback(NULL, storage->user_data); + return; + } + + storage->callback(path, storage->user_data); +} + +static void +release_cb(gpointer, GError *error) +{ + if (error) + syslog(LOG_WARNING, "Error while releasing storage: %s", error->message); +} + +static void +release(struct sd_disk_storage *storage) +{ + GError *error = NULL; + if (storage->handle) { + if (!ax_storage_release_async(storage->handle, release_cb, NULL, &error)) { + syslog(LOG_WARNING, "Failed to release storage: %s", error->message); + g_clear_error(&error); + } + storage->handle = NULL; + } +} + +static void +release_and_unsubscribe(struct sd_disk_storage *storage) +{ + GError *error = NULL; + + release(storage); + + if (storage->subscription_id) { + if (!ax_storage_unsubscribe(storage->subscription_id, &error)) { + syslog(LOG_WARNING, + "Failed to unsubscribe to storage events: %s", + error->message); + g_clear_error(&error); + } + storage->subscription_id = 0; + } +} + +void +sd_disk_storage_free(struct sd_disk_storage *storage) +{ + if (storage) + release_and_unsubscribe(storage); + free(storage); +} + +static void +subscribe_cb(gchar *storage_id, gpointer storage_void_ptr, GError *error) +{ + struct sd_disk_storage *storage = storage_void_ptr; + + if (error) { + syslog(LOG_WARNING, "subscribe_cb error: %s", error->message); + g_clear_error(&error); + storage->callback(NULL, storage->user_data); + } + + if (event_status_or_log(storage_id, AX_STORAGE_EXITING_EVENT)) { + storage->callback(NULL, storage->user_data); + release(storage); + } + + if (event_status_or_log(storage_id, AX_STORAGE_WRITABLE_EVENT)) { + if (!ax_storage_setup_async(storage_id, setup_cb, storage, &error)) { + syslog(LOG_WARNING, "ax_storage_setup_async error: %s", error->message); + g_clear_error(&error); + storage->callback(NULL, storage->user_data); + } + } +} + +static bool +subscribe(struct sd_disk_storage *storage, const char *storage_id) +{ + GError *error = NULL; + bool found = false; + GList *devices = ax_storage_list(&error); + for (GList *node = g_list_first(devices); node; node = g_list_next(node)) { + if (strcmp(node->data, storage_id) == 0) { + found = true; + if (!(storage->subscription_id = ax_storage_subscribe( + node->data, subscribe_cb, storage, &error))) { + syslog(LOG_ERR, + "Failed to subscribe to events of %s: %s", + (char *)node->data, + error->message); + g_clear_error(&error); + return false; + } + } + g_free(node->data); + } + g_list_free(devices); + if (!found) + syslog(LOG_INFO, + "No storage with id %s found", + storage_id); // Not an error if products doesn't have SD card slot + return true; +} + +struct sd_disk_storage * +sd_disk_storage_init(SdDiskCallback sd_disk_callback, void *user_data) +{ + struct sd_disk_storage *storage = g_malloc0(sizeof(struct sd_disk_storage)); + storage->callback = sd_disk_callback; + storage->user_data = user_data; + if (!subscribe(storage, "SD_DISK")) { + sd_disk_storage_free(storage); + return NULL; + } + return storage; +} diff --git a/app/sd_disk_storage.h b/app/sd_disk_storage.h new file mode 100644 index 0000000..54dbb66 --- /dev/null +++ b/app/sd_disk_storage.h @@ -0,0 +1,10 @@ +#pragma once + +typedef void (*SdDiskCallback)(const char *area_path, void *user_data); + +// Call sd_disk_callback with a path to the SD card when it has become available +// and with NULL when it is about to be unmounted. +struct sd_disk_storage *sd_disk_storage_init(SdDiskCallback sd_disk_callback, + void *user_data); + +void sd_disk_storage_free(struct sd_disk_storage *storage); From 9acab460437292d1f2d874bffd6e93d491bc7e39 Mon Sep 17 00:00:00 2001 From: Mattias Axelsson Date: Thu, 4 Apr 2024 16:13:58 +0200 Subject: [PATCH 2/2] Update Makefile --- app/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Makefile b/app/Makefile index 52a5963..525d90f 100644 --- a/app/Makefile +++ b/app/Makefile @@ -1,4 +1,4 @@ -PROG1 = dockerdwrapper +PROG1 = dockerdwrapperwithcompose OBJS1 = $(PROG1).o sd_disk_storage.o PKGS = gio-2.0 glib-2.0 axparameter axstorage