Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Listen to SD card availability using AXStorage #75

Merged
merged 2 commits into from
Apr 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions app/Makefile
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
PROG1 = dockerdwrapperwithcompose
OBJS1 = $(PROG1).c
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))

Expand All @@ -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
34 changes: 22 additions & 12 deletions app/dockerdwrapperwithcompose.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include <sysexits.h>
#include <syslog.h>
#include <unistd.h>
#include "sd_disk_storage.h"

#define APP_DIRECTORY "/usr/local/packages/" APP_NAME
#define APP_LOCALDATA APP_DIRECTORY "/localdata"
Expand Down Expand Up @@ -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;
}

/**
Expand Down Expand Up @@ -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);
Expand All @@ -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) {
Expand All @@ -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.");
Expand All @@ -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;
}
163 changes: 163 additions & 0 deletions app/sd_disk_storage.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
#include "sd_disk_storage.h"
#include <axsdk/axstorage.h>
#include <stdbool.h>
#include <stdio.h>
#include <syslog.h>
#include <unistd.h>

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;
}
10 changes: 10 additions & 0 deletions app/sd_disk_storage.h
Original file line number Diff line number Diff line change
@@ -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);
Loading