aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaurent Bercot <ska-skaware@skarnet.org>2026-09-08 16:12:24 +0000
committerLaurent Bercot <ska-skaware@skarnet.org>2026-09-08 16:12:24 +0000
commit5eefb9aae5e9e88b200ff7fcc445120c5ee2998b (patch)
treeaa0bc83b0b5a86dd9a1aab781f36f2c85c8a6b5c
parent125cf07d0b5139476b1f25fa4ba5a0782818eacc (diff)
downloads6-frontend-5eefb9aae5e9e88b200ff7fcc445120c5ee2998b.tar.gz
Improve user service managementHEADmain
- 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-xconfigure13
-rw-r--r--doc/s6-frontend.html20
-rw-r--r--doc/s6.conf.html47
-rw-r--r--doc/s6.html27
-rw-r--r--package/configure-snippets/configure_case_lines1
-rw-r--r--package/configure-snippets/configure_expand_dirs2
-rw-r--r--package/configure-snippets/configure_generate_configh3
-rw-r--r--package/configure-snippets/configure_generate_make2
-rw-r--r--package/configure-snippets/configure_help_install4
-rw-r--r--package/configure-snippets/configure_init_vars1
-rw-r--r--src/s6-frontend/s6-frontend.c19
-rw-r--r--src/s6-frontend/s6.c160
12 files changed, 253 insertions, 46 deletions
diff --git a/configure b/configure
index ace7d40..b04abb8 100755
--- a/configure
+++ b/configure
@@ -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) ;
}