tonarchy
tonarchy
https://git.tonybtw.com/tonarchy.git
git://git.tonybtw.com/tonarchy.git
Updated makefile for nix, and moved mkiso.c to build_iso.c, and added header file.
Diff
diff --git a/.gitignore b/.gitignore
index da45498..82bfebe 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,6 +16,7 @@ test-disk*
result
notes/
+build_iso
out/
iso/airootfs/usr/
diff --git a/Makefile b/Makefile
index 9e6ac98..029ef82 100644
--- a/Makefile
+++ b/Makefile
@@ -8,13 +8,14 @@ SRC = src/tonarchy.c
LATEST_ISO = $(shell ls -t out/*.iso 2>/dev/null | head -1)
TEST_DISK = test-disk.qcow2
-.PHONY: all clean install static mkiso build-iso test test-disk clean-iso clean-vm
+.PHONY: all clean install static build build-container test test-nix test-disk clean-iso clean-vm
all: $(TARGET)
static: $(TARGET)-static
-mkiso: tonarchy-mkiso
+build_iso: src/build_iso.c src/build_iso.h
+ $(CC) $(CFLAGS) src/build_iso.c -o build_iso
$(TARGET): $(SRC)
$(CC) $(CFLAGS) $(SRC) -o $(TARGET) $(LDFLAGS)
@@ -22,14 +23,18 @@ $(TARGET): $(SRC)
$(TARGET)-static: $(SRC)
$(CC) $(CFLAGS) $(SRC) -o $(TARGET)-static $(STATIC_LDFLAGS)
-tonarchy-mkiso: src/tonarchy-mkiso.c
- $(CC) $(CFLAGS) src/tonarchy-mkiso.c -o tonarchy-mkiso
+build: build_iso
+ ./build_iso --iso-profile ./iso --out-dir ./out
-build-iso: tonarchy-mkiso
- ./tonarchy-mkiso --iso-profile ./iso --out-dir ./out
+build-container: build_iso
+ ./build_iso --iso-profile ./iso --out-dir ./out --container podman
+
+test-nix:
+ @if [ -z "$(LATEST_ISO)" ]; then echo "No ISO found. Run 'nix run .#build_iso -- --container podman' first"; exit 1; fi
+ ./vm-test "$(LATEST_ISO)"
test:
- @if [ -z "$(LATEST_ISO)" ]; then echo "No ISO found. Run 'make build-iso' first"; exit 1; fi
+ @if [ -z "$(LATEST_ISO)" ]; then echo "No ISO found. Run 'make build' first"; exit 1; fi
@if [ ! -f "$(TEST_DISK)" ]; then \
echo "Creating test disk..."; \
qemu-img create -f qcow2 "$(TEST_DISK)" 20G; \
@@ -94,7 +99,7 @@ clean-iso:
sudo rm -rf /tmp/tonarchy_iso_work
clean: clean-iso clean-vm
- rm -f $(TARGET) $(TARGET)-static tonarchy-mkiso
+ rm -f $(TARGET) $(TARGET)-static build_iso
install: $(TARGET)
install -Dm755 $(TARGET) /usr/local/bin/$(TARGET)
diff --git a/flake.nix b/flake.nix
index ece30ec..864e59f 100644
--- a/flake.nix
+++ b/flake.nix
@@ -11,6 +11,33 @@
forAllSystems = fn: nixpkgs.lib.genAttrs systems (system: fn nixpkgs.legacyPackages.${system});
in
{
+ packages = forAllSystems (pkgs: {
+ build_iso = pkgs.stdenv.mkDerivation {
+ pname = "build_iso";
+ version = "0.1.0";
+ src = ./.;
+ buildInputs = [ pkgs.musl ];
+ buildPhase = ''
+ ${pkgs.musl.dev}/bin/musl-gcc -std=c23 -Wall -Wextra -O2 -static src/build_iso.c -o build_iso
+ '';
+ installPhase = ''
+ mkdir -p $out/bin
+ cp build_iso $out/bin/
+ '';
+ };
+
+ default = self.packages.${pkgs.system}.build_iso;
+ });
+
+ apps = forAllSystems (pkgs: {
+ build_iso = {
+ type = "app";
+ program = "${self.packages.${pkgs.system}.build_iso}/bin/build_iso";
+ };
+
+ default = self.apps.${pkgs.system}.build_iso;
+ });
+
devShells = forAllSystems (pkgs: {
default = pkgs.mkShell {
buildInputs = [
@@ -20,11 +47,15 @@
pkgs.bear
pkgs.qemu_kvm
pkgs.OVMF
+ pkgs.podman
+ pkgs.distrobox
];
shellHook = ''
export PS1="(tonarchy-dev) $PS1"
echo "tonarchy development environment"
echo "Run 'make' to build"
+ echo "Run 'make build' to build ISO natively (Arch)"
+ echo "Run 'nix run .#build_iso -- --container podman' to build ISO (NixOS)"
echo "Run './vm-test [iso-path]' to test an ISO in qemu"
'';
};
diff --git a/src/build_iso.c b/src/build_iso.c
new file mode 100644
index 0000000..1c2e234
--- /dev/null
+++ b/src/build_iso.c
@@ -0,0 +1,520 @@
+#include "build_iso.h"
+#include <stdarg.h>
+
+static FILE *log_file = NULL;
+
+void logger_init(const char *log_path) {
+ log_file = fopen(log_path, "a");
+ if (log_file) {
+ time_t now = time(NULL);
+ char *timestamp = ctime(&now);
+ timestamp[strlen(timestamp) - 1] = '\0';
+ fprintf(log_file, "\n=== Tonarchy ISO Build Log - %s ===\n", timestamp);
+ fflush(log_file);
+ }
+}
+
+void logger_close(void) {
+ if (log_file) {
+ fclose(log_file);
+ log_file = NULL;
+ }
+}
+
+void log_info(const char *fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ printf("[INFO] ");
+ vprintf(fmt, args);
+ printf("\n");
+ va_end(args);
+
+ if (log_file) {
+ va_start(args, fmt);
+ fprintf(log_file, "[INFO] ");
+ vfprintf(log_file, fmt, args);
+ fprintf(log_file, "\n");
+ fflush(log_file);
+ va_end(args);
+ }
+}
+
+void log_error(const char *fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ fprintf(stderr, "[ERROR] ");
+ vfprintf(stderr, fmt, args);
+ fprintf(stderr, "\n");
+ va_end(args);
+
+ if (log_file) {
+ va_start(args, fmt);
+ fprintf(log_file, "[ERROR] ");
+ vfprintf(log_file, fmt, args);
+ fprintf(log_file, "\n");
+ fflush(log_file);
+ va_end(args);
+ }
+}
+
+void log_warn(const char *fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ fprintf(stderr, "[WARN] ");
+ vfprintf(stderr, fmt, args);
+ fprintf(stderr, "\n");
+ va_end(args);
+
+ if (log_file) {
+ va_start(args, fmt);
+ fprintf(log_file, "[WARN] ");
+ vfprintf(log_file, fmt, args);
+ fprintf(log_file, "\n");
+ fflush(log_file);
+ va_end(args);
+ }
+}
+
+int run_command(const char *cmd) {
+ log_info("Running: %s", cmd);
+ int ret = system(cmd);
+ if (ret != 0) {
+ log_error("Command failed with code %d: %s", ret, cmd);
+ return 0;
+ }
+ return 1;
+}
+
+int run_command_in_container(const char *cmd, const Build_Config *config) {
+ char container_cmd[CMD_MAX_LEN];
+
+ if (config->container_type == CONTAINER_DISTROBOX) {
+ snprintf(container_cmd, sizeof(container_cmd),
+ "distrobox enter %s -- sh -c '%s'",
+ config->distrobox_name, cmd);
+ } else if (config->container_type == CONTAINER_PODMAN) {
+ snprintf(container_cmd, sizeof(container_cmd),
+ "podman run --rm --privileged "
+ "-v '%s:/src' "
+ "-v '%s:/profile' "
+ "-v '%s:/out' "
+ "-v '%s:/work' "
+ "docker.io/archlinux:latest sh -c '%s'",
+ config->tonarchy_src,
+ config->iso_profile,
+ config->out_dir,
+ config->work_dir,
+ cmd);
+ } else {
+ return run_command(cmd);
+ }
+
+ return run_command(container_cmd);
+}
+
+int create_directory(const char *path, mode_t mode) {
+ struct stat st;
+ if (stat(path, &st) == 0) {
+ return 1;
+ }
+
+ if (mkdir(path, mode) != 0) {
+ log_error("Failed to create directory: %s", path);
+ return 0;
+ }
+ return 1;
+}
+
+int detect_container_runtime(void) {
+ if (system("command -v podman >/dev/null 2>&1") == 0) {
+ return 1;
+ }
+ if (system("command -v distrobox >/dev/null 2>&1") == 0) {
+ return 1;
+ }
+ return 0;
+}
+
+int check_distrobox_exists(const char *name) {
+ char cmd[CMD_MAX_LEN];
+ snprintf(cmd, sizeof(cmd), "distrobox list | grep -q '%s'", name);
+ return system(cmd) == 0;
+}
+
+int build_tonarchy_static(const Build_Config *config) {
+ log_info("Building tonarchy static binary...");
+
+ char cmd[CMD_MAX_LEN];
+
+ if (config->use_container && config->container_type == CONTAINER_PODMAN) {
+ log_info("Building static binary in podman container...");
+ snprintf(cmd, sizeof(cmd),
+ "sudo podman run --rm "
+ "-v '%s:/src' "
+ "docker.io/archlinux:latest "
+ "sh -c 'pacman -Sy --noconfirm musl gcc && "
+ "cd /src && rm -f tonarchy tonarchy-static && "
+ "musl-gcc -std=c23 -Wall -Wextra -O2 -static src/tonarchy.c -o tonarchy-static'",
+ config->tonarchy_src);
+ if (!run_command(cmd)) {
+ log_error("Failed to build tonarchy-static in podman");
+ return 0;
+ }
+ } else if (config->use_container && config->container_type == CONTAINER_DISTROBOX) {
+ snprintf(cmd, sizeof(cmd),
+ "sudo pacman -S --noconfirm --needed musl && "
+ "cd '%s' && make clean && make static CC=musl-gcc",
+ config->tonarchy_src);
+ if (!run_command_in_container(cmd, config)) {
+ log_error("Failed to build tonarchy-static in distrobox");
+ return 0;
+ }
+ } else {
+ snprintf(cmd, sizeof(cmd),
+ "cd '%s' && make clean && make static CC=musl-gcc",
+ config->tonarchy_src);
+ if (!run_command(cmd)) {
+ log_error("Failed to build tonarchy-static");
+ return 0;
+ }
+ }
+
+ char binary_path[PATH_MAX_LEN];
+ snprintf(binary_path, sizeof(binary_path), "%s/tonarchy-static", config->tonarchy_src);
+
+ struct stat st;
+ if (stat(binary_path, &st) != 0) {
+ log_error("tonarchy-static binary not found at %s", binary_path);
+ return 0;
+ }
+
+ log_info("Built tonarchy-static successfully");
+ return 1;
+}
+
+int clean_airootfs(const Build_Config *config) {
+ log_info("Cleaning airootfs...");
+
+ char cmd[CMD_MAX_LEN];
+
+ snprintf(cmd, sizeof(cmd), "sudo rm -rf '%s/airootfs/usr'", config->iso_profile);
+ if (!run_command(cmd)) {
+ log_warn("Failed to clean airootfs/usr");
+ }
+
+ snprintf(cmd, sizeof(cmd), "sudo rm -rf '%s/airootfs/root/tonarchy'", config->iso_profile);
+ if (!run_command(cmd)) {
+ log_warn("Failed to clean airootfs/root/tonarchy");
+ }
+
+ return 1;
+}
+
+int clean_work_dir(const Build_Config *config) {
+ log_info("Cleaning work directory...");
+
+ char cmd[CMD_MAX_LEN];
+
+ snprintf(cmd, sizeof(cmd), "sudo umount -R '%s' 2>/dev/null || true", config->work_dir);
+ run_command(cmd);
+
+ snprintf(cmd, sizeof(cmd), "sudo rm -rf '%s'", config->work_dir);
+ if (!run_command(cmd)) {
+ log_error("Failed to remove work directory: %s", config->work_dir);
+ return 0;
+ }
+
+ sync();
+ sleep(1);
+
+ return 1;
+}
+
+int prepare_airootfs(const Build_Config *config) {
+ log_info("Preparing airootfs...");
+
+ char cmd[CMD_MAX_LEN];
+ char src_path[PATH_MAX_LEN];
+ char dest_path[PATH_MAX_LEN];
+
+ snprintf(cmd, sizeof(cmd), "mkdir -p '%s/airootfs/usr/local/bin'", config->iso_profile);
+ if (!run_command(cmd)) {
+ log_error("Failed to create airootfs/usr/local/bin");
+ return 0;
+ }
+
+ snprintf(cmd, sizeof(cmd), "mkdir -p '%s/airootfs/usr/share'", config->iso_profile);
+ if (!run_command(cmd)) {
+ log_error("Failed to create airootfs/usr/share");
+ return 0;
+ }
+
+ snprintf(src_path, sizeof(src_path), "%s/tonarchy-static", config->tonarchy_src);
+ snprintf(dest_path, sizeof(dest_path), "%s/airootfs/usr/local/bin/tonarchy", config->iso_profile);
+ snprintf(cmd, sizeof(cmd), "cp '%s' '%s'", src_path, dest_path);
+ if (!run_command(cmd)) {
+ log_error("Failed to copy tonarchy binary");
+ return 0;
+ }
+
+ snprintf(cmd, sizeof(cmd), "chmod 755 '%s'", dest_path);
+ if (!run_command(cmd)) {
+ log_error("Failed to set permissions on tonarchy binary");
+ return 0;
+ }
+
+ snprintf(src_path, sizeof(src_path), "%s/assets", config->tonarchy_src);
+ snprintf(dest_path, sizeof(dest_path), "%s/airootfs/usr/share/tonarchy", config->iso_profile);
+ snprintf(cmd, sizeof(cmd), "mkdir -p '%s'", dest_path);
+ if (!run_command(cmd)) {
+ log_error("Failed to create tonarchy share directory");
+ return 0;
+ }
+ snprintf(cmd, sizeof(cmd), "cp -r '%s'/* '%s'", src_path, dest_path);
+ if (!run_command(cmd)) {
+ log_error("Failed to copy tonarchy config files");
+ return 0;
+ }
+
+ snprintf(dest_path, sizeof(dest_path), "%s/airootfs/usr/share/wallpapers", config->iso_profile);
+ snprintf(cmd, sizeof(cmd), "cp -r '%s/wallpapers' '%s'", src_path, dest_path);
+ if (!run_command(cmd)) {
+ log_warn("Failed to copy wallpapers");
+ }
+
+ log_info("Setting proper ownership for airootfs...");
+ snprintf(cmd, sizeof(cmd), "sudo chown -R root:root '%s/airootfs/usr'", config->iso_profile);
+ if (!run_command(cmd)) {
+ log_error("Failed to set ownership on airootfs");
+ return 0;
+ }
+
+ return 1;
+}
+
+int run_mkarchiso(const Build_Config *config) {
+ log_info("Building ISO with mkarchiso...");
+
+ if (!create_directory(config->out_dir, 0755)) {
+ return 0;
+ }
+
+ if (!create_directory(config->work_dir, 0755)) {
+ return 0;
+ }
+
+ char cmd[CMD_MAX_LEN];
+ snprintf(cmd, sizeof(cmd), "sudo mkarchiso -v -w '%s' -o '%s' '%s'",
+ config->work_dir, config->out_dir, config->iso_profile);
+
+ if (!run_command(cmd)) {
+ log_error("mkarchiso failed");
+ return 0;
+ }
+
+ return 1;
+}
+
+int run_mkarchiso_in_container(const Build_Config *config) {
+ log_info("Building ISO with mkarchiso in container...");
+
+ if (!create_directory(config->out_dir, 0755)) {
+ return 0;
+ }
+
+ if (!create_directory(config->work_dir, 0755)) {
+ return 0;
+ }
+
+ char cmd[CMD_MAX_LEN];
+
+ log_info("Setting up container policy...");
+ run_command("sudo mkdir -p /etc/containers");
+ run_command("echo '{\"default\":[{\"type\":\"insecureAcceptAnything\"}]}' | sudo tee /etc/containers/policy.json > /dev/null");
+
+ snprintf(cmd, sizeof(cmd),
+ "sudo podman run --rm --privileged "
+ "-v '%s:/profile' "
+ "-v '%s:/out' "
+ "-v '%s:/work' "
+ "docker.io/archlinux:latest "
+ "sh -c 'pacman -Sy --noconfirm archiso && mkarchiso -v -w /work -o /out /profile'",
+ config->iso_profile,
+ config->out_dir,
+ config->work_dir);
+
+ if (!run_command(cmd)) {
+ log_error("mkarchiso in container failed");
+ return 0;
+ }
+
+ return 1;
+}
+
+const char *find_latest_iso(const char *out_dir) {
+ static char iso_path[PATH_MAX_LEN];
+ char cmd[CMD_MAX_LEN];
+
+ snprintf(cmd, sizeof(cmd), "ls -t '%s'/*.iso 2>/dev/null | head -n1", out_dir);
+
+ FILE *fp = popen(cmd, "r");
+ if (!fp) {
+ return NULL;
+ }
+
+ if (fgets(iso_path, sizeof(iso_path), fp) != NULL) {
+ iso_path[strcspn(iso_path, "\n")] = 0;
+ pclose(fp);
+ return iso_path;
+ }
+
+ pclose(fp);
+ return NULL;
+}
+
+static void print_usage(const char *prog_name) {
+ printf("Usage: %s [OPTIONS]\n", prog_name);
+ printf("\nOptions:\n");
+ printf(" --iso-profile PATH Path to ISO profile directory (default: ./iso)\n");
+ printf(" --out-dir PATH Output directory for ISO (default: ./out)\n");
+ printf(" --container [TYPE] Build using container (podman or distrobox)\n");
+ printf(" --distrobox NAME Distrobox container name (default: arch)\n");
+ printf(" -h, --help Show this help message\n");
+}
+
+static int parse_args(int argc, char *argv[], Build_Config *config) {
+ for (int i = 1; i < argc; i++) {
+ if (strcmp(argv[i], "--iso-profile") == 0 && i + 1 < argc) {
+ snprintf(config->iso_profile, sizeof(config->iso_profile), "%s", argv[++i]);
+ } else if (strcmp(argv[i], "--out-dir") == 0 && i + 1 < argc) {
+ snprintf(config->out_dir, sizeof(config->out_dir), "%s", argv[++i]);
+ } else if (strcmp(argv[i], "--container") == 0) {
+ config->use_container = true;
+ if (i + 1 < argc && argv[i + 1][0] != '-') {
+ i++;
+ if (strcmp(argv[i], "podman") == 0) {
+ config->container_type = CONTAINER_PODMAN;
+ } else if (strcmp(argv[i], "distrobox") == 0) {
+ config->container_type = CONTAINER_DISTROBOX;
+ } else {
+ log_error("Unknown container type: %s", argv[i]);
+ return 0;
+ }
+ } else {
+ config->container_type = CONTAINER_PODMAN;
+ }
+ } else if (strcmp(argv[i], "--distrobox") == 0 && i + 1 < argc) {
+ snprintf(config->distrobox_name, sizeof(config->distrobox_name), "%s", argv[++i]);
+ config->use_container = true;
+ config->container_type = CONTAINER_DISTROBOX;
+ } else if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) {
+ print_usage(argv[0]);
+ exit(0);
+ } else {
+ log_error("Unknown option: %s", argv[i]);
+ print_usage(argv[0]);
+ return 0;
+ }
+ }
+ return 1;
+}
+
+int main(int argc, char *argv[]) {
+ logger_init("/tmp/build_iso.log");
+
+ log_info("Tonarchy ISO Builder starting...");
+
+ Build_Config config = {
+ .work_dir = "/tmp/tonarchy_iso_work",
+ .distrobox_name = "arch",
+ .container_type = CONTAINER_NONE,
+ .use_container = false
+ };
+
+ if (getcwd(config.tonarchy_src, sizeof(config.tonarchy_src)) == NULL) {
+ log_error("Failed to get current directory");
+ return 1;
+ }
+
+ snprintf(config.iso_profile, sizeof(config.iso_profile), "%s/iso", config.tonarchy_src);
+ snprintf(config.out_dir, sizeof(config.out_dir), "%s/out", config.tonarchy_src);
+
+ if (!parse_args(argc, argv, &config)) {
+ logger_close();
+ return 1;
+ }
+
+ log_info("Tonarchy source: %s", config.tonarchy_src);
+ log_info("ISO profile: %s", config.iso_profile);
+ log_info("Work directory: %s", config.work_dir);
+ log_info("Output directory: %s", config.out_dir);
+
+ if (config.use_container) {
+ log_info("Container mode: %s",
+ config.container_type == CONTAINER_PODMAN ? "podman" : "distrobox");
+ if (config.container_type == CONTAINER_DISTROBOX) {
+ log_info("Distrobox name: %s", config.distrobox_name);
+ }
+ }
+
+ if (!build_tonarchy_static(&config)) {
+ log_error("Build failed");
+ logger_close();
+ return 1;
+ }
+
+ if (!clean_airootfs(&config)) {
+ log_error("Failed to clean airootfs");
+ logger_close();
+ return 1;
+ }
+
+ if (!clean_work_dir(&config)) {
+ log_error("Failed to clean work directory");
+ logger_close();
+ return 1;
+ }
+
+ if (!prepare_airootfs(&config)) {
+ log_error("Failed to prepare airootfs");
+ logger_close();
+ return 1;
+ }
+
+ int build_result;
+ if (config.use_container && config.container_type == CONTAINER_PODMAN) {
+ build_result = run_mkarchiso_in_container(&config);
+ } else {
+ build_result = run_mkarchiso(&config);
+ }
+
+ if (!build_result) {
+ log_error("Failed to build ISO");
+ logger_close();
+ return 1;
+ }
+
+ if (!clean_work_dir(&config)) {
+ log_warn("Failed to clean work directory after build");
+ }
+
+ log_info("Syncing filesystem...");
+ sync();
+ sleep(2);
+
+ const char *iso_path = find_latest_iso(config.out_dir);
+ if (iso_path) {
+ log_info("===================================");
+ log_info("ISO created successfully!");
+ log_info("Location: %s", iso_path);
+ log_info("Test with: make test");
+ log_info("===================================");
+ } else {
+ log_error("ISO was built but could not be found in output directory");
+ logger_close();
+ return 1;
+ }
+
+ logger_close();
+ return 0;
+}
diff --git a/src/build_iso.h b/src/build_iso.h
new file mode 100644
index 0000000..814e929
--- /dev/null
+++ b/src/build_iso.h
@@ -0,0 +1,57 @@
+#ifndef BUILD_ISO_H
+#define BUILD_ISO_H
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <time.h>
+#include <stdbool.h>
+
+#define PATH_MAX_LEN 512
+#define CMD_MAX_LEN 2048
+
+typedef enum {
+ CONTAINER_NONE,
+ CONTAINER_PODMAN,
+ CONTAINER_DISTROBOX
+} Container_Type;
+
+typedef struct {
+ char tonarchy_src[PATH_MAX_LEN];
+ char iso_profile[PATH_MAX_LEN];
+ char out_dir[PATH_MAX_LEN];
+ char work_dir[PATH_MAX_LEN];
+ char distrobox_name[128];
+ Container_Type container_type;
+ bool use_container;
+} Build_Config;
+
+void logger_init(const char *log_path);
+void logger_close(void);
+
+void log_info(const char *fmt, ...);
+void log_error(const char *fmt, ...);
+void log_warn(const char *fmt, ...);
+
+int run_command(const char *cmd);
+int run_command_in_container(const char *cmd, const Build_Config *config);
+int create_directory(const char *path, mode_t mode);
+
+int build_tonarchy_static(const Build_Config *config);
+int clean_airootfs(const Build_Config *config);
+int clean_work_dir(const Build_Config *config);
+int prepare_airootfs(const Build_Config *config);
+int run_mkarchiso(const Build_Config *config);
+int run_mkarchiso_in_container(const Build_Config *config);
+
+const char *find_latest_iso(const char *out_dir);
+
+int detect_container_runtime(void);
+int check_distrobox_exists(const char *name);
+
+#endif
diff --git a/src/tonarchy-mkiso.c b/src/tonarchy-mkiso.c
deleted file mode 100644
index ff8e466..0000000
--- a/src/tonarchy-mkiso.c
+++ /dev/null
@@ -1,345 +0,0 @@
-#define _GNU_SOURCE
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <time.h>
-
-static FILE *log_file = NULL;
-
-void logger_init(const char *log_path) {
- log_file = fopen(log_path, "a");
- if (log_file) {
- time_t now = time(NULL);
- char *timestamp = ctime(&now);
- timestamp[strlen(timestamp) - 1] = '\0';
- fprintf(log_file, "\n=== Tonarchy ISO Build Log - %s ===\n", timestamp);
- fflush(log_file);
- }
-}
-
-void logger_close(void) {
- if (log_file) {
- fclose(log_file);
- log_file = NULL;
- }
-}
-
-#define LOG_INFO(fmt, ...) do { \
- printf("[INFO] " fmt "\n", ##__VA_ARGS__); \
- if (log_file) { \
- fprintf(log_file, "[INFO] " fmt "\n", ##__VA_ARGS__); \
- fflush(log_file); \
- } \
-} while(0)
-
-#define LOG_ERROR(fmt, ...) do { \
- fprintf(stderr, "[ERROR] " fmt "\n", ##__VA_ARGS__); \
- if (log_file) { \
- fprintf(log_file, "[ERROR] " fmt "\n", ##__VA_ARGS__); \
- fflush(log_file); \
- } \
-} while(0)
-
-#define LOG_WARN(fmt, ...) do { \
- fprintf(stderr, "[WARN] " fmt "\n", ##__VA_ARGS__); \
- if (log_file) { \
- fprintf(log_file, "[WARN] " fmt "\n", ##__VA_ARGS__); \
- fflush(log_file); \
- } \
-} while(0)
-
-int create_directory(const char *path, mode_t mode);
-
-int run_command(const char *cmd) {
- LOG_INFO("Running: %s", cmd);
- int ret = system(cmd);
- if (ret != 0) {
- LOG_ERROR("Command failed with code %d: %s", ret, cmd);
- return 0;
- }
- return 1;
-}
-
-int create_directory(const char *path, mode_t mode) {
- struct stat st;
- if (stat(path, &st) == 0) {
- return 1;
- }
-
- if (mkdir(path, mode) != 0) {
- LOG_ERROR("Failed to create directory: %s", path);
- return 0;
- }
- return 1;
-}
-
-int build_tonarchy_static(const char *tonarchy_src) {
- LOG_INFO("Building tonarchy static binary...");
-
- char cmd[1024];
- snprintf(cmd, sizeof(cmd), "cd '%s' && make clean && make static CC=musl-gcc", tonarchy_src);
-
- if (!run_command(cmd)) {
- LOG_ERROR("Failed to build tonarchy-static");
- return 0;
- }
-
- char binary_path[512];
- snprintf(binary_path, sizeof(binary_path), "%s/tonarchy-static", tonarchy_src);
-
- struct stat st;
- if (stat(binary_path, &st) != 0) {
- LOG_ERROR("tonarchy-static binary not found at %s", binary_path);
- return 0;
- }
-
- LOG_INFO("Built tonarchy-static successfully");
- return 1;
-}
-
-int clean_airootfs(const char *iso_profile) {
- LOG_INFO("Cleaning airootfs...");
-
- char cmd[512];
-
- snprintf(cmd, sizeof(cmd), "sudo rm -rf '%s/airootfs/usr'", iso_profile);
- if (!run_command(cmd)) {
- LOG_WARN("Failed to clean airootfs/usr");
- }
-
- snprintf(cmd, sizeof(cmd), "sudo rm -rf '%s/airootfs/root/tonarchy'", iso_profile);
- if (!run_command(cmd)) {
- LOG_WARN("Failed to clean airootfs/root/tonarchy");
- }
-
- return 1;
-}
-
-int clean_work_dir(const char *work_dir) {
- LOG_INFO("Cleaning work directory...");
-
- char cmd[512];
-
- snprintf(cmd, sizeof(cmd), "sudo umount -R '%s' 2>/dev/null || true", work_dir);
- run_command(cmd);
-
- snprintf(cmd, sizeof(cmd), "sudo rm -rf '%s'", work_dir);
- if (!run_command(cmd)) {
- LOG_ERROR("Failed to remove work directory: %s", work_dir);
- return 0;
- }
-
- sync();
- sleep(1);
-
- return 1;
-}
-
-int prepare_airootfs(const char *iso_profile, const char *tonarchy_src) {
- LOG_INFO("Preparing airootfs...");
-
- char cmd[1024];
- char src_path[512];
- char dest_path[512];
-
- snprintf(cmd, sizeof(cmd), "mkdir -p '%s/airootfs/usr/local/bin'", iso_profile);
- if (!run_command(cmd)) {
- LOG_ERROR("Failed to create airootfs/usr/local/bin");
- return 0;
- }
-
- snprintf(cmd, sizeof(cmd), "mkdir -p '%s/airootfs/usr/share'", iso_profile);
- if (!run_command(cmd)) {
- LOG_ERROR("Failed to create airootfs/usr/share");
- return 0;
- }
-
- snprintf(src_path, sizeof(src_path), "%s/tonarchy-static", tonarchy_src);
- snprintf(dest_path, sizeof(dest_path), "%s/airootfs/usr/local/bin/tonarchy", iso_profile);
- snprintf(cmd, sizeof(cmd), "cp '%s' '%s'", src_path, dest_path);
- if (!run_command(cmd)) {
- LOG_ERROR("Failed to copy tonarchy binary");
- return 0;
- }
-
- snprintf(cmd, sizeof(cmd), "chmod 755 '%s'", dest_path);
- if (!run_command(cmd)) {
- LOG_ERROR("Failed to set permissions on tonarchy binary");
- return 0;
- }
-
- snprintf(src_path, sizeof(src_path), "%s/assets", tonarchy_src);
- snprintf(dest_path, sizeof(dest_path), "%s/airootfs/usr/share/tonarchy", iso_profile);
- snprintf(cmd, sizeof(cmd), "cp -r '%s'/* '%s'", src_path, dest_path);
- if (!run_command(cmd)) {
- LOG_ERROR("Failed to copy tonarchy config files");
- return 0;
- }
-
- snprintf(dest_path, sizeof(dest_path), "%s/airootfs/usr/share/wallpapers", iso_profile);
- snprintf(cmd, sizeof(cmd), "cp -r '%s/wallpapers' '%s'", src_path, dest_path);
- if (!run_command(cmd)) {
- LOG_WARN("Failed to copy wallpapers");
- }
-
- LOG_INFO("Setting proper ownership for airootfs...");
- snprintf(cmd, sizeof(cmd), "sudo chown -R root:root '%s/airootfs/usr'", iso_profile);
- if (!run_command(cmd)) {
- LOG_ERROR("Failed to set ownership on airootfs");
- return 0;
- }
-
- return 1;
-}
-
-int run_mkarchiso(const char *iso_profile, const char *work_dir, const char *out_dir) {
- LOG_INFO("Building ISO with mkarchiso...");
-
- if (!create_directory(out_dir, 0755)) {
- return 0;
- }
-
- if (!create_directory(work_dir, 0755)) {
- return 0;
- }
-
- char cmd[1024];
- snprintf(cmd, sizeof(cmd), "sudo mkarchiso -v -w '%s' -o '%s' '%s'", work_dir, out_dir, iso_profile);
-
- if (!run_command(cmd)) {
- LOG_ERROR("mkarchiso failed");
- return 0;
- }
-
- return 1;
-}
-
-const char* find_latest_iso(const char *out_dir) {
- static char iso_path[512];
- char cmd[1024];
-
- snprintf(cmd, sizeof(cmd), "ls -t '%s'/*.iso 2>/dev/null | head -n1", out_dir);
-
- FILE *fp = popen(cmd, "r");
- if (!fp) {
- return NULL;
- }
-
- if (fgets(iso_path, sizeof(iso_path), fp) != NULL) {
- iso_path[strcspn(iso_path, "\n")] = 0;
- pclose(fp);
- return iso_path;
- }
-
- pclose(fp);
- return NULL;
-}
-
-int main(int argc, char *argv[]) {
- logger_init("/tmp/tonarchy-mkiso.log");
-
- LOG_INFO("Tonarchy ISO Builder starting...");
-
- char tonarchy_src[512];
- char iso_profile[512];
- char out_dir[512];
- const char *work_dir = "/tmp/tonarchy_iso_work";
-
- const char *custom_iso_profile = NULL;
- const char *custom_out_dir = NULL;
-
- for (int i = 1; i < argc; i++) {
- if (strcmp(argv[i], "--iso-profile") == 0 && i + 1 < argc) {
- custom_iso_profile = argv[++i];
- } else if (strcmp(argv[i], "--out-dir") == 0 && i + 1 < argc) {
- custom_out_dir = argv[++i];
- } else if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) {
- printf("Usage: %s [OPTIONS]\n", argv[0]);
- printf("\nOptions:\n");
- printf(" --iso-profile PATH Path to ISO profile directory (default: ./iso)\n");
- printf(" --out-dir PATH Output directory for ISO (default: ./out)\n");
- printf(" -h, --help Show this help message\n");
- return 0;
- }
- }
-
- if (getcwd(tonarchy_src, sizeof(tonarchy_src)) == NULL) {
- LOG_ERROR("Failed to get current directory");
- return 1;
- }
-
- if (custom_iso_profile) {
- snprintf(iso_profile, sizeof(iso_profile), "%s", custom_iso_profile);
- } else {
- snprintf(iso_profile, sizeof(iso_profile), "%s/iso", tonarchy_src);
- }
-
- if (custom_out_dir) {
- snprintf(out_dir, sizeof(out_dir), "%s", custom_out_dir);
- } else {
- snprintf(out_dir, sizeof(out_dir), "%s/out", tonarchy_src);
- }
-
- LOG_INFO("Tonarchy source: %s", tonarchy_src);
- LOG_INFO("ISO profile: %s", iso_profile);
- LOG_INFO("Work directory: %s", work_dir);
- LOG_INFO("Output directory: %s", out_dir);
-
- if (!build_tonarchy_static(tonarchy_src)) {
- LOG_ERROR("Build failed");
- logger_close();
- return 1;
- }
-
- if (!clean_airootfs(iso_profile)) {
- LOG_ERROR("Failed to clean airootfs");
- logger_close();
- return 1;
- }
-
- if (!clean_work_dir(work_dir)) {
- LOG_ERROR("Failed to clean work directory");
- logger_close();
- return 1;
- }
-
- if (!prepare_airootfs(iso_profile, tonarchy_src)) {
- LOG_ERROR("Failed to prepare airootfs");
- logger_close();
- return 1;
- }
-
- if (!run_mkarchiso(iso_profile, work_dir, out_dir)) {
- LOG_ERROR("Failed to build ISO");
- logger_close();
- return 1;
- }
-
- if (!clean_work_dir(work_dir)) {
- LOG_WARN("Failed to clean work directory after build");
- }
-
- LOG_INFO("Syncing filesystem...");
- sync();
- sleep(2);
-
- const char *iso_path = find_latest_iso(out_dir);
- if (iso_path) {
- LOG_INFO("===================================");
- LOG_INFO("ISO created successfully!");
- LOG_INFO("Location: %s", iso_path);
- LOG_INFO("Test with: make test");
- LOG_INFO("===================================");
- } else {
- LOG_ERROR("ISO was built but could not be found in output directory");
- logger_close();
- return 1;
- }
-
- logger_close();
- return 0;
-}