diff options
| author | Laurent Bercot <ska-skaware@skarnet.org> | 2026-09-08 16:12:24 +0000 |
|---|---|---|
| committer | Laurent Bercot <ska-skaware@skarnet.org> | 2026-09-08 16:12:24 +0000 |
| commit | 5eefb9aae5e9e88b200ff7fcc445120c5ee2998b (patch) | |
| tree | aa0bc83b0b5a86dd9a1aab781f36f2c85c8a6b5c | |
| parent | 125cf07d0b5139476b1f25fa4ba5a0782818eacc (diff) | |
| download | s6-frontend-5eefb9aae5e9e88b200ff7fcc445120c5ee2998b.tar.gz | |
- Separate /etc/s6.conf from /etc/s6-user.conf
- Have --system|--user handled at the s6 level, not the s6-frontend level
- Also have --help rewritten at the s6 level because it's cleaner
- On --user, process the config file with sed to import XDG variables
- Do not use s6f_user_get_confdirs() anymore (can remove it if we
decide to stick with this design), --user now only changes the
conf file, and only command-line options such as --scandir can override
what is described in the conf file.
- Document the current behaviour.
| -rwxr-xr-x | configure | 13 | ||||
| -rw-r--r-- | doc/s6-frontend.html | 20 | ||||
| -rw-r--r-- | doc/s6.conf.html | 47 | ||||
| -rw-r--r-- | doc/s6.html | 27 | ||||
| -rw-r--r-- | package/configure-snippets/configure_case_lines | 1 | ||||
| -rw-r--r-- | package/configure-snippets/configure_expand_dirs | 2 | ||||
| -rw-r--r-- | package/configure-snippets/configure_generate_configh | 3 | ||||
| -rw-r--r-- | package/configure-snippets/configure_generate_make | 2 | ||||
| -rw-r--r-- | package/configure-snippets/configure_help_install | 4 | ||||
| -rw-r--r-- | package/configure-snippets/configure_init_vars | 1 | ||||
| -rw-r--r-- | src/s6-frontend/s6-frontend.c | 19 | ||||
| -rw-r--r-- | src/s6-frontend/s6.c | 160 |
12 files changed, 253 insertions, 46 deletions
@@ -30,7 +30,9 @@ Fine tuning of the installation directories: --repodir=DIR default s6-rc repository [s6-rc default: /var/lib/s6-rc/repository] --bootdb=LINK location of the bootable s6-rc compiled db [s6-rc default: /etc/s6-rc/compiled/current] --stmpdir=DIR secure location for temporary s6-frontend files [/run/s6-frontend] - --conffile=FILE default configuration file for s6 command [SYSCONFDIR/s6.conf] + --conffile=FILE default system configuration file for the s6 command [SYSCONFDIR/s6.conf] + --userconffile=FILE default user configuration file for the s6 command [SYSCONFDIR/s6-user.conf] + If no --prefix option is given, by default libdir (but not dynlibdir) will be /usr/lib, and includedir will be /usr/include. @@ -188,6 +190,7 @@ repodir= bootdb= stmpdir=/run/s6-frontend conffile='$sysconfdir/s6.conf' +userconffile='$sysconfdir/s6-user.conf' storelist='$prefix/share/s6/sources:$sysconfdir/s6/sources' defbundle= fdhuser= @@ -240,6 +243,7 @@ for arg ; do --bootdb=*) bootdb=${arg#*=} ;; --stmpdir=*) stmpdir=${arg#*=} ;; --conffile=*) conffile=${arg#*=} ;; + --userconffile=*) userconffile=${arg#*=} ;; --with-store-list=*) storelist=${arg#*=} ;; --with-default-bundle=*) defbundle=${arg#*=} ;; --with-fdholder-user=*) fdhuser=${arg#*=} ;; @@ -277,7 +281,7 @@ fi # Expand installation directories stripdir prefix -for i in exec_prefix dynlibdir libexecdir bindir libdir includedir sysconfdir pkgconfdir sysdeps sproot stmpdir conffile storelist ; do +for i in exec_prefix dynlibdir libexecdir bindir libdir includedir sysconfdir pkgconfdir sysdeps sproot stmpdir conffile userconffile storelist ; do eval tmp=\${$i} eval $i=$tmp stripdir $i @@ -566,6 +570,8 @@ echo "BOOTDB := $bootdb" echo "STMPDIR := $stmpdir" echo "STORELIST := $storelist" echo "FDHUSER := $fdhuser" +echo "CONFFILE := $conffile" +echo "USERCONFFILE := $userconffile" if $usensss ; then echo "LIBNSSS := -lnsss" @@ -677,6 +683,9 @@ echo "#define ${package_macro_name}_STMPDIR \"$stmpdir\"" echo "#undef ${package_macro_name}_CONF" echo "#define ${package_macro_name}_CONF \"$conffile\"" +echo "#undef ${package_macro_name}_USER_CONF" +echo "#define ${package_macro_name}_USER_CONF \"$userconffile\"" + echo "#undef ${package_macro_name}_STORELIST" echo "#define ${package_macro_name}_STORELIST \"$storelist\"" diff --git a/doc/s6-frontend.html b/doc/s6-frontend.html index 9d563f7..df98186 100644 --- a/doc/s6-frontend.html +++ b/doc/s6-frontend.html @@ -38,14 +38,26 @@ users should call <a href="s6.html">s6</a> instead. </p> <ul> - <li> <a href="s6.html">s6</a> gets the name of its configuration file from the -<tt>S6_CONF</tt> environment variable, or from the compiled-in default if -this variable is unset. Normally this default is <tt>/etc/s6.conf</tt>. </li> + <li> <a href="s6.html">s6</a> reads its configuration file at +<tt>/etc/s6.conf</tt> by default, overridable by the admin at build time +via the <tt>--conffile</tt> configure option, also overridable by the user +at run time via the <tt>S6_CONF</tt> environment variable. + <ul> + <li> If <a href="s6.html">s6</a> is run with the <tt>--user</tt> option, +it looks for <tt>/etc/s6-user.conf</tt> instead, overridable by the admin at +build time via the <tt>--userconffile</tt> configure option, also overridable +by the user at run time via the <tt>S6_USER_CONF</tt> environment variable. </li> + </ul> </li> <li> This configuration file (let's call it <em>conf</em>) contains <a href="s6.conf.html">variable definitions</a> that set the default for all the parts of the s6 system. </li> <li> <a href="s6.html">s6</a> rewrites itself into -<code>envfile -I <em>conf</em> -- s6-frontend <em>args...</em></code> </li> +<code>envfile -I <em>conf</em> -- s6-frontend <em>args...</em></code> + <ul> + <li> If the <tt>--user</tt> flag has been given, some text transformation +<a href="s6.conf.html#userservices">is first performed on the file</a> to substitute +the relevant XDG variables. </li> + </ul> </li> <li> The <a href="//skarnet.org/software/execline/envfile.html">envfile</a> program reads and parses <em>conf</em>, and then runs <a href="s6-frontend.html">s6-frontend</a> with the additional environment variables defined in <em>conf</em>. diff --git a/doc/s6.conf.html b/doc/s6.conf.html index 8120603..9c15615 100644 --- a/doc/s6.conf.html +++ b/doc/s6.conf.html @@ -37,6 +37,15 @@ are located). what the full path to the <em>foobar</em> service directory is. </p> +<h3> Location </h3> + +<p> +The global <tt>/etc/s6.conf</tt> path for the configuration variable can be +overridden by the admin at build time via the <tt>--conffile</tt> configure +option, and by the user at <a href="s6.html">s6</a> run time via the +<tt>S6_CONF</tt> environment variable. +</p> + <h2 id="description"> Description </h2> <p> @@ -107,5 +116,43 @@ The default is <strong>root</strong> and that is fine, but distributions may want to set it to an unprivileged user. </dd> </dl> +<h2 id="userservices"> User services </h2> + +<p> + If <a href="s6.html">s6</a> is invoked with the <tt>--user</tt> flag, +the <tt>/etc/s6-user.conf</tt> file is used instead, with the same +syntax and the same variables, but additionally, the following +environment variables, if present, are substituted: +</p> + +<ul> + <li> <tt>XDG_RUNTIME_DIR</tt> </li> + <li> <tt>XDG_DATA_HOME</tt> </li> + <li> <tt>XDG_CONFIG_HOME</tt> </li> + <li> <tt>XDG_STATE_HOME</tt> </li> + <li> <tt>XDG_CACHE_HOME</tt> </li> +</ul> + +<p> + That means that a global <tt>/etc/s6-user.conf</tt> file can for instance declare +</p> + +<pre> + scandir=${XDG_RUNTIME_DIR}/service +</pre> + +<p> +and the correct location for the <tt>scandir</tt> will be obtained, for every user. +</p> + +<h3> Location </h3> + +<p> +The global <tt>/etc/s6-user.conf</tt> path for the configuration variable can be +overridden by the admin at build time via the <tt>--userconffile</tt> configure +option, and by the user at <a href="s6.html">s6</a> run time via the +<tt>S6_USER_CONF</tt> environment variable. +</p> + </body> </html> diff --git a/doc/s6.html b/doc/s6.html index 661bc65..9fb6038 100644 --- a/doc/s6.html +++ b/doc/s6.html @@ -63,17 +63,6 @@ command, and on the linked documentation page you can find the interpretation of its various exit codes. </p> -<h2 id="env"> Environment variables </h2> - -<ul> - <li> s6 reads the <code>S6_CONF</code> environment variable -containing the absolute path to the -<a href="s6.conf.html">configuration file</a> for the s6 command. </li> - <li> If this variable is unset, the default is <tt>/etc/s6.conf</tt>, -possibly overridden by the <tt>--conffile</tt> build-time configure option to -s6-frontend. </li> -</ul> - <h2 id="options"> Global options </h2> <p> @@ -129,12 +118,18 @@ if <tt>auto</tt>. Not all commands and subcommands will use this setting. Also, for pretty-printing of columns, it is recommended to have built s6-frontend with util-linux support. </dd> + <dt> <tt>-S</tt>, <tt>--system</tt> </dt> + <dd> Use the <tt>/etc/s6.conf</tt> system <a href="s6.conf.html">configuration file</tt>. +This is the default. +The location of the file can be overridden by the admin at install time via the +<tt>--conffile</tt> configure option, or by the user at run time via the +<tt>S6_CONF</tt> environment variable. </dd> + <dt> <tt>-u</tt>, <tt>--user</tt> </dt> - <dd> Override the variables defined in the configuration file with values -built from XDG environment variables. This option only works if the XDG -environment variables are present in the environment. This option is -useful to address user services. You can see what values are used by -running <tt>s6 -u version export</tt>. </dd> + <dd> Use the <tt>/etc/s6-user.conf</tt> system <a href="s6.conf.html">configuration file</tt>. +The location of the file can be overridden by the admin at install time via the +<tt>--userconffile</tt> configure option, or by the user at run time via the +<tt>S6_USER_CONF</tt> environment variable. </dd> </dl> diff --git a/package/configure-snippets/configure_case_lines b/package/configure-snippets/configure_case_lines index ed2aaea..d4a1a64 100644 --- a/package/configure-snippets/configure_case_lines +++ b/package/configure-snippets/configure_case_lines @@ -4,6 +4,7 @@ --bootdb=*) bootdb=${arg#*=} ;; --stmpdir=*) stmpdir=${arg#*=} ;; --conffile=*) conffile=${arg#*=} ;; + --userconffile=*) userconffile=${arg#*=} ;; --with-store-list=*) storelist=${arg#*=} ;; --with-default-bundle=*) defbundle=${arg#*=} ;; --with-fdholder-user=*) fdhuser=${arg#*=} ;; diff --git a/package/configure-snippets/configure_expand_dirs b/package/configure-snippets/configure_expand_dirs index d4eff64..fed9152 100644 --- a/package/configure-snippets/configure_expand_dirs +++ b/package/configure-snippets/configure_expand_dirs @@ -1 +1 @@ -stmpdir conffile storelist +stmpdir conffile userconffile storelist diff --git a/package/configure-snippets/configure_generate_configh b/package/configure-snippets/configure_generate_configh index 3f99a88..171c246 100644 --- a/package/configure-snippets/configure_generate_configh +++ b/package/configure-snippets/configure_generate_configh @@ -70,6 +70,9 @@ echo "#define ${package_macro_name}_STMPDIR \"$stmpdir\"" echo "#undef ${package_macro_name}_CONF" echo "#define ${package_macro_name}_CONF \"$conffile\"" +echo "#undef ${package_macro_name}_USER_CONF" +echo "#define ${package_macro_name}_USER_CONF \"$userconffile\"" + echo "#undef ${package_macro_name}_STORELIST" echo "#define ${package_macro_name}_STORELIST \"$storelist\"" diff --git a/package/configure-snippets/configure_generate_make b/package/configure-snippets/configure_generate_make index d10c04a..765a1d3 100644 --- a/package/configure-snippets/configure_generate_make +++ b/package/configure-snippets/configure_generate_make @@ -5,6 +5,8 @@ echo "BOOTDB := $bootdb" echo "STMPDIR := $stmpdir" echo "STORELIST := $storelist" echo "FDHUSER := $fdhuser" +echo "CONFFILE := $conffile" +echo "USERCONFFILE := $userconffile" if $usensss ; then echo "LIBNSSS := -lnsss" diff --git a/package/configure-snippets/configure_help_install b/package/configure-snippets/configure_help_install index 82ead11..7c4502a 100644 --- a/package/configure-snippets/configure_help_install +++ b/package/configure-snippets/configure_help_install @@ -3,4 +3,6 @@ --repodir=DIR default s6-rc repository [s6-rc default: /var/lib/s6-rc/repository] --bootdb=LINK location of the bootable s6-rc compiled db [s6-rc default: /etc/s6-rc/compiled/current] --stmpdir=DIR secure location for temporary s6-frontend files [/run/s6-frontend] - --conffile=FILE default configuration file for s6 command [SYSCONFDIR/s6.conf] + --conffile=FILE default system configuration file for the s6 command [SYSCONFDIR/s6.conf] + --userconffile=FILE default user configuration file for the s6 command [SYSCONFDIR/s6-user.conf] + diff --git a/package/configure-snippets/configure_init_vars b/package/configure-snippets/configure_init_vars index a156235..0130a0a 100644 --- a/package/configure-snippets/configure_init_vars +++ b/package/configure-snippets/configure_init_vars @@ -4,6 +4,7 @@ repodir= bootdb= stmpdir=/run/s6-frontend conffile='$sysconfdir/s6.conf' +userconffile='$sysconfdir/s6-user.conf' storelist='$prefix/share/s6/sources:$sysconfdir/s6/sources' defbundle= fdhuser= diff --git a/src/s6-frontend/s6-frontend.c b/src/s6-frontend/s6-frontend.c index ff78f8b..c703042 100644 --- a/src/s6-frontend/s6-frontend.c +++ b/src/s6-frontend/s6-frontend.c @@ -26,9 +26,7 @@ enum golb_e { - GOLB_HELP = 0x01, - GOLB_VERSION = 0x02, - GOLB_USER = 0x04, + GOLB_USER = 0x01, } ; enum gola_e @@ -103,8 +101,8 @@ int main (int argc, char const *const *argv) { static gol_bool const rgolb[] = { - { .so = 'h', .lo = "help", .clear = 0, .set = GOLB_HELP }, - { .so = 'u', .lo = "user", .clear = 0, .set = GOLB_USER }, + { .so = 0, .lo = "system", .clear = GOLB_USER, .set = 0 }, + { .so = 0, .lo = "user", .clear = 0, .set = GOLB_USER }, } ; static gol_arg const rgola[] = { @@ -142,7 +140,6 @@ int main (int argc, char const *const *argv) struct global_s globals_in_the_stack = GLOBAL_ZERO ; uint64_t wgolb = 0 ; - unsigned int golc ; struct command_s *cmd ; char const *wgola[GOLA_N] = { @@ -159,16 +156,16 @@ int main (int argc, char const *const *argv) PROG = "s6-frontend" ; g = &globals_in_the_stack ; - golc = GOL_main(argc, argv, rgolb, rgola, &wgolb, wgola) ; - argc -= golc ; argv += golc ; + { + unsigned int golc = GOL_main(argc, argv, rgolb, rgola, &wgolb, wgola) ; + argc -= golc ; argv += golc ; + } if (wgola[GOLA_VERBOSITY] && !uint0_scan(wgola[GOLA_VERBOSITY], &g->verbosity)) strerr_dief1x(100, "verbosity must be an unsigned integer") ; - if (wgolb & GOLB_HELP) { main_help(argv) ; _exit(0) ; } - g->isuser = !!(wgolb & GOLB_USER) ; - if (g->isuser) s6f_user_get_confdirs(&g->dirs, &g->userstorage) ; +// if (g->isuser) s6f_user_get_confdirs(&g->dirs, &g->userstorage) ; if (wgola[GOLA_SCANDIR]) g->dirs.scan = wgola[GOLA_SCANDIR] ; if (wgola[GOLA_LIVEDIR]) g->dirs.live = wgola[GOLA_LIVEDIR] ; diff --git a/src/s6-frontend/s6.c b/src/s6-frontend/s6.c index 0e49885..96de61c 100644 --- a/src/s6-frontend/s6.c +++ b/src/s6-frontend/s6.c @@ -3,27 +3,165 @@ #include <stdlib.h> #include <skalibs/envexec.h> +#include <skalibs/stralloc.h> +#include <skalibs/djbunix.h> #include <execline/config.h> #include <s6-frontend/config.h> +enum golb_e +{ + GOLB_HELP = 0x01, + GOLB_VERSION = 0x02, + GOLB_USER = 0x04, +} ; + +enum gola_e +{ + GOLA_SCANDIR, + GOLA_LIVEDIR, + GOLA_REPODIR, + GOLA_BOOTDB, + GOLA_STMPDIR, + GOLA_STORELIST, + GOLA_VERBOSITY, + GOLA_FDHUSER, + GOLA_COLOR, + GOLA_N +} ; + +#define dienomem() strerr_diefusys(111, "build command line") + +static inline enum gola_e gola_pos (gol_arg const *tab, size_t n, enum gola_e i) +{ + for (enum gola_e j = 0 ; j < n ; j++) if (tab[j].i == i) return j ; + strerr_dief(101, "can't happen: rgola does not cover all gola_e values") ; +} + int main (int argc, char const *const *argv) { - char const *conffile = getenv("S6_CONF") ; - PROG = "s6" ; - if (!conffile) conffile = S6_FRONTEND_CONF ; - if (!argc--) strerr_dief1x(103, "invalid argc/argv") ; - argv++ ; + static gol_bool const rgolb[] = + { + { .so = 'h', .lo = "help", .clear = 0, .set = GOLB_HELP }, + { .so = 'u', .lo = "user", .clear = 0, .set = GOLB_USER }, + { .so = 'S', .lo = "system", .clear = GOLB_USER, .set = 0 }, + } ; + static gol_arg const rgola[] = + { + { .so = 's', .lo = "scandir", .i = GOLA_SCANDIR }, + { .so = 'l', .lo = "livedir", .i = GOLA_LIVEDIR }, + { .so = 'r', .lo = "repodir", .i = GOLA_REPODIR }, + { .so = 'c', .lo = "bootdb", .i = GOLA_BOOTDB }, + { .so = 0, .lo = "stmpdir", .i = GOLA_STMPDIR }, + { .so = 0, .lo = "storelist", .i = GOLA_STORELIST }, + { .so = 'v', .lo = "verbosity", .i = GOLA_VERBOSITY }, + { .so = 0, .lo = "fdholder-user", .i = GOLA_FDHUSER }, + { .so = 0, .lo = "color", .i = GOLA_COLOR }, + } ; + stralloc sa = STRALLOC_ZERO ; + uint64_t wgolb = 0 ; + char const *wgola[GOLA_N] = { 0 } ; + size_t optpos[GOLA_N] = { 0 } ; + unsigned int conf_overrides = 0 ; unsigned int m = 0 ; - char const *newargv[6 + argc] ; - newargv[m++] = EXECLINE_EXTBINPREFIX "envfile" ; - newargv[m++] = "-I" ; - newargv[m++] = "--" ; - newargv[m++] = conffile ; + PROG = "s6" ; + + { + unsigned int golc = GOL_main(argc, argv, rgolb, rgola, &wgolb, wgola) ; + argc -= golc ; argv += golc ; + } + + for (enum gola_e i = 0 ; i < GOLA_N ; i++) if (wgola[i]) + { + enum gola_e j = gola_pos(rgola, sizeof(rgola)/sizeof(gol_arg const), i) ; + optpos[i] = sa.len ; + if (!stralloc_catb(&sa, "--", 2) + || !stralloc_cats(&sa, rgola[j].lo) + || !stralloc_catb(&sa, "=", 1) + || !stralloc_cats(&sa, wgola[i]) + || !stralloc_0(&sa)) + dienomem() ; + conf_overrides++ ; + } + + char const *newargv[(wgolb & GOLB_USER ? 17 : 4) + 1 + conf_overrides + 1 + (wgolb & GOLB_HELP ? 1 : argc) + 1] ; + + if (wgolb & GOLB_USER) + { + static char const *const xdgvar[5] = + { + "XDG_RUNTIME_DIR", + "XDG_DATA_HOME", + "XDG_CONFIG_HOME", + "XDG_STATE_HOME", + "XDG_CACHE_HOME", + } ; + ssize_t xdgpos[5] = { -1, -1, -1, -1, -1 } ; + int dosubst = 0 ; + int fd ; + for (unsigned int i = 0 ; i < 5 ; i++) + { + char const *x = getenv(xdgvar[i]) ; + if (x) + { + dosubst = 1 ; + xdgpos[i] = sa.len ; + if (!stralloc_cats(&sa, " s|\\$") + || !stralloc_cats(&sa, xdgvar[i]) + || !stralloc_cats(&sa, "|") + || !stralloc_cats(&sa, x) + || !stralloc_cats(&sa, "|g;s|\\${") + || !stralloc_cats(&sa, xdgvar[i]) + || !stralloc_cats(&sa, "}|") + || !stralloc_cats(&sa, x) + || !stralloc_cats(&sa, "|g") + || !stralloc_0(&sa)) + dienomem() ; + } + } + { + char const *x = getenv("S6_USER_CONF") ; + if (!x) x = S6_FRONTEND_USER_CONF ; + fd = open_readb(x) ; + if (fd == -1) strerr_diefusys(111, "open ", x, " for reading") ; + if (fd_move(0, fd) == -1) strerr_diefusys(111, "fd_move") ; + } + + if (dosubst) + { + newargv[m++] = EXECLINE_BINPREFIX "pipeline" ; + newargv[m++] = " sed" ; + for (unsigned int i = 0 ; i < 5 ; i++) if (xdgpos[i] >= 0) + { + newargv[m++] = " -e" ; + newargv[m++] = sa.s + xdgpos[i] ; + } + } + newargv[m++] = "" ; + newargv[m++] = EXECLINE_EXTBINPREFIX "envfile" ; + newargv[m++] = "-I" ; + newargv[m++] = "--" ; + newargv[m++] = "-" ; + } + else + { + char const *conffile = getenv("S6_CONF") ; + if (!conffile) conffile = S6_FRONTEND_CONF ; + newargv[m++] = EXECLINE_EXTBINPREFIX "envfile" ; + newargv[m++] = "-I" ; + newargv[m++] = "--" ; + newargv[m++] = conffile ; + } + newargv[m++] = S6_FRONTEND_LIBEXECPREFIX "s6-frontend" ; - while (argc--) newargv[m++] = *argv++ ; + for (enum gola_e i = 0 ; i < GOLA_N ; i++) + if (wgola[i]) newargv[m++] = sa.s + optpos[i] ; + newargv[m++] = "--" ; + if (wgolb & GOLB_HELP) newargv[m++] = "help" ; + else while (argc--) newargv[m++] = *argv++ ; + newargv[m++] = 0 ; xexec(newargv) ; } |
