diff --git a/configure.ac b/configure.ac index bbe9292e..9f6b2cb3 100644 --- a/configure.ac +++ b/configure.ac @@ -130,7 +130,7 @@ AC_ARG_WITH(hostname, [hostname=$withval], [hostname=yes]) AC_ARG_WITH(runlevel, - AS_HELP_STRING([--with-runlevel=N], [Runlevel to switch to after bootstrap, default: 2]), + AS_HELP_STRING([--with-runlevel=N], [Runlevel to switch to after bootstrap [1-9], default: 2]), [runlevel=$withval], [runlevel=yes]) AC_ARG_WITH(random-seed, diff --git a/doc/cmdline.md b/doc/cmdline.md index 30b029be..be0f6bf4 100644 --- a/doc/cmdline.md +++ b/doc/cmdline.md @@ -73,6 +73,12 @@ The `bool` setting is one of `on, off, true false, 1, 0`. `[1]` will be started, so a `tty [1] @console nologin` configuration presents you with a root console without login. + * `1-9`, except `6`: override the configured `runlevel`. Like the `S` + and `rescue`, giving a single number on the kernel command line tells + Finit to ignore any `runlevel` in `/etc/finit.conf` as well as the + configure fallback `--with-runlevel=N` setting. Remember, `6` is the + reboot runlevel and is not permitted. Any other values are ignored. + For more on kernel boot parameters, see the man page [bootparam(7)][]. [config.md]: config.md#rescue-mode diff --git a/src/conf.c b/src/conf.c index 50923933..1e043a73 100644 --- a/src/conf.c +++ b/src/conf.c @@ -134,6 +134,33 @@ static void parse_finit_opts(char *opt) } } +/* + * When runlevel (single integer) is given on the command line, + * it overrides the runlevel in finit.conf and the built-in + * default (from configure). It do however have to pass the + * same sanity checks. + */ +static int parse_runlevel(char *arg) +{ + const char *err = NULL; + char *ptr = arg; + long long num; + + /* Sanity check the token is just digit(s) */ + while (*ptr) { + if (!isdigit(*ptr++)) + return 0; + } + + num = strtonum(arg, 1, 9, &err); + if (err || num == 6) { + _d("Not a valid runlevel (%s), valid levels are [1-9], excluding 6, skipping.", arg); + return 0; + } + + return (int)num; +} + static void parse_arg(char *arg) { if (!strncmp(arg, "finit.", 6)) { @@ -141,11 +168,19 @@ static void parse_arg(char *arg) return; } - if (string_compare(arg, "rescue") || string_compare(arg, "recover")) + if (string_compare(arg, "rescue") || string_compare(arg, "recover")) { rescue = 1; + return; + } - if (string_compare(arg, "single") || string_compare(arg, "S")) + if (string_compare(arg, "single") || string_compare(arg, "S")) { single = 1; + return; + } + + /* Put any new command line options before this line. */ + + cmdlevel = parse_runlevel(arg); } #ifdef KERNEL_CMDLINE diff --git a/src/finit.c b/src/finit.c index 4e3142c2..fa548159 100644 --- a/src/finit.c +++ b/src/finit.c @@ -62,6 +62,7 @@ int runlevel = 0; /* Bootstrap 'S' */ int cfglevel = RUNLEVEL; /* Fallback if no configured runlevel */ +int cmdlevel = 0; /* runlevel override from cmdline */ int prevlevel = -1; int debug = 0; /* debug mode from kernel cmdline */ int rescue = 0; /* rescue mode from kernel cmdline */ @@ -569,11 +570,12 @@ static void crank_worker(void *unused) */ static void bootstrap_worker(void *work) { - static int cnt = 120; static struct wq final = { .cb = finalize, .delay = 10 }; + static int cnt = 120; + int level = cfglevel; _d("Step all services ..."); service_step_all(SVC_TYPE_ANY); @@ -598,11 +600,18 @@ static void bootstrap_worker(void *work) if (runparts && fisdir(runparts) && !rescue) run_parts(runparts, NULL); + /* - * Start all tasks/services in the configured runlevel + * Start all tasks/services in the configured runlevel, or jump + * into the runlevel selected from the command line. */ - _d("Change to default runlevel(%d), starting all services ...", cfglevel); - service_runlevel(cfglevel); + if (cmdlevel) { + _d("Runlevel %d requested from command line, starting all services ...", cmdlevel); + level = cmdlevel; + } else + _d("Change to default runlevel(%d), starting all services ...", cfglevel); + + service_runlevel(level); } static int version(int rc) diff --git a/src/finit.h b/src/finit.h index 4e4c6889..a528e363 100644 --- a/src/finit.h +++ b/src/finit.h @@ -110,6 +110,7 @@ struct init_request { extern int runlevel; extern int cfglevel; +extern int cmdlevel; extern int prevlevel; extern int debug; extern int rescue;