mirror of
https://gitlab.com/sortix/sortix.git
synced 2023-02-13 20:55:38 -05:00
Refactor kernel command line parsing.
This commit is contained in:
parent
35d3c7e0b5
commit
d45417651f
5 changed files with 118 additions and 98 deletions
|
@ -218,9 +218,9 @@ menuentry() {
|
|||
printf "}\n"
|
||||
}
|
||||
|
||||
menuentry "live environment" ''
|
||||
menuentry "new installation" '--init="/sbin/init --target=sysinstall"'
|
||||
menuentry "upgrade existing installation" '--init="/sbin/init --target=sysupgrade"'
|
||||
menuentry "live environment" '-- /sbin/init'
|
||||
menuentry "new installation" '-- /sbin/init --target=sysinstall'
|
||||
menuentry "upgrade existing installation" '-- /sbin/init --target=sysupgrade'
|
||||
|
||||
echo
|
||||
cat << EOF
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
.Sh SYNOPSIS
|
||||
.Nm init
|
||||
.Op Fl \-target Ns "=" Ns Ar init-target
|
||||
.Op Fl \-
|
||||
.Op Ar chain-init ...
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
is the first program run after system startup and is responsible for
|
||||
|
@ -93,7 +95,8 @@ The
|
|||
target mounts the root filesystem as in
|
||||
.Pa /etc/fstab
|
||||
(see
|
||||
.Xr fstab 5) and runs the next
|
||||
.Xr fstab 5 )
|
||||
and runs the next
|
||||
.Nm
|
||||
program.
|
||||
This is used by
|
||||
|
@ -113,7 +116,9 @@ filesystem directory is bound at
|
|||
.Pp
|
||||
Finally the
|
||||
.Pa /sbin/init
|
||||
program of the target root filesystem is run inside a chroot.
|
||||
program (or
|
||||
.Ar chain-init
|
||||
if specified) of the target root filesystem is run inside a chroot.
|
||||
.Ss Configuration
|
||||
Once the
|
||||
.Nm
|
||||
|
|
34
init/init.c
34
init/init.c
|
@ -813,8 +813,10 @@ static void niht(void)
|
|||
}
|
||||
}
|
||||
|
||||
static int init(const char* target)
|
||||
static int init(int argc, char** argv, const char* target)
|
||||
{
|
||||
if ( 1 < argc )
|
||||
fatal("unexpected extra operand: %s", argv[1]);
|
||||
init_early();
|
||||
set_hostname();
|
||||
set_kblayout();
|
||||
|
@ -938,8 +940,10 @@ static int init(const char* target)
|
|||
return result;
|
||||
}
|
||||
|
||||
static int init_chain(const char* target)
|
||||
static int init_chain(int argc, char** argv, const char* target)
|
||||
{
|
||||
int next_argc = argc - 1;
|
||||
char** next_argv = argv + 1;
|
||||
init_early();
|
||||
prepare_block_devices();
|
||||
load_fstab();
|
||||
|
@ -986,17 +990,27 @@ static int init_chain(const char* target)
|
|||
if ( chdir("/") < 0 )
|
||||
fatal("chdir: %s: %m", chain_location);
|
||||
unsetenv("INIT_PID");
|
||||
const char* program = next_argv[0];
|
||||
if ( !strcmp(target, "chain-merge") )
|
||||
{
|
||||
const char* argv[] = { "init", "--target=merge", NULL };
|
||||
execv("/sysmerge/sbin/init", (char* const*) argv);
|
||||
fatal("Failed to load automatic update chain init: %s: %m", argv[0]);
|
||||
if ( next_argc < 1 )
|
||||
{
|
||||
program = "/sysmerge/sbin/init";
|
||||
next_argv = (char*[]) { "init", "--target=merge", NULL };
|
||||
}
|
||||
execvp(program, (char* const*) next_argv);
|
||||
fatal("Failed to load automatic update chain init: %s: %m",
|
||||
next_argv[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
const char* argv[] = { "init", NULL };
|
||||
execv("/sbin/init", (char* const*) argv);
|
||||
fatal("Failed to load chain init: %s: %m", argv[0]);
|
||||
if ( next_argc < 1 )
|
||||
{
|
||||
program = "/sbin/init";
|
||||
next_argv = (char*[]) { "init", NULL };
|
||||
}
|
||||
execvp(program, (char* const*) next_argv);
|
||||
fatal("Failed to load chain init: %s: %m", next_argv[0]);
|
||||
}
|
||||
}
|
||||
int status;
|
||||
|
@ -1102,11 +1116,11 @@ int main(int argc, char* argv[])
|
|||
!strcmp(target, "sysinstall") ||
|
||||
!strcmp(target, "sysupgrade") ||
|
||||
!strcmp(target, "merge") )
|
||||
return init(target);
|
||||
return init(argc, argv, target);
|
||||
|
||||
if ( !strcmp(target, "chain") ||
|
||||
!strcmp(target, "chain-merge") )
|
||||
return init_chain(target);
|
||||
return init_chain(argc, argv, target);
|
||||
|
||||
fatal("Unknown initialization target `%s'", target);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016 Jonas 'Sortie' Termansen.
|
||||
* Copyright (c) 2011-2017 Jonas 'Sortie' Termansen.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -108,8 +108,9 @@ static void BootThread(void* user);
|
|||
static void InitThread(void* user);
|
||||
static void SystemIdleThread(void* user);
|
||||
|
||||
static int argc;
|
||||
static char** argv;
|
||||
static multiboot_info_t* bootinfo;
|
||||
static char* init_cmdline;
|
||||
|
||||
static char* cmdline_tokenize(char** saved)
|
||||
{
|
||||
|
@ -156,6 +157,19 @@ static char* cmdline_tokenize(char** saved)
|
|||
return data;
|
||||
}
|
||||
|
||||
static void compact_arguments(int* argc, char*** argv)
|
||||
{
|
||||
for ( int i = 0; i < *argc; i++ )
|
||||
{
|
||||
while ( i < *argc && !(*argv)[i] )
|
||||
{
|
||||
for ( int n = i; n < *argc; n++ )
|
||||
(*argv)[n] = (*argv)[n+1];
|
||||
(*argc)--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo_p)
|
||||
{
|
||||
(void) magic;
|
||||
|
@ -235,59 +249,65 @@ extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo_p)
|
|||
FreeKernelAddress(&alloc);
|
||||
}
|
||||
|
||||
bool no_random_seed = false;
|
||||
int argmax = 1;
|
||||
argv = new char*[argmax + 1];
|
||||
if ( !argv )
|
||||
Panic("Failed to allocate kernel command line");
|
||||
|
||||
char* arg_saved = cmdline;
|
||||
char* arg;
|
||||
struct kernel_option
|
||||
{
|
||||
const char* name;
|
||||
bool has_parameter;
|
||||
} options[] =
|
||||
{
|
||||
{ "--init", true },
|
||||
{ "--no-random-seed", false },
|
||||
};
|
||||
size_t options_count = sizeof(options) / sizeof(options[0]);
|
||||
while ( (arg = cmdline_tokenize(&arg_saved)) )
|
||||
{
|
||||
struct kernel_option* option = NULL;
|
||||
char* parameter = NULL;
|
||||
for ( size_t i = 0; i < options_count; i++ )
|
||||
if ( argc == argmax )
|
||||
{
|
||||
struct kernel_option* candidate = &options[i];
|
||||
if ( candidate->has_parameter )
|
||||
{
|
||||
size_t name_length = strlen(candidate->name);
|
||||
if ( strncmp(arg, candidate->name, name_length) != 0 )
|
||||
continue;
|
||||
if ( arg[name_length] == '=' )
|
||||
parameter = arg + name_length + 1;
|
||||
else if ( !arg[name_length] )
|
||||
{
|
||||
if ( !(parameter = cmdline_tokenize(&arg_saved)) )
|
||||
{
|
||||
Log::PrintF("\r\e[J");
|
||||
Log::PrintF("kernel: fatal: option '%s' requires an argument\n", arg);
|
||||
HaltKernel();
|
||||
}
|
||||
}
|
||||
else
|
||||
continue;
|
||||
}
|
||||
else if ( strcmp(arg, candidate->name) != 0 )
|
||||
continue;
|
||||
option = candidate;
|
||||
argmax = argmax ? 2 * argmax : 8;
|
||||
char** new_argv = new char*[argmax + 1];
|
||||
if ( !new_argv )
|
||||
Panic("Failed to allocate kernel command line");
|
||||
for ( int i = 0; i < argc; i++ )
|
||||
new_argv[i] = argv[i];
|
||||
argv = new_argv;
|
||||
}
|
||||
if ( !option )
|
||||
argv[argc++] = arg;
|
||||
}
|
||||
argv[argc] = NULL;
|
||||
|
||||
bool no_random_seed = false;
|
||||
for ( int i = 0; i < argc; i++ )
|
||||
{
|
||||
const char* arg = argv[i];
|
||||
if ( arg[0] != '-' || !arg[1] )
|
||||
continue;
|
||||
argv[i] = NULL;
|
||||
if ( !strcmp(arg, "--") )
|
||||
break;
|
||||
if ( arg[1] != '-' )
|
||||
{
|
||||
char c;
|
||||
while ( (c = *++arg) ) switch ( c )
|
||||
{
|
||||
default:
|
||||
Log::PrintF("\r\e[J");
|
||||
Log::PrintF("kernel: fatal: unknown option -- '%c'\n", c);
|
||||
HaltKernel();
|
||||
}
|
||||
}
|
||||
else if ( !strcmp(arg, "--no-random-seed") )
|
||||
no_random_seed = true;
|
||||
else
|
||||
{
|
||||
Log::PrintF("\r\e[J");
|
||||
Log::PrintF("kernel: fatal: unrecognized option '%s'\n", arg);
|
||||
HaltKernel();
|
||||
}
|
||||
if ( !strcmp(option->name, "--init") )
|
||||
init_cmdline = parameter;
|
||||
else if ( !strcmp(option->name, "--no-random-seed") )
|
||||
no_random_seed = true;
|
||||
}
|
||||
|
||||
compact_arguments(&argc, &argv);
|
||||
|
||||
if ( argc == 0 )
|
||||
{
|
||||
argv[argc++] = (char*) "/sbin/init";
|
||||
argv[argc] = NULL;
|
||||
}
|
||||
|
||||
// Initialize the interrupt handler table and enable interrupts.
|
||||
|
@ -684,33 +704,6 @@ static void InitThread(void* /*user*/)
|
|||
|
||||
dtable.Reset();
|
||||
|
||||
static char default_init_cmdline[] = "/sbin/init";
|
||||
if ( !init_cmdline )
|
||||
init_cmdline = default_init_cmdline;
|
||||
|
||||
char* init_cmdline_dup = strdup(init_cmdline);
|
||||
if ( !init_cmdline_dup )
|
||||
PanicF("strdup: %m");
|
||||
size_t init_cmdline_tokens = 0;
|
||||
char* saved = init_cmdline_dup;
|
||||
char* arg;
|
||||
while ( (arg = cmdline_tokenize(&saved)) )
|
||||
init_cmdline_tokens++;
|
||||
free(init_cmdline_dup);
|
||||
|
||||
if ( INT_MAX - 1 < init_cmdline_tokens )
|
||||
Panic("Too many tokens in init command line");
|
||||
|
||||
int argc = init_cmdline_tokens;
|
||||
char** argv = new char*[argc + 1];
|
||||
if ( !argv )
|
||||
PanicF("operator new: %m");
|
||||
saved = init_cmdline;
|
||||
for ( int i = 0; i <= argc; i++ )
|
||||
argv[i] = cmdline_tokenize(&saved);
|
||||
|
||||
if ( argc == 0 )
|
||||
Panic("No init specified");
|
||||
const char* initpath = argv[0];
|
||||
Ref<Descriptor> init = root->open(&ctx, initpath, O_EXEC | O_READ);
|
||||
if ( !init )
|
||||
|
|
|
@ -6,7 +6,9 @@
|
|||
.Nd operating system kernel
|
||||
.Sh SYNOPSIS
|
||||
.Pa /boot/sortix.bin
|
||||
.Op Fl \-init Ns "=" Ns Ar init-command-line
|
||||
.Op Fl \-no-random-seed
|
||||
.Op Fl \-
|
||||
.Op Ar init ...
|
||||
.Sh DESCRIPTION
|
||||
.Pa /boot/sortix.bin
|
||||
is the operating system
|
||||
|
@ -19,22 +21,28 @@ compatible executable loaded by the bootloader along with a companion
|
|||
.Xr initrd 7
|
||||
that contains a userland.
|
||||
.Pp
|
||||
The kernel extracts the initrd into the initial kernel memory root filesystem
|
||||
and executes
|
||||
The kernel extracts the initrd into the initial kernel memory root filesystem.
|
||||
The specified
|
||||
.Ar init
|
||||
program is invoked with the given arguments, defaulting to the
|
||||
.Xr init 8
|
||||
as
|
||||
.Pa /sbin/init .
|
||||
The computer is powered off if this process exits 0, rebooted if it exits 1,
|
||||
at
|
||||
.Pa /sbin/init
|
||||
if
|
||||
.Ar init
|
||||
is not specified.
|
||||
If the
|
||||
.Nm init
|
||||
is to receive any argument starting with a dash, first pass the
|
||||
.Fl \-
|
||||
delimiter to stop kernel option parsing.
|
||||
The computer is powered off if the
|
||||
.Nm init
|
||||
process exits 0, rebooted if it exits 1,
|
||||
halted if it exits 2, and paniced otherwise.
|
||||
.Pp
|
||||
The options are as follows:
|
||||
.Bl -tag -width "12345678"
|
||||
.It Fl \-init Ns "=" Ns Ar init-command-line
|
||||
The
|
||||
.Ar init-command-line
|
||||
argument is split into tokens and used as the command line to invoke the
|
||||
specified
|
||||
.Xr init 8 .
|
||||
.It Fl \-no-random-seed
|
||||
Don't warn if no random seed file was loaded by the bootloader (usually from
|
||||
.Pa /boot/random.seed ) .
|
||||
|
|
Loading…
Reference in a new issue