logo

live-bootstrap

Mirror of <https://github.com/fosslinux/live-bootstrap>
commit: e1cc51964f3c4bcfe7a7eb40d0e6b0b808f128d8
parent c37486d428a84915ff852f88a8ab6017db26fc85
Author: fosslinux <fosslinux@aussies.space>
Date:   Wed, 29 May 2024 08:51:34 +1000

Merge pull request #468 from fosslinux/configurator

Add interactive "configurator"

Diffstat:

Mrootfs.py4++++
Aseed/configurator.c784+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aseed/configurator.x86.checksums1+
Mseed/script-generator.c26++------------------------
Mseed/script-generator.x86.checksums2+-
Mseed/seed.kaem10++++++++++
Msteps/SHA256SUMS.pkgs2+-
Msteps/checksum-transcriber-1.0/checksum-transcriber-1.0.x86.checksums2+-
Asteps/configurator81+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asteps/improve/reconfigure.sh6++++++
Msteps/jump/fiwix.sh9++++++---
Msteps/jump/linux.sh2+-
Msteps/linux-4.14.341-openela/files/config4++--
Msteps/manifest1+
Msteps/simple-patch-1.0/simple-patch-1.0.x86.checksums2+-
15 files changed, 902 insertions(+), 34 deletions(-)

