Compare commits

..
11 Commits
Author SHA1 Message Date
Joachim Wiberg 58e31dbd22 .github: try running with older Ubuntu version
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-06 19:57:46 +02:00
Joachim Wiberg 85058b54a8 plugins: bootmisc: use relative symlink for /var/run
In an upside world, much like the Finit test cases, the root may be
relocated.  This make /var/run relative to /var, instead of /.  Which
hopefully is safer and covers more use-cases.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-05 17:46:43 +02:00
Joachim Wiberg f16df142d7 Minor shellcheck fixes to debug code
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-05 17:46:20 +02:00
Joachim Wiberg f9f52a46a6 Debug sys plugin
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-05 07:27:22 +02:00
Joachim Wiberg ef1bfb869f test: HUP Finit from inside container instead ...
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-05 06:49:52 +02:00
Joachim Wiberg 5002c74876 test: force enable debug logs and HUP Finit before test
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-05 06:39:23 +02:00
Joachim Wiberg a0bc23c48f test: enable finit debug to see why API socket isn't created
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-04 20:52:08 +02:00
Joachim Wiberg 350cf6e578 test: dump contents of /var/run/finit/ to check for socket
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-04 20:46:48 +02:00
Joachim Wiberg b96a8d8766 test: dump correct root dir and add more PID 1 debug
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-04 20:31:13 +02:00
Joachim Wiberg a419828dea .github: no ~/.cache, check rest
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-04 20:22:05 +02:00
Joachim Wiberg 702b22d4a3 .github: check if ~/.cache exists, dump test root files
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-04 20:19:13 +02:00
159 changed files with 1026 additions and 3311 deletions
+3 -3
View File
@@ -29,11 +29,11 @@ jobs:
sudo apt-get -y update
sudo apt-get -y install pkg-config
wget https://github.com/troglobit/libuev/releases/download/v2.3.2/libuev-2.3.2.tar.xz
wget https://github.com/troglobit/libite/releases/download/v2.5.2/libite-2.5.2.tar.gz
wget https://github.com/troglobit/libite/releases/download/v2.3.1/libite-2.3.1.tar.gz
tar xf libuev-2.3.2.tar.xz
tar xf libite-2.5.2.tar.gz
tar xf libite-2.3.1.tar.gz
(cd libuev-2.3.2 && ./configure --prefix=/usr && make && sudo make install-strip)
(cd libite-2.5.2 && ./configure --prefix=/usr && make && sudo make install-strip)
(cd libite-2.3.1 && ./configure --prefix=/usr && make && sudo make install-strip)
sudo ldconfig
- uses: actions/checkout@v2
- name: Static Finit
+1 -1
View File
@@ -3,7 +3,7 @@ name: Release General
on:
push:
tags:
- '[0-9]+.[0-9]+*'
- '[0-9]+.[0-9]+'
jobs:
release:
+6 -95
View File
@@ -4,93 +4,20 @@ Change Log
All relevant changes are documented in this file.
[4.3][] - 2022-05-15
[4.3][UNRELEASED]
--------------------
Critical bug fix release. If you run a 32-bit target with GLIBC 2.34
you *need* to upgrade!
> **Note:** system verbosity on console at start and shutdown has been
> increased. Now the output of all commands is logged to the
> system logger, for early services `/dev/kmsg` is used.
>
> **Also:** please notice the updated support for enabling and disabling
> kernel and Finit debug messages on the system console. Very
> useful when debugging either of them, e.g., a kernel module.
> For details, see [cmdline.md](doc/cmdline.md).
### Changes
* Support for overriding default runlevel from kernel command line. Any
runlevel `[1-9]` may be selected, except 6 (reboot). Issue #261
* New command line option: `finit.fstab=/etc/fstab.custom`, with full
support for mounting, mount helpers, fsck, and swapon/off, issue #224
* Support for special device `/dev/root`, which may not exist in `/dev`.
Finit now looks up the matching block device for `/` in `/sys/block/`
* Loading `module`s no longer shows arguments in progress output
* Warning messages in progress output now in yellow, not red, issue #214
* `initctl`, new command line option `-V,--version` for ease of use
* Warning messages in progress output now in yellow, not red, issue 214
* `initctl`, new command line option `-v,--version` for ease of use
* Extended environment variables for pre/post scripts, issue #189
* New condition `done` for run task, issue #207 by Ming Liu, Atlas Copco
* Refactor parts of shutdown and reboot sequence for PREEMPT-RT kernels,
by Robert Andersson, Mathias Thore, and Ming Liu, Atlas Copco
* Conditions for run/task/sysv status, e.g. `run/foo/success` and
`task/bar/failure`. Issue #232, by Ming Liu, Atlas Copco
* Conditions for services, can be used to synchronize other stanzas:
- `service/foo/running`
- `service/foo/halted`
- `service/foo/missing`
- `service/foo/crashed`
- `service/foo/stopped`
- `service/foo/busy`
- `service/foo/restart`
* `initctl signal` support, by Jörgen Sigvardsson, issue #225
* `initctl cond get` support to match `cond [set | clear]`, issue #255
* `[WARN]` messages on console now printed in yellow, issue #214
* Network services now also stopped when going to runlevel 6 (reboot),
not just runlevel 0 (shutdown) or 1 (single-user)
* When `ifup` is missing on the system, bring at least `lo` up at boot
* Log output from `ifup -a` (and `ifdown -a`), to syslog
* Avoid blocking PID 1 when starting SysV init scripts
* Allow custom `pid:` for SysV init scripts
* Document supported types of forking/non-forking services
* Auto-detect running in some common forms of containers
* Simplify shutdown/reboot when running in a container
* Log to `stderr` when running in a container w/o syslog daemon
* Add support for `type:forking` to services, already supported but
with a very difficult `pid:` syntax, issue #223. Docs updated
* Support for setting global environment variables in `finit.conf`,
please note: this also affects Finit itself, be careful!
* Extended environment variables for pre/post scripts, issue #189
* Document secret service option `respawn`, which bypasses the crash
semantics, allowing endless restarts
* Document secret `HOOK_BANNER`, the first hook point before the banner
* Document slightly confusing `initctl reload foo` command. It does
*not* reload the service's `.conf` file! Issue #263
* Log changes; all instances where previously the `basename cmd` of a
service was used to identify the service, now the proper `name:id` is
used instead. Meaning, a service without a custom `:ID` or `name:`
will display the same as before, but with any of those customizations
the name and name:id will now be shown. **Note:** this may affect any
log scrapers out there!
* New plugin: `hook-scripts`, allows [run-parts(8)][] style scripts to
run on any hook point. Contributed by Tobias Waldekranz
* `initctl` (`reboot`) falls back to `-f` when it detects it is in
`sulogin` recovery mode, issue #247
* The bundled `sulogin` is no longer enabled by default, in favor of
distribution versions. Enable with `./configure --with-sulogin`
* Support args to sysv-like scripts, e.g. `bridge-stp br0 start`
* The `modules-load` plugin now skips all lines starting with `#` and
`;`. Furthermore, files in `/etc/modules-load.d/*.conf` are now read
in lexicographic order and UNIX backup files (`foo.conf~`) are skipped
* The `name:id` tuple is now more consistently used in all log and debug
messages instead of the basename of the command
* Simplify error output of `initctl start/stop/restart/signal`, no more
extra usage help, just a plain error message
* Exit codes of `initctl` have changed to use LSB script standard and BSD
sysexits.h exit codes. As before, a non-zero exit is error or missing
* Add support for `initctl -q` to more commands: stop, start, restart,
reload, signal, etc.
[run-parts(8)]: https://manpages.debian.org/cgi-bin/man.cgi?query=run-parts
### Fixes
* Fix nasty 32/64-bit alignment issue between finit and its plugins,
@@ -100,22 +27,6 @@ you *need* to upgrade!
or does not have the required controllers (cpu)
* Fix #217: iwatcher initialization issue, by Ming Liu, Atlas Copco
* Fix #218: initctl matches too many services, by Ming Liu, Atlas Copco
* Fix #219: not all filesystems unmounted at shutdown, by Ming Liu,
Mathias Thore, and Robert Andersson, Atlas Copco
* Fix #226: initctl shows wrong PID for crashing services
* Fix #227: reboot stalls if process stopped with `[WARN]`
* Fix #233: initctl shows wrong status for run/task, by Sergio Morlans
and Ming Liu, Atlas Copco
* Fix #248: source `env:file` also in `pre:` and `post` scripts
* Fix #260: drop limit on device name in `Checking filesystem...` output
* Fix start/stop and monitoring (restart) of SysV init scripts and
forking services, see the updated documentation for details
* Fix call to `swapoff` at shutdown, does not support `-e` flag
* Fix suspend to RAM issue. Previously `reboot(RB_SW_SUSPEND)` was
used, now the modern `/sys/power/state` API is used instead.
* Fix nasty run/task/service matcher bug, triggered by stanzas using the
same basename of a command but different `:ID`. Caused Finit to match
with already registered but different run/task/service
[4.2][] - 2022-01-16
@@ -870,7 +781,7 @@ The inetd release.
### Changes
* Add support for built-in inetd super server -- launch services on
demand. Supports filtering per interface and custom Inet ports.
* Upgrade to [libuEv][] v1.1.0 to better handle error conditions.
* Upgrade to [libuEv] v1.1.0 to better handle error conditions.
* Allow mixed case config directives in `finit.conf`
* Add support for RFC 868 (rdate) time plugin, start as inetd service.
* Load plugins before parsing `finit.conf`, this makes it possible to
@@ -901,7 +812,7 @@ The inetd release.
[1.11][] - 2015-01-24 [YANKED]
------------------------------
The [libuEv][] release.
The [libuEv] release.
**Note:** This release has been *yanked* from distribution due to a
regression in launching background processes and TTY's. Fixed in
+1 -1
View File
@@ -1,5 +1,5 @@
Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
Copyright (c) 2008-2022 Joachim Wiberg <troglobit@gmail.com>
Copyright (c) 2008-2021 Joachim Wiberg <troglobit@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
-2
View File
@@ -29,5 +29,3 @@ release: distcheck
printf "$$file.md5\t"; cat ../$$file.md5 | cut -f1 -d' '; \
printf "$$file.sha256\t"; cat ../$$file.sha256 | cut -f1 -d' '; \
done
DISTCHECK_CONFIGURE_FLAGS = --with-fstab=/etc/fstab
+9 -41
View File
@@ -45,10 +45,6 @@ Features include:
* Cgroups v2, both configuration and monitoring in `initctl top`
* Plugin support for customization
* Proper rescue mode with bundled `sulogin` for protected maintenance shell
* Integration with [watchdogd][] for full system supervision
* Logging to kernel ring buffer before `syslogd` has started, see the
recommended [sysklogd][] project for complete logging integration
and how to log to the kernel ring buffer from scripts using `logger`
Focus is on small and embedded systems, although Finit is fully usable
on server and desktop systems as well. For working examples, see the
@@ -56,12 +52,7 @@ on server and desktop systems as well. For working examples, see the
* [Void Linux](contrib/void/),
* [Alpine Linux](contrib/alpine/), and
* [Debian GNU/Linux](contrib/debian/), also works on Ubuntu/Linux Mint
> **Note:** support for various Linux distributions does not mean Finit
> installs easily on all architectures. The bundled install scripts are
> examples for standard installations, tested on amd64 (x86_64) systems.
> Custom setups, for embedded systems, can be found in [myLinux][].
* [Debian GNU/Linux](contrib/debian/)
Example
@@ -77,11 +68,7 @@ the [initctl](#commands--status) tool.
host default
# Runlevel to start after bootstrap, 'S', default: 2
#runlevel 2
# Support for setting global environment variables, using foo=bar syntax
# be careful though with variables like PATH, SHELL, LOGNAME, etc.
#PATH=/usr/bin:/bin:/usr/sbin:/sbin
runlevel 2
# Max file size for each log file: 100 kiB, rotate max 4 copies:
# log => log.1 => log.2.gz => log.3.gz => log.4.gz
@@ -110,11 +97,6 @@ service :8080 [2345] merecat -n -p 8080 /var/www -- Old web server
#sysv [S] /etc/init.d/acpid -- Starting ACPI Daemon
#task [S] /etc/init.d/kbd -- Preparing console
# Hidden from boot progress, using empty `--` description
#sysv [S] /etc/init.d/keyboard-setup --
#sysv [S] /etc/init.d/acpid --
#task [S] /etc/init.d/kbd --
# Run start scripts from this directory
# runparts /etc/start.d
@@ -281,8 +263,8 @@ unnecessary overhead, which can be removed at build-time using:
**Cgroups**
Finit supports cgroups v2 and comes with the following default groups in
which services and user sessions are placed in:
Finit supports cgroups v2 and comes with the following default groups
in which services and user sessions are placed in:
/sys/fs/cgroup
|-- init/ # cpu.weight:100
@@ -318,10 +300,6 @@ The `initctl` tool has three commands to help debug and optimize the
setup and monitoring of cgroups. See the `ps`, `top`, and `cgroup`
commands for details.
> **Note:** systems that do not support cgroups, specifically version 2,
> are automatically detected. On such systems the above functionality
> is disabled early at boot.
Runparts & /etc/rc.local
------------------------
@@ -431,24 +409,24 @@ services, called `initctl`. Unlike `telinit` the `initctl` tool does
not return until the given command has fully completed.
```
alpine:~# initctl help
Usage: initctl [OPTIONS] [COMMAND]
Options:
-b, --batch Batch mode, no screen size probing
-c, --create Create missing paths (and files) as needed
-f, --force Ignore missing files and arguments, never prompt
-h, --help This help text
-1, --once Only one lap in commands like 'top'
-p, --plain Use plain table headings, no ctrl chars
-q, --quiet Silent, only return status of command
-t, --no-heading Skip table headings
-v, --verbose Verbose output
-V, --version Show program version
-h, --help This help text
Commands:
debug Toggle Finit (daemon) debug
help This help text
version Show program version
version Show Finit version
ls | list List all .conf in /etc/finit.d
create <CONF> Create .conf in /etc/finit.d/available
@@ -461,20 +439,15 @@ Commands:
reload Reload *.conf in /etc/finit.d (activate changes)
cond set <COND> Set (assert) user-defined condition +usr/COND
cond get <COND> Get status of user-defined condition, see $? and -v
cond clear <COND> Clear (deassert) user-defined condition -usr/COND
cond status Show condition status, default cond command
cond dump [TYPE] Dump all, or a type of, conditions and their status
cond dump Dump all conditions and their status
log [NAME] Show ten last Finit, or NAME, messages from syslog
start <NAME>[:ID] Start service by name, with optional ID
stop <NAME>[:ID] Stop/Pause a running service by name
reload <NAME>[:ID] Reload service as if .conf changed (SIGHUP or restart)
This allows restart of run/tasks that have already run
Note: Finit .conf file(s) are *not* reloaded!
reload <NAME>[:ID] Reload service by name (SIGHUP or restart)
restart <NAME>[:ID] Restart (stop/start) service by name
signal <NAME>[:ID] <S> Send signal S to service by name, with optional ID
ident [NAME] Show matching identities for NAME, or all
status <NAME>[:ID] Show service status, by name
status Show status of services, default command
@@ -487,8 +460,6 @@ Commands:
halt Halt system
poweroff Halt and power off system
suspend Suspend system
utmp show Raw dump of UTMP/WTMP db
```
For services *not* supporting `SIGHUP` the `<!>` notation in the .conf
@@ -627,9 +598,6 @@ and proposed extensions.
[Joachim Wiberg]: https://troglobit.com
[License]: https://en.wikipedia.org/wiki/MIT_License
[License Badge]: https://img.shields.io/badge/License-MIT-teal.svg
[myLinux]: https://github.com/troglobit/myLinux/
[watchdogd]: https://github.com/troglobit/watchdogd/
[sysklogd]: https://github.com/troglobit/sysklogd/
[GitHub]: https://github.com/troglobit/finit/actions/workflows/build.yml/
[GitHub Status]: https://github.com/troglobit/finit/actions/workflows/build.yml/badge.svg
[Coverity Scan]: https://scan.coverity.com/projects/3545
+4 -41
View File
@@ -1,4 +1,4 @@
AC_INIT(Finit, 4.3, https://github.com/troglobit/finit/issues, finit, https://troglobit.com/projects/finit/)
AC_INIT(Finit, 4.3-dev, https://github.com/troglobit/finit/issues, finit, https://troglobit.com/finit.html)
AC_CONFIG_AUX_DIR(aux)
AM_INIT_AUTOMAKE([1.11 foreign dist-xz subdir-objects])
AM_SILENT_RULES([yes])
@@ -33,8 +33,8 @@ AC_PROG_MKDIR_P
# Configuration.
AC_HEADER_STDC
AC_CHECK_HEADERS([termios.h sys/ioctl.h mntent.h sys/sysmacros.h])
AC_CHECK_FUNCS([strstr getopt getmntent getmntent_r])
AC_CHECK_HEADERS([fstaby.h termios.h sys/ioctl.h])
AC_CHECK_FUNCS([strstr getopt getfsenty])
# Check for uint[8,16,32]_t
AC_TYPE_UINT8_T
@@ -90,17 +90,12 @@ AC_PLUGIN([modprobe], [yes], [Coldplug modules using modalias magic])
AC_PLUGIN([resolvconf], [no], [Setup necessary files for resolvconf])
AC_PLUGIN([x11-common], [no], [Console setup (for X)])
AC_PLUGIN([netlink], [yes], [Basic netlink plugin for IFUP/IFDN and GW events. Can be replaced with externally built plugin that links with libnl or similar.])
AC_PLUGIN([hook-scripts], [no], [Trigger script execution from hook points])
AC_PLUGIN([hotplug], [yes], [Setup and start udev or mdev hotplug daemon])
AC_PLUGIN([rtc], [yes], [Save and restore RTC using hwclock])
AC_PLUGIN([tty], [yes], [Automatically activate new TTYs, e.g. USB-to-serial])
AC_PLUGIN([urandom], [yes], [Setup and save random seed at boot/shutdown])
# Check for extra arguments or packages
AC_ARG_WITH(fstab,
AS_HELP_STRING([--with-fstab=FILE], [System default fstab, default $sysconfdir/fstab]),
[fstab=$withval], [fstab=yes])
AC_ARG_WITH(heading,
AS_HELP_STRING([--with-heading=GREET], [Heading for boot progress. Default: PRETTY_NAME from /etc/os-release, fallback to "Finit vX.YY"]),
[heading=$withval], [heading=yes])
@@ -130,7 +125,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 [1-9], default: 2]),
AS_HELP_STRING([--with-runlevel=N], [Runlevel to switch to after bootstrap, default: 2]),
[runlevel=$withval], [runlevel=yes])
AC_ARG_WITH(random-seed,
@@ -140,21 +135,10 @@ AC_ARG_WITH(random-seed,
AC_ARG_WITH(keventd,
AS_HELP_STRING([--with-keventd], [Enable built-in keventd, default: no]),, [with_keventd=no])
AC_ARG_WITH(sulogin,
AS_HELP_STRING([--with-sulogin], [Enable built-in sulogin, default: no.]),, [with_sulogin=no])
AC_ARG_WITH(watchdog,
AS_HELP_STRING([--with-watchdog=[DEV]], [Enable built-in watchdog, default: /dev/watchdog]),
[watchdog=$withval], [with_watchdog=no watchdog=])
AC_ARG_WITH(hook-scripts-path,
AS_HELP_STRING([--with-hook-scripts-path=DIR], [Base directory for hook scripts, default $libexecdir/finit/hook]),
[hook_scripts_path=$withval], [hook_scripts_path=yes])
AC_ARG_WITH(plugin-path,
AS_HELP_STRING([--with-plugin-path=DIR], [Search path for external plugins, default /usr/lib/finit/plugins:/usr/local/lib/finit/plugins]),
[plugin_path=$withval], [plugin_path=yes])
### Enable features ###########################################################################
# Create config.h from selected features and fallback defaults
@@ -180,12 +164,6 @@ AS_IF([test "x$enable_logrotate" != "xno"], [
AM_CONDITIONAL(LOGROTATE, [test "x$enable_logrotate" = "xyes"])
### With features ##############################################################################
AS_IF([test "x$with_fstab" != "xno"], [
AS_IF([test "x$fstab" = "xyes"], [fstab=$sysconfdir/fstab])
AC_EXPAND_DIR(fstab_path, "$fstab")
AC_DEFINE_UNQUOTED(FINIT_FSTAB, "$fstab_path", [Built-in default: /etc/fstab])],[
AC_DEFINE_UNQUOTED(FINIT_FSTAB, NULL, [No built-in default fstab])])
AS_IF([test "x$with_config" != "xno"], [
AS_IF([test "x$conf" = "xyes"], [
conf=$sysconfdir/finit.conf])])
@@ -240,8 +218,6 @@ AS_IF([test "x$with_random_seed" != "xno"], [
AS_IF([test "x$with_keventd" != "xno"], [with_keventd=yes])
AS_IF([test "x$with_sulogin" != "xno"], [with_sulogin=yes])
AS_IF([test "x$with_watchdog" != "xno"], [
AS_IF([test "x$watchdog" = "xyes"], [
watchdog=/dev/watchdog])
@@ -249,20 +225,9 @@ AS_IF([test "x$with_watchdog" != "xno"], [
AC_DEFINE_UNQUOTED(WDT_DEVNODE, "$watchdog", [Built-in watchdog device node])], [
watchdog=])
AS_IF([test "x$enable_hook_scripts_plugin" = "xyes" -a "x$with_hook_scripts_path" != "xno"], [
AS_IF([test "x$hook_scripts_path" = "xyes"], [hook_scripts_path=$libexecdir/finit/hook])
AC_EXPAND_DIR(hook_scripts_path, "$hook_scripts_path")
AC_DEFINE_UNQUOTED(PLUGIN_HOOK_SCRIPTS_PATH, "$hook_scripts_path", [Built-in default: $libexecdir/finit])])
AS_IF([test "x$with_plugin_path" != "xno"], [
AS_IF([test "x$plugin_path" = "xyes"], [plugin_path=/usr/lib/finit/plugins:/usr/local/lib/finit/plugins])
AC_EXPAND_DIR(plugin_path, "$plugin_path")
AC_DEFINE_UNQUOTED(EXTERNAL_PLUGIN_PATH, "$plugin_path", [Built-in default: /usr/lib/finit/plugins:/usr/local/lib/finit/plugins])])
# Control build with automake flags
AM_CONDITIONAL(STATIC, [test "x$enable_static" = "xyes"])
AM_CONDITIONAL(KEVENTD, [test "x$with_keventd" != "xno"])
AM_CONDITIONAL(SULOGIN, [test "x$with_sulogin" != "xno"])
AM_CONDITIONAL(WATCHDOGD, [test "x$with_watchdog" != "xno"])
AM_CONDITIONAL(DOC, [test "x$enable_doc" = "xyes"])
AM_CONDITIONAL(CONTRIB, [test "x$enable_contrib" = "xyes"])
@@ -296,7 +261,6 @@ cat <<EOF
Exec prefix...........: $eprefix
Sysconfdir............: `eval echo $sysconfdir`
Localstatedir.........: `eval echo $localstatedir`
Default fstab.........: `eval echo $fstab`
Finit config file.....: $conf_path
Finit config.d path...: $rcsd_path
Finit plugin path.....: $plugin_path
@@ -314,7 +278,6 @@ Optional features:
Install doc/..........: $enable_doc
Install contrib/......: $enable_contrib
Built-in keventd......: $with_keventd
Built-in sulogin......: $with_sulogin
Built-in watchdogd....: $with_watchdog $watchdog
Built-in logrotate....: $enable_logrotate
Skip fsck check.......: $enable_fastboot
-2
View File
@@ -1,8 +1,6 @@
Bootstrap
=========
0. Get bearings, disable kernel logs, initialize TTY and print banner,
unless `HOOK_BANNER` is defined, then call that instead
1. Prepare emergency shell, if enabled
2. Set up initial signal handlers
3. Set up default $PATH early
+9 -25
View File
@@ -29,8 +29,8 @@ optional plugins to enable. It depends on two external libraries:
The configure script checks for all dependencies, including the correct
version of the above mentioned libraries. Currently required versions:
- libite v2.2.0, or later
- libuEv v2.2.0, or later
- libite v2.2.0
- libuEv v2.2.0
Configure
@@ -54,7 +54,7 @@ Below are a few of the main switches to configure:
will be linked statically.
* `--enable-kernel-cmdline`: Enable Finit pre-4.1 parsing of init args from
`/proc/cmdline`, this is *not recommended* since Finit may be running as the
`/proc/cmdline`, this is not recommended since Finit may be running as the
init for container apps that can see the host's `/proc` filesystem
* `--enable-alsa-utils-plugin`: Enable the optional `alsa-utils.so` sound plugin.
@@ -65,19 +65,8 @@ Below are a few of the main switches to configure:
* `--enable-x11-common-plugin`: Enable the optional X Window `x11-common.so` plugin.
* `--with-sulogin`: Enable bundled `sulogin` program. Default is to use the
system `sulogin(8)`. The sulogin shipped with Finit *allows password-less*
login if the `root` user is disabled or has no password at all.
For more configure flags, see <kbd>./configure --help</kbd>
> **Note:** the configure script is not available in the GIT sources. It is
> however included in (officially supported) released tarballs. The
> idea is that you should not need GNU autotools to build, only the
> above mentioned dependencies, a POSIX shell, a C compiler and make.
> Any contributing to Finit can generate it from `configure.ac` using
> the `autogen.sh` script.
Example
-------
@@ -85,8 +74,8 @@ Example
First, unpack the archive:
```shell
$ tar xf finit-4.3.tar.gz
$ cd finit-4.3/
$ tar xf finit-4.1.tar.gz
$ cd finit-4.1/
```
Then configure, build and install:
@@ -102,7 +91,7 @@ $ make
$ DESTDIR=/tmp/finit make install
```
In this example the [finit-4.3.tar.gz][1] archive is unpacked to the
In this example the [finit-4.1.tar.gz][1] archive is unpacked to the
user's home directory, configured, built and installed to a temporary
staging directory. The environment variable `DESTDIR` controls the
destination directory when installing, very useful for building binary
@@ -157,22 +146,17 @@ enabled. The default Finit rescue mode configuration is installed into
By default the a root shell, without login, is started.
> **Note:** in this mode `initctl` will not work. Use the `-f` flag to
> force `reboot`, `shutdown`, or `poweroff`.
Debugging
---------
Edit, or append to, the kernel command line: remove `quiet` to enable
kernel messages and add `finit.debug` to enable Finit debug messages.
kernel messages and add `debug` to enable Finit debug messages.
```shell
append="init=/sbin/finit -- finit.debug"
append="init=/sbin/finit debug"
```
Notice the `--` separator.
To debug startup issues, in particular issues with getty/login, add
the following to your Finit .conf file:
@@ -191,6 +175,6 @@ it only for debugging start up issues when Finit crashes.
systems since they can potentially give a user root access.
[1]: ftp://troglobit.com/finit/finit-4.3.tar.gz
[1]: ftp://troglobit.com/finit/finit-4.1.tar.gz
[libuEv]: https://github.com/troglobit/libuev
[libite]: https://github.com/troglobit/libite
+6 -52
View File
@@ -10,43 +10,13 @@ The `bool` setting is one of `on, off, true false, 1, 0`.
> parameters to init. E.g., `init=/sbin/finit -- finit.debug rescue`
* `debug`: Enable kernel debug. Debug messages are printed to the
console until Finit starts up, unless `loglevel=7` (below) is used.
* `finit.cond=foo[,bar[,baz]]`: set `<boot/foo>` condition, optionally
multiple conditions can be set using the same option, separated with a
comma. Alternatively, multiple `foo.cond=arg` can be given. Each will
result in a `<boot/arg>` condition being set to control the rest of the
system bootstrap.
Very useful for selecting different boot modes, e.g. manufacturing test,
firmware upgrade, or rescue mode.
> Note: `<boot/...>` conditions cannot be cleared with `initctl`!
console until Finit starts up.
* `finit.debug[=bool]`: Enable finit debug. This is operated
independently of the kernel `debug` setting. New as of Finit v4.
independently of the kernel debug setting. New as of Finit v4.
* `finit.fstab=</path/to/etc/fstab.alternative>`: Tell Finit to use an
alternate `fstab` to mount the file system from. Remember, this file
must be on the `root=...` file system provided to Finit from the
kernel. By default the built-in fstab is used, which itself defaults
to `/etc/fstab`, but can be changed at build time with:
./configure --with-fstab=/path/to/fstab
It is even possible to disable a built-in default using:
./configure --without-fstab
Making `finit.fstab=/path/to/fstab` a *mandatory* command line option.
Note, if the command line fstab is missing, Finit falls back to the
built-in fstab, and if both are missing, the system treats this as a
bad `fsck` and thus calls `sulogin`. If, in turn, `sulogin` is not
available on the system, Finit calls reboot, which is also what will
happen when a user exits from `sulogin`.
* `finit.status[=bool]`: Control finit boot progress, including banner.
(Used to be `finit.show_status`, which works but is deprecated.)
* `finit.show_status[=bool]`: Control finit boot progress, including
banner.
* `finit.status_style=<classic,modern>`: Set Finit boot progress style,
when enabled.
@@ -56,18 +26,11 @@ The `bool` setting is one of `on, off, true false, 1, 0`.
signals and has no job control. Recommend using, and modifying,
`rescue` mode instead.
* `loglevel=<0-7>`, sets the kernel's log level, which is more granular
than `debug`. Also, when `loglevel=7`, Finit will *not disable*
kernel logs to the console. This is very useful when debugging the
kernel at system bring-up. Since `loglevel=7` is the same as `debug`
this means you have to use `quiet` for a quiet boot, until sysklogd
takes over logging of kernel events.
* `panic=SEC`: By default the kernel does not reboot after a kernel
panic. This setting will cause a kernel reboot after SEC seconds.
* `quiet`: Suppress kernel logging to console, except for warnings and
errors. Also, see `loglevel` and `quiet` above.
errors.
* `rescue`: Start rescue/maintenance mode. If your system comes with
the bundled `sulogin` program (Finit, or from util-linux/Busybox),
@@ -76,21 +39,12 @@ The `bool` setting is one of `on, off, true false, 1, 0`.
the system booted in a limited fallback mode. See [config.md][]
for more information.
**Note:** in this mode `initctl` will not work. Correct the problem
and use `reboot -f` to force reboot.
* `single`, or `S`: Single user mode, runlevel 1, in Finit. Useful to
debug problems with the regular runlevel. All services and TTYs in
`[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
[config.md][]: config.md#rescue-mode
[bootparam(7)]: https://www.man7.org/linux/man-pages/man7/bootparam.7.html
+5 -11
View File
@@ -46,16 +46,11 @@ Triggering
----------
Conditions are mainly triggered (asserted) by built-in plugins, e.g.,
- `netlink.so`: provides `<net/...>`
- `pidfile.so`: provides `<pid/...>`
- Cmdline `finit.cond=arg`: provides `<boot/arg`
See below for built-in conditions. Finit also supports user-defined
conditions, sometimes referred to as static or one-shot conditions.
They live in the `<usr/...` namespace and are constrained to a flat
hierarchy without any sub-directories, unlike the pidfile plugin, for
instance.
`netlink.so` and `pidfile.so`, see below for built-in conditions. Finit
also supports user-defined conditions, sometimes referred to as static
or one-shot conditions. They live in the `<usr/...` namespace and are
constrained to a flat hierarchy without any sub-directories, unlike the
pidfile plugin, for instance.
User-defined conditions are controlled using the `initctl cond set` and
`initctl cond clear` commands:
@@ -123,7 +118,6 @@ Built-in conditions:
- `sys/pwr/fail`
- `sys/key/ctrlaltdel`
- `usr/foo`
- `boot/arg`
**Note:** `up` means administratively up, the interface flag `IFF_UP`.
`running` is the `IFF_RUNNING` flag, meaning operatively up. The
+5 -60
View File
@@ -73,36 +73,6 @@ document [Finit Services](service.md).
> examples in the `contrib/` directory, which can be used as a base.
### Environment Variables
In Finit v4.3 support for setting environment variables in `finit.conf`,
and any `*.conf`, was added. It is worth noting that these are global
and *shared with all* services -- the only way to have service-local
environment is detailed in the next section.
The syntax for global environment variables is straight forward:
foo=bar
baz="qux"
On reload of .conf files, all tracked environment variables are cleared
so if `foo=bar` is removed from `finit.conf`, or any `finit.d/*.conf`
file, it will no longer be used by Finit or any new (!) started
run/tasks or services. The environment of already started processes can
not be changed.
The only variables reset to sane defaults on .conf reload are:
PATH=_PATH_STDPATH
SHELL=_PATH_BSHELL
LOGNAME=root
USER=root
It is entirely possible to override these as well from the .conf files,
but be careful. Changing SHELL changes the behavior of `system()` and a
lot of other commands as well.
Service Environment
-------------------
@@ -353,10 +323,6 @@ calls `init-script restart` on `initctl reload`. Similar to how
Forking services started with `sysv` scripts can be monitored by Finit
by declaring the PID file to look for: `pid:!/path/to/pidfile.pid`.
Notice the leading `!`, it signifies Finit should not try to create the
file, but rather watch that file for the resulting forked-off PID. This
syntax also works for forking daemons that do not have a command line
option to run it in the foreground, more on this below in `service`.
> `<COND>` is described in the [Services](#services) section.
@@ -372,27 +338,15 @@ After which they have to be manually restarted with `initctl restart
NAME`. The limits controling this are configurable, see the options
below.
> **Tip:** to allow endless restarts, see below option `respawn`
For daemons that support it, we recommend appending `--foreground`,
`--no-background`, `-n`, `-F`, or similar command line argument to
prevent them from forking off a sub-process in the background. This is
the most reliable way to monitor a service.
However, not all daemons support running in the foreground, or they may
start logging to the foreground as well, these are forking daemons and
are supported using the same syntax as forking `sysv` services, using
the `pid:!/path/to/pidfile.pid` syntax. There is an alternative syntax
that may be more intuitive, where Finit can also guess the PID file
based on the daemon's command name:
service type:forking ntpd -- NTP daemon
This example lets BusyBox `ntpd` daemonize itself. Finit uses the
basename of the binary to guess the PID file to watch for the PID:
`/var/run/ntpd.pid`. If Finit guesses wrong, you have to submit the
full `pid:!/path/to/file.pid`.
start logging to the foreground as well, these are called forking
services and are supported using the same syntax as forking `sysv`
services, using the `pid:!/path/to/pidfile.pid` syntax.
**Example:**
@@ -443,19 +397,13 @@ As mentioned previously, services are automatically restarted, this is
configurable with the following options:
* `restart:NUM` -- number of times Finit tries to restart a crashing
service, default: 10, max: 255. When this limit is reached the
service is marked *crashed* and must be restarted manually with
`initctl restart NAME`
service, default: 10. When this limit is reached the service is
marked *crashed* and must be restarted manually with `initctl`
* `restart_sec:SEC` -- number of seconds before Finit tries to restart
a crashing service, default: 2 seconds for the first five retries,
then back-off to 5 seconds. The maximum of this configured value
and the above (2 and 5) will be used
* `restart:always` -- no upper limit on the number of times Finit
tries to restart a crashing service. Same as `restart:-1`
* `norestart` -- dont restart on failures, same as `restart:0`
* `respawn` -- bypasses the `restart` mechanism completely, allows
endless restarts. Useful in many use-cases, but not what `service`
was originally designed for so not the default behavior
* `oncrash:reboot` -- when all retries have failed, and the service
has *crashed*, if this option is set the system is rebooted.
Note, future releases may include other `oncrash:` actions
@@ -677,9 +625,6 @@ activate it.
The rescue mode comes in two flavors; *traditional* and *fallback*.
> **Note:** in this mode `initctl` will not work. Use the `-f` flag to
> force `reboot`, `shutdown`, or `poweroff`.
### Traditional
+5 -34
View File
@@ -34,50 +34,26 @@ For your convenience a set of *optional* plugins are available:
* *dbus.so*: Setup and start system message bus, D-Bus, at boot.
_Optional plugin._
* *hook-scripts.so*: Trigger the execution of scripts from plugin hook
points (see [Hooks](#hooks)). Scripts are located in
`/libexec/finit/hook` by default, this can be build-time customized
by using the `--with-hook-scripts-path=PATH` argument to
`configure`. _Optional plugin._
* *hotplug.so*: Setup and start either udev or mdev hotplug daemon, if
available. Enabled by default.
available.
* *rtc.so*: Restore and save system clock from/to RTC on boot/halt.
Enabled by default.
* *modules-load.so*: Scans `/etc/modules-load.d/*.conf` for modules to
load using `modprobe`. Each file can contain multiple lines with the
name of the module to load. Any line starting with the standard UNIX
comment character, `#`, is skipped.
Modules are loaded when entering runlevel `[2345]` using the `task`
stanza. Each module gets a unique `name:modprobe.foo`, and
optional`:ID`. The `:ID` is a globally incremented index, which can
be disabled per file (anywhere) using the following config line:
set noindex
**Note:** unlike the traditional .conf `module` directive, which load
any listed module immediately, this plugin creates standard `taks`
directives which load the module(s) in the background. As long as
the `modprobe` program is found in the path, these tasks will always
return `[ OK ]` at boot. Check the actual status using `initctl`.
* *modules-load.so*: Scans /etc/modules-load.d for modules to modprobe.
* *netlink.so*: Listens to Linux kernel Netlink events for gateway and
interfaces. These events are then sent to the Finit service monitor
for services that may want to be SIGHUP'ed on new default route or
interfaces going up/down. Enabled by default.
interfaces going up/down.
* *resolvconf.so*: Setup necessary files for `resolvconf` at startup.
_Optional plugin._
* *tty.so*: Watches `/dev`, using inotify, for new device nodes (TTY's)
to start/stop getty consoles on them on demand. Useful when plugging
in a usb2serial converter to login to your embedded device. Enabled
by default.
in a usb2serial converter to login to your embedded device.
* *urandom.so*: Setup random seed at startup. Enabled by default.
* *urandom.so*: Setup random seed at startup.
* *x11-common.so*: Setup necessary files for X-Window. _Optional plugin._
@@ -93,11 +69,6 @@ Hooks
### Bootstrap Hooks
* `HOOK_BANNER`: The very first point at which a plugin can run.
Intended to be used as a banner replacement. Essentially this runs
just before entering runlevel S. Assume nothing is available, so
be prepared to use absolute paths, etc.
* `HOOK_ROOTFS_UP`: When `finit.conf` has been read and `/` has is
mounted — very early
+1 -11
View File
@@ -27,17 +27,7 @@ Finit can *not* start and monitor a daemon that:
### Forks to Background w/ PID File
There are two syntax variants, type 1 and type 2. The former is the
traditional one used also for `sysv` start/stop scripts, and the latter
is inspired by systemd, with a twist -- it lets Finit guess the pifdile
to look for based on the standard path and the basename of the command.
service pid:!/run/serv.pid serv -- Forking service, type 1
service type:forking serv -- Forking service, type 2
In this example the resulting files to watch for are `/run/serv.pid` and
`/var/run/serv.pid`, respectively. On most modern Linux systems this is
the same directory (`/var/run` is a symlink to `../run`).
service pid:!/run/serv.pid serv -- Forking service
### Runs in Foreground w/ PID File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 180 KiB

After

Width:  |  Height:  |  Size: 138 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 103 KiB

+2 -85
View File
@@ -11,11 +11,9 @@
.Nd Fast init for Linux systems
.Sh SYNOPSIS
.Nm /sbin/finit
.Op --
.Op finit.status_style=classic
.Op finit.show_status=[on,off]
.Op finit.debug
.Op finit.fstab=/etc/fstab.alt
.Op finit.status=<on,off>
.Op finit.status_style=<classic,modern>
.Op rescue | recover
.Op single | S
.Nm /sbin/telinit
@@ -63,93 +61,12 @@ Plugin support for customization
.It
Proper rescue mode with bundled `sulogin` for protected maintenance shell
.El
.Sh BOOTPARAM
.Nm
support the following command line parameters to alter the behavior
at boot. Notice the
.Cm --
separator needed to tell the kernel which paramters should be given to
PID 1. For more information on this, and available kernel command line
options, see
.Xr bootparam 7 .
.Bl -tag -width pid -offset indent
.It Cm finit.debug
Enable Finit debug messages on system console and log. Sometimes useful
when doing board bringup. Before the system log daemon has started,
Finit use the kernel ring buffer,
.Pa /dev/kmsg .
.It Cm finit.fstab=/path/to/fstab.alt
Tell
.Nm
to use an alternate
.Cm fstab
to mount the file system from. Remember, this file must be on the
.Cm root=...
file system provided to Finit from the kernel. If this file is missing,
.Nm
falls back to its built-in default, which can be changed at build time
using the
.Cm --with-fstab=/path/to/footab
configure option. It is even possible to completely disable the
built-in using
.Cm --without-fstab ,
meaning
.Nm
.Sy must
be started with the
.Cm finit.fstab
option.
.Pp
Should
.Nm
discover that there is no fstab file available, including the fallback,
it triggers the same failure mode as when
.Cm fsck
fails, starting
.Xr sulogin 8 ,
if that is availble. When
.Cm sulogin
is missing, or when the user exits from
.Cm sulogin ,
the system is rebooted.
.Pp
Default fstab, unless changed at build-time:
.Pa /etc/fstab
.It Cm finit.status=<on,off>
Control finit boot progress, including banner. This used to be called
.Cm finit.show_status ,
which still works but is deprecated.
.It Cm finit.status_style=<classic,modern>
Set Finit boot progress style, when enabled.
.It Cm rescue | recover
Start rescue/maintenance mode. If your system comes with the bundled
.Cm sulogin
program (Finit, or from util-linux/Busybox), you will be given a root
login to a maintenance shell. However, if
.Cm sulogin
is missing, the file
.Pa /lib/finit/rescue.conf
is read and the system booted in a limited fallback mode. See
.Xr finit.conf 5
for more information.
.It Cm single | S
Single user mode, runlevel 1, in Finit. Useful to debug problems with
the regular runlevel. All services and TTYs in
.Cm [1]
will be started, e.g., a
.Cm tty [1] @console nologin
configuration presents you with a root console without login.
.El
.Sh BOOTING
.Pp
Before laucnhing services, the system needs to be bootstrapped. This
involves mounting all filesystems (not already mounted by an initramfs)
in
.Pa /etc/fstab ,
or any alternate
.Pa fstab
file provided on the Finit command line using
.Cm finit.fstab ,
ensuring that necessary filesystems like:
.Pa /dev ,
.Pa /proc ,
+1 -32
View File
@@ -182,12 +182,6 @@ After which they have to be restarted manually using
The number of restarts, the delay between each restart, and more is
configurable, see the options below.
.Pp
.Bd -filled -offset indent
.Sy Tip:
to allow endless restarts, see below option
.Cm respawn
.Ed
.Pp
For daemons that support it, we recommend appending
.Cm --foreground , --no-background , -n , -F ,
or similar command line argument to prevent them from forking off a
@@ -200,21 +194,7 @@ services and are supported using the same syntax as forking
.Cm sysv
services, using the
.Cm pid:!/path/to/pidfile.pid
command modifier syntax. There is an alternative syntax that may be
more intuitive, where Finit can also guess the PID file based on the
daemon's command name:
.Bd -unfilled -offset indent
service type:forking ntpd -- NTP daemon
.Ed
.Pp
Here we let BusyBox
.Nm ntpd
daemonize itself. Finit uses the basename of the binary to guess the
PID file to watch for the PID:
.Pa /var/run/ntpd.pid .
If Finit guesses wrong, you have to submit the full
.Cm pid:!/path/to/file.pid
option to your service stanza.
command modifier syntax.
.Pp
.Sy Example: in the case of
.Cm ospfd
@@ -304,20 +284,9 @@ number of seconds before Finit tries to restart
a crashing service, default: 2 seconds for the first five retries,
then back-off to 5 seconds. The maximum of this configured value
and the above (2 and 5) will be used
.It Cm restart:always
no upper limit on the number of times Finit tries to restart a crashing
service. Same as
.Cm restart:-1
.It Cm norestart
dont restart on failures, same as
.Cm restart:0
.It Cm respawn
bypasses the
.Cm restart
mechanism completely, allows endless restarts. Useful in many
use-cases, but not what
.Cm service
was originally designed for so not the default behavior.
.It Cm oncrash:reboot
when all retries have failed, and the service
has
+6 -50
View File
@@ -24,11 +24,9 @@ This program follows the usual UNIX command line syntax, with long
options starting with two dashes (`-'). The options are as follows:
.Bl -tag -width Ds
.It Fl b, -batch
Batch mode, no screen size probing. Useful for scripting.
Batch mode, no screen size probing.
.It Fl c, -create
Create missing paths (and files) as needed. Useful with the
.Cm edit
command.
Create missing paths (and files) as needed. Useful with the edit command.
.It Fl f, -force
Ignore missing files and arguments, never prompt.
.It Fl h, -help
@@ -66,16 +64,7 @@ files in
Create
.Cm .conf
in
.Pa /etc/finit.d/available .
.Pp
Piping the contents into
.Nm
works as one would expect:
.Bd -literal -offset indent
echo "task name:foo /tmp/foo.sh -- Foo logger" | initctl create foo
initctl enable foo
initctl reload
.Ed
.Pa /etc/finit.d/available
.It Nm Ar delete Ar CONF
Delete
.Cm .conf
@@ -124,20 +113,6 @@ i.e., activates changes
.It Nm Ar cond set Ar COND
Set (assert) user-defined condition,
.Cm +usr/COND
.It Nm Ar cond get Ar COND
Get (quietly) the status of any condition. Defaults to user-defined
condions, but if a slash is detected, e.g.,
.Cm pid/foo
or
.Cm net/eth0/exist ,
then any condition can be read.
.Pp
The command is geared for scripting, check the exit code to get the
status of the condition, or give
.Nm
the
.Fl v
option for a more verbose output.
.It Nm Ar cond clr | clear Ar COND
Clear (deassert) user-defined condition,
.Cm -usr/COND
@@ -145,8 +120,8 @@ Clear (deassert) user-defined condition,
Show condition status, default
.Cm cond
command.
.It Nm Ar cond dump Op Cm TYPE
Dump all, or a given type of, conditions and their status
.It Nm Ar cond dump
Dump all conditions and their status
.It Nm Ar ident Op Cm NAME
Display indentities of all run/task/services, or only instances
matching
@@ -164,24 +139,7 @@ Start service by name, with optional ID, e.g.,
.It Nm Ar stop Cm NAME[:ID]
Stop/Pause a running service by name
.It Nm Ar reload Cm NAME[:ID]
Reload service as if its configuration had changed. Internally,
.Nm finit
marks the named service as "dirty" and turns the state machine,
resulting in a SIGHUP or restart of (at least) the named service.
Any dependant services are also restarted.
.Pp
.Sy Note:
no .conf file is reloaded with this variant of the command. Essentially
it is the same as calling
.Cm restart .
Except for two things:
.Bl -enum -offset indent -compact
.It
if the service supports HUP, it's signaled instead of stop-started, and
.It
it allows restarting run/task in the same runlevel -- which is otherwise
restricted
.El
Reload service by name (SIGHUP or restart)
.It Nm Ar signal Cm NAME:[ID] S
Send signal S to service, by name.
.Cm S
@@ -202,8 +160,6 @@ List cgroup config overview
List processes based on cgroups
.It Nm Ar top
Show top-like listing based on cgroups
.It Nm Ar plugins
List installed plugins
.It Nm Ar runlevel Op Ar 0-9
Show or set runlevel: 0 halt, 6 reboot
.It Nm Ar reboot
-4
View File
@@ -64,10 +64,6 @@ if BUILD_DBUS_PLUGIN
pkglib_LTLIBRARIES += dbus.la
endif
if BUILD_HOOK_SCRIPTS_PLUGIN
pkglib_LTLIBRARIES += hook-scripts.la
endif
if BUILD_HOTPLUG_PLUGIN
pkglib_LTLIBRARIES += hotplug.la
endif
+1 -1
View File
@@ -1,6 +1,6 @@
/* Save and restore ALSA sound settings using alsactl
*
* Copyright (c) 2012-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
+4 -52
View File
@@ -1,6 +1,6 @@
/* Setup necessary system files for, e.g. UTMP (tracking logins)
*
* Copyright (c) 2012-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -21,12 +21,8 @@
* THE SOFTWARE.
*/
#include "config.h" /* Generated by configure script */
#include <ftw.h>
#ifdef HAVE_MNTENT_H
#include <mntent.h>
#endif
#include <string.h>
#ifdef _LIBITE_LITE
# include <libite/lite.h>
@@ -43,12 +39,10 @@
static int is_tmpfs(char *path)
{
struct mntent mount;
struct mntent *mnt;
char buf[256];
int tmpfs = 0;
FILE *fp;
char *dir;
struct mntent *mnt;
/* If path is a symlink, check what it resolves to */
dir = realpath(path, NULL);
@@ -61,7 +55,7 @@ static int is_tmpfs(char *path)
return 0; /* Dunno, maybe not */
}
while ((mnt = getmntent_r(fp, &mount, buf, sizeof(buf)))) {
while ((mnt = getmntent(fp))) {
if (!strcmp(dir, mnt->mnt_dir))
break;
}
@@ -116,45 +110,6 @@ static void ln(const char *target, const char *linkpath)
_pe("Failed creating %s -> %s symlink", target, linkpath);
}
/* Kernel defines the following compulsory and recommended links
* https://github.com/torvalds/linux/blob/v5.18/Documentation/admin-guide/devices.rst#compulsory-links
*/
static void kernel_links(void)
{
struct {
char *tgt, *lnk;
int optional;
} k[] = {
{ "/proc/self/fd", "/dev/fd", 0 },
{ "fd/0", "/dev/stdin", 0 },
{ "fd/1", "/dev/stdout", 0 },
{ "fd/2", "/dev/stderr", 0 },
{ "socksys", "/dev/nfsd", 0 },
{ "null", "/dev/X0R", 0 },
{ "/proc/kcore", "/dev/core", 1 },
{ "ram0", "/dev/ramdisk", 1 },
{ "qft0", "/dev/ftape", 1 },
{ "video0", "/dev/bttv0", 1 },
{ "radio0", "/dev/radio", 1 },
};
char *fn, buf[80];
size_t i;
for (i = 0; i < NELEMS(k); i++) {
fn = k[i].tgt;
if (k[i].optional) {
if (fn[0] != '/') {
snprintf(buf, sizeof(buf), "/dev/%s", k[i].tgt);
fn = buf;
}
if (!fexist(fn))
continue;
}
ln(k[i].tgt, k[i].lnk);
}
}
/*
* Setup standard FHS 2.3 structure in /var, and write runlevel to UTMP
*/
@@ -180,7 +135,7 @@ static void setup(void *arg)
ln("/dev/shm", "/run/shm");
/* compat only, should really be set up by OS/dist */
ln("/run", "/var/run");
ln("../run", "/var/run");
} else {
makedir("/var/lock", 1777);
makedir("/var/run", 0755);
@@ -245,9 +200,6 @@ static void setup(void *arg)
if (whichp("restorecon"))
run("restorecon /var/run/sudo /var/run/sudo/ts", "restorecon");
/* Kernel symlinks, e.g. /proc/self/fd -> /dev/fd */
kernel_links();
umask(prev);
}
+14 -24
View File
@@ -1,6 +1,6 @@
/* Setup and start system message bus, D-Bus
*
* Copyright (c) 2012-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -35,20 +35,16 @@
#include "service.h"
#include "conf.h"
#define DBUS_DAEMON "dbus-daemon"
#define DBUS_ARGS "--nofork --system --syslog-only"
#define DBUS_DESC "D-Bus message bus daemon"
#define DAEMON "dbus-daemon"
#define ARGS "--nofork --system --syslog-only"
#define DESC "D-Bus message bus daemon"
#ifndef DBUS_DAEMONUSER
#define DBUS_DAEMONUSER "messagebus"
#ifndef DAEMONUSER
#define DAEMONUSER "messagebus"
#endif
#ifndef DBUS_DAEMONGROUP
#define DBUS_DAEMONGROUP "messagebus"
#endif
#ifndef DBUS_DAEMONPIDFILE
#define DBUS_DAEMONPIDFILE "/var/run/dbus/pid"
#ifndef DAEMONPIDFILE
#define DAEMONPIDFILE "/var/run/dbus/pid"
#endif
static void setup(void *arg)
@@ -62,32 +58,26 @@ static void setup(void *arg)
return;
}
cmd = which(DBUS_DAEMON);
cmd = which(DAEMON);
if (!cmd) {
_d("Skipping plugin, %s is not installed.", DBUS_DAEMON);
_d("Skipping plugin, %s is not installed.", DAEMON);
return;
}
prev =umask(0);
_d("Creating D-Bus Required Directories ...");
mksubsys("/var/run/dbus", 0755, DBUS_DAEMONUSER, DBUS_DAEMONGROUP);
mksubsys("/var/run/lock/subsys", 0755, DBUS_DAEMONUSER, DBUS_DAEMONGROUP);
mksubsys("/var/lib/dbus", 0755, DBUS_DAEMONUSER, DBUS_DAEMONGROUP);
mksubsys("/tmp/dbus", 0755, DBUS_DAEMONUSER, DBUS_DAEMONGROUP);
/* Generate machine id for dbus */
mksubsys("/var/run/dbus", 0755, DAEMONUSER, DAEMONUSER);
if (whichp("dbus-uuidgen"))
run_interactive("dbus-uuidgen --ensure", "Creating machine UUID for D-Bus");
/* Clean up from any previous pre-bootstrap run */
remove(DBUS_DAEMONPIDFILE);
remove(DAEMONPIDFILE);
/* Register service with Finit */
snprintf(line, sizeof(line), "[S12345789] cgroup.system pid:!%s @%s:%s %s %s -- %s",
DBUS_DAEMONPIDFILE, DBUS_DAEMONUSER, DBUS_DAEMONGROUP, cmd, DBUS_ARGS, DBUS_DESC);
DAEMONPIDFILE, DAEMONUSER, DAEMONUSER, cmd, ARGS, DESC);
if (service_register(SVC_TYPE_SERVICE, line, global_rlimit, NULL))
_pe("Failed registering %s", DBUS_DAEMON);
_pe("Failed registering %s", DAEMON);
free(cmd);
umask(prev);
-116
View File
@@ -1,116 +0,0 @@
/* Trigger scripts to run from finit's hooks
*
* Copyright (c) 2022 Tobias Waldekranz <tobias@waldekranz.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "finit.h"
#include "helpers.h"
#include "plugin.h"
#include "config.h"
#define CHOOSE(x, y) y
static const char *hscript_paths[] = HOOK_TYPES;
#undef CHOOSE
static void hscript_run_parts(hook_point_t hook)
{
char path[CMD_SIZE] = "";
strlcat(path, PLUGIN_HOOK_SCRIPTS_PATH, sizeof(path));
strlcat(path, hscript_paths[hook] + 4, sizeof(path));
run_parts(path, NULL);
}
static void hscript_banner(void *arg)
{
hscript_run_parts(HOOK_BANNER);
}
static void hscript_rootfs_up(void *arg)
{
hscript_run_parts(HOOK_ROOTFS_UP);
}
static void hscript_mount_error(void *arg)
{
hscript_run_parts(HOOK_MOUNT_ERROR);
}
static void hscript_mount_post(void *arg)
{
hscript_run_parts(HOOK_MOUNT_POST);
}
static void hscript_basefs_up(void *arg)
{
hscript_run_parts(HOOK_BASEFS_UP);
}
static void hscript_network_up(void *arg)
{
hscript_run_parts(HOOK_NETWORK_UP);
}
static void hscript_svc_up(void *arg)
{
hscript_run_parts(HOOK_SVC_UP);
}
static void hscript_system_up(void *arg)
{
hscript_run_parts(HOOK_SYSTEM_UP);
}
static void hscript_shutdown(void *arg)
{
hscript_run_parts(HOOK_SHUTDOWN);
}
static plugin_t plugin = {
.name = __FILE__,
.hook[HOOK_BANNER] = { .cb = hscript_banner },
.hook[HOOK_ROOTFS_UP] = { .cb = hscript_rootfs_up },
.hook[HOOK_MOUNT_ERROR] = { .cb = hscript_mount_error },
.hook[HOOK_MOUNT_POST] = { .cb = hscript_mount_post },
.hook[HOOK_BASEFS_UP] = { .cb = hscript_basefs_up },
.hook[HOOK_NETWORK_UP] = { .cb = hscript_network_up },
.hook[HOOK_SVC_UP] = { .cb = hscript_svc_up },
.hook[HOOK_SYSTEM_UP] = { .cb = hscript_system_up },
.hook[HOOK_SHUTDOWN] = { .cb = hscript_shutdown },
};
PLUGIN_INIT(plugin_init)
{
plugin_register(&plugin);
}
PLUGIN_EXIT(plugin_exit)
{
plugin_unregister(&plugin);
}
/**
* Local Variables:
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+2 -2
View File
@@ -1,6 +1,6 @@
/* Heuristically find and initialize a suitable hotplug daemon
*
* Copyright (c) 2012-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -95,7 +95,7 @@ static plugin_t plugin = {
.hook[HOOK_BASEFS_UP] = {
.cb = setup
},
.depends = { "bootmisc", "modprobe" },
.depends = { "bootmisc" },
};
PLUGIN_INIT(plugin_init)
+10 -70
View File
@@ -1,6 +1,6 @@
/* Coldplug modules using modalias magic
*
* Copyright (c) 2021-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -120,87 +120,27 @@ static int alias_exist(char *alias)
return 0;
}
static void alias_add_uniq(char *alias)
static int scan_alias(const char *path, const struct stat *st, int flag, struct FTW *unused)
{
if (alias_exist(alias))
return;
alias_add(alias);
}
static FILE *maybe_fopen_alias(const char *file, const char *path)
{
const char *basename;
basename = rindex(path, '/');
if (!basename)
return NULL;
basename++;
if (strcmp(file, basename))
return NULL;
return fopen(path, "r");
}
static int scan_modalias(const char *path)
{
char buf[256];
FILE *fp;
char buf[256];
fp = maybe_fopen_alias("modalias", path);
if (fnmatch("*/modalias", path, 0))
return 0;
fp = fopen(path, "r");
if (!fp)
return 1;
return 0;
if (fgets(buf, sizeof(buf), fp)) {
chomp(buf);
alias_add_uniq(buf);
if (!alias_exist(buf))
alias_add(buf);
}
fclose(fp);
return 0;
}
static int scan_uevent(const char *path)
{
char buf[256];
FILE *fp;
fp = maybe_fopen_alias("uevent", path);
if (!fp)
return 1;
while (fgets(buf, sizeof(buf), fp)) {
if (strstr(buf, "MODALIAS=") != buf)
continue;
chomp(buf);
alias_add_uniq(buf + strlen("MODALIAS="));
break;
}
fclose(fp);
return 0;
}
static int scan_alias(const char *path, const struct stat *st,
int flag, struct FTW *unused)
{
/* Sanity check: is this a regular file we can read? */
if (!(S_ISREG(st->st_mode) && (st->st_mode & S_IRUSR)))
return 0;
if (!scan_uevent(path))
return 0;
scan_modalias(path);
return 0;
}
static void coldplug(void *arg)
{
struct module *m, *tmp;
+25 -85
View File
@@ -21,29 +21,6 @@
* THE SOFTWARE.
*/
/*
* This plugin scans files in /etc/modules-load.d/, for each line in the
* file it assumes the name of a kernel module, with optional arguments.
* Each module is loaded when entering runlevel 2, 3, 4, or 5, using the
* modprobe tool.
*
* Loading is done by inserting a `task` stanza in Finit, ensuring all
* modules are loaded in parallel, with other modules and programs.
* Each `task` stanza is by default given the name:modprobe.module and
* indexed with `:ID`, starting with 1.
*
* Indexing can be disabled per file in /etc/modules-load.d/, anywwhere
* in a file, by putting the keyword `noindex` on a line of its own. A
* noindex command can appear anywhere in the file, and up to the point
* it is read, tasks will be indexed with an incrementing `:ID`. When
* `noindex` is read indexing is disabled and all subseequent tasks will
* not have any `:ID` at all.
*
* Please note, the :ID is there for your benefit, it ensures that tasks
* in Finit are unique. If you have two tasks with the same name and ID
* (or no ID), the last one read replaces any preceeding one!
*/
#include <unistd.h>
#include <sys/types.h>
#include <dirent.h>
@@ -63,94 +40,57 @@
#define MODULES_LOAD_PATH "/etc/modules-load.d"
#endif
#define SERVICE_LINE \
"cgroup.init name:modprobe.%s :%d [2345] /sbin/modprobe %s %s -- Kernel module: %s"
#define SERVICE_LINE_NOINDEX \
"cgroup.init name:modprobe.%s [2345] /sbin/modprobe %s %s -- Kernel module: %s"
"cgroup.init :%d name:modprobe.%s [2345] /sbin/modprobe %s %s -- Kernel module: %s"
static int load_file(const char *file, int index)
static void load(void *arg)
{
char module_path[PATH_MAX];
struct dirent *d;
char line[256];
int num = 0;
int index = 1;
FILE *fp;
DIR *dir;
_d("Scanning " MODULES_LOAD_PATH " for config files ...");
dir = opendir(MODULES_LOAD_PATH);
if (!dir)
return;
while ((d = readdir(dir))) {
char module_path[PATH_MAX];
strlcpy(module_path, MODULES_LOAD_PATH "/", sizeof(module_path));
strlcat(module_path, file, sizeof(module_path));
strlcat(module_path, d->d_name, sizeof(module_path));
fp = fopen(module_path, "r");
if (!fp)
return 0;
continue;
while (fgets(line, sizeof(line), fp)) {
char cmd[CMD_SIZE], *mod, *args;
chomp(line);
mod = strip_line(line);
if (!mod[0])
if (!*mod)
continue;
if (mod[0] == '#' || mod[0] == ';')
mod = chomp(mod);
if (!mod || !*mod)
continue;
if (!strcmp(mod, "set noindex")) {
index = 0;
continue;
}
if (!strncmp(mod, "set index", 9)) {
mod += 9;
args = strchr(mod, '=');
if (args) /* optional */
mod = args + 1;
index = atoi(mod);
continue;
}
mod = strtok_r(mod, " ", &args);
if (!mod)
continue;
if (!index)
snprintf(cmd, sizeof(cmd), SERVICE_LINE_NOINDEX, mod, mod, args, mod);
else
snprintf(cmd, sizeof(cmd), SERVICE_LINE, mod, index++, mod, args, mod);
snprintf(cmd, sizeof(cmd), SERVICE_LINE, index, mod, mod, args, mod);
service_register(SVC_TYPE_TASK, cmd, global_rlimit, NULL);
num++;
index++;
}
fclose(fp);
return num;
}
/* XXX: check here for .conf only? */
static int module_filter(const struct dirent *d)
{
if (d->d_type == DT_DIR)
return 0;
if (d->d_name[0] == '.')
return 0; /* skip dot files */
if (d->d_name[strlen(d->d_name) - 1] == '~')
return 0; /* skip backup files */
return 1;
}
static void load(void *arg)
{
struct dirent **dentry;
int index = 1;
int i, num;
_d("Scanning " MODULES_LOAD_PATH " for config files ...");
num = scandir(MODULES_LOAD_PATH, &dentry, module_filter, alphasort);
if (num > 0) {
for (i = 0; i < num; i++) {
index += load_file(dentry[i]->d_name, index);
free(dentry[i]);
}
free(dentry);
}
closedir(dir);
}
static plugin_t plugin = {
+8 -10
View File
@@ -1,8 +1,7 @@
/* Netlink plugin for IFUP/IFDN and GW events
*
* Copyright (C) 2009-2011 Mårten Wikström <marten.wikstrom@keystream.se>
* Copyright (C) 2009-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (C) 2009-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -253,18 +252,18 @@ static int nl_parse(int sd)
return -1;
}
// _d("recv %zd bytes", len);
_d("recv %lld bytes", len);
l = (size_t)len;
for (nh = (struct nlmsghdr *)nl_buf; NLMSG_OK(nh, l); nh = NLMSG_NEXT(nh, l)) {
struct nlmsgerr *nle;
switch (nh->nlmsg_type) {
case NLMSG_DONE:
// _d("Done with netlink messages.");
_d("Done with netlink messages.");
return 0;
case NLMSG_ERROR:
// _d("Kernel netlink comm. error.");
_d("Kernel netlink comm. error.");
nle = NLMSG_DATA(nh);
if (nle) {
errno = -nle->error;
@@ -274,13 +273,13 @@ static int nl_parse(int sd)
case RTM_NEWROUTE:
case RTM_DELROUTE:
// _d("Netlink route ...");
_d("Netlink route ...");
nl_route(nh, len);
break;
case RTM_NEWLINK:
case RTM_DELLINK:
// _d("Netlink link ...");
_d("Netlink link ...");
nl_link(nh, len);
break;
@@ -304,14 +303,14 @@ static int nl_request(int sd, unsigned int seq, int type)
switch (type) {
case RTM_GETROUTE:
// _d("RTM_GETROUTE");
_d("RTM_GETROUTE");
nlr->rtm.rtm_family = AF_INET;
nlr->rtm.rtm_table = RT_TABLE_MAIN;
nlr->nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
break;
case RTM_GETLINK:
// _d("RTM_GETLINK");
_d("RTM_GETLINK");
nlr->ifi.ifi_family = AF_UNSPEC;
nlr->ifi.ifi_change = 0xFFFFFFFF;
nlr->nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
@@ -450,7 +449,6 @@ PLUGIN_INIT(plugin_init)
PLUGIN_EXIT(plugin_exit)
{
plugin_unregister(&plugin);
close(plugin.io.fd);
}
/**
+4 -10
View File
@@ -1,7 +1,7 @@
/* Simple pidfile event monitor for the Finit condition engine
*
* Copyright (c) 2015-2016 Tobias Waldekranz <tobias@waldekranz.com>
* Copyright (c) 2016-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2016-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -98,16 +98,10 @@ static void pidfile_update_conds(char *dir, char *name, uint32_t mask)
return;
}
/* Service is not crashing, let's tell state machine! */
service_forked(svc);
if (pid != svc->pid) {
_d("Forking service %s (cmd %s) changed PID from %d to %d",
svc_ident(svc, NULL, 0), svc->cmd, svc->pid, pid);
_d("Forking service %s changed PID from %d to %d",
svc->cmd, svc->pid, pid);
svc->pid = pid;
/* Complement log in service.c for non-forking services */
logit(LOG_CONSOLE | LOG_NOTICE, "Started %s[%d]", svc_ident(svc, NULL, 0), pid);
}
}
@@ -311,8 +305,8 @@ PLUGIN_INIT(plugin_init)
PLUGIN_EXIT(plugin_exit)
{
plugin_unregister(&plugin);
iwatch_exit(&iw_pidfile);
plugin_unregister(&plugin);
}
/**
+1 -1
View File
@@ -1,6 +1,6 @@
/* Set kernel variables from /etc/sysctl.conf et al
*
* Copyright (c) 2016-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2016-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
+1 -1
View File
@@ -1,6 +1,6 @@
/* Setup necessary files for resolvconf
*
* Copyright (c) 2012-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
+1 -1
View File
@@ -1,6 +1,6 @@
/* Save and restore RTC using hwclock
*
* Copyright (c) 2012-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
+6 -2
View File
@@ -1,6 +1,6 @@
/* System condition event monitor for the Finit condition engine
*
* Copyright (c) 2021-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -160,19 +160,23 @@ static void sys_init(void *arg)
char sysdir[MAX_ARG_LEN];
char *path;
_d("Calling mkpath() on sys conds");
if (mkpath(pid_runpath(_PATH_CONDSYS, sysdir, sizeof(sysdir)), 0755) && errno != EEXIST) {
_pe("Failed creating %s condition directory, %s", COND_SYS, _PATH_CONDSYS);
return;
}
_d("Calling realpth() on condsys");
path = realpath(_PATH_CONDSYS, NULL);
if (!path) {
_pe("Cannot figure out real path to %s, aborting", _PATH_CONDSYS);
return;
}
_d("Calling iwatch_add()");
if (iwatch_add(&iw_sys, path, IN_ONLYDIR))
iwatch_exit(&iw_sys);
_d("Done.");
}
static plugin_t plugin = {
@@ -197,8 +201,8 @@ PLUGIN_INIT(plugin_init)
PLUGIN_EXIT(plugin_exit)
{
plugin_unregister(&plugin);
iwatch_exit(&iw_sys);
plugin_unregister(&plugin);
}
/**
+3 -2
View File
@@ -1,7 +1,7 @@
/* Optional TTY Watcher, used to catch new TTYs that are discovered, e.g., USB
*
* Copyright (c) 2013 Mattias Walström <lazzer@gmail.com>
* Copyright (c) 2013-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2013-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -116,9 +116,10 @@ PLUGIN_INIT(plugin_init)
PLUGIN_EXIT(plugin_exit)
{
plugin_unregister(&plugin);
if (plugin.io.fd)
close(plugin.io.fd);
plugin_unregister(&plugin);
}
/**
+1 -1
View File
@@ -1,6 +1,6 @@
/* Setup and save random seed at boot/shutdown
*
* Copyright (c) 2012-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
+2 -2
View File
@@ -1,6 +1,6 @@
/* User-defined condition event monitor for the Finit condition engine
*
* Copyright (c) 2021-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -123,8 +123,8 @@ PLUGIN_INIT(plugin_init)
PLUGIN_EXIT(plugin_exit)
{
plugin_unregister(&plugin);
iwatch_exit(&iw_usr);
plugin_unregister(&plugin);
}
/**
+1 -1
View File
@@ -1,6 +1,6 @@
/* Console setup (for X)
*
* Copyright (c) 2012-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
+2 -6
View File
@@ -8,10 +8,7 @@ AM_LDFLAGS = -export-dynamic
endif
sbin_PROGRAMS = finit initctl
pkglibexec_PROGRAMS = getty logit
if SULOGIN
pkglibexec_PROGRAMS += sulogin
endif
pkglibexec_PROGRAMS = getty logit sulogin
if KEVENTD
pkglibexec_PROGRAMS += keventd
endif
@@ -64,8 +61,7 @@ if LOGROTATE
finit_SOURCES += logrotate.c
endif
pkginclude_HEADERS = cgroup.h cond.h conf.h finit.h helpers.h log.h \
plugin.h svc.h service.h
pkginclude_HEADERS = cgroup.h cond.h finit.h helpers.h log.h plugin.h svc.h
finit_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
finit_CFLAGS += $(lite_CFLAGS) $(uev_CFLAGS)
+11 -61
View File
@@ -1,6 +1,6 @@
/* External client API, using UNIX domain socket.
*
* Copyright (c) 2015-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2015-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -21,8 +21,6 @@
* THE SOFTWARE.
*/
#include "config.h" /* Generated by configure script */
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
@@ -38,6 +36,7 @@
#endif
#include <uev/uev.h>
#include "config.h"
#include "finit.h"
#include "cond.h"
#include "conf.h"
@@ -45,9 +44,8 @@
#include "log.h"
#include "plugin.h"
#include "private.h"
#include "schedule.h"
#include "service.h"
#include "sig.h"
#include "service.h"
#include "util.h"
extern svc_t *wdog;
@@ -90,10 +88,8 @@ static int restart(svc_t *svc, void *user_data)
if (!svc)
return 1;
if (!svc_is_running(svc))
return start(svc, user_data);
service_stop(svc);
svc_mark_dirty(svc);
svc_start(svc);
service_step(svc);
return 0;
@@ -201,7 +197,7 @@ static svc_t *do_find(char *buf, size_t len)
if (!id)
return svc_named_iterator(&iter, 1, input);
return svc_find(input, id);
return svc_find_by_nameid(input, id);
}
static svc_t *do_find_byc(char *buf, size_t len)
@@ -228,44 +224,10 @@ static svc_t *do_find_byc(char *buf, size_t len)
return NULL;
}
static void bypass_shutdown(void *);
struct wq emergency = { .cb = bypass_shutdown };
static void bypass_shutdown(void *unused)
{
cprintf("TIMEOUT TIMEOUT SHUTTING DOWN NOW!!\n");
do_shutdown(halt);
}
static int do_reboot(int cmd, int timeout, char *buf, size_t len)
static int do_reboot(int cmd, char *buf, size_t len)
{
int rc = 1;
switch (cmd) {
case INIT_CMD_REBOOT:
halt = SHUT_REBOOT;
break;
case INIT_CMD_HALT:
halt = SHUT_HALT;
break;
case INIT_CMD_POWEROFF:
halt = SHUT_OFF;
break;
case INIT_CMD_SUSPEND:
break;
default:
return 255;
}
if (timeout > 0) {
emergency.delay = timeout * 1000;
schedule_work(&emergency);
}
switch (cmd) {
case INIT_CMD_REBOOT:
_d("reboot");
@@ -288,17 +250,17 @@ static int do_reboot(int cmd, int timeout, char *buf, size_t len)
case INIT_CMD_SUSPEND:
_d("suspend");
sync();
rc = suspend();
rc = reboot(RB_SW_SUSPEND);
if (rc) {
if (errno == EINVAL)
snprintf(buf, len, "Kernel does not support suspend to RAM.");
snprintf(buf, len, "Kernel does not support suspend.");
else
snprintf(buf, len, "Failed: %s", strerror(errno));
}
break;
default:
/* Handled previously */
rc = 255;
break;
}
@@ -356,10 +318,6 @@ static void api_cb(uev_t *w, void *arg, int events)
if (EAGAIN == errno)
break;
/* we get here when client restarts itself */
if (ECONNRESET == errno)
break;
_e("Failed reading initctl request, error %d: %s", errno, strerror(errno));
}
@@ -429,14 +387,6 @@ static void api_cb(uev_t *w, void *arg, int events)
result = do_reload(rq.data, sizeof(rq.data));
break;
case INIT_CMD_GET_PLUGINS:
result = plugin_list(rq.data, sizeof(rq.data));
break;
case INIT_CMD_PLUGIN_DEPS:
result = plugin_deps(rq.data, sizeof(rq.data));
break;
case INIT_CMD_GET_RUNLEVEL:
_d("get runlevel");
rq.runlevel = runlevel;
@@ -447,7 +397,7 @@ static void api_cb(uev_t *w, void *arg, int events)
case INIT_CMD_HALT:
case INIT_CMD_POWEROFF:
case INIT_CMD_SUSPEND:
result = do_reboot(rq.cmd, rq.sleeptime, rq.data, sizeof(rq.data));
result = do_reboot(rq.cmd, rq.data, sizeof(rq.data));
break;
case INIT_CMD_ACK:
+4 -7
View File
@@ -1,6 +1,6 @@
/* Finit control group support functions
*
* Copyright (c) 2019-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2019-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -465,9 +465,9 @@ void cgroup_init(uev_ctx_t *ctx)
if (mount("none", FINIT_CGPATH, "cgroup2", opts, NULL)) {
if (errno == ENOENT)
logit(LOG_INFO, "Kernel does not support cgroups v2, disabling.");
logit(LOG_NOTICE, "Kernel does not support cgroups v2, disabling.");
else if (errno == EPERM) /* Probably inside an unpriviliged container */
logit(LOG_INFO, "Not allowed to mount cgroups v2, disabling.");
logit(LOG_NOTICE, "Not allowed to mount cgroups v2, disabling.");
else
_pe("Failed mounting cgroup v2");
avail = 0;
@@ -511,9 +511,6 @@ void cgroup_init(uev_ctx_t *ctx)
/* prepare cgroup.events watcher */
fd = iwatch_init(&iw_cgroup);
if (fd == -1)
goto abort;
if (uev_io_init(ctx, &cgw, cgroup_events_cb, NULL, fd, UEV_READ)) {
_pe("Failed setting up cgroup.events watcher");
iwatch_exit(&iw_cgroup);
@@ -529,7 +526,7 @@ void cgroup_init(uev_ctx_t *ctx)
/* Move ourselves to init (best effort, otherwise run in 'root' group */
if (fnwrite("1", FINIT_CGPATH "/init/cgroup.procs")) {
_pe("Failed moving PID 1 to cgroup %s", FINIT_CGPATH "/init");
_pe("Failed moving PID 1 to cgroup ", FINIT_CGPATH "/init");
uev_io_stop(&cgw);
iwatch_exit(&iw_cgroup);
close(fd);
+1 -1
View File
@@ -1,6 +1,6 @@
/* Finit control group support functions
*
* Copyright (c) 2019-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2019-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
+9 -10
View File
@@ -1,6 +1,6 @@
/* New client tool, replaces old /dev/initctl API and telinit tool
*
* Copyright (c) 2019-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2019-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -23,6 +23,7 @@
#include "config.h"
#include <err.h>
#include <dirent.h>
#include <stdio.h>
#include <signal.h>
@@ -243,7 +244,7 @@ static float cgroup_cpuload(struct cg *cg)
snprintf(fn, sizeof(fn), "%s/cpu.stat", cg->cg_path);
fp = fopen(fn, "r");
if (!fp)
ERR(72, "Cannot open %s", fn);
err(1, "Cannot open %s", fn);
while (fgets(buf, sizeof(buf), fp)) {
uint64_t curr;
@@ -279,13 +280,13 @@ static struct cg *append(char *path)
if (access(fn, F_OK)) {
/* older kernels, 4.19, don't have summary cpu.stat in root */
if (strcmp(path, FINIT_CGPATH))
WARN("not a cgroup path with cpu controller, %s", path);
warn("not a cgroup path with cpu controller, %s", path);
return NULL;
}
cg = calloc(1, sizeof(struct cg));
if (!cg)
ERR(71, "failed allocating struct cg");
err(1, "failed allocating struct cg");
cg->cg_path = strdup(path);
if (list)
@@ -295,7 +296,7 @@ static struct cg *append(char *path)
item.key = cg->cg_path;
item.data = cg;
if (!hsearch(item, ENTER))
ERR(70, "failed adding to hash table");
err(1, "failed adding to hash table");
return cg;
}
@@ -433,6 +434,7 @@ int cgroup_tree(char *path, char *pfx, int mode, int pos)
pid_comm(pid, comm, sizeof(comm));
if (pid_cmdline(pid, buf, sizeof(buf))) {
char proc[ttcols];
int len;
switch (mode) {
case 1:
@@ -454,8 +456,6 @@ int cgroup_tree(char *path, char *pfx, int mode, int pos)
if (plain) {
strlcat(row, proc, rplen);
} else {
int len;
strlcat(row, CDIM, rlen);
strlcat(row, proc, rlen);
@@ -600,6 +600,7 @@ int show_cgtop(char *arg)
uev_t timer, input, sigint, sigterm, sigquit;
char path[512];
uev_ctx_t ctx;
int flags;
if (!arg)
arg = FINIT_CGPATH;
@@ -609,7 +610,7 @@ int show_cgtop(char *arg)
}
if (!hcreate(ttrows + 25))
ERR(70, "failed creating hash table");
err(1, "failed creating hash table");
sysinfo(&si);
total_ram = si.totalram * si.mem_unit;
@@ -618,8 +619,6 @@ int show_cgtop(char *arg)
uev_timer_init(&ctx, &timer, cgtop, arg, 1, ionce ? 0 : 1000);
if (!ionce && !plain) {
int flags;
atexit(cleanup);
ttraw();
hidecursor();
+1 -1
View File
@@ -1,6 +1,6 @@
/* Cgroup utility functions for initctl
*
* Copyright (c) 2019-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2019-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
+22 -23
View File
@@ -1,6 +1,6 @@
/* External client API, using UNIX domain socket.
*
* Copyright (c) 2015-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2015-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -21,13 +21,13 @@
* THE SOFTWARE.
*/
#include <err.h>
#include <errno.h>
#include <poll.h>
#include <sys/socket.h>
#include <sys/un.h>
#include "client.h"
#include "initctl.h"
static int sd = -1;
@@ -39,17 +39,11 @@ int client_connect(void)
};
sd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
if (-1 == sd) {
WARN("Failed creating UNIX domain socket");
return -1;
}
if (-1 == sd)
err(1, "Failed creating UNIX domain socket");
if (connect(sd, (struct sockaddr*)&sun, sizeof(sun)) == -1) {
if (errno != ENOENT)
WARNX("Failed connecting to finit");
close(sd);
return -1;
}
if (connect(sd, (struct sockaddr*)&sun, sizeof(sun)) == -1)
err(1, "Failed connecting to finit");
return sd;
}
@@ -72,21 +66,22 @@ int client_disconnect(void)
int client_send(struct init_request *rq, ssize_t len)
{
struct pollfd pfd = { 0 };
int result = 255;
int sd, result = 255;
int rc;
if (client_connect() == -1)
sd = client_connect();
if (-1 == sd)
return -1;
pfd.fd = sd;
pfd.events = POLLOUT;
if (poll(&pfd, 1, 2000) <= 0) {
WARN("Timed out waiting for Finit, errno %d", errno);
warn("Timed out waiting for Finit, errno %d", errno);
goto exit;
}
if (write(sd, rq, len) != len) {
WARN("Failed communicating with Finit, errno %d", errno);
warn("Failed communicating with Finit, errno %d", errno);
goto exit;
}
@@ -96,14 +91,14 @@ int client_send(struct init_request *rq, ssize_t len)
if (rc) {
if (errno == EINTR) /* shutdown/reboot */
goto exit;
WARN("poll(), errno %d", errno);
warn("poll(), errno %d", errno);
} else
WARNX("Timed out waiting for reply from Finit.");
warnx("Timed out waiting for reply from Finit.");
goto exit;
}
if (read(sd, rq, len) != len) {
WARN("Failed reading reply from Finit, errno %d", errno);
warn("Failed reading reply from Finit, errno %d", errno);
goto exit;
}
@@ -119,13 +114,15 @@ exit:
svc_t *client_svc_iterator(int first)
{
int sd = -1;
struct init_request rq = {
.magic = INIT_MAGIC,
.cmd = INIT_CMD_SVC_ITER,
};
static svc_t svc;
if (client_connect() == -1)
sd = client_connect();
if (sd == -1)
return NULL;
if (first)
@@ -144,7 +141,7 @@ svc_t *client_svc_iterator(int first)
return &svc;
error:
WARN("Failed communicating with finit, error %d", errno);
perror("Failed communicating with finit");
client_disconnect();
sd = -1;
@@ -158,8 +155,10 @@ svc_t *do_cmd(int cmd, const char *arg)
.cmd = cmd,
};
static svc_t svc;
int sd = -1;
if (client_connect() == -1)
sd = client_connect();
if (sd == -1)
return NULL;
strlcpy(rq.data, arg, sizeof(rq.data));
@@ -175,7 +174,7 @@ svc_t *do_cmd(int cmd, const char *arg)
return &svc;
error:
client_disconnect();
WARN("Failed communicating with finit, error %d", errno);
perror("Failed communicating with finit");
return NULL;
}
+1 -1
View File
@@ -1,6 +1,6 @@
/* External client API, using UNIX domain socket.
*
* Copyright (c) 2015-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2015-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
+1 -99
View File
@@ -21,7 +21,6 @@
* THE SOFTWARE.
*/
#include <dirent.h>
#include <ftw.h>
#include <libgen.h>
#include <stdio.h>
@@ -36,67 +35,6 @@
#include "pid.h"
#include "service.h"
struct cond_boot {
TAILQ_ENTRY(cond_boot) link;
char *name;
};
static TAILQ_HEAD(, cond_boot) cond_boot_list = TAILQ_HEAD_INITIALIZER(cond_boot_list);
/*
* Parse finit.cond=cond[,cond[,...]] from command line. It creates a
* temporary linked list of conds which are freed when finit reaches
* cond_init(), which calls cond_boot_strap() to realize the conditions
* in the file system as regular static conditions. Policy, however,
* dictates that these are read-only and should not be possible to
* manage from initctl.
*/
void cond_boot_parse(char *arg)
{
struct cond_boot *node;
if (!arg)
return;
node = malloc(sizeof(*node));
if (!node) {
_pe("Out of memory cannot track boot conditions");
return;
}
node->name = strdup(arg);
TAILQ_INSERT_HEAD(&cond_boot_list, node, link);
}
/*
* Convert all conditions read from the kernel command line (above) into
* proper finit conditions.
*/
static void cond_boot_strap(void)
{
struct cond_boot *node, *tmp;
TAILQ_FOREACH_SAFE(node, &cond_boot_list, link, tmp) {
TAILQ_REMOVE(&cond_boot_list, node, link);
if (node->name) {
char *ptr;
ptr = strtok(node->name, ",");
while (ptr) {
char cond[strlen(ptr) + 6];
snprintf(cond, sizeof(cond), "boot/%s", ptr);
cond_set_oneshot_noupdate(cond);
ptr = strtok(NULL, ",");
}
free(node->name);
}
free(node);
}
}
/*
* The service condition name is constructed from the 'pid/' prefix and
* the unique NAME:ID tuple that identify each process in Finit. Here
@@ -194,31 +132,6 @@ static int cond_checkpath(const char *path)
return 0;
}
/* Intended for 'service/foo/`, nothing else */
static void cond_delpath(const char *path)
{
char fn[PATH_MAX];
struct dirent *d;
DIR *dir;
dir = opendir(path);
if (!dir)
return;
while ((d = readdir(dir))) {
if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
continue;
paste(fn, sizeof(fn), path, d->d_name);
if (remove(fn))
_pe("Failed removing condition path, file %s", fn);
}
closedir(dir);
if (unlink(path) && errno != EISDIR)
_pe("Failed removing condition path %s", fn);
}
int cond_set_path(const char *path, enum cond_state next)
{
enum cond_state prev;
@@ -242,19 +155,9 @@ int cond_set_path(const char *path, enum cond_state next)
break;
case COND_OFF:
if (unlink(path)) {
switch (errno) {
case ENOENT:
break;
case EISDIR:
cond_delpath(path);
break;
default:
if (unlink(path) && errno != ENOENT)
_pe("Failed removing condition '%s'", path);
break;
}
}
break;
default:
_e("Invalid condition state");
@@ -427,7 +330,6 @@ void cond_init(void)
}
cond_bump_reconf();
cond_boot_strap();
}
/**
+1 -2
View File
@@ -31,7 +31,6 @@ enum cond_state cond_get (const char *name);
enum cond_state cond_get_agg (const char *names);
int cond_affects (const char *name, const char *names);
void cond_boot_parse (char *arg);
int cond_update (const char *name);
int cond_set_path (const char *path, enum cond_state new);
void cond_set (const char *name);
@@ -39,7 +38,7 @@ void cond_set_oneshot (const char *name);
void cond_clear (const char *name);
void cond_reload (void);
int cond_set_noupdate(const char *name);
int cond_set_noupdate (const char *name);
int cond_set_oneshot_noupdate(const char *name);
int cond_clear_noupdate(const char *name);
+45 -187
View File
@@ -1,6 +1,6 @@
/* Parser for /etc/finit.conf and /etc/finit.d/<SVC>.conf
*
* Copyright (c) 2012-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -48,16 +48,12 @@
#include "util.h"
#define BOOTSTRAP (runlevel == 0)
#define MATCH_CMD(l, c, x) \
(!strncasecmp(l, c, strlen(c)) && (x = (l) + strlen(c)))
int logfile_size_max = 200000; /* 200 kB */
int logfile_count_max = 5;
struct env_entry {
TAILQ_ENTRY(env_entry) link;
char *name;
};
static TAILQ_HEAD(, env_entry) env_list = TAILQ_HEAD_INITIALIZER(env_list);
struct rlimit initial_rlimit[RLIMIT_NLIMITS];
struct rlimit global_rlimit[RLIMIT_NLIMITS];
@@ -71,7 +67,7 @@ struct conf_change {
static struct iwatch iw_conf;
static uev_t etcw;
static TAILQ_HEAD(, conf_change) conf_change_list = TAILQ_HEAD_INITIALIZER(conf_change_list);
static TAILQ_HEAD(head, conf_change) conf_change_list = TAILQ_HEAD_INITIALIZER(conf_change_list);
static int parse_conf(char *file, int is_rcsd);
static void drop_changes(void);
@@ -91,8 +87,7 @@ fallback:
/*
* finit.debug = [on,off]
* finit.fstab = /path/to/etc/fstab.aternative
* finit.status = [on,off] (compat finit.show_status)
* finit.show_status = [on,off]
* finit.status_style = [old,classic,modern]
*/
static void parse_finit_opts(char *opt)
@@ -108,16 +103,6 @@ static void parse_finit_opts(char *opt)
return;
}
if (string_compare(opt, "fstab")) {
fstab = arg;
return;
}
if (string_compare(opt, "cond")) {
cond_boot_parse(arg);
return;
}
if (string_compare(opt, "status_style")) {
if (!arg) {
_e("status_style option requires an argument, skipping.");
@@ -131,39 +116,12 @@ static void parse_finit_opts(char *opt)
return;
}
if (string_compare(opt, "status") || string_compare(opt, "show_status")) {
if (string_compare(opt, "show_status")) {
show_progress(get_bool(arg, 1) ? PROGRESS_DEFAULT : PROGRESS_SILENT);
return;
}
}
/*
* 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)) {
@@ -171,19 +129,11 @@ 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
@@ -255,98 +205,8 @@ void conf_parse_cmdline(int argc, char *argv[])
parse_kernel_cmdline();
parse_kernel_loglevel();
}
/*
* Clear all environment variables read in parse_env(), they may be
* removed now so let the next call to parse_env() restore them.
*/
void conf_reset_env(void)
{
struct env_entry *node, *tmp;
TAILQ_FOREACH_SAFE(node, &env_list, link, tmp) {
TAILQ_REMOVE(&env_list, node, link);
if (node->name) {
unsetenv(node->name);
free(node->name);
}
free(node);
}
setenv("PATH", _PATH_STDPATH, 1);
setenv("SHELL", _PATH_BSHELL, 1);
setenv("LOGNAME", "root", 1);
setenv("USER", "root", 1);
}
/*
* Sets, and makes a note of, all KEY=VALUE lines in a given .conf line
* from finit.conf, or other .conf file. Note, PATH is always reset in
* the conf_reset_env() function.
*/
static void parse_env(char *line)
{
struct env_entry *node;
char *key, *val, *end;
/* skip any leading whitespace */
key = line;
while (isspace(*key))
key++;
/* find end of line */
end = key;
while (*end)
end++;
/* strip trailing whitespace */
if (end > key) {
end--;
while (isspace(*end))
*end-- = 0;
}
val = strchr(key, '=');
if (!val)
return;
*val++ = 0;
/* strip leading whitespace from value */
while (isspace(*val))
val++;
/* unquote value, if quoted */
if (val[0] == '"' || val[0] == '\'') {
char q = val[0];
if (*end == q) {
val = &val[1];
*end = 0;
}
}
/* find end of key */
end = key;
while (*end)
end++;
/* strip trailing whitespace */
if (end > key) {
end--;
while (isspace(*end))
*end-- = 0;
}
setenv(key, val, 1);
node = malloc(sizeof(*node));
if (!node) {
_pe("Out of memory cannot track env vars");
return;
}
node->name = strdup(key);
TAILQ_INSERT_HEAD(&env_list, node, link);
log_init();
}
static int kmod_exists(char *mod)
@@ -442,10 +302,8 @@ void conf_parse_cond(svc_t *svc, char *cond)
if (svc_is_daemon(svc))
svc->sighup = 1;
if (!cond) {
memset(svc->cond, 0, sizeof(svc->cond));
if (!cond)
return;
}
/* First character must be '!' if SIGHUP is not supported. */
ptr = cond;
@@ -459,12 +317,12 @@ void conf_parse_cond(svc_t *svc, char *cond)
ptr[i] = 0;
if (i >= sizeof(svc->cond)) {
logit(LOG_WARNING, "Too long event list in declaration of %s: %s", svc_ident(svc, NULL, 0), ptr);
logit(LOG_WARNING, "Too long event list in declaration of %s: %s", svc->cmd, ptr);
return;
}
if (!strncmp(ptr, "svc/", 4)) {
logit(LOG_ERR, "Unsupported cond syntax for %s: <%s", svc_ident(svc, NULL, 0), ptr);
logit(LOG_ERR, "Unsupported cond syntax for %s: <%s", svc->cmd, ptr);
return;
}
@@ -622,7 +480,7 @@ static void conf_parse_cgroup(char *line)
cgroup_add(name, config, 0);
}
static int parse_static(char *line, int is_rcsd)
static void parse_static(char *line, int is_rcsd)
{
char cmd[CMD_SIZE];
char *x;
@@ -630,7 +488,7 @@ static int parse_static(char *line, int is_rcsd)
if (BOOTSTRAP && (MATCH_CMD(line, "host ", x) || MATCH_CMD(line, "hostname ", x))) {
if (hostname) free(hostname);
hostname = strdup(strip_line(x));
return 0;
return;
}
if (BOOTSTRAP && MATCH_CMD(line, "mknod ", x)) {
@@ -639,25 +497,25 @@ static int parse_static(char *line, int is_rcsd)
strcpy(cmd, "mknod ");
strlcat(cmd, dev, sizeof(cmd));
run_interactive(cmd, "Creating device node %s", dev);
return 0;
return;
}
/* Kernel module to load */
if (BOOTSTRAP && MATCH_CMD(line, "module ", x)) {
kmod_load(strip_line(x));
return 0;
return;
}
if (BOOTSTRAP && MATCH_CMD(line, "network ", x)) {
if (network) free(network);
network = strdup(strip_line(x));
return 0;
return;
}
if (BOOTSTRAP && MATCH_CMD(line, "runparts ", x)) {
if (runparts) free(runparts);
runparts = strdup(strip_line(x));
return 0;
return;
}
if (MATCH_CMD(line, "include ", x)) {
@@ -666,10 +524,11 @@ static int parse_static(char *line, int is_rcsd)
strlcpy(cmd, file, sizeof(cmd));
if (!fexist(cmd)) {
_e("Cannot find include file %s, absolute path required!", x);
return 1;
return;
}
return parse_conf(cmd, is_rcsd);
parse_conf(cmd, is_rcsd);
return;
}
if (MATCH_CMD(line, "log ", x)) {
@@ -690,14 +549,12 @@ static int parse_static(char *line, int is_rcsd)
logfile_size_max = size;
if (count >= 0)
logfile_count_max = count;
return 0;
}
if (MATCH_CMD(line, "shutdown ", x)) {
if (sdown) free(sdown);
sdown = strdup(strip_line(x));
return 0;
return;
}
/*
@@ -714,7 +571,7 @@ static int parse_static(char *line, int is_rcsd)
cfglevel = RUNLEVEL;
if (cfglevel < 1 || cfglevel > 9 || cfglevel == 6)
cfglevel = 2; /* Fallback */
return 0;
return;
}
/*
@@ -734,65 +591,72 @@ static int parse_static(char *line, int is_rcsd)
if (disabled)
service_init();
}
return 0;
return;
}
return 1;
}
static int parse_dynamic(char *line, struct rlimit rlimit[], char *file)
static void parse_dynamic(char *line, struct rlimit rlimit[], char *file)
{
char *x;
/* Monitored daemon, will be respawned on exit */
if (MATCH_CMD(line, "service ", x)) {
service_register(SVC_TYPE_SERVICE, x, rlimit, file);
return 0;
return;
}
/* One-shot task, will not be respawned */
if (MATCH_CMD(line, "task ", x)) {
service_register(SVC_TYPE_TASK, x, rlimit, file);
return 0;
return;
}
/* Like task but waits for completion, useful w/ [S] */
if (MATCH_CMD(line, "run ", x)) {
service_register(SVC_TYPE_RUN, x, rlimit, file);
return 0;
return;
}
/* Similar to task but is treated like a SysV init script */
if (MATCH_CMD(line, "sysv ", x)) {
service_register(SVC_TYPE_SYSV, x, rlimit, file);
return 0;
return;
}
/* Read resource limits */
if (MATCH_CMD(line, "rlimit ", x)) {
conf_parse_rlimit(x, rlimit);
return 0;
return;
}
/* Read control group limits */
if (MATCH_CMD(line, "cgroup ", x)) {
conf_parse_cgroup(x);
return 0;
return;
}
/* Set current cgroup for the following services/run/tasks */
if (MATCH_CMD(line, "cgroup.", x)) {
strlcpy(cgroup_current, x, sizeof(cgroup_current));
return 0;
return;
}
/* Regular or serial TTYs to run getty */
if (MATCH_CMD(line, "tty ", x)) {
service_register(SVC_TYPE_TTY, strip_line(x), rlimit, file);
return 0;
return;
}
}
return 1;
static void tabstospaces(char *line)
{
if (!line)
return;
for (int i = 0; line[i]; i++) {
if (line[i] == '\t')
line[i] = ' ';
}
}
static int parse_conf(char *file, int is_rcsd)
@@ -826,13 +690,8 @@ static int parse_conf(char *file, int is_rcsd)
if (MATCH_CMD(line, "#", x))
continue;
if (!parse_static(line, is_rcsd))
continue;
if (!parse_dynamic(line, is_rcsd ? rlimit : global_rlimit, file))
continue;
/* Not static or dynamic conf, check if it is a global env. */
parse_env(line);
parse_static(line, is_rcsd);
parse_dynamic(line, is_rcsd ? rlimit : global_rlimit, file);
}
fclose(fp);
@@ -856,7 +715,6 @@ int conf_reload(void)
/* Mark and sweep */
cgroup_mark_all();
svc_mark_dynamic();
conf_reset_env();
/*
* Reset global rlimit to bootstrap values from conf_init().
+1 -2
View File
@@ -1,6 +1,6 @@
/* Parser for /etc/finit.conf and /etc/finit.d/<SVC>.conf
*
* Copyright (c) 2012-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -42,7 +42,6 @@ int conf_any_change (void);
int conf_changed (char *file);
int conf_monitor (void);
void conf_reset_env (void);
void conf_parse_cmdline (int argc, char *argv[]);
int conf_parse_runlevels (char *runlevels);
void conf_parse_cond (svc_t *svc, char *cond);
+5 -7
View File
@@ -1,7 +1,7 @@
/* Functions for exec'ing processes
*
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2008-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -97,14 +97,12 @@ static int do_redirect(void)
*/
int run(char *cmd, char *log)
{
char *args[NUM_ARGS + 1] = { 0 };
int status, result, i = 0;
char *args[NUM_ARGS + 1], *arg;
char *backup = NULL;
pid_t pid;
if (!log) {
char *arg;
/* We must create a copy that is possible to modify. */
backup = arg = strdup(cmd);
if (!arg)
@@ -166,7 +164,7 @@ int run(char *cmd, char *log)
_exit(rc);
} else if (-1 == pid) {
_pe("%s", !log ? args[0] : cmd);
_pe("%s", args[0]);
if (backup)
free(backup);
@@ -329,7 +327,7 @@ static int activate_console(int noclear, int nowait)
static const char clr[] = "\r\e[K";
static const char cup[] = "\e[A";
struct termios orig;
char ch;
char c;
int rc;
if (nowait || rescue)
@@ -351,7 +349,7 @@ static int activate_console(int noclear, int nowait)
dprint(STDERR_FILENO, clr, strlen(clr));
dprint(STDERR_FILENO, msg, strlen(msg));
while ((rc = read(STDIN_FILENO, &ch, 1)) > 0 && ch != '\r' && ch != '\n')
while ((rc = read(STDIN_FILENO, &c, 1)) > 0 && c != '\r' && c != '\n')
continue;
/* On any error (likely EINTR), we avoid starting getty */
+91 -221
View File
@@ -1,7 +1,7 @@
/* Finit - Fast /sbin/init replacement w/ I/O, hook & service plugins
*
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2008-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -26,18 +26,16 @@
#include <ctype.h>
#include <dirent.h>
#include <getopt.h>
#ifdef HAVE_MNTENT_H
#include <mntent.h>
#ifdef HAVE_FSTAB_H
#include <fstab.h>
#endif
#include <getopt.h>
#include <mntent.h>
#include <time.h> /* tzet() */
#include <sys/klog.h>
#include <sys/mount.h>
#include <sys/stat.h> /* umask(), mkdir() */
#include <sys/wait.h>
#ifdef HAVE_SYS_SYSMACROS_H
#include <sys/sysmacros.h>
#endif
#ifdef _LIBITE_LITE
# include <libite/lite.h>
#else
@@ -62,14 +60,12 @@
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 */
int single = 0; /* single user mode from kernel cmdline */
int bootstrap = 1; /* set while bootrapping (for TTYs) */
int kerndebug = 0; /* set if /proc/sys/kernel/printk > 7 */
char *fstab = FINIT_FSTAB;
char *sdown = NULL;
char *network = NULL;
char *hostname = NULL;
@@ -110,170 +106,70 @@ static void banner(void)
#endif
}
static int sulogin(int do_reboot)
{
int rc = EX_OSFILE;
char *cmd[] = {
_PATH_SULOGIN,
"sulogin",
};
size_t i;
for (i = 0; i < NELEMS(cmd); i++) {
char *path = which(cmd[i]);
if (!path)
continue;
if (access(path, X_OK)) {
free(path);
continue;
}
rc = systemf("%s", path);
free(path);
break;
}
if (do_reboot) {
do_shutdown(SHUT_REBOOT);
exit(rc);
}
return rc;
}
char *fs_root_dev(char *real, size_t len)
{
struct dirent *d;
struct stat st;
int found = 0;
dev_t dev;
DIR *dir;
if (stat("/", &st))
return NULL;
if (S_ISBLK(st.st_mode))
dev = st.st_rdev;
else
dev = st.st_dev;
dir = opendir("/sys/block");
if (!dir)
return NULL;
while ((d = readdir(dir))) {
char buf[10];
char *ptr;
if (fnread(buf, sizeof(buf), "/sys/block/%s/dev", d->d_name) == -1)
continue;
ptr = strchr(buf, ':');
if (!ptr)
continue;
*ptr++ = 0;
if (atoi(buf) == (int)major(dev) && atoi(ptr) == (int)minor(dev)) {
/* Guess name, assume no renaming */
snprintf(real, len, "/dev/%s", d->d_name);
found = 1;
break;
}
}
closedir(dir);
if (!found)
return NULL;
return real;
}
/*
* Check all filesystems in /etc/fstab with a fs_passno > 0
*/
static int fsck(int pass)
{
struct mntent mount;
struct mntent *mnt;
char real[192];
char buf[256];
struct fstab *fs;
int rc = 0;
FILE *fp;
fp = setmntent(fstab, "r");
if (!fp) {
_pe("Failed opening fstab: %s", fstab);
sulogin(1);
if (!setfsent()) {
_pe("Failed opening fstab");
return 1;
}
_d("Opened %s, pass %d", fstab, pass);
while ((mnt = getmntent_r(fp, &mount, buf, sizeof(buf)))) {
int fsck_rc = 0;
while ((fs = getfsent())) {
char cmd[80];
struct stat st;
char cmd[256];
char *dev;
int fsck_rc = 0;
_d("got: fsname '%s' dir '%s' type '%s' opts '%s' freq '%d' passno '%d'",
mnt->mnt_fsname, mnt->mnt_dir, mnt->mnt_type, mnt->mnt_opts,
mnt->mnt_freq, mnt->mnt_passno);
if (mnt->mnt_passno == 0 || mnt->mnt_passno != pass)
if (fs->fs_passno != pass)
continue;
/* Device to maybe fsck, */
dev = mnt->mnt_fsname;
errno = 0;
if (stat(dev, &st) || !S_ISBLK(st.st_mode)) {
int skip = 1;
if (string_match(dev, "UUID=") || string_match(dev, "LABEL="))
skip = 0;
/*
* Kernel short form for root= device, figure out
* actual device since we cannot rely on symlinks
* https://bugs.busybox.net/show_bug.cgi?id=8891
*/
else if (string_compare(dev, "/dev/root")) {
if (fs_root_dev(real, sizeof(real))) {
dev = real;
skip = 0;
}
}
if (skip) {
_d("Cannot fsck %s, not a block device: %s", dev, strerror(errno));
if (stat(fs->fs_spec, &st) || !S_ISBLK(st.st_mode)) {
if (!string_match(fs->fs_spec, "UUID=") && !string_match(fs->fs_spec, "LABEL=")) {
_d("Cannot fsck %s, not a block device: %s", fs->fs_spec, strerror(errno));
continue;
}
}
if (ismnt("/proc/mounts", mnt->mnt_dir, "rw")) {
_d("Skipping fsck of %s, already mounted rw on %s.", dev, mnt->mnt_dir);
if (ismnt("/proc/mounts", fs->fs_file, "rw")) {
_d("Skipping fsck of %s, already mounted rw on %s.", fs->fs_spec, fs->fs_file);
continue;
}
#ifdef FSCK_FIX
snprintf(cmd, sizeof(cmd), "fsck -yf %s", dev);
snprintf(cmd, sizeof(cmd), "fsck -yf %s", fs->fs_spec);
#else
snprintf(cmd, sizeof(cmd), "fsck -a %s", dev);
snprintf(cmd, sizeof(cmd), "fsck -a %s", fs->fs_spec);
#endif
_d("Running pass %d fsck command %s", pass, cmd);
fsck_rc = run_interactive(cmd, "Checking filesystem %s", dev);
fsck_rc = run_interactive(cmd, "Checking filesystem %.13s", fs->fs_spec);
/*
* "failure" is defined as exiting with a return code of
* 2 or larger. A return code of 1 indicates that filesystem
* errors were corrected but that the boot may proceed.
*/
if (fsck_rc > 1) {
logit(LOG_CONSOLE | LOG_ALERT, "Failed fsck %s, attempting sulogin ...", dev);
sulogin(1);
char *sulogin[] = {
_PATH_SULOGIN,
"sulogin",
};
size_t i;
for (i = 0; i < NELEMS(sulogin); i++) {
if (systemf(sulogin[i]))
continue;
break;
}
do_shutdown(SHUT_REBOOT);
}
rc += fsck_rc;
}
endmntent(fp);
endfsent();
return rc;
}
@@ -306,22 +202,38 @@ static void fs_mount(const char *src, const char *tgt, const char *fstype,
}
#ifndef SYSROOT
/* If / is not listed in fstab, or listed as 'ro', leave it alone */
static int fs_readonly_root(struct fstab *fs)
{
char *tok, *str;
if (!fs)
return 1;
str = fs->fs_mntops;
while ((tok = strtok(str, ","))) {
if (!strcmp(tok, "ro"))
return 1;
str = NULL;
}
return 0;
}
static void fs_remount_root(int fsckerr)
{
struct mntent *mnt;
FILE *fp;
struct fstab *fs;
fp = setmntent(fstab, "r");
if (!fp)
if (!setfsent())
return;
while ((mnt = getmntent(fp))) {
if (!strcmp(mnt->mnt_dir, "/"))
while ((fs = getfsent())) {
if (!strcmp(fs->fs_file, "/"))
break;
}
/* If / is not listed in fstab, or listed as 'ro', leave it alone */
if (!mnt || hasmntopt(mnt, "ro"))
if (fs_readonly_root(fs))
goto out;
if (fsckerr)
@@ -331,7 +243,7 @@ static void fs_remount_root(int fsckerr)
"Remounting / as read-write");
out:
endmntent(fp);
endfsent();
}
#else
static void fs_remount_root(int fsckerr)
@@ -407,69 +319,22 @@ static void fs_finalize(void)
fs_mount("tmpfs", "/tmp", "tmpfs", MS_NOSUID | MS_NODEV, "mode=1777");
}
static void fs_swapon(char *cmd, size_t len)
{
struct mntent *mnt;
FILE *fp;
if (!whichp("swapon"))
return;
fp = setmntent(fstab, "r");
if (!fp)
return;
while ((mnt = getmntent(fp))) {
if (strcmp(mnt->mnt_type, MNTTYPE_SWAP))
continue;
snprintf(cmd, len, "swapon %s", mnt->mnt_fsname);
run_interactive(cmd, "Enabling swap %s", mnt->mnt_fsname);
}
endmntent(fp);
}
static void fs_mount_all(void)
{
char cmd[256] = "mount -na";
if (!fstab || !fexist(fstab)) {
logit(LOG_CONSOLE | LOG_NOTICE, "%s system fstab %s, trying fallback ...",
!fstab ? "Missing" : "Cannot find", fstab ?: "\b");
fstab = FINIT_FSTAB;
}
if (!fstab || !fexist(fstab)) {
logit(LOG_CONSOLE | LOG_EMERG, "%s system fstab %s, attempting sulogin ...",
!fstab ? "Missing" : "Cannot find", fstab ?: "\b");
sulogin(1);
}
/*
* Needed by fsck, both BusyBox and util-linux support this.
* We leave it set in the env. for the benefit of any mount
* helpers and other system tools that the user expects to
* behave even if we've booted with a different fstab.
*/
setenv("FSTAB_FILE", fstab, 1);
if (!rescue)
fs_remount_root(fsck_all());
_d("Root FS up, calling hooks ...");
plugin_run_hooks(HOOK_ROOTFS_UP);
if (fstab && strcmp(fstab, "/etc/fstab"))
snprintf(cmd, sizeof(cmd), "mount -na -T %s", fstab);
if (run_interactive(cmd, "Mounting filesystems from %s", fstab))
if (run_interactive("mount -na", "Mounting filesystems"))
plugin_run_hooks(HOOK_MOUNT_ERROR);
_d("Calling extra mount hook, after mount -a ...");
plugin_run_hooks(HOOK_MOUNT_POST);
_d("Enable any swap ...");
fs_swapon(cmd, sizeof(cmd));
if (whichp("swapon"))
run("swapon -ea", "swapon");
_d("Finalize, ensure common file systems are available ...");
fs_finalize();
@@ -573,12 +438,11 @@ 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 * 10; /* We run with 100ms period */
int level = cfglevel;
_d("Step all services ...");
service_step_all(SVC_TYPE_ANY);
@@ -603,18 +467,11 @@ static void bootstrap_worker(void *work)
if (runparts && fisdir(runparts) && !rescue)
run_parts(runparts, NULL);
/*
* Start all tasks/services in the configured runlevel, or jump
* into the runlevel selected from the command line.
* Start all tasks/services in the configured runlevel
*/
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);
service_runlevel(cfglevel);
}
static int version(int rc)
@@ -713,7 +570,7 @@ int main(int argc, char *argv[])
};
uev_ctx_t loop;
/* user calling telinit or init */
/* telinit or stand-alone process monitor */
if (getpid() != 1)
return telinit(argc, argv);
@@ -724,12 +581,12 @@ int main(int argc, char *argv[])
/*
* Parse /proc/cmdline (debug, rescue, console=, etc.)
* Also calls log_init() to set correct log level
*/
conf_parse_cmdline(argc, argv);
/*
* Figure out system console(s) and call log_init() to set
* correct log level, possibly finit.debug enabled.
* Figure out system console(s)
*/
console_init();
@@ -742,7 +599,10 @@ int main(int argc, char *argv[])
/*
* Set PATH, SHELL, and PWD early to something sane
*/
conf_reset_env();
setenv("PATH", _PATH_STDPATH, 1);
setenv("SHELL", _PATH_BSHELL, 1);
setenv("LOGNAME", "root", 1);
setenv("USER", "root", 1);
if (chdir("/"))
_pe("Failed cd /");
@@ -750,8 +610,21 @@ int main(int argc, char *argv[])
/*
* In case of emergency.
*/
if (rescue)
rescue = sulogin(0);
if (rescue) {
char *sulogin[] = {
_PATH_SULOGIN,
"sulogin",
};
size_t i;
for (i = 0; i < NELEMS(sulogin); i++) {
if (systemf(sulogin[i]))
continue;
rescue = 0;
break;
}
}
/*
* Load plugins early, the first hook is in banner(), so we
@@ -780,10 +653,7 @@ int main(int argc, char *argv[])
*/
cgroup_init(&loop);
/*
* Check custom fstab from cmdline, including fallback, then run
* fsck before mounting all filesystems, on error call sulogin.
*/
/* Check and mount filesystems. */
fs_mount_all();
/* Bootstrap conditions, needed for hooks */
@@ -806,7 +676,7 @@ int main(int argc, char *argv[])
*/
if (whichp(FINIT_LIBPATH_ "/watchdogd") && fexist(WDT_DEVNODE)) {
service_register(SVC_TYPE_SERVICE, "[123456789] cgroup.init name:watchdog :finit " FINIT_LIBPATH_ "/watchdogd -- Finit watchdog daemon", global_rlimit, NULL);
wdog = svc_find("watchdog", "finit");
wdog = svc_find_by_nameid("watchdog", "finit");
}
/*
+4 -6
View File
@@ -1,7 +1,7 @@
/* Finit - Fast /sbin/init replacement w/ I/O, hook & service plugins
*
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2008-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -83,8 +83,8 @@
#define INIT_CMD_STOP_SVC 11
#define INIT_CMD_RELOAD_SVC 12 /* SIGHUP service */
#define INIT_CMD_RESTART_SVC 13 /* START service, clearing blocks */
#define INIT_CMD_GET_PLUGINS 14 /* Fill data[] with loaded plugins */
#define INIT_CMD_PLUGIN_DEPS 15 /* Fill data[] with plugin deps */
#define INIT_CMD_UNUSED2 14 /* Unused, was INIT_CMD_QUERY_INETD */
#define INIT_CMD_UNUSED1 15 /* Unused, was INIT_CMD_EMIT */
#define INIT_CMD_GET_RUNLEVEL 16
#define INIT_CMD_REBOOT 20
#define INIT_CMD_HALT 21
@@ -110,18 +110,16 @@ struct init_request {
extern int runlevel;
extern int cfglevel;
extern int cmdlevel;
extern int prevlevel;
extern int debug;
extern int rescue;
extern int single;
extern int bootstrap;
extern int kerndebug;
extern char *fstab;
extern char *rcsd;
extern char *sdown;
extern char *network;
extern char *hostname;
extern char *rcsd;
extern char *runparts;
extern char *osheading;
extern uev_ctx_t *ctx;
+3 -10
View File
@@ -1,6 +1,6 @@
/* Initialize and serve a login terminal
*
* Copyright (c) 2016-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2016-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -21,7 +21,7 @@
* THE SOFTWARE.
*/
#include "config.h" /* Generated by configure script */
#include "config.h"
#include <err.h>
#include <errno.h>
@@ -49,7 +49,6 @@
#endif
static long logname_len = 32; /* useradd(1) limit at 32 chars */
static int passenv = 0; /* Set /bin/login -p or not */
/*
* Read one character from stdin.
@@ -186,9 +185,6 @@ static int do_login(char *name)
{
struct stat st;
if (passenv)
execl(_PATH_LOGIN, _PATH_LOGIN, "-p", name, NULL);
else
execl(_PATH_LOGIN, _PATH_LOGIN, name, NULL);
/*
@@ -256,14 +252,11 @@ int main(int argc, char *argv[])
char *tty, *speed = "0", *term = NULL;
int c;
while ((c = getopt(argc, argv, "h?p")) != EOF) {
while ((c = getopt(argc, argv, "h?")) != EOF) {
switch(c) {
case 'h':
case '?':
return usage(0);
case 'p':
passenv = 1;
break;
default:
return usage(1);
}
+51 -28
View File
@@ -1,7 +1,7 @@
/* Misc. utility functions for finit and its plugins
*
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2008-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -22,8 +22,6 @@
* THE SOFTWARE.
*/
#include "config.h" /* Generated by configure script */
#include <ctype.h> /* isblank() */
#include <errno.h>
#include <grp.h>
@@ -83,7 +81,7 @@ char *console(void)
void console_init(void)
{
log_init();
ttinit();
}
ssize_t cprintf(const char *fmt, ...)
@@ -102,17 +100,6 @@ ssize_t cprintf(const char *fmt, ...)
return size;
}
void tabstospaces(char *line)
{
if (!line)
return;
for (int i = 0; line[i]; i++) {
if (line[i] == '\t')
line[i] = ' ';
}
}
char *strip_line(char *line)
{
char *ptr;
@@ -513,25 +500,20 @@ void networking(int updown)
if (fexist("/etc/network/interfaces")) {
pid_t pid;
if (!updown) {
run_interactive("ifdown -a", "Stopping networking");
goto done;
}
pid = fork();
if (pid == 0) {
int rc = EX_OSERR;
const char *cmd;
FILE *pp;
setsid();
sig_unblock();
if (updown)
cmd = "ifup -a 2>&1";
else if (whichp("ifquery"))
/* Regular ifodwn supports --force but not -f */
cmd = "ifdown -a --force 2>&1";
else
/* Busybox ifdown support -f, but not --force */
cmd = "ifdown -a -f 2>&1";
pp = popen(cmd, "r");
pp = popen("ifup -a 2>&1", "r");
if (pp) {
char buf[256];
@@ -544,8 +526,7 @@ void networking(int updown)
_exit(rc);
}
cgroup_service("network", pid, NULL);
print(pid > 0 ? 0 : 1, "%s network interfaces ...",
updown ? "Bringing up" : "Taking down");
print(pid > 0 ? 0 : 1, "Bringing up network interfaces ...");
goto done;
}
@@ -600,6 +581,48 @@ int in_container(void)
return 0;
}
#ifndef HAVE_GETFSENT
static lfile_t *fstab = NULL;
int setfsent(void)
{
if (fstab)
lfclose(fstab);
fstab = lfopen("/etc/fstab", " \t\n");
if (!fstab)
return 0;
return 1;
}
struct fstab *getfsent(void)
{
static struct fstab fs;
fs.fs_spec = lftok(fstab);
if (fs.fs_spec == NULL)
return NULL;
fs.fs_file = lftok(fstab);
fs.fs_vfstype = lftok(fstab);
fs.fs_mntops = lftok(fstab);
fs.fs_type = "rw";
fs.fs_freq = atoi(lftok(fstab) ?: "0");
fs.fs_passno = atoi(lftok(fstab) ?: "0");
return &fs;
}
void endfsent(void)
{
if (fstab)
lfclose(fstab);
fstab = NULL;
}
#endif /* HAVE_GETFSENT */
/**
* Local Variables:
* indent-tabs-mode: t
+22 -5
View File
@@ -1,7 +1,7 @@
/* Misc. utility functions and C-library extensions for finit and its plugins
*
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2008-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -25,6 +25,8 @@
#ifndef FINIT_HELPERS_H_
#define FINIT_HELPERS_H_
#include <mntent.h>
#include <sched.h> /* sched_yield() */
#include <stdarg.h>
#include <sys/resource.h>
#include <sys/types.h>
@@ -45,11 +47,26 @@ typedef enum {
PROGRESS_MODERN,
} pstyle_t;
#ifndef HAVE_GETFSENT
struct fstab {
char *fs_spec; /* block device name */
char *fs_file; /* mount point */
char *fs_vfstype; /* file-system type */
char *fs_mntops; /* mount options */
const char *fs_type; /* rw/rq/ro/sw/xx option */
int fs_freq; /* dump frequency, in days */
int fs_passno; /* pass number on parallel dump */
};
int setfsent (void);
void endfsent (void);
struct fstab *getfsent (void);
#endif /* HAVE_GETFSENT */
char *console (void);
void console_init (void);
ssize_t cprintf (const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
ssize_t cprintf (const char *fmt, ...);
void tabstospaces (char *line);
char *strip_line (char *line);
void enable_progress (int onoff);
@@ -62,7 +79,7 @@ void stty (int fd, speed_t speed);
void print_banner (const char *heading);
void printv (const char *fmt, va_list ap);
void print (int action, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
void print (int action, const char *fmt, ...);
void print_desc (char *action, char *desc);
int print_result (int fail);
@@ -80,7 +97,7 @@ int in_container (void);
int complete (char *cmd, int pid);
int run (char *cmd, char *log);
int run_interactive (char *cmd, char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
int run_interactive (char *cmd, char *fmt, ...);
int exec_runtask (char *cmd, char *args[]);
pid_t run_getty (char *tty, char *cmd, char *args[], int noclear, int nowait, struct rlimit rlimit[]);
pid_t run_sh (char *tty, int noclear, int nowait, struct rlimit rlimit[]);
+111 -191
View File
@@ -1,6 +1,6 @@
/* New client tool, replaces old /dev/initctl API and telinit tool
*
* Copyright (c) 2015-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2015-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -23,6 +23,7 @@
#include "config.h"
#include <err.h>
#include <ftw.h>
#include <ctype.h>
#include <getopt.h>
@@ -38,7 +39,6 @@
# include <lite/lite.h>
#endif
#include "initctl.h"
#include "client.h"
#include "cond.h"
#include "serv.h"
@@ -64,7 +64,6 @@ int verbose = 0;
int plain = 0;
int quiet = 0;
int runlevel = 0;
int timeout = 0;
int cgrp = 0;
int utmp = 0;
@@ -155,21 +154,12 @@ static int toggle_debug(char *arg)
return client_send(&rq, sizeof(rq));
}
static int do_log(svc_t *svc, char *tail)
static int do_log(char *svc)
{
const char *logfile = "/var/log/syslog";
pid_t pid;
char *nm;
char *logfile = "/var/log/syslog";
if (svc) {
nm = svc_ident(svc, NULL, 0);
pid = svc->pid;
if (!pid)
return 0; /* not running */
} else {
nm = "finit";
pid = 1;
}
if (!svc || !svc[0])
svc = "finit";
if (!fexist(logfile)) {
logfile = "/var/log/messages";
@@ -177,20 +167,7 @@ static int do_log(svc_t *svc, char *tail)
return 0; /* bail out, maybe in container */
}
return systemf("cat %s | grep '\\[%d\\]\\|%s' %s", logfile, pid, nm, tail);
}
static int show_log(char *arg)
{
svc_t *svc = NULL;
if (arg) {
svc = client_svc_find(arg);
if (!svc)
ERRX(69, "no such task or service(s): %s", arg);
}
return do_log(svc, "");
return systemf("cat %s | grep %s | tail -10", logfile, svc);
}
static int do_runlevel(char *arg)
@@ -252,11 +229,20 @@ static int do_startstop(int cmd, char *arg)
};
if (!arg || !arg[0])
ERRX(2, "missing command argument");
errx(1, "missing argument to %s", (cmd == INIT_CMD_START_SVC
? "start"
: (cmd == INIT_CMD_STOP_SVC
? "stop"
: "restart")));
strlcpy(rq.data, arg, sizeof(rq.data));
if (client_send(&rq, sizeof(rq)))
ERRX(69, "no such task or service(s): %s", arg);
if (client_send(&rq, sizeof(rq))) {
fprintf(stderr, "No such task or service(s): %s\n\n", arg);
fprintf(stderr, "Usage: initctl %s <NAME>[:ID]\n",
cmd == INIT_CMD_START_SVC ? "start" :
(cmd == INIT_CMD_STOP_SVC ? "stop" : "restart"));
return 1;
}
return do_svc(cmd, arg);
}
@@ -274,10 +260,23 @@ static int do_reload (char *arg)
static int do_restart(char *arg)
{
if (do_startstop(INIT_CMD_RESTART_SVC, arg))
ERRX(7, "failed restarting %s", arg);
size_t retries = 3;
svc_t *svc;
return 0;
if (do_startstop(INIT_CMD_STOP_SVC, arg))
return 1;
while (retries-- > 0 && (svc = client_svc_find(arg))) {
if (!svc_is_running(svc))
break;
sleep(1);
}
if (retries == 0)
errx(1, "Failed stopping %s (restart)", arg);
return do_startstop(INIT_CMD_RESTART_SVC, arg);
}
/**
@@ -299,19 +298,27 @@ int do_signal(int argc, char *argv[])
int signo;
if (argc != 2)
ERRX(2, "invalid number of arguments to signal");
errx(1, "invalid number of arguments to signal");
/* Validate service name */
strlcpy(rq.data, argv[0], sizeof(rq.data));
if (client_send(&rq, sizeof(rq)))
ERRX(69, "no such task or service(s): %s", argv[0]);
if (client_send(&rq, sizeof(rq))) {
fprintf(stderr, "No such task or service(s): %s\n\n", argv[0]);
goto show_usage;
}
/* Validate signal name (or number) */
signo = str2sig(argv[1]);
if (signo == -1) {
const char *errstr = NULL;
/* Not a signal name, is it an actual signal number? */
errno = 0;
signo = (int)strtol(argv[1], NULL, 10);
signo = (int)strtonum(argv[1], 1, 31, &errstr);
if (errstr)
ERRX(65, "%s signal: %s", errstr, argv[1]);
/* Was it a number? Was it a signo that finit recognizes? */
if (errno || !*(sig2str(signo))) {
fprintf(stderr, "Not a valid signal (or signo): %s\n", argv[1]);
goto show_usage;
}
}
/* Reuse runlevel for signal number. */
@@ -321,9 +328,12 @@ int do_signal(int argc, char *argv[])
strlcpy(rq.data, argv[0], sizeof(rq.data));
return client_send(&rq, sizeof(rq));
show_usage:
fprintf(stderr, "Usage: initctl signal <NAME>[:ID] <S>\n");
return 1;
}
char *dump_filter;
static int dump_one_cond(const char *fpath, const struct stat *sb, int tflag, struct FTW *ftwbuf)
{
const char *cond, *asserted;
@@ -338,10 +348,6 @@ static int dump_one_cond(const char *fpath, const struct stat *sb, int tflag, st
asserted = condstr(cond_get_path(fpath));
cond = &fpath[strlen(_PATH_COND)];
if (dump_filter && dump_filter[0] && strncmp(cond, dump_filter, strlen(dump_filter)))
return 0;
if (strncmp("pid/", cond, 4) == 0) {
svc_t *svc;
@@ -369,68 +375,53 @@ static int dump_one_cond(const char *fpath, const struct stat *sb, int tflag, st
static int do_cond_dump(char *arg)
{
col_widths();
if (heading)
print_header("%-*s %-*s %-6s %s", pw, "PID", iw, "IDENT",
"STATUS", "CONDITION");
if (heading) {
char title[80];
snprintf(title, sizeof(title), "%-*s %-*s %-6s %s", pw, "PID",
iw, "IDENT", "STATUS", "CONDITION");
print_header(title);
}
dump_filter = arg;
if (nftw(_PATH_COND, dump_one_cond, 20, 0) == -1) {
WARNX("Failed parsing %s", _PATH_COND);
warnx("Failed parsing %s", _PATH_COND);
return 1;
}
return 0;
}
typedef enum { COND_CLR, COND_SET, COND_GET } condop_t;
static int do_cond_act(char *arg, condop_t op)
static int do_cond_act(char *arg, int creat)
{
char path[256];
char oneshot[256];
size_t off;
if (arg && strncmp(arg, COND_USR, strlen(COND_USR)) == 0)
arg += strlen(COND_USR);
if (!arg || !arg[0])
ERRX(2, "Invalid condition (empty)");
/* allowed to read any condition, but not set/clr */
if (op != COND_GET) {
errx(1, "Invalid condition (empty)");
if (strchr(arg, '/'))
ERRX(2, "Invalid condition (slashes)");
errx(1, "Invalid condition (slashes)");
if (strchr(arg, '.'))
ERRX(2, "Invalid condition (periods)");
}
errx(1, "Invalid condition (periods)");
if (strchr(arg, '/'))
snprintf(path, sizeof(path), _PATH_COND "%s", arg);
else
snprintf(path, sizeof(path), _PATH_CONDUSR "%s", arg);
snprintf(oneshot, sizeof(oneshot), _PATH_CONDUSR "%s", arg);
off = strlen(_PATH_COND);
switch (op) {
case COND_GET:
off = !fexist(path);
if (verbose)
puts(off ? "off" : "on");
return off;
case COND_SET:
if (symlink(_PATH_RECONF, path) && errno != EEXIST)
ERR(73, "Failed asserting condition <%s>", &path[off]);
break;
case COND_CLR:
if (erase(path) && errno != ENOENT)
ERR(73, "Failed deasserting condition <%s>", &path[off]);
break;
if (creat) {
if (symlink(_PATH_RECONF, oneshot) && errno != EEXIST)
err(1, "Failed asserting condition <%s>", &oneshot[off]);
} else {
if (erase(oneshot) && errno != ENOENT)
err(1, "Failed deasserting condition <%s>", &oneshot[off]);
}
return 0;
}
static int do_cond_get(char *arg) { return do_cond_act(arg, COND_GET); }
static int do_cond_set(char *arg) { return do_cond_act(arg, COND_SET); }
static int do_cond_clr(char *arg) { return do_cond_act(arg, COND_CLR); }
static int do_cond_set(char *arg) { return do_cond_act(arg, 1); }
static int do_cond_clr(char *arg) { return do_cond_act(arg, 0); }
static char *svc_cond(svc_t *svc, char *buf, size_t len)
{
@@ -489,9 +480,13 @@ static int do_cond_show(char *arg)
svc_t *svc;
col_widths();
if (heading)
print_header("%-*s %-*s %-6s %s", pw, "PID", iw, "IDENT",
"STATUS", "CONDITION (+ ON, ~ FLUX, - OFF)");
if (heading) {
char title[80];
snprintf(title, sizeof(title), "%-*s %-*s %-6s %s", pw, "PID",
iw, "IDENT", "STATUS", "CONDITION (+ ON, ~ FLUX, - OFF)");
print_header(title);
}
for (svc = client_svc_iterator(1); svc; svc = client_svc_iterator(0)) {
if (!svc->cond[0])
@@ -518,7 +513,6 @@ static int do_cmd(int cmd)
struct init_request rq = {
.magic = INIT_MAGIC,
.cmd = cmd,
.sleeptime = timeout,
};
if (client_send(&rq, sizeof(rq))) {
@@ -605,44 +599,6 @@ static int show_version(char *arg)
return 0;
}
static int plugins_list(char *arg)
{
struct init_request rq = {
.magic = INIT_MAGIC,
.cmd = INIT_CMD_GET_PLUGINS,
};
char buf[sizeof(rq.data)];
char *ptr;
int rc;
rc = client_send(&rq, sizeof(rq));
if (rc) {
if (rc == 255)
return 69;
else
ERRX(69, "No such command");
}
memcpy(buf, rq.data, sizeof(buf));
if (heading)
print_header("%-18s %s", "PLUGIN", "DEPENDENCIES");
ptr = strtok(buf, " ");
while (ptr) {
rq.cmd = INIT_CMD_PLUGIN_DEPS;
strlcpy(rq.data, ptr, sizeof(rq.data));
rc = client_send(&rq, sizeof(rq));
if (rc)
printf("%s\n", ptr);
else
printf("%-18s %s\n", ptr, rq.data);
ptr = strtok(NULL, " ");
}
return 0;
}
/**
* runlevel_string - Convert a bit encoded runlevel to .conf syntax
* @levels: Bit encoded runlevels
@@ -708,13 +664,6 @@ static char *svc_command(svc_t *svc, char *buf, size_t len)
strlcat(buf, svc->args[i], len);
}
if (svc_is_sysv(svc)) {
char *cmd = svc->state == SVC_HALTED_STATE ? "stop" : "start";
strlcat(buf, " ", len);
strlcat(buf, cmd, len);
}
strlcat(buf, bold ? "\e[0m" : "", len);
return buf;
@@ -734,17 +683,16 @@ static char *svc_environ(svc_t *svc, char *buf, size_t len)
return buf;
}
static char *exit_status(svc_t *svc, char *buf, size_t len)
static char *exit_status(int status, char *buf, size_t len)
{
int rc, sig;
rc = WEXITSTATUS(svc->status);
sig = WTERMSIG(svc->status);
rc = WEXITSTATUS(status);
sig = WTERMSIG(status);
if (WIFEXITED(svc->status))
snprintf(buf, len, " (code=exited, status=%d%s%s)", rc, code2str(rc),
svc->manual ? ", manual=yes" : "");
else if (WIFSIGNALED(svc->status))
if (WIFEXITED(status))
snprintf(buf, len, " (code=exited, status=%d%s)", rc, code2str(rc));
else if (WIFSIGNALED(status))
snprintf(buf, len, " (code=signal, status=%d%s)", sig, sig2str(sig));
return buf;
@@ -760,7 +708,7 @@ static char *status(svc_t *svc, int full)
s = svc_status(svc);
switch (svc->state) {
case SVC_HALTED_STATE:
exit_status(svc, ok, sizeof(ok));
exit_status(svc->status, ok, sizeof(ok));
color = "\e[1m";
break;
@@ -769,7 +717,7 @@ static char *status(svc_t *svc, int full)
break;
case SVC_DONE_STATE:
exit_status(svc, ok, sizeof(ok));
exit_status(svc->status, ok, sizeof(ok));
if (WIFEXITED(svc->status)) {
if (WEXITSTATUS(svc->status))
color = "\e[1;31m";
@@ -784,7 +732,7 @@ static char *status(svc_t *svc, int full)
break;
default:
exit_status(svc, ok, sizeof(ok));
exit_status(svc->status, ok, sizeof(ok));
color = "\e[1;33m";
break;
}
@@ -816,28 +764,6 @@ static void show_cgroup_tree(char *group, char *pfx)
cgroup_tree(path, pfx, 0, 0);
}
/*
* arg: 'foo' should match foo:1 foo:2, etc. but not foobar
* arg: 'foo:1' should only match foo:1
* arg: 'foo:' is allowed to fail, unsupported syntax atm
* arg: 'foo:*' is allowed to fail, unsupported syntax atm
*/
static int svc_compare(svc_t *svc, char *arg)
{
char ident[MAX_IDENT_LEN];
char *ptr;
svc_ident(svc, ident, sizeof(ident));
ptr = strchr(ident, ':');
if (ptr && !strchr(arg, ':'))
*ptr = 0;
if (!strcmp(ident, arg))
return 1;
return 0;
}
static int show_status(char *arg)
{
char ident[MAX_IDENT_LEN];
@@ -851,16 +777,22 @@ static int show_status(char *arg)
long now = jiffies();
char uptm[42] = "N/A";
char *pidfn = NULL;
int exact = 0;
for (svc = client_svc_iterator(1); svc; svc = client_svc_iterator(0))
num += svc_compare(svc, arg);
for (svc = client_svc_iterator(1); svc; svc = client_svc_iterator(0)) {
svc_ident(svc, ident, sizeof(ident));
if (string_compare(ident, arg))
num++;
if (string_case_compare(ident, arg))
exact++;
}
if (num > 1)
if (num > 1 && !exact)
break;
svc = client_svc_find(arg);
if (!svc)
ERRX(69, "no such task or service(s): %s", arg);
return 255;
if (quiet) {
if (svc_is_runtask(svc))
@@ -890,8 +822,6 @@ static int show_status(char *arg)
printf(" User : %s\n", svc->username);
printf(" Group : %s\n", svc->group);
printf(" Uptime : %s\n", svc->pid ? uptime(now - svc->start_time, uptm, sizeof(uptm)) : uptm);
if (svc->manual)
printf(" Starts : %d\n", svc->once);
printf(" Restarts : %d (%d/%d)\n", svc->restart_tot, svc->restart_cnt, svc->restart_max);
printf(" Runlevels : %s\n", runlevel_string(runlevel, svc->runlevels));
if (cgrp && svc->pid > 1) {
@@ -915,7 +845,7 @@ static int show_status(char *arg)
no_cgroup:
printf("\n");
return do_log(svc, "| tail -10");
return do_log(svc->cmd);
}
col_widths();
@@ -929,14 +859,14 @@ static int show_status(char *arg)
else
strlcat(title, "COMMAND", sizeof(title));
print_header("%s", title);
print_header(title);
}
for (svc = client_svc_iterator(1); svc; svc = client_svc_iterator(0)) {
char *lvls;
svc_ident(svc, ident, sizeof(ident));
if (num && !svc_compare(svc, arg))
if (num && !string_compare(ident, arg))
continue;
printf("%-*d ", pw, svc->pid);
@@ -1025,13 +955,13 @@ static int usage(int rc)
" -b, --batch Batch mode, no screen size probing\n"
" -c, --create Create missing paths (and files) as needed\n"
" -f, --force Ignore missing files and arguments, never prompt\n"
" -h, --help This help text\n"
" -1, --once Only one lap in commands like 'top'\n"
" -p, --plain Use plain table headings, no ctrl chars\n"
" -q, --quiet Silent, only return status of command\n"
" -t, --no-heading Skip table headings\n"
" -v, --verbose Verbose output\n"
" -V, --version Show program version\n"
" -h, --help This help text\n"
"\n"
"Commands:\n"
" debug Toggle Finit (daemon) debug\n"
@@ -1066,19 +996,17 @@ static int usage(int rc)
" reload Reload " FINIT_CONF " (activate changes)\n");
fprintf(stderr,
// " reload <NAME>[:ID] Reload (SIGHUP) service by name\n"
"\n"
" cond set <COND> Set (assert) user-defined condition +usr/COND\n"
" cond get <COND> Get status of user-defined condition, see $? and -v\n"
" cond clear <COND> Clear (deassert) user-defined condition -usr/COND\n"
" cond status Show condition status, default cond command\n"
" cond dump [TYPE] Dump all, or a type of, conditions and their status\n"
" cond dump Dump all conditions and their status\n"
"\n"
" log [NAME] Show ten last Finit, or NAME, messages from syslog\n"
" start <NAME>[:ID] Start service by name, with optional ID\n"
" stop <NAME>[:ID] Stop/Pause a running service by name\n"
" reload <NAME>[:ID] Reload service as if .conf changed (SIGHUP or restart)\n"
" This allows restart of run/tasks that have already run\n"
" Note: Finit .conf file(s) are *not* reloaded!\n"
" reload <NAME>[:ID] Reload service by name (SIGHUP or restart)\n"
" restart <NAME>[:ID] Restart (stop/start) service by name\n"
" signal <NAME>[:ID] <S> Send signal S to service by name, with optional ID\n"
" ident [NAME] Show matching identities for NAME, or all\n"
@@ -1091,8 +1019,6 @@ static int usage(int rc)
" ps List processes based on cgroups\n"
" top Show top-like listing based on cgroups\n");
fprintf(stderr,
"\n"
" plugins List installed plugins\n"
"\n"
" runlevel [0-9] Show or set runlevel: 0 halt, 6 reboot\n"
" reboot Reboot system\n"
@@ -1162,7 +1088,7 @@ static int cmd_parse(int argc, char *argv[], struct cmd *command)
}
if (argv[0] && strlen(argv[0]) > 0)
ERRX(3, "No such command. See 'initctl help' for an overview of available commands.");
errx(1, "No such command. See 'initctl help' for an overview of available commands.");
return command[0].cb(NULL); /* default cmd */
}
@@ -1187,7 +1113,6 @@ int main(int argc, char *argv[])
{ "status", NULL, do_cond_show, NULL, NULL }, /* default cmd */
{ "dump", NULL, do_cond_dump, NULL, NULL },
{ "set", NULL, do_cond_set, NULL, NULL },
{ "get", NULL, do_cond_get, NULL, NULL },
{ "clr", NULL, do_cond_clr, NULL, NULL },
{ "clear", NULL, do_cond_clr, NULL, NULL },
{ NULL, NULL, NULL, NULL, NULL }
@@ -1214,7 +1139,7 @@ int main(int argc, char *argv[])
{ "cond", cond, NULL, NULL, NULL },
{ "log", NULL, show_log, NULL, NULL },
{ "log", NULL, do_log, NULL, NULL },
{ "start", NULL, do_start, NULL, NULL },
{ "stop", NULL, do_stop, NULL, NULL },
{ "restart", NULL, do_restart, NULL, NULL },
@@ -1224,8 +1149,6 @@ int main(int argc, char *argv[])
{ "ps", NULL, show_cgps, &cgrp, NULL },
{ "top", NULL, show_cgtop, &cgrp, NULL },
{ "plugins", NULL, plugins_list, NULL, NULL },
{ "runlevel", NULL, do_runlevel, NULL, NULL },
{ "reboot", NULL, do_reboot, NULL, NULL },
{ "halt", NULL, do_halt, NULL, NULL },
@@ -1301,9 +1224,6 @@ void logit(int prio, const char *fmt, ...)
{
va_list ap;
if (quiet)
return;
va_start(ap, fmt);
if (prio <= LOG_ERR)
verrx(1, fmt, ap);
+2 -10
View File
@@ -1,6 +1,6 @@
/* New client tool, replaces old /dev/initctl API and telinit tool
*
* Copyright (c) 2015-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2015-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -24,8 +24,6 @@
#ifndef FINIT_INITCTL_H_
#define FINIT_INITCTL_H_
#include <err.h>
#include "finit.h"
#include "util.h"
@@ -35,14 +33,8 @@ extern int ionce; /* initctl -1 */
extern int heading; /* initctl -t */
extern int verbose; /* initctl -v */
extern int plain; /* initctl -p */
extern int quiet; /* initctl -q */
#define ERR(rc, fmt, args...) do { if (!quiet) err(rc, fmt, ##args); else exit(rc); } while (0)
#define ERRX(rc, fmt, args...) do { if (!quiet) errx(rc, fmt, ##args); else exit(rc); } while (0)
#define WARN(fmt, args...) do { if (!quiet) warn(fmt, ##args); } while (0)
#define WARNX(fmt, args...) do { if (!quiet) warnx(fmt, ##args); } while (0)
extern void print_header(const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
extern void print_header(const char *fmt, ...);
#endif /* FINIT_INITCTL_H_ */
+3 -5
View File
@@ -1,7 +1,7 @@
/* inotify watcher for files or directories
*
* Copyright (c) 2015-2016 Tobias Waldekranz <tobias@waldekranz.com>
* Copyright (c) 2016-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2016-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -62,10 +62,8 @@ int iwatch_init(struct iwatch *iw)
* reconf of systems with lots of services.
*/
len = sizeof(sz);
if (!getsockopt(iw->fd, SOL_SOCKET, SO_RCVBUF, &sz, &len)) {
if (setsockopt(iw->fd, SOL_SOCKET, SO_RCVBUF, &sz, sizeof(sz)))
_pe("Failed increasing size of inotify socket");
}
if (!getsockopt(iw->fd, SOL_SOCKET, SO_RCVBUF, &sz, &len))
setsockopt(iw->fd, SOL_SOCKET, SO_RCVBUF, &sz, sizeof(sz));
initialized = 1;
+1 -1
View File
@@ -1,7 +1,7 @@
/* inotify watcher for files or directories
*
* Copyright (c) 2015-2016 Tobias Waldekranz <tobias@waldekranz.com>
* Copyright (c) 2016-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2016-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
+6 -42
View File
@@ -1,6 +1,6 @@
/* Listens to kernel events like AC power status and manages sys/ conditions
*
* Copyright (c) 2021-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -24,7 +24,6 @@
#include <errno.h>
#include <dirent.h>
#include <poll.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
@@ -53,10 +52,6 @@
static int num_ac_online;
static int num_ac;
static int running = 1;
static int level;
static int logon;
int debug; /* debug in other modules as well */
void logit(int prio, const char *fmt, ...)
@@ -64,9 +59,9 @@ void logit(int prio, const char *fmt, ...)
va_list ap;
va_start(ap, fmt);
if (logon)
if (!debug)
vsyslog(prio, fmt, ap);
else if (prio <= level) {
else {
vfprintf(stderr, fmt, ap);
fprintf(stderr, "\n");
}
@@ -184,26 +179,6 @@ static void init(void)
sys_cond("pwr/ac", 1);
}
static void set_logging(int prio)
{
setlogmask(LOG_UPTO(prio));
level = prio;
}
static void toggle_debug(int signo)
{
(void)signo;
debug ^= 1;
set_logging(debug ? LOG_DEBUG : LOG_NOTICE);
}
static void shut_down(int signo)
{
(void)signo;
running = 0;
}
/*
* Started by Finit as soon as possible when base filesystem is up,
* modules have been probed, or insmodded from /etc/finit.conf, so by
@@ -223,13 +198,10 @@ int main(int argc, char *argv[])
}
if (!debug) {
openlog("keventd", LOG_PID, LOG_DAEMON);
set_logging(LOG_NOTICE);
logon = 1;
openlog("keventd", LOG_CONS | LOG_PID, LOG_DAEMON);
setlogmask(LOG_UPTO(LOG_NOTICE));
}
signal(SIGUSR1, toggle_debug);
signal(SIGTERM, shut_down);
init();
pfd.events = POLLIN;
@@ -244,18 +216,11 @@ int main(int argc, char *argv[])
panic("bind failed");
logit(LOG_DEBUG, "Waiting for events ...");
while (running) {
while (-1 != poll(&pfd, 1, -1)) {
char *path = NULL;
int ac = 0;
int i, len;
if (-1 == poll(&pfd, 1, -1)) {
if (errno == EINTR)
continue;
break;
}
len = recv(pfd.fd, buf, sizeof(buf), MSG_DONTWAIT);
if (len == -1) {
switch (errno) {
@@ -270,7 +235,6 @@ int main(int argc, char *argv[])
}
}
buf[len] = 0;
logit(LOG_DEBUG, "%s", buf);
/* skip libusb events, focus on kernel events/changes */
if (strncmp(buf, "change@", 7))
+9 -13
View File
@@ -1,6 +1,6 @@
/* Finit daemon log functions
*
* Copyright (c) 2008-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2008-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -21,8 +21,7 @@
* THE SOFTWARE.
*/
#include "config.h" /* Generated by configure script */
#include "config.h"
#include <stdio.h>
#include <stdarg.h>
#ifdef _LIBITE_LITE
@@ -41,8 +40,6 @@ static int loglevel = LOG_INFO;
void log_init(void)
{
ttinit();
if (debug)
loglevel = LOG_DEBUG;
else
@@ -75,25 +72,24 @@ static int log_open(void)
if (debug)
opts |= LOG_PERROR;
closelog();
openlog("finit", opts, LOG_DAEMON);
setlogmask(LOG_UPTO(loglevel));
return up = 1;
}
static void log_close(void)
{
closelog();
up = 0;
}
/* Toggle debug mode */
void log_debug(void)
{
debug = !debug;
log_close();
log_init();
if (debug) {
loglevel = LOG_DEBUG;
} else {
loglevel = LOG_NOTICE;
ttinit();
}
log_open();
logit(LOG_NOTICE, "Debug mode %s", debug ? "enabled" : "disabled");
+4 -4
View File
@@ -1,6 +1,6 @@
/* Finit daemon log functions
*
* Copyright (c) 2008-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2008-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -43,14 +43,14 @@
#define _d(fmt, args...) logit(LOG_DEBUG, "%s():" fmt, __func__, ##args)
#define _w(fmt, args...) logit(LOG_WARNING, "%s():" fmt, __func__, ##args)
#define _e(fmt, args...) logit(LOG_ERR, "%s():" fmt, __func__, ##args)
#define _pe(fmt, args...) logit(LOG_ERR, "%s():" fmt ": %s", __func__, ##args, strerror(errno))
#define _pe(fmt, args...) logit(LOG_ERR, "%s():" fmt ": %n", __func__, ##args, strerror(errno))
void log_init (void);
void log_exit (void);
void log_debug (void);
void logit (int prio, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
void flog (char *file, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
void logit (int prio, const char *fmt, ...);
void flog (char *file, const char *fmt, ...);
#endif /* FINIT_LOG_H_ */
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2018-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
+2 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2018-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -49,6 +49,7 @@ static int recreate(char *path, mode_t mode, uid_t uid, gid_t gid)
*/
int logrotate(char *file, int num, off_t sz)
{
int cnt;
struct stat st;
if (stat(file, &st))
@@ -59,7 +60,6 @@ int logrotate(char *file, int num, off_t sz)
size_t len = strlen(file) + 10 + 1;
char ofile[len];
char nfile[len];
int cnt;
/* First age zipped log files */
for (cnt = num; cnt > 2; cnt--) {
+1 -3
View File
@@ -1,6 +1,6 @@
/* Handle MD arrays
*
* Copyright (c) 2016-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2016-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -21,8 +21,6 @@
* THE SOFTWARE.
*/
#include "config.h" /* Generated by configure script */
#include <glob.h>
#include <stdio.h>
#include <string.h>
+6 -28
View File
@@ -1,6 +1,6 @@
/* Mount and unmount helpers
*
* Copyright (c) 2016-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2016-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -21,17 +21,10 @@
* THE SOFTWARE.
*/
#include "config.h" /* Generated by configure script */
#include <errno.h>
#include <string.h>
#ifdef HAVE_MNTENT_H
#include <mntent.h>
#endif
#include <sys/mount.h>
#include "helpers.h"
/*
* SysV init on Debian/Ubuntu skips these protected mount points
*
@@ -72,12 +65,12 @@ static void iterator_end(FILE **fp)
*fp = NULL;
}
static struct mntent *iterator(char *filename, FILE **fp)
static struct mntent *iterator(char *fstab, FILE **fp)
{
static struct mntent *mnt;
if (!*fp && filename) {
*fp = setmntent(filename, "r");
if (!*fp && fstab) {
*fp = setmntent(fstab, "r");
if (!*fp)
return NULL;
}
@@ -93,28 +86,13 @@ static struct mntent *iterator(char *filename, FILE **fp)
return NULL;
}
static int unmount(const char *target)
{
int rc;
rc = umount(target);
if (rc) {
if (errno != EBUSY)
print(2, "Failed unmounting %s, error %d: %s", target, errno, strerror(errno));
return rc;
}
print(0, "Unmounting %s", target);
return 0;
}
void unmount_tmpfs(void)
{
struct mntent *mnt;
FILE *fp = NULL;
while ((mnt = iterator("/proc/mounts", &fp))) {
if (!strcmp("tmpfs", mnt->mnt_fsname) && !unmount(mnt->mnt_dir))
if (!strcmp("tmpfs", mnt->mnt_fsname) && !umount(mnt->mnt_dir))
iterator_end(&fp); /* Restart iteration */
}
}
@@ -125,7 +103,7 @@ void unmount_regular(void)
FILE *fp = NULL;
while ((mnt = iterator("/proc/mounts", &fp))) {
if (!unmount(mnt->mnt_dir))
if (!umount(mnt->mnt_dir))
iterator_end(&fp); /* Restart iteration */
}
}
+5 -13
View File
@@ -1,7 +1,7 @@
/* PID and PID file helpers
*
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2008-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -22,8 +22,6 @@
* THE SOFTWARE.
*/
#include "config.h" /* Generated by configure script */
#include <errno.h>
#include <paths.h>
#include <stdio.h>
@@ -71,11 +69,10 @@ int pid_alive(pid_t pid)
*/
char *pid_get_name(pid_t pid, char *name, size_t len)
{
static char line[64];
char *pname = NULL;
char path[32];
int ret = 1;
FILE *fp;
char *pname, path[32];
static char line[64];
snprintf(path, sizeof(path), "/proc/%d/status", pid);
fp = fopen(path, "r");
@@ -116,8 +113,8 @@ char *pid_file(svc_t *svc)
pid_t pid_file_read(const char *fn)
{
pid_t pid = 0;
char buf[42];
FILE *fp;
char buf[42];
fp = fopen(fn, "r");
if (!fp)
@@ -160,11 +157,6 @@ int pid_file_set(svc_t *svc, char *file, int not)
file++;
}
if (svc_is_forking(svc) && !not) {
logit(LOG_WARNING, "Service %s is forking, adjusting to pid:!%s", svc->name, file);
not = 1;
}
pid_runpath(file, &svc->pidfile[not], sizeof(svc->pidfile) - not);
if (not)
svc->pidfile[0] = '!';
@@ -207,8 +199,8 @@ int pid_file_parse(svc_t *svc, char *arg)
/* 'pid:' implies argument following*/
if (!strncmp(arg, "pid:", 4)) {
char path[MAX_ARG_LEN];
int len, not = 0;
char path[MAX_ARG_LEN];
arg += 4;
if ((arg[0] == '!' && arg[1] == '/') || arg[0] == '/')
+1 -1
View File
@@ -1,7 +1,7 @@
/* PID and PID file helpers
*
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2008-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
+8 -65
View File
@@ -1,6 +1,6 @@
/* Plugin based services architecture for finit
*
* Copyright (c) 2012-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -21,8 +21,6 @@
* THE SOFTWARE.
*/
#include "config.h" /* Generated by configure script */
#include <errno.h>
#include <dlfcn.h> /* dlopen() et al */
#include <dirent.h> /* readdir() et al */
@@ -36,6 +34,7 @@
# include <lite/queue.h> /* BSD sys/queue.h API */
#endif
#include "config.h"
#include "cond.h"
#include "finit.h"
#include "helpers.h"
@@ -260,8 +259,8 @@ int plugin_io_init(plugin_t *p)
/* Setup any I/O callbacks for plugins that use them */
static int init_plugins(uev_ctx_t *ctx)
{
plugin_t *p, *tmp;
int fail = 0;
plugin_t *p, *tmp;
PLUGIN_ITERATOR(p, tmp) {
if (plugin_io_init(p))
@@ -302,7 +301,7 @@ static int load_one(char *path, char *name)
noext = strcmp(name + strlen(name) - 3, ".so");
snprintf(sofile, sizeof(sofile), "%s/%s%s", path, name, noext ? ".so" : "");
_d("Loading plugin %s ...", sofile);
_d("Loading plugin %s ...", basename(sofile));
handle = dlopen(sofile, RTLD_LAZY | RTLD_LOCAL);
if (!handle) {
_e("Failed loading plugin %s: %s", sofile, dlerror());
@@ -356,8 +355,6 @@ static int load_plugins(char *path)
dp = opendir(path);
if (!dp) {
if (errno == ENOENT)
return 0;
_e("Failed, cannot open plugin directory %s: %s", path, strerror(errno));
return 1;
}
@@ -383,68 +380,14 @@ static int load_plugins(char *path)
}
#endif /* ENABLE_STATIC */
int plugin_list(char *buf, size_t len)
{
#ifndef ENABLE_STATIC
plugin_t *p, *tmp;
buf[0] = 0;
PLUGIN_ITERATOR(p, tmp) {
if (buf[0])
strlcat(buf, " ", len);
strlcat(buf, p->name, len);
}
#else
buf[0] = 0;
#endif
return 0;
}
int plugin_deps(char *buf, size_t len)
{
#ifndef ENABLE_STATIC
plugin_t *p;
p = plugin_find(buf);
buf[0] = 0;
if (p) {
int i;
for (i = 0; i < PLUGIN_DEP_MAX; i++) {
if (!p->depends[i])
continue;
if (buf[0])
strlcat(buf, " ", len);
strlcat(buf, p->depends[i], len);
}
}
#else
buf[0] = 0;
#endif
return 0;
}
int plugin_init(uev_ctx_t *ctx)
{
load_plugins(PLUGIN_PATH);
int fail = 1;
#ifdef EXTERNAL_PLUGIN_PATH
char *paths = strdup(EXTERNAL_PLUGIN_PATH);
char *path;
if (!load_plugins(PLUGIN_PATH))
fail = init_plugins(ctx);
if (paths) {
_d("Loading external plugins from %s ...", paths);
path = strtok(paths, ":");
while (path) {
load_plugins(path);
path = strtok(NULL, ":");
}
free(paths);
}
#endif
return init_plugins(ctx);
return fail;
}
void plugin_exit(void)
+1 -4
View File
@@ -1,6 +1,6 @@
/* Plugin based services architecture for finit
*
* Copyright (c) 2012-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -146,9 +146,6 @@ typedef struct plugin {
/* Public plugin API */
int plugin_io_init (plugin_t *plugin);
int plugin_list (char *buf, size_t len);
int plugin_deps (char *buf, size_t len);
int plugin_register (plugin_t *plugin);
int plugin_unregister (plugin_t *plugin);
+1 -4
View File
@@ -1,7 +1,7 @@
/* Private header file for main finit daemon, not for plugins
*
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2008-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -29,9 +29,6 @@
#include "plugin.h"
#define SERVICE_INTERVAL_DEFAULT 300000 /* 5 mins */
#define MATCH_CMD(l, c, x) \
(!strncasecmp(l, c, strlen(c)) && (x = (l) + strlen(c)))
extern int service_interval;
int api_init (uev_ctx_t *ctx);
+7 -26
View File
@@ -1,6 +1,6 @@
/* reboot, halt, poweroff, shutdown, suspend for finit
*
* Copyright (c) 2009-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2009-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -26,7 +26,6 @@
#include <getopt.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "util.h"
@@ -43,8 +42,6 @@ static cmd_t cmd = CMD_UNKNOWN;
static char *msg = NULL;
/* initctl API */
extern int timeout;
extern int do_reboot (char *arg);
extern int do_halt (char *arg);
extern int do_poweroff(char *arg);
@@ -105,13 +102,12 @@ static int usage(int rc)
{
fprintf(stderr, "Usage: %s [OPTIONS]\n\n"
"Options:\n"
" -?, --help This help text\n"
" --help This help text\n"
" -f, --force Force unsafe %s now, do not contact the init system.\n"
" --halt Halt system, regardless of how the command is called.\n"
" -h Halt or power off after shutdown.\n"
" -P, --poweroff Power-off system, regardless of how the command is called.\n"
" -r, --reboot Reboot system, regardless of how the command is called.\n"
" -t, --timeout=SEC Force reboot/shutdown after a given timeout\n"
"\n", prognm, msg);
return rc;
@@ -119,22 +115,20 @@ static int usage(int rc)
int reboot_main(int argc, char *argv[])
{
int c, force = 0;
struct option long_options[] = {
{"help", 0, NULL, '?'},
{"help", 0, NULL, 'h'},
{"force", 0, NULL, 'f'},
{"halt", 0, NULL, 'H'},
{"poweroff", 0, NULL, 'p'},
{"reboot", 0, NULL, 'r'},
{"timeout", 1, NULL, 't'},
{NULL, 0, NULL, 0}
};
int c, force = 0;
int tmp;
/* Initial command taken from program name */
transform(prognm);
while ((c = getopt_long(argc, argv, "h?fHPprt:", long_options, NULL)) != EOF) {
while ((c = getopt_long(argc, argv, "h?fHPpr", long_options, NULL)) != EOF) {
switch(c) {
case '?':
return usage(0);
@@ -157,13 +151,6 @@ int reboot_main(int argc, char *argv[])
cmd = CMD_REBOOT;
break;
case 't':
tmp = atoi(optarg);
if (tmp < 1)
errx(1, "Invalid forced timeout value.");
timeout = tmp;
break;
default:
return usage(1);
}
@@ -172,13 +159,7 @@ int reboot_main(int argc, char *argv[])
/* Check for any overrides */
transform(NULL);
/* Check if we're in sulogin shell */
if (getenv("SULOGIN"))
force = 1;
if (force) {
sync();
switch (cmd) {
case CMD_REBOOT:
c = reboot(RB_AUTOBOOT);
@@ -193,9 +174,9 @@ int reboot_main(int argc, char *argv[])
break;
case CMD_SUSPEND:
c = suspend();
c = reboot(RB_SW_SUSPEND);
if (c && errno == EINVAL)
errx(1, "Kernel does not support suspend to RAM.");
errx(1, "Kernel does not support suspend.");
break;
case CMD_UNKNOWN:
+1 -1
View File
@@ -1,6 +1,6 @@
/* Work queue helper functions
*
* Copyright (c) 2018-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2018-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
+1 -1
View File
@@ -1,6 +1,6 @@
/* Work queue helper functions
*
* Copyright (c) 2018-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2018-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
+26 -55
View File
@@ -1,6 +1,6 @@
/* List and enable/disable service configurations
*
* Copyright (c) 2017-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2017-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -23,6 +23,7 @@
#include "config.h"
#include <err.h>
#include <fcntl.h> /* Definition of AT_* constants */
#include <glob.h>
#include <stdio.h>
@@ -33,24 +34,9 @@
# include <lite/lite.h>
#endif
#include "client.h"
#include "initctl.h"
static int is_builtin(char *arg)
{
svc_t *svc;
svc = client_svc_find(arg);
if (!svc)
return 0;
if (svc->file[0])
return 0;
return 1;
}
static int calc_width(char *arr[], size_t len)
{
int width = 0;
@@ -232,7 +218,7 @@ int serv_enable(char *arg)
int ena;
if (!arg || !arg[0]) {
WARNX("missing argument to enable, may be one of:");
warnx("missing argument to enable, may be one of:");
return serv_list("available");
}
@@ -242,18 +228,18 @@ int serv_enable(char *arg)
}
if (chdir(FINIT_RCSD))
ERR(72, "failed cd %s", FINIT_RCSD);
err(1, "failed cd %s", FINIT_RCSD);
if (icreate && mkdir("enabled", 0755) && EEXIST != errno)
ERR(73, "failed creating %s/enabled directory", FINIT_RCSD);
err(1, "failed creating %s/enabled directory", FINIT_RCSD);
ena = !chdir("enabled"); /* System *may* have enabled/ dir. */
snprintf(path, sizeof(path), "%savailable/%s", ena ? "../" : "", arg);
if (!fexist(path))
ERRX(72, "cannot find %s", conf(path, sizeof(path), arg, 0));
errx(1, "cannot find %s", conf(path, sizeof(path), arg, 0));
if (fexist(arg))
ERRX(1, "%s already enabled", arg);
errx(1, "%s already enabled", arg);
return symlink(path, arg) != 0;
}
@@ -264,7 +250,7 @@ int do_disable(char *arg, int check)
char corr[40];
if (!arg || !arg[0]) {
WARNX("missing argument to disable, may be one of:");
warnx("missing argument to disable, may be one of:");
return serv_list("enabled");
}
@@ -274,15 +260,15 @@ int do_disable(char *arg, int check)
}
if (chdir(FINIT_RCSD))
ERR(72, "failed cd %s", FINIT_RCSD);
err(1, "failed cd %s", FINIT_RCSD);
if (chdir("enabled")) /* System *may* have enabled/ dir. */
dbg("Failed changing to %s/enabled/: %s", FINIT_RCSD, strerror(errno));
if (check && stat(arg, &st))
ERRX(6, "%s not (an) enabled (service).", arg);
errx(1, "%s not (an) enabled (service).", arg);
if (check && (st.st_mode & S_IFMT) == S_IFLNK)
ERRX(1, "cannot disable %s, not a symlink.", arg);
errx(1, "cannot disable %s, not a symlink.", arg);
return remove(arg) != 0;
}
@@ -298,16 +284,14 @@ int serv_touch(char *arg)
char *fn;
if (!arg || !arg[0]) {
WARNX("missing argument to touch, may be one of:");
warnx("missing argument to touch, may be one of:");
return serv_list("enabled");
}
fn = conf(path, sizeof(path), arg, 0);
if (!fexist(fn)) {
if (!strstr(arg, "finit.conf"))
ERRX(72, "%s not available.", arg);
if (is_builtin(arg))
ERRX(4, "%s is a built-in service.", arg);
errx(1, "%s not available.", arg);
strlcpy(path, FINIT_CONF, sizeof(path));
fn = path;
@@ -315,7 +299,7 @@ int serv_touch(char *arg)
/* libite:touch() follows symlinks */
if (utimensat(AT_FDCWD, fn, NULL, AT_SYMLINK_NOFOLLOW))
ERR(71, "failed marking %s for reload", fn);
err(1, "failed marking %s for reload", fn);
return 0;
}
@@ -327,10 +311,7 @@ int serv_show(char *arg)
fn = conf(path, sizeof(path), arg, 0);
if (!fexist(fn)) {
if (is_builtin(arg))
ERRX(4, "%s is a built-in service.", arg);
WARNX("Cannot find %s", arg);
warnx("Cannot find %s", arg);
return 1;
}
@@ -364,11 +345,8 @@ static int do_edit(char *arg, int creat)
fn = conf(path, sizeof(path), arg, creat);
if (!fexist(fn)) {
if (is_builtin(arg))
ERRX(4, "%s is a built-in service.", arg);
if (!creat) {
WARNX("Cannot find %s, use -c flag, create command, or select one of:", arg);
warnx("Cannot find %s, use -c flag, create command, or select one of:", arg);
return serv_list(NULL);
}
@@ -377,7 +355,7 @@ static int do_edit(char *arg, int creat)
copyfile(SAMPLE_CONF, fn, 0, 0);
#endif
} else if (creat)
WARNX("the file %s already exists, falling back to edit.", fn);
warnx("the file %s already exists, falling back to edit.", fn);
for (size_t i = 0; i < NELEMS(editor); i++) {
if (systemf("%s %s 2>/dev/null", editor[i], path))
@@ -393,7 +371,6 @@ int serv_edit(char *arg)
if (!arg || !arg[0]) {
if (!yorn("Do you want to edit %s (y/N)? ", FINIT_CONF))
return 0;
arg = "";
}
return do_edit(arg, icreate);
@@ -406,10 +383,7 @@ int serv_creat(char *arg)
FILE *fp;
if (!arg || !arg[0])
ERRX(2, "missing argument to create");
if (is_builtin(arg))
ERRX(4, "%s is a built-in service.", arg);
errx(1, "missing argument to create");
/* Input from a pipe or a proper TTY? */
if (isatty(STDIN_FILENO))
@@ -418,16 +392,16 @@ int serv_creat(char *arg)
/* Open fn for writing from pipe */
fn = conf(buf, sizeof(buf), arg, 1);
if (!fn)
ERR(73, "failed creating conf %s", arg);
err(1, "failed creating conf %s", arg);
if (!icreate && fexist(fn)) {
WARNX("%s already exists, skipping (use -c to override)", fn);
warnx("%s already exists, skipping (use -c to override)", fn);
fn = "/dev/null";
}
fp = fopen(fn, "w");
if (!fp)
ERR(73, "failed opening %s for writing", fn);
err(1, "failed opening %s for writing", fn);
while (fgets(buf, sizeof(buf), stdin))
fputs(buf, fp);
@@ -441,24 +415,21 @@ int serv_delete(char *arg)
char *fn;
if (!arg || !arg[0]) {
WARNX("missing argument to delete, may be one of:");
warnx("missing argument to delete, may be one of:");
return serv_list("available");
}
fn = conf(buf, sizeof(buf), arg, 0);
if (!fn) {
if (is_builtin(arg))
ERRX(4, "%s is a built-in service.", arg);
ERRX(72, FINIT_RCSD " missing on system.");
}
if (!fn)
errx(1, FINIT_RCSD " missing on system.");
if (!fexist(fn))
WARNX("cannot find %s", fn);
warnx("cannot find %s", fn);
if (iforce || yorn("Remove file and symlink(s) to %s (y/N)? ", fn)) {
do_disable(arg, 0);
if (remove(fn))
ERR(1, "Failed removing %s", fn);
err(1, "Failed removing %s", fn);
}
return 0;
+1 -1
View File
@@ -1,6 +1,6 @@
/* List and enable/disable service configurations
*
* Copyright (c) 2017-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2017-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
+143 -285
View File
@@ -1,7 +1,7 @@
/* Finit service monitor, task starter and generic API for managing svc_t
*
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2008-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -25,7 +25,6 @@
#include "config.h" /* Generated by configure script */
#include <ctype.h> /* isblank() */
#include <sched.h> /* sched_yield() */
#include <string.h>
#include <sys/reboot.h>
#include <sys/prctl.h>
@@ -90,7 +89,7 @@ static void service_timeout_cb(uev_t *w, void *arg, int events)
* Returns:
* POSIX OK(0) on success, non-zero on error.
*/
int service_timeout_after(svc_t *svc, int timeout, void (*cb)(svc_t *svc))
static int service_timeout_after(svc_t *svc, int timeout, void (*cb)(svc_t *svc))
{
if (svc->timer_cb)
return -EBUSY;
@@ -108,7 +107,7 @@ int service_timeout_after(svc_t *svc, int timeout, void (*cb)(svc_t *svc))
* Returns:
* POSIX OK(0) on success, non-zero on error.
*/
int service_timeout_cancel(svc_t *svc)
static int service_timeout_cancel(svc_t *svc)
{
int err;
@@ -198,10 +197,9 @@ static int lredirect(svc_t *svc)
pid = fork();
if (pid == 0) {
char *prio = "daemon.info";
char buf[MAX_IDENT_LEN];
char *tag;
int fds;
char *tag = basename(svc->cmd);
char *prio = "daemon.info";
sched_yield();
@@ -214,9 +212,6 @@ static int lredirect(svc_t *svc)
/* Reset signals */
sig_unblock();
/* Default syslog identity name[:id] */
tag = svc_ident(svc, buf, sizeof(buf));
if (!whichp(_PATH_LOGIT)) {
logit(LOG_INFO, _PATH_LOGIT " missing, using syslog for %s instead", svc->name);
fallback_logger(tag, prio);
@@ -386,20 +381,6 @@ static char *group_name(svc_t *svc, char *buf, size_t len)
return buf;
}
static void compose_cmdline(svc_t *svc, char *buf, size_t len)
{
size_t i;
strlcpy(buf, svc->cmd, len);
for (i = 1; i < MAX_NUM_SVC_ARGS; i++) {
if (!strlen(svc->args[i]))
break;
strlcat(buf, " ", len);
strlcat(buf, svc->args[i], len);
}
}
static pid_t service_fork(svc_t *svc)
{
pid_t pid;
@@ -420,19 +401,20 @@ static pid_t service_fork(svc_t *svc)
/* Set configured limits */
for (int i = 0; i < RLIMIT_NLIMITS; i++) {
if (setrlimit(i, &svc->rlimit[i]) == -1)
logit(LOG_WARNING, "%s: rlimit: failed setting %s",
svc_ident(svc, NULL, 0), rlim2str(i));
logit(LOG_WARNING,
"%s: rlimit: Failed setting %s",
svc->cmd, rlim2str(i));
}
/* Set desired user+group */
if (gid >= 0) {
if (setgid(gid))
_pe("%s: failed setgid(%d)", svc_ident(svc, NULL, 0), gid);
_pe("%s: failed setgid(%d)", svc->cmd, gid);
}
if (uid >= 0) {
if (setuid(uid))
_pe("%s: failed setuid(%d)", svc_ident(svc, NULL, 0), uid);
_pe("%s: failed setuid(%d)", svc->cmd, uid);
/* Set default path for regular users */
if (uid > 0)
@@ -441,7 +423,7 @@ static pid_t service_fork(svc_t *svc)
setenv("HOME", home, 1);
if (chdir(home)) {
if (chdir("/"))
_pe("%s: failed chdir(%s) and chdir(/)", svc_ident(svc, NULL, 0), home);
_pe("%s: failed chdir(%s) and chdir(/)", svc->cmd, home);
}
}
}
@@ -463,7 +445,6 @@ static pid_t service_fork(svc_t *svc)
static int service_start(svc_t *svc)
{
int result = 0, do_progress = 1;
char cmdline[CMD_SIZE] = "";
sigset_t nmask, omask;
char grnam[80];
pid_t pid;
@@ -478,14 +459,14 @@ static int service_start(svc_t *svc)
/* Don't try and start service if it doesn't exist. */
if (!whichp(svc->cmd)) {
logit(LOG_WARNING, "%s: missing %s or not in $PATH", svc_ident(svc, NULL, 0), svc->cmd);
logit(LOG_WARNING, "%s: missing or not in $PATH", svc->cmd);
svc_missing(svc);
return 1;
}
/* Unlike systemd we do not allow starting service if env is missing, unless - */
if (!svc_checkenv(svc)) {
logit(LOG_WARNING, "%s: missing %s env file %s", svc_ident(svc, NULL, 0), svc->cmd, svc->env);
logit(LOG_WARNING, "%s: missing env file %s", svc->cmd, svc->env);
svc_missing(svc);
return 1;
}
@@ -500,9 +481,8 @@ static int service_start(svc_t *svc)
}
}
compose_cmdline(svc, cmdline, sizeof(cmdline));
if (svc_is_sysv(svc))
logit(LOG_CONSOLE | LOG_NOTICE, "Calling '%s start' ...", cmdline);
logit(LOG_CONSOLE | LOG_NOTICE, "Calling '%s start' ...", svc->cmd);
if (!svc->desc[0])
do_progress = 0;
@@ -538,7 +518,7 @@ static int service_start(svc_t *svc)
int rc;
if ((rc = wordexp(svc->cmd, &we, 0))) {
_e("%s: failed wordexp(%s): %d", svc_ident(svc, NULL, 0), svc->cmd, rc);
_e("%s: failed wordexp(%s): %d", svc->cmd, svc->cmd, rc);
nomem:
wordfree(&we);
_exit(1);
@@ -566,19 +546,19 @@ static int service_start(svc_t *svc)
strlcat(str, arg, sizeof(str));
if ((rc = wordexp(str, &we, WRDE_APPEND))) {
_e("%s: failed wordexp(%s): %d", svc_ident(svc, NULL, 0), str, rc);
_e("%s: failed wordexp(%s): %d", svc->cmd, str, rc);
goto nomem;
}
}
if (we.we_wordc > MAX_NUM_SVC_ARGS) {
logit(LOG_ERR, "%s: too many args to %s after expansion.", svc_ident(svc, NULL, 0), svc->cmd);
logit(LOG_ERR, "%s: too man args after expansion.", svc->cmd);
goto nomem;
}
for (i = 0; i < we.we_wordc; i++) {
if (strlen(we.we_wordv[i]) >= sizeof(svc->args[i])) {
logit(LOG_ERR, "%s: expanded %s arg. '%s' too long", svc_ident(svc, NULL, 0), svc->cmd, we.we_wordv[i]);
logit(LOG_ERR, "%s: expanded arg. '%s' too long", we.we_wordv[i]);
rc = WRDE_NOSPACE;
goto nomem;
}
@@ -589,16 +569,9 @@ static int service_start(svc_t *svc)
}
wordfree(&we);
} else {
size_t j;
i = 0;
args[i++] = svc->cmd;
/* this handles, e.g., bridge-stop br0 start */
for (j = 0; j < MAX_NUM_SVC_ARGS; j++) {
if (!strlen(svc->args[j]))
break;
args[i++] = svc->args[j];
}
args[i++] = svc->cmd;
args[i++] = "start";
}
args[i] = NULL;
@@ -631,7 +604,16 @@ static int service_start(svc_t *svc)
_exit(status);
} else if (debug) {
_d("Starting %s", cmdline);
char buf[CMD_SIZE] = "";
for (i = 0; i < MAX_NUM_SVC_ARGS; i++) {
if (strlen(svc->args[i]) == 0)
break;
if (buf[0])
strlcat(buf, " ", sizeof(buf));
strlcat(buf, svc->args[i], sizeof(buf));
}
_d("Starting %s %s", svc->cmd, buf);
}
if (svc_is_tty(svc))
@@ -639,7 +621,6 @@ static int service_start(svc_t *svc)
else
cgroup_service(group_name(svc, grnam, sizeof(grnam)), pid, &svc->cgroup);
if (!svc_is_sysv(svc))
logit(LOG_CONSOLE | LOG_NOTICE, "Starting %s[%d]", svc_ident(svc, NULL, 0), pid);
svc->pid = pid;
@@ -687,7 +668,7 @@ static void service_kill(svc_t *svc)
if (svc->pid <= 1) {
/* Avoid killing ourselves or all processes ... */
_d("%s: Aborting SIGKILL, already terminated.", svc_ident(svc, NULL, 0));
_d("%s: Aborting SIGKILL, already terminated.", svc->cmd);
return;
}
@@ -717,7 +698,7 @@ static void service_cleanup(svc_t *svc)
fn = pid_file(svc);
if (fn && remove(fn) && errno != ENOENT)
logit(LOG_CRIT, "Failed removing service %s pidfile %s",
svc_ident(svc, NULL, 0), fn);
basename(svc->cmd), fn);
/* No longer running, update books. */
if (svc_is_tty(svc) && svc->pid > 1)
@@ -731,16 +712,11 @@ static void service_cleanup(svc_t *svc)
* service_stop - Stop service
* @svc: Service to stop
*
* Called externally by initctl to perform stop/start (restart) of
* services. Internally it is used to bring a run/task/service to
* HALTED state.
*
* Returns:
* 0 if the service was successfully stopped. Non-zero otherwise.
*/
int service_stop(svc_t *svc)
static int service_stop(svc_t *svc)
{
char cmdline[CMD_SIZE] = "";
int do_progress = 1;
int rc = 0;
@@ -752,7 +728,6 @@ int service_stop(svc_t *svc)
service_timeout_cancel(svc);
compose_cmdline(svc, cmdline, sizeof(cmdline));
if (!svc_is_sysv(svc)) {
if (svc->pid <= 1)
return 1;
@@ -762,7 +737,7 @@ int service_stop(svc_t *svc)
logit(LOG_CONSOLE | LOG_NOTICE, "Stopping %s[%d], sending %s ...",
svc_ident(svc, NULL, 0), svc->pid, sig_name(svc->sighalt));
} else {
logit(LOG_CONSOLE | LOG_NOTICE, "Calling '%s stop' ...", cmdline);
logit(LOG_CONSOLE | LOG_NOTICE, "Calling '%s stop' ...", svc->cmd);
}
/*
@@ -772,14 +747,6 @@ int service_stop(svc_t *svc)
*/
svc_started(svc);
/*
* Verify there's still something there before we send the reaper.
*/
if (svc->pid > 1 && !pid_alive(svc->pid)) {
svc->pid = 0;
return 0;
}
if (!svc->desc[0])
do_progress = 0;
@@ -802,30 +769,19 @@ int service_stop(svc_t *svc)
svc_set_state(svc, SVC_HALTED_STATE);
}
} else {
char *args[MAX_NUM_SVC_ARGS + 1];
size_t i = 0, j;
char *args[] = { svc->cmd, "stop", NULL };
pid_t pid;
args[i++] = svc->cmd;
/* this handles, e.g., bridge-stop br0 stop */
for (j = 0; j < MAX_NUM_SVC_ARGS - 2; j++) {
if (!strlen(svc->args[j]))
break;
args[i++] = svc->args[j];
}
args[i++] = "stop";
args[i] = NULL;
pid = fork();
switch (pid) {
case 0:
setsid();
redirect(svc);
exec_runtask(args[0], &args[1]);
exec_runtask(svc->cmd, args);
_exit(0);
break;
case -1:
_pe("Failed fork() to call sysv script '%s stop'", cmdline);
_pe("Failed fork() to call sysv script '%s stop'", svc->cmd);
rc = 1;
break;
default:
@@ -864,7 +820,7 @@ static int service_restart(svc_t *svc)
return 1;
if (svc->pid <= 1) {
_d("%s: bad PID %d for %s, SIGHUP", svc_ident(svc, NULL, 0), svc->pid, svc->cmd);
_d("Bad PID %d for %s, SIGHUP", svc->pid, svc->cmd);
svc->start_time = svc->pid = 0;
return 1;
}
@@ -967,7 +923,7 @@ static void parse_env(svc_t *svc, char *env)
return;
if (strlen(env) >= sizeof(svc->env)) {
_e("%s: env file is too long (>%zu chars)", svc_ident(svc, NULL, 0), sizeof(svc->env));
_e("%s: env file is too long (>%d chars)", svc->cmd, sizeof(svc->env));
return;
}
@@ -991,7 +947,7 @@ static void parse_cgroup(svc_t *svc, char *cgroup)
}
if (strlen(ptr) >= sizeof(svc->cgroup)) {
_e("%s: cgroup settings too long (>%zu chars)", svc_ident(svc, NULL, 0), sizeof(svc->cgroup));
_e("%s: cgroup settings too long (>%d chars)", svc->cmd, sizeof(svc->cgroup));
return;
}
@@ -1016,7 +972,7 @@ static void parse_killdelay(svc_t *svc, char *delay)
sec = strtonum(delay, 1, 60, &errstr);
if (errstr) {
_e("%s: killdelay %s is %s (1-60)", svc_ident(svc, NULL, 0), delay, errstr);
_e("%s: killdelay %s is %s (1-60)", svc->cmd, delay, errstr);
return;
}
@@ -1027,39 +983,26 @@ static void parse_killdelay(svc_t *svc, char *delay)
static void parse_script(char *type, char *script, char *buf, size_t len)
{
if (access(script, X_OK))
logit(LOG_WARNING, "%s:%s is missing or not executable, skipping.", type, script);
logit(LOG_WARNING, "%s: %s:%s is missing or not executable, skipping.", type, script);
else
strlcpy(buf, script, len);
}
/*
* 'name:<name>' or derived from '/path/to/cmd args'
* name:<name>
*/
static char *parse_name(char *cmd, char *arg)
static void parse_name(svc_t *svc, char *arg)
{
char *name = NULL;
if (arg && !strncasecmp(arg, "name:", 5)) {
name = arg + 5;
} else {
char *ptr;
ptr = strchr(cmd, ' ');
if (!ptr)
ptr = cmd + strlen(cmd);
while (ptr > cmd) {
if (*ptr == '/') {
ptr++;
break;
}
ptr--;
name = strrchr(svc->cmd, '/');
name = name ? name + 1 : svc->cmd;
}
name = ptr;
}
return name;
strlcpy(svc->name, name, sizeof(svc->name));
}
/*
@@ -1144,6 +1087,7 @@ static void parse_cmdline_args(svc_t *svc, char *cmd)
svc->args_dirty = (diff > 0);
}
/**
* service_register - Register service, task or run commands
* @type: %SVC_TYPE_SERVICE(0), %SVC_TYPE_TASK(1), %SVC_TYPE_RUN(2)
@@ -1210,7 +1154,7 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
char *dev = NULL;
int respawn = 0;
int levels = 0;
int forking = 0, manual = 0;
int manual = 0;
int restart_max = SVC_RESPAWN_MAX;
int restart_tmo = 0;
unsigned oncrash_action = SVC_ONCRASH_IGNORE;
@@ -1252,8 +1196,6 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
}
while (cmd) {
char *arg;
if (type == SVC_TYPE_TTY && cmd[0] == '@')
break; /* @console */
@@ -1265,48 +1207,42 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
cond = &cmd[1];
else if (cmd[0] == ':') /* :ID */
id = &cmd[1];
else if (MATCH_CMD(cmd, "log", arg))
else if (!strncasecmp(cmd, "log", 3))
log = cmd;
else if (MATCH_CMD(cmd, "pid", arg))
else if (!strncasecmp(cmd, "pid", 3))
pid = cmd;
else if (MATCH_CMD(cmd, "name:", arg))
else if (!strncasecmp(cmd, "name:", 5))
name = cmd;
else if (MATCH_CMD(cmd, "type:forking", arg))
forking = 1;
else if (MATCH_CMD(cmd, "manual:yes", arg))
else if (!strncasecmp(cmd, "manual:yes", 10))
manual = 1;
else if (MATCH_CMD(cmd, "restart:", arg)) {
if (MATCH_CMD(arg, "always", arg))
restart_max = -1;
else
restart_max = atoi(arg);
}
else if (MATCH_CMD(cmd, "restarttmo:", arg)) /* compat alias */
restart_tmo = atoi(arg) * 1000;
else if (MATCH_CMD(cmd, "restart_sec:", arg))
restart_tmo = atoi(arg) * 1000;
else if (MATCH_CMD(cmd, "norestart", arg))
else if (!strncasecmp(cmd, "restart:", 8))
restart_max = atoi(&cmd[8]);
else if (!strncasecmp(cmd, "restarttmo:", 11)) /* compat alias */
restart_tmo = atoi(&cmd[11]) * 1000;
else if (!strncasecmp(cmd, "restart_sec:", 12))
restart_tmo = atoi(&cmd[12]) * 1000;
else if (!strncasecmp(cmd, "norestart", 9))
restart_max = 0;
else if (MATCH_CMD(cmd, "oncrash:", arg)) {
if (MATCH_CMD(arg, "reboot", arg))
else if (!strncasecmp(cmd, "oncrash:", 8)) {
if (!strncasecmp(&cmd[8], "reboot", 6))
oncrash_action = SVC_ONCRASH_REBOOT;
}
else if (MATCH_CMD(cmd, "respawn", arg))
else if (!strncasecmp(cmd, "respawn", 7))
respawn = 1;
else if (MATCH_CMD(cmd, "halt:", arg))
halt = arg;
else if (MATCH_CMD(cmd, "kill:", arg))
delay = arg;
else if (MATCH_CMD(cmd, "pre:", arg))
pre_script = arg;
else if (MATCH_CMD(cmd, "post:", arg))
post_script = arg;
else if (MATCH_CMD(cmd, "env:", arg))
env = arg;
else if (MATCH_CMD(cmd, "cgroup:", arg))
cgroup = arg; /* only settings */
else if (MATCH_CMD(cmd, "cgroup.", arg))
cgroup = arg; /* with group */
else if (!strncasecmp(cmd, "halt:", 5))
halt = &cmd[5];
else if (!strncasecmp(cmd, "kill:", 5))
delay = &cmd[5];
else if (!strncasecmp(cmd, "pre:", 4))
pre_script = &cmd[4];
else if (!strncasecmp(cmd, "post:", 5))
post_script = &cmd[5];
else if (!strncasecmp(cmd, "env:", 4))
env = &cmd[4];
else if (!strncasecmp(cmd, "cgroup:", 7))
cgroup = &cmd[7]; /* only settings */
else if (!strncasecmp(cmd, "cgroup.", 7))
cgroup = &cmd[6]; /* with group */
else
break;
@@ -1322,7 +1258,6 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
return 0;
}
name = parse_name(cmd, name);
if (!id)
id = "";
@@ -1364,32 +1299,35 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
next:
svc = svc_find_by_tty(dev);
} else
svc = svc_find(name, id);
svc = svc_find(cmd, id);
if (!svc) {
_d("Creating new svc for %s name %s id %s type %d", cmd, name, id, type);
svc = svc_new(cmd, name, id, type);
_d("Creating new svc for %s id #%s type %d", cmd, id, type);
svc = svc_new(cmd, id, type);
if (!svc) {
_e("Out of memory, cannot register service %s", cmd);
return errno = ENOMEM;
}
if (manual)
if (type == SVC_TYPE_SERVICE && manual)
svc_stop(svc);
} else {
_d("Found existing svc for %s name %s id %s type %d", cmd, name, id, type);
svc->restart_max = restart_max;
svc->restart_tmo = restart_tmo;
svc->oncrash_action = oncrash_action;
} else {
/* update type, may have changed from service -> task */
svc->type = type;
/* update path, may have changed on reload */
strlcpy(svc->cmd, cmd, sizeof(svc->cmd));
/* e.g., if missing cmd or env before */
if (!manual)
svc_unblock(svc);
}
/* Decode any optional pid:/optional/path/to/file.pid */
if (pid && (svc_is_daemon(svc) || svc_is_sysv(svc)) && pid_file_parse(svc, pid))
_e("Invalid 'pid' argument to service: %s", pid);
if (username) {
char *ptr = strchr(username, ':');
@@ -1404,7 +1342,7 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
}
svc->runlevels = levels;
_d("Service %s runlevel 0x%02x", svc_ident(svc, NULL, 0), svc->runlevels);
_d("Service %s runlevel 0x%02x", svc->cmd, svc->runlevels);
conf_parse_cond(svc, cond);
@@ -1438,7 +1376,8 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
id = ptr;
strlcpy(svc->name, "tty", sizeof(svc->name));
strlcpy(svc->id, id, sizeof(svc->id));
}
} else
parse_name(svc, name);
parse_cmdline_args(svc, cmd);
@@ -1466,30 +1405,8 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
parse_env(svc, env);
if (file)
strlcpy(svc->file, file, sizeof(svc->file));
svc->manual = manual;
svc->respawn = respawn;
svc->forking = forking;
svc->restart_max = restart_max;
svc->restart_tmo = restart_tmo;
svc->oncrash_action = oncrash_action;
/* Decode any (optional) pid:/optional/path/to/file.pid */
if (svc_is_daemon(svc) || svc_is_sysv(svc)) {
char tmp[sizeof(svc->name) + 6]; /* pid:! + svc->name */
/* no pid: set, figure out a default to track this svc */
if (!pid && forking) {
snprintf(tmp, sizeof(tmp), "pid:!%s", svc->name);
pid = tmp;
logit(LOG_INFO, "%s: forking but no pid:!file set, guessing -> %s", svc->name, tmp);
}
if (pid && pid_file_parse(svc, pid))
logit(LOG_WARNING, "%s: service has invalid 'pid:' config: %s", svc->name, pid);
if (svc->pidfile[0] == '!')
svc->forking = 1;
}
if (respawn)
svc->respawn = 1;
/* Set configured limits */
memcpy(svc->rlimit, rlimit, sizeof(svc->rlimit));
@@ -1562,22 +1479,14 @@ void service_monitor(pid_t lost, int status)
default:
_d("collected %s(%d), normal exit: %d, signaled: %d, exit code: %d",
svc_ident(svc, NULL, 0), lost, WIFEXITED(status), WIFSIGNALED(status), WEXITSTATUS(status));
svc->cmd, lost, WIFEXITED(status), WIFSIGNALED(status), WEXITSTATUS(status));
svc->status = status;
break;
}
/* Forking sysv/services declare themselves with pid:!/path/to/pid.file */
if (svc_is_forking(svc)) {
/* Likely start script exiting */
if (svc_is_starting(svc)) {
svc->pid = 0; /* Expect no more activity from this one */
goto cont;
}
logit(LOG_CONSOLE | LOG_NOTICE, "Stopped %s[%d]", svc_ident(svc, NULL, 0), lost);
}
if (svc_is_starting(svc) && svc_is_forking(svc))
return;
/* Terminate any children in the same proess group, e.g. logit */
kill(-svc->pid, SIGKILL);
@@ -1596,11 +1505,11 @@ void service_monitor(pid_t lost, int status)
done:
/* No longer running, update books. */
svc->start_time = svc->pid = 0;
cont:
if (!service_step(svc)) {
/* Clean out any bootstrap tasks, they've had their time in the sun. */
if (svc_clean_bootstrap(svc))
_d("collected bootstrap task %s(%d), removing.", svc_ident(svc, NULL, 0), lost);
_d("collected bootstrap task %s(%d), removing.", svc->cmd, lost);
}
sm_step(&sm);
@@ -1652,11 +1561,21 @@ static void service_kill_script(svc_t *svc)
static void set_pre_post_envs(svc_t *svc, const char *type)
{
char buf[25 + 256] = "/etc/default:/etc/conf.d";
const char *fn = svc_getenv(svc);
const char *exist = "0";
setenv("SERVICE_TYPE", svc_typestr(svc), 1);
setenv("SERVICE_IDENT", svc_ident(svc, NULL, 0), 1);
setenv("SERVICE_SCRIPT_TYPE", type, 1);
if (fn) {
setenv("SERVICE_ENV_FILE", fn, 1);
if (!access(fn, R_OK))
exist = "1";
}
setenv("SERVICE_ENV_FILE", fn, 1);
setenv("SERVICE_ENV_FILE_EXIST", exist, 1);
#ifdef FINIT_SYSCONFIG
strlcat(buf, ":", sizeof(buf));
strlcat(buf, FINIT_SYSCONFIG, sizeof(buf));
@@ -1673,20 +1592,12 @@ static void service_pre_script(svc_t *svc)
}
if (svc->pid == 0) {
char buf[CMD_SIZE];
char *argv[4] = {
"sh",
"-ac",
buf,
"-c",
svc->pre_script,
NULL
};
char *env_file;
env_file = svc_getenv(svc);
if (env_file)
snprintf(buf, sizeof(buf), ". %s; exec %s", env_file, svc->pre_script);
else
strlcpy(buf, svc->pre_script, sizeof(buf));
set_pre_post_envs(svc, "pre");
execvp(_PATH_BSHELL, argv);
@@ -1706,24 +1617,17 @@ static void service_post_script(svc_t *svc)
}
if (svc->pid == 0) {
char buf[CMD_SIZE];
char *argv[4] = {
"sh",
"-ac",
buf,
"-c",
svc->post_script,
NULL
};
char *env_file;
int rc, sig;
rc = WEXITSTATUS(svc->status);
sig = WTERMSIG(svc->status);
env_file = svc_getenv(svc);
if (env_file)
snprintf(buf, sizeof(buf), ". %s; exec %s", env_file, svc->post_script);
else
strlcpy(buf, svc->post_script, sizeof(buf));
set_pre_post_envs(svc, "post");
if (WIFEXITED(svc->status)) {
@@ -1752,7 +1656,7 @@ static void service_retry(svc_t *svc)
service_timeout_cancel(svc);
if (svc->respawn) {
_d("%s crashed/exited, respawning ...", svc_ident(svc, NULL, 0));
_d("%s crashed/exited, respawning ...", svc->cmd);
svc_unblock(svc);
service_step(svc);
return;
@@ -1760,20 +1664,19 @@ static void service_retry(svc_t *svc)
if (svc->state != SVC_HALTED_STATE ||
svc->block != SVC_BLOCK_RESTARTING) {
svc_set_state(svc, SVC_RUNNING_STATE);
logit(LOG_CONSOLE | LOG_NOTICE, "Successfully restarted crashing service %s.",
svc_ident(svc, NULL, 0));
return;
}
/* Peak instability index */
if (svc->restart_max != -1 && *restart_cnt >= svc->restart_max) {
if (*restart_cnt >= svc->restart_max) {
logit(LOG_CONSOLE | LOG_WARNING, "Service %s keeps crashing, not restarting.",
svc_ident(svc, NULL, 0));
svc_crashing(svc);
*restart_cnt = 0;
if (svc->oncrash_action == SVC_ONCRASH_REBOOT) {
logit(LOG_ERR, "%s issuing reboot", svc_ident(svc, NULL, 0));
logit(LOG_ERR, "%s issuing reboot", svc->cmd);
sync();
kill(1, SIGTERM);
}
@@ -1783,7 +1686,7 @@ static void service_retry(svc_t *svc)
(*restart_cnt)++;
_d("%s crashed, trying to start it again, attempt %d", svc_ident(svc, NULL, 0), *restart_cnt);
_d("%s crashed, trying to start it again, attempt %d", svc->cmd, *restart_cnt);
logit(LOG_CONSOLE | LOG_WARNING, "Service %s[%d] died, restarting (%d/%d)",
svc_ident(svc, NULL, 0), svc->oldpid, *restart_cnt, svc->restart_max);
svc_unblock(svc);
@@ -1805,7 +1708,7 @@ static void svc_set_state(svc_t *svc, svc_state_t new)
/* if PID isn't collected within SVC_TERM_TIMEOUT msec, kill it! */
if (*state == SVC_STOPPING_STATE) {
_d("%s is stopping, wait %d sec before sending SIGKILL ...",
svc_ident(svc, NULL, 0), svc->killdelay / 1000);
svc->cmd, svc->killdelay / 1000);
service_timeout_cancel(svc);
service_timeout_after(svc, svc->killdelay, service_kill);
}
@@ -1813,8 +1716,8 @@ static void svc_set_state(svc_t *svc, svc_state_t new)
if (svc_is_runtask(svc)) {
char success[MAX_COND_LEN], failure[MAX_COND_LEN];
snprintf(success, sizeof(success), "%s/%s/success", svc_typestr(svc), svc_ident(svc, NULL, 0));
snprintf(failure, sizeof(failure), "%s/%s/failure", svc_typestr(svc), svc_ident(svc, NULL, 0));
snprintf(success, sizeof(success), "%s/%s/success", svc_typestr(svc), svc->name);
snprintf(failure, sizeof(failure), "%s/%s/failure", svc_typestr(svc), svc->name);
/* create success/failure condition when entering SVC_DONE_STATE. */
if (*state == SVC_DONE_STATE) {
@@ -1830,39 +1733,6 @@ static void svc_set_state(svc_t *svc, svc_state_t new)
cond_clear(failure);
}
}
if (svc_is_daemon(svc)) {
char cond[MAX_COND_LEN];
snprintf(cond, sizeof(cond), "service/%s/", svc_ident(svc, NULL, 0));
cond_clear(cond);
switch (svc->state) {
case SVC_HALTED_STATE:
case SVC_RUNNING_STATE:
strlcat(cond, svc_status(svc), sizeof(cond));
cond_set_oneshot(cond);
break;
default:
break;
}
}
}
/*
* Called by pidfile plugin for forking services that have successfully started.
* We get here when the service_monitor() collects the PID, sets svc->pid to 0,
* and the state machine prepares for the worst bu setting state to HALTED.
*/
void service_forked(svc_t *svc)
{
/* Stop forking_retry() timer */
service_timeout_cancel(svc);
/* Not crashing, restore RUNNING state */
svc_unblock(svc);
svc_set_state(svc, SVC_RUNNING_STATE);
}
/*
@@ -1883,28 +1753,31 @@ restart:
old_state = svc->state;
enabled = svc_enabled(svc);
_d("%20s(%4d): %8s %3sabled/%-7s cond:%-4s", svc_ident(svc, NULL, 0), svc->pid,
_d("%20s(%4d): %8s %3sabled/%-7s cond:%-4s", svc->cmd, svc->pid,
svc_status(svc), enabled ? "en" : "dis", svc_dirtystr(svc),
condstr(cond_get_agg(svc->cond)));
switch (svc->state) {
case SVC_HALTED_STATE:
if (enabled)
if (enabled) {
if (svc_has_pre(svc)) {
svc_set_state(svc, SVC_SETUP_STATE);
service_pre_script(svc);
} else
svc_set_state(svc, SVC_READY_STATE);
}
break;
case SVC_DONE_STATE:
if (svc_is_changed(svc))
svc_set_state(svc, SVC_HALTED_STATE);
if (svc_is_runtask(svc) && svc_is_manual(svc) && enabled)
svc_set_state(svc, SVC_READY_STATE);
break;
case SVC_STOPPING_STATE:
if (!svc->pid) {
char condstr[MAX_COND_LEN];
_d("%s: stopped, cleaning up timers and conditions ...", svc_ident(svc, NULL, 0));
_d("%s: stopped, cleaning up timers and conditions ...", svc->cmd);
service_timeout_cancel(svc);
cond_clear(mkcond(svc, condstr, sizeof(condstr)));
@@ -1921,8 +1794,6 @@ restart:
case SVC_TYPE_TASK:
case SVC_TYPE_RUN:
if (svc->manual)
svc_stop(svc);
svc_set_state(svc, SVC_DONE_STATE);
break;
@@ -1940,7 +1811,7 @@ restart:
case SVC_SETUP_STATE:
if (!svc->pid)
svc_set_state(svc, SVC_STARTING_STATE);
svc_set_state(svc, SVC_READY_STATE);
break;
case SVC_READY_STATE:
@@ -1951,21 +1822,6 @@ restart:
if (sm_is_in_teardown(&sm))
break;
if (svc_has_pre(svc)) {
svc_set_state(svc, SVC_SETUP_STATE);
service_pre_script(svc);
break;
}
svc_set_state(svc, SVC_STARTING_STATE);
}
break;
case SVC_STARTING_STATE:
if (!enabled) {
svc_set_state(svc, SVC_HALTED_STATE);
break;
}
err = service_start(svc);
if (err) {
if (svc_is_missing(svc)) {
@@ -1979,6 +1835,7 @@ restart:
/* Everything went fine, clean and set state */
svc_mark_clean(svc);
svc_set_state(svc, SVC_RUNNING_STATE);
}
break;
case SVC_RUNNING_STATE:
@@ -1988,26 +1845,27 @@ restart:
}
if (!svc->pid) {
if (svc_is_daemon(svc) || svc_is_sysv(svc) || svc_is_tty(svc)) {
if (svc_is_daemon(svc) || svc_is_tty(svc)) {
svc_restarting(svc);
svc_set_state(svc, SVC_HALTED_STATE);
/*
* Restart directly after the first crash, except for forking services
* which we need to wait for the forked-off child to create its pid
* file. In both cases, after that, retry after 2 sec
* Restart directly after the first crash,
* then retry after 2 sec
*/
if (!svc->respawn)
_d("delayed restart of %s", svc_ident(svc, NULL, 0));
if (svc_is_forking(svc))
service_timeout_after(svc, 2000, service_retry);
else
_d("delayed restart of %s", svc->cmd);
service_timeout_after(svc, 1, service_retry);
break;
}
if (svc_is_runtask(svc)) { /* only run/task, not sysv here */
if (svc_is_runtask(svc)) {
if (svc_is_sysv(svc)) {
if (!svc->started)
svc_set_state(svc, SVC_STOPPING_STATE);
} else {
svc_set_state(svc, SVC_STOPPING_STATE);
}
svc->once++;
break;
}
@@ -2086,7 +1944,7 @@ restart:
}
if (svc->state != old_state) {
_d("%20s(%4d): -> %8s", svc_ident(svc, NULL, 0), svc->pid, svc_status(svc));
_d("%20s(%4d): -> %8s", svc->cmd, svc->pid, svc_status(svc));
changed++;
goto restart;
}
@@ -2157,15 +2015,15 @@ int service_completed(void)
if (strstr(svc->cond, plugin_hook_str(HOOK_SVC_UP)) ||
strstr(svc->cond, plugin_hook_str(HOOK_SYSTEM_UP))) {
_d("Skipping %s(%s), post-strap hook", svc->desc, svc_ident(svc, NULL, 0));
_d("Skipping %s(%s), post-strap hook", svc->desc, svc->cmd);
continue;
}
if (!svc->once) {
_d("%s has not yet completed ...", svc_ident(svc, NULL, 0));
_d("%s has not yet completed ...", svc->cmd);
return 0;
}
_d("%s has completed ...", svc_ident(svc, NULL, 0));
_d("%s has completed ...", svc->cmd);
}
return 1;
+1 -7
View File
@@ -1,7 +1,7 @@
/* Finit service monitor, task starter and generic API for managing svc_t
*
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2008-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -35,12 +35,6 @@ void service_runtask_clean (void);
void service_reload_dynamic (void);
void service_update_rdeps (void);
int service_timeout_after (svc_t *svc, int timeout, void (*cb)(svc_t *svc));
int service_timeout_cancel (svc_t *svc);
void service_forked (svc_t *svc);
int service_stop (svc_t *svc);
int service_step (svc_t *svc);
void service_step_all (int types);
void service_worker (void *unused);
+10 -47
View File
@@ -1,7 +1,7 @@
/* Signal management - Be conservative with what finit responds to!
*
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2008-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -69,12 +69,7 @@
* Finit defaults to nothing but sets sys/pwr/fail condition.
*/
#include "config.h" /* Generated by configure script */
#include <dirent.h>
#ifdef HAVE_MNTENT_H
#include <mntent.h>
#endif
#include <string.h> /* strerror() */
#include <sched.h>
#include <sys/reboot.h>
@@ -171,30 +166,6 @@ void mdadm_wait(void);
void unmount_tmpfs(void);
void unmount_regular(void);
static void fs_swapoff(void)
{
struct mntent *mnt;
char cmd[256];
FILE *fp;
if (!whichp("swapoff"))
return;
fp = setmntent(fstab, "r");
if (!fp)
return;
while ((mnt = getmntent(fp))) {
if (strcmp(mnt->mnt_type, MNTTYPE_SWAP))
continue;
snprintf(cmd, sizeof(cmd), "swapoff %s", mnt->mnt_fsname);
run_interactive(cmd, "Disabling swap %s", mnt->mnt_fsname);
}
endmntent(fp);
}
/*
* Kernel threads have no cmdline so fgets() returns NULL for them. We
* also skip "special" processes, e.g. mdadm/mdmon or watchdogd that must
@@ -236,8 +207,7 @@ void do_iterate_proc(int (*cb)(int, void *), void *data)
_d("Skipping %s ...", &file[1]);
else
if (cb(pid, data)) {
_d("PID %d is still alive (%s)", pid, file);
fclose(fp);
print(0, "PID %d is still alive (%s)", pid, file);
break;
}
}
@@ -352,21 +322,14 @@ void do_shutdown(shutop_t op)
/* Unmount any tmpfs before unmounting swap ... */
unmount_tmpfs();
fs_swapoff();
if (whichp("swapoff"))
run("swapoff -e -a", "swapoff");
/* ... unmount remaining regular file systems. */
unmount_regular();
/*
* We sit on / so we must remount it ro, try all the things!
* See the following links for details:
* - https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=339023
* - https://bugs.launchpad.net/ubuntu/+source/util-linux/+bug/29187
*/
sync();
run("mount -n -o remount,ro -t dummytype dummydev /", NULL);
run("mount -n -o remount,ro dummydev /", NULL);
run("mount -n -o remount,ro /", "mount");
/* We sit on / so we must remount it read-only */
run("mount -n -o remount,ro -t none rootfs /", "mount");
/* Call mdadm to mark any RAID array(s) as clean before halting. */
mdadm_wait();
@@ -496,8 +459,8 @@ static void sigterm_cb(uev_t *w, void *arg, int events)
*/
static void sigchld_cb(uev_t *w, void *arg, int events)
{
int status;
pid_t pid;
int status;
if (UEV_ERROR == events) {
_e("Unrecoverable error in signal watcher");
@@ -560,8 +523,8 @@ static void chld_handler(int sig, siginfo_t *info, void *ctx)
void sig_init(void)
{
struct sigaction sa;
int i;
struct sigaction sa;
for (i = 1; i < NSIG; i++)
IGNSIG(sa, i, SA_RESTART);
@@ -574,9 +537,9 @@ void sig_init(void)
*/
void sig_unblock(void)
{
struct sigaction sa;
sigset_t nmask;
int i;
sigset_t nmask;
struct sigaction sa;
sigemptyset(&nmask);
sigaddset(&nmask, SIGHUP);
+1 -1
View File
@@ -1,7 +1,7 @@
/* Signal management - Be conservative with what finit responds to!
*
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2008-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
+2 -2
View File
@@ -187,7 +187,7 @@ restart:
*/
svc = svc_stop_completed();
if (svc) {
_d("Waiting to collect %s, cmd %s(%d) ...", svc_ident(svc, NULL, 0), svc->cmd, svc->pid);
_d("Waiting to collect %s(%d) ...", svc->cmd, svc->pid);
break;
}
@@ -240,7 +240,7 @@ restart:
*/
svc = svc_stop_completed();
if (svc) {
_d("Waiting to collect %s, cmd %s(%d) ...", svc_ident(svc, NULL, 0), svc->cmd, svc->pid);
_d("Waiting to collect %s(%d) ...", svc->cmd, svc->pid);
break;
}
+1 -3
View File
@@ -1,6 +1,6 @@
/* Reset terminal line settings (stty sane)
*
* Copyright (c) 2016-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2016-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -21,8 +21,6 @@
* THE SOFTWARE.
*/
#include "config.h" /* Generated by configure script */
#include <errno.h>
#include <stdlib.h>
#include <unistd.h> /* _POSIX_VDISABLE */
+1 -4
View File
@@ -1,6 +1,6 @@
/* poor man's sulogin, may be statically linked
*
* Copyright (c) 2021-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -193,9 +193,6 @@ int main(void)
nopass:
freepw(&pw);
/* tell initctl/reboot to trigger force mode */
setenv("SULOGIN", "finit", 1);
return sh();
}
}
+32 -12
View File
@@ -1,7 +1,7 @@
/* Low-level service primitives and generic API for managing svc_t structures
*
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2008-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -22,8 +22,7 @@
* THE SOFTWARE.
*/
#include "config.h" /* Generated by configure script */
#include <err.h>
#include <ctype.h> /* isdigit() */
#include <time.h>
#include <signal.h>
@@ -106,17 +105,16 @@ static void svc_gc(void *arg)
/**
* svc_new - Create a new service
* @cmd: External program to call
* @name: Default or custom svc name
* @id: Instance id
* @type: Service type, one of service, task, run
*
* Returns:
* A pointer to a new &svc_t object, or %NULL if out of empty slots.
*/
svc_t *svc_new(char *cmd, char *name, char *id, int type)
svc_t *svc_new(char *cmd, char *id, int type)
{
svc_t *svc, *iter = NULL;
int job = -1;
svc_t *svc, *iter = NULL;
/* Find first job n:o if registering multiple instances */
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
@@ -134,8 +132,6 @@ svc_t *svc_new(char *cmd, char *name, char *id, int type)
svc->type = type;
svc->job = job;
if (name)
strlcpy(svc->name, name, sizeof(svc->name));
if (id && id[0])
strlcpy(svc->id, id, sizeof(svc->id));
if (cmd)
@@ -350,13 +346,13 @@ svc_t *svc_stop_completed(void)
/**
* svc_find - Find a service object by its full path name
* @name: Full path name, e.g., /sbin/syslogd
* @cmd: Full path name, e.g., /sbin/syslogd
* @id: Optional instance id
*
* Returns:
* A pointer to an &svc_t object, or %NULL if not found.
*/
svc_t *svc_find(char *name, char *id)
svc_t *svc_find(char *cmd, char *id)
{
svc_t *svc, *iter = NULL;
@@ -364,7 +360,7 @@ svc_t *svc_find(char *name, char *id)
id = "";
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
if (!strcmp(svc->name, name) && !strcmp(svc->id, id))
if (!strcmp(svc->cmd, cmd) && !strcmp(svc->id, id))
return svc;
}
@@ -413,6 +409,30 @@ svc_t *svc_find_by_jobid(int job, char *id)
return NULL;
}
/**
* svc_find_by_nameid - Find an service object by its basename:ID
* @name: Process name to match
* @id: Optional instance id
*
* Returns:
* A pointer to an &svc_t object, or %NULL if not found.
*/
svc_t *svc_find_by_nameid(char *name, char *id)
{
svc_t *svc, *iter = NULL;
if (!id)
id = "";
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
if (!strcmp(svc->id, id) && !strcmp(name, svc->name))
return svc;
}
return NULL;
}
svc_t *svc_find_by_tty(char *dev)
{
svc_t *svc, *iter = NULL;
@@ -698,7 +718,7 @@ int svc_parse_jobstr(char *str, size_t len, void *user_data, int (*found)(svc_t
*ptr++ = 0;
id = ptr;
svc = svc_find(token, id);
svc = svc_find_by_nameid(token, id);
if (!svc && not_found)
result += not_found(token, id, user_data);
else if (found)
+7 -10
View File
@@ -1,7 +1,7 @@
/* Low-level service primitives and generic API for managing svc_t structures
*
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2008-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -63,7 +63,6 @@ typedef enum {
SVC_SETUP_STATE, /* Running pre: script */
SVC_WAITING_STATE, /* Condition is in flux, process SIGSTOPed */
SVC_READY_STATE, /* Enabled but condition not satisfied */
SVC_STARTING_STATE, /* Conditions OK and pre: script done, start */
SVC_RUNNING_STATE, /* Process running */
} svc_state_t;
@@ -122,14 +121,12 @@ typedef struct svc {
int status; /* From waitpid() when process is collected */
const svc_state_t state; /* Paused, Reloading, Restart, Running, ... */
svc_type_t type; /* Service, run, task, ... */
char protect; /* Services like dbus-daemon & udev by Finit */
char manual; /* run/task that require `initctl start foo` */
int protect; /* Services like dbus-daemon & udev by Finit */
const int dirty; /* 0: unmodified, 1: modified */
const int removed;
int starting; /* ... waiting for pidfile to be re-asserted */
int runlevels;
int sighup; /* This service supports SIGHUP :) */
int forking; /* This is a service/sysv daemon that forks, wait for it ... */
svc_block_t block; /* Reason that this service is currently stopped */
char cond[MAX_COND_LEN];
@@ -141,7 +138,7 @@ typedef struct svc {
/* Counters */
char once; /* run/task, (at least) once per runlevel */
unsigned int restart_tot; /* Total restarts ever, summarized, including `initctl restart` */
int restart_max; /* Maximum number of restarts allowed */
unsigned char restart_max; /* Maximum number of restarts allowed */
int restart_tmo; /* Time required for the service to start. */
unsigned char oncrash_action; /* Action to perform in crashed state. */
char respawn; /* ttys, or services with `respawn`, never increment restart_cnt */
@@ -195,13 +192,14 @@ typedef struct svc {
struct timespec gc;
} svc_t;
svc_t *svc_new (char *cmd, char *name, char *id, int type);
svc_t *svc_new (char *cmd, char *id, int type);
int svc_del (svc_t *svc);
void svc_validate (svc_t *svc);
svc_t *svc_find (char *name, char *id);
svc_t *svc_find (char *cmd, char *id);
svc_t *svc_find_by_pid (pid_t pid);
svc_t *svc_find_by_jobid (int job, char *id);
svc_t *svc_find_by_nameid (char *name, char *id);
svc_t *svc_find_by_tty (char *dev);
svc_t *svc_find_by_pidfile (char *fn);
@@ -230,8 +228,7 @@ static inline int svc_is_daemon (svc_t *svc) { return svc && SVC_TYPE_SERVICE
static inline int svc_is_sysv (svc_t *svc) { return svc && SVC_TYPE_SYSV == svc->type; }
static inline int svc_is_tty (svc_t *svc) { return svc && SVC_TYPE_TTY == svc->type; }
static inline int svc_is_runtask (svc_t *svc) { return svc && (SVC_TYPE_RUNTASK & svc->type);}
static inline int svc_is_forking (svc_t *svc) { return svc && svc->forking; }
static inline int svc_is_manual (svc_t *svc) { return svc && svc->manual; }
static inline int svc_is_forking (svc_t *svc) { return (svc_is_daemon(svc) || svc_is_sysv(svc)) && svc->pidfile[0] == '!'; }
static inline int svc_in_runlevel (svc_t *svc, int runlevel) { return svc && ISSET(svc->runlevels, runlevel); }
static inline int svc_nohup (svc_t *svc) { return svc && (0 == svc->sighup || 0 != svc->args_dirty); }
+3 -15
View File
@@ -1,7 +1,7 @@
/* Finit TTY handling
*
* Copyright (c) 2013 Mattias Walström <lazzer@gmail.com>
* Copyright (c) 2013-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2013-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -22,8 +22,6 @@
* THE SOFTWARE.
*/
#include "config.h" /* Generated by configure script */
#include <ctype.h> /* isdigit() */
#include <signal.h>
#include <termios.h>
@@ -154,7 +152,6 @@ char *tty_atcon(void)
int tty_parse_args(char *cmd, struct tty *tty)
{
char *dev = NULL;
int passenv = 0;
size_t i;
do {
@@ -166,8 +163,6 @@ int tty_parse_args(char *cmd, struct tty *tty)
tty->nologin = 1;
else if (!strcmp(cmd, "notty"))
tty->notty = 1; /* for board bringup */
else if (!strcmp(cmd, "passenv"))
passenv = 1;
else if (!strcmp(cmd, "rescue"))
tty->rescue = 1; /* for rescue shells */
else if (whichp(cmd)) /* in $PATH? */
@@ -175,7 +170,7 @@ int tty_parse_args(char *cmd, struct tty *tty)
else
tty->args[tty->num++] = cmd;
cmd = strtok(NULL, " ");
cmd = strtok(NULL, " \t");
} while (cmd && tty->num < NELEMS(tty->args));
/* rescue shells are always notty */
@@ -231,15 +226,8 @@ int tty_parse_args(char *cmd, struct tty *tty)
tty->dev, tty->baud ?: "0", tty->term ?: "N/A");
/* Built-in getty now comes as standalone program */
if (!tty->cmd) {
if (passenv && tty->num < NELEMS(tty->args)) {
for (i = tty->num; i > 0; i--)
tty->args[i] = tty->args[i - 1];
tty->args[0] = "-p";
tty->num++;
}
if (!tty->cmd)
tty->cmd = _PATH_GETTY;
}
return 0;
}
+1 -1
View File
@@ -1,7 +1,7 @@
/* Finit TTY handling
*
* Copyright (c) 2013 Mattias Walström <lazzer@gmail.com>
* Copyright (c) 2013-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2013-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
+4 -43
View File
@@ -1,6 +1,6 @@
/* Misc. shared utility functions for initctl, reboot and finit
*
* Copyright (c) 2016-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2016-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -21,13 +21,10 @@
* THE SOFTWARE.
*/
#include "config.h" /* Generated by configure script */
#include "config.h"
#include <ctype.h> /* isprint() */
#include <errno.h>
#ifdef HAVE_MNTENT_H
#include <mntent.h>
#endif
#include <regex.h>
#include <string.h>
#include <stdlib.h>
@@ -227,7 +224,7 @@ int fngetint(char *path, int *val)
{
char buf[64];
if (fnread(buf, sizeof(buf), "%s", path) <= 0)
if (fnread(buf, sizeof(buf), path) <= 0)
return -1;
errno = 0;
@@ -238,40 +235,6 @@ int fngetint(char *path, int *val)
return 0;
}
/*
* This is a replacement for the non-working reboot(RB_SW_SUSPEND). It
* checks for suspend to RAM support, assuming `mem_sleep` has a sane
* default, e.g. 'deep' or 's2idle'. The latter should be possible to
* select from finit.conf, but for now we go with the kernel default.
* For more information on kernel sleep states, see:
* https://www.kernel.org/doc/html/latest/admin-guide/pm/sleep-states.html
*/
int suspend(void)
{
char buf[80];
char *ptr;
if (fnread(buf, sizeof(buf), "/sys/power/state") <= 0) {
opnotsup:
errno = EINVAL;
return 1;
}
chomp(buf);
ptr = strtok(buf, " ");
while (ptr) {
if (!strcmp(ptr, "mem"))
break;
ptr = strtok(NULL, " ");
}
if (!ptr)
goto opnotsup;
return fnwrite("mem", "/sys/power/state");
}
int strtobytes(char *arg)
{
int mod = 0, bytes;
@@ -491,9 +454,7 @@ static int hasopt(char *opts, char *opt)
int ismnt(char *file, char *dir, char *mode)
{
struct mntent mount;
struct mntent *mnt;
char buf[256];
int found = 0;
FILE *fp;
@@ -501,7 +462,7 @@ int ismnt(char *file, char *dir, char *mode)
if (!fp)
return 0; /* Dunno, maybe not */
while ((mnt = getmntent_r(fp, &mount, buf, sizeof(buf)))) {
while ((mnt = getmntent(fp))) {
if (!strcmp(mnt->mnt_dir, dir)) {
if (mode) {
if (hasopt(mnt->mnt_opts, mode))
+5 -7
View File
@@ -1,6 +1,6 @@
/* Misc. shared utility functions for initctl, reboot and finit
*
* Copyright (c) 2016-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2016-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -54,13 +54,11 @@ extern char *prognm;
char *progname (char *arg0);
char *str (char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
int fnread (char *buf, size_t len, char *fmt, ...) __attribute__ ((format (printf, 3, 4)));
int fnwrite (char *value, char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
char *str (char *fmt, ...);
int fnread (char *buf, size_t len, char *fmt, ...);
int fnwrite (char *value, char *fmt, ...);
int fngetint (char *path, int *val);
int suspend (void);
int strtobytes (char *arg);
char *sig2str (int sig);
int str2sig (char *sig);
@@ -87,7 +85,7 @@ int ttcooked (void);
#define ttcooked() 0
#endif
static __attribute__ ((format (printf, 1, 2))) inline void dbg(char *fmt, ...)
static inline void dbg(char *fmt, ...)
{
va_list ap;
+2 -2
View File
@@ -1,6 +1,6 @@
/* UTMP API
*
* Copyright (c) 2016-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2016-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -21,7 +21,7 @@
* THE SOFTWARE.
*/
#include "config.h" /* Generated by configure script */
#include "config.h"
#include <time.h>
#include <arpa/inet.h>
+1 -1
View File
@@ -1,6 +1,6 @@
/* UTMP API
*
* Copyright (c) 2016-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2016-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
+1 -1
View File
@@ -1,6 +1,6 @@
/* Built-in watchdog daemon
*
* Copyright (c) 2016-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2016-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
+1 -1
View File
@@ -1,6 +1,6 @@
/* Built-in watchdog daemon
*
* Copyright (c) 2016-2022 Joachim Wiberg <troglobit@gmail.com>
* Copyright (c) 2016-2021 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
+1 -32
View File
@@ -1,32 +1,8 @@
SUBDIRS = common tenv
EXTRA_DIST = skel/bin/busybox-x86_64.md5 skel/sbin/service.sh skel/bin/slay \
skel/etc/env skel/bin/pre.sh skel/bin/post.sh skel/sbin/task.sh \
skel/cdrom/.empty skel/dev/shm/.empty skel/dev/pts/.empty \
skel/etc/inittab skel/etc/hostname skel/etc/fstab \
skel/etc/init.d/rcS skel/etc/init.d/rcK skel/tmp/.empty \
skel/etc/finit.d/.empty skel/etc/init.d/S01-service.sh \
skel/etc/init.d/S02-serv.sh \
skel/proc/.empty skel/root/.empty skel/run/.empty \
skel/sbin/chrootsetup.sh skel/srv/.empty skel/sys/.empty \
skel/usr/bin/.empty skel/usr/lib/.empty skel/usr/sbin/.empty \
skel/home/.empty skel/usr/games/.empty skel/usr/src/.empty \
skel/usr/share/.empty skel/usr/include/.empty \
skel/usr/local/games/.empty skel/usr/local/sbin/.empty \
skel/usr/local/share/.empty skel/usr/local/src/.empty \
skel/usr/local/lib/.empty skel/usr/local/bin/.empty \
skel/usr/local/etc/.empty skel/var/.empty
EXTRA_DIST += setup-root.sh
EXTRA_DIST = setup-root.sh
EXTRA_DIST += add-remove-dynamic-service.sh
EXTRA_DIST += add-remove-dynamic-service-sub-config.sh
EXTRA_DIST += cond-start-task.sh
EXTRA_DIST += failing-sysv.sh
EXTRA_DIST += global-envs.sh
EXTRA_DIST += initctl-status-subset.sh
EXTRA_DIST += pre-post-serv.sh
EXTRA_DIST += restart-self.sh
EXTRA_DIST += runlevel.sh
EXTRA_DIST += start-stop-service.sh
EXTRA_DIST += start-stop-service-sub-config.sh
EXTRA_DIST += start-kill-service.sh
@@ -50,13 +26,6 @@ TESTS = checkself.sh
TESTS += setup-root.sh
TESTS += add-remove-dynamic-service.sh
TESTS += add-remove-dynamic-service-sub-config.sh
TESTS += cond-start-task.sh
TESTS += failing-sysv.sh
TESTS += global-envs.sh
TESTS += initctl-status-subset.sh
TESTS += pre-post-serv.sh
TESTS += restart-self.sh
TESTS += runlevel.sh
TESTS += start-stop-service.sh
TESTS += start-stop-service-sub-config.sh
TESTS += start-kill-service.sh
@@ -13,12 +13,15 @@ test_teardown()
say "Running test teardown."
texec rm -f "$FINIT_RCSD/service.conf"
texec rm -f /test_assets/service.sh
}
say "Test start $(date)"
cp "$TEST_DIR"/common/service.sh "$TENV_ROOT"/test_assets/
say "Add a dynamic service in $FINIT_RCSD/service.conf"
texec sh -c "echo 'service [2345] kill:20 log service.sh -- Dyn serv' > $FINIT_RCSD/service.conf"
texec sh -c "echo 'service [2345] kill:20 log /test_assets/service.sh -- Dyn serv' > $FINIT_RCSD/service.conf"
say 'Reload Finit'
texec sh -c "initctl reload"
+10 -1
View File
@@ -3,6 +3,7 @@
set -eu
TEST_DIR=$(dirname "$0")
export DEBUG=1
# shellcheck source=/dev/null
. "$TEST_DIR/tenv/lib.sh"
@@ -13,12 +14,20 @@ test_teardown()
say "Running test teardown."
texec rm -f "$FINIT_CONF"
texec rm -f /test_assets/service.sh
}
say "Hi, this is /run et al"
texec sh -c "echo 'ROOT:/bin'; ls -l /bin/; echo 'ROOT:/sbin'; ls -l /sbin/; echo 'ROOT:/run'; ls -l /run/; echo 'ROOT:/run/finit/'; ls -l /run/finit/; echo 'ROOT:/dev'; ls -l /dev/; ps; ls -l /proc/1/fd/"
say "HUPing PID 1 ..."
texec sh -c "kill -HUP 1"
say "Test start $(date)"
cp "$TEST_DIR"/common/service.sh "$TENV_ROOT"/test_assets/
say "Add a dynamic service in $FINIT_CONF"
texec sh -c "echo 'service [2345] kill:20 log service.sh -- Dyn service' > $FINIT_CONF"
texec sh -c "echo 'service [2345] kill:20 log /test_assets/service.sh -- Dyn service' > $FINIT_CONF"
say 'Reload Finit'
texec sh -c "initctl reload"
+2 -2
View File
@@ -1,4 +1,4 @@
noinst_PROGRAMS = serv
EXTRA_DIST = service.conf service.sh S01-service.sh slay.sh
noinst_PROGRAMS = serv
serv_SOURCES = serv.c
serv_CPPFLAGS = -D_XOPEN_SOURCE=600 -D_BSD_SOURCE -D_GNU_SOURCE -D_DEFAULT_SOURCE
@@ -1,7 +1,7 @@
#!/bin/sh
# SysV style start script for service.sh
DAEMON="/sbin/service.sh"
DAEMON="/test_assets/service.sh"
PIDFILE="/var/run/service.pid"
start()
+3 -79
View File
@@ -15,60 +15,6 @@
#define PROGNM "serv"
static void verify_env(char *arg)
{
char *key, *value;
char *replica;
char *env;
key = replica = strdupa(arg);
if (!replica)
err(1, "Failed duplicating arg %s", arg);
value = strchr(replica, ':');
if (!value)
errx(1, "Invalid format of KEY:VALUE arg, missing ':' in %s", replica);
*(value++) = 0;
env = getenv(key);
if (!env)
errx(1, "No '%s' in environment", key);
if (strcmp(env, value))
errx(1, "Mismatch, environment '%s' vs expected value '%s'", env, value);
}
static void verify_noenv(char *key)
{
char *val;
val = getenv(key);
if (val)
errx(1, "Error, key %s is set in environment to '%s'", key, val);
}
static void inc_restarts(void)
{
char buf[10];
int cnt = 0;
FILE *fp;
fp = fopen("/tmp/serv-restart.cnt", "r+");
if (!fp) {
fp = fopen("/tmp/serv-restart.cnt", "w");
if (!fp)
err(1, "failed creating restart counter file");
} else {
if (fgets(buf, sizeof(buf), fp))
cnt = atoi(buf);
}
cnt++;
fseek(fp, SEEK_SET, 0);
fprintf(fp, "%d", cnt);
fclose(fp);
}
static void sig(int signo)
{
warnx("We got signal %d ...", signo);
@@ -102,13 +48,10 @@ static int usage(int rc)
fprintf(fp,
"%s [-nhp] [-P FILE]\n"
"\n"
" -h Show help text (this)\n"
" -e K:V Verify K environment variable is V value\n"
" -E K Verify K is not set in the environment\n"
" -n Run in foreground\n"
" -h Show help text (this)\n"
" -p Create PID file despite running in foreground\n"
" -P FILE Create PID file using FILE\n"
" -r SVC Call initctl to restart service SVC (self)\n"
"\n"
"By default this program daemonizes itself to the background, and,\n"
"when it's done setting up its signal handler(s), creates a PID file\n"
@@ -123,21 +66,13 @@ int main(int argc, char *argv[])
{
int do_background = 1;
int do_pidfile = 1;
int do_restart = 0;
char *pidfn = NULL;
char cmd[80];
int c;
while ((c = getopt(argc, argv, "e:E:hnpP:r:")) != EOF) {
while ((c = getopt(argc, argv, "hnpP:")) != EOF) {
switch (c) {
case 'h':
return usage(0);
case 'e':
verify_env(optarg);
break;
case 'E':
verify_noenv(optarg);
break;
case 'n':
do_background = 0;
do_pidfile--;
@@ -148,10 +83,6 @@ int main(int argc, char *argv[])
case 'P':
pidfn = optarg;
break;
case 'r':
snprintf(cmd, sizeof(cmd), "initctl restart %s", optarg);
do_restart = 1;
break;
default:
return usage(1);
}
@@ -171,15 +102,8 @@ int main(int argc, char *argv[])
pidfile(pidfn);
warnx("Entering while(1) loop");
while (1) {
while (1)
sleep(1);
if (do_restart) {
inc_restarts();
if (system(cmd))
return 1;
break;
}
}
warnx("Leaving ...");
return 0;
+1
View File
@@ -0,0 +1 @@
service [2345] kill:20 log /test_assets/service.sh

Some files were not shown because too many files have changed in this diff Show More