diff options
-rw-r--r-- | doc/pies.texi | 193 | ||||
-rw-r--r-- | src/.gitignore | 1 | ||||
-rw-r--r-- | src/Makefile.am | 8 | ||||
-rw-r--r-- | src/cmdline.opt | 6 | ||||
-rw-r--r-- | src/pies.h | 2 | ||||
-rw-r--r-- | src/sysvinit.c | 28 | ||||
-rw-r--r-- | src/telinit.opt | 89 |
7 files changed, 268 insertions, 59 deletions
diff --git a/doc/pies.texi b/doc/pies.texi index ae4a56a..1f162a2 100644 --- a/doc/pies.texi +++ b/doc/pies.texi @@ -1647,12 +1647,17 @@ component @var{tag} @{ # @xref{Prerequisites, dependents}. dependents (@var{compnames}); # @r{List of flags.} # @xref{flags}. flags (@var{flags}); + + # @r{For @i{init} components: runlevels in which to start this} + # @r{component.} + # @xref{Runlevels}. + runlevels @var{string}; # @r{Listen on the given url.} # @xref{Inetd-Style Components}. socket @var{url}; # @r{Set socket type.} @@ -1701,20 +1706,20 @@ component @var{tag} @{ # @r{For @samp{inetd} components:} # @r{Text to send back if access is denied by ACL.} # @xref{Inetd-Style Components, access-denied-message}. access-denied-message @var{text}; - # @r{ACL for administrative access to this component.} - # @FIXME-xref{Access to Components}. + # @r{ACL for administrative (read-write) access to this component.} + # @xref{Visibility}. admin-acl @var{name}; # @r{or:} admin-acl @{ @dots{} @} # @r{ACL for read-only access to this component.} - # @FIXME-xref{Access to Components}. + # @xref{Visibility}. list-acl @var{name}; # @r{or:} list-acl @{ @dots{} @} # @r{ACL for this component.} # @xref{ACL}. @@ -2146,35 +2151,46 @@ seconds. This statement is reserved for use in the future. Currently (as of version @value{VERSION}) it is a no-op. @end deffn The control interface is protected by three access control lists (@xref{ACL}, for a discussion of their syntax). -@deffn {Config: control} acl - Controls who can connect to the control interface. +@deffn {Config: control} acl @var{name} +@deffnx {Config: control} acl @{ @dots{} @} + Controls who can connect to the interface. The first form refers to +a named ACL that must have been defined earlier by @code{defacl} +statement (@pxref{defacl}). Use the second form to define a new ACL +in place. @end deffn -@deffn {Config: control} user-acl +@deffn {Config: control} user-acl @var{name} +@deffnx {Config: control} user-acl @{ @dots{} @} Control interface provides two kinds of operations: @dfn{read-only} (such as getting information about running components) and @dfn{write} operations (such as stopping or restarting components). - The @code{user-acl} controls read access to components that don't -have per-component @code{user-acl} (@FIXME-pxref{per-component user-acl}). + The @code{user-acl} controls read access. Access to particular +components can also be controlled individually, using the +per-component @code{list-acl} statement (@pxref{Visibility, list-acl}). @end deffn -@deffn {Config: control} admin-acl - Defines access control list for write access to the @command{pies} -instance itself and to the components for which no specific -@code{admin-acl} statements are supplied (@FIXME-pxref{per-component -admin-acl}). +@deffn {Config: control} admin-acl @var{name} +@deffnx {Config: control} admin-acl @{ @dots{} @} + Controls write access to the @command{pies} instance itself and to +the components for which no specific @code{admin-acl} statements are +supplied (@pxref{Visibility, admin-acl}). In particular, whoever passes @code{admin-acl} can issue commands for stopping the instance and reloading its configuration. @end deffn + When checking whether the user has a particular kind of access to a +component, first the corresponding ACL from the @code{control} section +is checked. If it allows access, then the per-component ACL is tried. +If it allows access too, then the operation is permitted. + @deffn {Config: control} realm @var{name} Defines the realm for basic authentication. Default value is @samp{pies}. @end deffn @node inetd @section Using @command{inetd} Configuration Files @@ -2451,12 +2467,21 @@ Sets the PID file name. @end deffn @deffn {Config} qotd-file @var{file-name} Sets the name of the @samp{quotation-of-the-day} file. @end deffn +The following statements are retained for compatibility with earlier +@command{pies} versions. They are silently ignored: + +@deffn {Config} control-file @var{arg} +@end deffn + +@deffn {Config} stat-file @var{arg} +@end deffn + @node Pies Debugging @chapter Pies Debugging @xopindex{debug, described} The amount of debugging information produced by @command{pies} is configured by the following statements: @@ -2570,14 +2595,15 @@ UNIX socket for communication using @command{piesctl}. @end table @menu * Runlevels:: * Init Process Configuration:: * Init Command Line:: -* piesctl telinit:: * Init Environment:: +* piesctl telinit:: +* telinit command:: @end menu @node Runlevels @section Runlevels Runlevel determines the set of components to be run in normal state. @@ -2596,13 +2622,13 @@ Multiuser mode. Multiuser with X11. @end table @anchor{Ondemand runlevels} Additionally, three special runlevels @samp{a}, @samp{b} and @samp{c} can be used to start @dfn{on-demand} components without actually -changing the runlevel. Once started, on-demain components persist +changing the runlevel. Once started, on-demain components persist through eventual runlevel changes. @node Init Process Configuration @section Init Process Configuration @anchor{inittab} The two configuration files are read in this order: @@ -2753,24 +2779,45 @@ The default set up is equivalent to specifying Stop parsing after this line. The remaining material is ignored. @end table Both the traditional @file{/etc/inittab} and pies-native @file{/etc/pies.init} files are entirely equivalent, excepting that, naturally, the latter is more flexible and gives much more -possibilities in defining the system behavior. The inittab entry -discussed above is equivalent to the following statement in -@file{pies.init} file: +possibilities in defining the system behavior. The declaration of a +component in @file{/etc/pies.init} can contain all the statements +discussed in @ref{Component Statement}. The only difference is that +runlevels to start the component is must be specified: + +@deffn {Config: component} runlevels @var{string} +Specifies the runlevel to start the component in. The @var{string} +argument is a string of runlevel characters. +@end deffn + +For example, the inittab entry discussed above is equivalent to the +following statement in @file{pies.init} file: @example component @var{id} @{ mode @var{mode}; runlevels @var{runlevels}; command @var{command}; @} @end example +The default runlevel is specified in @file{/etc/pies.init} using +the following construct: + +@deffn {Config} initdefault @var{rl} +Declare the default runlevel. The argument is the runlevel name. +E.g. + +@example +initdefault 3; +@end example +@end deffn + If both @file{/etc/inittab} and @file{/etc/pies.init} are present, the latter can declare components with the same @var{id} as the ones declared in the former. In that case, the two entries will be merged, the latter one overriding the former. Thus, @file{/etc/pies.init} can be used to complement definitions in @file{inittab}. Consider, for example the following inittab entry: @@ -2819,12 +2866,38 @@ Initialize default runlevel @samp{S}. @item -b @itemx emergency Run emergency shell @command{/sbin/sulogin}, prior to initialization. @end table +@node Init Environment +@section Init Environment + +Programs run from @command{pies} init process inherit a basic +environment consisting of the following variables: + +@table @option +@item PREVLEVEL=@var{L} +Previous runlevel, or letter @samp{N} if the runlevel hasn't been +changed since startup. + +@item RUNLEVEL=@var{L} +Current runlevel. + +@item CONSOLE=@var{device} +Pathname of the console device file. + +@item INIT_VERSION="GNU Pies @value{VERSION}" +Version of @command{pies}. + +@item PATH=/bin:/usr/bin:/sbin:/usr/sbin +@end table + +Once the system is booted up, the environment can be controlled using +the @command{piesctl telinit environ} (or @command{pies -T -e}) command. + @node piesctl telinit @section piesctl telinit @deffn {Telnit Runlevel} piesctl telinit runlevel Report the runlevel and state of the process 1. @end deffn @@ -2844,37 +2917,78 @@ hold at most 32 variables. @end deffn @deffn {Telinit Env} piesctl telinit environ unset @var{NAME} Unset variable @var{NAME}. @end deffn -@node Init Environment -@section Init Environment +@node telinit command +@section The Telinit Command -Programs run from @command{pies} init process inherit a basic -environment consisting of the following variables: +@xopindex{telinit option, introduced} + When given the @option{-T} (@option{--telinit}) option, +@command{pies} emulates the behavior of the traditional +@command{telinit} command. This is a legacy way of communicating with +the init process. The commands are sent via named pipe +@file{/dev/initctl}. When the @option{-T} option is given, the rest +of command line after it is handled as @command{telinit} options. The +following command: -@table @option -@item PREVLEVEL=@var{L} -Previous runlevel, or letter @samp{N} if the runlevel hasn't been -changed since startup. +@example +pies -T [-t @var{n}] @var{r} +@end example -@item RUNLEVEL=@var{L} -Current runlevel. +@noindent +tells init process to switch to runlevel @var{r}. Possible values for +@var{r} are: -@item CONSOLE=@var{device} -Pathname of the console device file. +@table @asis +@item 0 to 9 +Instructs init to switch to the specified runlevel. +@item S or s +Tells init to switch to the single user mode. +@item a, b, or c +Tells init to enable on-demand components with the specified +runlevel. The actual runlevel is not changed. +@item Q or q +Tells init to rescan configuration files. +@end table -@item INIT_VERSION="GNU Pies @value{VERSION}" -Version of @command{pies}. +The @option{-t} (@option{--timeout}) option sets the time to wait +for processes to terminate after sending them the SIGTERM signal. Any +processes that remain running after @var{n} seconds will be sent the +SIGKILL signal. The default value is 5 seconds. -@item PATH=/bin:/usr/bin:/sbin:/usr/sbin -@end table +This usage is equivalent to the @command{piesctl telinit runlevel} +command (@pxref{piesctl telinit}). -Once the system is booted up, the environment can be controlled using -the @command{piesctl telinit environ} command. +The @option{-e} (@option{--environment}) option modifies the init +process environment. Its argument is either a variable assignment +@samp{@var{name}=@var{value}} to set a variable, or the name of a +variable to unset it. Several @option{-e} options can be given to +process multiple variables in a single command. Note, however, that +given @var{n} @option{-e} options, the total length of their arguments +is limited to 367 - @var{n} bytes. + +This option provides a limited subset of the functionality offered by +the @command{piesctl telinit environ} command. + +The table below summarizes all options available in @option{telinit} +mode: + +@table @option +@item -t @var{n} +Wait @var{n} seconds for processes to terminate after sending them the +SIGTERM signal. Any processes that remain running after that time +will be sent the SIGKILL signal. The default value is 5 seconds. + +@item -e @var{var}=@var{value} +Define environment variable @var{var} as having value @var{value}. + +@item -e @var{var} +Unset environment variable @var{var}. +@end table @node Configuration Examples @chapter Configuration Examples In this section we provide several examples of working @command{pies} configuration files. @@ -3240,12 +3354,19 @@ arguments, dependencies for each component are listed. @xref{trace-depend}. @opsummary{trace-prereq} @item --trace-prereq List prerequisites for components named in the command line. Without arguments, prerequisites for each component are listed. @xref{trace-prereq}. +@opsummary{telinit} +@item --telinit +@item -T +Emulate the @command{telinit} legacy interface. The rest of command +line following this option is processed as @command{telinit} options. +@xref{telinit command}, for a detailed description of these. + @item -E Preprocess configuration file and exit. @xref{Preprocessor}. @opsummary{force} @item --force Force startup even if another instance may be running. diff --git a/src/.gitignore b/src/.gitignore index a83b9ab..3bf90ef 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -5,6 +5,7 @@ meta1gram.h meta1gram.output meta1lex.c pies pies.rc piesctl piesctl-cl.h +telinit.h diff --git a/src/Makefile.am b/src/Makefile.am index 6515804..b0e9b6f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -38,26 +38,28 @@ pies_SOURCES = \ noinst_HEADERS = \ acl.h\ cmdline.h\ meta1parse.h\ pies.h\ prog.h\ - piesctl-cl.h + piesctl-cl.h\ + telinit.h -BUILT_SOURCES=cmdline.h piesctl-cl.h +BUILT_SOURCES=cmdline.h piesctl-cl.h telinit.h incdir=$(pkgdatadir)/$(VERSION)/include inc_DATA = pp-setup -EXTRA_DIST = cmdline.opt piesctl-cl.opt pp-setup inetd.in +EXTRA_DIST = cmdline.opt piesctl-cl.opt telinit.opt pp-setup inetd.in SUFFIXES=.opt .c .h .opt.h: $(AM_V_GEN)m4 -s $(top_srcdir)/@GRECS_SUBDIR@/build-aux/getopt.m4 $< > $@ cmdline.h: cmdline.opt piesctl-cl.h: piesctl-cl.opt +telinit.h: telinit.opt pies_LDADD = \ ../ident/libident.a\ ../lib/libpies.a\ @GRECS_LDADD@\ ../gnu/libgnu.a\ diff --git a/src/cmdline.opt b/src/cmdline.opt index 7d6f7d4..d8bd02f 100644 --- a/src/cmdline.opt +++ b/src/cmdline.opt @@ -109,17 +109,17 @@ OPTION(lint,t,, [<parse configuration file and exit>]) BEGIN log_to_stderr_only = 1; lint_mode = 1; END -OPTION(telinit,T,RUNLEVEL, - [<emulate telinit command>]) +OPTION(telinit,T,, + [<telinit command: run "pies -T --help" for help>]) BEGIN log_to_stderr_only = 1; - exit (telinit (optarg)); + exit (telinit (argc - (optind - 1), argv + (optind - 1))); END GROUP(Preprocessor) OPTION(include-directory,I,DIR, [<add include directory>]) @@ -532,13 +532,13 @@ struct inetd_builtin *inetd_builtin_lookup (const char *service, int socktype); /* sysvinit.c */ void sysvinit_begin (void); int is_comp_wait (struct component *comp); int is_valid_runlevel (int c); int console_open (int mode); -int telinit (const char *arg); +int telinit (int argc, char **argv); int inittab_parse (const char *file); int sysvinit_sigtrans (int sig, int *pact); void sysvinit_runlevel_setup (int mask); void sysvinit_sysdep_begin (void); void sysvinit_power (void); diff --git a/src/sysvinit.c b/src/sysvinit.c index a150058..9043619 100644 --- a/src/sysvinit.c +++ b/src/sysvinit.c @@ -526,12 +526,14 @@ sysvinit_fifo_handler (int fd, void *data) if (buf.req.magic != INIT_MAGIC) logmsg (LOG_ERR, _("got invalid initreq")); else { debug (1, ("INITREQ: cmd=%d, runlevel=%d, sleeptime=%d", buf.req.cmd, buf.req.runlevel, buf.req.sleeptime)); + if (buf.req.sleeptime > 0) + shutdown_timeout = buf.req.sleeptime; switch (buf.req.cmd) { case INIT_CMD_RUNLVL: buf.req.runlevel = toupper (buf.req.runlevel); switch (buf.req.runlevel) { @@ -904,49 +906,43 @@ is_comp_wait (struct component *comp) return 1; default: break; } return 0; } - + +#include "telinit.h" + int -telinit (const char *arg) +telinit (int argc, char **argv) { int fd; struct sysvinit_request req; - - if (arg[1] || !is_valid_runlevel (*arg)) - { - logmsg (LOG_CRIT, "invalid argument"); - exit (EX_USAGE); - } + memset (&req, 0, sizeof (req)); req.magic = INIT_MAGIC; - req.cmd = INIT_CMD_RUNLVL; - req.runlevel = *arg; -#if 0 - req.sleeptime = sltime; -#endif + + telinit_parser (&req, argc, argv); signal (SIGALRM, SIG_DFL); alarm (5); fd = open (init_fifo, O_WRONLY); if (fd < 0) { logmsg (LOG_ERR, _("cannot open %s: %s"), init_fifo, strerror (errno)); - exit (EX_UNAVAILABLE); + return EX_UNAVAILABLE; } if (write (fd, &req, sizeof (req)) != sizeof (req)) { logmsg (LOG_ERR, _("error writing to %s: %s"), init_fifo, strerror (errno)); - exit (EX_UNAVAILABLE); + return EX_UNAVAILABLE; } alarm (0); close (fd); - exit (0); + return 0; } static char * getfld (char *str, char **endp) { char *p; diff --git a/src/telinit.opt b/src/telinit.opt new file mode 100644 index 0000000..f052a53 --- /dev/null +++ b/src/telinit.opt @@ -0,0 +1,89 @@ +/* This file is part of GNU Pies. -*- c -*- + Copyright (C) 2016 Sergey Poznyakoff + + GNU Pies is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + GNU Pies is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Pies. If not, see <http://www.gnu.org/licenses/>. */ + +OPTIONS_COMMAND_BEGIN("pies", + [<>], + [<send command to init process via the legacy interface>], + [<[RUNLEVEL]>], + [<gnu>], + [<noversion>]) + +OPTION(timeout,t,[<SECONDS>], + [<set interval between sending TERM and KILL signals>]) +BEGIN + char *p; + errno = 0; + shutdown_timeout = strtoul (optarg, &p, 0); + if (*p || errno) + { + logmsg (LOG_ERR, _("invalid number: %s"), optarg); + exit (EX_USAGE); + } +END + +OPTION(environment,e,[<VAR=[VAL]>],[<change environment>]) +BEGIN + size_t len = strlen (optarg); + if (envsize + len + 2 > sizeof(req->data)) + { + logmsg (LOG_ERR, _("-e argument too long")); + exit (EX_USAGE); + } + memcpy (req->data + envsize, optarg, len); + envsize += len; + req->data[envsize++] = 0; +END + +OPTIONS_END + +static void +telinit_parser (struct sysvinit_request *req, int argc, char *argv[]) +{ + int i; + char *cmds[] = { "-T", NULL }; + size_t envsize = 0; + + proginfo.subcmd = cmds; + GETOPT(argc, argv, i); + argc -= i; + argv += i; + if (envsize) + { + req->data[envsize++] = 0; + req->cmd = INIT_CMD_SETENV; + if (argc) + { + logmsg (LOG_ERR, _("too many arguments")); + exit (EX_USAGE); + } + } + else + { + if (argc != 1) + { + logmsg (LOG_ERR, _("bad number of arguments")); + exit (EX_USAGE); + } + if (argv[0][1] || !is_valid_runlevel (argv[0][0])) + { + logmsg (LOG_ERR, _("invalid runlevel: %s"), argv[0]); + exit (EX_USAGE); + } + req->cmd = INIT_CMD_RUNLVL; + req->runlevel = argv[0][0]; + req->sleeptime = shutdown_timeout; + } +} |