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"
|
printf "}\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
menuentry "live environment" ''
|
menuentry "live environment" '-- /sbin/init'
|
||||||
menuentry "new installation" '--init="/sbin/init --target=sysinstall"'
|
menuentry "new installation" '-- /sbin/init --target=sysinstall'
|
||||||
menuentry "upgrade existing installation" '--init="/sbin/init --target=sysupgrade"'
|
menuentry "upgrade existing installation" '-- /sbin/init --target=sysupgrade'
|
||||||
|
|
||||||
echo
|
echo
|
||||||
cat << EOF
|
cat << EOF
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
.Sh SYNOPSIS
|
.Sh SYNOPSIS
|
||||||
.Nm init
|
.Nm init
|
||||||
.Op Fl \-target Ns "=" Ns Ar init-target
|
.Op Fl \-target Ns "=" Ns Ar init-target
|
||||||
|
.Op Fl \-
|
||||||
|
.Op Ar chain-init ...
|
||||||
.Sh DESCRIPTION
|
.Sh DESCRIPTION
|
||||||
.Nm
|
.Nm
|
||||||
is the first program run after system startup and is responsible for
|
is the first program run after system startup and is responsible for
|
||||||
|
@ -93,7 +95,8 @@ The
|
||||||
target mounts the root filesystem as in
|
target mounts the root filesystem as in
|
||||||
.Pa /etc/fstab
|
.Pa /etc/fstab
|
||||||
(see
|
(see
|
||||||
.Xr fstab 5) and runs the next
|
.Xr fstab 5 )
|
||||||
|
and runs the next
|
||||||
.Nm
|
.Nm
|
||||||
program.
|
program.
|
||||||
This is used by
|
This is used by
|
||||||
|
@ -113,7 +116,9 @@ filesystem directory is bound at
|
||||||
.Pp
|
.Pp
|
||||||
Finally the
|
Finally the
|
||||||
.Pa /sbin/init
|
.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
|
.Ss Configuration
|
||||||
Once the
|
Once the
|
||||||
.Nm
|
.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();
|
init_early();
|
||||||
set_hostname();
|
set_hostname();
|
||||||
set_kblayout();
|
set_kblayout();
|
||||||
|
@ -938,8 +940,10 @@ static int init(const char* target)
|
||||||
return result;
|
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();
|
init_early();
|
||||||
prepare_block_devices();
|
prepare_block_devices();
|
||||||
load_fstab();
|
load_fstab();
|
||||||
|
@ -986,17 +990,27 @@ static int init_chain(const char* target)
|
||||||
if ( chdir("/") < 0 )
|
if ( chdir("/") < 0 )
|
||||||
fatal("chdir: %s: %m", chain_location);
|
fatal("chdir: %s: %m", chain_location);
|
||||||
unsetenv("INIT_PID");
|
unsetenv("INIT_PID");
|
||||||
|
const char* program = next_argv[0];
|
||||||
if ( !strcmp(target, "chain-merge") )
|
if ( !strcmp(target, "chain-merge") )
|
||||||
{
|
{
|
||||||
const char* argv[] = { "init", "--target=merge", NULL };
|
if ( next_argc < 1 )
|
||||||
execv("/sysmerge/sbin/init", (char* const*) argv);
|
{
|
||||||
fatal("Failed to load automatic update chain init: %s: %m", argv[0]);
|
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
|
else
|
||||||
{
|
{
|
||||||
const char* argv[] = { "init", NULL };
|
if ( next_argc < 1 )
|
||||||
execv("/sbin/init", (char* const*) argv);
|
{
|
||||||
fatal("Failed to load chain init: %s: %m", argv[0]);
|
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;
|
int status;
|
||||||
|
@ -1102,11 +1116,11 @@ int main(int argc, char* argv[])
|
||||||
!strcmp(target, "sysinstall") ||
|
!strcmp(target, "sysinstall") ||
|
||||||
!strcmp(target, "sysupgrade") ||
|
!strcmp(target, "sysupgrade") ||
|
||||||
!strcmp(target, "merge") )
|
!strcmp(target, "merge") )
|
||||||
return init(target);
|
return init(argc, argv, target);
|
||||||
|
|
||||||
if ( !strcmp(target, "chain") ||
|
if ( !strcmp(target, "chain") ||
|
||||||
!strcmp(target, "chain-merge") )
|
!strcmp(target, "chain-merge") )
|
||||||
return init_chain(target);
|
return init_chain(argc, argv, target);
|
||||||
|
|
||||||
fatal("Unknown initialization target `%s'", 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
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* 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 InitThread(void* user);
|
||||||
static void SystemIdleThread(void* user);
|
static void SystemIdleThread(void* user);
|
||||||
|
|
||||||
|
static int argc;
|
||||||
|
static char** argv;
|
||||||
static multiboot_info_t* bootinfo;
|
static multiboot_info_t* bootinfo;
|
||||||
static char* init_cmdline;
|
|
||||||
|
|
||||||
static char* cmdline_tokenize(char** saved)
|
static char* cmdline_tokenize(char** saved)
|
||||||
{
|
{
|
||||||
|
@ -156,6 +157,19 @@ static char* cmdline_tokenize(char** saved)
|
||||||
return data;
|
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)
|
extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo_p)
|
||||||
{
|
{
|
||||||
(void) magic;
|
(void) magic;
|
||||||
|
@ -235,59 +249,65 @@ extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo_p)
|
||||||
FreeKernelAddress(&alloc);
|
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_saved = cmdline;
|
||||||
char* arg;
|
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)) )
|
while ( (arg = cmdline_tokenize(&arg_saved)) )
|
||||||
{
|
{
|
||||||
struct kernel_option* option = NULL;
|
if ( argc == argmax )
|
||||||
char* parameter = NULL;
|
|
||||||
for ( size_t i = 0; i < options_count; i++ )
|
|
||||||
{
|
{
|
||||||
struct kernel_option* candidate = &options[i];
|
argmax = argmax ? 2 * argmax : 8;
|
||||||
if ( candidate->has_parameter )
|
char** new_argv = new char*[argmax + 1];
|
||||||
{
|
if ( !new_argv )
|
||||||
size_t name_length = strlen(candidate->name);
|
Panic("Failed to allocate kernel command line");
|
||||||
if ( strncmp(arg, candidate->name, name_length) != 0 )
|
for ( int i = 0; i < argc; i++ )
|
||||||
continue;
|
new_argv[i] = argv[i];
|
||||||
if ( arg[name_length] == '=' )
|
argv = new_argv;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
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("\r\e[J");
|
||||||
Log::PrintF("kernel: fatal: unrecognized option '%s'\n", arg);
|
Log::PrintF("kernel: fatal: unrecognized option '%s'\n", arg);
|
||||||
HaltKernel();
|
HaltKernel();
|
||||||
}
|
}
|
||||||
if ( !strcmp(option->name, "--init") )
|
}
|
||||||
init_cmdline = parameter;
|
|
||||||
else if ( !strcmp(option->name, "--no-random-seed") )
|
compact_arguments(&argc, &argv);
|
||||||
no_random_seed = true;
|
|
||||||
|
if ( argc == 0 )
|
||||||
|
{
|
||||||
|
argv[argc++] = (char*) "/sbin/init";
|
||||||
|
argv[argc] = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize the interrupt handler table and enable interrupts.
|
// Initialize the interrupt handler table and enable interrupts.
|
||||||
|
@ -684,33 +704,6 @@ static void InitThread(void* /*user*/)
|
||||||
|
|
||||||
dtable.Reset();
|
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];
|
const char* initpath = argv[0];
|
||||||
Ref<Descriptor> init = root->open(&ctx, initpath, O_EXEC | O_READ);
|
Ref<Descriptor> init = root->open(&ctx, initpath, O_EXEC | O_READ);
|
||||||
if ( !init )
|
if ( !init )
|
||||||
|
|
|
@ -6,7 +6,9 @@
|
||||||
.Nd operating system kernel
|
.Nd operating system kernel
|
||||||
.Sh SYNOPSIS
|
.Sh SYNOPSIS
|
||||||
.Pa /boot/sortix.bin
|
.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
|
.Sh DESCRIPTION
|
||||||
.Pa /boot/sortix.bin
|
.Pa /boot/sortix.bin
|
||||||
is the operating system
|
is the operating system
|
||||||
|
@ -19,22 +21,28 @@ compatible executable loaded by the bootloader along with a companion
|
||||||
.Xr initrd 7
|
.Xr initrd 7
|
||||||
that contains a userland.
|
that contains a userland.
|
||||||
.Pp
|
.Pp
|
||||||
The kernel extracts the initrd into the initial kernel memory root filesystem
|
The kernel extracts the initrd into the initial kernel memory root filesystem.
|
||||||
and executes
|
The specified
|
||||||
|
.Ar init
|
||||||
|
program is invoked with the given arguments, defaulting to the
|
||||||
.Xr init 8
|
.Xr init 8
|
||||||
as
|
at
|
||||||
.Pa /sbin/init .
|
.Pa /sbin/init
|
||||||
The computer is powered off if this process exits 0, rebooted if it exits 1,
|
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.
|
halted if it exits 2, and paniced otherwise.
|
||||||
.Pp
|
.Pp
|
||||||
The options are as follows:
|
The options are as follows:
|
||||||
.Bl -tag -width "12345678"
|
.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
|
.It Fl \-no-random-seed
|
||||||
Don't warn if no random seed file was loaded by the bootloader (usually from
|
Don't warn if no random seed file was loaded by the bootloader (usually from
|
||||||
.Pa /boot/random.seed ) .
|
.Pa /boot/random.seed ) .
|
||||||
|
|
Loading…
Reference in a new issue