From 7d439676f6e9d5a449810442dbe92ff1446173dc Mon Sep 17 00:00:00 2001 From: Hugo Osvaldo Barrera Date: Tue, 21 Jul 2026 01:37:46 +0200 Subject: [PATCH] Set default runlevel for --user to 'default' The existing default runlevel of sysinit was never intentional, and a side-effect of how system mode works. Closes: https://github.com/OpenRC/openrc/issues/1035 --- NEWS.md | 13 +++++++++++++ man/rc-status.8 | 3 ++- src/librc/librc.c | 2 +- src/librc/rc.h.in | 2 +- src/openrc-run/openrc-run.c | 2 +- src/openrc/rc.c | 4 ++-- src/rc-depend/rc-depend.c | 2 +- src/rc-status/rc-status.c | 8 ++++---- src/rc-update/rc-update.c | 3 ++- src/shared/misc.c | 29 ++++++++++++++++++++++++++--- src/shared/misc.h | 2 ++ 11 files changed, 55 insertions(+), 15 deletions(-) diff --git a/NEWS.md b/NEWS.md index 389ebd8fb..a43ace668 100644 --- a/NEWS.md +++ b/NEWS.md @@ -4,6 +4,19 @@ OpenRC NEWS This file will contain a list of notable changes for each release. Note the information in this file is in reverse order. +## OpenRC 0.64 + +librc: rc_runlevel_get() now returns NULL when no runlevel has been set, +instead of falling back to "sysinit". + +rc-update now adds/deletes services in the default runlevel when invoked +without a runlevel if none is set (for example in a chroot). + +rc-status -r now prints an empty line when no runlevel has been set. + +The RC_DEFAULTLEVEL environment variable now honours the +rc_default_runlevel setting from rc.conf. + ## OpenRC 0.62 User services are no longer considered experimental. diff --git a/man/rc-status.8 b/man/rc-status.8 index 03b33fe68..30978a265 100644 --- a/man/rc-status.8 +++ b/man/rc-status.8 @@ -69,7 +69,8 @@ List all defined runlevels. .It Fl m , -manual Show all manually started services. .It Fl r , -runlevel -Print the current runlevel name. +Print the current runlevel name, or an empty line if no runlevel has +been set. .It Fl S , -supervised Show all supervised services. .It Fl s , -servicelist diff --git a/src/librc/librc.c b/src/librc/librc.c index 9a072bb9b..4a8af2490 100644 --- a/src/librc/librc.c +++ b/src/librc/librc.c @@ -484,7 +484,7 @@ rc_runlevel_get(void) if (!runlevel || !*runlevel) { free(runlevel); - runlevel = xstrdup(RC_LEVEL_SYSINIT); + runlevel = NULL; } return runlevel; diff --git a/src/librc/rc.h.in b/src/librc/rc.h.in index f6354a6db..45a254db6 100644 --- a/src/librc/rc.h.in +++ b/src/librc/rc.h.in @@ -158,7 +158,7 @@ const char *rc_runleveldir(void); const char *rc_svcdir(void); /*! Return the current runlevel. - * @return the current runlevel */ + * @return the current runlevel, or NULL if no runlevel has been set */ char *rc_runlevel_get(void); /*! Checks if the runlevel exists or not diff --git a/src/openrc-run/openrc-run.c b/src/openrc-run/openrc-run.c index 23b5591fc..234d72f82 100644 --- a/src/openrc-run/openrc-run.c +++ b/src/openrc-run/openrc-run.c @@ -1290,7 +1290,7 @@ int main(int argc, char **argv) if ((runlevel = xstrdup(getenv("RC_RUNLEVEL"))) == NULL) { env_filter(); env_config(); - runlevel = rc_runlevel_get(); + runlevel = effective_runlevel(); } setenv("EINFO_LOG", applet, 1); diff --git a/src/openrc/rc.c b/src/openrc/rc.c index 0216a6ab6..f718085db 100644 --- a/src/openrc/rc.c +++ b/src/openrc/rc.c @@ -875,7 +875,7 @@ int main(int argc, char **argv) * won't actually be starting them all. */ bootlevel = getenv("RC_BOOTLEVEL"); - runlevel = rc_runlevel_get(); + runlevel = effective_runlevel(); rc_logger_open(newlevel ? newlevel : runlevel); @@ -890,7 +890,7 @@ int main(int argc, char **argv) if (newlevel && strcmp(newlevel, RC_LEVEL_SYSINIT) == 0) { do_sysinit(); free(runlevel); - runlevel = rc_runlevel_get(); + runlevel = effective_runlevel(); } rc_plugin_load(); diff --git a/src/rc-depend/rc-depend.c b/src/rc-depend/rc-depend.c index 791bddc87..98fb0ee96 100644 --- a/src/rc-depend/rc-depend.c +++ b/src/rc-depend/rc-depend.c @@ -112,7 +112,7 @@ int main(int argc, char **argv) } if (!runlevel) - runlevel = rc_runlevel_get(); + runlevel = effective_runlevel(); services = rc_stringlist_new(); while (optind < argc) { diff --git a/src/rc-status/rc-status.c b/src/rc-status/rc-status.c index b3f800cda..0b8ee3b74 100644 --- a/src/rc-status/rc-status.c +++ b/src/rc-status/rc-status.c @@ -233,7 +233,7 @@ static void print_services_in_state(const char *runlevel, RC_STRINGLIST *svcs, rc_stringlist_add(types, "iafter"); } if (!runlevel) - r = rc_runlevel_get(); + r = effective_runlevel(); l = rc_deptree_depends(deptree, types, svcs, r ? r : runlevel, RC_DEP_STRICT | RC_DEP_TRACE | RC_DEP_START); free(r); @@ -377,7 +377,7 @@ int main(int argc, char **argv) /* NOTREACHED */ case 'r': runlevel = rc_runlevel_get(); - printf("%s\n", runlevel); + printf("%s\n", runlevel ? runlevel : ""); goto exit; /* NOTREACHED */ case 'S': @@ -432,7 +432,7 @@ int main(int argc, char **argv) if (opt == 0) exit(EXIT_FAILURE); if (!TAILQ_FIRST(levels)) { - runlevel = rc_runlevel_get(); + runlevel = effective_runlevel(); rc_stringlist_add(levels, runlevel); } @@ -463,7 +463,7 @@ int main(int argc, char **argv) rc_stringlist_free(levels); levels = rc_stringlist_new(); if (!runlevel) - runlevel = rc_runlevel_get(); + runlevel = effective_runlevel(); rc_stringlist_add(levels, runlevel); } rc_stringlist_add(levels, RC_LEVEL_SYSINIT); diff --git a/src/rc-update/rc-update.c b/src/rc-update/rc-update.c index a46c9ff76..26a24a867 100644 --- a/src/rc-update/rc-update.c +++ b/src/rc-update/rc-update.c @@ -319,7 +319,8 @@ int main(int argc, char **argv) runlevels = rc_runlevel_list(); } else { p = rc_runlevel_get(); - rc_stringlist_add(runlevels, p); + rc_stringlist_add(runlevels, + p ? p : default_runlevel()); free(p); } } diff --git a/src/shared/misc.c b/src/shared/misc.c index 1d8f80990..ae6c436f8 100644 --- a/src/shared/misc.c +++ b/src/shared/misc.c @@ -152,6 +152,25 @@ env_filter(void) rc_stringlist_free(profile); } +const char * +default_runlevel(void) +{ + const char *runlevel = rc_conf_value("rc_default_runlevel"); + + return runlevel ? runlevel : RC_LEVEL_DEFAULT; +} + +char * +effective_runlevel(void) +{ + char *runlevel = rc_runlevel_get(); + + if (!runlevel) + runlevel = xstrdup(rc_is_user() ? default_runlevel() : RC_LEVEL_SYSINIT); + + return runlevel; +} + void env_config(void) { @@ -218,7 +237,7 @@ env_config(void) } xasprintf(&tmpdir, "%s/tmp", svcdir); - e = rc_runlevel_get(); + e = effective_runlevel(); setenv("RC_VERSION", VERSION, 1); setenv("RC_LIBEXECDIR", RC_LIBEXECDIR, 1); @@ -240,13 +259,17 @@ env_config(void) free(e); free(tmpdir); - if ((fp = fopen(RC_KRUNLEVEL, "r"))) { + /* krunlevel is a system-wide override; it never applies to + * user sessions. */ + if (!rc_is_user() && (fp = fopen(RC_KRUNLEVEL, "r"))) { if (xgetline(&buffer, &size, fp) != -1) setenv("RC_DEFAULTLEVEL", buffer, 1); + else + setenv("RC_DEFAULTLEVEL", default_runlevel(), 1); free(buffer); fclose(fp); } else { - setenv("RC_DEFAULTLEVEL", RC_LEVEL_DEFAULT, 1); + setenv("RC_DEFAULTLEVEL", default_runlevel(), 1); } if (sys) diff --git a/src/shared/misc.h b/src/shared/misc.h index b0df78cf9..765649c60 100644 --- a/src/shared/misc.h +++ b/src/shared/misc.h @@ -37,6 +37,8 @@ char *rc_conf_value(const char *var); bool rc_conf_yesno(const char *var); +const char *default_runlevel(void); +char *effective_runlevel(void); void env_filter(void); void env_config(void); int signal_setup(int sig, void (*handler)(int));