1
0
Fork 0
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:
Jonas 'Sortie' Termansen 2017-02-25 23:25:53 +01:00
parent 35d3c7e0b5
commit d45417651f
5 changed files with 118 additions and 98 deletions

View file

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

View file

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

View file

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

View file

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

View file

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