diff --git a/rootfs.py b/rootfs.py @@ -49,6 +49,7 @@ def create_configuration_file(args): config.write("DISK=sda1\n") config.write("KERNEL_BOOTSTRAP=False\n") config.write(f"BUILD_KERNELS={args.update_checksums or args.build_kernels}\n") + config.write(f"CONFIGURATOR={args.configurator}\n") # pylint: disable=too-many-statements,too-many-branches def main(): @@ -90,6 +91,9 @@ def main(): parser.add_argument("-i", "--interactive", help="Use interactive prompts to resolve issues during bootstrap", action="store_true") + parser.add_argument("--configurator", + help="Run the interactive configurator", + action="store_true") parser.add_argument("-r", "--repo", help="Path to prebuilt binary packages", nargs=None) parser.add_argument("--early-preseed", diff --git a/seed/configurator.c b/seed/configurator.c @@ -0,0 +1,784 @@ +/* + * SPDX-FileCopyrightText: 2024 fosslinux <fosslinux@aussies.space> + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#define MAX_STRING 2048 +#define MAX_SHORT 512 +#define MAX_ID 128 +#define MAX_VAR 128 + +#include <bootstrappable.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/utsname.h> + +#define TRUE 1 +#define FALSE 0 + +#define KIND_NONE 0 +#define KIND_MENU 1 +#define KIND_OPTION 2 + +#define TYPE_NONE 0 +#define TYPE_BOOL 1 +#define TYPE_SIZE 2 +#define TYPE_STRING 3 +#define TYPE_INT 4 + +struct Entry { + int kind; // either menu or option + char *env_var; // name of the environment variable this option is stored in + char *id; // the id of the configuration item + char *short_desc; // short description of the config + char *full_desc; // extended description of the config + + int type; // the type of the configuration option + char *validation; // any validation rules + char *val; + char *default_val; + + struct Entry *children; // submenus + struct Entry *parent; + struct Entry *next; +}; +typedef struct Entry Entry; + +Entry *find_entry(Entry *head, char *id) { + char *component = strchr(id, '/'); + if (component == NULL) { + component = id + strlen(id); + } + + Entry *current; + Entry *final; + int len; + while (1) { + len = component - id; + + current = head; + while (current != NULL) { + /* ensure that the id isn't just a substring of the component but actually is the component */ + if (strlen(current->id) == len && strncmp(id, current->id, len) == 0) { + /* Found it! */ + final = current; + head = current->children; + break; + } + current = current->next; + } + if (current == NULL) { + /* Did not find it */ + return NULL; + } + + if (component[0] == '\0') { + break; + } + + component += 1; + component = strchr(component, '/'); + if (component == NULL) { + component = id + strlen(id); + } + } + + return final; +} + +Entry *get_parent(Entry *head, char *id) { + char *parent_id = calloc(MAX_ID, sizeof(char)); + strcpy(parent_id, id); + char *final_slash = strrchr(parent_id, '/'); + final_slash[0] = '\0'; + Entry *ret = find_entry(head, parent_id); + free(parent_id); + return ret; +} + +char read_string(FILE *f, char *out, int length) { + int i = 0; + char c = fgetc(f); + while (c != ' ' && c != '\n' && c != EOF && i < length - 1) { + out[i] = c; + i += 1; + c = fgetc(f); + } + if (i >= length - 1) { + fputs("String too long!\n", stdout); + fclose(f); + exit(1); + } + out[i] = '\0'; + return c; +} + +int set_val(Entry *entry, char *val) { + if (entry->type == TYPE_BOOL) { + if (strcmp(val, "True") != 0 && strcmp(val, "False") != 0) { + fputs("Invalid input: ", stdout); + fputs(val, stdout); + fputs(" is not a boolean value\n", stdout); + return 1; + } + } else if (entry->type == TYPE_INT) { + int intval = strtoint(val); + if (intval == 0 && strcmp(val, "0") != 0) { + fputs("Invalid input: ", stdout); + fputs(val, stdout); + fputs(" is not an integer\n", stdout); + return 1; + } + } else if (entry->type == TYPE_SIZE) { + /* We should have either a K, M, G, T, or no letter, at the end of the size. */ + char c = val[strlen(val) - 1]; + if (!(('0' <= c && c <= '9') || c == 'K' || c == 'M' || c == 'G' || c == 'T')) { + fputs("Invalid input: ", stdout); + fputc(c, stdout); + fputs(" is not a valid suffix for a size\n", stdout); + return 1; + } + /* Check it is an integer */ + char *final_char = val + strlen(val) - 1; + if ('A' <= final_char[0] && final_char[0] <= 'Z') { + final_char[0] = '\0'; + } + int intval = strtoint(val); + if (intval == 0 && strcmp(val, "0") != 0) { + fputs("Invalid input: ", stdout); + fputs(val, stdout); + fputs(" is not a valid size\n", stdout); + return 1; + } + final_char[0] = c; + } else if (entry->type == TYPE_STRING) { + /* Validation rules. */ + char *validation = entry->validation; + char *next; + int found = FALSE; + while (validation != NULL) { + if (validation[0] == '\0') { + found = TRUE; + break; + } + next = strchr(validation, '|'); + if (next == NULL) { + if (strcmp(validation, val) == 0) { + found = TRUE; + } + break; + } else { + if (strncmp(validation, val, next - validation) == 0) { + found = TRUE; + } + } + validation = next + 1; + } + if (found == FALSE) { + fputs("Invalid input: ", stdout); + fputs(val, stdout); + fputs(" does not match the validation rules ", stdout); + fputs(entry->validation, stdout); + fputc('\n', stdout); + return 1; + } + } + + entry->val = calloc(strlen(val) + 1, sizeof(char)); + strcpy(entry->val, val); + return 0; +} + +void read_entry(char c, FILE *conf, Entry *head) { + Entry *new = calloc(1, sizeof(Entry)); + + /* Read the kind */ + if (c == 'm') { + new->kind = KIND_MENU; + } else if (c == 'o') { + new->kind = KIND_OPTION; + } else { + fputs("Invalid entry: kind ", stdout); + fputc(c, stdout); + fputc('\n', stdout); + fclose(conf); + exit(1); + } + fgetc(conf); + + /* Read the id */ + new->id = calloc(MAX_ID, sizeof(char)); + c = read_string(conf, new->id, MAX_ID); + if (c != ' ') { + fputs("Invalid entry: no variable\n", stdout); + fclose(conf); + exit(1); + } + + /* Read the environment variable */ + new->env_var = calloc(MAX_VAR, sizeof(char)); + c = read_string(conf, new->env_var, MAX_VAR); + if (c != ' ') { + fputs("Invalid entry: no data type\n", stdout); + fclose(conf); + exit(1); + } + if (strcmp(new->env_var, "_") == 0) { + free(new->env_var); + new->env_var = NULL; + } + + /* Read the data type */ + char *data_type = calloc(MAX_ID, sizeof(char)); + read_string(conf, data_type, MAX_ID); + if (c != ' ') { + fputs("Invalid entry: no default value\n", stdout); + fclose(conf); + exit(1); + } + if (strcmp(data_type, "_") == 0) { + new->type = TYPE_NONE; + } else if (strcmp(data_type, "bool") == 0) { + new->type = TYPE_BOOL; + } else if (strcmp(data_type, "size") == 0) { + new->type = TYPE_SIZE; + } else if (strcmp(data_type, "int") == 0) { + new->type = TYPE_INT; + } else if (data_type[0] == '"') { + new->type = TYPE_STRING; + new->validation = data_type + 1; + char *closing_quote = strrchr(data_type, '"'); + closing_quote[0] = '\0'; + } else { + fputs("Invalid entry: unknown type: ", stdout); + fputs(data_type, stdout); + fputc('\n', stdout); + fclose(conf); + exit(1); + } + if (new->type != TYPE_STRING) { + free(data_type); + } + + /* Read the default value */ + char *default_val = calloc(MAX_STRING, sizeof(char)); + read_string(conf, default_val, MAX_ID); + if (strcmp(default_val, "_") != 0) { + set_val(new, default_val); + new->default_val = default_val; + } else { + new->default_val = NULL; + } + + /* Read the short description */ + new->short_desc = calloc(MAX_SHORT, sizeof(char)); + int i = 0; + c = fgetc(conf); + while (c != '\n' && c != EOF) { + new->short_desc[i] = c; + c = fgetc(conf); + i += 1; + } + + /* Read the long description */ + new->full_desc = calloc(MAX_STRING, sizeof(char)); + i = 0; + c = fgetc(conf); + char prev = '\0'; + while (!(c == '\n' && prev == '\n') && c != EOF) { + new->full_desc[i] = c; + prev = c; + c = fgetc(conf); + i += 1; + } + + new->children = NULL; + new->next = NULL; + + Entry *parent = get_parent(head, new->id); + new->parent = parent; + if (parent->children == NULL) { + parent->children = new; + } else { + Entry *current = parent->children; + while (current->next != NULL) { + current = current->next; + } + current->next = new; + } +} + +Entry *read_config(char *filename) { + FILE *conf = fopen(filename, "r"); + if (conf == NULL) { + fputs("Unable to open ", stdout); + fputs(filename, stdout); + fputc('\n', stdout); + exit(0); + } + char c = fgetc(conf); + + Entry *head = calloc(1, sizeof(Entry)); + head->id = ""; + head->env_var = ""; + head->next = NULL; + Entry *current = head; + + while (c != EOF) { + if (c == '#' || c == '\n') { + /* Skip comments or empty lines. */ + while (c != '\n' && c != EOF) { + c = fgetc(conf); + } + } else { + read_entry(c, conf, head); + } + c = fgetc(conf); + } + + fclose(conf); + + return head; +} + +Entry *get_env_var(Entry *head, char *var) { + Entry *ret; + Entry *current; + for (current = head->children; current != NULL; current = current->next) { + if (current->env_var != NULL) { + if (strcmp(current->env_var, var) == 0) { + return current; + } + } + if (current->children != NULL) { + ret = get_env_var(current, var); + if (ret != NULL) { + return ret; + } + } + } + return NULL; +} + +int set_cfg_varline(Entry *head, char *line) { + char *var = calloc(strlen(line) + 1, sizeof(char)); + strcpy(var, line); + char *val = strchr(var, '='); + val[0] = '\0'; + val += 1; + char *newline = strchr(val, '\n'); + if (newline != NULL) { + newline[0] = '\0'; + } + Entry *entry = get_env_var(head, var); + if (entry != NULL) { + int not_ok = set_val(entry, val); + if (not_ok) { + fputs("^ Originated from ", stdout); + fputs(var, stdout); + fputs("=", stdout); + fputs(val, stdout); + fputs("\n", stdout); + } + } + return entry == NULL; +} + +char *set_cfg_values(Entry *head, char **envp) { + int i = 0; + + FILE *cfg = fopen("/steps/bootstrap.cfg", "r"); + if (cfg == NULL) { + return ""; + } + + char *extra = calloc(MAX_STRING, sizeof(char)); + char *line = calloc(MAX_STRING, sizeof(char)); + while (fgets(line, MAX_STRING, cfg) != NULL) { + if (set_cfg_varline(head, line)) { + if (strncmp("CONFIGURATOR=", line, 13) != 0) { + strcat(extra, line); + } + } + free(line); + line = calloc(MAX_STRING, sizeof(char)); + } + + fclose(cfg); + + return extra; +} + +void write_cfg_list(Entry *head, FILE *cfg) { + Entry *current; + for (current = head->children; current != NULL; current = current->next) { + if (current->kind == KIND_OPTION && current->val != NULL) { + fputs(current->env_var, cfg); + fputs("=", cfg); + fputs(current->val, cfg); + fputs("\n", cfg); + } + if (current->children != NULL) { + write_cfg_list(current, cfg); + } + } +} + +void write_cfg_values(Entry *head, char *extra, int configurator_done) { + FILE *cfg = fopen("/steps/bootstrap.cfg", "w"); + if (cfg == NULL) { + fputs("Unable to open /steps/bootstrap.cfg", stderr); + exit(1); + } + if (configurator_done == TRUE) { + fputs("CONFIGURATOR=False\n", cfg); + } + fputs(extra, cfg); + write_cfg_list(head, cfg); + fclose(cfg); +} + +void print_short_desc(char *short_desc) { + char *post_markers = strrchr(short_desc, ']'); + if (post_markers == NULL) { + post_markers = short_desc; + } else { + post_markers += 1; + while (post_markers[0] == ' ') { + post_markers += 1; + } + } + fputs(post_markers, stdout); +} + +void print_recursive_desc(Entry *entry) { + if (entry->parent != NULL) { + if (strcmp(entry->parent->id, "") != 0) { + print_recursive_desc(entry->parent); + fputs("/", stdout); + print_short_desc(entry->short_desc); + return; + } + } + print_short_desc(entry->short_desc); +} + +int any_unset(Entry *head); + +int check_set(Entry *entry, Entry *head) { + int ret = 0; + if (entry->kind == KIND_OPTION && entry->val == NULL) { + fputs("The configuration option ", stdout); + print_recursive_desc(entry); + fputs(" is unset\n", stdout); + ret = 1; + } + if (entry->children != NULL) { + ret |= any_unset(entry); + } + return ret; +} + +int any_unset(Entry *head) { + int ret = 0; + Entry *current; + for (current = head->children; current != NULL; current = current->next) { + ret |= check_set(current, head); + } + return ret; +} + +void print_menu(Entry *menu, int is_toplevel) { + if (!is_toplevel) { + fputs("(0) [MENU] Go up\n", stdout); + } + int i = 1; + Entry *current; + for (current = menu->children; current != NULL; current = current->next) { + fputs("(", stdout); + fputs(int2str(i, 10, FALSE), stdout); + fputs(") ", stdout); + if (current->kind == KIND_MENU) { + fputs("[MENU] ", stdout); + } + fputs(current->short_desc, stdout); + fputc('\n', stdout); + i += 1; + } +} + +Entry *get_nth_option(Entry *menu, int n) { + int i = 1; + Entry *current; + for (current = menu->children; current != NULL && i < n; current = current->next) { + i += 1; + } + if (current == NULL) { + fputs("There is no option ", stdout); + fputs(int2str(n, 10, FALSE), stdout); + fputs("!\n", stdout); + } + return current; +} + +void how_to_use(void) { + fputs( + "How to navigate around this configuration menu:\n" + "h or help: at any time, will reprint this help message\n" + "l or list: shows the current menu options\n" + "o <num> or open <num>: open a (sub)menu\n" + "? <num> or describe <num>: provides a more detailed description of an option or menu\n" + "s <num> <val> or set <num> <val>: set the value of an option\n" + "g <num> or get <num>: get the value of an option\n" + "g all or get all: get the value of all options in the menu\n" + "r <num> or reset <num>: reset the value of an option to the default (if there is one)\n" + "e or exit: exits the program\n", + stdout); +} + +Entry *extract_num(char **command, Entry *menu) { + command[0] = strchr(command[0], ' '); + if (command[0] == NULL) { + fputs("Expected menu number to operate on!\n", stdout); + } + command[0] += 1; + char *num = command[0]; + char *new = strchr(command[0], ' '); + if (new == NULL) { + new = strchr(command[0], '\n'); + } + command[0] = new; + command[0][0] = '\0'; + command[0] += 1; + /* strtoint does not check if it is not a number */ + int i; + for (i = 0; i < strlen(num); i += 1) { + if (!('0' <= num[i] && num[i] <= '9')) { + fputs(num, stdout); + fputs(" is not a menu number!\n", stdout); + return NULL; + } + } + int n = strtoint(num); + return get_nth_option(menu, n); +} + +Entry *submenu(char *command, Entry *menu, Entry *head) { + command = strchr(command, ' '); + if (strlen(command) < 1) { + fputs("Expected menu number to operate on!\n", stdout); + } + /* 0 is the "go up" menu option */ + if (command[1] == '0') { + if (strcmp(menu->id, "") == 0) { + fputs("There is no option 0!\n", stdout); + return menu; + } + return menu->parent; + } + + Entry *new = extract_num(&command, menu); + if (new == NULL) { + return menu; + } + if (new->kind != KIND_MENU) { + fputs("This is not a menu!\n", stdout); + return menu; + } + return new; +} + +void print_description(char *command, Entry *menu) { + Entry *opt = extract_num(&command, menu); + if (opt != NULL) { + fputs(opt->full_desc, stdout); + } +} + +void set_opt_value(char *command, Entry *menu) { + Entry *opt = extract_num(&command, menu); + if (opt == NULL) { + return; + } + if (opt->kind != KIND_OPTION) { + fputs("Cannot set a menu's value!\n", stdout); + return; + } + + /* Remove the newline */ + char *newline = strchr(command, '\n'); + newline[0] = '\0'; + set_val(opt, command); +} + +void print_opt_value(Entry *opt) { + print_short_desc(opt->short_desc); + + fputs(": ", stdout); + if (opt->val == NULL) { + fputs("unset", stdout); + } else { + fputs(opt->val, stdout); + } + fputc('\n', stdout); +} + +void get_opt_value(char *command, Entry *menu) { + Entry *opt = extract_num(&command, menu); + if (opt == NULL) { + return; + } + if (opt->kind != KIND_OPTION) { + fputs("Cannot get a menu's value!\n", stdout); + return; + } + + print_opt_value(opt); +} + +void get_all_values(Entry *menu) { + Entry *current; + for (current = menu->children; current != NULL; current = current->next) { + if (current->kind == KIND_OPTION) { + print_opt_value(current); + } + } +} + +void reset_value(char *command, Entry *menu) { + Entry *opt = extract_num(&command, menu); + if (opt == NULL) { + return; + } + if (opt->kind != KIND_OPTION) { + fputs("Cannot reset a menu's value!\n", stdout); + return; + } + opt->val = opt->default_val; +} + +void no_input(Entry *head) { + fputs("You don't seem to be running under Fiwix or Linux currently.\n", stdout); + fputs("Likely, you are currently running under builder-hex0.\n", stdout); + fputs("That's ok! We're going to make some assumptions; namely, that you do need\n", stdout); + fputs("the kernel bootstrap, and that you'll get a chance to configure later.\n", stdout); + write_cfg_values(head, "KERNEL_BOOTSTRAP=True\nBUILD_KERNELS=True\n", FALSE); +} + +int main(int argc, char **argv, char **envp) { + /* + * Check we are being non-interactive and bootstrap.cfg exists in + * which case we do not need to do anything. + */ + char *interactivity = getenv("CONFIGURATOR"); + if (interactivity != NULL) { + if (strcmp(interactivity, "False") == 0) { + return 0; + } + } + FILE *bootstrap_cfg = fopen("/steps/bootstrap.cfg", "r"); + if (bootstrap_cfg != NULL) { + char *line = calloc(MAX_STRING, sizeof(char)); + while (fgets(line, MAX_STRING, bootstrap_cfg) != NULL) { + if (strcmp(line, "CONFIGURATOR=False\n") == 0) { + fclose(bootstrap_cfg); + return 0; + } + free(line); + line = calloc(MAX_STRING, sizeof(char)); + } + fclose(bootstrap_cfg); + } + + if (argc != 2) { + fputs("Usage: ", stdout); + fputs(argv[0], stdout); + fputs(" <configuration>\n", stdout); + exit(1); + } + Entry *head = read_config(argv[1]); + char *extra = set_cfg_values(head, envp); + + /* + * Check if we are NOT running under fiwix or linux. + * If we are not, and need configuration to occur, then we presume that + * we will not be able to get any input from the user. + */ + struct utsname *kernel = calloc(1, sizeof(struct utsname)); + uname(kernel); + if (kernel->sysname == NULL) { + no_input(head); + return 0; + } else if (strcmp(kernel->sysname, "Linux") != 0 && strcmp(kernel->sysname, "Fiwix") != 0) { + no_input(head); + return 0; + } + + fputs("Welcome to live-bootstrap!\n", stdout); + fputs("We need to do some brief configuration before continuing.\n\n", stdout); + how_to_use(); + fputc('\n', stdout); + + Entry *menu = head; + print_menu(menu, menu == head); + char *command = calloc(MAX_STRING, sizeof(char)); + fputs("\nCommand: ", stdout); + fflush(stdout); + command = fgets(command, MAX_STRING, stdin); + while (command != NULL) { + if (strcmp("h\n", command) == 0 || strcmp("help\n", command) == 0) { + how_to_use(); + } else if (strcmp("l\n", command) == 0 || strcmp("list\n", command) == 0) { + print_menu(menu, menu == head); + } else if (strncmp("o ", command, 2) == 0 || strncmp("open ", command, 5) == 0) { + menu = submenu(command, menu, head); + print_menu(menu, menu == head); + } else if (strncmp("? ", command, 2) == 0 || strncmp("describe ", command, 9) == 0) { + print_description(command, menu); + } else if (strcmp("g all\n", command) == 0 || strcmp("get all\n", command) == 0) { + get_all_values(menu); + } else if (strncmp("g ", command, 2) == 0 || strncmp("get ", command, 4) == 0) { + get_opt_value(command, menu); + } else if (strncmp("s ", command, 2) == 0 || strncmp("set ", command, 4) == 0) { + set_opt_value(command, menu); + } else if (strncmp("r ", command, 2) == 0 || strncmp("reset ", command, 6) == 0) { + reset_value(command, menu); + } else if (strcmp("e\n", command) == 0 || strcmp("exit\n", command) == 0) { + if (!any_unset(head)) { + break; + } + } else { + fputs("Unknown command ", stdout); + fputs(command, stdout); + } + fputs("\nCommand: ", stdout); + fflush(stdout); + /* + * M2-Planet's fgets does not properly terminate the buffer if there is + * already data in it + */ + free(command); + command = calloc(MAX_STRING, sizeof(char)); + command = fgets(command, MAX_STRING, stdin); + } + + if (any_unset(head)) { + fputs( + "Uh oh! You have left me in a tough position - you can't input further because you\n" + "closed the input stream. But the inputs you gave me are not valid!\n" + "I'm going to re-exec myself and hope you are able to start again from scratch.\n", + stderr + ); + execve(argv[0], argv, envp); + return 0; + } + + write_cfg_values(head, extra, TRUE); + + fputs("\nThank you! We will now continue with the bootstrap.\n", stdout); + + return 0; +} diff --git a/seed/configurator.x86.checksums b/seed/configurator.x86.checksums @@ -0,0 +1 @@ +8235581c60334314b5a8321b0b07d6fb905669dce81878c8cfed909377573e91 configurator diff --git a/seed/script-generator.c b/seed/script-generator.c @@ -176,30 +176,8 @@ char *get_var(char *name) { last = var; } - /* If the variable is unset, prompt the user. */ - if (variables == NULL) { - variables = calloc(1, sizeof(Variable)); - var = variables; - } else { - last->next = calloc(1, sizeof(Variable)); - var = last->next; - } - var->name = calloc(strlen(name) + 1, sizeof(char)); - strcpy(var->name, name); - var->val = calloc(MAX_STRING, sizeof(char)); - fputs("You have not set a value for ", stdout); - fputs(name, stdout); - fputs(" in bootstrap.cfg. Please set it now:\n", stdout); - while (fgets(var->val, MAX_STRING, stdin) == 0 || var->val[0] == '\n') { - fputs("Error inputting, try again:\n", stdout); - } - if (var->val[0] == 0) { - fputs("You put in an EOF!\n", stderr); - exit(1); - } - /* Trim the newline. */ - var->val[strlen(var->val)] = 0; - return var->val; + /* If the variable is unset, take it to be the empty string. */ + return ""; } /* Recursive descent interpreter. */ diff --git a/seed/script-generator.x86.checksums b/seed/script-generator.x86.checksums @@ -1 +1 @@ -dc6106dbc02839cdc9e3e2348432242eb6d33d840ab74badfd63c3c9997462b9 script-generator +a0ad0938f7a66b44674db2b0a2a0410966098b3cc511d8b1a4dadc77b1828088 script-generator diff --git a/seed/seed.kaem b/seed/seed.kaem @@ -64,6 +64,15 @@ MES_PKG=mes-0.26 MES_PREFIX=${SRCDIR}/${MES_PKG}/build/${MES_PKG} GUILE_LOAD_PATH=${MES_PREFIX}/mes/module:${MES_PREFIX}/module:${SRCDIR}/${MES_PKG}/build/${NYACC_PKG}/module +M2-Mesoplanet --architecture ${ARCH} -f configurator.c -o configurator +# Checksums +if match x${UPDATE_CHECKSUMS} xTrue; then + sha256sum -o configurator.${ARCH}.checksums configurator +else + sha256sum -c configurator.${ARCH}.checksums +fi +./configurator /steps/configurator + M2-Mesoplanet --architecture ${ARCH} -f script-generator.c -o script-generator # Checksums if match x${UPDATE_CHECKSUMS} xTrue; then @@ -72,4 +81,5 @@ else sha256sum -c script-generator.${ARCH}.checksums fi ./script-generator /steps/manifest + kaem --file /steps/0.sh diff --git a/steps/SHA256SUMS.pkgs b/steps/SHA256SUMS.pkgs @@ -77,7 +77,7 @@ b39826742e236890f3562cdf19492e7ef4224b271f3e75ddeab1f07982b03ebe libffi-3.3_0.t daae709e98d2df2190d1d13b4e86f7f3fe90fa7a975282fe0bb03289b6539f29 libtool-2.2.4_0.tar.bz2 6cefa575362149620f8008a32c8af54f0198a18bc6ab910bd3cead196c1507d7 libtool-2.4.7_0.tar.bz2 503007bbcddcf4e49d26514c59b4c9501f8b42f0c994a59dfdc388b1ae6b7900 libunistring-0.9.10_0.tar.bz2 -5787f84a49e1d22560d0398e4f9075d6021017eb2a757697dc2877e7565d0199 linux-4.14.341-openela_0.tar.bz2 +540927c71fb1682175e32a655dfd4a987c494577549bf30e79ef3b1e4f039a4d linux-4.14.341-openela_0.tar.bz2 c97644d0db5b3de127b048683afee6d31453441d97ba5dea71df5838b13542a4 linux-headers-4.14.341-openela_0.tar.bz2 78b0cf6d9312e53c613186cbddd5f747310f375c1f322f33a6ac33682d2f3389 m4-1.4.19_0.tar.bz2 0e3c21b0a1d8ca0c3f74a98ebe268809def62778ff4a486ff20c1d6e8247dc49 m4-1.4.7_0.tar.bz2 diff --git a/steps/checksum-transcriber-1.0/checksum-transcriber-1.0.x86.checksums b/steps/checksum-transcriber-1.0/checksum-transcriber-1.0.x86.checksums @@ -1 +1 @@ -19fd50d727e8a7feba8b6e369e68287d1922d8f623a156fb113d994891e96998 /usr/bin/checksum-transcriber +59cc0fb361f84e81a1cda6111ef847188d6c7c839c5a52166d9185ca767cf920 /usr/bin/checksum-transcriber diff --git a/steps/configurator b/steps/configurator @@ -0,0 +1,81 @@ +# SPDX-FileCopyrightText: 2024 fosslinux <fosslinux@aussies.space> +# +# SPDX-License-Identifier: GPL-3.0-or-later +# +# The structure of this file: +# <option type> <id> <variable> <type> <default> <short description> +# <long description> +# +# repeat + +m /general _ _ _ General configuration +Settings for how you would like live-bootstrap to run. + +o /general/timestamps FORCE_TIMESTAMPS bool False Zero timestamps at end +At the end of the bootstrap, set the timestamps of all files to 0 UNIX time. + +o /general/swap SWAP_SIZE size 0 Swap size +The size of a swapfile to be created once swap is supported in live-bootsrap. +Intended for systems with low RAM. + +o /general/kernel_bootstrap KERNEL_BOOTSTRAP bool True Use the kernel bootstrap +This only applies if you are not in a chroot-like environment. You should +already know whether you want this flag or not. If you booted using +builder-hex0, this flag should be true; if you booted using your own Linux +kernel, this flag should be false. + +o /general/interactive INTERACTIVE bool True Drop to a shell post-bootstrap +At the end of the bootstrap, drop to a shell which you can do further things +in. + +o /general/disk DISK "" _ [IMPORTANT] [DANGER] Disk +live-bootstrap needs a disk which the final system will be installed onto. +This should be in the form of the name of the device node, eg sda. If you +have externally downloaded sources or the like, place in here the device +node with the appropriate partition, eg sda1. +Disclaimer for bare metal users: +It is highly recommended that all disks other than this disk are removed +from the system to avoid accidental data loss. It is vital that you choose +this correctly, otherwise you risk overwriting an existing disk on your +system. LIVE-BOOTSTRAP TAKES NO LIABILITY FOR ANY DATA LOSS RESULTING FROM +ITS USE. + +m /sysinfo _ _ _ System information +Details about your specific system and the environment live-bootstrap is +running in. + +o /sysinfo/chroot CHROOT bool False Chroot-like environment +Only set to True if live-bootstrap is running in a chroot-like environment. +This might be in a chroot, on bubblewrap, or similar. QEMU is not a +chroot-like environment. + +o /sysinfo/baremetal BARE_METAL bool False Bare metal environment +Only set to True if live-bootstrap is running directly on bare metal, without +another kernel or virtualisation layer in between. A chroot, bubblewrap, or +QEMU is not bare metal. + +o /sysinfo/jobs FINAL_JOBS int _ Number of jobs +The number of jobs that packages should be compiled with. A sensible value +would be the number of threads on your system. + +o /sysinfo/arch ARCH "x86|amd64|riscv64" _ Architecture +The architecture live-bootstrap is running on. + +m /sysinfo/internal _ _ _ [INTERNAL] Advanced configuration +Internal configuration. You should not touch this unless you know what you +are doing! + +o /sysinfo/internal/ci INTERNAL_CI bool False Internal CI +If you are seeing this, it should not be set to true. (Flag for live-bootstrap +CI). + +m /dev _ _ _ [DEV] Development options +Options intended for primarily live-bootstrap development or debugging. + +o /dev/update_checksums UPDATE_CHECKSUMS bool False [DEV] Update checksums of packages +Rather than checking checksums of packages against the existing list, generate +a new list for the checksums of packages. + +o /dev/build_kernels BUILD_KERNELS bool _ Build kernels +Even when they are not required, still build kernels/kernel adjacent packages. +This option has no effect when using KERNEL_BOOTSTRAP. diff --git a/steps/improve/reconfigure.sh b/steps/improve/reconfigure.sh @@ -0,0 +1,6 @@ +# SPDX-FileCopyrightText: 2024 fosslinux <fosslinux@aussies.space> +# +# SPDX-License-Identifier: GPL-3.0-or-later +set -ex +/configurator /steps/configurator +/script-generator /steps/manifest diff --git a/steps/jump/fiwix.sh b/steps/jump/fiwix.sh @@ -7,11 +7,14 @@ set -ex # Build the ext2 image -make_fiwix_initrd -s 1376256 /boot/fiwix.ext2 +# 1392640 = 1360 MB +make_fiwix_initrd -s 1381376 /boot/fiwix.ext2 # Boot Fiwix +# 199680 = 195 MB +# as of 2024-05-27, Initrd = ~183 MB, kernel = ~10.5MB for Linux if match x${BARE_METAL} xTrue; then - kexec-fiwix /boot/fiwix -i /boot/fiwix.ext2 -m /e820 -c "fiwix console=/dev/tty1 root=/dev/ram0 initrd=fiwix.ext2 kexec_proto=linux kexec_size=204800 kexec_cmdline=\"init=/init consoleblank=0\"" + kexec-fiwix /boot/fiwix -i /boot/fiwix.ext2 -m /e820 -c "fiwix console=/dev/tty1 root=/dev/ram0 initrd=fiwix.ext2 kexec_proto=linux kexec_size=199680 kexec_cmdline=\"init=/init consoleblank=0\"" else - kexec-fiwix /boot/fiwix -i /boot/fiwix.ext2 -m /e820 -c "fiwix console=/dev/ttyS0 root=/dev/ram0 initrd=fiwix.ext2 kexec_proto=linux kexec_size=204800 kexec_cmdline=\"init=/init console=ttyS0\"" + kexec-fiwix /boot/fiwix -i /boot/fiwix.ext2 -m /e820 -c "fiwix console=/dev/ttyS0 root=/dev/ram0 initrd=fiwix.ext2 kexec_proto=linux kexec_size=199680 kexec_cmdline=\"init=/init console=ttyS0\"" fi diff --git a/steps/jump/linux.sh b/steps/jump/linux.sh @@ -17,7 +17,7 @@ if [ "${KERNEL_BOOTSTRAP}" = True ]; then find / -xdev -type d -printf "dir %p %m %U %G\n" >> /initramfs.list find / -xdev -type f -printf "file %p %p %m %U %G\n" >> /initramfs.list find / -xdev -type l -printf "slink %p %l %m %U %G\n" >> /initramfs.list - kexec-linux "/dev/ram1" "/boot/vmlinuz" "!gen_init_cpio /initramfs.list | gzip -c" + kexec-linux "/dev/ram1" "/boot/vmlinuz" "!gen_init_cpio /initramfs.list | bzip2 -c" else mkdir /etc # kexec time diff --git a/steps/linux-4.14.341-openela/files/config b/steps/linux-4.14.341-openela/files/config @@ -62,8 +62,8 @@ CONFIG_HAVE_KERNEL_LZMA=y CONFIG_HAVE_KERNEL_XZ=y CONFIG_HAVE_KERNEL_LZO=y CONFIG_HAVE_KERNEL_LZ4=y -CONFIG_KERNEL_GZIP=y -# CONFIG_KERNEL_BZIP2 is not set +# CONFIG_KERNEL_GZIP is not set +CONFIG_KERNEL_BZIP2=y # CONFIG_KERNEL_LZMA is not set # CONFIG_KERNEL_XZ is not set # CONFIG_KERNEL_LZO is not set diff --git a/steps/manifest b/steps/manifest @@ -41,6 +41,7 @@ build: fiwix-1.5.0-lb1 ( BUILD_FIWIX == True ) build: lwext4-1.0.0-lb1 ( BUILD_FIWIX == True ) build: kexec-fiwix-1.0 ( BUILD_FIWIX == True ) jump: fiwix ( KERNEL_BOOTSTRAP == True ) +improve: reconfigure ( CONFIGURATOR != True ) define: JOBS = 1 ( KERNEL_BOOTSTRAP == True ) build: make-3.82 build: patch-2.5.9 diff --git a/steps/simple-patch-1.0/simple-patch-1.0.x86.checksums b/steps/simple-patch-1.0/simple-patch-1.0.x86.checksums @@ -1 +1 @@ -f66b8200c9237a7d5fe6a3d4d94f1ae661009d8ad14efdc7e95ac4cb8c4775e8 /usr/bin/simple-patch +e6826990991981a959646355b5418ce2561a2fd1724004dd5e0a845ebb387373 /usr/bin/simple-patch