Compare commits

..
Author SHA1 Message Date
Jacques de Laval 50c99762f1 Add run target for running Finit as a stand alone unprivileged process
It could be very useful, during development, to be able to run Finit on a
host system without having to provision a full VM. We have all the building
blocks for easily containerizing Finit - in the test framework - so adding
a "run" target that does the orchestration makes sense.

Signed-off-by: Jacques de Laval <jacques@de-laval.se>
2021-03-05 01:39:42 +01:00
Jacques de Laval 067043b298 test: Use STDOUT of parent process instead of a pipe as tty for finit
Signed-off-by: Jacques de Laval <jacques@de-laval.se>
2021-03-05 01:24:31 +01:00
299 changed files with 5149 additions and 23310 deletions
+5 -5
View File
@@ -9,9 +9,9 @@ For email questions/requests/alerts there is always the risk of memory
exhaustion on the part of the maintainer(s). exhaustion on the part of the maintainer(s).
If you are unsure of what to do, or how to implement an idea or bugfix, If you are unsure of what to do, or how to implement an idea or bugfix,
open an issue with `"[RFC: Unsure if this is a bug ... ?"`, or use the open an issue with `"[RFC: Unsure if this is a bug ... ?"`, or similar,
GitHub discussions forum, so we can discuss it. Talking about the code so we can discuss it. Talking about the code first is the best way to
first is the best way to get started before submitting a pull request. get started before submitting a pull request.
Either way, when sending an email, patch, or pull request, start by Either way, when sending an email, patch, or pull request, start by
stating the version the change is made against, what it does, and why. stating the version the change is made against, what it does, and why.
@@ -24,8 +24,7 @@ the maintainer(s) and make it easier for them to include your code.
Coding Style Coding Style
------------ ------------
> [!TIP] > **Tip:** Always submit code that follows the style of surrounding code!
> Always submit code that follows the style of surrounding code!
First of all, lines are allowed to be longer than 72 characters these First of all, lines are allowed to be longer than 72 characters these
days. In fact, there exist no enforced maximum, but keeping it around days. In fact, there exist no enforced maximum, but keeping it around
@@ -74,6 +73,7 @@ It is expected of everyone engaging in the project to, in the words of
Bill & Ted; [be excellent to each other][conduct]. Bill & Ted; [be excellent to each other][conduct].
[github]: https://github.com/troglobit/finit/
[KNF]: https://en.wikipedia.org/wiki/Kernel_Normal_Form [KNF]: https://en.wikipedia.org/wiki/Kernel_Normal_Form
[gitbook]: https://git-scm.com/book/ch5-2.html [gitbook]: https://git-scm.com/book/ch5-2.html
[conduct]: CODE-OF-CONDUCT.md [conduct]: CODE-OF-CONDUCT.md
-70
View File
@@ -1,70 +0,0 @@
name: Bob the Builder
# Run on all branches, including all pull requests, except the 'dev'
# branch since that's where we run Coverity Scan (limited tokens/day)
on:
push:
branches:
- '**'
- '!dev'
pull_request:
branches:
- '**'
jobs:
build:
# Verify we can build on latest Ubuntu with both gcc and clang
name: ${{ matrix.compiler }}
runs-on: ubuntu-latest
strategy:
matrix:
compiler: [gcc, clang]
fail-fast: false
env:
CC: ${{ matrix.compiler }}
steps:
- name: Install dependencies
run: |
sudo apt-get -y update
sudo apt-get -y install pkg-config tree jq libuev-dev libite-dev
- uses: actions/checkout@v4
- name: Static Finit
run: |
./autogen.sh
./configure --prefix= --enable-static
make -j3 V=1
- name: Regular Finit
run: |
./configure --prefix=/usr --exec-prefix= --sysconfdir=/etc --localstatedir=/var \
--enable-x11-common-plugin --enable-testserv-plugin --with-watchdog \
--with-keventd \
CFLAGS="-fsanitize=address -ggdb"
make -j3 clean
make -j3 V=1
- name: Install to /tmp
run: |
DESTDIR=/tmp make install-strip
tree /tmp || true
- name: Check dependencies
run: |
ldd /tmp/sbin/finit
size /tmp/sbin/finit
ldd /tmp/sbin/initctl
size /tmp/sbin/initctl
ldd /tmp/sbin/reboot
size /tmp/sbin/reboot
- name: Verify starting and showing usage text
run: |
sudo /tmp/sbin/finit -h
sudo /tmp/sbin/initctl -h
- name: Enable unprivileged userns (unshare)
run: |
sudo sysctl kernel.apparmor_restrict_unprivileged_userns=0
- name: Run Unit Tests
run: |
make check || (cat test/test-suite.log; false)
- name: Upload Test Results
uses: actions/upload-artifact@v4
with:
name: finit-test-${{ matrix.compiler }}
path: test/*.log
-88
View File
@@ -1,88 +0,0 @@
name: Coverity Scan
on:
push:
branches:
- 'dev'
workflow_dispatch:
env:
PROJECT_NAME: finit
CONTACT_EMAIL: troglobit@gmail.com
COVERITY_NAME: troglobit-finit
COVERITY_PROJ: troglobit%2Ffinit
jobs:
coverity:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Fetch latest Coverity Scan MD5
id: var
env:
TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
run: |
wget -q https://scan.coverity.com/download/cxx/linux64 \
--post-data "token=$TOKEN&project=${COVERITY_PROJ}&md5=1" \
-O coverity-latest.tar.gz.md5
echo "md5=$(cat coverity-latest.tar.gz.md5)" | tee -a $GITHUB_OUTPUT
- uses: actions/cache@v4
id: cache
with:
path: coverity-latest.tar.gz
key: ${{ runner.os }}-coverity-${{ steps.var.outputs.md5 }}
restore-keys: |
${{ runner.os }}-coverity-${{ steps.var.outputs.md5 }}
${{ runner.os }}-coverity-
${{ runner.os }}-coverity
- name: Download Coverity Scan
env:
TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
run: |
if [ ! -f coverity-latest.tar.gz ]; then
wget -q https://scan.coverity.com/download/cxx/linux64 \
--post-data "token=$TOKEN&project=${COVERITY_PROJ}" \
-O coverity-latest.tar.gz
else
echo "Latest Coverity Scan available from cache :-)"
md5sum coverity-latest.tar.gz
fi
mkdir coverity
tar xzf coverity-latest.tar.gz --strip 1 -C coverity
- name: Install dependencies
run: |
sudo apt-get -y update
sudo apt-get -y install pkg-config
wget https://github.com/troglobit/libuev/releases/download/v2.4.0/libuev-2.4.0.tar.xz
wget https://github.com/troglobit/libite/releases/download/v2.5.2/libite-2.5.2.tar.gz
tar xf libuev-2.4.0.tar.xz
tar xf libite-2.5.2.tar.gz
(cd libuev-2.4.0 && ./configure --prefix=/usr && make && sudo make install-strip)
(cd libite-2.5.2 && ./configure --prefix=/usr && make && sudo make install-strip)
sudo ldconfig
- name: Configure
run: |
./autogen.sh
./configure --prefix= --enable-x11-common-plugin --with-watchdog --with-keventd
- name: Build
run: |
export PATH=`pwd`/coverity/bin:$PATH
cov-build --dir cov-int make
- name: Submit results to Coverity Scan
env:
TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
run: |
tar czvf ${PROJECT_NAME}.tgz cov-int
curl \
--form project=${COVERITY_NAME} \
--form token=$TOKEN \
--form email=${CONTACT_EMAIL} \
--form file=@${PROJECT_NAME}.tgz \
--form version=trunk \
--form description="${PROJECT_NAME} $(git rev-parse HEAD)" \
https://scan.coverity.com/builds?project=${COVERITY_PROJ}
- name: Upload build.log
uses: actions/upload-artifact@v4
with:
name: coverity-build.log
path: cov-int/build-log.txt
-62
View File
@@ -1,62 +0,0 @@
name: Release General
on:
push:
tags:
- '[0-9]+.[0-9]+*'
jobs:
release:
name: Build and upload release tarball
if: startsWith(github.ref, 'refs/tags/')
runs-on: ubuntu-latest
env:
MAKEFLAGS: -j3
steps:
- uses: actions/checkout@v4
- name: Installing dependencies ...
run: |
sudo apt-get -y update
sudo apt-get -y install pkg-config jq libuev-dev libite-dev
- name: Setting release variables ...
id: build
run: |
ver=${GITHUB_REF#refs/tags/}
echo "ver=${ver}" >> $GITHUB_OUTPUT
if echo $ver | grep -qE '^[0-9]+\.[0-9]+(\.[0-9]+)?(-alpha|-beta|-rc)[0-9]*$'; then
echo "pre=true" >> $GITHUB_OUTPUT
else
echo "pre=false" >> $GITHUB_OUTPUT
fi
if echo $ver | grep -qE '^[0-9.]+\.[0-9.]+(\.[0-9]+)?$'; then
echo "latest=true" >> $GITHUB_OUTPUT
else
echo "latest=false" >> $GITHUB_OUTPUT
fi
- name: Creating Makefiles ...
run: |
./autogen.sh
./configure --prefix=/usr --exec-prefix= --sysconfdir=/etc --localstatedir=/var \
--enable-x11-common-plugin --enable-testserv-plugin --with-watchdog \
--with-keventd
- name: Enable unprivileged userns (unshare)
run: |
sudo sysctl kernel.apparmor_restrict_unprivileged_userns=0
- name: Build release ...
run: |
make release || (cat test/test-suite.log; false)
ls -lF ../
mkdir -p artifacts/
mv ../*.tar.* artifacts/
- name: Extract ChangeLog entry ...
run: |
awk '/-----*/{if (x == 1) exit; x=1;next}x' ChangeLog.md \
|head -n -1 > release.md
cat release.md
- uses: ncipollo/release-action@v1
with:
name: Finit v${{ github.ref_name }}
prerelease: ${{ steps.build.outputs.pre }}
makeLatest: ${{ steps.build.outputs.latest }}
bodyFile: "release.md"
artifacts: "artifacts/*"
-51
View File
@@ -1,51 +0,0 @@
name: Weekly Distcheck
# Verify that `make distcheck` works as intended: all tests pass, and
# any new files are distributed in the tarballs
on:
schedule:
- cron: '0 0 * * 0'
workflow_dispatch:
jobs:
schedule:
runs-on: ubuntu-latest
outputs:
run: ${{ steps.check.outputs.run }}
steps:
- uses: actions/checkout@v4
- name: Check for any commits since last week
id: schedule
run: |
commits="$(git log --format=%H --since='1 week ago')"
if [ -n "$commits" ]; then
echo "run=true" >> $GITHUB_OUTPUT
else
echo "run=false" >> $GITHUB_OUTPUT
fi
distcheck:
needs: schedule
if: ${{ needs.schedule.outputs.run == 'true' }}
runs-on: ubuntu-latest
steps:
- name: Install dependencies
run: |
sudo apt-get -y update
sudo apt-get -y install pkg-config jq libuev-dev libite-dev
- uses: actions/checkout@v4
- name: Base run
run: |
./autogen.sh
./configure --prefix=/usr --exec-prefix= --sysconfdir=/etc --localstatedir=/var
make -j9 V=1
- name: Install to /tmp
run: |
DESTDIR=/tmp make install-strip
- name: Enable unprivileged userns (unshare)
run: |
sudo sysctl kernel.apparmor_restrict_unprivileged_userns=0
- name: Check dist tarball
run: |
ver=$(/tmp/sbin/initctl -V | awk '/Finit.*/ {print $2;}')
dir=finit-$ver/_build/sub
make -j1 distcheck || (cat $dir/test/test-suite.log; false)
-7
View File
@@ -14,7 +14,6 @@ GTAGS
/autom4te.cache /autom4te.cache
/aclocal.m4 /aclocal.m4
/ar-lib /ar-lib
/backup/
/compile /compile
/config.cache /config.cache
/config.h /config.h
@@ -37,9 +36,6 @@ GTAGS
/test-driver /test-driver
/test-suite.log /test-suite.log
# Misc
/.gdb_history
# TroglOS build system # TroglOS build system
/.config /.config
/.stamp /.stamp
@@ -49,6 +45,3 @@ GTAGS
/.autoconf /.autoconf
/.automake /.automake
/.built /.built
# VS Code user settings
.vscode
-7
View File
@@ -1,7 +0,0 @@
# GNU Global .conf file, see /etc/gtags/gtags.conf for details.
default:\
:tc=default@/etc/gtags/gtags.conf:\
:tc=common:
common:\
:skip=tags,TAGS,ID,y.tab.c,y.tab.h,gtags.files,cscope.files,cscope.out,cscope.po.out,cscope.in.out,,{arch}/,autom4te.cache/,*.orig,*.rej,*.bak,*~,#*#,*.swp,*.tmp,*_flymake.*,*_flymake,*.o,*.a,*.so,*.lo,*.zip,*.gz,*.bz2,*.xz,*.lzh,*.Z,*.tgz,*.min.js,*min.css,sysroot/:
+65
View File
@@ -0,0 +1,65 @@
# Travis CI integration -- https://travis-ci.org/troglobit/finit
# Defaults to GNU GCC and autotools: ./configure && make && make test
language: c
# Use docker for quicker builds, it now allows https://docs.travis-ci.com/user/apt/
sudo: false
# Use non-docker builds atm. to install libuEv and libite from source
#sudo: true
# Test build with both GCC and Clang (LLVM)
compiler:
- gcc
- clang
# The secure: declaration is the encrypted COVERITY_SCAN_TOKEN, created
# via the "travis encrypt" command using the project repo's public key
env:
global:
- PKG_CONFIG_PATH=/tmp/lib/pkgconfig
- CFLAGS="-W -Wall -Wextra"
- secure: "eOiuHs02lG2Uv146K9dMqucGTWUJFEhpz1oAtwe+kPrRXsXWc20hYMO+DSpMgD05vSvNeQA6p7h7LdRFQ+/g/Obj27TsOE+RKkUvRAtdwzxnKVyii9C/nmML8cFw7rIA0VS8O9mAkVYeyDxNDupBp3e9DPCibhKPvqCvioTnyy4="
addons:
apt:
packages:
- tree
coverity_scan:
project:
name: "troglobit/finit"
description: "finit | Fast & Extensible init for Linux"
notification_email: troglobit@gmail.com
build_command_prepend: "./autogen.sh && ./configure --prefix=/tmp"
build_command: "make"
branch_pattern: dev
install:
- 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.3.1/libite-2.3.1.tar.gz
- tar xf libuev-2.3.2.tar.xz
- tar xf libite-2.3.1.tar.gz
- (cd libuev-2.3.2 && ./configure --prefix=/tmp && make && make install-strip)
- (cd libite-2.3.1 && ./configure --prefix=/tmp && make && make install-strip)
# Custom build script for the time being, no "make test" yet
script:
- ./autogen.sh
- ./configure --prefix=/tmp --enable-static
- make clean
- make V=1 -j5
- ./configure --prefix=/tmp --enable-x11-common-plugin --enable-fallback-shell --enable-watchdog --enable-logit
- cat config.log
- make clean
- make V=1 -j5
- make install-strip
- tree /tmp
- ldd /tmp/sbin/finit
- size /tmp/sbin/finit
- size /tmp/sbin/initctl
- size /tmp/sbin/reboot
- LD_LIBRARY_PATH=/tmp/lib /tmp/sbin/initctl -h
- unshare -V
- nsenter -V
- chroot --version
- 'LD_LIBRARY_PATH=/tmp/lib make distcheck || (cat finit-4.0-beta1/_build/sub/test/test-suite.log; exit 1)'
+55 -1014
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1,5 +1,5 @@
Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com> Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
Copyright (c) 2008-2024 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 Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
+16 -20
View File
@@ -1,5 +1,5 @@
ACLOCAL_AMFLAGS = -I m4 ACLOCAL_AMFLAGS = -I m4
SUBDIRS = man plugins src system tmpfiles.d SUBDIRS = plugins src test
doc_DATA = README.md LICENSE contrib/finit.conf doc_DATA = README.md LICENSE contrib/finit.conf
EXTRA_DIST = README.md LICENSE ChangeLog.md contrib/finit.conf EXTRA_DIST = README.md LICENSE ChangeLog.md contrib/finit.conf
@@ -9,22 +9,7 @@ endif
if DOC if DOC
SUBDIRS += doc SUBDIRS += doc
endif endif
if LIBSYSTEMD
SUBDIRS += libsystemd
endif
if LIBSYSTEMD
SUBDIRS += test
# Explicit dependency to ensure libsystemd is built before test
test: libsystemd
else
SUBDIRS += test
endif
if BASH
bashdir = $(BASH_DIR)
dist_bash_DATA = initctl
endif
# Compat hook # Compat hook
install-dev: install-dev:
@make -C src install-pkgincludeHEADERS @make -C src install-pkgincludeHEADERS
@@ -45,7 +30,18 @@ release: distcheck
printf "$$file.sha256\t"; cat ../$$file.sha256 | cut -f1 -d' '; \ printf "$$file.sha256\t"; cat ../$$file.sha256 | cut -f1 -d' '; \
done done
DISTCHECK_CONFIGURE_FLAGS = --prefix=/usr --sysconfdir=/etc --localstatedir=/var \ run:
--enable-testserv-plugin --enable-x11-common-plugin \ srcdir=@srcdir@/test \
--with-watchdog --with-keventd --with-fstab=/etc/fstab \ top_builddir=@top_builddir@ \
--with-bash-completion-dir=no TENV_ROOT=$(tenv_root) \
@srcdir@/test/setup-root.sh
mkdir -p $(dir $(tenv_root)/@FINIT_CONF@)
echo 'tty [12345] @console linux noclear nologin' > $(tenv_root)/@FINIT_CONF@
-TENV_ROOT=$(tenv_root) \
TESTENV_PATH=@sbindir@:/bin \
FINIT_RCSD=@FINIT_RCSD@ \
test/tenv/start.sh finit
run : tenv_root ?= @abs_top_builddir@/run-rootfs
+89 -335
View File
@@ -1,8 +1,9 @@
[![License Badge][]][License] [![GitHub Status][]][GitHub] [![Coverity Status][]][Coverity Scan] [![License Badge][]][License] [![Travis Status]][Travis] [![Coverity Status]][Coverity Scan]
<img align="right" src="img/finit3.png" alt="Finit: Fast Init"> <img align="right" src="img/finit3.png" alt="Finit: Fast Init">
* [Introduction](#introduction) * [Introduction](#introduction)
* [Features](#features) * [Features](#features)
* [Bootstrap](doc/bootstrap.md#bootstrap)
* [Runlevels](#runlevels) * [Runlevels](#runlevels)
* [Syntax](doc/config.md#syntax) * [Syntax](doc/config.md#syntax)
* [Runparts & /etc/rc.local](#runparts--etcrclocal) * [Runparts & /etc/rc.local](#runparts--etcrclocal)
@@ -21,53 +22,20 @@
Introduction Introduction
------------ ------------
Fast init for Linux systems. Reverse engineered from the [EeePC Finit is a simple alternative to [SysV init][4] and [systemd][6]. It
fastinit][] by [Claudio Matsuoka][] — "gaps filled with frog DNA …" was reverse engineered from the [EeePC fastinit][] over ten years ago
by [Claudio Matsuoka][] — "gaps filled with frog DNA …"
![Alpine screenshot](img/alpine-screenshot2.png)
*Figure 1: Screenshot of Finit booting [Alpine Linux (HowTo)](https://github.com/troglobit/finit/tree/master/contrib/alpine).*
Features include:
* Runlevels, defined per service
* One-shot tasks, services (daemons), or [SysV init][4] start/stop scripts
* Runparts and `/etc/rc.local` support
* Process supervision similar to [systemd][]
* Sourcing environment files
* Conditions for network/process/custom dependencies
* Readiness notification; PID files (native) for synchronizing system
startup, support for systemd [sd_notify()][], or [s6 style][] too
* Limited support for [tmpfiles.d(5)][] (no aging, attributes, or subvolumes)
* Pre/Post script actions
* Rudimentary [templating support](doc/config.md#templating)
* Tooling to enable/disable services
* Built-in getty
* Built-in watchdog, with support for hand-over to [watchdogd](https://troglobit.com/watchdogd.html)
* Built-in support for Debian/BusyBox `/etc/network/interfaces`
* 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 Focus is on small and embedded systems, although Finit is fully usable
on server and desktop systems as well. For working examples, see the on server and desktop systems as well. For working examples, see the
[contrib/](contrib/) section with tutorials for the following Linux [contrib/](contrib/) section with tutorials for:
distributions:
* [Void Linux](contrib/void/), * [Void Linux](contrib/void/),
* [Alpine Linux](contrib/alpine/), and * [Alpine Linux](contrib/alpine/), and
* [Debian GNU/Linux](contrib/debian/), also works on Ubuntu/Linux Mint * [Debian GNU/Linux](contrib/debian/)
> [!NOTE] ![Alpine screenshot](img/alpine-screenshot.png)
> Support for various Linux distributions does not mean Finit installs The screenshot shows [Alpine Linux](https://www.alpinelinux.org/).
> easily on all architectures. The bundled install scripts are examples
> for standard installations, tested on amd64 (x86_64) systems. Custom
> setups, e.g., for embedded systems, can be found in the following
> [Buildroot][] based examples: [myLinux][], [Infix][], or the plain
> [br2-finit-demo](https://github.com/troglobit/br2-finit-demo).
Example Example
@@ -76,36 +44,24 @@ Example
This example `/etc/finit.conf` can also be split up in multiple `.conf` This example `/etc/finit.conf` can also be split up in multiple `.conf`
files in `/etc/finit.d`. Available, but not yet enabled, services can files in `/etc/finit.d`. Available, but not yet enabled, services can
be placed in `/etc/finit.d/available` and enabled by an operator using be placed in `/etc/finit.d/available` and enabled by an operator using
the [initctl](#commands--status) tool. See the above mentioned Linux the [initctl](#commands--status) tool.
distributions, or [myLinux][].
> [!TIP]
> As of Finit v4.4, `.conf` lines can be broken up using the standard
> UNIX continuation character (`\`), trailing comments are now also
> supported. The latter means you need to escape any hashes used in
> directives and descriptions (`\#`). For more on this and examples,
> see the [finit.conf(5)][] manual or [doc/config.md](doc/config.md).
```ApacheConf ```ApacheConf
# Fallback if /etc/hostname is missing # Fallback if /etc/hostname is missing
host default host default
# Runlevel to start after bootstrap, 'S', default: 2 # Runlevel to start after bootstrap, 'S', default: 2
#runlevel 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
# Max file size for each log file: 100 kiB, rotate max 4 copies: # 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 # log => log.1 => log.2.gz => log.3.gz => log.4.gz
log size=100k count=4 log size=100k count=4
# Services to be monitored and respawned as needed # Services to be monitored and respawned as needed
service [S12345] env:-/etc/conf.d/watchdog watchdog $WATCHDOG_OPTS $WATCHDOG_DEV -- System watchdog daemon service [S12345] watchdogd -L -f -- System watchdog daemon
service [S12345] env:-/etc/conf.d/syslog syslogd -n $SYSLOGD_OPTS -- System log daemon service [S12345] syslogd -n -b 3 -D -- System log daemon
service [S12345] <pid/syslogd> env:-/etc/conf.d/klogd klogd -n $KLOGD_OPTS -- Kernel log daemon service [S12345] <pid/syslogd> klogd -n -- Kernel log daemon
service [2345] env:-/etc/conf.d/lldpd lldpd -d $LLDPD_OPTS -- LLDP daemon (IEEE 802.1ab) service [2345] lldpd -d -c -M1 -H0 -i -- LLDP daemon (IEEE 802.1ab)
# The BusyBox ntpd does not use syslog when running in the foreground # The BusyBox ntpd does not use syslog when running in the foreground
# So we use this trick to redirect stdout/stderr to a log file. The # So we use this trick to redirect stdout/stderr to a log file. The
@@ -120,29 +76,24 @@ service :80 [2345] merecat -n -p 80 /var/www -- Web server
service :8080 [2345] merecat -n -p 8080 /var/www -- Old web server service :8080 [2345] merecat -n -p 8080 /var/www -- Old web server
# Alternative method instead of below runparts, can also use /etc/rc.local # Alternative method instead of below runparts, can also use /etc/rc.local
#sysv [S] /etc/init.d/keyboard-setup -- Setting up preliminary keymap #task [S] /etc/init.d/keyboard-setup start -- Setting up preliminary keymap
#sysv [S] /etc/init.d/acpid -- Starting ACPI Daemon #task [S] /etc/init.d/acpid start -- Starting ACPI Daemon
#task [S] /etc/init.d/kbd -- Preparing console #task [S] /etc/init.d/kbd start -- 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 # Run start scripts from this directory
# runparts /etc/start.d # runparts /etc/start.d
# Virtual consoles run BusyBox getty, keep kernel default speed # Virtual consoles run BusyBox getty, keep kernel default speed
tty [12345] /sbin/getty -L 0 /dev/tty1 linux nowait noclear tty [12345] /sbin/getty -L 0 /dev/tty1 linux
tty [2345] /sbin/getty -L 0 /dev/tty2 linux nowait noclear tty [12345] /sbin/getty -L 0 /dev/tty2 linux
tty [2345] /sbin/getty -L 0 /dev/tty3 linux nowait noclear tty [12345] /sbin/getty -L 0 /dev/tty3 linux
# Use built-in getty for serial port and USB serial # Use built-in getty for serial port and USB serial
#tty [12345] /dev/ttyAMA0 noclear nowait tty [12345] /dev/ttyAMA0 noclear nowait
#tty [12345] /dev/ttyUSB0 noclear tty [12345] /dev/ttyUSB0 noclear
# Just give me a shell, I need to debug this embedded system! # Just give me a shell, I need to debug this embedded system!
#tty [12345] console noclear nologin tty [12345] @console noclear nologin
``` ```
The `service` stanza, as well as `task`, `run` and others are described The `service` stanza, as well as `task`, `run` and others are described
@@ -151,10 +102,10 @@ some of the most common components needed to start a UNIX daemon:
``` ```
service [LVLS] <COND> log env:[-]/etc/default/daemon daemon ARGS -- Daemon daemon service [LVLS] <COND> log env:[-]/etc/default/daemon daemon ARGS -- Daemon daemon
^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
| | | | | | | `---------- Optional description | | | | | | | `-- Optional description
| | | | | | `------------------ Daemon arguments | | | | | | `----------- Daemon arguments
| | | | | `------------------------- Path to daemon | | | | | `-------------------------- Path to daemon
| | | | `---------------------------------------------------- Optional env. file | | | | `---------------------------------------------------- Optional env. file
| | | `-------------------------------------------------------- Redirect output to log | | | `-------------------------------------------------------- Redirect output to log
| | `--------------------------------------------------------------- Optional conditions | | `--------------------------------------------------------------- Optional conditions
@@ -166,13 +117,13 @@ Some components are optional: runlevel(s), condition(s) and description,
making it easy to create simple start scripts and still possible for more making it easy to create simple start scripts and still possible for more
advanced uses as well: advanced uses as well:
service /usr/sbin/sshd -D service sshd -D
Dependencies are handled using [conditions](doc/conditions.md). One of Dependencies are handled using [conditions](doc/conditions.md). One of
the most common conditions is to wait for basic networking to become the most common conditions is to wait for basic networking to become
available: available:
service <net/route/default> nginx -- High performance HTTP server service <net/route/default> nginx -- High performace HTTP server
Here is another example where we instruct Finit to not start BusyBox Here is another example where we instruct Finit to not start BusyBox
`ntpd` until `syslogd` has started properly. Finit waits for `syslogd` `ntpd` until `syslogd` has started properly. Finit waits for `syslogd`
@@ -247,49 +198,11 @@ networking here. The configured `runlevel NUM` from `/etc/finit.conf`
is what Finit changes to after bootstrap, unless 'single' (or 'S') is is what Finit changes to after bootstrap, unless 'single' (or 'S') is
given on the kernel cmdline, in which case runlevel 1 is started. given on the kernel cmdline, in which case runlevel 1 is started.
All services in runlevel S) are started first, followed by the desired All services in runlevel S(0) are started first, followed by the desired
run-time runlevel. Run tasks in runlevel S can be started in sequence run-time runlevel. Run tasks in runlevel S can be started in sequence
by using `run [S] cmd`. Changing runlevels at runtime is done like any by using `run [S] cmd`. Changing runlevels at runtime is done like any
other init, e.g. <kbd>init 4</kbd>, but also using the more advanced other init, e.g. <kbd>init 4</kbd>, but also using the more advanced
[`initctl`](#commands--status) tool. `intictl` tool.
**Conditions**
As mentioned previously, Finit has an advanced dependency system to
handle synchronization, called [conditions](doc/conditions.md). It can
be used in many ways; depend on another service, network availability,
etc.
One *really cool* example useful for embedded systems is to run certain
scripts if a board has a certain feature encoded in its device tree. At
bootstrap we run the following `ident` script:
```sh
#!/bin/sh
conddir=/var/run/finit/cond/hw/model
dtmodel=/sys/firmware/devicetree/base/model
if ! test -e $dtmodel; then
exit 0
fi
model=$(cat $dtmodel | tr "[A-Z] " "[a-z]-")
mkdir -p $conddir && ln -s ../../reconf $conddir/$model
```
Provided the device tree node exists, and is a string, we can then use
the condition `<hw/model/foo>` when starting other scripts. Here is an
example:
```
run [S] /path/to/ident --
task [2] <hw/model/foo> /path/to/foo-init -- Initializing Foo board
```
> [!TIP]
> Notice the trick with an empty description to hide the call to `ident`
> in the Finit progress output.
**Plugins** **Plugins**
@@ -319,11 +232,8 @@ For more information, see [doc/plugins.md](doc/plugins.md).
By default, Finit monitors `/etc/finit.d/` and `/etc/finit.d/enabled/` By default, Finit monitors `/etc/finit.d/` and `/etc/finit.d/enabled/`
registering any changes to `.conf` files. To activate a change the user registering any changes to `.conf` files. To activate a change the user
must call `initctl reload`, which reloads all modified files, stops any must call `initctl reload`, which reloads all modified files, stops any
removed services, starts new ones, and restarts any modified ones. If the removed services, starts new ones, and restarts any modified ones, with
command line arguments of a service have changed, the process will be SIGHUP if the process supports it.
terminated and then started again with the updated arguments. If the arguments
have not been modified and the process supports SIGHUP, the process will
receive a SIGHUP rather than being terminated and started.
For some use-cases the extra step of calling `initctl reload` creates an For some use-cases the extra step of calling `initctl reload` creates an
unnecessary overhead, which can be removed at build-time using: unnecessary overhead, which can be removed at build-time using:
@@ -331,51 +241,6 @@ unnecessary overhead, which can be removed at build-time using:
configure --enable-auto-reload configure --enable-auto-reload
**Cgroups**
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
|-- system/ # cpu.weight:9800
`-- user/ # cpu.weight:100
Finit itself and its helper scripts and services are placed in the
top-level leaf-node group `init/`, which also is _reserved_.
All run/task/service/sysv processes are placed in their own sub-group
in `system/`. The name of each sub-group is taken from the respective
`.conf` file from `/etc/finit.d`.
All getty/tty processes are placed in their own sub-group in `user/`.
The name of each sub-group is taken from the username.
A fourth group also exists, the `root` group. It is also _reserved_ and
primarily intended for RT tasks. If you have RT tasks they need to be
declared as such in their service stanza like this:
service [...] <...> cgroup.root /path/to/foo args -- description
or
cgroup.root
service [...] <...> /path/to/foo args -- description
service [...] <...> /path/to/bar args -- description
See [doc/config.md](doc/config.md#cgroups) for more information, e.g.,
how to configure per-group limits.
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 Runparts & /etc/rc.local
------------------------ ------------------------
@@ -395,33 +260,8 @@ Right after the runlevel change when all services have started properly,
No configuration stanza in `/etc/finit.conf` is required for `rc.local`. No configuration stanza in `/etc/finit.conf` is required for `rc.local`.
If it exists and is an executable shell script Finit calls it at the very If it exists and is an executable shell script Finit calls it at the very
end of the boot, before calling the `HOOK_SYSTEM_UP`. See more on hooks end of the boot, before calling the `HOOK_SYSTEM_UP`. See more on hooks
in [doc/plugins.md](doc/plugins.md#hooks). in [doc/plugins.md](doc/plugins.md#hooks), and about the system bootstrap
in [doc/bootstrap.md](doc/bootstrap.md).
### Limitations
It is not possible to call Finit via signals or use `initctl` in any
runparts or `/etc/rc.local` script. This because Finit is single
threaded and is calling these scripts in a blocking fashion at the end
of runlevel S, at which point the event loop has not yet been started.
The event loop is the whole thing which Finit is built around, except
for runlevel S, which remains a slow procession through a lot of set up,
with a few hooks and blocking call outs to external scripts.
However, not all `initctl` commands are prohibited. Supported commands:
- `inictl cond`: only operate of files in `/run/finit/cond`
- `initctl enable/disable`: enabled run/task/service is activated on
the runlevel change from S to 2
- `initctl touch/show/create/delete/list`: `create`, provided the
non-interactive mode is used, again changes take effect in the
runlevel change directly after bootstrap
- `initctl -f reboot/poweroff/halt`: provided the `-f` flag is used to
force direct kernel commands
**Example:** you can set a `usr/` condition in `/etc/rc.local` and have
a service/task in runlevel 2 depend on it to execute.
Runlevels Runlevels
@@ -508,67 +348,40 @@ Finit also implements a modern API to query status, and start/stop
services, called `initctl`. Unlike `telinit` the `initctl` tool does services, called `initctl`. Unlike `telinit` the `initctl` tool does
not return until the given command has fully completed. not return until the given command has fully completed.
``` ```shell
~ $ initctl -h
Usage: initctl [OPTIONS] [COMMAND] Usage: initctl [OPTIONS] [COMMAND]
Options: 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
-j, --json JSON output in 'status' and 'cond' commands
-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, --verbose Verbose output
-V, --version Show program version -h, --help This help text
Commands: Commands:
debug Toggle Finit (daemon) debug debug Toggle Finit (daemon) debug
help This help text help This help text
version Show program version version Show Finit version
ls | list List all .conf in /etc/finit.d list List all .conf in /etc/finit.d/
create <CONF> Create .conf in /etc/finit.d/available enable <CONF> Enable .conf in /etc/finit.d/available/
delete <CONF> Delete .conf in /etc/finit.d/available disable <CONF> Disable .conf in /etc/finit.d/[enabled/]
show <CONF> Show .conf in /etc/finit.d/available touch <CONF> Mark .conf in /etc/finit.d/ for reload
edit <CONF> Edit .conf in /etc/finit.d/available reload Reload *.conf in /etc/finit.d/ (activates changes)
touch <CONF> Change .conf in /etc/finit.d/available
enable <CONF> Enable .conf in /etc/finit.d/available cond show Show condition status
disable <CONF> Disable .conf in /etc/finit.d/enabled cond dump Dump all conditions and their status
reload Reload *.conf in /etc/finit.d (activate changes)
cond set <COND> Set (assert) user-defined conditions +usr/COND
cond get <COND> Get status of user-defined condition, see $? and -v
cond clear <COND> Clear (deassert) user-defined conditions -usr/COND
cond status Show condition status, default cond command
cond dump [TYPE] Dump all, or a type of, conditions and their status
log [NAME] Show ten last Finit, or NAME, messages from syslog log [NAME] Show ten last Finit, or NAME, messages from syslog
start <NAME>[:ID] Start service by name, with optional ID start <JOB|NAME>[:ID] Start service by job# or name, with optional ID
stop <NAME>[:ID] Stop/Pause a running service by name stop <JOB|NAME>[:ID] Stop/Pause a running service by job# or name
reload <NAME>[:ID] Reload service as if .conf changed (SIGHUP or restart) restart <JOB|NAME>[:ID] Restart (stop/start) service by job# or name
This allows restart of run/tasks that have already run status <JOB|NAME>[:ID] Show service status, by job# or name
Note: Finit .conf file(s) are *not* reloaded! status | show Show status of services, default command
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
cgroup List cgroup config overview
ps List processes based on cgroups
top Show top-like listing based on cgroups
plugins List installed plugins
runlevel [0-9] Show or set runlevel: 0 halt, 6 reboot runlevel [0-9] Show or set runlevel: 0 halt, 6 reboot
reboot Reboot system reboot Reboot system
halt Halt system halt Halt system
poweroff Halt and power off system poweroff Halt and power off system
suspend Suspend system
utmp show Raw dump of UTMP/WTMP db utmp show Raw dump of UTMP/WTMP db
``` ```
@@ -577,74 +390,22 @@ file must be used to tell Finit to stop and start it on `reload` and
`runlevel` changes. If `<>` holds more [conditions](doc/conditions.md), `runlevel` changes. If `<>` holds more [conditions](doc/conditions.md),
these will also affect how a service is maintained. these will also affect how a service is maintained.
> [!NOTE] **Note:** even though it is possible to start services not belonging in
> Even though it is possible to start services not belonging in the the current runlevel these services will not be respawned automatically
> current runlevel these services will not be respawned automatically by by Finit if they exit (crash). Hence, if the runlevel is 2, the below
> Finit if they exit (crash). Hence, if the runlevel is 2, the below Dropbear SSH service will not be restarted if it is killed or exits.
> Dropbear SSH service will not be restarted if it is killed or exits.
The `status` command is the default, it displays a quick overview of all ```shell
monitored run/task/services. Here we call `initctl -p`, suitable for ~ $ initctl status -v
scripting and documentation: 1 running 476 [S12345] /sbin/watchdog -T 16 -t 2 -F /dev/watchdog
2 running 477 [S12345] /sbin/syslogd -n -b 3 -D
``` 3 running 478 [S12345] /sbin/klogd -n
alpine:~# initctl -p 4:1 inetd 0 [2345] internal time allow *:37,!eth0
PID IDENT STATUS RUNLEVELS DESCRIPTION 4:2 inetd 0 [2345] internal time allow eth0:3737
====================================================================== 5:1 inetd 0 [2345] /sbin/telnetd allow *:23 deny eth0,eth1
1506 acpid running [---2345----] ACPI daemon 5:2 inetd 0 [2345] /sbin/telnetd allow eth0:2323,eth2:2323,eth1:2323
1509 crond running [---2345----] Cron daemon 6:1 inetd 0 [345] /sbin/dropbear allow eth0:222
1489 dropbear running [---2345----] Dropbear SSH daemon 6:2 inetd 0 [345] /sbin/dropbear allow *:22 deny eth0
1511 klogd running [S-12345----] Kernel log daemon
1512 ntpd running [---2345----] NTP daemon
1473 syslogd running [S-12345----] Syslog daemon
alpine:~# initctl -pv
PID IDENT STATUS RUNLEVELS COMMAND
======================================================================
1506 acpid running [---2345----] acpid -f
1509 crond running [---2345----] crond -f -S $CRON_OPTS
1489 dropbear running [---2345----] dropbear -R -F $DROPBEAR_OPTS
1511 klogd running [S-12345----] klogd -n $KLOGD_OPTS
1512 ntpd running [---2345----] ntpd -n $NTPD_OPTS
1473 syslogd running [S-12345----] syslogd -n
```
The environment variables to each of the services above are read from,
in the case of Alpine Linux, `/etc/conf.d/`. Other distributions may
have other directories, e.g., Debian use `/etc/default/`.
The `status` command takes an optional `NAME:ID` argument. Here we
check the status of `dropbear`, which only has one instance in this
system:
```
alpine:~# initctl -p status dropbear
Status : running
Identity : dropbear
Description : Dropbear SSH daemon
Origin : /etc/finit.d/enabled/dropbear.conf
Environment : -/etc/conf.d/dropbear
Condition(s):
Command : dropbear -R -F $DROPBEAR_OPTS
PID file : !/run/dropbear.pid
PID : 1485
User : root
Group : root
Uptime : 2 hour 46 min 56 sec
Runlevels : [---2345----]
Memory : 1.2M
CGroup : /system/dropbear cpu 0 [100, max] mem [--.--, max]
|- 1485 dropbear -R -F
|- 2634 dropbear -R -F
|- 2635 ash
`- 2652 initctl -p status dropbear
Apr 8 12:19:49 alpine authpriv.info dropbear[1485]: Not backgrounding
Apr 8 12:37:45 alpine authpriv.info dropbear[2300]: Child connection from 192.168.121.1:47834
Apr 8 12:37:46 alpine authpriv.notice dropbear[2300]: Password auth succeeded for 'root' from 192.168.121.1:47834
Apr 8 12:37:46 alpine authpriv.info dropbear[2300]: Exit (root) from <192.168.121.1:47834>: Disconnect received
Apr 8 15:02:11 alpine authpriv.info dropbear[2634]: Child connection from 192.168.121.1:48576
Apr 8 15:02:12 alpine authpriv.notice dropbear[2634]: Password auth succeeded for 'root' from 192.168.121.1:48576
``` ```
@@ -682,43 +443,36 @@ This project is based on the [original finit][] by [Claudio Matsuoka][]
which was reverse engineered from syscalls of the [EeePC fastinit][] — which was reverse engineered from syscalls of the [EeePC fastinit][] —
"gaps filled with frog DNA …" "gaps filled with frog DNA …"
Finit is developed and maintained by [Joachim Wiberg][] at [GitHub][6]. Finit is developed and maintained by [Joachim Wiberg][] at [GitHub][].
Please file bug reports, clone it, or send pull requests for bug fixes Please file bug reports, clone it, or send pull requests for bug fixes
and proposed extensions. and proposed extensions.
[1]: https://en.wikipedia.org/wiki/Process_supervision [1]: https://en.wikipedia.org/wiki/Process_supervision
[2]: https://cr.yp.to/daemontools.html [2]: http://cr.yp.to/daemontools.html
[3]: https://smarden.org/runit/ [3]: http://smarden.org/runit/
[4]: https://en.wikipedia.org/wiki/Init [4]: http://en.wikipedia.org/wiki/Init
[5]: https://en.wikipedia.org/wiki/Runlevel [5]: http://en.wikipedia.org/wiki/Runlevel
[6]: https://github.com/troglobit/finit [6]: https://www.freedesktop.org/wiki/Software/systemd/
[9]: https://github.com/troglobit/troglos
[RFC862]: https://tools.ietf.org/html/rfc862 [RFC862]: https://tools.ietf.org/html/rfc862
[RFC863]: https://tools.ietf.org/html/rfc863 [RFC863]: https://tools.ietf.org/html/rfc863
[RFC864]: https://tools.ietf.org/html/rfc864 [RFC864]: https://tools.ietf.org/html/rfc864
[RFC867]: https://tools.ietf.org/html/rfc867 [RFC867]: https://tools.ietf.org/html/rfc867
[RFC868]: https://tools.ietf.org/html/rfc868 [RFC868]: https://tools.ietf.org/html/rfc868
[init]: https://en.wikipedia.org/wiki/Init [init]: http://en.wikipedia.org/wiki/Init
[upstart]: https://upstart.ubuntu.com/ [upstart]: http://upstart.ubuntu.com/
[systemd]: https://www.freedesktop.org/wiki/Software/systemd/ [systemd]: http://www.freedesktop.org/wiki/Software/systemd/
[openrc]: https://www.gentoo.org/proj/en/base/openrc/ [openrc]: http://www.gentoo.org/proj/en/base/openrc/
[sd_notify()]: https://www.freedesktop.org/software/systemd/man/sd_notify.html [run-parts(8)]: http://manpages.debian.org/cgi-bin/man.cgi?query=run-parts
[s6 style]: https://skarnet.org/software/s6/notifywhenup.html
[run-parts(8)]: https://manpages.debian.org/cgi-bin/man.cgi?query=run-parts
[tmpfiles.d(5)]: https://www.freedesktop.org/software/systemd/man/tmpfiles.d.html
[original finit]: http://helllabs.org/finit/ [original finit]: http://helllabs.org/finit/
[EeePC fastinit]: https://web.archive.org/web/20071208212450/http://wiki.eeeuser.com/boot_process:the_boot_process [EeePC fastinit]: https://web.archive.org/web/20071208212450/http://wiki.eeeuser.com/boot_process:the_boot_process
[Claudio Matsuoka]: https://github.com/cmatsuoka [Claudio Matsuoka]: https://github.com/cmatsuoka
[Joachim Wiberg]: https://troglobit.com [Joachim Wiberg]: http://troglobit.com
[Buildroot]: https://buildroot.org [GitHub]: https://github.com/troglobit/finit
[Infix]: https://kernelkit.github.io
[finit.conf(5)]: https://man.troglobit.com/man5/finit.conf.5.html
[License]: https://en.wikipedia.org/wiki/MIT_License [License]: https://en.wikipedia.org/wiki/MIT_License
[License Badge]: https://img.shields.io/badge/License-MIT-teal.svg [License Badge]: https://img.shields.io/badge/License-MIT-teal.svg
[myLinux]: https://github.com/troglobit/myLinux/ [Travis]: https://travis-ci.org/troglobit/finit
[watchdogd]: https://github.com/troglobit/watchdogd/ [Travis Status]: https://travis-ci.org/troglobit/finit.png?branch=master
[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 [Coverity Scan]: https://scan.coverity.com/projects/3545
[Coverity Status]: https://scan.coverity.com/projects/3545/badge.svg [Coverity Status]: https://scan.coverity.com/projects/3545/badge.svg
-33
View File
@@ -1,33 +0,0 @@
#!/bin/sh
# Run test suite with the correct configure params
run_make=1
jobs=17
while [ $# -gt 0 ]; do
case "$1" in
-n|--no-make)
run_make=0
;;
-j|--jobs)
shift
jobs="$1"
;;
*)
echo "Usage: $0 [--no-make] [-j N]"
exit 1
;;
esac
shift
done
if [ "$run_make" -eq 1 ]; then
make distclean
fi
./configure --prefix=/usr --exec-prefix= --sysconfdir=/etc --localstatedir=/var \
--enable-x11-common-plugin --with-watchdog --with-keventd \
CFLAGS='-fsanitize=address -ggdb'
if [ "$run_make" -eq 1 ]; then
make -j"$jobs" clean check
fi
+67 -234
View File
@@ -1,25 +1,20 @@
AC_INIT([Finit], [4.13-pre], [https://github.com/troglobit/finit/issues], AC_INIT(Finit, 4.0-rc1, https://github.com/troglobit/finit/issues, finit, https://troglobit.com/finit.html)
[finit], [https://troglobit.com/projects/finit/])
AC_CONFIG_AUX_DIR(aux) AC_CONFIG_AUX_DIR(aux)
AM_INIT_AUTOMAKE([1.11 foreign dist-xz subdir-objects]) AM_INIT_AUTOMAKE([1.11 foreign dist-xz subdir-objects])
AM_SILENT_RULES([yes]) AM_SILENT_RULES([yes])
AC_CONFIG_SRCDIR([src/finit.c]) AC_CONFIG_SRCDIR([src/finit.c])
AC_CONFIG_HEADERS([config.h]) AC_CONFIG_HEADER([config.h])
AC_CONFIG_FILES([Makefile AC_CONFIG_FILES([Makefile
contrib/Makefile contrib/Makefile
contrib/alpine/Makefile contrib/alpine/finit.d/Makefile contrib/alpine/finit.d/available/Makefile contrib/alpine/Makefile contrib/alpine/finit.d/Makefile contrib/alpine/finit.d/available/Makefile
contrib/debian/Makefile contrib/debian/finit.d/Makefile contrib/debian/finit.d/available/Makefile contrib/debian/Makefile contrib/debian/finit.d/Makefile contrib/debian/finit.d/available/Makefile contrib/debian/grub.d/Makefile
contrib/void/Makefile contrib/void/finit.d/Makefile contrib/void/finit.d/available/Makefile contrib/void/Makefile contrib/void/finit.d/Makefile contrib/void/finit.d/available/Makefile
doc/Makefile doc/Makefile
libsystemd/Makefile libsystemd/libsystemd.pc
man/Makefile
plugins/Makefile plugins/Makefile
src/Makefile src/Makefile
system/Makefile system/10-hotplug.conf test/test.env
test/test.env test/Makefile test/Makefile])
test/lib/Makefile test/src/Makefile
tmpfiles.d/Makefile])
# Older versions of autoconf (<2.58) do not have AC_CONFIG_MACRO_DIR() # Older versions of autoconf (<2.58) do not have AC_CONFIG_MACRO_DIR()
#m4_include([m4/plugin.m4]) #m4_include([m4/plugin.m4])
@@ -36,8 +31,9 @@ AC_PROG_INSTALL
AC_PROG_MKDIR_P AC_PROG_MKDIR_P
# Configuration. # Configuration.
AC_CHECK_HEADERS([termios.h sys/ioctl.h mntent.h sys/sysmacros.h]) AC_HEADER_STDC
AC_CHECK_FUNCS([strstr getopt getmntent getmntent_r]) AC_CHECK_HEADERS([fstaby.h termios.h])
AC_CHECK_FUNCS([strstr getopt getfsenty])
# Check for uint[8,16,32]_t # Check for uint[8,16,32]_t
AC_TYPE_UINT8_T AC_TYPE_UINT8_T
@@ -52,36 +48,33 @@ PKG_CHECK_MODULES([uev], [libuev >= 2.2.0])
PKG_CHECK_MODULES([lite], [libite >= 2.2.0]) PKG_CHECK_MODULES([lite], [libite >= 2.2.0])
# Check for configured Finit features # Check for configured Finit features
AC_ARG_ENABLE(emergency_shell,
AS_HELP_STRING([--enable-emergency-shell], [Experimental emergency fallback at boot.
Use only for debugging very early boot problems with Finit]),,[
enable_emergency_shell=no])
AC_ARG_ENABLE(fallback_shell,
AS_HELP_STRING([--enable-fallback-shell], [Start a shell if no TTYs can start]),,[
enable_fallback_shell=no])
AC_ARG_ENABLE(auto_reload, AC_ARG_ENABLE(auto_reload,
AS_HELP_STRING([--enable-auto-reload], [Automatic reload on any .conf change]),,[ AS_HELP_STRING([--enable-auto-reload], [Automatic reload on any .conf change]),,[
enable_auto_reload=no]) enable_auto_reload=no])
AC_ARG_ENABLE(kernel_cmdline, AC_ARG_ENABLE(watchdog,
AS_HELP_STRING([--enable-kernel-cmdline], [Parse init args from /proc/cmdline (don't use!)]),,[ AS_HELP_STRING([--enable-watchdog], [Enable built-in watchdog, uses /dev/watchdog]),,[
enable_kernel_cmdline=no]) enable_watchdog=no])
AC_ARG_ENABLE(fastboot,
AS_HELP_STRING([--enable-fastboot], [Skip fsck check on filesystems listed in /etc/fstab]),,[
enable_fastboot=no])
AC_ARG_ENABLE(fsckfix,
AS_HELP_STRING([--enable-fsckfix], [Run fsck fix mode (options: -yf) on filesystems listed in /etc/fstab]),,[
enable_fsckfix=no])
AC_ARG_ENABLE(cgroup,
AS_HELP_STRING([--disable-cgroup], [Disable cgroup v2 support, default: autodetect from /sys/fs/cgroup]),,[
enable_cgroup=yes])
AC_ARG_ENABLE(redirect, AC_ARG_ENABLE(redirect,
AS_HELP_STRING([--disable-redirect], [Disable redirection of service output to /dev/null]),,[ AS_HELP_STRING([--enable-redirect], [Redirect service output to /dev/null, default: no]),,[
enable_redirect=yes]) enable_redirect_output=no])
AC_ARG_ENABLE(kernel_logging, AC_ARG_ENABLE(logit,
AS_HELP_STRING([--disable-kernel-logging], [Disable kernel logging to console (use 'quiet' instead!]),,[ AS_HELP_STRING([--disable-logit], [Disable logit, used for log redirection, default: enable]),,[
enable_kernel_logging=yes]) enable_logit=yes])
AC_ARG_ENABLE(logrotate, AC_ARG_ENABLE(logrotate,
AS_HELP_STRING([--disable-logrotate], [Disable built-in rotation of /var/log/wtmp]),,[ AS_HELP_STRING([--disable-logrotate], [Disable built-in rotation of /var/log/wtmp, default enabled]),,[
enable_logrotate=yes]) enable_logrotate=yes])
AC_ARG_ENABLE(doc, AC_ARG_ENABLE(doc,
@@ -92,39 +85,19 @@ AC_ARG_ENABLE(contrib,
AS_HELP_STRING([--disable-contrib], [Disable build and install of contrib section]),,[ AS_HELP_STRING([--disable-contrib], [Disable build and install of contrib section]),,[
enable_contrib=yes]) enable_contrib=yes])
AC_ARG_ENABLE([rescue],
AS_HELP_STRING([--disable-rescue], [Disable potentially unsafe rescue mode]),,
[enable_rescue=yes])
# Check for extra plugins to enable # Check for extra plugins to enable
AC_ARG_ENABLE(all_plugins, enable_all_plugins=auto
AS_HELP_STRING([--enable-all-plugins], [Enable all plugins, default: auto]),
enable_all_plugins=$enableval, enable_all_plugins=auto)
AC_PLUGIN([alsa-utils], [no], [Save and restore ALSA sound settings using alsactl]) AC_PLUGIN([alsa-utils], [no], [Save and restore ALSA sound settings using alsactl])
AC_PLUGIN([dbus], [no], [Setup and start system message bus, D-Bus]) AC_PLUGIN([dbus], [no], [Setup and start system message bus, D-Bus])
AC_PLUGIN([modules-load], [no], [Scans /etc/modules-load.d for modules to load]) AC_PLUGIN([modules-load], [no], [Scans /etc/modules-load.d for modules to load])
AC_PLUGIN([modprobe], [no], [Coldplug modules using modalias magic])
AC_PLUGIN([resolvconf], [no], [Setup necessary files for resolvconf]) AC_PLUGIN([resolvconf], [no], [Setup necessary files for resolvconf])
AC_PLUGIN([x11-common], [no], [Console setup (for X)]) 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([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([hotplug], [yes], [Start udevd or mdev kernel event datamon])
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])
AC_PLUGIN([testserv], [no], [Test plugin to start test serv daemon])
# Check for extra arguments or packages # Check for extra arguments or packages
AC_ARG_WITH([bash-completion-dir],
AS_HELP_STRING([--with-bash-completion-dir[=PATH]], [Directory to install Bash completion, default: auto]),
[bash_dir=$withval], [bash_dir=yes])
AC_ARG_WITH(fstab,
AS_HELP_STRING([--with-fstab=FILE], [System default fstab, default $sysconfdir/fstab]),
[fstab=$withval], [fstab=yes])
AC_ARG_WITH(heading, 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"]), AS_HELP_STRING([--with-heading=GREET], [Display GREET instead of Finit version at boot]),
[heading=$withval], [heading=yes]) [heading=$withval], [heading=yes])
AC_ARG_WITH(config, AC_ARG_WITH(config,
@@ -143,98 +116,44 @@ AC_ARG_WITH(sysconfig,
AS_HELP_STRING([--with-sysconfig=DIR], [System environment directory, sourced by .conf files, default /etc/default & /etc/conf.d]), AS_HELP_STRING([--with-sysconfig=DIR], [System environment directory, sourced by .conf files, default /etc/default & /etc/conf.d]),
[sysconfig=$withval], [sysconfig=default]) [sysconfig=$withval], [sysconfig=default])
AC_ARG_WITH(group,
AS_HELP_STRING([--with-group=NAME], [Group for /run/finit/socket (initctl), default: root]),
[group=$withval], [group=root])
AC_ARG_WITH(hostname, AC_ARG_WITH(hostname,
AS_HELP_STRING([--with-hostname=NAME], [If /etc/hostname is missing, default: noname]), AS_HELP_STRING([--with-hostname=NAME], [If /etc/hostname is missing, default: noname]),
[hostname=$withval], [hostname=yes]) [hostname=$withval], [hostname=yes])
AC_ARG_WITH(runlevel, 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]) [runlevel=$withval], [runlevel=yes])
AC_ARG_WITH(random-seed, AC_ARG_WITH(random-seed,
AS_HELP_STRING([--with-random-seed=FILE], [Save a random seed for /dev/urandom across reboots, default /var/lib/misc/random-seed]), AS_HELP_STRING([--with-random-seed=FILE], [Save a random seed for /dev/urandom across reboots, default /var/lib/misc/random-seed]),
[random_seed=$withval], [random_seed=yes]) [random_seed=$withval], [random_seed=yes])
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@<:@=USER@:>@], [Enable built-in sulogin, optional USER to request password for (default root), default: no.]),[sulogin=$withval],[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(libsystemd,
AS_HELP_STRING([--with-libsystemd], [Build replacement libsystemd library, default: yes]),
[with_libsystemd=$withval], [with_libsystemd=yes])
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])
AC_ARG_WITH(rtc-date,
AS_HELP_STRING([--with-rtc-date=DATE], [If RTC date/time is too old, restore to DATE, format "YYYY-MM-DD HH:MM:SS", default "2000-01-01 00:00:00"]),
[rtc_date=$withval], [rtc_date=no])
AC_ARG_WITH(rtc-file,
AS_HELP_STRING([--with-rtc-file=FILE], [If RTC is missing, save and restore system clock from this file, default: no]),
[rtc_file=$withval], [rtc_file=no])
### Enable features ########################################################################### ### Enable features ###########################################################################
# Create config.h from selected features and fallback defaults # Create config.h from selected features and fallback defautls
AS_IF([test "x$enable_emergency_shell" = "xyes"], [
AC_DEFINE(EMERGENCY_SHELL, 1, [Fork off init and let PID 1 wait and start /bin/sh if init crashes.])])
AS_IF([test "x$enable_fallback_shell" = "xyes"], [
AC_DEFINE(FALLBACK_SHELL, 1, [Start /bin/sh on console if no TTYs.])])
AS_IF([test "x$enable_auto_reload" = "xyes"], [ AS_IF([test "x$enable_auto_reload" = "xyes"], [
AC_DEFINE(AUTO_RELOAD, 1, [Finit automatically does `initctl reload` on any .conf change])]) AC_DEFINE(AUTO_RELOAD, 1, [Finit automatically does `initctl reload` on any .conf change])])
AS_IF([test "x$enable_kernel_cmdline" = "xyes"], [ AS_IF([test "x$enable_watchdog" = "xyes"], [
AC_DEFINE(KERNEL_CMDLINE, 1, [Dumpster diving after init args from /proc/cmdline])]) AC_DEFINE(BUILTIN_WATCHDOG, 1, [Enable built-in watchdog, kicks on /dev/watchdog])])
AS_IF([test "x$enable_kernel_logging" = "xyes"], [
AC_DEFINE(KERNEL_LOGGING, 1, [Keep kernel warn/err logs to console])])
AS_IF([test "x$enable_cgroup" = "xyes"], [
AC_DEFINE(CGROUP2_ENABLED, 1, [Autodetect cgroup v2 support from /sys/fs/cgroup])])
AS_IF([test "x$enable_fastboot" = "xyes"], [
AC_DEFINE(FAST_BOOT, 1, [Skip fsck check on filesystems listed in /etc/fstab])])
AS_IF([test "x$enable_fsckfix" = "xyes"], [
AC_DEFINE(FSCK_FIX, 1, [Run fsck fix mode (options: -yf) on filesystems listed in /etc/fstab])])
AS_IF([test "x$enable_redirect" = "xyes"], [ AS_IF([test "x$enable_redirect" = "xyes"], [
AC_DEFINE(REDIRECT_OUTPUT, 1, [Enable redirection of service output to /dev/null])]) AC_DEFINE(REDIRECT_OUTPUT, 1, [Enable redirection of service output to /dev/null])])
### Disable features ########################################################################### ### Disable features ###########################################################################
AS_IF([test "x$enable_logit" != "xno"], [
AC_DEFINE(LOGIT_ENABLED, 1, [Enable logit tool, used for log redirection by Finit])])
AS_IF([test "x$enable_logrotate" != "xno"], [ AS_IF([test "x$enable_logrotate" != "xno"], [
AC_DEFINE(LOGROTATE_ENABLED, 1, [Enable built-in rotation of /var/log/wtmp et al.])]) AC_DEFINE(LOGROTATE_ENABLED, 1, [Enable built-in rotation of /var/log/wtmp et al.])])
AS_IF([test "x$enable_rescue" != "xno"], [
AC_DEFINE([RESCUE_MODE], 1, [Define to enable support for rescue mode.])])
AM_CONDITIONAL(LOGROTATE, [test "x$enable_logrotate" = "xyes"])
### With features ############################################################################## ### With features ##############################################################################
AS_IF([test "x$bash_dir" = "xyes"], [
PKG_CHECK_MODULES([BASH_COMPLETION], [bash-completion >= 2.0],
[BASH_DIR="$(pkg-config --variable=completionsdir bash-completion)"],
[BASH_DIR="$datadir/bash-completion/completions"])], [
BASH_DIR="$bash_dir"])
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$with_config" != "xno"], [
AS_IF([test "x$conf" = "xyes"], [ AS_IF([test "x$conf" = "xyes"], [
conf=$sysconfdir/finit.conf])]) conf=$sysconfdir/finit.conf])])
@@ -250,9 +169,10 @@ AC_DEFINE_UNQUOTED(FINIT_RCSD, "$rcsd_path", [Finit rcS.d/, default /etc/finit.d
AC_SUBST(FINIT_RCSD, "$rcsd_path") AC_SUBST(FINIT_RCSD, "$rcsd_path")
AS_IF([test "x$with_rc_local" != "xno"], [ AS_IF([test "x$with_rc_local" != "xno"], [
AS_IF([test "x$rclocal" = "xyes"], [rclocal=$sysconfdir/rc.local]) AS_IF([test "x$rclocal" = "xyes"], [
AC_EXPAND_DIR(rclocal_path, "$rclocal") rclocal=$sysconfdir/rc.local])])
AC_DEFINE_UNQUOTED(FINIT_RC_LOCAL, "$rclocal_path", [Compat SysV /etc/rc.local file to run last at boot.])]) AC_EXPAND_DIR(rclocal_path, "$rclocal")
AC_DEFINE_UNQUOTED(FINIT_RC_LOCAL, "$rclocal_path", [Compat SysV /etc/rc.local file to run last at boot.])
AS_IF([test "x$with_sysconfig" != "xno"], [ AS_IF([test "x$with_sysconfig" != "xno"], [
AS_IF([test "x$sysconfig" != "xdefault"], [ AS_IF([test "x$sysconfig" != "xdefault"], [
@@ -261,13 +181,9 @@ AS_IF([test "x$with_sysconfig" != "xno"], [
[System environment, default /etc/default & /etc/conf.d])])]) [System environment, default /etc/default & /etc/conf.d])])])
AS_IF([test "x$with_heading" != "xno"], [ AS_IF([test "x$with_heading" != "xno"], [
AS_IF([test "x$heading" = "xyes"], [heading=""]) AS_IF([test "x$heading" = "xyes"], [
AC_DEFINE_UNQUOTED(INIT_OSHEADING, "$heading", [Displayed by Finit at boot, defaults to /etc/os-release PRETTY_NAME])]) heading="$PACKAGE_NAME v$PACKAGE_VERSION"])])
AC_DEFINE_UNQUOTED(INIT_HEADING, "$heading", [Displayed by Finit at boot])
AS_IF([test "x$with_group" != "xno"], [
AS_IF([test "x$group" = "xyes"], [
group=root])])
AC_DEFINE_UNQUOTED(DEFGROUP, "$group", [For /run/finit/socket])
AS_IF([test "x$with_hostname" != "xno"], [ AS_IF([test "x$with_hostname" != "xno"], [
AS_IF([test "x$hostname" = "xyes"], [ AS_IF([test "x$hostname" = "xyes"], [
@@ -286,100 +202,30 @@ AS_IF([test "x$with_random_seed" != "xno"], [
AC_EXPAND_DIR(random_path, "$random_seed") AC_EXPAND_DIR(random_path, "$random_seed")
AC_DEFINE_UNQUOTED(RANDOMSEED, "$random_path", [Improve random at boot by seeding it with sth from before.])]) AC_DEFINE_UNQUOTED(RANDOMSEED, "$random_path", [Improve random at boot by seeding it with sth from before.])])
AS_IF([test "x$rtc_date" != "xno"], [
AC_DEFINE_UNQUOTED(RTC_TIMESTAMP_CUSTOM, "$rtc_date", [Custom RTC restore date, default: 2000-01-01 00:00])], [
rtc_date=""])
AS_IF([test "x$rtc_file" != "xno"], [
AS_IF([test "x$rtc_file" = "xyes"], [
rtc_file=/var/lib/misc/rtc])
AC_EXPAND_DIR(rtcfile_path, "$rtc_file")
AC_DEFINE_UNQUOTED(RTC_FILE, "$rtcfile_path", [Save and restore system time from this file if /dev/rtc is missing.])],[
AC_DEFINE_UNQUOTED(RTC_FILE, NULL)])
AS_IF([test "x$with_keventd" != "xno"], [with_keventd=yes])
AS_IF([test "x$with_sulogin" != "xno"], [
AS_IF([test "x$sulogin" = "xyes"], [
sulogin=root])
with_sulogin=yes
AC_DEFINE_UNQUOTED(SULOGIN_USER, "$sulogin", [Built-in sulogin user, default: root])], [
sulogin=])
AS_IF([test "x$with_watchdog" != "xno"], [
AS_IF([test "x$watchdog" = "xyes"], [
watchdog=/dev/watchdog])
with_watchdog=yes
AC_DEFINE_UNQUOTED(WDT_DEVNODE, "$watchdog", [Built-in watchdog device node])], [
watchdog=])
AS_IF([test "x$with_libsystemd" != "xno"], [
AC_DEFINE(HAVE_LIBSYSTEMD, 1, [Build replacement libsystemd library support])])
AS_IF([test "x$enable_hook_scripts_plugin" != "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 # Control build with automake flags
AM_CONDITIONAL(BASH, [test "x$bash_dir" != "xno"]) AM_CONDITIONAL(STATIC, [test "x$enable_static" = "xyes"])
AM_CONDITIONAL(STATIC, [test "x$enable_static" = "xyes"]) AM_CONDITIONAL(WATCHDOGD, [test "x$enable_watchdog" = "xyes"])
AM_CONDITIONAL(KEVENTD, [test "x$with_keventd" != "xno"]) AM_CONDITIONAL(LOGIT, [test "x$enable_logit" = "xyes"])
AM_CONDITIONAL(SULOGIN, [test "x$with_sulogin" != "xno"]) AM_CONDITIONAL(DOC, [test "x$enable_doc" = "xyes"])
AM_CONDITIONAL(WATCHDOGD, [test "x$with_watchdog" != "xno"]) AM_CONDITIONAL(CONTRIB, [test "x$enable_contrib" = "xyes"])
AM_CONDITIONAL(LIBSYSTEMD, [test "x$with_libsystemd" != "xno"])
AM_CONDITIONAL(DOC, [test "x$enable_doc" = "xyes"])
AM_CONDITIONAL(CONTRIB, [test "x$enable_contrib" = "xyes"])
AM_CONDITIONAL(TESTSERV, [test "x$enable_testserv_plugin" = "xyes"])
# Workaround for as-of-yet unreleased runstatedir support, planned for
# autoconf 2.70, which some major distros have backported.
AS_IF([test -z "$runstatedir"], runstatedir="$localstatedir/run")
AC_SUBST(runstatedir)
# Override default libdir, used for plugins and rescue.conf # Override default libdir, used for plugins and rescue.conf
pkglibdir=$libdir/finit pkglibdir=$libdir/finit
AC_SUBST(pkglibexecdir) AC_SUBST(pkglibexecdir)
AC_EXPAND_DIR(pkglibexecdir, "$libexecdir/finit") AC_EXPAND_DIR(pkglibexecdir, "$libexecdir/finit")
AC_DEFINE_UNQUOTED(FINIT_EXECPATH_, "$pkglibexecdir", [Finit libexec path]) AC_DEFINE_UNQUOTED(FINIT_LIBPATH_, "$pkglibexecdir", [Finit libexec path])
AC_EXPAND_DIR(finit_runpath, "$runstatedir/finit/system")
AC_DEFINE_UNQUOTED(FINIT_RUNPATH_, "$finit_runpath", [Finit runtime dynamic system services])
AC_EXPAND_DIR(plugin_path, "$pkglibdir/plugins") AC_EXPAND_DIR(plugin_path, "$libdir/finit/plugins")
AC_SUBST(plugin_path) AC_SUBST(plugin_path)
AC_DEFINE_UNQUOTED(PLUGIN_PATH, "$plugin_path", [Finit plugin path]) AC_DEFINE_UNQUOTED(PLUGIN_PATH, "$plugin_path", [Finit plugin path])
AC_EXPAND_DIR(tmpfiles_path, "$libdir/tmpfiles.d") AC_EXPAND_DIR(rescue_conf, "$libdir/finit/rescue.conf")
AC_SUBST(tmpfiles_path)
AC_DEFINE_UNQUOTED(TMPFILES_PATH_, "$tmpfiles_path", [Main tmpfiles.d/, override in /etc])
AC_EXPAND_DIR(finit_tmpfiles, "$pkglibdir/tmpfiles.d")
AC_SUBST(finit_tmpfiles)
AC_DEFINE_UNQUOTED(FINIT_TMPFILES, "$finit_tmpfiles", [Finit tmpfiles.d/ .conf path])
AC_EXPAND_DIR(system_path, "$pkglibdir/system")
AC_SUBST(system_path)
AC_DEFINE_UNQUOTED(FINIT_SYSPATH_, "$system_path", [Static services, previously generated at runtime by plugins])
AC_EXPAND_DIR(rescue_conf, "$pkglibdir/rescue.conf")
AC_DEFINE_UNQUOTED(RESCUE_CONF, "$rescue_conf", [Finit rescue mode .conf]) AC_DEFINE_UNQUOTED(RESCUE_CONF, "$rescue_conf", [Finit rescue mode .conf])
AC_EXPAND_DIR(sample_conf, "$pkglibdir/sample.conf") AC_EXPAND_DIR(sample_conf, "$libdir/finit/sample.conf")
AC_DEFINE_UNQUOTED(SAMPLE_CONF, "$sample_conf", [Finit sameple.conf for initctl create]) AC_DEFINE_UNQUOTED(SAMPLE_CONF, "$sample_conf", [Finit sameple.conf for initctl create])
AC_EXPAND_DIR(bash_completion_dir, "$BASH_DIR") AC_EXPAND_DIR(path_stdpath, "$sbindir:$bindir:/usr/sbin:/usr/bin:/sbin:/bin")
AC_SUBST(BASH_DIR, "$bash_completion_dir") AC_DEFINE_UNQUOTED(_PATH_STDPATH, "$path_stdpath", [Default PATH])
AS_IF([test "$heading" = ""], [heading="<DEFAULT>"])
AS_IF([test "$heading" = "no"], [heading="<NONE>"])
RTC_DATE=$rtc_date
AS_IF([test "$rtc_date" = ""], [RTC_DATE="<DEFAULT>"])
AS_IF([test "$rtc_date" = "no"], [RTC_DATE="<DEFAULT>"])
# Generate all files # Generate all files
AC_OUTPUT AC_OUTPUT
@@ -388,16 +234,14 @@ cat <<EOF
------------------ Summary ------------------ ------------------ Summary ------------------
$PACKAGE_NAME version $PACKAGE_VERSION $PACKAGE_NAME version $PACKAGE_VERSION
Prefix................: $(eval echo $prefix) Prefix................: $prefix
Exec prefix...........: $(eval echo $exec_prefix) Exec prefix...........: `eval echo $exec_prefix`
Libdir................: $(eval echo $libdir)
Sysconfdir............: `eval echo $sysconfdir` Sysconfdir............: `eval echo $sysconfdir`
Localstatedir.........: `eval echo $localstatedir` Localstatedir.........: `eval echo $localstatedir`
Default fstab.........: `eval echo $fstab`
Finit config file.....: $conf_path Finit config file.....: $conf_path
Finit config.d path...: $rcsd_path Finit config.d path...: $rcsd_path
Finit plugin path.....: $plugin_path Finit plugin path.....: $plugin_path
Compat rc.local path..: `eval echo $rclocal` Compat rc.local path..: $rclocal_path
System environment....: ${sysconfig_path:-${sysconfig}} System environment....: ${sysconfig_path:-${sysconfig}}
Random seed path......: $random_path Random seed path......: $random_path
C Compiler............: $CC $CFLAGS $CPPFLAGS $LDFLAGS $LIBS C Compiler............: $CC $CFLAGS $CPPFLAGS $LDFLAGS $LIBS
@@ -406,27 +250,16 @@ cat <<EOF
Behavior: Behavior:
Boot heading..........: $heading Boot heading..........: $heading
Plugins...............: $plugins Plugins...............: $plugins
RTC restore date......: $RTC_DATE
RTC fallback file.....: $rtc_file
Optional features: Optional features:
Install doc/..........: $enable_doc Install doc/..........: $enable_doc
Install contrib/......: $enable_contrib Install contrib/......: $enable_contrib
Bash completion.......: $bash_completion_dir Built-in watchdogd....: $enable_watchdog
Built-in keventd......: $with_keventd
Built-in sulogin......: $with_sulogin $sulogin
Built-in watchdogd....: $with_watchdog $watchdog
Built-in logrotate....: $enable_logrotate Built-in logrotate....: $enable_logrotate
Replacement libsystemd: $with_libsystemd Scripting tool logit..: $enable_logit
Use cgroup v2.........: $enable_cgroup Emergency shell.......: $enable_emergency_shell
Parse kernel cmdline..: $enable_kernel_cmdline Fallback shell........: $enable_fallback_shell
Keep kernel logging...: $enable_kernel_logging
Skip fsck check.......: $enable_fastboot
Run fsck fix mode.....: $enable_fsckfix
Redirect output.......: $enable_redirect
Rescue mode...........: $enable_rescue
Default hostname......: $hostname Default hostname......: $hostname
Default group.........: $group
Default runlevel......: $runlevel Default runlevel......: $runlevel
------------- Compiler version -------------- ------------- Compiler version --------------
+1 -1
View File
@@ -1,5 +1,5 @@
SUBDIRS = finit.d SUBDIRS = finit.d
docsdir := @docdir@/contrib/alpine docsdir := @docdir@/contrib/alpine
docs_DATA = README.md finit.conf build.sh install.sh rc.local docs_DATA = README.md finit.conf alpine-release build.sh install.sh rc.local
EXTRA_DIST = $(docs_DATA) EXTRA_DIST = $(docs_DATA)
+2 -5
View File
@@ -1,8 +1,5 @@
HowTo: Finit on Alpine Linux 3.4...3.19 HowTo: Finit on Alpine Linux 3.4-3.6
======================================= ====================================
> [!TIP]
> https://troglobit.com/post/2021-02-12-alpine-linux-with-finit/
HowTo use Finit to boot an [Alpine Linux][] system. It is assumed that HowTo use Finit to boot an [Alpine Linux][] system. It is assumed that
the user has already installed make, a compiler, C library header files, the user has already installed make, a compiler, C library header files,
+1
View File
@@ -0,0 +1 @@
3.6.2
+3 -2
View File
@@ -17,8 +17,8 @@ PKG_CONFIG_LIBDIR=/usr/lib/pkgconfig:/usr/local/lib/pkgconfig ./configure \
--prefix=/usr --exec-prefix= \ --prefix=/usr --exec-prefix= \
--sysconfdir=/etc --localstatedir=/var \ --sysconfdir=/etc --localstatedir=/var \
--enable-dbus-plugin --enable-x11-common-plugin \ --enable-dbus-plugin --enable-x11-common-plugin \
--enable-alsa-utils-plugin --without-watchdog \ --enable-alsa-utils-plugin --enable-watchdog \
--with-keventd --with-sulogin --with-heading="Alpine Linux 3.13"
echo echo
echo "*** Building ..." echo "*** Building ..."
@@ -35,3 +35,4 @@ fi
echo echo
echo "*** Done" echo "*** Done"
echo echo
+1 -17
View File
@@ -5,22 +5,6 @@
# Default is 2 # Default is 2
#runlevel 2 #runlevel 2
# Top-level cgroups and their default settings. All groups mandatory
# but more can be added, max 8 groups in total currently. The cgroup
# 'root' is also available, reserved for RT processes. Settings are
# as-is, only one shorthand 'mem.' exists, other than that it's the
# cgroup v2 controller default names.
#cgroup init cpu.weight:100
#cgroup user cpu.weight:100
#cgroup system cpu.weight:9700
# Task to run if ctrl-alt-del is pressed. This condition is asserted by
# Finit upon receiving SIGINT (from the kernel).
#task <sys/key/ctrlaltdel> [12345789] initctl reboot -- Rebooting system
# Task to run if the kernel gets a power fail condition is pressed.
# Asserted by Finit upon receiving SIGPWR (from the kernel).
#task <sys/pwr/fail> [12345789] initctl poweroff -- Shutting down system
## Bootstrap services and tasks ## Bootstrap services and tasks
# Can be listed here or in /etc/finit.d/*.conf # Can be listed here or in /etc/finit.d/*.conf
+2 -1
View File
@@ -1,7 +1,8 @@
SUBDIRS = available SUBDIRS = available
docsdir := @docdir@/contrib/alpine/finit.d docsdir := @docdir@/contrib/alpine/finit.d
d_LINKS = acpid.conf crond.conf dropbear.conf getty.conf \ d_LINKS = acpid.conf crond.conf dropbear.conf getty.conf \
keymap.conf modules.conf ntpd.conf syslogd.conf keymap.conf modules.conf ntpd.conf \
klogd.conf syslogd.conf
install-exec-hook: install-exec-hook:
@$(MKDIR_P) $(DESTDIR)$(docsdir)/available @$(MKDIR_P) $(DESTDIR)$(docsdir)/available
+2 -1
View File
@@ -1,4 +1,5 @@
docsdir := @docdir@/contrib/alpine/finit.d/available docsdir := @docdir@/contrib/alpine/finit.d/available
docs_DATA = acpid.conf crond.conf dropbear.conf getty.conf keymap.conf \ docs_DATA = acpid.conf crond.conf dropbear.conf getty.conf keymap.conf \
lxdm.conf modules.conf ntpd.conf syslogd.conf watchdog.conf lxdm.conf modules.conf ntpd.conf klogd.conf syslog.conf \
watchdog.conf
EXTRA_DIST = $(docs_DATA) EXTRA_DIST = $(docs_DATA)
+3 -4
View File
@@ -1,5 +1,4 @@
# Consoles to start getty on when system is up # Consoles to start getty on when system is up
tty [12345] /dev/ttyS0 noclear tty [12345] /dev/tty1 noclear nowait
tty [12345] /dev/tty1 noclear nowait tty [2345] /dev/tty2 noclear nowait
tty [2345] /dev/tty2 noclear nowait tty [2345] /dev/tty3 noclear nowait
tty [2345] /dev/tty3 noclear nowait
@@ -0,0 +1,2 @@
# Start klogd as soon as possible, after syslogd, should always run
service [S12345] <pid/syslogd> env:-/etc/conf.d/klogd klogd -n $KLOGD_OPTS -- Kernel log daemon
@@ -4,4 +4,3 @@
#module evdev #module evdev
#module mousedev #module mousedev
#module 8139cp #module 8139cp
#module softdog
@@ -0,0 +1,2 @@
# Start syslogd as soon as possible, should always run
service [S12345] env:-/etc/conf.d/syslog syslogd -n $SYSLOGD_OPTS -- Syslog daemon
@@ -1,4 +0,0 @@
# Start syslogd as soon as possible, should always run
# Start klogd as soon as possible, but after syslogd
service [S12345] env:-/etc/conf.d/syslog syslogd -n $SYSLOGD_OPTS -- Syslog daemon
service [S12345] <pid/syslogd> env:-/etc/conf.d/klogd klogd -n $KLOGD_OPTS -- Kernel log daemon
+28 -35
View File
@@ -1,53 +1,44 @@
#!/bin/sh #!/bin/sh
if [ "$(id -u)" != "0" ]; then if [ "x`id -u`" != "x0" ]; then
printf "\n\e[1m*** This script must run as root\e[0m\n\n" echo
echo "*** This script must run as root"
echo
exit 1 exit 1
fi fi
# shellcheck disable=SC3037,SC3045,SC2154
yorn()
{
printf "\e[1m> %s (y/N)?\e[0m " "$*"
read -rn1 yorn
echo
if [ "$yorn" = "y" ] || [ "$yorn" = "Y" ]; then
return 0
fi
return 1
}
# Adjust base directory # Adjust base directory
if grep -q contrib/alpine Makefile 2>/dev/null; then if [ -e alpine-release ]; then
cd ../.. cd ../..
fi elif [ ! -e autogen.sh ]; then
echo "*** Please run this script from the Finit base directory."
if [ ! -e configure.ac ]; then
printf "\n\e[1m*** Please run this script from the Finit base directory.\e[0m\n"
exit 1 exit 1
fi fi
printf "\n\e[1mInstall Finit on Alpine Linux\n" echo
printf "========================================================================\e[0m\n" echo "*** Install Finit on Alpine Linux"
printf "/sbin/finit - PID 1\n" echo "========================================================================"
printf "/lib/finit/plugins/* - All enabled Finit plugins\n" echo "/sbin/finit - PID 1"
printf "/etc/finit.conf - Finit configuration file\n" echo "/lib/finit/plugins/* - All enabled Finit plugins"
printf "/etc/finit.d/ - Finit services\n" echo "/etc/finit.conf - Finit configuration file"
echo "/etc/finit.d/ - Finit services"
echo
read -p "Do you want to continue (y/N)? " yorn
if yorn "Do you want to continue"; then if [ "x$yorn" = "xy" -o "x$yorn" = "xY" ]; then
printf "\n\e[1m*** Installing Finit files ...\e[0m\n" echo
echo "*** Installing Finit files ..."
make install make install
cd /usr/share/doc/finit/contrib/alpine || exit 1 cd /usr/share/doc/finit/contrib/alpine
for file in finit.conf rc.local; do for file in finit.conf rc.local; do
install -vbD $file /etc/$file install -vbD $file /etc/$file
done done
cp -va finit.d /etc/ cp -va finit.d /etc/
if yorn "Install Finit as the system default Init"; then read -p "*** Install Finit as the system default Init (y/N)? " yorn
printf "\e[1m*** Updating /sbin/init symlink --> finit ...\e[0m\n" if [ "x$yorn" = "xy" -o "x$yorn" = "xY" ]; then
cd /sbin || exit 1 echo "*** Updating /sbin/init symlink --> finit ..."
cd /sbin
rm init rm init
ln -s finit init ln -s finit init
@@ -56,8 +47,10 @@ if yorn "Do you want to continue"; then
ln -s reboot shutdown ln -s reboot shutdown
ln -s reboot suspend ln -s reboot suspend
fi fi
printf "\n\e[1m*** Done\e[0m\n" echo "*** Done"
echo echo
else else
printf "\n\e[1m*** Aborting install.\e[0m\n\n" echo
echo "*** Aborting install."
echo
fi fi
+1 -1
View File
@@ -4,5 +4,5 @@
# #
# Each line is run in sequence. # Each line is run in sequence.
# #
# NOTE: Remember to set the executable bit! # NOTE: Remeber to set the executable bit!
# #
+2 -2
View File
@@ -1,4 +1,4 @@
SUBDIRS = finit.d SUBDIRS = finit.d grub.d
docsdir := @docdir@/contrib/debian docsdir := @docdir@/contrib/debian
docs_DATA = README.md finit.conf build.sh install.sh docs_DATA = README.md finit.conf os-release build.sh install.sh
EXTRA_DIST = $(docs_DATA) EXTRA_DIST = $(docs_DATA)
+7 -22
View File
@@ -20,44 +20,29 @@ tools pre-systemd work as intended.
root@debian:~# apt install initscripts console-setup root@debian:~# apt install initscripts console-setup
> [!TIP]
> As of Debian 11 (Bullseye), libuev and libite are part of the main
> section of Debian. So just install the -dev packages :)
The following script can then be used to configure, build, install and The following script can then be used to configure, build, install and
set up your system to run Finit: set up your system to run Finit:
user@debian:~/finit$ contrib/debian/build.sh user@debian:~/finit$ contrib/debian/build.sh
However, since `/sbin/init` already exists on your system, the script However, since `/sbin/init` already exists on your system, the script
creates another entry in your GRUB config by updating `$SUPPORTED_INITS` creates another entry in your GRUB config, in `/etc/grub.d/40_custom`,
in `/etc/grub.d/10_inux` and run `update-grub`. On reboot you will find where `init=/sbin/finit` is added to your kernel line. It is of course
a (finit) entry in the "Advanced options for Debian GNU/Linux" section. also possible to change the default init to Finit, if you do you can
It is of course also possible to change the default init to Finit: remove the custom Grub entry:
user@debian:~/finit# cd /sbin user@debian:~/finit# cd /sbin
user@debian:/sbin# sudo mv init oldinit user@debian:/sbin# sudo rm init
user@debian:/sbin# sudo ln -s finit init user@debian:/sbin# sudo ln -s finit init
Before rebooting, check the default [/etc/finit.conf](finit.conf) and Before rebooting, check the default [/etc/finit.conf](finit.conf) and
`/etc/finit.d/*.conf` files. The build + install script above provides `/etc/finit.d/*.conf` files. The build + install script above provides
a few sample `.conf` files. See `initctl ls` after boot for a list of a few sample `.conf` files. See `initctl list` after boot for a list of
enabled and available services, you can then use `enable` and `disable` enabled and available services.
comands to `initctl`, followed by `reload` to activate your changes.
You can also use a standard [/etc/rc.local](rc.local) for one-shot tasks You can also use a standard [/etc/rc.local](rc.local) for one-shot tasks
and initialization like keyboard language etc. and initialization like keyboard language etc.
> [!NOTE]
> For the X Window system, you may need to `sudo apt install elogind`
> (Bullseye and later), followed by `initctl reload` to activate it (it
> is enabled by default), and logout/login again. The elogind daemon
> ensures a regular non-root user can start and interact with an X
> session, otherwise keyboard and mouse won't work. When you're happy,
> you can enable the lightdm.conf, change the default runlevel to 3, and
> presto! you have a desktop again.
Have fun! Have fun!
/Joachim ツ /Joachim ツ
+6 -2
View File
@@ -25,8 +25,9 @@ echo
--prefix=/usr --exec-prefix= \ --prefix=/usr --exec-prefix= \
--sysconfdir=/etc --localstatedir=/var \ --sysconfdir=/etc --localstatedir=/var \
--enable-dbus-plugin --enable-x11-common-plugin \ --enable-dbus-plugin --enable-x11-common-plugin \
--enable-alsa-utils-plugin --with-keventd \ --enable-alsa-utils-plugin \
--with-random-seed=/var/lib/urandom/random-seed --with-random-seed=/var/lib/urandom/random-seed \
--with-heading="Debian GNU/Linux"
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
echo echo
@@ -59,3 +60,6 @@ else
echo "*** Use 'sudo contrib/debian/install.sh' later to install Finit" echo "*** Use 'sudo contrib/debian/install.sh' later to install Finit"
echo echo
fi fi
+1 -17
View File
@@ -5,22 +5,6 @@
# Default is 2 # Default is 2
#runlevel 2 #runlevel 2
# Top-level cgroups and their default settings. All groups mandatory
# but more can be added, max 8 groups in total currently. The cgroup
# 'root' is also available, reserved for RT processes. Settings are
# as-is, only one shorthand 'mem.' exists, other than that it's the
# cgroup v2 controller default names.
#cgroup init cpu.weight:100
#cgroup user cpu.weight:100
#cgroup system cpu.weight:9700
# Task to run if ctrl-alt-del is pressed. This condition is asserted by
# Finit upon receiving SIGINT (from the kernel).
#task <sys/key/ctrlaltdel> [12345789] initctl reboot -- Rebooting system
# Task to run if the kernel gets a power fail condition is pressed.
# Asserted by Finit upon receiving SIGPWR (from the kernel).
#task <sys/pwr/fail> [12345789] initctl poweroff -- Shutting down system
## Bootstrap services and tasks ## Bootstrap services and tasks
# Can be listed here or in /etc/finit.d/*.conf # Can be listed here or in /etc/finit.d/*.conf
+2 -4
View File
@@ -1,9 +1,7 @@
SUBDIRS = available SUBDIRS = available
docsdir := @docdir@/contrib/debian/finit.d docsdir := @docdir@/contrib/debian/finit.d
d_LINKS = acpid.conf apparmor.conf avahi-daemon.conf \ d_LINKS = console-setup.conf getty.conf keyboard-setup.conf \
bluetooth.conf console-setup.conf elogind.conf \ modules.conf rsyslogd.conf sshd.conf
getty.conf keyboard-setup.conf modules.conf \
plymouth-quit.conf rsyslogd.conf sshd.conf
install-exec-hook: install-exec-hook:
@$(MKDIR_P) $(DESTDIR)$(docsdir)/available @$(MKDIR_P) $(DESTDIR)$(docsdir)/available
+3 -6
View File
@@ -1,8 +1,5 @@
docsdir := @docdir@/contrib/debian/finit.d/available docsdir := @docdir@/contrib/debian/finit.d/available
docs_DATA = acpid.conf apparmor.conf avahi-daemon.conf bluetooth.conf \ docs_DATA = acpid.conf console-setup.conf getty.conf keyboard-setup.conf \
console-setup.conf elogind.conf getty.conf \ lightdm.conf modules.conf rsyslogd.conf sntpd.conf \
keyboard-setup.conf lightdm.conf modules.conf sntpd.conf \ sshd.conf syslogd.conf xdm.conf
plymouth-quit.conf rsyslogd.conf sshd.conf syslogd.conf \
xdm.conf
EXTRA_DIST = $(docs_DATA) EXTRA_DIST = $(docs_DATA)
@@ -1 +0,0 @@
task [2345] <sys/pwr/ac,pid/syslogd> halt:usr1 env:-/etc/default/anacron anacron -d -q $ANACRON_ARGS -- Anacron jobs
@@ -1,2 +0,0 @@
sysv [S] /etc/init.d/apparmor -- AppArmor initialization
@@ -1 +0,0 @@
service [2345] env:-/etc/default/avahi-daemon avahi-daemon -s $AVAHI_DAEMON_OPTS -- Avahi mDNS/DNS-SD Stack
@@ -1,3 +0,0 @@
# To ignore errors like "org.freedesktop.hostname1", update the env file with
# "--noplugin=hostname", i.e. append to BLUETOOTHD_OPTS
service [2345] log:null env:-/etc/default/bluetooth /usr/libexec/bluetooth/bluetoothd -n $BLUETOOTHD_OPTS -- Bluetooth service
@@ -1 +0,0 @@
service [2345] <sys/pwr/ac,pid/syslogd> env:-/etc/default/cron cron -f $EXTRA_OPTS -- Background job processing daemon
@@ -1,4 +0,0 @@
# On some systems, bootstrap can be really quick and cause elogind
# to not start before a user has managed to log in. To prevent
# this, add <pid/elogind> as condition to your TTYs in getty.conf
service [2345] <pid/syslogd> /lib/elogind/elogind -- Login manager
+2 -5
View File
@@ -1,7 +1,4 @@
# Consoles to start getty on when system is up # Consoles to start getty on when system is up
tty [12345] /dev/tty1 linux noclear nowait tty [12345] /dev/tty1 linux noclear nowait
tty [2345] /dev/tty2 linux nowait tty [2345] /dev/tty2 linux noclear nowait
tty [2345] /dev/tty3 linux nowait tty [2345] /dev/tty3 linux noclear nowait
tty [2345] /dev/tty4 linux nowait
tty [2345] /dev/tty5 linux nowait
tty [2345] /dev/tty6 linux nowait
@@ -1,2 +0,0 @@
# Need to stop plymouth, or it'll block stdin on tty1
task [S] /usr/bin/plymouth quit -- Stopping Plymouth Boot Screen
+14
View File
@@ -0,0 +1,14 @@
#!/bin/sh
exec tail -n +3 $0
# This file provides an easy way to add custom menu entries. Simply type the
# menu entries you want to add after this comment. Be careful not to change
# the 'exec tail' line above.
menuentry '$MENU with Finit' --class $TYPE --class gnu-linux --class gnu --class os --user {
insmod gzio
insmod part_msdos
insmod ext2
search --no-floppy --fs-uuid --set=root $BOOT
linux /vmlinuz root=UUID=$ROOT ro quiet init=/sbin/finit
initrd /initrd.img
}
+3
View File
@@ -0,0 +1,3 @@
docsdir := @docdir@/contrib/debian/grub.d
docs_DATA = 40_custom
EXTRA_DIST = $(docs_DATA)
+9 -15
View File
@@ -8,10 +8,10 @@ if [ "x`id -u`" != "x0" ]; then
fi fi
# Adjust base directory # Adjust base directory
grep -q debian Makefile 2>/dev/null grep -q Debian os-release 2>/dev/null
if [ $? -eq 0 ]; then if [ $? -eq 0 ]; then
cd ../.. cd ../..
elif [ ! -e configure.ac ]; then elif [ ! -e autogen.sh ]; then
echo "*** Please run this script from the Finit base directory." echo "*** Please run this script from the Finit base directory."
exit 1 exit 1
fi fi
@@ -23,7 +23,7 @@ echo "/sbin/finit - PID 1"
echo "/lib/finit/plugins/* - All enabled Finit plugins" echo "/lib/finit/plugins/* - All enabled Finit plugins"
echo "/etc/finit.conf - Finit configuration file" echo "/etc/finit.conf - Finit configuration file"
echo "/etc/finit.d/ - Finit services" echo "/etc/finit.d/ - Finit services"
echo "/etc/grub.d/10_linux - Add Finit to Grub's SUPPORTED_INITS" echo "/etc/grub.d/40_custom - Add menu entry to the Grub boot loader"
echo echo
read -p "Do you want to continue (y/N)? " yorn read -p "Do you want to continue (y/N)? " yorn
echo echo
@@ -38,18 +38,12 @@ if [ "x$yorn" = "xy" -o "x$yorn" = "xY" ]; then
cp -va finit.d /etc/ cp -va finit.d /etc/
echo "*** Setting up a GRUB boot entry ..." echo "*** Setting up a GRUB boot entry ..."
fn=/etc/grub.d/10_linux MENU=`grep gnu-linux /boot/grub/grub.cfg |head -1 |sed "s/menuentry '\([^']*\).*/\1/"`
if [ -e $fn ]; then TYPE=`grep gnu-linux /boot/grub/grub.cfg |head -1 |sed "s/.*' --class \([a-z]*\).*/\1/"`
if `grep SUPPORTED_INITS $fn |head -1 |grep -q finit`; then BOOT=`grep set=root /boot/grub/grub.cfg |head -1 |sed 's/.* \([a-f0-9]*-[a-f0-9]*-[a-f0-9]*-[a-f0-9]*-[a-f0-9]*\).*/\1/'`
echo "Already installed, done." ROOT=`grep root=UUID /boot/grub/grub.cfg |head -1 |sed 's/.*UUID=\([a-f0-9]*-[a-f0-9]*-[a-f0-9]*-[a-f0-9]*-[a-f0-9]*\).*/\1/'`
else cat grub.d/40_custom | sed "s,\$BOOT,$BOOT,;s,\$ROOT,$ROOT,;s,\$TYPE,$TYPE,;s,\$MENU,$MENU," >/etc/grub.d/40_custom
echo "Adding Finit to list of SUPPORTED_INITS ..." update-grub
sed -i 's/SUPPORTED_INITS="[^"]*/& finit:\/sbin\/finit/' $fn
update-grub
fi
else
echo "Cannot find $fn, you'll have to set up your bootloader on your own."
fi
echo echo
echo "*** Done" echo "*** Done"
+8
View File
@@ -0,0 +1,8 @@
PRETTY_NAME="Debian GNU/Linux 8 (jessie)"
NAME="Debian GNU/Linux"
VERSION_ID="8"
VERSION="8 (jessie)"
ID=debian
HOME_URL="http://www.debian.org/"
SUPPORT_URL="http://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"
+2 -37
View File
@@ -8,18 +8,6 @@ module evdev
module loop module loop
module psmouse module psmouse
# Top-level cgroups and their default settings. All groups mandatory
# but more can be added, max 8 groups in total currently. The cgroup
# 'root' is also available, reserved for RT processes. Settings are
# as-is, only one shorthand 'mem.' exists, other than that it's the
# cgroup v2 controller default names.
cgroup init cpu.weight:100
cgroup user cpu.weight:100
cgroup system cpu.weight:9700 cpu.max:50000
# Example extra cgroup
cgroup maint cpu.weight:100
# Runlevel to start after bootstrap, runlevel 'S' # Runlevel to start after bootstrap, runlevel 'S'
runlevel 2 runlevel 2
@@ -28,21 +16,13 @@ network service networking start
# Max file size for each log file: 100 kiB, rotate max 4 copies: # 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 # log => log.1 => log.2.gz => log.3.gz => log.4.gz
log size:100k count:4 log size=100k count=4
# Virtual consoles to start getty on # Virtual consoles to start getty on
tty /dev/tty1 tty /dev/tty1
tty /dev/tty2 tty /dev/tty2
tty /dev/tty3 tty /dev/tty3
# Task to run if ctrl-alt-del is pressed. This condition is asserted by
# Finit upon receiving SIGINT (from the kernel).
task <sys/key/ctrlaltdel> [12345789] initctl reboot -- Rebooting system
# Task to run if the kernel gets a power fail condition is pressed.
# Asserted by Finit upon receiving SIGPWR (from the kernel).
task <sys/pwr/fail> [12345789] initctl poweroff -- Shutting down system
# Alternative method instead of runparts # Alternative method instead of runparts
#task [S] /etc/init.d/keyboard-setup start -- Setting up preliminary keymap #task [S] /etc/init.d/keyboard-setup start -- Setting up preliminary keymap
#task [S] /etc/init.d/acpid start -- Starting ACPI Daemon #task [S] /etc/init.d/acpid start -- Starting ACPI Daemon
@@ -50,24 +30,9 @@ task <sys/pwr/fail> [12345789] initctl poweroff -- Shutting down system
#run [2] /etc/init.d/networking start -- Start networking #run [2] /etc/init.d/networking start -- Start networking
# Services to be monitored and respawned as needed # Services to be monitored and respawned as needed
# klgod and syslogd are placed in the maint cgroup
cgroup.maint
service [2345] <pid/syslogd> klogd -n -- Kernel logging server service [2345] <pid/syslogd> klogd -n -- Kernel logging server
service [2345] syslogd -n -- Syslog server service [2345] syslogd -n -- Syslog server
service [3] gdm -- GNOME Display Manager
# gdm in the system cgroup (default when read from it's own .conf file)
cgroup.system
service [3] cgroup:cpu.weight:250,mem.max:10M gdm -- GNOME Display Manager
# Start SSH daemon with opts from /etc/default/ssh (if available), move
# to user cgroup with cpu.weight:250. Default for services is system
# group. Default weight in user group is 100 (above). Max length of
# cgroup argument is (currently) 63 chars.
#
# Notice alternative syntax where current cgroup is only set for this
# particular service.
service [2345] cgroup.user:cpu.weight:250,mem.max:10M env:-/etc/default/ssh /usr/sbin/sshd -D $SSHD_OPTS -- OpenSSH daemon
# The BusyBox ntpd does not use syslog when running in the foreground # The BusyBox ntpd does not use syslog when running in the foreground
# So we use this trick to redirect stdout/stderr to a log file. The # So we use this trick to redirect stdout/stderr to a log file. The
@@ -1,75 +0,0 @@
In Finit issue #196 we were reminded [1] of a missing inotify flag in
Linux older kernels, IN_MASK_CREATE. Finit makes use of this internally
for monitoring PID conditions, and more. This is a central mechanism to
synchronize services at boot and reload at runtime.
The following patch for Linux 4.9.0, was provided by Andy Savage for
other people that may want to run Finit on slightly older kernels.
[1]: https://github.com/troglobit/finit/issues/196
Index: fs/notify/inotify/inotify_user.c
===================================================================
--- fs.orig/notify/inotify/inotify_user.c
+++ fs/notify/inotify/inotify_user.c
@@ -522,6 +522,7 @@ static int inotify_update_existing_watch
__u32 old_mask, new_mask;
__u32 mask;
int add = (arg & IN_MASK_ADD);
+ int create = (arg & IN_MASK_CREATE);
int ret;
mask = inotify_arg_to_mask(arg);
@@ -529,6 +530,8 @@ static int inotify_update_existing_watch
fsn_mark = fsnotify_find_inode_mark(group, inode);
if (!fsn_mark)
return -ENOENT;
+ else if (create)
+ return -EEXIST;
i_mark = container_of(fsn_mark, struct inotify_inode_mark, fsn_mark);
@@ -726,6 +729,10 @@ SYSCALL_DEFINE3(inotify_add_watch, int,
if (unlikely(!f.file))
return -EBADF;
+ /* IN_MASK_ADD and IN_MASK_CREATE don't make sense together */
+ if (unlikely((mask & IN_MASK_ADD) && (mask & IN_MASK_CREATE)))
+ return -EINVAL;
+
/* verify that this is indeed an inotify instance */
if (unlikely(f.file->f_op != &inotify_fops)) {
ret = -EINVAL;
@@ -814,7 +821,7 @@ static int __init inotify_user_setup(voi
BUILD_BUG_ON(IN_ISDIR != FS_ISDIR);
BUILD_BUG_ON(IN_ONESHOT != FS_IN_ONESHOT);
- BUG_ON(hweight32(ALL_INOTIFY_BITS) != 21);
+ BUG_ON(hweight32(ALL_INOTIFY_BITS) != 22);
inotify_inode_mark_cachep = KMEM_CACHE(inotify_inode_mark, SLAB_PANIC);
Index: include/linux/inotify.h
===================================================================
--- include.orig/linux/inotify.h
+++ include/linux/inotify.h
@@ -17,6 +17,6 @@ extern struct ctl_table inotify_table[];
IN_DELETE_SELF | IN_MOVE_SELF | IN_UNMOUNT | \
IN_Q_OVERFLOW | IN_IGNORED | IN_ONLYDIR | \
IN_DONT_FOLLOW | IN_EXCL_UNLINK | IN_MASK_ADD | \
- IN_ISDIR | IN_ONESHOT)
+ IN_MASK_CREATE | IN_ISDIR | IN_ONESHOT)
#endif /* _LINUX_INOTIFY_H */
Index: include/uapi/linux/inotify.h
===================================================================
--- include.orig/uapi/linux/inotify.h
+++ include/uapi/linux/inotify.h
@@ -52,6 +52,7 @@ struct inotify_event {
#define IN_ONLYDIR 0x01000000 /* only watch the path if it is a directory */
#define IN_DONT_FOLLOW 0x02000000 /* don't follow a sym link */
#define IN_EXCL_UNLINK 0x04000000 /* exclude events on unlinked objects */
+#define IN_MASK_CREATE 0x10000000 /* only create watches */
#define IN_MASK_ADD 0x20000000 /* add to the mask of an already existing watch */
#define IN_ISDIR 0x40000000 /* event occurred against dir */
#define IN_ONESHOT 0x80000000 /* only send event once */
+1 -1
View File
@@ -1,4 +1,4 @@
SUBDIRS = finit.d SUBDIRS = finit.d
docsdir := @docdir@/contrib/void docsdir := @docdir@/contrib/void
docs_DATA = README.md finit.conf build.sh install.sh rc.local docs_DATA = README.md finit.conf build.sh install.sh rc.local xbps
EXTRA_DIST = $(docs_DATA) EXTRA_DIST = $(docs_DATA)
+3 -2
View File
@@ -17,8 +17,8 @@ PKG_CONFIG_LIBDIR=/usr/lib/pkgconfig:/usr/local/lib/pkgconfig ./configure \
--prefix=/usr --exec-prefix= \ --prefix=/usr --exec-prefix= \
--sysconfdir=/etc --localstatedir=/var \ --sysconfdir=/etc --localstatedir=/var \
--enable-dbus-plugin --enable-x11-common-plugin \ --enable-dbus-plugin --enable-x11-common-plugin \
--enable-alsa-utils-plugin --with-watchdog \ --enable-alsa-utils-plugin --enable-watchdog \
--with-keventd --with-sulogin --with-heading="Void Linux"
echo echo
echo "*** Building ..." echo "*** Building ..."
@@ -35,3 +35,4 @@ fi
echo echo
echo "*** Done" echo "*** Done"
echo echo
-17
View File
@@ -5,22 +5,5 @@
# Default is 2 # Default is 2
#runlevel 2 #runlevel 2
# Top-level cgroups and their default settings. All groups mandatory
# but more can be added, max 8 groups in total currently. The cgroup
# 'root' is also available, reserved for RT processes. Settings are
# as-is, only one shorthand 'mem.' exists, other than that it's the
# cgroup v2 controller default names.
#cgroup init cpu.weight:100
#cgroup user cpu.weight:100
#cgroup system cpu.weight:9700
# Task to run if ctrl-alt-del is pressed. This condition is asserted by
# Finit upon receiving SIGINT (from the kernel).
#task <sys/key/ctrlaltdel> [12345789] initctl reboot -- Rebooting system
# Task to run if the kernel gets a power fail condition is pressed.
# Asserted by Finit upon receiving SIGPWR (from the kernel).
#task <sys/pwr/fail> [12345789] initctl poweroff -- Shutting down system
## Bootstrap services and tasks ## Bootstrap services and tasks
# Can be listed here or in /etc/finit.d/*.conf # Can be listed here or in /etc/finit.d/*.conf
+2 -2
View File
@@ -1,5 +1,5 @@
docsdir := @docdir@/contrib/void/finit.d/available docsdir := @docdir@/contrib/void/finit.d/available
docs_DATA = acpid.conf crond.conf dhcpcd.conf dmeventd.conf getty.conf \ docs_DATA = acpid.conf crond.conf dhcpcd.conf dmeventd.conf getty.conf \
keymap.conf lxdm.conf modules.conf ntpd.conf \ keymap.conf klogd.conf lxdm.conf modules.conf ntpd.conf \
sshd.conf syslog.conf uuidd.conf sshd.conf syslogd.conf uuidd.conf
EXTRA_DIST = $(docs_DATA) EXTRA_DIST = $(docs_DATA)
@@ -0,0 +1,2 @@
# Start klogd as soon as possible, should always run
service [S12345] <pid/syslogd> klogd -n -- Kernel log daemon
@@ -4,4 +4,3 @@
#module evdev #module evdev
#module mousedev #module mousedev
#module 8139cp #module 8139cp
module softdog
@@ -1,4 +0,0 @@
# Start syslogd as soon as possible, should always run
# Start klogd as soon as possible, but after syslogd
service [S12345] syslogd -n -- Syslog daemon
service [S12345] <pid/syslogd> klogd -n -- Kernel log daemon
@@ -0,0 +1,2 @@
# Start syslogd as soon as possible, should always run
service [S12345] syslogd -n -- Syslog daemon
+2 -3
View File
@@ -8,10 +8,9 @@ if [ "x`id -u`" != "x0" ]; then
fi fi
# Adjust base directory # Adjust base directory
grep -q void Makefile 2>/dev/null if [ -e xbps ]; then
if [ $? -eq 0 ]; then
cd ../.. cd ../..
elif [ ! -e configure.ac ]; then elif [ ! -e autogen.sh ]; then
echo "*** Please run this script from the Finit base directory." echo "*** Please run this script from the Finit base directory."
exit 1 exit 1
fi fi
+1 -1
View File
@@ -4,4 +4,4 @@
# #
# Each line is run in sequence. # Each line is run in sequence.
# #
# NOTE: Remember to set the executable bit! # NOTE: Remeber to set the executable bit!
+6 -18
View File
@@ -19,31 +19,19 @@ Some of these are also registered in the issue tracker on GitHub.
* Add new (complimentary) .svc file format to slowly migrate away * Add new (complimentary) .svc file format to slowly migrate away
from the very terse one-liner format currently used from the very terse one-liner format currently used
* Allow running as non-pid1 => read .conf and RCSD form cmdline * Allow running as non-pid1 => read .conf and RCSD form cmdline
* When a process dies, and Finit does not restart it, we should collect
a `siginfo_t` from the SIGCHLD signal and supply to the user in case
`initctl status <process>` is called to debug the issue.
* Add `finit.conf` support for UPS notification (SIGPWR) to start a task * Add `finit.conf` support for UPS notification (SIGPWR) to start a task
using, e.g. <sys/power/{ok,fail,low}> conditions. More info in sig.c using, e.g. <sys/power/{ok,fail,low}> conditions. More info in sig.c
As of Finit v4.1 SIGPWR generates <sys/power/fail> condition and it
is up to a task to check why and take appropriate action.
* Add `finit.conf` support for ctrl-alt-delete (SIGINT) and kbrequest, * Add `finit.conf` support for ctrl-alt-delete (SIGINT) and kbrequest,
i.e. KeyboardSignal, (SIGWINCH) behavior. Using conditions to a task, i.e. KeyboardSignal, (SIGWINCH) behavior. Using conditions to a task,
e.g, <sys/key/ctrlaltdel> and <sys/key/signal> like SIGPWR handling. e.g, <sys/key/ctrlaltdel> and <sys/key/signal> like SIGPWR handling.
* Write man pages for finit and `finit.conf`, steal from the excellent
As of Finit v4.1 SIGINT generates <sys/key/ctrlaltdel>, but there is `pimd` man pages ...
no check if the signal actually originates from the kernel. To get * Add support for timed shutdown in Finit, including cancelled shutdown
this verification, a new libuEv release is needed. As of June 6 -21
that functionality is not yet released.
Initctl
-------
* Add support for timed shutdown in Finit, including cancelled shutdown:
shutdown -h 03:35 "foobar was here"
* Add support for JSON output, or similar, from `initctl show`, e.g. * Add support for JSON output, or similar, from `initctl show`, e.g.
`initctl show --json` `initctl show --json`
* Add support for `-s` to redirect all output to syslog, for scripting
Init Init
+56
View File
@@ -0,0 +1,56 @@
Bootstrap
=========
1. Prepare emergency shell, if enabled
2. Set up initial signal handlers
3. Set up default $PATH early
4. Mount `/proc` and `/sys`
5. Check kernel command line for `debug` to figure out log level
6. Load all `.so` plugins
7. Call `fsck` on file systems listed in `/etc/fstab`
8. Populate `/dev` using either udev or mdev, depending on system type
9. Parse `/etc/finit.conf` and all `/etc/finit.d/*.conf` files
10. Start built-in watchdog, if enabled
11. Set hostname
12. Remount `/` read-write if `/` is listed in `/etc/fstab` without `ro`
13. Call 1st level hooks, `HOOK_ROOTFS_UP`
14. Mount all file systems listed in `/etc/fstab` and swap, if available
15. Enable SysV init signals
16. Call 2nd level hooks, `HOOK_BASEFS_UP`
17. Cleanup stale files from `/tmp/*` et al, handled by `bootmisc` plugin
18. Load kernel params from `/etc/sysctl.d/*.conf`, `/etc/sysctl.conf`
et al. (Supports all locations that SysV init does.), handled by
`procps` plugin
19. Start all 'S' runlevel tasks and services
20. Bring up loopback interface and all `/etc/network/interfaces`, if
the `.conf` setting `network <SCRIPT>` is set, it is called instead
21. Call 3rd level hooks, `HOOK_NETWORK_UP`
22. If `runparts <DIR>` is set, [run-parts(8)][] is called on `<DIR>`
23. Switch to the configured runlevel from `/etc/finit.conf`, default 2.
At every runlevel change all `*.conf` files in `/etc/finit.d/` are
(re)loaded and new services, tasks, and blocking run commands are
started. Provided they are allowed in the new runlevel and all of
their conditions, if any, are set.
24. Call 4th level hooks, `HOOK_SVC_UP`
25. Call `/etc/rc.local`, if it exists and is an executable shell script
26. Call 5th level (last) hooks, `HOOK_SYSTEM_UP`
27. Start all configured TTYs, or a fallback shell on `/dev/console`
In (19) and (22) tasks and services defined in `/etc/finit.conf` and
`/etc/sysctl.d/*.conf` are started. Remember, all `service` and `task`
stanzas are started in parallel and `run` in sequence, and in the order
listed. Hence, to emulate a SysV `/etc/init.d/rcS` one could write a
long `finit.conf` with only `run` statements.
Notice the five hook points that are called at various point in the
bootstrap process. This is where plugins can extend the boot in any way
they please. There are other hook points, e.g. `HOOK_MOUNT_ERROR`, for
more on this see [plugins.md](plugins.md).
For instance, at `HOOK_BASEFS_UP` a plugin could read an XML file from a
USB stick, convert/copy its contents to the system's `/etc/` directory,
well before all 'S' runlevel tasks are started. This could be used with
system images that are created read-only and all configuration is stored
on external media.
[run-parts(8)]: http://manpages.debian.org/cgi-bin/man.cgi?query=run-parts
+34 -63
View File
@@ -1,5 +1,5 @@
Building Finit Building
============== ========
* [Introduction](#introduction) * [Introduction](#introduction)
* [Configure](#configure) * [Configure](#configure)
@@ -17,21 +17,20 @@ optional plugins to enable. It depends on two external libraries:
- [libuEv][], the event loop - [libuEv][], the event loop
- [libite][] (-lite), much needed frog DNA - [libite][] (-lite), much needed frog DNA
> [!IMPORTANT] **NOTE:** Most free/open source software that uses `configure` default
> Most free/open source software packages that use `configure` default to install to `/usr/local`. However, some Linux distributions do no
> to install to `/usr/local`. However, some Linux distributions do no longer search that path for installed software, e.g. Fedora and Alpine
> longer search that path for installed software, e.g. Fedora and Alpine Linux. To get finit's configure script to find its dependencies you
> Linux. To get finit's configure script to find its dependencies you have to help the `pkg-config` tool a bit if you do not change the
> have to help the `pkg-config` tool a bit if you do not change the default prefix path:
> default prefix path:
> PKG_CONFIG_LIBDIR=/usr/local/lib/pkgconfig ./configure
> PKG_CONFIG_LIBDIR=/usr/local/lib/pkgconfig ./configure
The configure script checks for all dependencies, including the correct The configure script checks for all dependencies, including the correct
version of the above mentioned libraries. Currently required versions: version of the above mentioned libraries. Currently requried versions:
- libite v2.2.0, or later - libite v2.2.0
- libuEv v2.2.0, or later - libuEv v2.2.0
Configure Configure
@@ -54,10 +53,6 @@ Below are a few of the main switches to configure:
built-ins (.o files) and all external libraries, except the C library built-ins (.o files) and all external libraries, except the C library
will be linked statically. 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
init for container apps that can see the host's `/proc` filesystem
* `--enable-alsa-utils-plugin`: Enable the optional `alsa-utils.so` sound plugin. * `--enable-alsa-utils-plugin`: Enable the optional `alsa-utils.so` sound plugin.
* `--enable-dbus-plugin`: Enable the optional D-Bus `dbus.so` plugin. * `--enable-dbus-plugin`: Enable the optional D-Bus `dbus.so` plugin.
@@ -66,20 +61,8 @@ Below are a few of the main switches to configure:
* `--enable-x11-common-plugin`: Enable the optional X Window `x11-common.so` plugin. * `--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> 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 Example
------- -------
@@ -87,16 +70,16 @@ Example
First, unpack the archive: First, unpack the archive:
```shell ```shell
$ tar xf finit-4.3.tar.gz $ tar xf finit-3.0.tar.xz
$ cd finit-4.3/ $ cd finit-3.0/
``` ```
Then configure, build and install: Then configure, build and install:
```shell ```shell
$ ./configure --prefix=/usr --exec-prefix= \ $ ./configure --prefix=/usr --exec-prefix= \
--sysconfdir=/etc --localstatedir=/var \ --sysconfdir=/etc --localstatedir=/var \
--with-keventd --with-watchdog --with-heading="Alpine Linux 3.13" --with-hostname=alpine
$ make $ make
. .
. .
@@ -104,24 +87,23 @@ $ make
$ DESTDIR=/tmp/finit make install $ 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-3.0.tar.xz][1] archive is unpacked to the
user's home directory, configured, built and installed to a temporary user's home directory, configured, built and installed to a temporary
staging directory. The environment variable `DESTDIR` controls the staging directory. The environment variable `DESTDIR` controls the
destination directory when installing, very useful for building binary destination directory when installing, very useful for building binary
standalone packages. standalone packages.
Finit 4.1 and later can detect if it runs on an embedded system, or a Finit 3.0 and later can detect if it runs on an embedded system, or a
system that use BusyBox tools instead of udev & C:o. On such systems system that use BusyBox tools instead of udev & C:o. On such systems
`mdev` instead of `udev` is used. However, remember to also change the `mdev` instead of `udev` is used. However, remember to also change the
Linux config to: Linux config to:
CONFIG_UEVENT_HELPER_PATH="/sbin/mdev" CONFIG_UEVENT_HELPER_PATH="/sbin/mdev"
> [!TIP] **Note:** If you run into problems starting Finit, take a look at
> If you run into problems starting Finit, take a look at `finit.c`. `finit.c`. One of the most common problems is a custom Linux kernel
> One of the most common problems is a custom Linux kernel build that build that lack `CONFIG_DEVTMPFS`. Another is too much cruft in the
> lack `CONFIG_DEVTMPFS`. Another is too much cruft in the system system `/etc/fstab`.
> `/etc/fstab`.
Running Running
@@ -160,43 +142,32 @@ enabled. The default Finit rescue mode configuration is installed into
By default the a root shell, without login, is started. By default the a root shell, without login, is started.
> [!IMPORTANT]
> In rescue mode `initctl` will not work, the same goes for `reboot`,
> `shutdown`, and `poweroff` commands, provided they are the Finit
> versions of these commands. Use the `-f` flag to force the action.
Debugging Debugging
--------- ---------
Edit, or append to, the kernel command line: remove `quiet` to enable 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 ```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, try
`configure --enable-fallback-shell`. When no TTYs are detected, and
To debug startup issues, in particular issues with getty/login, add Finit is configured with this option, Finit will try to start a bare
the following to your Finit .conf file: `/bin/sh` on the boot console. Remember, this is only for debugging
and would leave your production system potentially wide open.
tty [12345789] notty noclear
The `notty` option ensures reusing the stdin/stdout set up by the
kernel. Remember, this is only for debugging and would leave your
production system potentially wide open.
There is also a rescue shell available, in case Finit crashes and the There is also a rescue shell available, in case Finit crashes and the
kernel usually reboots: `configure --enable-emergency-shell`. However, kernel usually reboots: `configure --enable-emergency-shell`. However,
the behavior of Finit is severely limited when this is enabled, so use the behavior of Finit is severely limited when this is enabled, so use
it only for debugging start up issues when Finit crashes. it only for debugging start up issues when Finit crashes.
> [!CAUTION] **NOTE:** Neither of these two configure options should be enabled on
> None of these options should be enabled on production systems since production systems since they can potentially give a user root access.
> they can potentially give a user root access.
[1]: ftp://troglobit.com/finit/finit-4.3.tar.gz [1]: ftp://troglobit.com/finit/finit-3.0.tar.xz
[libuEv]: https://github.com/troglobit/libuev [libuEv]: https://github.com/troglobit/libuev
[libite]: https://github.com/troglobit/libite [libite]: https://github.com/troglobit/libite
+15 -89
View File
@@ -4,70 +4,17 @@ Tips & Tricks with the kernel cmdline
This document summarizes the different boot parameters that can be This document summarizes the different boot parameters that can be
passed on the Linux kernel command line. Not limited to Finit. passed on the Linux kernel command line. Not limited to Finit.
> [!IMPORTANT]
> Remember to use `--` to separate kernel parameters from parameters to
> init. E.g., `init=/sbin/finit -- finit.debug rescue`
The `bool` setting is one of `on, off, true false, 1, 0`. The `bool` setting is one of `on, off, true false, 1, 0`.
* `debug`: Enable kernel debug. Debug messages are printed to the * `debug`: Enable kernel debug. Debug messages are printed to the
console until Finit starts up, unless `loglevel=7` (below) is used. console until Finit starts up.
* `fsck.mode=<auto,force,skip>`, default: `auto`, unless built with
`configure --enable-fastboot`, in which case the default is `skip`
* `fsck.repair=<preen,yes,no>`, default: `preen`, unless built with
`configure --enable-fsckfix`, in which case the default is `yes`.
This configure option also sets `fsck.mode=force`, unless fastboot
is selected at the same time. I.e., the `--enable-fastboot` build
option overrides the `fsck.mode` default value.
* `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`!
* `finit.config=/path/to/alternative/finit.conf`: override the
compile-time bootstrap config file, default:
./configure --with-config=/etc/finit.conf
Useful when starting up in various rescue mode, factory, or
production test setups. Use the top-level configuration file
directive `rcsd /path/to/finit.d` to override the default
rcS.d directory.
* `finit.debug[=bool]`: Enable finit debug. This is operated * `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 * `finit.show_status[=bool]`: Control finit boot progress, including
alternate `fstab` to mount the file system from. Remember, this file banner.
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.status_style=<classic,modern>`: Set Finit boot progress style, * `finit.status_style=<classic,modern>`: Set Finit boot progress style,
when enabled. when enabled.
@@ -77,44 +24,23 @@ The `bool` setting is one of `on, off, true false, 1, 0`.
signals and has no job control. Recommend using, and modifying, signals and has no job control. Recommend using, and modifying,
`rescue` mode instead. `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=SEC`: By default the kernel does not reboot after a kernel
panic. This setting will cause a kernel reboot after SEC seconds. panic. This setting will cause a kernel reboot after SEC seconds.
* `quiet`: Suppress kernel logging to console, except for warnings and * `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 * `rescue`: Start Finit rescue mode; no network, no `fsck` of file
the bundled `sulogin` program (Finit, or from util-linux/Busybox), systems in `/etc/fstab`, no `/etc/rc.local`, no `runparts`. The
you will be given a root login to a maintenance shell. However, if configuration is read from `/lib/finit/rescue.conf`, and can be
`sulogin` is missing, the file `/lib/finit/rescue.conf` is read and modified by the operator.
the system booted in a limited fallback mode. See [config.md][]
for more information.
This option can be disabled with `configure --without-rescue` * `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.
**Note:** in this mode `initctl` will not work. Correct the problem For more on kernel boot paramaters, see the man page [bootparam(7)][].
and use `reboot -f` to force reboot.
* `single`, or `S`: Overrides the configured runlevel (default: 2) to go
to after bootstrap by forcing it to runlevel 1, this is also known
as single user mode. Useful to debug startup problems. 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
[bootparam(7)]: https://www.man7.org/linux/man-pages/man7/bootparam.7.html [bootparam(7)]: https://www.man7.org/linux/man-pages/man7/bootparam.7.html
+23 -118
View File
@@ -13,9 +13,9 @@ Finit Conditions
Introduction Introduction
------------ ------------
Conditions are a relatively new addition to Finit, introduced in v3, Conditions are a new addition to Finit, introduced in v3, with the
with the intention of providing a mechanism for common synchronization intention of providing a mechanism for common synchronization problems.
problems. For example: For example:
- *"wait for service A to start before starting service B"*, or - *"wait for service A to start before starting service B"*, or
- *"wait for basic network access to be available"* - *"wait for basic network access to be available"*
@@ -27,16 +27,6 @@ specified separated by comma. Multiple conditions are logically AND'ed
during evaluation, i.e. all conditions must be satisfied in order for a during evaluation, i.e. all conditions must be satisfied in order for a
service to run. service to run.
A special syntax, using a leading `!` in run/task/service conditions,
denote if a:
- service does not support `SIGHUP`
- run/task should not block runlevel changes (i.e., bootstrap)
Finit guarantees by default that all run/tasks run (at least) once
per runlevel. For most tasks this is a good default, for example
checking SSH host keys or loading keymap. However, for conditions
that are unlikely to happen it is not. (See example below.)
### Example ### Example
@@ -45,60 +35,17 @@ that are unlikely to happen it is not. (See example below.)
In this example the Network monitor daemon `netd` is not started until In this example the Network monitor daemon `netd` is not started until
both the `pid/setupd` *and* `pid/zebra` conditions are satisfied. A both the `pid/setupd` *and* `pid/zebra` conditions are satisfied. A
`pid/` condition is satisfied by the corresponding service's PID file `pid/` condition is satisfied by the corresponding service's PID file
being created, i.e., the service's default readiness notification. being created.
> [!IMPORTANT] **NOTE:** Conditions also stop services when a condition is no longer
> Conditions also stop services when a condition is no longer asserted. asserted. I.e., if the Zebra process above stops or restarts, netd
> I.e., if the `zebra` process above stops or restarts, `netd` will also will also stop or restart.
> stop or restart.
Another example is `dropbear`, it does not support `SIGHUP`, but we can
also see optional sourcing of arguments from an environment file:
service [2345789] <!> env:-/etc/default/dropbear dropbear -F -R $DROPBEAR_ARGS -- Dropbear SSH daemon
Finally, the weird "block runlevel changes" example. Here we see what
happens when Finit receives `SIGPWR`, sent from a power daemon like
[powstatd(8)][]. A condition is asserted and a user can set up their
own task to act on it. We do not want this task to block Finit from
moving to the next runlevel after bootstrap, so we set `<!>`:
task [S0123456789] <!sys/pwr/fail> name:pwrfail initctl poweroff -- Power failure, shutting down
Triggering Triggering
---------- ----------
Conditions are mainly triggered (asserted) by built-in plugins, e.g., Conditions can only be triggered by built-in plugins.
- `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.
User-defined conditions are controlled using the `initctl cond set` and
`initctl cond clear` commands:
initctl cond set foo
initctl cond clear foo
The purpose of user-defined conditions is to be able to start or stop
services, or run/task jobs, on external site-dependent stimuli.
Example:
service [2345] <usr/foo> alarm --arg foo -- Foo alarm
For convenience, prefixing with `usr/` is allowed, but any other slashes
or period characters are disallowed. E.g., to trigger the `Foo alarm`,
the same as above, can also be achieved like this:
initctl cond set usr/foo
initctl cond clear usr/foo
Conditions retain their current state until the next reconfiguration or Conditions retain their current state until the next reconfiguration or
runlevel change. At that point all set conditions transition into the runlevel change. At that point all set conditions transition into the
@@ -107,49 +54,19 @@ on this, see [Internals](#internals).) Thus, after a reconfiguration it
is up to the "owner" of the condition to convey the new (or possibly is up to the "owner" of the condition to convey the new (or possibly
unchanged) state of it. unchanged) state of it.
Static (one-shot) conditions, like `usr/`, never enter the `flux` state. > **Note:** For `pid/` conditions it is expected that services "touch"
> or recreate their PID file on `SIGHUP`.
> [!IMPORTANT]
> For `pid/` conditions it is expected that the service reassert, i.e.,
> "touch" or recreate, their PID file on `SIGHUP`. This can be done by
> calling `utimensat()` on the PID file. Provided, of course, that the
> service supports reloading on `SIGHUP`, otherwise it will be restarted
> by Finit when they instead exit on the signal. For such services, use
> `<!>` to tell Finit the service does not support `SIGHUP`.
Built-in Conditions Built-in Conditions
------------------- -------------------
Finit comes with a set of plugins for conditions: Finit comes with a `pidfile` and `netlink` plugin. When enabled, the
`pidfile` plugin watches `/var/run/` (recursively) for PID files created
- `devmon` (built-in) by the monitored services, and sets a corresponding condition in the
- `netlink` `pid/` namespace. Similarily, the `netlink` plugin provides basic
- `pidfile` conditions for when an interface is brought up/down and when a default
- `sys` route (gateway) is set, in the `net/` namespace.
- `usr`
The `devmon` (built-in) plugin monitors `/dev` and `/dev/dir` for device
nodes being created and removed. It is active only when a run, task, or
service has declared a `<dev/foo>` or `<dev/dir/bar>` condition.
The `pidfile` plugin (recursively) watches `/run/` (recursively) for PID
files created by the monitored services, and sets a corresponding
condition in the `pid/` namespace.
Similarly, the `netlink` plugin provides basic conditions for when an
interface is brought up/down and when a default route (gateway) is set,
in the `net/` namespace.
The `sys` and `usr` plugins monitor are passive condition monitors where
the action is provided by `keventd`, signal handlers, and in the case of
`usr`, the end-user via the `initctl` tool.
Additionally, the various states of a run/task/sysv/service can also be
used as conditions, the image above shows the state names. The syntax
for a `service` type process: `<service/foo/STATE>`. The other types,
in particular run/task/sysv, there are the additional states `success`
and `failure`.
With the example listed above, finit does not start the `/sbin/netd` With the example listed above, finit does not start the `/sbin/netd`
daemon until `setupd` and `zebra` has started *and* created their PID daemon until `setupd` and `zebra` has started *and* created their PID
@@ -168,19 +85,10 @@ Built-in conditions:
- `net/<IFNAME>/exist` - `net/<IFNAME>/exist`
- `net/<IFNAME>/up` - `net/<IFNAME>/up`
- `net/<IFNAME>/running` - `net/<IFNAME>/running`
- `service/<NAME[:ID]>/<STATE>`
- `{run, task, sysv}/<NAME[:ID]>/{<STATE>, success, failure}`
- `sys/pwr/ac`
- `sys/pwr/fail`
- `sys/key/ctrlaltdel`
- `usr/foo`
- `boot/arg`
- `dev/node` and `dev/dir/node`
> [!NOTE] **Note:** `up` means administratively up, the interface flag `IFF_UP`.
> Here, `up` means administratively up, the interface flag `IFF_UP`. `running` is the `IFF_RUNNING` flag, meaning operatively up. The
> `running` is the `IFF_RUNNING` flag, meaning operatively up. The difference is that `running` tells if the NIC has link.
> difference is that `running` tells if the NIC has link.
Composition Composition
@@ -212,9 +120,8 @@ the service stanza for the daemon. It is far from optimal since any
synchronization of depending services may fail due to the daemon not synchronization of depending services may fail due to the daemon not
having reinitialized/created their IPC sockets, or similar. having reinitialized/created their IPC sockets, or similar.
> [!NOTE] > **Note:** in versions of Finit prior to v4, the PID conditions were
> In versions of Finit prior to v4, the PID conditions were called 'svc' > called 'svc' conditions, and they were far more complex.
> conditions, and they were far more complex.
Debugging Debugging
@@ -223,7 +130,7 @@ Debugging
If a service is not being started as it should, the problem might be If a service is not being started as it should, the problem might be
that one of its conditions is not in the expected state. Use the that one of its conditions is not in the expected state. Use the
command `initctl status` to inspect service status. Services in the command `initctl status` to inspect service status. Services in the
`waiting` state are pending a condition. `ready` state are pending a condition.
In that situation, running `initctl cond show` reveals which of the In that situation, running `initctl cond show` reveals which of the
conditions that are not satisfied. Listed as `off` below. conditions that are not satisfied. Listed as `off` below.
@@ -240,7 +147,7 @@ PID IDENT STATUS CONDITION (+ ON, ~ FLUX, - OFF)
Here we can see that `netd` is allowed to run since both its conditions Here we can see that `netd` is allowed to run since both its conditions
are in the `on` state, as indicated by the `+`-prefix. `udhcpc` however are in the `on` state, as indicated by the `+`-prefix. `udhcpc` however
is not allowed to run since `net/vlan1/exist` condition is not satisfied. is not allowed to run since `net/vlan1/exist` condition is not satsifed.
As indicated by the `-`-prefix. As indicated by the `-`-prefix.
To fake interface `vlan1` suddenly appearing, and test what happens to To fake interface `vlan1` suddenly appearing, and test what happens to
@@ -291,5 +198,3 @@ Therefore, any plugin that supplies Finit with conditions must ensure
that their state is updated after each reconfiguration. This can be that their state is updated after each reconfiguration. This can be
done by binding to the `HOOK_SVC_RECONF` hook. For an example of how done by binding to the `HOOK_SVC_RECONF` hook. For an example of how
to do this, see `plugins/pidfile.c`. to do this, see `plugins/pidfile.c`.
[powstatd(8)]: https://manpages.ubuntu.com/manpages/trusty/en/man8/powstatd.8.html
+100 -1060
View File
File diff suppressed because it is too large Load Diff
+2 -3
View File
@@ -34,9 +34,8 @@ build time:
./configure --with-rcsd=/etc/init.d --with-config=/etc/init.d/init.conf ./configure --with-rcsd=/etc/init.d --with-config=/etc/init.d/init.conf
``` ```
> [!IMPORTANT] > **Note:** remember `--prefix` et al as well, the default is likely
> Remember `--prefix` et al as well, the default is likely *not* what > *not* what you want. See the [build docs][1] for details.
> you want. See the [build docs][1] for details.
The resulting directory structure is depicted below. Please notice how The resulting directory structure is depicted below. Please notice how
`/etc/finit.conf` now resides in the same sub-directory as a non-symlink `/etc/finit.conf` now resides in the same sub-directory as a non-symlink
+29 -159
View File
@@ -8,8 +8,7 @@ Hooks & Plugins
* [Shutdown Hooks](#shutdown-hooks) * [Shutdown Hooks](#shutdown-hooks)
Finit can be extended to add general functionality in the form of I/O Finit can be extended to add general functionality in the form of I/O
monitors, or hook plugins. It is even possible to run scripts at these monitors, or hook plugins.
hook points, see below.
The following sections detail existing plugins and hook points. For The following sections detail existing plugins and hook points. For
more information, see the plugins listed below. more information, see the plugins listed below.
@@ -28,95 +27,33 @@ For your convenience a set of *optional* plugins are available:
system and runs at `HOOK_BASEFS_UP`. The `/var`, `/run`, and `/dev` system and runs at `HOOK_BASEFS_UP`. The `/var`, `/run`, and `/dev`
file systems must be writable for this plugin to work. file systems must be writable for this plugin to work.
This plugin is a wrapper for the [tmpfiles.d(5)][] implementation that Note: On an embedded system both `/var` and `/run` can be `tmpfs` RAM
Finit has. Capable but limited: no aging, attributes, or subvolumes. disks and `/dev` is usually a `devtmpfs`. This must be defined in the
`/etc/fstab` file and in the Linux kernel config.
By default, `/lib/finit/tmpfiles.d` carries all the default .conf
files distributed with Finit. It is read first but can be overridden
by any of the standard tmpfiles.d directories, e.g. `/etc/tmpfiles.d`.
> [!NOTE]
> On an embedded system both `/var` and `/run` can be `tmpfs` RAM
> disks and `/dev` is usually a `devtmpfs`. This must be defined in
> the `/etc/fstab` file and in the Linux kernel config.
* *dbus.so*: Setup and start system message bus, D-Bus, at boot. * *dbus.so*: Setup and start system message bus, D-Bus, at boot.
_Optional plugin._ _Optional plugin._
* *hook-scripts.so*: Trigger the execution of scripts from plugin hook * *hotplug.so*: Setup and start either udev or mdev hotplug daemon, if
points (see [Hooks](#hooks)). _Optional plugin._ available.
This plugin is particularly useful for early boot debugging that needs
to take place before regular services are available.
For example, say that you want to enable some kernel tracing before
modules are loaded. With hook scripts, you can just drop in a shell
script in `/libexec/finit/hook/mount/all/` that will poke the right
control files in tracefs.
Scripts are located in `/libexec/finit/hook` by default, this can be
customized at build-time using the `--with-hook-scripts-path=PATH`
argument to `configure`.
* *hotplug.so*: Replaced with `/lib/finit/system/10-hotplug.conf`, which
checks for `udevd` and `mdev` at boot. This file can be overridden by a
file in `/etc/finit.d/10-hotplug.conf`.
Enabled by default.
> [!TIP]
> See the [Services](config.md#services) section in the configuration
> guide for an example how to run `mdevd`, alternative to plain mdev.
* *rtc.so*: Restore and save system clock from/to RTC on boot/halt. * *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 * *modules-load.so*: Scans /etc/modules-load.d for modules to modprobe.
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, `#`, or `;`, is skipped.
Modules are by default loaded in runlevel `S` using the `task` stanza.
Each module gets a unique `name:modprobe.foo`, and optional`:ID`. The
runlevel can be changed per file using:
set runlevel 2345
The `:ID` is a globally incremented index, which can be disabled per
file (anywhere) using the following config line:
set noindex
To change the index used by the plugin:
set index 1234
Since these tasks run in the background, they return `[ OK ]` at boot,
unless the modprobe tool does not exist. Check syslog for warnings
and the actual status of the operation using `initctl`.
> [!IMPORTANT]
> Unlike the traditional .conf `module` directive, which load any listed
> module immediately, this plugin creates a background `task` which load
> the module(s) in the background. The program is modprobe,
> `/sbin/modprobe`, which you can override per .conf file:
>
> set modprobe /path/to/maybe-a-modprobe-wrapper
* *netlink.so*: Listens to Linux kernel Netlink events for gateway and * *netlink.so*: Listens to Linux kernel Netlink events for gateway and
interfaces. These events are then sent to the Finit service monitor 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 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. * *resolvconf.so*: Setup necessary files for `resolvconf` at startup.
_Optional plugin._ _Optional plugin._
* *tty.so*: Watches `/dev`, using inotify, for new device nodes (TTY's) * *tty.so*: Watches `/dev`, using inotify, for new device nodes (TTY's)
to start/stop getty consoles on them on demand. Useful when plugging to start/stop getty consoles on them on demand. Useful when plugging
in a usb2serial converter to login to your embedded device. Enabled in a usb2serial converter to login to your embedded device.
by default.
* *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._ * *x11-common.so*: Setup necessary files for X-Window. _Optional plugin._
@@ -130,107 +67,40 @@ state, etc. Available hook points are:
Hooks Hooks
----- -----
In the below listings, the first label is the hook point for a C plugin,
the second is the condition name and hook script path. A hook script is
a plain shell script, or program, that does a very small dedicated job
at the below hook points.
See [Run-parts Scripts](config.md#run-parts-scripts) for details on the
requirements, possibilities, and *limitations* of hook scripts.
All hook scripts are called with at least one environment variable set,
the hook name, useful when reusing the same hook script for multiple
hook points:
- `FINIT_HOOK_NAME`: set to the second label, e.g., `hook/net/up`
- `FINIT_SHUTDOWN`: set for `hook/sys/shutdown` and later to one
of `halt`, `poweroff`, or `reboot`.
**Example:**
$ mkdir -p /libexec/finit/hook/sys/down
$ cat <<EOF >/libexec/finit/hook/sys/down/foo.sh
#!/bin/sh
echo 'I run just before the reboot() syscall at shutdown/reboot'
echo 'I have access to /dev since devtmpfs is exempt from umount'
echo "FINIT_HOOK_NAME: $FINIT_HOOK_NAME"
if [ -n "$FINIT_SHUTDOWN" ]; then
echo "FINIT_SHUTDOWN: $FINIT_SHUTDOWN"
fi
exit 0
EOF
$ chmod +x /libexec/finit/hook/sys/down/foo.sh
> [!IMPORTANT]
> To use hook scripts, even for pre-bootstrap and pre-shutdown tasks,
> you must build with `configure --enable-hook-scripts-plugin`.
### Bootstrap Hooks ### Bootstrap Hooks
* `HOOK_BANNER`, `hook/sys/banner`: The very first point at which a * `HOOK_ROOTFS_UP`: When `finit.conf` has been read and `/` has is
plugin can run. Intended to be used as a banner replacement. mounted — very early
Essentially this runs just before entering runlevel S. Assume nothing
is available, so be prepared to use absolute paths, etc.
* `HOOK_ROOTFS_UP`, `hook/mount/root`: When `finit.conf` has been read * `HOOK_BASEFS_UP`: All of `/etc/fstab` is mounted, swap is available
and `/` has is mounted — very early and default init signals are setup
* `HOOK_MOUNT_ERROR`, `hook/mount/error`: executed if `mount -a` fails * `HOOK_NETWORK_UP`: System bootstrap, runlevel S, has completed and
networking is up (`lo` is up and the `network` script has run)
* `HOOK_MOUNT_POST`, `hook/mount/post`: always executed after `mount -a` * `HOOK_SVC_UP`: All services in the active runlevel has been launched
* `HOOK_BASEFS_UP`, `hook/mount/all`: All of `/etc/fstab` is mounted, * `HOOK_SYSTEM_UP`: All services *and* everything in `/etc/finit.d`
swap is available and default init signals are setup has been launched
* `HOOK_SVC_PLUGIN`, `hook/svc/plugin`: Called in `conf_init()` right
before loading `/etc/finit.conf`. For plugins to register any early
run/task/services, please do NOT use any earlier hook point. That
will cause uninitialized rlimits that lead to unpredictable results
when Finit later tries to start the run/task/service.
* `HOOK_NETWORK_UP`, `hook/net/up`: System bootstrap, runlevel S, has
completed and networking is up (`lo` is up and the `network` script
has run)
* `HOOK_SVC_UP`, `hook/svc/up`: All services in the active runlevel have
been launched
* `HOOK_SYSTEM_UP`, `hook/sys/up`: All services *and* everything in
`/etc/finit.d` has been launched
### Runtime Hooks ### Runtime Hooks
* `HOOK_SVC_RECONF`, N/A: Called when the user has changed something in * `HOOK_SVC_RECONF`: Called when the user has changed something in the
the `/etc/finit.d` directory and issued `SIGHUP`. The hook is called `/etc/finit.d` directory and issued `SIGHUP`. The hook is called when
when all modified/removed services have been stopped. When the hook all modified/removed services have been stopped. When the hook has
has completed, Finit continues to start all modified and new services. completed, Finit continues to start all modified and new services.
* `HOOK_RUNLEVEL_CHANGE`, N/A: Called when the user has issued a * `HOOK_RUNLEVEL_CHANGE`: Called when the user has issued a runlevel
runlevel change. The hook is called when services not matching the change. The hook is called when services not matching the new
new runlevel have been been stopped. When the hook has completed, runlevel have been been stopped. When the hook has completed, Finit
Finit continues to start all services in the new runlevel. continues to start all services in the new runlevel.
### Shutdown Hooks ### Shutdown Hooks
* `HOOK_NETWORK_DN`, `hook/net/down`: Called right after having changed * `HOOK_SHUTDOWN`: Called at shutdown/reboot, right before all
to runlevel 6, or 0, when all services have received their 'stop' signal. services are sent `SIGTERM`
* `HOOK_SHUTDOWN`, `hook/sys/shutdown`: Called at shutdown/reboot, right
before all services are sent `SIGTERM`
* `HOOK_SVC_DN`, `hook/svc/down`: In shutdown/reboot, all services and
non-reserved processes have been killed. **Note:** only hook scripts
can run here!
* `HOOK_SYSTEM_DN`, `hook/sys/down`: In shutdown/reboot, called after
all non-reserved file systems have been unmounted, just before Finit
tells the kernel to reboot or shut down. **Note:** only hook scripts
can run here!
Plugins like `tty.so` extend finit by acting on events, they are called Plugins like `tty.so` extend finit by acting on events, they are called
I/O plugins and are called from the finit main loop when `poll()` I/O plugins and are called from the finit main loop when `poll()`
detects an event. See the source code for `plugins/*.c` for more help detects an event. See the source code for `plugins/*.c` for more help
and ideas. and ideas.
[tmpfiles.d(5)]: https://www.freedesktop.org/software/systemd/man/tmpfiles.d.html
+2 -57
View File
@@ -1,60 +1,7 @@
Finit Services Finit Services
============== ==============
Starting & Monitoring ![The service state machine](svc-machine.png "The service state machine")
---------------------
Finit can start and monitor the following types of daemons:
* Forks to background, creates a PID file
* Runs in foreground:
- creates a PID file
- does not create a PID file -- Finit can create it for you (optional)
Finit can *not* start and monitor a daemon that:
* Forks to background and does *not* create a PID file
| | Forking | Creates PID File | Finit creates PID File |
|---|---------|------------------|------------------------|
| ✔ | Yes | Yes | No |
| ✔ | No | Yes | No |
| ✔ | No | No | Yes, optionally |
| ✘ | Yes | No | No |
> [!NOTE]
> PID files is one mechanism used to assert conditions to synchronize
> the start and stop of other, dependent, services.
### 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`).
### Runs in Foreground w/ PID File
service serv -n -p -- Foreground service w/ PID file
### Runs in Foreground w/o PID File
Same as previous, but we tell Finit to create the PID file, because we
need it to synchronize start/stop of a dependent service.
service pid:/run/serv.pid serv -n -- Foreground service w/o PID file
### Runs in Foreground w/ Custom PID File
service pid:/run/servy.pid serv -n -p -P /run/servy.pid -- Foreground service w/ custom PID file
State Machine State Machine
------------- -------------
@@ -64,8 +11,6 @@ For `run`s and `task`s there is an additional end state called `DONE`,
not shown in the diagram for brevity. Services start in the `HALTED` not shown in the diagram for brevity. Services start in the `HALTED`
state. state.
![The service state machine](svc-machine.png "The service state machine")
The current state depends on the two following conditions: The current state depends on the two following conditions:
* `E`: Service enabled. In order for `E` to be satisfied, the service * `E`: Service enabled. In order for `E` to be satisfied, the service
@@ -73,7 +18,7 @@ The current state depends on the two following conditions:
A service may be stopped, or blocked, for several reasons: A service may be stopped, or blocked, for several reasons:
- The user has manually stopped the service using `initctl stop NAME` - The user has manually stopped the service using `initctl stop JOB`
- The program exits immediately. I.e. keeps crashing (make sure to use - The program exits immediately. I.e. keeps crashing (make sure to use
the 'run this service in the foreground' command line option) the 'run this service in the foreground' command line option)
- The binary is missing in the filesystem - The binary is missing in the filesystem
+9 -17
View File
@@ -12,36 +12,28 @@ have been adopted:
Same effect as `finit q`, `init q`, or `initctl reload`, reloads all Same effect as `finit q`, `init q`, or `initctl reload`, reloads all
*.conf files in `/etc/finit.d/` *.conf files in `/etc/finit.d/`
This also restarts the API (initctl) socket, like SysV init and systemd
does on USR1 with their FIFO/D-Bus.
`SIGUSR1` `SIGUSR1`
--------- ---------
Since Finit 4.1 this signal causes Finit to restart its API (initctl) Calls shutdown hooks, including `HOOK_SHUTDOWN`, stopping all running
socket, like SysV init and systemd does on USR1 with their FIFO/D-Bus. processes, and unmounts all file systems. Then tells kernel to halt.
Most people these days want `SIGUSR2` though.
Finit <= 4.0 performed a system halt (like USR2 without power-off), but
this caused compatibility problems with systemd and sysvinit on desktop
systems. Hence, since Finit 4.1 it is no longer possible to halt a
system with a signal.
SysV init and systemd use this to re-open their FIFO/D-Bus.
`SIGUSR2` `SIGUSR2`
--------- ---------
Calls shutdown hooks, including `HOOK_SHUTDOWN`, stopping all running Like SIGUSR1, but tell kernel to power-off the system, if ACPI or
processes, and unmounts all file systems. Then tells kernel to power similar exists to actually do this. If the kernel fails power-off,
off the system, if ACPI or similar exists to actually do this. If the Finit falls back to halt.
kernel fails power-off, Finit falls back to halt.
SysV init N/A, systemd dumps its internal state to log. SysV init N/A, systemd dumps its internal state to log.
`SIGTERM` `SIGTERM`
--------- ---------
Like `SIGUSR2`, but tell kernel to reboot the system when done. Like `SIGUSR1`, but tell kernel to reboot the system when done.
SysV init N/A, systemd rexecutes itself. SysV init N/A, systemd rexecutes itself.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 320 KiB

After

Width:  |  Height:  |  Size: 16 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 814 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

-141
View File
@@ -1,141 +0,0 @@
_cond()
{
initctl -pt cond dump | awk '{print $4}' | sed 's/<\(.*\)>/\1/'
}
_ident()
{
if [ -n "$1" ]; then
initctl ident | grep -q $1
else
initctl ident
fi
}
_svc()
{
initctl ls -pt | grep $1 | sed "s/.*\/\(.*\)/\1/g" | sort -u
}
_enabled()
{
echo "$(_svc enabled)"
}
_available()
{
all=$(mktemp)
ena=$(mktemp)
echo "$(_svc available)" >$all
echo "$(_svc enabled)" >$ena
grep -v -f $ena $all
rm $all $ena
}
# Determine first non-option word. Usually the command
_firstword() {
local firstword i
firstword=
for ((i = 1; i < ${#COMP_WORDS[@]}; ++i)); do
if [[ ${COMP_WORDS[i]} != -* ]]; then
firstword=${COMP_WORDS[i]}
break
fi
done
echo $firstword
}
# Determine last non-option word. Uusally a sub-command
_lastword() {
local lastword i
lastword=
for ((i = 1; i < ${#COMP_WORDS[@]}; ++i)); do
if [[ ${COMP_WORDS[i]} != -* ]] && [[ -n ${COMP_WORDS[i]} ]] && [[ ${COMP_WORDS[i]} != $cur ]]; then
lastword=${COMP_WORDS[i]}
fi
done
echo $lastword
}
_initctl()
{
local cur command
cur=${COMP_WORDS[COMP_CWORD]}
prev="${COMP_WORDS[COMP_CWORD-1]}"
firstword=$(_firstword)
lastword=$(_lastword)
commands="status cond debug help kill ls log version list enable \
disable touch show cat edit create delete reload start \
stop restart signal cgroup ps top plugins runlevel reboot \
halt poweroff suspend utmp"
cond_cmds="set get clear status dump"
cond_types="hook net pid service task usr"
signals="int term hup stop tstp cont usr1 usr2 pwr"
options="-b --batch \
-c --create \
-d --debug \
-f --force \
-h --help \
-j --json \
-n --noerr \
-1 --once \
-p --plain \
-q --quiet \
-t --no-heading \
-v --verbose \
-V --version"
case "${firstword}" in
enable)
COMPREPLY=($(compgen -W "$(_available)" -- $cur))
;;
disable|touch)
COMPREPLY=($(compgen -W "$(_enabled)" -- $cur))
;;
show|cat|edit|delete)
COMPREPLY=($(compgen -W "$(_svc .)" -- $cur))
;;
start|stop|restart|log|status)
COMPREPLY=($(compgen -W "$(_ident)" -- $cur))
;;
signal|kill)
if $(_ident "${prev}"); then
COMPREPLY=($(compgen -W "$signals" -- $cur))
else
COMPREPLY=($(compgen -W "$(_ident)" -- $cur))
fi
;;
cond)
case "${lastword}" in
set|clear)
compopt -o nospace
COMPREPLY=($(compgen -W "usr/" -- $cur))
;;
get)
COMPREPLY=($(compgen -W "$(_cond)" -- $cur))
;;
dump)
COMPREPLY=($(compgen -W "$cond_types" -- $cur))
;;
*)
COMPREPLY=($(compgen -W "$cond_cmds" -- $cur))
;;
esac
;;
*)
COMPREPLY=($(compgen -W "$commands" -- $cur))
;;
esac
if [[ $cur == -* ]]; then
COMPREPLY=($(compgen -W "$options" -- $cur))
fi
}
complete -F _initctl initctl
-7
View File
@@ -1,7 +0,0 @@
.deps/*
.libs/*
.dirstamp
*.lo
libsystemd.*
Makefile
Makefile.in
-12
View File
@@ -1,12 +0,0 @@
# libsystemd replacement library
lib_LTLIBRARIES = libsystemd.la
libsystemd_la_SOURCES = sd-daemon.c sd-daemon.h
libsystemd_la_LDFLAGS = -version-info 0:0:0
# pkg-config support
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libsystemd.pc
# Install header to systemd/ subdirectory
systemddir = $(includedir)/systemd
systemd_HEADERS = sd-daemon.h
-10
View File
@@ -1,10 +0,0 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: libsystemd
Description: Finit replacement for systemd notification library
Version: @PACKAGE_VERSION@
Libs: -L${libdir} -lsystemd
Cflags: -I${includedir}
-217
View File
@@ -1,217 +0,0 @@
/* SPDX-License-Identifier: MIT-0 */
/*
* systemd notify protocol, supporting readiness notification on startup
* and reloading, according to the protocol defined at:
* https://www.freedesktop.org/software/systemd/man/latest/sd_notify.html
*
* This protocol is guaranteed to be stable as per:
* https://systemd.io/PORTABILITY_AND_STABILITY/
*/
#define _GNU_SOURCE 1
#include <errno.h>
#include <inttypes.h>
#include <signal.h>
#include <stdbool.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <time.h>
#include <unistd.h>
#include "sd-daemon.h"
/*
* NOTE: As per spec., this function does not return POSIX OK(0) but
* rather "a positive value", i.e., 1.
*/
int sd_notify(int unset_environment, const char *state)
{
struct sockaddr_un sun = {
.sun_family = AF_UNIX,
};
size_t len, sun_len;
const char *path;
ssize_t written;
int sd;
if (!state)
return -EINVAL;
len = strlen(state);
if (len == 0)
return -EINVAL;
/* If the variable is not set, the protocol is a noop */
path = getenv("NOTIFY_SOCKET");
if (!path)
return 0; /* Not set? Nothing to do */
/* Only AF_UNIX is supported, with path or abstract sockets */
if (path[0] != '/' && path[0] != '@')
return -EAFNOSUPPORT;
/* Ensure there is room for NUL byte */
sun_len = strlen(path);
if (sun_len >= sizeof(sun.sun_path))
return -E2BIG;
strlcpy(sun.sun_path, path, sizeof(sun.sun_path));
if (sun.sun_path[0] == '@')
sun.sun_path[0] = 0;
sd = socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (sd == -1)
return -errno;
if (connect(sd, (struct sockaddr *)&sun, offsetof(struct sockaddr_un, sun_path) + sun_len) == -1) {
close(sd);
return -errno;
}
if (unset_environment)
unsetenv("NOTIFY_SOCKET");
written = write(sd, state, len);
if (written != (ssize_t) len) {
close(sd);
return written < 0 ? -errno : -EPROTO;
}
return 1;
}
/*
* Printf-style notification function
*/
int sd_notifyf(int unset_environment, const char *format, ...)
{
va_list ap;
char *state;
int ret;
if (!format)
return -EINVAL;
va_start(ap, format);
ret = vasprintf(&state, format, ap);
va_end(ap);
if (ret < 0)
return -ENOMEM;
ret = sd_notify(unset_environment, state);
free(state);
return ret;
}
/*
* PID-specific notification function
*/
int sd_pid_notify(pid_t pid, int unset_environment, const char *state)
{
char path[256], *env;
size_t len;
int ret;
if (!state)
return -EINVAL;
len = strlen(state);
if (len == 0)
return -EINVAL;
if (pid == 0)
pid = getpid();
env = getenv("NOTIFY_SOCKET");
if (env) {
env = strdup(env);
if (!env)
return -errno;
}
snprintf(path, sizeof(path), "@run/finit/notify/%d", pid);
setenv("NOTIFY_SOCKET", path, 1);
ret = sd_notify(unset_environment, state);
if (env) {
setenv("NOTIFY_SOCKET", env, 1);
free(env);
}
return ret;
}
/*
* PID-specific printf-style notification function
*/
int sd_pid_notifyf(pid_t pid, int unset_environment, const char *format, ...)
{
va_list ap;
char *state;
int ret;
if (!format)
return -EINVAL;
va_start(ap, format);
ret = vasprintf(&state, format, ap);
va_end(ap);
if (ret < 0)
return -ENOMEM;
ret = sd_pid_notify(pid, unset_environment, state);
free(state);
return ret;
}
/*
* Socket activation stub - Finit doesn't support socket activation yet
* Returns 0 (no file descriptors passed)
*/
int sd_listen_fds(int unset_environment)
{
if (unset_environment) {
unsetenv("LISTEN_PID");
unsetenv("LISTEN_FDS");
unsetenv("LISTEN_FDNAMES");
}
return 0;
}
/*
* Watchdog stub - Finit doesn't support watchdog yet
* Returns 0 (no watchdog enabled)
*/
int sd_watchdog_enabled(int unset_environment, uint64_t *usec)
{
if (unset_environment) {
unsetenv("WATCHDOG_PID");
unsetenv("WATCHDOG_USEC");
}
if (usec)
*usec = 0;
return 0;
}
/*
* System detection function
* Returns 1 to indicate systemd compatibility (trick applications)
*/
int sd_booted(void)
{
return 1;
}
-38
View File
@@ -1,38 +0,0 @@
#ifndef SD_DAEMON_H_
#define SD_DAEMON_H_
#include <stdint.h>
#include <sys/types.h>
#define SD_LISTEN_FDS_START 3
/* systemd logging defines for stderr parsing by Finit */
#define SD_EMERG "<0>" /* system is unusable */
#define SD_ALERT "<1>" /* action must be taken immediately */
#define SD_CRIT "<2>" /* critical conditions */
#define SD_ERR "<3>" /* error conditions */
#define SD_WARNING "<4>" /* warning conditions */
#define SD_NOTICE "<5>" /* normal but significant condition */
#define SD_INFO "<6>" /* informational */
#define SD_DEBUG "<7>" /* debug-level messages */
/* Basic notification function */
int sd_notify(int unset_environment, const char *state);
/* Printf-style notification functions */
int sd_notifyf(int unset_environment, const char *format, ...);
/* PID-specific notification functions */
int sd_pid_notify(pid_t pid, int unset_environment, const char *state);
int sd_pid_notifyf(pid_t pid, int unset_environment, const char *format, ...);
/* Socket activation stubs */
int sd_listen_fds(int unset_environment);
/* Watchdog stub */
int sd_watchdog_enabled(int unset_environment, uint64_t *usec);
/* System detection */
int sd_booted(void);
#endif /* SD_DAEMON_H_ */
+23 -19
View File
@@ -1,6 +1,8 @@
# From https://github.com/collectd/collectd/blob/master/configure.ac # From https://github.com/collectd/collectd/blob/master/configure.ac
# Dependency handling currently unused # Dependency handling currently unused
define([toupper], [translit([$1], [a-z], [A-Z])])
define([sanitize], [translit([$1], [-], [_])])
define([enadis], [ifelse([$1], [yes], [disable], [enable])]) define([enadis], [ifelse([$1], [yes], [disable], [enable])])
# AC_PLUGIN(name, default, info) # AC_PLUGIN(name, default, info)
@@ -8,25 +10,27 @@ define([enadis], [ifelse([$1], [yes], [disable], [enable])])
AC_DEFUN([AC_PLUGIN],[ AC_DEFUN([AC_PLUGIN],[
m4_divert_once([HELP_ENABLE], [ m4_divert_once([HELP_ENABLE], [
Optional Plugins:]) Optional Plugins:])
define(PLUGGY, m4_translit([$1],[a-z-][A-Z-]))dnl
AC_ARG_ENABLE([$1-plugin], AS_HELP_STRING([--enadis($2)-$1-plugin], [$3]), [
if test "x$enableval" = "xyes"; then
enable_plugin="yes"
else
enable_plugin="no" enable_plugin="no"
fi], [ define(pluggy, sanitize($1))
if test "x$enable_all_plugins" = "xauto"; then define(PLUGGY, toupper(pluggy))
if test "x$2" = "xyes"; then AC_ARG_ENABLE([$1-plugin], AS_HELP_STRING([--enadis($2)-$1-plugin], [$3]), [
enable_plugin="yes" if test "x$enableval" = "xyes"; then
enable_plugin="yes"
else else
enable_plugin="no" enable_plugin="no"
fi], [
if test "x$enable_all_plugins" = "xauto"; then
if test "x$2" = "xyes"; then
enable_plugin="yes"
else
enable_plugin="no"
fi
else
enable_plugin="$enable_all_plugins"
fi])
if test "x$enable_plugin" = "xyes"; then
AC_DEFINE([HAVE_]PLUGGY[_PLUGIN], 1, [Define to 1 if the $1 plugin is enabled.])
plugins="$1 $plugins"
fi fi
else AM_CONDITIONAL([BUILD_]PLUGGY[_PLUGIN], test "x$enable_plugin" = "xyes")
enable_plugin="$enable_all_plugins" enable_pluggy="$enable_plugin"])
fi])
if test "x$enable_plugin" = "xyes"; then
AC_DEFINE(HAVE_[]m4_translit($1,[-a-z],[_A-Z])_PLUGIN, 1, [Define to 1 if the $1 plugin is enabled.])
plugins="$1 $plugins"
fi
AM_CONDITIONAL(BUILD_[]m4_translit($1,[-a-z],[_A-Z])_PLUGIN, test "x$enable_plugin" = "xyes")])
-2
View File
@@ -1,2 +0,0 @@
Makefile
Makefile.in
-2
View File
@@ -1,2 +0,0 @@
dist_man8_MANS = finit.8 initctl.8
dist_man5_MANS = finit.conf.5
-348
View File
@@ -1,348 +0,0 @@
.\" Hey, EMACS: -*- nroff -*-
.\" First parameter, NAME, should be all caps
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
.\" other parameters are allowed: see man(7), man(1)
.Dd Apr 22, 2023
.\" Please adjust this date whenever revising the manpage.
.Dt FINIT 8 SMM
.Os Linux
.Sh NAME
.Nm finit
.Nd Fast init for Linux systems
.Sh SYNOPSIS
.Nm /sbin/finit
.Op --
.Op debug
.Op finit.cond=foo[,bar[,baz]]
.Op finit.config=/path/to/alt/finit.conf
.Op finit.debug
.Op finit.fstab=/etc/fstab.alt
.Op finit.status=<on,off>
.Op finit.status_style=<classic,modern>
.Op loglevel=<0-7>
.Op panic=SEC
.Op quiet
.Op rescue | recover
.Op single | S
.Nm /sbin/telinit
.Op Fl hv
.Op q | Q | 0-9
.Sh DESCRIPTION
Fast init for Linux systems. Reverse engineered from the EeePC
fastinit, 10+ years ago by Claudio Matsuoka, "gaps filled with frog
DNA ...". Focus is on small and embedded systems, although Finit is
fully usable on server and desktop systems as well.
.Pp
Features include:
.Bl -bullet -width 1n -compact
.It
Runlevels, defined per service
.It
One-shot tasks, services (daemons), or SysV init start/stop scripts
.It
Runparts and
.Pa /etc/rc.local
support
.It
Process supervision similar to
.Xr systemd 8
.It
Sourcing environment files
.It
Conditions for network/process/custom dependencies
.It
Process readiness notification for synchronizing system startup as well
as reconfiguration at runtime. Natively PID files are used, but systemd
.Cm sd_notify()
and s6 notification is also supported.
.It
Limited support for
.Xr tmpfiles.d 5 ,
no aging, attributes, or subvolumes
.It
Pre/Post script actions
.It
Tooling to enable/disable services
.It
Built-in getty
.It
Built-in watchdog, with support for hand-over to
.Lk https://troglobit.com/watchdogd.html watchdogd
.It
Built-in support for Debian/BusyBox
.Pa /etc/network/interfaces
.It
Cgroups v2, both configuration and monitoring in `initctl top`
.It
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 debug
Enable kernel debug. Debug messages are printed to the console until
Finit starts up, unless
.Cm loglevel=7
(below) is used.
.It Cm finit.cond=foo[,bar[,baz]]
set
.Cm <boot/foo>
condition, optionally multiple conditions can be set using the same
option, separated with a comma. Alternatively, multiple
.Cm foo.cond=arg
can be given. Each will result in a
.Cm <boot/arg>
condition being set to control the rest of the system bootstrap.
.Pp
Very useful for selecting different boot modes, e.g. manufacturing test,
firmware upgrade, or rescue mode.
.Pp
.Sy Note:
.Cm <boot/...>
conditions cannot be cleared with
.Nm initctl !
.It Cm finit.config=/path/to/alternative/finit.conf
override the compile-time bootstrap config file, default:
.Bd -unfilled -offset indent
./configure --with-config=/etc/finit.conf
.Ed
Useful when starting up in various rescue mode, factory, or
production test setups. Use the top-level configuration file
directive
.Cm rcsd Ar /path/to/finit.d
to override the default rcS.d directory.
.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 loglevel=<0-7>
set the kernel's log level, which is more granular than
.Cm debug .
Also, when
.Cm loglevel=7 ,
Finit will
.Em not disable
kernel logs to the console. This is very useful when debugging the
kernel at system bring-up. Since
.Cm loglevel=7
is the same as
.Cm debug
this means you have to use
.Cm quiet
for a quiet boot, until sysklogd takes over logging of kernel events.
.It Cm panic=SEC
By default the kernel does not reboot after a kernel panic. This
setting will cause a kernel reboot after
.Ar SEC
seconds.
.It Cm quiet
Suppress kernel logging to console, except for warnings and errors.
Also, see
.Cm loglevel
and
.Cm quiet
above.
.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.
.Pp
.Sy Note:
by definition, single user mode does not have networking enabled. This
is also true for runlevel 1.
.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 ,
.Pa /sys ,
and
.Pa /run
are available and can provide the system with the services required.
.Pp
With that out of the way, a set of plugins take over:
.Pp
.Bl -tag -width bootmisc.so -offset indent
.It Cm bootmisc.so
Cleans up stale files from previous boots and default directories are
created in tmpfs filesystems
.It Cm modprobe.so
Probes kernel modules required by the system
.It Cm procps.so
Set kernel variables from
.Pa /etc/sysctl.conf
et al
.El
.Pp
When the plugins are done, finit reads
.Pa /etc/finit.conf
and all other enabled services in
.Pa /etc/finit.d/* .
First all services, run/tasks in runlevel S (bootStrap) are started,
When all run/tasks have completed, Finit changes to the configured
runlevel (default 2), Processes are started in parallel, in dependency
order according to their conditions.
.Pp
When all services and run/tasks have been started, the console progress
is disabled and all configured getty services are started.
.Sh CONDITIONS
The condition subysystem in Finit was initially created to track PID
files of daemons. If service/task B requires service A to have started,
Finit waits for the PID file of service A to be created/updated before
it starts service B. Conversely, if service A is stopped and its PID
file removed, service B is also stopped.
.Pp
The following condition families are available today:
.Pp
.Bl -tag -width service -offset indent
.It Cm net
Linux netlink events, e.g. net/route/default, net/eth0/up, and
net/et0/running
.It Cm pid
PID files based on the service declaration
.Cm name:id ,
gives the condition pid/name:id
.It Cm service
Tracks run/task/service state stansitions, including readiness. E.g.,
.Cm service/foo/ready
can be used as a condition for service
.Cm bar ,
provided
.Cm foo
properly signals its readiness to Finit.
.It Cm sys
System conditions, e.g. sys/key/ctrlaltdel and sys/pwr/fail
.It Cm usr
User conditions, assert and deassert using
.Cm initctl cond [set|clr] foo
.El
.Sh SIGNALS
PID 1 is the only process that by default blocks all signals. Finit
allows for the following signals to control operation, but recommends
instead using the
.Xr initctl 8
tool.
.Pp
.Bl -tag -width TERM
.It HUP
Tell
.Nm
to reload its configuration file(s), same as
.Cm initctl reload
.It USR1
Restart API
.Cm ( initctl )
socket.
.It USR2
Tell
.Nm
to perform a system shutdown, same as
.Cm initctl poweroff
.It TERM
Like SIGUSR2 but performs a reboot, same as
.Cm initctl reboot
.It INT
Sent from kernel when Ctrl-Alt-Del is pressed (on the console), this
asserts the sys/key/ctrlaltdel condition, which can be used to start
tasks or services
.It PWR
Sent from a a power daemon on changes to UPS status, Finit asserts
the sys/pwr/fail condition
.El
.Sh FILES
.Bl -tag -width /etc/finit.d/available/*.conf -compact
.It Pa /etc/finit.conf
Main configuration file
.It Pa /etc/finit.d/*.conf
Static service definitions
.It Pa /etc/finit.d/available/*.conf
Available services
.It Pa /etc/finit.d/enabled/*.conf
Symlinks from available
.It Pa /run/finit/
Runtime files, including the condition subsystem
.El
.Sh SEE ALSO
.Xr finit.conf 5
.Xr initctl 8
.Xr tmpfiles.d 5
.Sh AUTHORS
.Nm
was conceived and reverse engineered by Claudio Matsuoka. Since v1.0,
maintained by Joachim Wiberg, with contributions by many others.
-1003
View File
File diff suppressed because it is too large Load Diff
-277
View File
@@ -1,277 +0,0 @@
.\" Hey, EMACS: -*- nroff -*-
.\" First parameter, NAME, should be all caps
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
.\" other parameters are allowed: see man(7), man(1)
.Dd June 6, 2021
.\" Please adjust this date whenever revising the manpage.
.Dt INITCTL 8 SMM
.Os Linux
.Sh NAME
.Nm initctl
.Nd Control tool for Finit
.Sh SYNOPSIS
.Nm /sbin/initctl
.Op Fl bcfhjlpqtvV
.Op COMMAND
.Sh DESCRIPTION
.Nm
is the official tool for interacting with
.Xr finit 8 .
It comes with functions for showing status, querying health of services,
as well as editing, enabling and disabling services.
.Sh OPTIONS
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.
.It Fl c, -create
Create missing paths (and files) as needed. Useful with the
.Cm edit
command.
.It Fl f, -force
Ignore missing files and arguments, never prompt.
.It Fl h, -help
Show built-in help text.
.It Fl j, -json
JSON output in
.Ar status
and
.Ar cond
commands.
.It Fl n, -noerr
When scripting
.Nm
to stop, start, restart, or signal a task or service, this option can be
used to ignore error 69 (no such task or service) and instead return 0
(OK).
.It Fl 1, -once
Only one lap in commands like top.
.It Fl p, -plain
Use plain table headings, no ANSI control characters.
.It Fl q, -quiet
Silent, only return status of command.
.It Fl t, -no-heading
Skip table headings.
.It Fl v, -verbose
Verbose output, where applicable.
.It Fl V, -version
Show program version.
.El
.Sh COMMANDS
.Bl -tag -width Ds
.It Nm Ar debug
Toggle
.Nm finit
(daemon) debug to
.Pa /dev/console
.It Nm Ar help
Show built-in help text.
.It Nm Ar version
Show program version.
.It Nm Ar ls | list
List all
.Cm *.conf
files in
.Pa /etc/finit.d
.It Nm Ar create Ar CONF
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
.It Nm Ar delete Ar CONF
Delete
.Cm .conf
in
.Pa /etc/finit.d/available
.It Nm Ar show Ar CONF
Show
.Cm .conf
in
.Pa /etc/finit.d/available
.It Nm Ar edit Ar CONF
Edit
.Cm .conf
in
.Pa /etc/finit.d/available
.It Nm Ar touch Ar CONF
Change (mark as modified)
.Cm .conf
in
.Pa /etc/finit.d/available ,
like
.Ar edit
this tells
.Nm finit
that a configuration has been changed and is a candidate to be restarted
(or SIGHUP'ed) on
.Cm initctl reload
.It Nm Ar enable Ar CONF
Enable
.Cm .conf
in
.Pa /etc/finit.d/available ,
i.e., add symlink in
.Pa /etc/finit.d/enabled
.It Nm Ar disable Ar CONF
Disable
.Cm .conf
in
.Pa /etc/finit.d/enabled ,
i.e., removes symlink.
.It Nm Ar reload
Reload
.Cm *.conf in
.Pa /etc/finit.d ,
i.e., activates changes.
.It Nm Ar cond set Ar COND Op 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: 0 - on, 1 - off, 255 - flux. For a more
verbose output, use the
.Fl v
option.
.It Nm Ar cond clr | clear Ar COND Op COND ...
Clear (deassert) user-defined condition,
.Cm -usr/COND
.It Nm Ar cond status
Show condition status, default
.Cm cond
command. Also supports the
.Fl j
option for detailed JSON output.
.It Nm Ar cond dump Op Cm TYPE
Dump all, or a given type of, conditions and their status. Also
supports the
.Fl j
option for detailed JSON output.
.It Nm Ar ident Op Cm NAME
Display indentities of all run/task/services, or only instances
matching
.Cm NAME .
A partial string, e.g.,
.Cm NAM ,
will not match anything.
.It Nm Ar log Op Cm NAME
Show ten last Finit, or
.Cm NAME ,
messages from syslog.
.It Nm Ar start Cm NAME[:ID]
Start service by name, with optional ID, e.g.,
.Cm initctl start tty:1
.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
.It Nm Ar signal Cm NAME:[ID] S
Send signal S to service, by name.
.Cm S
may be a complete signal name such as SIGHUP, or short name such as HUP, or the signal number such as 1 (SIGHUP).
.It Nm Ar restart Cm NAME[:ID]
Restart (stop/start) service by name.
.It Nm Ar status Cm NAME[:ID]
Show service status, by name. If only
.Cm NAME
is given and multiple instances exits, a summary of all matching
instances are shown. Only an exact match displays detailed status
for a given instance.
.Pp
With the
.Fl q
option this command is silent, provided the
.Ar NAME[:ID]
selection matches a single run/task/service. The exit code of
.Nm
is non-zero if there is a problem. Zero is returned if a run/task has
run (at least) once in the current runlevel, and when a service is running
(as expected). See the
.Fl j
option for detailed JSON output suitable for machine parsing.
.Pp
.Sy Tip:
.Xr jq 1
is a useful scripting tool in combination with JSON output.
.It Nm Ar status
Show status of all services, default command. Also supports the
.Fl j
option for detailed JSON output.
.It Nm Ar cgroup
List cgroup config overview.
.It Nm Ar ps
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.
.Pp
If called at boot (runlevel S) to set the runlevel, Finit only schedules
the change, effectively overriding the configured runlevel from
.Pa /etc/finit.conf .
Useful to trigger a fail-safe mode, or similar.
.It Nm Ar reboot
Reboot system, default if
.Cm reboot
is symlinked to
.Nm .
.It Nm Ar halt
Halt system, default if
.Cm halt
is symlinked to
.Nm .
.It Nm Ar poweroff
Power-off system, default if
.Cm poweroff
is symlinked to
.Nm .
.It Nm Ar suspend
Suspend system, default if
.Cm suspend
is symlinked to
.Nm .
.It Nm Ar utmp show
Raw dump of UTMP/WTMP db.
.El
.Sh SEE ALSO
.Xr finit.conf 5
.Xr finit 8
.Sh AUTHORS
.Nm finit
was conceived and reverse engineered by Claudio Matsuoka. Since v1.0,
maintained by Joachim Wiberg, with contributions by many others.
+10 -42
View File
@@ -1,13 +1,13 @@
pkglibdir = $(plugin_path) pkglibdir = $(plugin_path)
AM_LDFLAGS = -module -avoid-version -shared AM_LDFLAGS = -module -avoid-version -shared
AM_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99 AM_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
AM_CPPFLAGS = -I$(top_srcdir)/src AM_CPPFLAGS = -I$(top_srcdir)/src -U_FORTIFY_SOURCE
AM_CPPFLAGS += -D_XOPEN_SOURCE=600 -D_BSD_SOURCE -D_GNU_SOURCE -D_DEFAULT_SOURCE AM_CPPFLAGS += -D_XOPEN_SOURCE=600 -D_BSD_SOURCE -D_GNU_SOURCE -D_DEFAULT_SOURCE
AM_CPPFLAGS += -D__FINIT__ $(lite_CFLAGS) $(uev_CFLAGS) AM_CPPFLAGS += $(lite_CFLAGS)
if STATIC if STATIC
noinst_LTLIBRARIES = libplug.la noinst_LTLIBRARIES = libplug.la
libplug_la_SOURCES = bootmisc.c pidfile.c procps.c sys.c usr.c libplug_la_SOURCES = bootmisc.c modprobe.c rtc.c pidfile.c procps.c tty.c urandom.c
if BUILD_ALSA_UTILS_PLUGIN if BUILD_ALSA_UTILS_PLUGIN
libplug_la_SOURCES += alsa-utils.c libplug_la_SOURCES += alsa-utils.c
@@ -17,12 +17,12 @@ if BUILD_DBUS_PLUGIN
libplug_la_SOURCES += dbus.c libplug_la_SOURCES += dbus.c
endif endif
if BUILD_MODULES_LOAD_PLUGIN if BUILD_HOTPLUG_PLUGIN
libplug_la_SOURCES += modules-load.c libplug_la_SOURCES += hotplug.c
endif endif
if BUILD_MODPROBE_PLUGIN if BUILD_MODULES_LOAD_PLUGIN
libplug_la_SOURCES += modprobe.c libplug_la_SOURCES += modules-load.c
endif endif
if BUILD_NETLINK_PLUGIN if BUILD_NETLINK_PLUGIN
@@ -33,24 +33,8 @@ if BUILD_RESOLVCONF_PLUGIN
libplug_la_SOURCES += resolvconf.c libplug_la_SOURCES += resolvconf.c
endif endif
if BUILD_RTC_PLUGIN
libplug_la_SOURCES += rtc.c
endif
if BUILD_TTY_PLUGIN
libplug_la_SOURCES += tty.c
endif
if BUILD_URANDOM_PLUGIN
libplug_la_SOURCES += urandom.c
endif
if BUILD_X11_COMMON_PLUGIN
libplug_la_SOURCES += x11-common.c
endif
else else
pkglib_LTLIBRARIES = bootmisc.la pidfile.la procps.la sys.la usr.la pkglib_LTLIBRARIES = bootmisc.la modprobe.la rtc.la pidfile.la procps.la tty.la urandom.la
if BUILD_ALSA_UTILS_PLUGIN if BUILD_ALSA_UTILS_PLUGIN
pkglib_LTLIBRARIES += alsa-utils.la pkglib_LTLIBRARIES += alsa-utils.la
@@ -60,18 +44,14 @@ if BUILD_DBUS_PLUGIN
pkglib_LTLIBRARIES += dbus.la pkglib_LTLIBRARIES += dbus.la
endif endif
if BUILD_HOOK_SCRIPTS_PLUGIN if BUILD_HOTPLUG_PLUGIN
pkglib_LTLIBRARIES += hook-scripts.la pkglib_LTLIBRARIES += hotplug.la
endif endif
if BUILD_MODULES_LOAD_PLUGIN if BUILD_MODULES_LOAD_PLUGIN
pkglib_LTLIBRARIES += modules-load.la pkglib_LTLIBRARIES += modules-load.la
endif endif
if BUILD_MODPROBE_PLUGIN
pkglib_LTLIBRARIES += modprobe.la
endif
if BUILD_NETLINK_PLUGIN if BUILD_NETLINK_PLUGIN
pkglib_LTLIBRARIES += netlink.la pkglib_LTLIBRARIES += netlink.la
endif endif
@@ -80,18 +60,6 @@ if BUILD_RESOLVCONF_PLUGIN
pkglib_LTLIBRARIES += resolvconf.la pkglib_LTLIBRARIES += resolvconf.la
endif endif
if BUILD_RTC_PLUGIN
pkglib_LTLIBRARIES += rtc.la
endif
if BUILD_TTY_PLUGIN
pkglib_LTLIBRARIES += tty.la
endif
if BUILD_URANDOM_PLUGIN
pkglib_LTLIBRARIES += urandom.la
endif
if BUILD_X11_COMMON_PLUGIN if BUILD_X11_COMMON_PLUGIN
pkglib_LTLIBRARIES += x11-common.la pkglib_LTLIBRARIES += x11-common.la
endif endif
+6 -21
View File
@@ -1,6 +1,6 @@
/* Save and restore ALSA sound settings using alsactl /* Save and restore ALSA sound settings using alsactl
* *
* Copyright (c) 2012-2024 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 * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -21,12 +21,7 @@
* THE SOFTWARE. * THE SOFTWARE.
*/ */
#ifdef _LIBITE_LITE #include <lite/lite.h>
# include <libite/lite.h>
#else
# include <lite/lite.h>
#endif
#include "finit.h" #include "finit.h"
#include "helpers.h" #include "helpers.h"
#include "plugin.h" #include "plugin.h"
@@ -35,26 +30,16 @@
static void save(void *arg) static void save(void *arg)
{ {
if (rescue) {
dbg("Skipping %s plugin in rescue mode.", __FILE__);
return;
}
if (whichp(ALSACTL)) { if (whichp(ALSACTL)) {
dbg("Saving sound settings ..."); _d("Saving sound settings ...");
run_interactive(ALSACTL " -g store", "Saving sound settings"); run_interactive(ALSACTL " -g store", "Saving sound settings");
} }
} }
static void restore(void *arg) static void restore(void *arg)
{ {
if (rescue) {
dbg("Skipping %s plugin in rescue mode.", __FILE__);
return;
}
if (whichp(ALSACTL)) { if (whichp(ALSACTL)) {
dbg("Restoring sound settings ..."); _d("Restoring sound settings ...");
run_interactive(ALSACTL " -g restore", "Restoring sound settings"); run_interactive(ALSACTL " -g restore", "Restoring sound settings");
} }
} }
@@ -65,12 +50,12 @@ static plugin_t plugin = {
.hook[HOOK_SHUTDOWN] = { .cb = save } .hook[HOOK_SHUTDOWN] = { .cb = save }
}; };
PLUGIN_INIT(__init) PLUGIN_INIT(plugin_init)
{ {
plugin_register(&plugin); plugin_register(&plugin);
} }
PLUGIN_EXIT(__exit) PLUGIN_EXIT(plugin_exit)
{ {
plugin_unregister(&plugin); plugin_unregister(&plugin);
} }
+99 -75
View File
@@ -1,6 +1,6 @@
/* Setup necessary system files for, e.g. UTMP (tracking logins) /* Setup necessary system files for, e.g. UTMP (tracking logins)
* *
* Copyright (c) 2012-2024 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 * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -21,18 +21,10 @@
* THE SOFTWARE. * THE SOFTWARE.
*/ */
#include "config.h" /* Generated by configure script */
#include <ftw.h> #include <ftw.h>
#ifdef HAVE_MNTENT_H
#include <mntent.h> #include <mntent.h>
#endif
#include <string.h> #include <string.h>
#ifdef _LIBITE_LITE #include <lite/lite.h>
# include <libite/lite.h>
#else
# include <lite/lite.h>
#endif
#include "config.h" #include "config.h"
#include "finit.h" #include "finit.h"
@@ -43,12 +35,10 @@
static int is_tmpfs(char *path) static int is_tmpfs(char *path)
{ {
struct mntent mount;
struct mntent *mnt;
char buf[256];
int tmpfs = 0; int tmpfs = 0;
FILE *fp; FILE *fp;
char *dir; char *dir;
struct mntent *mnt;
/* If path is a symlink, check what it resolves to */ /* If path is a symlink, check what it resolves to */
dir = realpath(path, NULL); dir = realpath(path, NULL);
@@ -61,7 +51,7 @@ static int is_tmpfs(char *path)
return 0; /* Dunno, maybe not */ return 0; /* Dunno, maybe not */
} }
while ((mnt = getmntent_r(fp, &mount, buf, sizeof(buf)))) { while ((mnt = getmntent(fp))) {
if (!strcmp(dir, mnt->mnt_dir)) if (!strcmp(dir, mnt->mnt_dir))
break; break;
} }
@@ -75,25 +65,19 @@ static int is_tmpfs(char *path)
return tmpfs; return tmpfs;
} }
static int bootclean(const char *fpath, const struct stat *sb, int tflag, struct FTW *ftw) static int do_clean(const char *fpath, const struct stat *sb, int tflag, struct FTW *ftw)
{ {
if (ftw->level == 0) if (ftw->level == 0)
return 1; return 1;
dbg("Removing %s ...", fpath); _d("Removing %s ...", fpath);
(void)remove(fpath); (void)remove(fpath);
return 0; return 0;
} }
/* /* We can safely skip tmpfs, nothing to clean from previous boot there */
* Cleanup stale files from previous boot, if any still linger on. static void bootclean(void)
* Some systems, e.g. Alpine Linux, still have a persistent /run and
* /tmp, i.e. not tmpfs.
*
* We can safely skip tmpfs, nothing to clean there.
*/
static void clean(void *arg)
{ {
char *dir[] = { char *dir[] = {
"/tmp/", "/tmp/",
@@ -106,46 +90,7 @@ static void clean(void *arg)
if (is_tmpfs(dir[i])) if (is_tmpfs(dir[i]))
continue; continue;
nftw(dir[i], bootclean, 20, FTW_DEPTH); nftw(dir[i], do_clean, 20, FTW_DEPTH);
}
}
/* 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);
} }
} }
@@ -154,35 +99,114 @@ static void kernel_links(void)
*/ */
static void setup(void *arg) static void setup(void *arg)
{ {
mode_t prev; int uid, gid;
prev = umask(0); /* Cleanup stale files, if any still linger on. */
bootclean();
/* Kernel symlinks, e.g. /proc/self/fd -> /dev/fd */ _d("Setting up FHS structure in /var ...");
kernel_links(); umask(0);
makedir("/var/cache", 0755);
makedir("/var/db", 0755); /* _PATH_VARDB on some systems */
makedir("/var/games", 0755);
makedir("/var/lib", 0755);
makedir("/var/lib/misc", 0755); /* _PATH_VARDB on some systems */
makedir("/var/lib/alarm", 0755);
makedir("/var/lib/urandom",0755);
if (fisdir("/run")) {
_d("System with new /run tmpfs ...");
makedir("/run/lock", 1777);
symlink("/run/lock", "/var/lock");
symlink("/dev/shm", "/run/shm");
/* Create all system tmpfiles.d(5) */ /* compat only, should really be set up by OS/dist */
run_interactive(_PATH_TMPFILES " --create", "Creating required directories and files"); symlink("/run", "/var/run");
} else {
makedir("/var/lock", 1777);
makedir("/var/run", 0755);
}
makedir("/var/log", 0755);
makedir("/var/mail", 0755);
makedir("/var/opt", 0755);
makedir("/var/spool", 0755);
makedir("/var/spool/cron", 0755);
makedir("/var/tmp", 0755);
makedir("/var/empty", 0755);
/*
* If /etc/group or "utmp" group is missing,
* default to "root"/"wheel" group
*/
_d("Setting up necessary UTMP files ...");
gid = getgroup("utmp");
if (gid < 0)
gid = 0;
/*
* UTMP actually needs multiple db files
*/
if (has_utmp()) {
create("/var/run/utmp", 0644, 0, gid); /* Currently logged in */
create("/var/log/wtmp", 0644, 0, gid); /* Login history */
create("/var/log/btmp", 0600, 0, gid); /* Failed logins */
create("/var/log/lastlog", 0644, 0, gid);
}
/* Set BOOT_TIME UTMP entry */ /* Set BOOT_TIME UTMP entry */
utmp_set_boot(); utmp_set_boot();
umask(prev); #ifdef TOUCH_ETC_NETWORK_RUN_IFSTATE
touch("/etc/network/run/ifstate");
#else
erase("/etc/network/run/ifstate");
#endif
_d("Setting up misc files ...");
makedir("/var/run/network",0755); /* Needed by Debian/Ubuntu ifupdown */
makedir("/var/run/lldpd", 0755); /* Needed by lldpd */
makedir("/var/run/pluto", 0755); /* Needed by Openswan */
makedir("/var/run/quagga", 0755); /* Needed by Quagga */
makedir("/var/log/quagga", 0755); /* Needed by Quagga */
makedir("/var/run/frr", 0755); /* Needed by FRR */
makedir("/var/log/frr", 0755); /* Needed by FRR */
makedir("/var/run/sshd", 01755); /* OpenSSH */
gid = getgroup("tty");
if (gid < 0)
gid = 0;
makefifo("/dev/xconsole", 0640); /* sysklogd */
chown("/dev/xconsole", 0, gid);
if (!fexist("/etc/mtab"))
symlink("../proc/self/mounts", "/etc/mtab");
/* Void Linux has a uuidd that runs as uuid:uuid and needs /run/uuid */
uid = getuser("uuidd", NULL);
if (uid >= 0) {
gid = getgroup("uuidd");
if (gid < 0)
gid = 0;
makedir("/var/run/uuidd", 0755);
chown("/var/run/uuidd", uid, gid);
}
umask(022);
} }
static plugin_t plugin = { static plugin_t plugin = {
.name = __FILE__, .name = __FILE__,
.hook[HOOK_MOUNT_POST] = { .cb = clean }, .hook[HOOK_BASEFS_UP] = {
.hook[HOOK_BASEFS_UP] = { .cb = setup }, .cb = setup
},
.depends = { "pidfile" }, .depends = { "pidfile" },
}; };
PLUGIN_INIT(__init) PLUGIN_INIT(plugin_init)
{ {
plugin_register(&plugin); plugin_register(&plugin);
} }
PLUGIN_EXIT(__exit) PLUGIN_EXIT(plugin_exit)
{ {
plugin_unregister(&plugin); plugin_unregister(&plugin);
} }
+28 -120
View File
@@ -1,6 +1,6 @@
/* Setup and start system message bus, D-Bus /* Setup and start system message bus, D-Bus
* *
* Copyright (c) 2012-2024 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 * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -22,11 +22,7 @@
*/ */
#include <sys/types.h> #include <sys/types.h>
#ifdef _LIBITE_LITE #include <lite/lite.h>
# include <libite/lite.h>
#else
# include <lite/lite.h>
#endif
#include "finit.h" #include "finit.h"
#include "config.h" #include "config.h"
@@ -35,143 +31,55 @@
#include "service.h" #include "service.h"
#include "conf.h" #include "conf.h"
#define DBUS_DAEMON "dbus-daemon" #define DAEMON "dbus-daemon"
#define DBUS_ARGS "--nofork --system --syslog-only" #define ARGS "--nofork --system"
#define DBUS_DESC "D-Bus message bus daemon" #define DESC "D-Bus message bus daemon"
#ifndef DBUS_DAEMONUSER
#define DBUS_DAEMONUSER "messagebus"
#endif
#ifndef DBUS_DAEMONGROUP
#define DBUS_DAEMONGROUP "messagebus"
#endif
/*
* Dumnpster diving for the D-Bus main configuration file
* where <pidfile> is defined.
*/
static char *dbus_pidfn(void)
{
char *alt[] = {
"/usr/share/dbus-1/system.conf",
"/etc/dbus-1/system.conf",
NULL
};
int i;
for (i = 0; alt[i]; i++) {
char *fn = alt[i];
char buf[256];
FILE *fp;
fp = fopen(fn, "r");
if (!fp)
continue;
fn = NULL;
while (fgets(buf, sizeof(buf), fp)) {
char *pos;
pos = strstr(buf, "<pidfile>");
if (!pos)
continue;
fn = pos + strlen("<pidfile>");
pos = strstr(fn, "</pidfile>");
if (!pos) {
fn = NULL;
break;
}
*pos = 0;
break;
}
fclose(fp);
if (fn)
return strdup(fn);
}
return NULL;
}
static void setup(void *arg) static void setup(void *arg)
{ {
char *group = DBUS_DAEMONGROUP;
char *user = DBUS_DAEMONUSER;
char line[256];
char *pidfn;
mode_t prev;
char *cmd; char *cmd;
char line[256];
if (rescue) { cmd = which(DAEMON);
dbg("Skipping %s plugin in rescue mode.", __FILE__);
return;
}
cmd = which(DBUS_DAEMON);
if (!cmd) { if (!cmd) {
dbg("Skipping plugin, %s is not installed.", DBUS_DAEMON); _d("Skipping plugin, %s is not installed.", DAEMON);
return; return;
} }
if (getuser(user, NULL) == -1) { umask(0);
if (getuser("dbus", NULL) == -1)
user = "root"; /* fallback */
else
user = "dbus"; /* e.g., Buildroot */
}
if (getgroup(group) == -1) { makedir("/var/run/dbus", 0755);
if (getgroup("dbus") == -1) makedir("/var/lock/subsys", 0755);
group = "root"; /* fallback */ makedir("/var/lock/subsys/messagebus", 0755);
else if (whichp("dbus-uuidgen"))
group = "dbus"; /* e.g., Buildroot */ run("dbus-uuidgen --ensure");
}
/* Clean up from any previous pre-bootstrap run */ /* Clean up from any previous pre-bootstrap run */
pidfn = dbus_pidfn(); erase("/var/run/dbus/pid");
if (pidfn)
remove(pidfn);
dbg("Creating D-Bus Required Directories ..."); /* Register service with Finit */
prev = umask(0); snprintf(line, sizeof(line), "[S12345] pid:!/run/dbus/pid log:prio:daemon.info,tag:dbus %s %s -- %s", cmd, ARGS, DESC);
mksubsys("/var/run/dbus", 0755, user, group); if (service_register(SVC_TYPE_SERVICE, line, global_rlimit, NULL))
mksubsys("/var/run/lock/subsys", 0755, user, group); _pe("Failed registering %s", DAEMON);
mksubsys("/var/lib/dbus", 0755, user, group);
mksubsys("/tmp/dbus", 0755, user, group);
umask(prev);
/* Generate machine id for dbus */
if (whichp("dbus-uuidgen"))
run_interactive("dbus-uuidgen --ensure", "Verifying D-Bus machine UUID");
/*
* Register service with Finit
* Note: dbus drops privs after starting up.
*/
if (pidfn) {
snprintf(line, sizeof(line), "[S123456789] cgroup.system notify:none name:dbus pid:!%s %s %s -- %s",
pidfn, cmd, DBUS_ARGS, DBUS_DESC);
free(pidfn);
} else
snprintf(line, sizeof(line), "[S123456789] cgroup.system notify:none name:dbus %s %s -- %s",
cmd, DBUS_ARGS, DBUS_DESC);
conf_save_service(SVC_TYPE_SERVICE, line, "dbus.conf");
free(cmd); free(cmd);
umask(022);
} }
static plugin_t plugin = { static plugin_t plugin = {
.name = __FILE__, .name = __FILE__,
.hook[HOOK_SVC_PLUGIN] = { .cb = setup }, .hook[HOOK_NETWORK_UP] = {
.cb = setup
},
.depends = { "bootmisc", },
}; };
PLUGIN_INIT(__init) PLUGIN_INIT(plugin_init)
{ {
plugin_register(&plugin); plugin_register(&plugin);
} }
PLUGIN_EXIT(__exit) PLUGIN_EXIT(plugin_exit)
{ {
plugin_unregister(&plugin); plugin_unregister(&plugin);
} }
-117
View File
@@ -1,117 +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"
extern void plugin_script_run(hook_point_t no);
static void hscript_run_parts(hook_point_t no)
{
plugin_script_run(no);
}
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 },
/*
* We have exited here, so these are handled a bit differently by Finit,
* when hook scripts are enabled, just to provide the user with the same
* interface:
*
* .hook[HOOK_SVC_DN] = { .cb = hscript_svc_down },
* .hook[HOOK_SYS_DN] = { .cb = hscript_system_down },
*/
};
PLUGIN_INIT(__init)
{
plugin_register(&plugin);
}
PLUGIN_EXIT(__exit)
{
plugin_unregister(&plugin);
}
/**
* Local Variables:
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+110
View File
@@ -0,0 +1,110 @@
/* Heuristically find and initialize a suitable hotplug daemon
*
* 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
* 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 <stdio.h>
#include "config.h"
#include "conf.h"
#include "finit.h"
#include "helpers.h"
#include "plugin.h"
#include "service.h"
static void setup(void *arg)
{
char cmd[256];
char *path;
/*
* Populate /dev and prepare for runtime events from kernel.
* Prefer udev if mdev is also available on the system.
*/
path = which("udevd");
if (!path)
path = which("/lib/systemd/systemd-udevd");
if (path) {
/* Register udevd as a monitored service */
snprintf(cmd, sizeof(cmd), "[S12345789] pid:udevd name:udevd log %s "
"-- Device event managing daemon", path);
if (service_register(SVC_TYPE_SERVICE, cmd, global_rlimit, NULL)) {
_pe("Failed registering %s", path);
} else {
snprintf(cmd, sizeof(cmd), ":1 [S] <pid/udevd> log "
"udevadm trigger -c add -t devices "
"-- Requesting device events");
service_register(SVC_TYPE_RUN, cmd, global_rlimit, NULL);
snprintf(cmd, sizeof(cmd), ":2 [S] <pid/udevd> log "
"udevadm trigger -c add -t subsystems "
"-- Requesting subsystem events");
service_register(SVC_TYPE_RUN, cmd, global_rlimit, NULL);
}
free(path);
/* Debian has this little script to copy generated
* rules while the system was read-only. TODO: When
* this functionality was hardcoded in finit.c, this
* call was made in crank_worker(). Now that
* filesystems are mounted earlier we should be able
* to make this call directly after the triggers have
* run, but this has not been tested AT ALL. */
if (fexist("/lib/udev/udev-finish"))
run_interactive("/lib/udev/udev-finish", "Finalizing udev");
} else {
path = which("mdev");
if (path) {
/* Embedded Linux systems usually have BusyBox mdev */
if (debug)
touch("/dev/mdev.log");
snprintf(cmd, sizeof(cmd), "%s -s", path);
free(path);
run_interactive(cmd, "Populating device tree");
}
}
}
static plugin_t plugin = {
.name = __FILE__,
.hook[HOOK_BASEFS_UP] = {
.cb = setup
},
};
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:
*/
+17 -80
View File
@@ -1,6 +1,6 @@
/* Coldplug modules using modalias magic /* Coldplug modules using modalias magic
* *
* Copyright (c) 2021-2024 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 * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -40,15 +40,11 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/time.h> /* gettimeofday() */ #include <sys/time.h> /* gettimeofday() */
#include <sys/types.h> #include <sys/types.h>
#ifdef _LIBITE_LITE #include <lite/lite.h>
# include <libite/lite.h>
#else
# include <lite/lite.h>
#endif
#include "config.h" #include "config.h"
#include "finit.h" #include "finit.h"
#include "util.h" #include "helpers.h"
#include "plugin.h" #include "plugin.h"
struct module { struct module {
@@ -71,14 +67,14 @@ static int modprobe(char *alias)
pid = fork(); pid = fork();
switch (pid) { switch (pid) {
case -1: case -1:
err(1, "Failed forking modprobe child"); _pe("Failed forking modprobe child");
return 1; return 1;
case 0: case 0:
execvp(args[0], args); execvp(args[0], args);
break; break;
default: default:
if (!complete(args[0], pid)) if (!complete(args[0], pid))
dbg("Successful modprobe of %s", alias); _d("Successful modprobe of %s", alias);
break; break;
} }
@@ -106,7 +102,7 @@ static void alias_remove(struct module *m)
TAILQ_REMOVE(&modules, m, link); TAILQ_REMOVE(&modules, m, link);
free(m->alias); free(m->alias);
free(m); free(m);
} }
static int alias_exist(char *alias) static int alias_exist(char *alias)
{ {
@@ -120,86 +116,27 @@ static int alias_exist(char *alias)
return 0; 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 = basenm(path);
if (!strcmp(basename, path))
return NULL;
if (strcmp(file, basename))
return NULL;
return fopen(path, "r");
}
static int scan_modalias(const char *path)
{
char buf[256];
FILE *fp; FILE *fp;
char buf[256];
fp = maybe_fopen_alias("modalias", path); if (fnmatch("*/modalias", path, 0))
return 0;
fp = fopen(path, "r");
if (!fp) if (!fp)
return 1; return 0;
if (fgets(buf, sizeof(buf), fp)) { if (fgets(buf, sizeof(buf), fp)) {
chomp(buf); chomp(buf);
alias_add_uniq(buf); if (!alias_exist(buf))
alias_add(buf);
} }
fclose(fp); fclose(fp);
return 0; 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) static void coldplug(void *arg)
{ {
struct module *m, *tmp; struct module *m, *tmp;
@@ -232,12 +169,12 @@ static plugin_t plugin = {
.depends = { "bootmisc", } .depends = { "bootmisc", }
}; };
PLUGIN_INIT(__init) PLUGIN_INIT(plugin_init)
{ {
plugin_register(&plugin); plugin_register(&plugin);
} }
PLUGIN_EXIT(__exit) PLUGIN_EXIT(plugin_exit)
{ {
plugin_unregister(&plugin); plugin_unregister(&plugin);
} }
+46 -171
View File
@@ -21,37 +21,10 @@
* THE SOFTWARE. * THE SOFTWARE.
*/ */
/* #include <lite/lite.h>
* 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 preceding one!
*/
#include <unistd.h> #include <unistd.h>
#include <sys/types.h> #include <sys/types.h>
#include <dirent.h> #include <dirent.h>
#ifdef _LIBITE_LITE
# include <libite/lite.h>
#else
# include <lite/lite.h>
#endif
#include "finit.h" #include "finit.h"
#include "helpers.h" #include "helpers.h"
@@ -62,166 +35,68 @@
#ifndef MODULES_LOAD_PATH #ifndef MODULES_LOAD_PATH
#define MODULES_LOAD_PATH "/etc/modules-load.d" #define MODULES_LOAD_PATH "/etc/modules-load.d"
#endif #endif
#define MODPROBE_PATH "/sbin/modprobe"
#define SERVICE_LINE \ #define SERVICE_LINE \
"cgroup.init name:modprobe.%s :%d [%s] %s %s %s --" ":%d name:modprobe.%s [2345] /sbin/modprobe %s %s -- Kernel module: %s"
#define SERVICE_LINE_NOINDEX \
"cgroup.init name:modprobe.%s [%s] %s %s %s --"
static int modules_load(const char *file, int index)
{
char module_path[PATH_MAX];
char *modprobe_path;
int num = 0;
char *line;
char *lvl;
FILE *fp;
strlcpy(module_path, MODULES_LOAD_PATH "/", sizeof(module_path));
strlcat(module_path, file, sizeof(module_path));
fp = fopen(module_path, "r");
if (!fp) {
warnx("failed opening %s for reading, skipping ...", module_path);
return 0;
}
modprobe_path = strdup(MODPROBE_PATH);
if (!modprobe_path) {
fail:
warnx("failed allocating memory in modules-load plugin.");
fclose(fp);
return -1;
}
lvl = strdup("S");
if (!lvl) {
free(modprobe_path);
goto fail;
}
while ((line = fparseln(fp, NULL, NULL, NULL, 0))) {
char cmd[CMD_SIZE], *mod, *args, *set;
/*
* fparseln() skips regular UNIX comments only.
* This is for modules-load.d(5) compat.
*/
if (line[0] == ';')
goto next;
/* trim whitespace */
mod = strip_line(line);
if (!mod[0])
goto next;
/* Finit extension 'set foo bar' */
if ((set = fgetval(mod, "set", "= \t"))) {
char *val = mod;
if (!strcmp(set, "noindex")) {
index = 0;
free(set);
goto next;
}
if ((val = fgetval(set, "index", "= \t"))) {
index = atoi(val);
free(set);
free(val);
goto next;
}
if ((val = fgetval(set, "runlevel", "= \t"))) {
free(lvl);
lvl = val;
free(set);
goto next;
}
if ((val = fgetval(set, "modprobe", "= \t"))) {
if (access(val, X_OK)) {
warn("%s: cannot use %s", module_path, val);
free(set);
free(val);
free(line);
goto skip;
} else {
free(modprobe_path);
modprobe_path = val;
}
free(set);
goto next;
}
/* unknown 'set' command, ignore. */
goto next;
}
mod = strtok_r(mod, " ", &args);
if (!mod)
goto next;
if (!index)
snprintf(cmd, sizeof(cmd), SERVICE_LINE_NOINDEX, mod, lvl, modprobe_path, mod, args);
else
snprintf(cmd, sizeof(cmd), SERVICE_LINE, mod, index++, lvl, modprobe_path, mod, args);
dbg("task %s", cmd);
service_register(SVC_TYPE_TASK, cmd, global_rlimit, NULL);
num++;
next:
free(line);
}
skip:
free(modprobe_path);
free(lvl);
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) static void load(void *arg)
{ {
struct dirent **dentry; FILE *fp;
DIR *dirp;
struct dirent *direntp;
char line[256];
int index = 1; int index = 1;
int i, num;
dbg("Scanning " MODULES_LOAD_PATH " for config files ..."); _d("Scanning " MODULES_LOAD_PATH " for config files ...");
num = scandir(MODULES_LOAD_PATH, &dentry, module_filter, alphasort);
if (num > 0) { dirp = opendir(MODULES_LOAD_PATH);
for (i = 0; i < num; i++) { if (!dirp) return;
index += modules_load(dentry[i]->d_name, index);
free(dentry[i]); while ((direntp = readdir(dirp)))
{
char module_path[PATH_MAX];
strlcpy(module_path, MODULES_LOAD_PATH "/", sizeof(module_path));
strlcat(module_path, direntp->d_name, sizeof(module_path));
fp = fopen(module_path, "r");
if (!fp) continue;
while (fgets(line, sizeof(line), fp)) {
char cmd[CMD_SIZE], *mod, *args;
mod = strip_line(line);
if (!*mod) continue;
mod = chomp(mod);
if (!mod || !*mod) continue;
mod = strtok_r(mod, " ", &args);
snprintf(cmd, sizeof(cmd), SERVICE_LINE,
index, mod, mod, args, mod);
service_register(SVC_TYPE_TASK, cmd, global_rlimit, NULL);
index++;
} }
free(dentry);
fclose(fp);
} }
closedir(dirp);
} }
static plugin_t plugin = { static plugin_t plugin = {
.name = __FILE__, .name = __FILE__,
.hook[HOOK_SVC_PLUGIN] = { .cb = load }, .hook[HOOK_BASEFS_UP] = {
.cb = load
},
}; };
PLUGIN_INIT(__init) PLUGIN_INIT(plugin_init)
{ {
plugin_register(&plugin); plugin_register(&plugin);
} }
PLUGIN_EXIT(__exit) PLUGIN_EXIT(plugin_exit)
{ {
plugin_unregister(&plugin); plugin_unregister(&plugin);
} }
+82 -306
View File
@@ -1,8 +1,7 @@
/* Netlink plugin for IFUP/IFDN and GW events /* Netlink plugin for IFUP/IFDN and GW events
* *
* Copyright (C) 2009-2011 Mårten Wikström <marten.wikstrom@keystream.se> * Copyright (C) 2009-2011 Mårten Wikström <marten.wikstrom@keystream.se>
* Copyright (C) 2009-2024 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 * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -18,7 +17,6 @@
*/ */
#include <arpa/inet.h> #include <arpa/inet.h>
#include <ctype.h>
#include <errno.h> #include <errno.h>
#include <net/if.h> /* IFNAMSIZ */ #include <net/if.h> /* IFNAMSIZ */
#include <sys/socket.h> #include <sys/socket.h>
@@ -29,90 +27,70 @@
#include "finit.h" #include "finit.h"
#include "cond.h" #include "cond.h"
#include "log.h"
#include "helpers.h" #include "helpers.h"
#include "plugin.h" #include "plugin.h"
#include "service.h"
#define NL_BUFSZ 4096 static int nlmsg_validate(struct nlmsghdr *nh, size_t len)
{
if (!NLMSG_OK(nh, len))
return 1;
struct nl_request { if (nh->nlmsg_type == NLMSG_DONE) {
struct nlmsghdr nh; _d("Done with netlink messages.");
union { return 1;
struct rtmsg rtm; }
struct ifinfomsg ifi;
};
};
static int nl_defidx; if (nh->nlmsg_type == NLMSG_ERROR) {
static int nl_ifdown; _d("Netlink reports error.");
static char *nl_buf; return 1;
}
return 0;
}
static void nl_route(struct nlmsghdr *nlmsg, ssize_t len) static void nl_route(struct nlmsghdr *nlmsg)
{ {
char daddr[INET_ADDRSTRLEN];
char gaddr[INET_ADDRSTRLEN];
struct in_addr ind, ing;
struct rtmsg *r; struct rtmsg *r;
struct rtattr *a; struct rtattr *a;
int plen = 0;
int dst = 0;
int idx = 0;
int gw = 0;
int la; int la;
int gw = 0, dst = 0, mask = 0, idx = 0;
if (nlmsg->nlmsg_len < NLMSG_LENGTH(sizeof(struct rtmsg))) { if (nlmsg->nlmsg_len < NLMSG_LENGTH(sizeof(struct rtmsg))) {
errx(1, "Packet too small or truncated!"); _e("Packet too small or truncated!");
return; return;
} }
r = NLMSG_DATA(nlmsg); r = NLMSG_DATA(nlmsg);
a = RTM_RTA(r); a = RTM_RTA(r);
la = RTM_PAYLOAD(nlmsg); la = RTM_PAYLOAD(nlmsg);
if (la >= len) {
errx(1, "Packet too large!");
return;
}
while (RTA_OK(a, la)) { while (RTA_OK(a, la)) {
void *data = RTA_DATA(a); void *data = RTA_DATA(a);
switch (a->rta_type) { switch (a->rta_type) {
case RTA_GATEWAY: case RTA_GATEWAY:
gw = *((int *)data); gw = *((int *)data);
//dbg("GW: 0x%04x", gw); //_d("GW: 0x%04x", gw);
break; break;
case RTA_DST: case RTA_DST:
dst = *((int *)data); dst = *((int *)data);
plen = r->rtm_dst_len; mask = r->rtm_dst_len;
//dbg("Prefix LEN: 0x%04x", plen); //_d("MASK: 0x%04x", mask);
break; break;
case RTA_OIF: case RTA_OIF:
idx = *((int *)data); idx = *((int *)data);
//dbg("IDX: 0x%04x", idx); //_d("IDX: 0x%04x", idx);
break; break;
} }
a = RTA_NEXT(a, la); a = RTA_NEXT(a, la);
} }
ind.s_addr = dst; if ((!dst && !mask) && (gw || idx)) {
ing.s_addr = gw; if (nlmsg->nlmsg_type == RTM_DELROUTE)
inet_ntop(AF_INET, &ind, daddr, sizeof(daddr));
inet_ntop(AF_INET, &ing, gaddr, sizeof(gaddr));
dbg("Got gw %s dst/len %s/%d ifindex %d", gaddr, daddr, plen, idx);
if ((!dst && !plen) && (gw || idx)) {
if (nlmsg->nlmsg_type == RTM_DELROUTE) {
cond_clear("net/route/default"); cond_clear("net/route/default");
nl_defidx = 0; else
} else {
cond_set("net/route/default"); cond_set("net/route/default");
nl_defidx = idx;
}
} }
} }
@@ -127,277 +105,83 @@ static void net_cond_set(char *ifname, char *cond, int set)
cond_clear(msg); cond_clear(msg);
} }
static int validate_ifname(const char *ifname) static void nl_link(struct nlmsghdr *nlmsg)
{ {
if (!ifname || !ifname[0])
return 1;
if (strnlen(ifname, IFNAMSIZ) == IFNAMSIZ)
return 1;
if (!strcmp(ifname, ".") || !strcmp(ifname, ".."))
return 1;
while (*ifname) {
if (*ifname == '/' || *ifname == ':' || isspace(*ifname))
return 1;
ifname++;
}
return 0;
}
/*
* Check if this interface was associated with the default route
* previously, or if it's been removed. If so, trigger a recheck
* of the system default route.
*/
static void nl_check_default(char *ifname)
{
int idx = (int)if_nametoindex(ifname);
if ((nl_defidx > 0 && nl_defidx == idx) || (idx == 0 && errno == ENODEV))
nl_ifdown = 1;
}
static void nl_link(struct nlmsghdr *nlmsg, ssize_t len)
{
char ifname[IFNAMSIZ + 1];
struct ifinfomsg *i;
struct rtattr *a;
int la; int la;
char ifname[IFNAMSIZ + 1];
struct rtattr *a;
struct ifinfomsg *i;
if (nlmsg->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg))) { if (nlmsg->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg))) {
errx(1, "Packet too small or truncated!"); _e("Packet too small or truncated!");
return; return;
} }
i = NLMSG_DATA(nlmsg); i = NLMSG_DATA(nlmsg);
a = (struct rtattr *)((char *)i + NLMSG_ALIGN(sizeof(struct ifinfomsg))); a = (struct rtattr *)((char *)i + NLMSG_ALIGN(sizeof(struct ifinfomsg)));
la = NLMSG_PAYLOAD(nlmsg, sizeof(struct ifinfomsg)); la = NLMSG_PAYLOAD(nlmsg, sizeof(struct ifinfomsg));
if (la >= len) {
errx(1, "Packet too large!");
return;
}
for (; RTA_OK(a, la); a = RTA_NEXT(a, la)) {
if (a->rta_type != IFLA_IFNAME)
continue;
strlcpy(ifname, RTA_DATA(a), sizeof(ifname));
if (validate_ifname(ifname)) {
dbg("Invalid interface name '%s', skipping ...", ifname);
continue;
}
switch (nlmsg->nlmsg_type) {
case RTM_NEWLINK:
/*
* New interface has appeared, or interface flags has changed.
* Check ifi_flags here to see if the interface is UP/DOWN
*/
dbg("%s: New link, flags 0x%x, change 0x%x", ifname, i->ifi_flags, i->ifi_change);
net_cond_set(ifname, "exist", 1);
net_cond_set(ifname, "up", i->ifi_flags & IFF_UP);
net_cond_set(ifname, "running", i->ifi_flags & IFF_RUNNING);
if (!(i->ifi_flags & IFF_UP) || !(i->ifi_flags & IFF_RUNNING))
nl_check_default(ifname);
break;
case RTM_DELLINK:
/* NOTE: Interface has disappeared, not link down ... */
dbg("%s: Delete link", ifname);
net_cond_set(ifname, "exist", 0);
net_cond_set(ifname, "up", 0);
net_cond_set(ifname, "running", 0);
nl_check_default(ifname);
break;
case RTM_NEWADDR:
dbg("%s: New Address", ifname);
break;
case RTM_DELADDR:
dbg("%s: Deconfig Address", ifname);
break;
default:
dbg("%s: Msg 0x%x", ifname, nlmsg->nlmsg_type);
break;
}
}
}
static int nl_parse(int sd)
{
while (1) {
struct nlmsghdr *nh;
ssize_t len;
size_t l;
while ((len = recv(sd, nl_buf, NL_BUFSZ, 0)) < 0) {
switch (errno) {
case EAGAIN: /* Nothing more right now. */
return 0;
case EINTR: /* Signal */
continue;
case ENOBUFS: /* netlink(7) */
break;
default:
err(1, "recv()");
break;
}
return -1;
}
// dbg("recv %zd 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:
// dbg("Done with netlink messages.");
return 0;
case NLMSG_ERROR:
// dbg("Kernel netlink comm. error.");
nle = NLMSG_DATA(nh);
if (nle) {
errno = -nle->error;
err(1, "Kernel netlink error %d", errno);
}
return -1;
case RTM_NEWROUTE:
case RTM_DELROUTE:
// dbg("Netlink route ...");
nl_route(nh, len);
break;
while (RTA_OK(a, la)) {
if (a->rta_type == IFLA_IFNAME) {
strlcpy(ifname, RTA_DATA(a), sizeof(ifname));
switch (nlmsg->nlmsg_type) {
case RTM_NEWLINK: case RTM_NEWLINK:
/*
* New interface has appeared, or interface flags has changed.
* Check ifi_flags here to see if the interface is UP/DOWN
*/
_d("%s: New link, flags 0x%x, change 0x%x", ifname, i->ifi_flags, i->ifi_change);
net_cond_set(ifname, "exist", 1);
net_cond_set(ifname, "up", i->ifi_flags & IFF_UP);
net_cond_set(ifname, "running", i->ifi_flags & IFF_RUNNING);
break;
case RTM_DELLINK: case RTM_DELLINK:
// dbg("Netlink link ..."); /* NOTE: Interface has disappeared, not link down ... */
nl_link(nh, len); _d("%s: Delete link", ifname);
net_cond_set(ifname, "exist", 0);
net_cond_set(ifname, "up", 0);
net_cond_set(ifname, "running", 0);
break;
case RTM_NEWADDR:
_d("%s: New Address", ifname);
break;
case RTM_DELADDR:
_d("%s: Deconfig Address", ifname);
break; break;
default: default:
warnx("unhandled netlink message, type %d", nh->nlmsg_type); _d("%s: Msg 0x%x", ifname, nlmsg->nlmsg_type);
break; break;
} }
} }
a = RTA_NEXT(a, la);
} }
} }
static int nl_request(int sd, unsigned int seq, int type)
{
struct nl_request *nlr = (struct nl_request *)nl_buf;
memset(nlr, 0, sizeof(struct nl_request));
nlr->nh.nlmsg_type = type;
nlr->nh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
nlr->nh.nlmsg_seq = seq;
nlr->nh.nlmsg_pid = 1;
switch (type) {
case RTM_GETROUTE:
// dbg("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:
// dbg("RTM_GETLINK");
nlr->ifi.ifi_family = AF_UNSPEC;
nlr->ifi.ifi_change = 0xFFFFFFFF;
nlr->nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
break;
default:
warnx("Cannot resync, unhandled message type %d", type);
return -1;
}
if (send(sd, nlr, nlr->nh.nlmsg_len, 0) < 0)
return 1;
return nl_parse(sd);
}
static void nl_resync_routes(int sd, unsigned int seq)
{
if (nl_request(sd, seq, RTM_GETROUTE))
err(1, "Failed netlink route request");
}
static void nl_resync_ifaces(int sd, unsigned int seq)
{
if (nl_request(sd, seq, RTM_GETLINK))
err(1, "Failed netlink link request");
}
/*
* We've potentially lost netlink events, let's resync with kernel.
*/
static void nl_resync(int all)
{
unsigned int seq = 0;
int sd;
sd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
if (sd < 0) {
err(1, "netlink socket");
return;
}
if (all) {
dbg("============================ RESYNC =================================");
/* this doesn't update conditions, and thus does not stop services */
cond_deassert("net/");
nl_resync_ifaces(sd, seq++);
nl_resync_routes(sd, seq++);
/* delayed update after we've corrected things */
service_step_all(SVC_TYPE_ANY);
dbg("=========================== RESYNCED ================================");
} else
nl_resync_routes(sd, seq++);
close(sd);
}
static void nl_callback(void *arg, int sd, int events) static void nl_callback(void *arg, int sd, int events)
{ {
if (nl_parse(sd) < 0) { ssize_t len;
if (errno == ENOBUFS) { /* netlink(7) */ static char buf[4096];
warnx("busy system, resynchronizing with kernel."); struct nlmsghdr *nh;
nl_resync(1);
return; memset(buf, 0, sizeof(buf));
} len = recv(sd, buf, sizeof(buf), 0);
if (len < 0) {
if (errno != EINTR) /* Signal */
_pe("recv()");
return;
} }
/* for (nh = (struct nlmsghdr *)buf; !nlmsg_validate(nh, len); nh = NLMSG_NEXT(nh, len)) {
* Linux doesn't send route changes when interfaces go down, so //_d("Well formed netlink message received. type %d ...", nh->nlmsg_type);
* we need to check ourselves, e.g. for loss of default route. if (nh->nlmsg_type == RTM_NEWROUTE || nh->nlmsg_type == RTM_DELROUTE)
*/ nl_route(nh);
if (nl_ifdown) { else
dbg("interface down, checking default route."); nl_link(nh);
if (nl_defidx > 0) {
nl_defidx = 0;
nl_resync(0);
if (nl_defidx <= 0) {
cond_clear("net/route/default");
nl_defidx = 0;
}
}
nl_ifdown = 0;
} }
} }
@@ -415,31 +199,24 @@ static plugin_t plugin = {
}, },
}; };
PLUGIN_INIT(__init) PLUGIN_INIT(plugin_init)
{ {
struct sockaddr_nl sa;
int sd; int sd;
struct sockaddr_nl sa;
sd = socket(AF_NETLINK, SOCK_RAW | SOCK_NONBLOCK | SOCK_CLOEXEC, NETLINK_ROUTE); sd = socket(AF_NETLINK, SOCK_RAW | SOCK_NONBLOCK | SOCK_CLOEXEC, NETLINK_ROUTE);
if (sd < 0) { if (sd < 0) {
err(1, "socket()"); _pe("socket()");
return; return;
} }
memset(&sa, 0, sizeof(sa)); memset(&sa, 0, sizeof(sa));
sa.nl_family = AF_NETLINK; sa.nl_family = AF_NETLINK;
sa.nl_groups = RTMGRP_IPV4_ROUTE | RTMGRP_LINK; sa.nl_groups = RTMGRP_IPV4_ROUTE | RTMGRP_LINK; // | RTMGRP_NOTIFY | RTMGRP_IPV4_IFADDR;
sa.nl_pid = getpid(); sa.nl_pid = getpid();
if (bind(sd, (struct sockaddr *)&sa, sizeof(sa)) < 0) { if (bind(sd, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
err(1, "bind()"); _pe("bind()");
close(sd);
return;
}
nl_buf = malloc(NL_BUFSZ);
if (!nl_buf) {
err(1, "malloc()");
close(sd); close(sd);
return; return;
} }
@@ -448,10 +225,9 @@ PLUGIN_INIT(__init)
plugin_register(&plugin); plugin_register(&plugin);
} }
PLUGIN_EXIT(__exit) PLUGIN_EXIT(plugin_exit)
{ {
plugin_unregister(&plugin); plugin_unregister(&plugin);
close(plugin.io.fd);
} }
/** /**
+39 -110
View File
@@ -1,7 +1,7 @@
/* Simple pidfile event monitor for the Finit condition engine /* Simple pidfile event monitor for the Finit condition engine
* *
* Copyright (c) 2015-2016 Tobias Waldekranz <tobias@waldekranz.com> * Copyright (c) 2015-2016 Tobias Waldekranz <tobias@waldekranz.com>
* Copyright (c) 2016-2024 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 * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -52,13 +52,13 @@ static int pidfile_add_path(struct iwatch *iw, char *path)
ptr = slash++; ptr = slash++;
slash = strchr(ptr, '/'); slash = strchr(ptr, '/');
if (slash) { if (slash) {
dbg("Path too deep, skipping %s", path); _d("Path too deep, skipping.");
return -1; return -1;
} }
} }
} }
return iwatch_add(iw, path, IN_ONLYDIR | IN_CLOSE_WRITE); return iwatch_add(iw, path, IN_ONLYDIR);
} }
static void pidfile_update_conds(char *dir, char *name, uint32_t mask) static void pidfile_update_conds(char *dir, char *name, uint32_t mask)
@@ -66,95 +66,36 @@ static void pidfile_update_conds(char *dir, char *name, uint32_t mask)
char cond[MAX_COND_LEN]; char cond[MAX_COND_LEN];
char fn[PATH_MAX]; char fn[PATH_MAX];
svc_t *svc; svc_t *svc;
char *nm;
paste(fn, sizeof(fn), dir, name); paste(fn, sizeof(fn), dir, name);
_d("path: %s, mask: %08x", fn, mask);
if (fnmatch("*\\.pid", fn, 0) && fnmatch("*/pid", fn, 0)) if (fnmatch("*\\.pid", fn, 0) && fnmatch("*/pid", fn, 0))
return; return;
dbg("path: %s, mask: %08x", fn, mask);
svc = svc_find_by_pidfile(fn); svc = svc_find_by_pidfile(fn);
if (!svc) { if (!svc) {
dbg("No matching svc for %s", fn); _d("No matching svc for %s", fn);
return; return;
} }
switch (svc->state) { _d("Found svc %s for %s with pid %d", svc->name, fn, svc->pid);
case SVC_TEARDOWN_STATE:
case SVC_CLEANUP_STATE:
case SVC_SETUP_STATE:
/*
* E.g., a setup script for a container may run in lieu
* of crun, trying to fetch a container image from the
* network. This script may want to advertise its PID
* to the system for clean and swift reboots.
*/
dbg("%s[%d]: ignoring any PID file changes in CLEANUP/TEARDOWN/SETUP",
svc_ident(svc, NULL, 0), svc->pid);
return;
default:
break;
}
/* Service condistion to set/clear */
mkcond(svc, cond, sizeof(cond)); mkcond(svc, cond, sizeof(cond));
if (mask & (IN_CREATE | IN_ATTRIB | IN_MODIFY | IN_MOVED_TO)) {
nm = svc_ident(svc, NULL, 0); svc_started(svc);
dbg("Found svc %s for %s with pid %d", nm, fn, svc->pid);
if (svc_is_stopping(svc)) {
dbg("Ignoring pidfile death rattles while service %s is %s", nm, svc_status(svc));
goto sneaky_zebra;
}
if (mask & (IN_CLOSE_WRITE | IN_ATTRIB | IN_MODIFY | IN_MOVED_TO)) {
/*
* only mark native services as started, the s6 and
* systemd style services rely on their respective
* readiness notification. Issue #343
*/
if (svc->notify == SVC_NOTIFY_PID)
svc_started(svc);
if (!svc_has_pidfile(svc)) {
dbg("Setting %s PID file to %s", svc->name, fn);
pid_file_set(svc, fn, 1);
}
if (svc_is_forking(svc)) { if (svc_is_forking(svc)) {
pid_t pid; pid_t pid;
pid = pid_file_read(fn); pid = pid_file_read(pid_file(svc));
if (pid == -1) { _d("Forking service %s changed PID from %d to %d",
/* handle case when service dies immediately */ svc->cmd, svc->pid, pid);
if (!fexist(fn)) svc->pid = pid;
cond_clear(cond);
return;
}
/* Service is not crashing, let's tell state machine! */
service_forked(svc);
if (pid != svc->pid) {
dbg("Forking service %s (cmd %s) changed PID from %d to %d",
svc_ident(svc, NULL, 0), 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);
}
} }
if (svc->notify == SVC_NOTIFY_PID) cond_set(cond);
cond_set(cond); } else if (mask & IN_DELETE)
if (svc->notify == SVC_NOTIFY_PID || svc->notify == SVC_NOTIFY_NONE)
service_ready(svc, 1);
} else if (mask & IN_DELETE) {
sneaky_zebra:
cond_clear(cond); cond_clear(cond);
if (svc->notify == SVC_NOTIFY_PID)
service_ready(svc, 0);
}
} }
/* synthesize events in case of new run dirs */ /* synthesize events in case of new run dirs */
@@ -176,7 +117,7 @@ static void pidfile_scandir(struct iwatch *iw, char *dir, int len)
return; return;
for (i = 0; i < gl.gl_pathc; i++) { for (i = 0; i < gl.gl_pathc; i++) {
dbg("scan found %s", gl.gl_pathv[i]); _d("scan found %s", gl.gl_pathv[i]);
pidfile_update_conds(dir, gl.gl_pathv[i], IN_CREATE); pidfile_update_conds(dir, gl.gl_pathv[i], IN_CREATE);
} }
globfree(&gl); globfree(&gl);
@@ -191,7 +132,7 @@ static void pidfile_handle_dir(struct iwatch *iw, char *dir, char *name, int mas
struct iwatch_path *iwp; struct iwatch_path *iwp;
paste(path, sizeof(path), dir, name); paste(path, sizeof(path), dir, name);
dbg("path: %s", path); _d("path: %s", path);
iwp = iwatch_find_by_path(iw, path); iwp = iwatch_find_by_path(iw, path);
@@ -210,29 +151,24 @@ static void pidfile_callback(void *arg, int fd, int events)
{ {
static char ev_buf[8 *(sizeof(struct inotify_event) + NAME_MAX + 1) + 1]; static char ev_buf[8 *(sizeof(struct inotify_event) + NAME_MAX + 1) + 1];
struct inotify_event *ev; struct inotify_event *ev;
ssize_t sz; ssize_t sz, off;
size_t off;
sz = read(fd, ev_buf, sizeof(ev_buf) - 1); sz = read(fd, ev_buf, sizeof(ev_buf) - 1);
if (sz <= 0) { if (sz <= 0) {
err(1, "invalid inotify event"); _pe("invalid inotify event");
return; return;
} }
ev_buf[sz] = 0; ev_buf[sz] = 0;
for (off = 0; off < (size_t)sz; off += sizeof(*ev) + ev->len) { for (off = 0; off < sz; off += sizeof(*ev) + ev->len) {
struct iwatch_path *iwp; struct iwatch_path *iwp;
if (off + sizeof(*ev) > (size_t)sz)
break;
ev = (struct inotify_event *)&ev_buf[off]; ev = (struct inotify_event *)&ev_buf[off];
if (off + sizeof(*ev) + ev->len > (size_t)sz)
break;
if (!ev->mask) if (!ev->mask)
continue; continue;
_d("name %s, event: 0x%08x", ev->name, ev->mask);
/* Find base path for this event */ /* Find base path for this event */
iwp = iwatch_find_by_wd(&iw_pidfile, ev->wd); iwp = iwatch_find_by_wd(&iw_pidfile, ev->wd);
if (!iwp) if (!iwp)
@@ -243,7 +179,12 @@ static void pidfile_callback(void *arg, int fd, int events)
continue; continue;
} }
if (ev->mask & (IN_CLOSE_WRITE | IN_DELETE | IN_ATTRIB | IN_MODIFY | IN_MOVED_TO)) if (ev->mask & IN_DELETE) {
_d("pidfile %s/%s removed ...", iwp->path, ev->name);
continue;
}
if (ev->mask & (IN_CREATE | IN_ATTRIB | IN_MODIFY | IN_MOVED_TO))
pidfile_update_conds(iwp->path, ev->name, ev->mask); pidfile_update_conds(iwp->path, ev->name, ev->mask);
} }
} }
@@ -267,9 +208,6 @@ static void pidfile_reconf(void *arg)
if (svc_is_changed(svc) || svc_is_starting(svc)) if (svc_is_changed(svc) || svc_is_starting(svc))
continue; continue;
if (svc->notify == SVC_NOTIFY_PID)
service_ready(svc, 1);
mkcond(svc, cond, sizeof(cond)); mkcond(svc, cond, sizeof(cond));
if (cond_get(cond) == COND_ON) if (cond_get(cond) == COND_ON)
continue; continue;
@@ -278,9 +216,9 @@ static void pidfile_reconf(void *arg)
} }
/* /*
* This calls service_step(), which in turn schedules itself as * This will call service_step(), which in turn will schedule itself
* long as stepped services change state. Services going from * as long as stepped services change state. Services going from
* PAUSED to RUNNING reassert their conditions in that loop, * WAITING to RUNNING will reassert their conditions in that loop,
* which in turn may unlock other services, and so on. * which in turn may unlock other services, and so on.
*/ */
service_step_all(SVC_TYPE_SERVICE | SVC_TYPE_RUNTASK); service_step_all(SVC_TYPE_SERVICE | SVC_TYPE_RUNTASK);
@@ -288,14 +226,8 @@ static void pidfile_reconf(void *arg)
static void pidfile_init(void *arg) static void pidfile_init(void *arg)
{ {
char piddir[MAX_ARG_LEN];
char *path; char *path;
if (mkpath(pid_runpath(_PATH_CONDPID, piddir, sizeof(piddir)), 0755) && errno != EEXIST) {
err(1, "Failed creating %s condition directory, %s", COND_PID, _PATH_CONDPID);
return;
}
/* /*
* The bootmisc plugin is responsible for setting up /var/run. * The bootmisc plugin is responsible for setting up /var/run.
* and/or /run, with proper symlinks etc. We depend on bootmisc * and/or /run, with proper symlinks etc. We depend on bootmisc
@@ -303,18 +235,15 @@ static void pidfile_init(void *arg)
*/ */
path = realpath(_PATH_VARRUN, NULL); path = realpath(_PATH_VARRUN, NULL);
if (!path) { if (!path) {
dbg("Failed querying realpath(%s): %s", _PATH_VARRUN, strerror(errno));
path = realpath("/run", NULL); path = realpath("/run", NULL);
if (!path) { if (!path) {
errx(1, "System does not have %s or /run, aborting.", _PATH_VARRUN); _e("System does not have %s or /run, aborting.", _PATH_VARRUN);
return; return;
} }
} }
if (pidfile_add_path(&iw_pidfile, path)) if (pidfile_add_path(&iw_pidfile, path))
iwatch_exit(&iw_pidfile); iwatch_exit(&iw_pidfile);
free(path);
} }
/* /*
@@ -327,18 +256,18 @@ static void pidfile_init(void *arg)
* *
* service <net/iface/lo> /sbin/dropbear ... * service <net/iface/lo> /sbin/dropbear ...
* *
* This service provides the <pid/dropbear> condition, which will not be * Which provides the <pid/dropbear> condition, will not be set by
* set by pidfile.so during `initctl reload` because dropbear is still * pidfile.so during `initctl reload` because dropbear is still
* SIGSTP:ed (in state PAUSED) waiting for <net/iface/lo>. * SIGSTP:ed waiting for <net/iface/lo>.
*/ */
static plugin_t plugin = { static plugin_t plugin = {
.name = __FILE__, .name = __FILE__,
.hook[HOOK_BASEFS_UP] = { .cb = pidfile_init }, .hook[HOOK_BASEFS_UP] = { .cb = pidfile_init },
.hook[HOOK_SVC_RECONF] = { .cb = pidfile_reconf }, .hook[HOOK_SVC_RECONF] = { .cb = pidfile_reconf },
.depends = { "netlink" }, /* bootmisc depends on us */ .depends = { "netlink" },
}; };
PLUGIN_INIT(__init) PLUGIN_INIT(plugin_init)
{ {
int fd; int fd;
@@ -353,10 +282,10 @@ PLUGIN_INIT(__init)
plugin_register(&plugin); plugin_register(&plugin);
} }
PLUGIN_EXIT(__exit) PLUGIN_EXIT(plugin_exit)
{ {
plugin_unregister(&plugin);
iwatch_exit(&iw_pidfile); iwatch_exit(&iw_pidfile);
plugin_unregister(&plugin);
} }
/** /**
+8 -28
View File
@@ -1,6 +1,6 @@
/* Set kernel variables from /etc/sysctl.conf et al /* Set kernel variables from /etc/sysctl.conf et al
* *
* Copyright (c) 2016-2024 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 * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -22,30 +22,14 @@
*/ */
#include <glob.h> #include <glob.h>
#ifdef _LIBITE_LITE #include <lite/lite.h>
# include <libite/lite.h>
#else
# include <lite/lite.h>
#endif
#include "finit.h"
#include "helpers.h"
#include "plugin.h" #include "plugin.h"
#include "conf.h"
#include "log.h"
#ifndef SYSCTL_PATH
#define SYSCTL_PATH "/sbin/sysctl"
#endif
static void setup(void *arg) static void setup(void *arg)
{ {
size_t i;
glob_t gl; glob_t gl;
char buf[160];
if (rescue) {
dbg("Skipping %s plugin in rescue mode.", __FILE__);
return;
}
glob("/run/sysctl.d/*.conf", 0, NULL, &gl); glob("/run/sysctl.d/*.conf", 0, NULL, &gl);
glob("/etc/sysctl.d/*.conf", GLOB_APPEND, NULL, &gl); glob("/etc/sysctl.d/*.conf", GLOB_APPEND, NULL, &gl);
@@ -55,13 +39,9 @@ static void setup(void *arg)
glob("/mnt/sysctl.d/*.conf", GLOB_APPEND, NULL, &gl); glob("/mnt/sysctl.d/*.conf", GLOB_APPEND, NULL, &gl);
glob("/etc/sysctl.conf", GLOB_APPEND, NULL, &gl); glob("/etc/sysctl.conf", GLOB_APPEND, NULL, &gl);
if (gl.gl_pathc > 0) { if (gl.gl_pathc > 0) {
size_t i;
for (i = 0; i < gl.gl_pathc; i++) { for (i = 0; i < gl.gl_pathc; i++) {
char cmd[160]; snprintf(buf, sizeof(buf), "/sbin/sysctl -e -p %s >/dev/null", gl.gl_pathv[i]);
run(buf);
snprintf(cmd, sizeof(cmd), "%s -e -p %s >/dev/null", SYSCTL_PATH, gl.gl_pathv[i]);
run(cmd, "sysctl");
} }
globfree(&gl); globfree(&gl);
} }
@@ -76,12 +56,12 @@ static plugin_t plugin = {
.depends = { "bootmisc", }, .depends = { "bootmisc", },
}; };
PLUGIN_INIT(__init) PLUGIN_INIT(plugin_init)
{ {
plugin_register(&plugin); plugin_register(&plugin);
} }
PLUGIN_EXIT(__exit) PLUGIN_EXIT(plugin_exit)
{ {
plugin_unregister(&plugin); plugin_unregister(&plugin);
} }
+6 -10
View File
@@ -1,6 +1,6 @@
/* Setup necessary files for resolvconf /* Setup necessary files for resolvconf
* *
* Copyright (c) 2012-2024 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 * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -21,11 +21,7 @@
* THE SOFTWARE. * THE SOFTWARE.
*/ */
#ifdef _LIBITE_LITE #include <lite/lite.h>
# include <libite/lite.h>
#else
# include <lite/lite.h>
#endif
#include "finit.h" #include "finit.h"
#include "helpers.h" #include "helpers.h"
@@ -37,7 +33,7 @@
*/ */
static void setup(void *arg) static void setup(void *arg)
{ {
dbg("Setting up the resolver ..."); _d("Setting up the resolver ...");
mkpath("/etc/resolvconf", 0755); mkpath("/etc/resolvconf", 0755);
mkpath("/etc/resolvconf/run", 0755); mkpath("/etc/resolvconf/run", 0755);
mkpath("/var/run/resolvconf", 0755); mkpath("/var/run/resolvconf", 0755);
@@ -45,7 +41,7 @@ static void setup(void *arg)
touch("/etc/resolvconf/run/enable-updates"); touch("/etc/resolvconf/run/enable-updates");
chdir("/etc/resolvconf/run/interface"); chdir("/etc/resolvconf/run/interface");
run_parts("/etc/resolvconf/update.d", "-i", NULL, 0, 0); run_parts("/etc/resolvconf/update.d", "-i");
chdir("/"); chdir("/");
} }
@@ -57,12 +53,12 @@ static plugin_t plugin = {
.depends = { "bootmisc", }, .depends = { "bootmisc", },
}; };
PLUGIN_INIT(__init) PLUGIN_INIT(plugin_init)
{ {
plugin_register(&plugin); plugin_register(&plugin);
} }
PLUGIN_EXIT(__exit) PLUGIN_EXIT(plugin_exit)
{ {
plugin_unregister(&plugin); plugin_unregister(&plugin);
} }
+55 -217
View File
@@ -1,6 +1,6 @@
/* Save and restore RTC using hwclock /* Save and restore RTC using hwclock
* *
* Copyright (c) 2012-2024 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 * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -21,43 +21,17 @@
* THE SOFTWARE. * THE SOFTWARE.
*/ */
#include "config.h"
#include <time.h> #include <time.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <linux/rtc.h> #include <linux/rtc.h>
#ifdef _LIBITE_LITE #include <lite/lite.h>
# include <libite/lite.h>
#else
# include <lite/lite.h>
#endif
#include "finit.h" #include "finit.h"
#include "helpers.h" #include "helpers.h"
#include "plugin.h" #include "plugin.h"
#include "private.h"
#include "conf.h"
#include "log.h"
/*
* Kernel RTC driver validates against this date for sanity check. The
* on NTP sync the driver can also update the RTC every 11 mins. We use
* the same update interval to handle manual time set and file save.
*/
#define RTC_TIMESTAMP_BEGIN_2000 "2000-01-01 00:00:00"
#define RTC_FMT "%Y-%m-%d %H:%M:%S"
#define RTC_PERIOD (11 * 60 * 1000)
#ifdef RTC_TIMESTAMP_CUSTOM
static char *rtc_timestamp = RTC_TIMESTAMP_CUSTOM;
#else
static char *rtc_timestamp = RTC_TIMESTAMP_BEGIN_2000;
#endif
static time_t rtc_date_fallback = 946684800LL;
static char *rtc_file = RTC_FILE;
static uev_t rtc_timer;
/* Kernel RTC driver validates against this date for sanity check */
#define RTC_TIMESTAMP_BEGIN_2000 946684800LL /* 2000-01-01 00:00:00 */
static void tz_set(char *tz, size_t len) static void tz_set(char *tz, size_t len)
{ {
@@ -82,125 +56,6 @@ static void tz_restore(char *tz)
tzset(); tzset();
} }
static int time_set(struct tm *tm)
{
struct tm fallback = { 0 };
struct timeval tv = { 0 };
char tz[128];
int rc = 0;
tz_set(tz, sizeof(tz));
if (!tm) {
logit(LOG_NOTICE, "Resetting system clock to kernel default, %s.", rtc_timestamp);
tm = &fallback;
/* Attempt to set RTC to a sane value ... */
tv.tv_sec = rtc_date_fallback;
if (!gmtime_r(&tv.tv_sec, tm)) {
rc = 1;
goto out;
}
}
tm->tm_isdst = -1; /* Use tzdata to figure it out, please. */
tv.tv_sec = mktime(tm);
if (tv.tv_sec == (time_t)-1 || tv.tv_sec < rtc_date_fallback) {
errno = EINVAL;
rc = 2;
} else {
if (settimeofday(&tv, NULL) == -1)
rc = 1;
}
out:
tz_restore(tz);
return rc;
}
static int time_get(struct tm *tm)
{
struct timeval tv = { 0 };
char tz[128];
int rc = 0;
tz_set(tz, sizeof(tz));
rc = gettimeofday(&tv, NULL);
if (rc < 0 || tv.tv_sec < rtc_date_fallback)
rc = 2;
else
gmtime_r(&tv.tv_sec, tm);
tz_restore(tz);
return rc;
}
static void file_save(void *arg)
{
struct tm tm = { 0 };
int rc = 0;
FILE *fp;
if (!rtc_file)
return;
fp = fopen(rtc_file, "w");
if (!fp) {
logit(LOG_WARNING, "Failed saving system clock to %s, code %d: %s",
rtc_file, errno, strerror(errno));
return;
}
if ((rc = time_get(&tm))) {
logit(LOG_WARNING, "System clock invalid, before %s, not saving", rtc_timestamp);
print_desc(NULL, "System clock invalid, skipping");
} else {
char buf[32] = { 0 };
print_desc(NULL, "Saving system clock to file");
strftime(buf, sizeof(buf), RTC_FMT, &tm);
fprintf(fp, "%s\n", buf);
}
print(rc, NULL);
fclose(fp);
}
static void file_restore(void *arg)
{
struct tm tm = { 0 };
int rc = 1;
FILE *fp;
if (!rtc_file) {
logit(LOG_NOTICE, "System has no RTC (missing driver?), skipping restore.");
return;
}
print_desc(NULL, "Restoring system clock from backup");
fp = fopen(rtc_file, "r");
if (fp) {
char buf[32];
if (fgets(buf, sizeof(buf), fp)) {
chomp(buf);
strptime(buf, RTC_FMT, &tm);
rc = time_set(&tm);
}
fclose(fp);
} else
logit(LOG_WARNING, "Missing %s", rtc_file);
if (rc) {
time_set(NULL);
rc = 2;
}
print(rc, NULL);
}
static int rtc_open(void) static int rtc_open(void)
{ {
char *alt[] = { char *alt[] = {
@@ -224,124 +79,107 @@ static int rtc_open(void)
static void rtc_save(void *arg) static void rtc_save(void *arg)
{ {
struct timeval tv = { 0 };
struct tm tm = { 0 }; struct tm tm = { 0 };
int fd, rc = 0; int fd, rc = 0;
char tz[128];
if (rescue) {
dbg("Skipping %s plugin in rescue mode.", __FILE__);
return;
}
fd = rtc_open(); fd = rtc_open();
if (fd < 0) if (fd < 0)
return; return;
if ((rc = time_get(&tm))) { tz_set(tz, sizeof(tz));
rc = gettimeofday(&tv, NULL);
if (rc < 0 || tv.tv_sec < RTC_TIMESTAMP_BEGIN_2000) {
print_desc(NULL, "System clock invalid, not saving to RTC"); print_desc(NULL, "System clock invalid, not saving to RTC");
} else { invalid:
print_desc(NULL, "Saving system clock (UTC) to RTC"); logit(LOG_ERR, "System clock invalid, before 2000-01-01 00:00, not saving to RTC");
rc = ioctl(fd, RTC_SET_TIME, &tm);
}
if (rc && errno == EINVAL) {
logit(LOG_WARNING, "System clock invalid, before %s, not saving to RTC", rtc_timestamp);
rc = 2; rc = 2;
goto out;
} }
print_desc(NULL, "Saving system time (UTC) to RTC");
gmtime_r(&tv.tv_sec, &tm);
if (ioctl(fd, RTC_SET_TIME, &tm) < 0) {
if (EINVAL == errno)
goto invalid;
rc = 1;
goto out;
}
out:
tz_restore(tz);
print(rc, NULL); print(rc, NULL);
close(fd); close(fd);
} }
static void rtc_restore(void *arg) static void rtc_restore(void *arg)
{ {
struct timeval tv = { 0 };
struct tm tm = { 0 }; struct tm tm = { 0 };
int fd, rc = 0; int fd, rc = 0;
char tz[128];
if (rescue) {
dbg("Skipping %s plugin in rescue mode.", __FILE__);
return;
}
fd = rtc_open(); fd = rtc_open();
if (fd < 0) { if (fd < 0)
file_restore(arg);
return; return;
}
if ((rc = ioctl(fd, RTC_RD_TIME, &tm)) < 0) { tz_set(tz, sizeof(tz));
if (ioctl(fd, RTC_RD_TIME, &tm) < 0) {
char msg[120]; char msg[120];
snprintf(msg, sizeof(msg), "Failed restoring system clock, %s", snprintf(msg, sizeof(msg), "Failed restoring system clock, %s",
EINVAL == errno ? "RTC time is too old" : EINVAL == errno ? "RTC time is too old" :
ENOENT == errno ? "RTC has no saved time" : "see log for details"); ENOENT == errno ? "RTC has no saved time" : "see log for details");
print_desc(NULL, msg); print_desc(NULL, msg);
} else {
print_desc(NULL, "Restoring system clock (UTC) from RTC"); invalid:
rc = time_set(&tm); logit(LOG_ERR, "Failed restoring system clock from RTC.");
if (EINVAL == errno)
logit(LOG_ERR, "RTC time is too old (before 2000-01-01 00:00)");
else if (ENOENT == errno)
logit(LOG_ERR, "RTC has no previously saved (valid) time.");
else
logit(LOG_ERR, "RTC error code %d: %s", errno, strerror(errno));
rc = 2;
goto out;
} }
if (rc) { print_desc(NULL, "Restoring system clock (UTC) from RTC");
logit(LOG_WARNING, "Failed restoring system clock from RTC."); tm.tm_isdst = -1; /* Use tzdata to figure it out, please. */
if (EINVAL == errno) tv.tv_sec = mktime(&tm);
logit(LOG_WARNING, "RTC time is too old (before %s)", rtc_timestamp); if (tv.tv_sec < RTC_TIMESTAMP_BEGIN_2000) {
else if (ENOENT == errno) errno = EINVAL;
logit(LOG_WARNING, "RTC has no previously saved (valid) time."); goto invalid;
else }
logit(LOG_WARNING, "RTC error code %d: %s", errno, strerror(errno));
print(2, NULL); if (settimeofday(&tv, NULL) == -1)
rc = 1;
/* Try restoring from last save game */
if (rtc_file)
file_restore(arg);
} else
print(0, NULL);
out:
tz_restore(tz);
print(rc, NULL);
close(fd); close(fd);
} }
static void save(void *arg)
{
rtc_save(arg);
file_save(arg);
}
static void update(uev_t *w, void *arg, int events)
{
save(arg);
}
static plugin_t plugin = { static plugin_t plugin = {
.name = __FILE__, .name = __FILE__,
.hook[HOOK_BASEFS_UP] = { .hook[HOOK_BASEFS_UP] = {
.cb = rtc_restore .cb = rtc_restore
}, },
.hook[HOOK_SHUTDOWN] = { .hook[HOOK_SHUTDOWN] = {
.cb = save .cb = rtc_save
} }
}; };
PLUGIN_INIT(__init) PLUGIN_INIT(plugin_init)
{ {
struct tm tm = { 0 };
if (!strptime(rtc_timestamp, RTC_FMT, &tm)) {
logit(LOG_WARNING, "Invalid restore date '%s', reverting to '%s'",
rtc_timestamp, RTC_TIMESTAMP_BEGIN_2000);
rtc_timestamp = RTC_TIMESTAMP_BEGIN_2000;
} else
rtc_date_fallback = mktime(&tm);
uev_timer_init(ctx, &rtc_timer, update, NULL, RTC_PERIOD, RTC_PERIOD);
plugin_register(&plugin); plugin_register(&plugin);
} }
PLUGIN_EXIT(__exit) PLUGIN_EXIT(plugin_exit)
{ {
uev_timer_stop(&rtc_timer);
plugin_unregister(&plugin); plugin_unregister(&plugin);
} }
-213
View File
@@ -1,213 +0,0 @@
/* System condition event monitor for the Finit condition engine
*
* Copyright (c) 2021-2024 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
* 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 <dirent.h>
#include <fnmatch.h>
#include <glob.h>
#include <limits.h>
#include <paths.h>
#include "finit.h"
#include "cond.h"
#include "pid.h"
#include "plugin.h"
#include "iwatch.h"
static struct iwatch iw_sys;
static int sys_add_path(struct iwatch *iw, char *path)
{
return iwatch_add(iw, path, IN_ONLYDIR | IN_CLOSE_WRITE);
}
/*
* unlink conditions with no active task/service, otherwise they may
* trigger inadvertently when calling `initctl reload` to activate
* a new configuration.
*/
static void sys_update_conds(char *dir, char *name, uint32_t mask)
{
char path[256];
char *cond;
char *ptr;
ptr = strrchr(name, '/');
if (ptr)
snprintf(path, sizeof(path), "%s/%s", dir, ++ptr);
else
snprintf(path, sizeof(path), "%s/%s", dir, name);
cond = strstr(path, COND_BASE);
if (!cond)
return;
cond += strlen(COND_BASE) + 1;
dbg("cond: %s set: %d", cond, (mask & IN_CREATE) ? 1 : 0);
if (!cond_update(cond))
unlink(path);
}
/* synthesize events in case of new run dirs */
static void sys_scandir(struct iwatch *iw, char *dir, int len)
{
glob_t gl;
size_t i;
char path[len + 6];
int rc;
snprintf(path, sizeof(path), "%s/*", dir);
rc = glob(path, GLOB_NOSORT, NULL, &gl);
if (rc && rc != GLOB_NOMATCH)
return;
for (i = 0; i < gl.gl_pathc; i++) {
dbg("scan found %s", gl.gl_pathv[i]);
sys_update_conds(dir, gl.gl_pathv[i], IN_CREATE);
}
globfree(&gl);
}
/*
* create/remove sub-directory in monitored directory
*/
static void sys_handle_dir(struct iwatch *iw, char *dir, char *name, int mask)
{
char path[strlen(dir) + strlen(name) + 2];
struct iwatch_path *iwp;
paste(path, sizeof(path), dir, name);
dbg("path: %s", path);
iwp = iwatch_find_by_path(iw, path);
if (mask & IN_CREATE) {
if (!iwp) {
if (!sys_add_path(iw, path))
sys_scandir(iw, path, sizeof(path));
}
} else if (mask & IN_DELETE) {
if (iwp)
iwatch_del(&iw_sys, iwp);
}
}
static void sys_callback(void *arg, int fd, int events)
{
static char ev_buf[8 *(sizeof(struct inotify_event) + NAME_MAX + 1) + 1];
struct inotify_event *ev;
ssize_t sz;
size_t off;
sz = read(fd, ev_buf, sizeof(ev_buf) - 1);
if (sz <= 0) {
err(1, "invalid inotify event");
return;
}
ev_buf[sz] = 0;
for (off = 0; off < (size_t)sz; off += sizeof(*ev) + ev->len) {
struct iwatch_path *iwp;
if (off + sizeof(*ev) > (size_t)sz)
break;
ev = (struct inotify_event *)&ev_buf[off];
if (off + sizeof(*ev) + ev->len > (size_t)sz)
break;
dbg("name %s, event: 0x%08x", ev->name, ev->mask);
if (!ev->mask)
continue;
/* Find base path for this event */
iwp = iwatch_find_by_wd(&iw_sys, ev->wd);
if (!iwp)
continue;
if (ev->mask & IN_ISDIR) {
sys_handle_dir(&iw_sys, iwp->path, ev->name, ev->mask);
continue;
}
if (ev->mask & (IN_CREATE | IN_DELETE))
sys_update_conds(iwp->path, ev->name, ev->mask);
}
}
static void sys_init(void *arg)
{
char sysdir[MAX_ARG_LEN];
char *path;
mkpath(_PATH_COND, 0755);
if (mkpath(pid_runpath(_PATH_CONDSYS, sysdir, sizeof(sysdir)), 0755) && errno != EEXIST) {
err(1, "Failed creating %s condition directory, %s", COND_SYS, _PATH_CONDSYS);
return;
}
path = realpath(_PATH_CONDSYS, NULL);
if (!path) {
err(1, "Cannot figure out real path to %s, aborting", _PATH_CONDSYS);
return;
}
if (iwatch_add(&iw_sys, path, IN_ONLYDIR))
iwatch_exit(&iw_sys);
free(path);
}
static plugin_t plugin = {
.name = __FILE__,
.hook[HOOK_BASEFS_UP] = { .cb = sys_init },
.depends = { "bootmisc", },
};
PLUGIN_INIT(__init)
{
int fd;
fd = iwatch_init(&iw_sys);
if (fd < 0)
return;
plugin.io.fd = fd;
plugin.io.cb = sys_callback;
plugin.io.flags = PLUGIN_IO_READ;
plugin_register(&plugin);
}
PLUGIN_EXIT(__exit)
{
plugin_unregister(&plugin);
iwatch_exit(&iw_sys);
}
/**
* Local Variables:
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+32 -57
View File
@@ -1,7 +1,7 @@
/* Optional TTY Watcher, used to catch new TTYs that are discovered, e.g., USB /* 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 Mattias Walström <lazzer@gmail.com>
* Copyright (c) 2013-2024 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 * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -27,24 +27,18 @@
#include <unistd.h> /* read() */ #include <unistd.h> /* read() */
#include <sys/inotify.h> #include <sys/inotify.h>
#include <sys/stat.h> #include <sys/stat.h>
#ifdef _LIBITE_LITE #include <lite/lite.h>
# include <libite/lite.h>
#else
# include <lite/lite.h>
#endif
#include "finit.h" #include "finit.h"
#include "helpers.h" #include "helpers.h"
#include "plugin.h" #include "plugin.h"
#include "service.h"
#include "tty.h" #include "tty.h"
#include "log.h"
static void tty_watcher(void *arg, int fd, int events); static void watcher(void *arg, int fd, int events);
static plugin_t plugin = { static plugin_t plugin = {
.io = { .io = {
.cb = tty_watcher, .cb = watcher,
.flags = PLUGIN_IO_READ, .flags = PLUGIN_IO_READ,
}, },
}; };
@@ -56,70 +50,51 @@ static void setup(void)
plugin.io.fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC); plugin.io.fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
if (-1 == plugin.io.fd || inotify_add_watch(plugin.io.fd, "/dev", IN_CREATE | IN_DELETE) < 0) if (-1 == plugin.io.fd || inotify_add_watch(plugin.io.fd, "/dev", IN_CREATE | IN_DELETE) < 0)
err(1, "Failed starting TTY watcher"); _pe("Failed starting TTY watcher");
} }
static void do_tty(char *tty, size_t len, int creat) static void watcher(void *arg, int fd, int events)
{ {
char name[len + 6]; char buf[EVENT_SIZE];
svc_t *svc; int len = 0;
snprintf(name, sizeof(name), "/dev/%s", tty); while ((len = read(fd, buf, sizeof(buf)))) {
svc = svc_find_by_tty(name); struct inotify_event *notified = (struct inotify_event *)buf;
if (svc) { char name[notified->len + 6];
if (svc_is_blocked(svc) && creat) { struct tty *entry;
dbg("%s: blocked, re-enabling", svc_ident(svc, NULL, 0));
svc_start(svc); if (-1 == len) {
} else if (svc->pid) { if (errno == EINVAL)
dbg("%s: missing ...", svc_ident(svc, NULL, 0)); setup();
svc_missing(svc); if (errno == EINTR)
continue;
break; /* Likely EAGAIN */
} }
service_step_all(SVC_TYPE_TTY); snprintf(name, sizeof(name), "/dev/%s", notified->name);
entry = tty_find(name);
if (entry && tty_enabled(entry)) {
if (notified->mask & IN_CREATE)
tty_start(entry);
else if (entry->pid)
tty_stop(entry);
}
} }
} }
static void tty_watcher(void *arg, int fd, int events) PLUGIN_INIT(plugin_init)
{
static char ev_buf[8 *(sizeof(struct inotify_event) + NAME_MAX + 1) + 1];
struct inotify_event *ev;
ssize_t sz;
size_t off;
sz = read(fd, ev_buf, sizeof(ev_buf) - 1);
if (sz <= 0) {
err(1, "invalid inotify event");
return;
}
ev_buf[sz] = 0;
for (off = 0; off < (size_t)sz; off += sizeof(*ev) + ev->len) {
if (off + sizeof(*ev) > (size_t)sz)
break;
ev = (struct inotify_event *)&ev_buf[off];
if (off + sizeof(*ev) + ev->len > (size_t)sz)
break;
if (!ev->mask)
continue;
dbg("tty %s, event: 0x%08x", ev->name, ev->mask);
do_tty(ev->name, ev->len, ev->mask & IN_CREATE);
}
}
PLUGIN_INIT(__init)
{ {
setup(); setup();
plugin_register(&plugin); plugin_register(&plugin);
} }
PLUGIN_EXIT(__exit) PLUGIN_EXIT(plugin_exit)
{ {
plugin_unregister(&plugin);
if (plugin.io.fd) if (plugin.io.fd)
close(plugin.io.fd); close(plugin.io.fd);
plugin_unregister(&plugin);
} }
/** /**

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