Merge pull request #468 from fosslinux/configurator

Add interactive "configurator"
This commit is contained in:
fosslinux 2024-05-29 08:51:34 +10:00 committed by GitHub
commit e1cc51964f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 903 additions and 35 deletions

View file

@ -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",

784
seed/configurator.c Normal file
View file

@ -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;
}

View file

@ -0,0 +1 @@
8235581c60334314b5a8321b0b07d6fb905669dce81878c8cfed909377573e91 configurator

View file

@ -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. */

View file

@ -1 +1 @@
dc6106dbc02839cdc9e3e2348432242eb6d33d840ab74badfd63c3c9997462b9 script-generator
a0ad0938f7a66b44674db2b0a2a0410966098b3cc511d8b1a4dadc77b1828088 script-generator

View file

@ -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

@ -1 +1 @@
Subproject commit 779e5424d4b55fe9b7faea2285ae8b6486df0433
Subproject commit 18eac1d08535a685c817247fb8c41a1dba9bbf6f

View file

@ -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

View file

@ -1 +1 @@
19fd50d727e8a7feba8b6e369e68287d1922d8f623a156fb113d994891e96998 /usr/bin/checksum-transcriber
59cc0fb361f84e81a1cda6111ef847188d6c7c839c5a52166d9185ca767cf920 /usr/bin/checksum-transcriber

81
steps/configurator Normal file
View file

@ -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.

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -1 +1 @@
f66b8200c9237a7d5fe6a3d4d94f1ae661009d8ad14efdc7e95ac4cb8c4775e8 /usr/bin/simple-patch
e6826990991981a959646355b5418ce2561a2fd1724004dd5e0a845ebb387373 /usr/bin/simple-patch