From: Pratyush Yadav <ptyadav@xxxxxxxxx> luoctl is a utility to interact with the LUO state machine. It currently supports viewing and change the current state of LUO. This can be used by scripts, tools, or developers to control LUO state during the live update process. Example usage: $ luoctl state normal $ luoctl prepare $ luoctl state prepared $ luoctl cancel $ luoctl state normal Signed-off-by: Pratyush Yadav <ptyadav@xxxxxxxxx> Signed-off-by: Pasha Tatashin <pasha.tatashin@xxxxxxxxxx> --- tools/lib/luo/Makefile | 6 +- tools/lib/luo/cli/.gitignore | 1 + tools/lib/luo/cli/Makefile | 18 ++++ tools/lib/luo/cli/luoctl.c | 178 +++++++++++++++++++++++++++++++++++ 4 files changed, 202 insertions(+), 1 deletion(-) create mode 100644 tools/lib/luo/cli/.gitignore create mode 100644 tools/lib/luo/cli/Makefile create mode 100644 tools/lib/luo/cli/luoctl.c diff --git a/tools/lib/luo/Makefile b/tools/lib/luo/Makefile index e851c37d3d0a..e8f6bd3b9e85 100644 --- a/tools/lib/luo/Makefile +++ b/tools/lib/luo/Makefile @@ -13,7 +13,7 @@ LIB_NAME = libluo STATIC_LIB = $(LIB_NAME).a SHARED_LIB = $(LIB_NAME).so -.PHONY: all clean install +.PHONY: all clean install cli all: $(STATIC_LIB) $(SHARED_LIB) @@ -26,8 +26,12 @@ $(SHARED_LIB): $(OBJS) %.o: %.c $(HEADERS) $(CC) $(CFLAGS) -c $< -o $@ +cli: $(STATIC_LIB) + $(MAKE) -C cli + clean: rm -f $(OBJS) $(STATIC_LIB) $(SHARED_LIB) + $(MAKE) -C cli clean install: all install -d $(DESTDIR)/usr/local/lib diff --git a/tools/lib/luo/cli/.gitignore b/tools/lib/luo/cli/.gitignore new file mode 100644 index 000000000000..3a5e2d287f60 --- /dev/null +++ b/tools/lib/luo/cli/.gitignore @@ -0,0 +1 @@ +/luoctl diff --git a/tools/lib/luo/cli/Makefile b/tools/lib/luo/cli/Makefile new file mode 100644 index 000000000000..6c0cbf92a420 --- /dev/null +++ b/tools/lib/luo/cli/Makefile @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: LGPL-3.0-or-later +LUOCTL = luoctl +INCLUDE_DIR = ../include +HEADERS = $(wildcard $(INCLUDE_DIR)/*.h) + +CC = gcc +CFLAGS = -Wall -Wextra -O2 -g -I$(INCLUDE_DIR) +LDFLAGS = -L.. -l:libluo.a + +.PHONY: all clean + +all: $(LUOCTL) + +luoctl: luoctl.c ../libluo.a $(HEADERS) + $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) + +clean: + rm -f $(LUOCTL) diff --git a/tools/lib/luo/cli/luoctl.c b/tools/lib/luo/cli/luoctl.c new file mode 100644 index 000000000000..39ba0bdd44f0 --- /dev/null +++ b/tools/lib/luo/cli/luoctl.c @@ -0,0 +1,178 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +/** + * @file luoctl.c + * @brief Simple utility to interact with LUO + * + * This utility allows viewing and controlling LUO state. + * + * Copyright (C) 2025 Amazon.com Inc. or its affiliates. + * Author: Pratyush Yadav <ptyadav@xxxxxxxxx> + */ + +#include <libluo.h> +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <getopt.h> + +#define fatal(fmt, ...) \ + do { \ + fprintf(stderr, "Error: " fmt, ##__VA_ARGS__); \ + exit(1); \ + } while (0) + +struct command { + char *name; + int (*handler)(void); +}; + +static void usage(const char *prog_name) +{ + printf("Usage: %s [command]\n\n", prog_name); + printf("Commands:\n"); + printf(" state - Show current LUO state\n"); + printf(" prepare - Prepare for live update\n"); + printf(" cancel - Cancel live update preparation\n"); + printf(" finish - Signal completion of restoration\n"); +} + +static enum liveupdate_state get_state(void) +{ + enum liveupdate_state state; + int ret; + + ret = luo_get_state(&state); + if (ret) + fatal("failed to get LUO state: %s\n", strerror(-ret)); + + return state; +} + +static int show_state(void) +{ + enum liveupdate_state state; + + state = get_state(); + printf("%s\n", luo_state_to_string(state)); + return 0; +} + +static int do_prepare(void) +{ + enum liveupdate_state state; + int ret; + + state = get_state(); + if (state != LIVEUPDATE_STATE_NORMAL) + fatal("can only switch to prepared state from normal state. Current state: %s\n", + luo_state_to_string(state)); + + ret = luo_prepare(); + if (ret) + fatal("failed to prepare for live update: %s\n", strerror(-ret)); + + return 0; +} + +static int do_cancel(void) +{ + enum liveupdate_state state; + int ret; + + state = get_state(); + if (state != LIVEUPDATE_STATE_PREPARED) + fatal("can only cancel from normal state. Current state: %s\n", + luo_state_to_string(state)); + + ret = luo_cancel(); + if (ret) + fatal("failed to cancel live update: %s\n", strerror(-ret)); + + return 0; +} + +static int do_finish(void) +{ + enum liveupdate_state state; + int ret; + + state = get_state(); + if (state != LIVEUPDATE_STATE_UPDATED) + fatal("can only finish from updated state. Current state: %s\n", + luo_state_to_string(state)); + + ret = luo_finish(); + if (ret) + fatal("failed to finish live update: %s\n", strerror(-ret)); + + return 0; +} + +static struct command commands[] = { + {"state", show_state}, + {"prepare", do_prepare}, + {"cancel", do_cancel}, + {"finish", do_finish}, + {NULL, NULL}, +}; + +int main(int argc, char *argv[]) +{ + struct option long_options[] = { + {"help", no_argument, 0, 'h'}, + {0, 0, 0, 0} + }; + struct command *command; + int ret = -EINVAL, opt; + char *cmd; + + if (!luo_is_available()) { + fprintf(stderr, "LUO is not available on this system\n"); + return 1; + } + + while ((opt = getopt_long(argc, argv, "ht:e:", long_options, NULL)) != -1) { + switch (opt) { + case 'h': + usage(argv[0]); + return 0; + default: + fprintf(stderr, "Try '%s --help' for more information.\n", argv[0]); + return 1; + } + } + + if (argc - optind != 1) { + usage(argv[0]); + return 1; + } + + cmd = argv[optind]; + + ret = luo_init(); + if (ret < 0) { + fprintf(stderr, "Failed to initialize LibLUO: %s\n", strerror(-ret)); + return 1; + } + + command = &commands[0]; + while (command->name) { + if (!strcmp(cmd, command->name)) { + ret = command->handler(); + break; + } + command++; + } + + if (!command->name) { + fprintf(stderr, "Unknown command %s. Try '%s --help' for more information\n", + cmd, argv[0]); + ret = -EINVAL; + } + + luo_cleanup(); + return (ret < 0) ? 1 : 0; +} -- 2.50.0.727.gbf7dc18ff4-goog