Compare commits

...
175 Commits
Author SHA1 Message Date
Joachim Nilsson 6d41725387 Bump version for v3.1 release
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-23 14:51:55 +01:00
Joachim Nilsson ceb91f746c Revert "Disable clang build during Coverity Scan run"
This reverts commit 22a69d8cca.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-23 14:45:24 +01:00
Joachim Nilsson a8802ab0d2 Mention Void Linux tutorial in README, change to bullet list
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-23 14:31:03 +01:00
Joachim Nilsson ad98f69560 Ignore return value from rename(), ofile may not exist yet.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-23 14:03:07 +01:00
Joachim Nilsson 5953090688 Document some relevant cmdline options
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-23 13:45:22 +01:00
Joachim Nilsson 22a69d8cca Disable clang build during Coverity Scan run
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-23 11:45:55 +01:00
Joachim Nilsson 710a3d2c8f Fix Coverity warning, array cannot be NULL
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-23 11:45:15 +01:00
Joachim Nilsson 658fb9b037 Check return value from rename(), fall back to truncate() on error
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-23 11:39:50 +01:00
Joachim Nilsson a84bb9042f Update and add ignore for WeOS build system files
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-23 09:51:39 +01:00
Joachim Nilsson eeb13dba74 Toggle silent mode (progress) when toggling debug mode
Starting in debug mode and disabling debug at runtime did not exhibit
the same behavior as if starting in normal mode and toggling debug mode
at runtime.  This patch adds toggling of silent mode (progress output)
to runtime debug toggling.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-23 09:44:44 +01:00
Joachim Nilsson 3d20237959 Follow-up to f858d94, only reinitialize screen when toggling debug mode
The screen_init() call for each print() & C:o caused serious screen
artefacts in debug mode.  This patch reworks f858d94 to only re-init
screen when toggling debug.

Also, avoid screen_init() completely if started in debug mode.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-23 09:33:24 +01:00
Joachim Nilsson ddf1bce642 Add screen_exit() fn to restore screen defaults in debug mode
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-23 09:31:44 +01:00
Joachim Nilsson 93cd4116db Update ChangeLog and prepare for v3.1 release
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-23 01:21:37 +01:00
Joachim Nilsson 1df6a91a94 Document sufficiently complex, yet deceptively simple, function
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-23 00:44:40 +01:00
Joachim Nilsson c64a71ff30 Follow-up to ba2ab4b, crashing services may not have a PID rn
- Don't warn of missing PID, even if only _d(), perfectly normal
- Allow stopping restart timer of non-services (e.g. task/run)
- Allow stopping services with no PID rn, i.e. stop libuEv timer

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-23 00:17:02 +01:00
Joachim Nilsson b2b6fd25d8 Relocate service helper script to contrib/
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-22 22:28:18 +01:00
Joachim Nilsson 3ca548b681 Add list of major contributors, from Westermo
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-22 21:31:05 +01:00
Joachim Nilsson ba2ab4b446 Follow-up to 2683049, only stop running, non-inet, services
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-22 20:52:37 +01:00
Joachim Nilsson a8183b0559 Check if symlink exists before trying to create symlink
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-22 20:45:05 +01:00
Joachim Nilsson 227e4fa097 Create destination contrib/*/finit.d dir if missing
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-22 19:03:06 +01:00
Joachim Nilsson 3d68ebbf54 Fix off-by-one in condition reassert()
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-22 15:24:11 +01:00
Joachim Nilsson 6e017025aa Fix bad string pointer arithmetic in condition reassert
On `initctl reload` we reassert conditions, i.e. bring each still viable
condition back in sync with the new reconf generation.  This patch fixes
an assumption in the reassert() callback that caused the following nasty
transformation:

	/run/finit/cond/net/lo/up --> /run/finit/cond/lo/up

The transformation was caused by the reassert() code assuming a /var/run
prefix rather than /run.  We must check the actual runpath, or like this
patch does, use a path neutral way to find the base condition string.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-22 15:17:07 +01:00
Joachim Nilsson 5f818f917e cond_init(): Create correct condition path, /var/run might not exist
The cond_init() function is called before the bootmisc.so plugin has
run.  It is responsble for setting up the /var/run symlink to /run on
systems with the new layout.  Therefore we must wrap COND_PATH with
pid_runpath() to create the correct runtime path.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-22 15:17:07 +01:00
Joachim Nilsson 0da1deb487 Add docs/*.md to distribution
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-22 09:02:19 +01:00
Joachim Nilsson 0337985422 Ignore generated files
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-22 09:02:19 +01:00
Joachim Nilsson f59d41cdec Add silly process monitor script to distribution.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-22 09:02:18 +01:00
Joachim Nilsson 1cc998eb60 Distribute and install contrib/ directory with all examples
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-22 09:01:58 +01:00
Joachim Nilsson 8c1d84305d Minor, refactor
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-22 08:38:52 +01:00
Joachim Nilsson 7e4e5127c7 Preserve Markdown links on installed .md files in docs/ sub-directory
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-21 10:22:25 +01:00
Joachim Nilsson 3b813bca68 Ignore generated files
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-20 20:48:26 +01:00
Joachim Nilsson a1f210bc70 Distribute and install relevant docs/*.md
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-20 20:47:33 +01:00
Joachim Nilsson 0ecf46d7a9 Prefer _exit() over exit() in forked service handlers
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-19 16:35:15 +01:00
Joachim Nilsson 268304927d Fix segfault, stop a crashing service before deleting it
Finit tries to restart crashing services.  If a service is removed
before Finit has given up restarting it, then the background timer
responsible the restart may dereference a free():d svc_t.

Hence, make sure to properly stop (and step) a service and its timer
callbacks in service_unregister() before calling svc_del().

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-19 16:27:25 +01:00
Joachim Nilsson fa02b59db5 Refactor, set STOPPING state in service_stop()
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-19 16:24:39 +01:00
Joachim Nilsson 2c904b5b44 service_unregister(): Also call inetd_del() for inetd services
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-19 16:07:22 +01:00
Joachim Nilsson 4191abc79f service_timeout_cb(): Check callback pointer before calling it
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-19 16:07:22 +01:00
Joachim Nilsson abb928f60b service_stop(): Also stop any pending restart timers
In service_stop() we call svc_del() which, as of Finit v3.1, free():s
the svc_t, so we don't want any lingering restart timers to wake up
after free() and start dereferencing the svc_t.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-19 16:07:22 +01:00
Joachim Nilsson 3c52118a8e svc_clean_dynamic(): Fix access after free()
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-19 13:20:25 +01:00
Joachim Nilsson 5354a57313 plugin_unregister(): Stop I/O watcher before free():ing watcher
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-18 18:35:18 +01:00
Joachim Nilsson 92b1d882e5 do_kill(): Also skip gdbserver from being killed
To improve debug possibilities at shutdown, keep gdbserver running even
during shutdown.

Note: The gdbserver service runlevels must be sth like [123456789] for
      this to work in the first place.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-18 18:21:37 +01:00
Joachim Nilsson fd7a6c5020 cond.c: Normalize COND_PATH, some systems have /run not /var/run
On most modern Linux systems /run is a tmpfs that replaces /var/run.
The latter is set up as a symlink to /run by the bootmisc.so plugin.

However, Finit conditions rely on the /var/run/finit/cond prefix, which
does not exist until bootmisc.so has run, which is *after* `mount -a`
has run.  Therefore, to have working conditions before we run `mount -a`
we must normalize the path constructed by cond_path() to use either the
/run or /var/run (default) prefix.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-18 14:44:25 +01:00
Joachim Nilsson a61551d15f pid.c: Relocate pid_runpath() to a static inline fn
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-18 14:44:00 +01:00
Joachim Nilsson 7f62a69f74 New hook/mount/post, runs after mount -a but before hook/mount/all
This gives the operator a way to add a post-mount script, e.g. to peform
a 2nd stage mount or mount preparations, before the bootmisc.so plugin
and others run in hook/mount/all

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-18 13:34:28 +01:00
Joachim Nilsson c969bda62d bootmisc.so: Create /etc/mtab symlink if missing
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-18 13:34:28 +01:00
Joachim Nilsson af41fcd35e api_exit(): Must stop libuEv watcher before closing descriptor
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-18 13:34:28 +01:00
Joachim Nilsson 84e9569be6 initctl: Adjust field widths in show/status
The job:id field can now be used to display job:INET_PORT_NUMBER, e.g.
100:16161 for job 100 localhost SNMP port 16161.

The service name field has been reduced from 20 --> 16 bytes since the
full path has been reduced to display the basename.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-17 18:42:24 +01:00
Joachim Nilsson a4ece0fe3f Add log rotate, log, condition and non-SIGHUP example .conf sample
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-16 17:41:03 +01:00
Joachim Nilsson b2f66da1f9 Cleanup TODO, last item turned out to be bogus
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-16 17:06:55 +01:00
Joachim Nilsson abbc0a1d5c Fix Ctrl-C, and signals in general, on "logins" in nologin mode
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-16 16:25:11 +01:00
Joachim Nilsson 37e420bd35 Minor, itemize example files
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-16 16:03:36 +01:00
Joachim Nilsson d72eb45d6e Refactor, simplify text and rename section
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-16 16:02:06 +01:00
Joachim Nilsson 30c593f64e Minor, reorder debug messages to not mess up progress text
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-16 14:55:57 +01:00
Joachim Nilsson f858d94d2a Reinitialize screen at shutdown and when in debug mode
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-16 14:47:14 +01:00
Joachim Nilsson 992bab2f8f Allow empty -- run/task/service descriptions => no progress
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-16 14:38:55 +01:00
Joachim Nilsson 72c9681ffb Change debug messages to use svc->cmd rather than empty svc->desc
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-16 14:15:49 +01:00
Joachim Nilsson e439b79e82 Refactor, only show process progress if -- Description is set
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-16 14:15:10 +01:00
Joachim Nilsson 36e001d636 Refactor, rindex() --> strrchr(), LEGACY as of POSIX.1-2001
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-16 14:13:48 +01:00
Joachim Nilsson 75aa14466f Allow disabling log rotation, log size:0
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-16 07:50:52 +01:00
Joachim Nilsson 7f899b7a91 Clarify size:200k and count:5 global log rotation options
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-16 07:46:27 +01:00
Joachim Nilsson 1c177fd953 TODO before v3.1 GA release
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-16 07:41:20 +01:00
Joachim Nilsson 617ec7c147 Document global log rotation setting log size:200k count:5
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-15 19:42:33 +01:00
Joachim Nilsson 192d3aafe7 Add support for global logfile max size and max num. rotated
# 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 size=100k count=4

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-15 19:42:33 +01:00
Joachim Nilsson f11ebb0046 New function, strtobytes(), allows k/M/G ISO size modifiers
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-15 19:42:33 +01:00
Joachim Nilsson b5e260b9e0 Minor refactor
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-15 18:30:41 +01:00
Joachim Nilsson 45c10edad6 Fix static build, libplug.la is now in ../plugins/, not plugins/
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-15 16:05:39 +01:00
Joachim Nilsson b60d8ce4b6 Fix bootstrap ordering problem, inotify watchers *after* HOOK_BASEFS_UP
An external plugin to set up /etc can use HOOK_BASEFS_UP, but the Finit
conf_monitor() must then be called *after* not before that hook, or the
inotify watchers will listen on the wrong inode.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-15 15:23:25 +01:00
Joachim Nilsson d35a8bbda9 Fix problem building external plugins
The file plugin.h is installed to $prefix/include and used by external
plugins.  Therefore it must not include, or depend on, features set by
the configure script in config.h

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-15 15:07:24 +01:00
Joachim Nilsson c616270ccb Bump version for v3.1-rc2
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-15 12:19:51 +01:00
Joachim Nilsson 890ac2f4e1 Update ChangeLog for upcoming v3.1 release
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-15 12:19:51 +01:00
Joachim Nilsson 8063b1bfe1 Include rescue.conf in distribution
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-15 12:19:51 +01:00
Joachim Nilsson 0bcfb464ce make release: Call distcheck target verify build from tarball
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-15 12:19:51 +01:00
Joachim Nilsson dc5b1a5980 Increase size of intermediate buffers
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-15 12:19:51 +01:00
Joachim Nilsson 14555d7a7b configure: Fix misspelled --enable-redirect option
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-15 10:17:50 +01:00
Joachim Nilsson a06127b990 Document new log:... option to task/run/services
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-15 10:10:20 +01:00
Joachim Nilsson 3b8e7d677f rlimit can be set globally or locally depending on .conf file
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-15 10:06:19 +01:00
Joachim Nilsson 097fce4170 Ignore logit binary
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-15 10:03:12 +01:00
Joachim Nilsson 306bf0f191 Add support for configurable redirect to /dev/null, issue #21
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-15 07:44:33 +01:00
Joachim Nilsson f25390004b Add support for redirecting output to a file using logit, issue #21
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-15 07:44:33 +01:00
Joachim Nilsson cbd4cc8d34 Extend .conf syntax for 'log' option, issue #21
This is the first patch in a series to add support for

    log:/path/to/logfile,priority:facility.level,tag:ident

In this patch support for 'priority:' and 'tag:', log file support
coming later.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-15 07:44:33 +01:00
Joachim Nilsson 44591c6e51 logit: Sync each log entry to file
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-15 07:44:33 +01:00
Joachim Nilsson 0e51a1eed8 logit: Hard code program name and clarify distribution scope
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-15 06:58:44 +01:00
Joachim Nilsson c315fb5637 Add logit v1.0 to Finit distribution
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-15 06:58:44 +01:00
Joachim Nilsson 1017e7b8e5 Disable conditions for some non-oneshot (runtime) hooks
The SVC_RECONF, SVC_LOST, SVC_START, and RUNLEVEL_CHANGE hooks are not
one-shot, they are also not regular conditions since there exist no
mechanism to reset them from flux.

One idea was to turn them into actions, but the lost + start hooks need
to be called multiple times per trigger, e.g. `initctl reload`, which
turned out to be non-trivial to implement right now.

Therefore, for (at least) the Finit v3.1 release these conditions have
been disabled ("nop") and ignored by Finit.  Only actual C-style plugins
will be called.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-14 11:24:29 +01:00
Joachim Nilsson 8ef216af62 Let hook conditions be oneshot, prevents flux on reload
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-14 11:24:29 +01:00
Joachim Nilsson a9b9631098 Minor, reduce debug noise from plugin recursion
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-14 11:24:29 +01:00
Joachim Nilsson cc186334e0 Add support for one-shot conditions, like most hooks
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-14 11:24:29 +01:00
Joachim Nilsson e1b87d707f Support touching custom PID files
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-13 22:03:17 +01:00
Joachim Nilsson 68e7bcba4c Refactor and document pid_file_parse()
This patch cleans up the implmentation, adds documentation and also
makes sure to adjust the prefix path of a pid:/prefix/path argument.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-13 21:52:06 +01:00
Joachim Nilsson f9783b4b41 pidfile: Use realpath() to figure out of _PATH_VARRUN is a symlink
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-13 21:49:18 +01:00
Joachim Nilsson 32d9afc7bb Use pid_runpath() in svc_find_by_pidfile(), used by pidfile plugin
The pidfile plugin just listens to changes in files in /run or /var/run,
so when trying to locate an svc_t from a file change we need to compare
using the proper prefix path.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-13 21:47:11 +01:00
Joachim Nilsson 91b550662e New function, pid_runpath(), figures out /var/run or /run prefix
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-13 21:42:13 +01:00
Joachim Nilsson d87af8270e docs/config.md: Document new pid:/optional/file.pid argument
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-12 21:09:55 +01:00
Joachim Nilsson 366c23f5d1 TODO: Remember to handle PID files in subdirectories to /run
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-12 21:07:15 +01:00
Joachim Nilsson 0d4bc69584 pidfile: Use new svc_find_by_pidfile() in plugin
A service may now have a custom PID file, possibly because it doesn't
really create one itself.  This needs to be taken into account also in
the pidfile plugin.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-11 10:50:19 +01:00
Joachim Nilsson cccf199280 New function, svc_find_by_pidfile()
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-11 10:49:58 +01:00
Joachim Nilsson a1c33dec21 Refactor, move all PID file related functions to the same module
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-11 10:48:17 +01:00
Joachim Nilsson df303c6243 Nota bene, changing name of PID file of running process
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-11 09:05:24 +01:00
Joachim Nilsson 6a6ae6fa3b Fix #95: Create PID file if program does not
This patch adds support for creating, and removing, a PID file for
programs (services) that for some reason does not create one.  With
Finit this is very useful since it allows us to use our condition
support even for "broken" daemons.

To enable this for a service, use the following syntax:

    service pid[:[/path/to/]file[.pid]] /path/to/daemon

I.e., `pid` is a required argument if you want to enable the feature,
but the rest is optional:

    pid             --> /run/`basename $CMD`.pid
    pid:file        --> /run/file.pid
    pid:file.dip    --> /run/file.dip
    pid:/mnt/k      --> /mnt/k.pid
    pid:/mnt/k.foo  --> /mnt/k.foo

There is an additional feature with this patch.  For daemons that run
with a different identiy one usually wants to create the PID file with
that identity, e.g.:

    service inadyn -I dyn     -- Dyn.com DDNS client
    service inadyn -I freedns -- FreeDNS DDNS client

Here inadyn will look for /etc/dyn.conf and create /run/dyn.pid, and
/etc/freedns.conf and create /run/freedns.pid, respetively.  While Finit
will in both cases assume the PID file is /run/inadyn.pid ... err fail!

To get out of this mess the `pid` argument can be used to tell Finit
what the real PID file the daemon creates is called:

    service pid:!dyn     inadyn -I dyn     -- Dyn.com DDNS client
    service pid:!freedns inadyn -I freedns -- FreeDNS DDNS client

The same composition rules listed above applies also to the `!` variant.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-10 23:27:05 +01:00
Joachim Nilsson 4011b5a3b8 Relocate all docs from doc/* to docs/*, integrates better w/ GitHub
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-10 02:28:33 +01:00
Joachim Nilsson 68ef6ec108 Fix v3.1 regression, segfault when inetd service connection exits
The service_step() function may call svc_del() on an svc from the
service_monitor(), so we need a way to tell the latter that it no
longer can dereference the pointer.

This regression is limited to v3.1, due to the introduction of the
new non-shared-memory store of svc_t.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-10 02:10:14 +01:00
Joachim Nilsson 89a9d92d6c Refactor construction of inetd service connection description
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-10 01:41:14 +01:00
Joachim Nilsson 15cb576293 Fix v3.1 regression in start of inetd services, missing rlimit
Per service rlimit is new in v3.1.  When an inetd service connection is
created we do a selective copy from the parent inetd.  We also need to
copy the parent's rlimits, otherwise the child will be killed as soon
as the kernel starts it.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-10 01:36:24 +01:00
Joachim Nilsson 90734eee16 reboot: Reboot via Finit + watchdogd may take a while
This patch increases the default wait, 2 --> 5 sec, while pending for
Finit + watchdogd controlled reboot/shutdown.  We don't want to hand
back the prompt when we're not really ready yet.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-04 11:20:08 +01:00
Joachim Nilsson 71915e0e14 Make sure log_exit() restores progress output on shutdown/reboot
This patch builds on top of the recently introduced "silent by default"
and support for kernel cmdline `splash` to disable silent operation.

At shutdown/reboot `log_exit()` is called, the intention is to re-enable
progress output so the user can see what's going on.  So, we need to re-
set `silent` to the same setting as log_init() started with, hence the
new `muffler()`.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-04 11:16:58 +01:00
Joachim Nilsson 112ab2c22f initctl: Refactor, use struct command rather than command_t
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-04 11:15:55 +01:00
Joachim Nilsson 8f00ac2e90 Do *not* redirect stdout/stderr of services by default
Automatic redirection of output was introduced in v3.0 and for the
upcoming v3.1 a configure option was added to disable it.

By popular demand this patch flips the default.  One now has to
explicitly enable this feature to get redirection.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-04 11:12:59 +01:00
Joachim Nilsson 6fb070c75c TODO: Update and remove recently fixed items \o/
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-31 18:31:02 +01:00
Joachim Nilsson 8fd431f3e9 initctl: Show uptime of running services in show <NAME> output
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-31 18:30:08 +01:00
Joachim Nilsson 50f128cd1d Track service start time using new jiffies() function
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-31 18:29:43 +01:00
Joachim Nilsson f6fa576270 New functions: jiffies() and uptime(), implemented with sysinfo()
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-31 18:28:29 +01:00
Joachim Nilsson b26d30757d Document new initctl status <JOB|NAME> command
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-31 17:11:15 +01:00
Joachim Nilsson dc9d0b6fca Add service wrapper script, sometimes more convenient to use
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-31 17:08:35 +01:00
Joachim Nilsson ff95ca92b1 Update cron syntax proposal: @hourly, @daily, @weekly, @reboot, etc.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-31 16:52:09 +01:00
Joachim Nilsson c939aed87f Add net/IFNAME/running to list of supported conditions
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-31 15:01:11 +01:00
Joachim Nilsson 71ea9e2ea3 Support for restarting initctl API socket on SIGHUP
This patch adds support for restarting the API socket on SIGHUP, similar
to how SysV init and systemd use SIGUSR1 to restart their FIFO or D-Bus.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-31 13:28:27 +01:00
Joachim Nilsson b6bd10d960 Follow-up to c1344e8, never shutdown() API socket, or segfault
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-31 13:27:25 +01:00
Joachim Nilsson 87d8157175 fixup! netlink.so: Add support for IFF_RUNNING => net/IFNAME/running
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-31 13:26:58 +01:00
Joachim Nilsson cf6faa9eeb netlink.so: Refactor, break out condition set/clear func.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-31 12:41:27 +01:00
Joachim Nilsson 80a71aff07 netlink.so. Refactor (simplify) and fix problem with loss of events
An interface may come up with IFF_RUNNING already set, but we would
only detect IFF_UP.  This patch simplfies the code a lot by pivoting
the qualifier from using ifi_change to ifi_flags, which is the actual
current status of an interface.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-31 12:25:50 +01:00
Joachim Nilsson 04a4653e9b netlink.so: Add support for IFF_RUNNING => net/IFNAME/running
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-31 12:07:47 +01:00
Joachim Nilsson 3aa9d9f451 README: Document how to re-enable progress with configure or splash
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-30 22:10:10 +01:00
Joachim Nilsson c1afca9c33 README: Clarify that runparts runs *before* networking is up
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-30 22:01:56 +01:00
Joachim Nilsson 205915d42f Document new rescue (recovery) mode
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-30 21:58:26 +01:00
Joachim Nilsson 631f89b58c conf_parse_cmdline(): Relax check for 'debug' flag
Relax check for 'debug' flag, we want to catch '--debug' and 'finit_debug'

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-30 21:57:36 +01:00
Joachim Nilsson 6d1c245985 Update documentation, debug replaces --debug and finit_debug
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-30 21:56:24 +01:00
Joachim Nilsson fc08b0c65b README: Clarify runlevel section a bit, new 'single' user mode
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-30 21:46:03 +01:00
Joachim Nilsson 83021b11d8 No need to take down network if it's already down (at boot)
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-30 21:33:45 +01:00
Joachim Nilsson 5309ece2f9 Add support for splash progress mode from kernel cmdline
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-30 21:28:30 +01:00
Joachim Nilsson 6480850ee2 Enforce *no networking* in single-user mode, runlevel 1
This is a quite intrusive change.  In addition to the already reserved
runlevels 0 and 6, halt and reboot, respectively, this patch reserves
runlevel 1 as *no networking*, like the traditional SysV init did.  One
of the reasons for this change is the new 'single' user mode, introduced
earlier.  Most users when entering 'S' or 'single' on the kernel cmdline
expect the single user mode (runlevel 1) to be without networking.

This leaves 2, 3, 4, 5, and 7, 8, 9 as fully user-configurable runlevels
with networking.

Of course, networking can still be enabled in runlevel 1 using ifconfig
or ifupdown, or change runlevel.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-30 21:20:06 +01:00
Joachim Nilsson eaa82377c4 Add support for single (S) user mode from kernel cmdline
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-30 21:20:06 +01:00
Joachim Nilsson 5b3df3654c conf_parse_cmdline(): Use strict string comparison
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-30 21:20:06 +01:00
Joachim Nilsson 55cb50ef90 In rescue mode, always set hostname from /lib/finit/rescue.conf
If hostname is missing from /lib/finit/rescue.conf the system will
default to the configured default hostname (noname).

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-30 21:20:06 +01:00
Joachim Nilsson 3f7e03e813 Refactor, re-order a bit so screen_init() doesn't run in rescue mode
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-30 21:20:06 +01:00
Joachim Nilsson ab723d2f31 Add support for a rescue (recovery) mode from kernel cmdline
This patch adds a rescue (revovery) mode to Finit.  Simply add `rescue`
to the kernel cmdline at boot and the following steps at bootstrap will
be skipped:

- Load of services/run/task/etc in /etc/finit.conf + /etc/finit.d/*.conf
- fsck of filesystems in /etc/fstab
- Remount of / to read-write
- Mount of all filesystems in /etc/fstab
- swapon
- A few plugin hooks:
  - HOOK_ROOTFS_UP
  - HOOK_MOUNT_ERROR
  - HOOK_BASEFS_UP
- `runparts DIR`
- /etc/rc.local

Instead of loading /etc/finit.conf and /etc/finit.d/*.conf Finit loads
the file /lib/finit/rescue.conf, which can be overridden by the operator
if needed.  If this file is removed (or lost), Finit falls back to start
a simple root shell, without any login.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-30 21:20:06 +01:00
Joachim Nilsson bc149d95fc conf: Add hostname alias to host
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-30 21:20:06 +01:00
Joachim Nilsson c605874b26 Remove --with-plugindir=DIR, use --prefix or --libdir instead
The /lib/finit/plugins path is as of this patch not longer possible to
change.  Use --prefix or --libdir instead to change the leading path.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-30 21:20:06 +01:00
Joachim Nilsson c33ba6a477 Remove reboot symlinks properly on uninstall
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-30 21:20:06 +01:00
Joachim Nilsson 63199d368f conf: lim2str(): Fix buffer overflow in local debug function
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-30 21:20:06 +01:00
Joachim Nilsson db3263c441 Refactor conf_parse_cmdline(), support 'debug' as well as '--debug'
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-30 21:19:55 +01:00
Joachim Nilsson 925212f7cf Merge pull request #94 from joerg-krause/patch-1
doc/config.md: Add entry about using wrapper scripts to execute pre commands
2017-12-30 21:03:03 +01:00
Jörg Krause ad401280c2 doc/config.md: Add entry about using wrapper scripts to execute pre commands
See: https://github.com/troglobit/finit/issues/93
2017-12-30 17:55:12 +01:00
Joachim Nilsson f3d2586417 Fix build warning on musl libc
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-30 13:12:05 +01:00
Joachim Nilsson 6fc1d27bcf conf: Check if a kernel module has been loaded first
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-30 13:09:34 +01:00
Joachim Nilsson f3305e75b7 conf_reload(): Exit properly, even if no /etc/finit.d/*.conf exitsts
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-30 12:47:27 +01:00
Joachim Nilsson e4c12314b1 doc/config.md: Mention /etc/finit.d/available/ and initctl enable
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-29 21:00:46 +01:00
Joachim Nilsson c9a1a64ce5 doc/config.md: Update with changes to finit.conf and stanza limits
Finit v3.1 adds support for reloading /etc/finit.conf, document what
actually is read at runtime, compared to at bootstrap, and clarify
which stanzas are for what part of the boot process.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-29 20:52:43 +01:00
Joachim Nilsson 3843f62aa8 README.md: Update with difference between runparts & /etc/rc.local
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-29 20:51:42 +01:00
Joachim Nilsson ef54c4826b bootstrap.md: runparts goes before the runlevel change
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-29 20:51:14 +01:00
Joachim Nilsson 2fac65becb Fix long-standing bug, runparts() should run before runlevel change
The difference between `runparts DIR` and `/etc/rc.local` is that one
should run just before the first runlevel change (to the configured
runlevel) at the end of bootstrap, whereas the other should run just
before launcing the TTYs, i.e. after all tasks in the configured
runlevel have been started.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-29 20:48:47 +01:00
Joachim Nilsson 46b253dea6 doc: The module configuration stanza supports optional args
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-29 20:15:29 +01:00
Joachim Nilsson b04983c3f3 conf: Make rlimit [hard|soft] optional => possible to set both
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-29 20:15:12 +01:00
Joachim Nilsson f2d142ef57 Only reload .conf and services if any .conf file has changed
This patch is an optimization.  Now that we monitor for any .conf file
changes (as soon as the event loop starts) we can skip automatic reload
of all .conf files and services if no .conf file has changed.  Unless
the user issues an `initctl reload`, `init q`, or sends us SIGHUP.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-29 19:22:01 +01:00
Joachim Nilsson 33ce746e58 parse_conf(): Increase log with actual limits in case of problems.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-29 16:57:36 +01:00
Joachim Nilsson 6ecb86b4a7 conf_reload(): No need to reload global rlimits again
This patch removes duplicate reload of global_rlimit[], which
parse_conf() already has done.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-29 16:56:30 +01:00
Joachim Nilsson 338810b886 Fix #92: Load .conf files and initialize global_rlimit[] earlier
As reported in #92, systems with an udevd very early register a service
using global_rlimit[].  The change was introduced in b68c5c1 but did
not take the ordering problem into consideration, global_rlimit[] was
left uninitialized, which likely led to severely limited udevd that
was continously crashing.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-29 16:51:49 +01:00
Joachim Nilsson c1344e89ff api_exit(): Only shutdown() of API socket at runtime
Not needed at shutdown/reboot.  Also, it may segfault at that stage.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-28 20:48:44 +01:00
Joachim Nilsson bc35b42bd2 inet_stop(): Check argument and skip shutdown(), just close() socket
- Validate function argument
- Skip¹ shutdown() when closing a TCP socket, not needed

___
¹ also, shutdown() segfaults a late shutdown/reboot

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-28 20:46:19 +01:00
Joachim Nilsson dcf8fbe235 do_shutdown(): Advise watchdog using SIGPWR, system is going down
On shutdown/reboot, send SIGPR as a heads-up to watchdogd that the
system is going down.  All file systems are about to be unmounted.
It's just about the last process left running in the system, so we
give it two seconds to complete its work before we continue.

When everything has been unmounted and we're ready to call reboot(),
we send SIGTERM to the registered watchdog, to give ti the chance to
let the WDT reset the system.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-28 20:45:02 +01:00
Joachim Nilsson c82a2ce215 Built-in watchdog: on SIGPWR, exit main loop and prepare for SIGTERM
When Finit enters shutdown/reboot we need to advise any watchdogd that
we are going down *before* we unmount any file systems.  This to let
the user save any state, e.g. reboot counters, to disk.  Right before
we call reboot() in Finit we send SIGTERM to the watchdogd to give it
the chance to use the WDT to reboot the system.

The WDT cricuitry on embedded systems is often connected to the RESETn
logic of all relevant board compoents, whereas reboot() only reboots the
SoC with the CPU.  Hence, a WDT reboot is more efficient and more like a
regular power cycle, which users of embedded systems often want.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-28 20:24:32 +01:00
Joachim Nilsson e1bb5e3396 Add --disable-redirect-output to configure script
This patch makes it possible to control the default redirection of
(misbehaving) services output to /dev/null.  With this disabled,
a service may write to its stdout/stderr and mess up the console.

By default all service/run/tasks stdout/stderr is redirected.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-28 20:22:06 +01:00
Joachim Nilsson 8198582c10 Revert "Travis-CI: Disable clang temporarily, for Coverity Scan run"
This reverts commit cbafbaea1d.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-24 11:01:24 +01:00
Joachim Nilsson 0d19842aa1 conf_changed(): Fix possible NULL ptr deref, found by Coverity Scan
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-24 10:35:07 +01:00
Joachim Nilsson 6f665ab283 inet_dgram_drop(): Fix control flow logic, found by Coverity Scan
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-24 10:31:19 +01:00
Joachim Nilsson 3f731aa5a3 inet_dgram_drop(): Check return value from recv()
Found by Coverity Scan.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-24 10:28:22 +01:00
Joachim Nilsson 9e8a01669e api: Fix possible descriptor leak, found by Coverity Scan
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-24 10:02:49 +01:00
Joachim Nilsson cbafbaea1d Travis-CI: Disable clang temporarily, for Coverity Scan run
... so we don't lose tokens ...

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-24 09:53:14 +01:00
Joachim Nilsson f534368b33 The @console and nologin flags deserve mentioning early
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-24 09:51:16 +01:00
Joachim Nilsson 78fc9fccc5 Update initctl usage text
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-24 09:51:04 +01:00
Joachim Nilsson 3f7df3d35e Update ChangeLog with new nologin option to tty configs
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-24 03:29:38 +01:00
Joachim Nilsson 9fc33418f9 Document nologin option flag to tty configuration directive
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-24 03:26:31 +01:00
Joachim Nilsson 72bc3b1a91 Fix #91: Add support for tty nologin, to start /bin/sh immediately
This patch adds a `nologin` flag to the `tty` configuration directive,
making it possible to set up really simple embedded systems with no
login.

Example, put the following line in `/etc/finit.d/getty.conf` to get
a "Please press Enter to ..." prompt before being presented with a
root shell prompt.

    tty [12345] @console noclear nologin

Needless to say, this is not very secure, but can be really useful
for developer setups, during board bringup, or similar.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-24 01:54:07 +01:00
Joachim Nilsson d6ea1c0cab Protect internal services like dbus-daemon and udevd
In f3669c7 the difference between static and dynamic services was
removed.  This led to a regression in handling internally created
services for, e.g., dbus-daemon and udevd, mentioned in issue #90.

This patch introduces a "protected" flag for svc_t to prevent the
mark-and-sweep handling of regularly loaded services.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-23 21:57:31 +01:00
Joachim Nilsson 523a270f22 Update README slightly, there's systemd-udevd and eudev these days
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-23 19:33:27 +01:00
Joachim Nilsson 3258edc246 Fix #90: Restore tmpfs mount of /dev/shm, removed in d7401b2
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-23 19:02:06 +01:00
Joachim Nilsson 32b7a14cb3 Add ismnt() helper function, wrap fismnt()
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-12-23 19:00:41 +01:00
79 changed files with 2155 additions and 474 deletions
+8 -1
View File
@@ -2,13 +2,15 @@
*.o
*.so
*.gz
ID
GPATH
GRTAGS
GSYMS
GTAGS
# GNU configure and build system
/autom4te.cache/*
/.deps
/autom4te.cache
/aclocal.m4
/ar-lib
/compile
@@ -33,3 +35,8 @@ GTAGS
/.config
/.stamp
/.unpacked
# WeOS build system
/.autoconf
/.automake
/.built
+5
View File
@@ -1,6 +1,11 @@
Current Maintainer(s):
* Joachim Nilsson <troglobit@gmail.com>
Major Contributors:
* Tobias Waldekranz <tobias@waldekranz.com>
* Mattias Walström <mattias.walstrom@westermo.se>
* Jonas Johansson <jonas.johansson@westermo.se>
Original Author(s):
* Claudio Matsuoka <cmatsuoka@gmail.com>
+47 -4
View File
@@ -4,17 +4,34 @@ Change Log
All relevant changes are documented in this file.
[3.1][] - 2017-12-xx
[3.1][] - 2018-01-23
--------------------
Finit v3.1 require libuEv v2.1.0, or later, and libite v2.0.1, or later.
Improvements to `netlink.so` plugin, per-service `rlimit` support,
improved integration with `watchdogd`, auto-detect TTY console. Much
improved debug, rescue and logging support. Also, many fixes to both
big and small issues, most notably in the condition handling, which no
longer is sensitive to time skips.
This version requires at least libuEv v2.1.0 and libite v2.0.1
### Changes
* Support for more kernel command line settings:
- splash, enable boot progress
- debug, like `--debug` but also enable kernel debug
- single, single user mode (no network)
- rescue, new rescue mode
* Support for `IFF_RUNNING` to netlink plugin => `net/IFNAME/running`
* Support for restarting `initctl` API socket on `SIGHUP`
* Greatly updated `initctl status <JOB|NAME>` command
* Support for `rlimit` per service/run/task/inetd/tty, issue #45
* Support for setting `hard` and `soft` rlimit for a resource at once
* Support for auto-detecting serial console using Linux SysFS, the new
`tty @console` eliminates the need to keep track of different console
devices across embedded platforms: `/dev/ttyS0`, `/dev/ttyAMA0`, etc.
* Add TTY `nologin` option. Bypasses login and skips immediately to a
root shell. Useful during board bringup, in developer builds, etc.
* Support for calling run/tasks on Finit internal HOOK points, issue #18
* Removed support for long-since deprecated `console DEV` setting
* Cosmetic change to login, pressing enter at the `Press enter to ...`
@@ -25,6 +42,9 @@ Finit v3.1 require libuEv v2.1.0, or later, and libite v2.0.1, or later.
of inetd services, and `Loading configuration ...`. No end user knows
what those plugins and configurations are, i.e. internal state+config
* Change kernel WDT timeout (3 --> 30 sec) for built-in watchdog daemon
* Advise watchdog dawmon on shutdown and reboot using `SIGPWR` and then
`SIGTERM`. It is recommended the daemon start a timer on the first
signal, in case the shutdown process somehow hangs.
* Handle `/etc/` OverlayFS, reload /etc/finit.d/*.conf after `mount -a`
* initctl: Add support for printing previous runlevel
* initctl: Support short forms of all commands
@@ -38,6 +58,25 @@ Finit v3.1 require libuEv v2.1.0, or later, and libite v2.0.1, or later.
on mtime of `.conf` files, instead an inotify handler tracks file
changes for time *insensitive* dependency tracking
* Change condition handling to not rely on mtime but a generation id.
* New configure script option `--enable-redirect` to automatically
redirect `stdout` and `stderr` of all applications to `/dev/null`
* New `pid` sub-option to services when a service does not create a PID
file, or when the PID file has another name. Issue #95
* Greatly improved `log` sub-option to service/run/tasks, selectively
redirect `stdout` and `stderr` using the new tool `logit` to either
syslog or a logfile. Issue #44
* Support for automatic log rotation of logfiles created by `log`
option. Use `configure --disable-logrotate` on systems with a
dedicated log rotation service. Issue #44
* Support for disabling service/run/task progress with empty ` --`
description. Note: no description separator gives a default desc.
* Create `/etc/mtab` symlink if missing on system (bootmisc plugin)
* New hook: `hook/mount/post` runs after `mount -a` but before the
`hook/mount/all`, where `bootmisc.so` runs. This provides the
possibility of running a second stage mount command before files in
`/run` and similar are created
* Skip `gdbserver` when unleashing the grim reaper at shutdown
* Distribute and install `docs/` and `contrib/` directories
### Fixes
@@ -57,6 +96,8 @@ Finit v3.1 require libuEv v2.1.0, or later, and libite v2.0.1, or later.
plugin before the pidfile plugin on `HOOK_SVC_RECONF` events
* Handle event loop failure modes, issue found by Westermo
* Handle API socket errors more gracefully, restart socket
* Do not attempt to load kernel modules more than once at bootstrap
* Remove reboot symlinks properly on uninstall
* Fix regression in condition handling, reconf condition must be kept
as a reference point to previous reconfiguration, or bootstrap.
* Fix nasty race condition with internal service stop, abort kill if the
@@ -70,6 +111,7 @@ Finit v3.1 require libuEv v2.1.0, or later, and libite v2.0.1, or later.
* Fix issue #81 properly, remove use of SYSV shm IPC completely. Finit
now use the API socket for all communication between PID 1 and initctl
* Fix segfault on x86_64 when started with kernel cmdline `--debug`
* Normalize condition paths on systems with `/run` instead of `/var/run`
[3.0][] - 2017-10-19
@@ -97,7 +139,7 @@ distributions.
* Ensure plugins always have a default name, file name
* Reorganization, move all source files to a `src/` sub-directory
* Add support for `initctl <list|enable|disable> <SVC>`, much needed by
distributions. See [doc/distro.md](doc/distro.md) for details
distributions. See [docs/distro.md](docs/distro.md) for details
* Remove `UNUSED()` macro, mentioned here because it may have been used
by external plugin developers. Set `-Wno-unused-parameter` instead
* New table headings in `initctl`, using `top` style inverted text
@@ -667,7 +709,8 @@ Major bug fix release.
* Initial release
[UNRELEASED]: https://github.com/troglobit/finit/compare/3.0...HEAD
[UNRELEASED]: https://github.com/troglobit/finit/compare/3.1...HEAD
[3.1]: https://github.com/troglobit/finit/compare/3.0...3.1
[3.0]: https://github.com/troglobit/finit/compare/2.4...3.0
[2.4]: https://github.com/troglobit/finit/compare/2.3...2.4
[2.3]: https://github.com/troglobit/finit/compare/2.2...2.3
+2 -2
View File
@@ -1,5 +1,5 @@
ACLOCAL_AMFLAGS = -I m4
SUBDIRS = plugins src
SUBDIRS = contrib docs plugins src
doc_DATA = README.md LICENSE contrib/finit.conf
EXTRA_DIST = README.md LICENSE ChangeLog.md contrib/finit.conf
@@ -8,7 +8,7 @@ install-dev:
@make -C src install-pkgincludeHEADERS
# Target to run when building a release
release: dist
release: distcheck
@for file in $(DIST_ARCHIVES); do \
md5sum $$file > ../$$file.md5; \
done
+90 -33
View File
@@ -2,17 +2,19 @@
* [Introduction](#introduction)
* [Features](#features)
* [Bootstrap](doc/bootstrap.md#bootstrap)
* [Bootstrap](docs/bootstrap.md#bootstrap)
* [Runlevels](#runlevels)
* [Syntax](doc/config.md#syntax)
* [Inetd](doc/inetd.md#inetd)
* [Syntax](docs/config.md#syntax)
* [Inetd](docs/inetd.md#inetd)
* [Runparts & /etc/rc.local](#runparts--etcrclocal)
* [Hooks, Callbacks & Plugins](doc/plugins.md#hooks-callbacks--plugins)
* [Hooks, Callbacks & Plugins](docs/plugins.md#hooks-callbacks--plugins)
* [Rebooting & Halting](#rebooting--halting)
* [Commands & Status](#commands--status)
* [Building](doc/build.md#building)
* [Running](doc/build.md#running)
* [Debugging](doc/build.md#debugging)
* [Tips & Tricks with the kernel cmdline](docs/cmdline.md)
* [Building](docs/build.md#building)
* [Running](docs/build.md#running)
* [Recovery](docs/build.md#recovery)
* [Debugging](docs/build.md#debugging)
* [Requirements](#requirements)
* [Origin & References](#origin--references)
@@ -27,8 +29,11 @@ was reverse engineered from the [EeePC fastinit][] ten years ago by
Focus is on small and embedded systems, although Finit is fully usable
on server and desktop systems as well. For working examples, see the
[contrib/](contrib/) section where both [Debian](contrib/debian/) and
up to date [Alpine Linux](contrib/alpine/) tutorials can be found.
[contrib/](contrib/) section with tutorials for:
* [Alpine Linux](contrib/alpine/),
* [Debian GNU/Linux](contrib/debian/), and
* [Void Linux](contrib/void/)
![Alpine screenshot](images/alpine-screenshot.png)
The screenshot shows [Alpine Linux](https://www.alpinelinux.org/).
@@ -49,12 +54,23 @@ host default
# Runlevel to start after bootstrap, 'S', default: 2
runlevel 2
# Max file size for each log file: 100 kiB, rotate max 4 copies:
# log => log.1 => log.2.gz => log.3.gz => log.4.gz
log size=100k count=4
# Services to be monitored and respawned as needed
service [S12345] /sbin/watchdogd -L -f -- System watchdog daemon
service [S12345] /sbin/syslogd -n -b 3 -D -- System log daemon
service [S12345] /sbin/klogd -n -- Kernel log daemon
service [2345] /sbin/lldpd -d -c -M1 -H0 -i -- LLDP daemon (IEEE 802.1ab)
# 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
# log file is rotated with the above settings. The condition declares
# a dependency on a system default route (gateway) to be set. A single
# <!> at the beginning means ntpd does not respect SIGHUP for restart.
service [2345] log:/var/log/ntpd.log <!net/route/default> /sbin/ntpd -n -l -I eth0 -- NTP daemon
# For multiple instances of the same service, add :ID somewhere between
# the service/run/task keyword and the command.
service :1 [2345] /sbin/merecat -n -p 80 /var/www -- Web server
@@ -87,10 +103,13 @@ tty [12345] /sbin/getty -L 115200 /dev/tty3 linux
# Use built-in getty for serial port and USB serial
tty [12345] /dev/ttyAMA0 115200 noclear nowait
tty [12345] /dev/ttyUSB0 115200 noclear
# Just give me a shell, I need to debug this embedded system!
tty [12345] @console noclear nologin
```
The `service` stanza, as well as `task`, `run`, `inetd` and others are
described in full in [doc/config.md](doc/config.md). Here's a quick
described in full in [docs/config.md](docs/config.md). Here's a quick
overview of some of the most common components needed to start a UNIX
daemon:
@@ -111,7 +130,7 @@ advanced uses as well:
service /usr/sbin/sshd -D
Dependencies are handled using [conditions](doc/conditions.md). One of
Dependencies are handled using [conditions](docs/conditions.md). One of
the most common conditions is to wait for basic networking to become
available:
@@ -152,7 +171,7 @@ Start, monitor and restart services should they fail.
**Inetd**
Finit comes with a built-in [inetd server](doc/inetd.md). No need to
Finit comes with a built-in [inetd server](docs/inetd.md). No need to
maintain a separate config file for services that you want to start on
demand.
@@ -167,7 +186,7 @@ Built-in optional inetd services:
- discard [RFC863][]
- time (rdate) [RFC868][]
For more information, see [doc/inetd.md](doc/inetd.md).
For more information, see [docs/inetd.md](docs/inetd.md).
**Getty**
@@ -192,7 +211,9 @@ figures it out by querying sysfs: `/sys/class/tty/console/active`.
tty [12345] @console 115200 linux noclear
```
For more information, see [doc/config.md](doc/config.md#syntax).
Notice the optional `noclear`, `nowait`, and `nologin` flags. The
latter is for skipping the login process entirely. For more information,
see [docs/config.md](docs/config.md#syntax).
**Runlevels**
@@ -201,10 +222,18 @@ Support for SysV init-style [runlevels][5] is available, in the same
minimal style as everything else in Finit. The `[2345]` syntax can be
applied to service, task, run, inetd, and TTY stanzas.
All services in runlevel S(1) are started first, followed by the desired
run-time runlevel. Runlevel S can be started in sequence 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 `intictl` tool.
Reserved runlevels are 0 and 6, halt and reboot, respectively just like
SysV init. Runlevel 1 can be configured freely, but is recommended to
be kept as the system single-user runlevel since Finit will not start
networking here. The configured `runlevel NUM` from `/etc/finit.conf`
is what Finit changes to after bootstrap, unless 'single' (or 'S') is
given on the kernel cmdline, in which case runlevel 1 is started.
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
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
`intictl` tool.
**Plugins**
@@ -229,25 +258,49 @@ Extensions and functionality not purely related to what an `/sbin/init`
needs to start a system are available as a set of plugins that either
hook into the boot process or respond to various I/O.
For more information, see [doc/plugins.md](doc/plugins.md).
For more information, see [docs/plugins.md](docs/plugins.md).
**Progress**
Finit prior to v3.0 showed the progress at boot: plugins and modules
being loaded, run/tasks/services being started, etc. By default Finit
is now silent, but progress can still be enabled at build-time using:
configure --enable-progress
or at boot from the kernel cmdline using the boot parameter `splash`:
```shell
append="init=/sbin/finit splash"
```
For a really nice boot, add `quiet` as well. This silences the output
from the kernel, leaving only warnings and errors. For other kernel
command line parameters, see [docs/build.md](docs/build.md#recovery).
Runparts & /etc/rc.local
------------------------
At the end of the boot, when networking and all services are up, Finit
calls its built-in [run-parts(8)][] on the `runparts <DIR>` directory,
and `/etc/rc.local`, in that order if they exist.
At the end of the boot, when all bootstrap (`S`) tasks and services have
started, but not networking, Finit calls its built-in [run-parts(8)][]
command on any configured `runparts <DIR>` directory. This happens just
before changing to the configured runlevel (default 2). (Networking is
enabled just prior to changing from single user mode.)
```shell
runparts /etc/rc.d/
```
Right after the runlevel change when all services have started properly,
`/etc/rc.local` is called.
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 end of the boot, before calling the `HOOK_SYSTEM_UP`. See more on
hooks in [doc/plugins.md](doc/plugins.md#hooks), and about the system
bootstrap in [doc/bootstrap.md](doc/bootstrap.md).
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
in [docs/plugins.md](docs/plugins.md#hooks), and about the system bootstrap
in [docs/bootstrap.md](docs/bootstrap.md).
Runlevels
@@ -325,7 +378,7 @@ section.
For compatibility reasons Finit listens to the same set of signals as
BusyBox init. This is not 100% compatible with SysV init, but clearly
the more common combination for Finit. For more details, see
[doc/signals.md](doc/signals.md).
[docs/signals.md](docs/signals.md).
Finit also listens to the classic SysV init FIFO, used by `telinit`.
Support for this is implemented by the `initctl.so` plugin. Hence,
@@ -373,6 +426,7 @@ Commands:
list List all .conf in /etc/finit.d/
enable <CONF> Enable .conf in /etc/finit.d/available/
disable <CONF> Disable .conf in /etc/finit.d/[enabled/]
touch <CONF> Mark .conf in /etc/finit.d/ for reload
reload Reload *.conf in /etc/finit.d/ (activates changes)
cond set <COND> Set (assert) condition => +COND
@@ -384,6 +438,7 @@ Commands:
start <JOB|NAME>[:ID] Start service by job# or name, with optional ID
stop <JOB|NAME>[:ID] Stop/Pause a running service by job# or name
restart <JOB|NAME>[:ID] Restart (stop/start) service by job# or name
status <JOB|NAME>[:ID] Show service status, by job# or name
status | show Show status of services, default command
runlevel [0-9] Show or set runlevel: 0 halt, 6 reboot
@@ -396,7 +451,7 @@ Commands:
For services *not* supporting `SIGHUP` the `<!>` notation in the .conf
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](docs/conditions.md),
these will also affect how a service is maintained.
**Note:** even though it is possible to start services not belonging in
@@ -422,11 +477,13 @@ Requirements
------------
Finit is capable of running on both desktop/server systems with udev and
embedded systems that usually come with BusyBox mdev. Finit probes for
them at runtime and expects `/dev/` to be writable, usually `devtmpfs`.
It is also possible to run on a statically set up `/dev` if needed. It
is however not a good idea to have both udev and mdev installed at the
same time, this will lead to unpredictable results.
embedded systems that usually come with BusyBox mdev. Some systems have
systemd-udev or eudev today instead of the original udev, Finit probes
for all of them at runtime and expects `/dev/` to be a writable file
system using `devtmpfs`. It is also possible to run on a statically set
up `/dev` if needed. It is however not a good idea to have both udev
and mdev installed at the same time, this will lead to unpredictable
results.
At boot Finit calls either `mdev` or `udevd` to populate `/dev`, this is
done slightly differently and on systems with udev you might want to add
+29 -7
View File
@@ -1,10 +1,17 @@
AC_INIT(Finit, 3.1-rc1, https://github.com/troglobit/finit/issues, finit, http://troglobit.com/finit.html)
AC_INIT(Finit, 3.1, https://github.com/troglobit/finit/issues, finit, http://troglobit.com/finit.html)
AM_INIT_AUTOMAKE([1.11 foreign no-dist-gzip dist-xz subdir-objects])
AM_SILENT_RULES([yes])
AC_CONFIG_SRCDIR([src/finit.c])
AC_CONFIG_HEADER([config.h])
AC_CONFIG_FILES([Makefile plugins/Makefile src/Makefile])
AC_CONFIG_FILES([Makefile
contrib/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/grub.d/Makefile
contrib/void/Makefile contrib/void/finit.d/Makefile contrib/void/finit.d/available/Makefile
docs/Makefile
plugins/Makefile
src/Makefile])
# Older versions of autoconf (<2.58) do not have AC_CONFIG_MACRO_DIR()
#m4_include([m4/plugin.m4])
@@ -21,6 +28,7 @@ LT_INIT([shared disable-static dlopen aix-soname=both disable-fast-install])
AC_PROG_CC
AC_PROG_LN_S
AC_PROG_INSTALL
AC_PROG_MKDIR_P
# Configuration.
AC_HEADER_STDC
@@ -58,6 +66,10 @@ AC_ARG_ENABLE(watchdog,
AS_HELP_STRING([--enable-watchdog], [Enable built-in watchdog, uses /dev/watchdog]),,[
enable_watchdog=no])
AC_ARG_ENABLE(redirect,
AS_HELP_STRING([--enable-redirect], [Redirect service output to /dev/null, default: no]),,[
enable_redirect_output=no])
AC_ARG_ENABLE(inetd,
AS_HELP_STRING([--disable-inetd], [Disable built-in inetd super server, default enabled]),,[
enable_inetd=yes])
@@ -89,11 +101,6 @@ AC_ARG_WITH(fifo,
AS_HELP_STRING([--with-fifo=FIFO], [FIFO for init/telinit clients, default /var/run/initctl]),
[fifo=$withval], [fifo=$localstatedir/run/initctl])
AC_ARG_WITH(plugindir,
AS_HELP_STRING([--with-plugindir=DIR], [Finit plugin directory, default /lib/finit/plugins]),
[pkglibdir=$withval], [pkglibdir=$libdir/finit/plugins])
AC_SUBST([pkglibdir])
AC_ARG_WITH(config,
AS_HELP_STRING([--with-config=CONFIG], [Finit bootstrap config file, default /etc/finit.conf]),
[conf=$withval], [conf=$sysconfdir/finit.conf])
@@ -143,6 +150,9 @@ AS_IF([test "x$enable_progress" = "xyes"], [
AS_IF([test "x$enable_watchdog" = "xyes"], [
AC_DEFINE(BUILTIN_WATCHDOG, 1, [Enable built-in watchdog, kicks on /dev/watchdog])])
AS_IF([test "x$enable_redirect" = "xyes"], [
AC_DEFINE(REDIRECT_OUTPUT, 1, [Enable redirection of service output to /dev/null])])
### Disable features ###########################################################################
AS_IF([test "x$enable_inetd" != "xno"], [
enable_inetd="yes"
@@ -207,6 +217,17 @@ AM_CONDITIONAL(STATIC, [test "x$enable_static" = "xyes"])
AM_CONDITIONAL(INETD, [test "x$enable_inetd" = "xyes"])
AM_CONDITIONAL(WATCHDOGD, [test "x$enable_watchdog" = "xyes"])
# Override default libdir, used for plugins and rescue.conf
#pkglibdir=$libdir/finit
#AC_SUBST(pkglibdir)
#AC_EXPAND_DIR(pkglibdir, "$libdir/finit")
AC_EXPAND_DIR(plugin_path, "$libdir/finit/plugins")
AC_SUBST(plugin_path)
AC_DEFINE_UNQUOTED(PLUGIN_PATH, "$plugin_path", [Finit plugin path])
AC_EXPAND_DIR(rescue_conf, "$libdir/finit/rescue.conf")
AC_DEFINE_UNQUOTED(RESCUE_CONF, "$rescue_conf", [Finit rescue mode .conf])
# Generate all files
AC_OUTPUT
@@ -220,6 +241,7 @@ cat <<EOF
FIFO path.............: $fifo_path
Finit config file.....: $conf_path
Finit config.d path...: $rcsd_path
Finit plugin path.....: $plugin_path
Compat rc.local path..: $rclocal_path
Random seed path......: $random_path
C Compiler............: $CC $CFLAGS $CPPFLAGS $LDFLAGS $LIBS
+2
View File
@@ -0,0 +1,2 @@
Makefile
Makefile.in
+5
View File
@@ -0,0 +1,5 @@
SUBDIRS = alpine debian void
bin_SCRIPT = service
docsdir := @docdir@/contrib
docs_DATA = README.md finit.conf procmon.sh
EXTRA_DIST = $(docs_DATA)
+5
View File
@@ -0,0 +1,5 @@
SUBDIRS = finit.d
docsdir := @docdir@/contrib/alpine
docs_DATA = README.md finit.conf alpine-release build.sh install.sh rc.local
EXTRA_DIST = $(docs_DATA)
+27
View File
@@ -0,0 +1,27 @@
SUBDIRS = available
docsdir := @docdir@/contrib/alpine/finit.d
d_LINKS = dropbear.conf getty.conf keymap.conf modules.conf klogd.conf \
syslogd.conf
install-exec-hook:
@$(MKDIR_P) $(DESTDIR)$(docsdir)
@for file in $(d_LINKS); do \
lnk=$(DESTDIR)$(docsdir)/$$file; \
src=available/$$file; \
if [ -L $$lnk ]; then \
echo "Skipping $$lnk exists."; \
else \
$(LN_S) $$src $$lnk; \
fi; \
done
uninstall-hook:
@for file in $(d_LINKS); do \
lnk=$(DESTDIR)$(docsdir)/$$file; \
src=available/$$file; \
if [ "`readlink $$lnk`" != "$$src" ]; then \
continue; \
fi; \
$(RM) $$lnk; \
done
@@ -0,0 +1,4 @@
docsdir := @docdir@/contrib/alpine/finit.d/available
docs_DATA = acpid.conf crond.conf dropbear.conf getty.conf keymap.conf \
lxdm.conf modules.conf ntpd.conf klogd.conf syslogd.conf
EXTRA_DIST = $(docs_DATA)
+4
View File
@@ -0,0 +1,4 @@
SUBDIRS = finit.d grub.d
docsdir := @docdir@/contrib/debian
docs_DATA = README.md finit.conf os-release build.sh install.sh
EXTRA_DIST = $(docs_DATA)
+27
View File
@@ -0,0 +1,27 @@
SUBDIRS = available
docsdir := @docdir@/contrib/debian/finit.d
d_LINKS = console-setup.conf getty.conf keyboard-setup.conf \
modules.conf rsyslogd.conf sshd.conf
install-exec-hook:
@$(MKDIR_P) $(DESTDIR)$(docsdir)
@for file in $(d_LINKS); do \
lnk=$(DESTDIR)$(docsdir)/$$file; \
src=available/$$file; \
if [ -L $$lnk ]; then \
echo "Skipping $$lnk exists."; \
else \
$(LN_S) $$src $$lnk; \
fi; \
done
uninstall-hook:
@for file in $(d_LINKS); do \
lnk=$(DESTDIR)$(docsdir)/$$file; \
src=available/$$file; \
if [ "`readlink $$lnk`" != "$$src" ]; then \
continue; \
fi; \
$(RM) $$lnk; \
done
@@ -0,0 +1,5 @@
docsdir := @docdir@/contrib/debian/finit.d/available
docs_DATA = acpid.conf console-setup.conf getty.conf \
keyboard-setup.conf lightdm.conf modules.conf \
ntpclient.conf rsyslogd.conf sshd.conf xdm.conf
EXTRA_DIST = $(docs_DATA)
+3
View File
@@ -0,0 +1,3 @@
docsdir := @docdir@/contrib/debian/grub.d
docs_DATA = 40_custom
EXTRA_DIST = $(docs_DATA)
+11
View File
@@ -17,6 +17,10 @@ runlevel 2
# Network bringup script
network service networking start
# 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 size=100k count=4
# Virtual consoles to start getty on
tty /dev/tty1
tty /dev/tty2
@@ -33,6 +37,13 @@ service [2345] /sbin/klogd -n -- Kernel logging server
service [2345] /sbin/syslogd -n -- Syslog server
service [3] /usr/sbin/gdm -- GNOME Display Manager
# 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
# log file is rotated with the above settings. The condition declares
# a dependency on a system default route (gateway) to be set. A single
# <!> at the beginning means ntpd does not respect SIGHUP for restart.
service [2345] log:/var/log/ntpd.log <!net/route/default> /sbin/ntpd -n -l -I eth0 -- NTP daemon
# Run start scripts from this directory
# runparts /etc/start.d
+51
View File
@@ -0,0 +1,51 @@
#!/bin/sh
USAGE="Usage: $0 processName"
LOG_FILE="/tmp/memusage.csv"
ELAPSED_TIME=0
PERIOD=1 # seconds
if [ $# -ne 1 ]; then
echo $USAGE
exit 1
fi
echo "ElapsedTime,VmSize,VmRSS" > $LOG_FILE
# Monitor memory usage forever until script is killed
while :
do
SUM_VM_SIZE=0
SUM_RSS_SIZE=0
# In case the monitored process has not yet started
# keep searching until its PID is found
PROCESS_PIDS=""
while :
do
PROCESS_PIDS=`/bin/pidof $1`
if [ "$PROCESS_PIDS.X" != ".X" ]; then
break
fi
done
for PID in ${PROCESS_PIDS} ; do
VM_SIZE=`awk '/VmSize/ {print $2}' < /proc/$PID/status`
if [ "$VM_SIZE.X" = ".X" ]; then
continue
fi
#echo exprVM_ $SUM_VM_SIZE + $VM_SIZE
SUM_VM_SIZE=`expr $SUM_VM_SIZE + $VM_SIZE`
VM_RSS=`awk '/VmRSS/ {print $2}' < /proc/$PID/status`
if [ "$VM_RSS.X" = ".X" ]; then
continue
fi
SUM_RSS_SIZE=`expr $SUM_RSS_SIZE + $VM_RSS`
done
echo "$ELAPSED_TIME sec, $SUM_VM_SIZE KB, $SUM_RSS_SIZE KB"
echo "$ELAPSED_TIME,$SUM_VM_SIZE,$SUM_RSS_SIZE" >> $LOG_FILE
sleep $PERIOD
VM_SIZE=""
VM_RSS=""
# Needs to get actual elapsed time instead of doing this
ELAPSED_TIME=`expr $ELAPSED_TIME + $PERIOD`
done
+33
View File
@@ -0,0 +1,33 @@
#!/bin/sh
JOB=$1
CMD=$2
usage() {
echo "Usage: service [job# | name] <stop | start | restart | status | show>"
exit 1
}
if [ $# -eq 0 ]; then
initctl show
exit 0
fi
case $CMD in
stop)
;;
start)
;;
restart)
;;
status)
;;
show)
;;
*)
usage
;;
esac
initctl $2 $1
+4
View File
@@ -0,0 +1,4 @@
SUBDIRS = finit.d
docsdir := @docdir@/contrib/void
docs_DATA = README.md finit.conf build.sh install.sh rc.local xbps
EXTRA_DIST = $(docs_DATA)
+26
View File
@@ -0,0 +1,26 @@
SUBDIRS = available
docsdir := @docdir@/contrib/void/finit.d
d_LINKS = acpid.conf dhcpcd.conf getty.conf sshd.conf uuidd.conf
install-exec-hook:
@$(MKDIR_P) $(DESTDIR)$(docsdir)
@for file in $(d_LINKS); do \
lnk=$(DESTDIR)$(docsdir)/$$file; \
src=available/$$file; \
if [ -L $$lnk ]; then \
echo "Skipping $$lnk exists."; \
else \
$(LN_S) $$src $$lnk; \
fi; \
done
uninstall-hook:
@for file in $(d_LINKS); do \
lnk=$(DESTDIR)$(docsdir)/$$file; \
src=available/$$file; \
if [ "`readlink $$lnk`" != "$$src" ]; then \
continue; \
fi; \
$(RM) $$lnk; \
done
@@ -0,0 +1,5 @@
docsdir := @docdir@/contrib/void/finit.d/available
docs_DATA = acpid.conf crond.conf dhcpcd.conf dmeventd.conf getty.conf \
keymap.conf klogd.conf lxdm.conf modules.conf ntpd.conf \
sshd.conf syslogd.conf uuidd.conf
EXTRA_DIST = $(docs_DATA)
+2
View File
@@ -0,0 +1,2 @@
Makefile
Makefile.in
+4
View File
@@ -0,0 +1,4 @@
docsdir := @docdir@/docs
docs_DATA = config.md conditions.md distro.md inetd.md plugins.md \
service.md signals.md svc-machine.png cmdline.md
EXTRA_DIST = $(docs_DATA)
+15 -15
View File
@@ -21,24 +21,15 @@ can also be used.
General
-------
* Add support for `rescue` on the kernel command line, start rescue mode
if enabled with `configure` script. Could mean skip `/etc/finit.conf`
et al and jump straight to a single getty login on console.
* Add support for timed shutdown in Finit, including cancelled shutdown.
* SysV init and systemd use SIGUSR1 to restart their FIFO/D-Bus. Add
API restart to SIGHUP callback for the same functionality in Finit.
* Add support for timed shutdown in Finit, including cancelled shutdown,
possibly using an at-job, see [crond section](#Crond) below
* 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
* Add `finit.conf` support for ctrl-alt-delete (SIGINT) and kbrequest,
i.e. KeyboardSignal, (SIGWINCH) behavior. Using conditions to a task,
e.g, <sys/key/ctrlaltdel> and <sys/key/signal> like SIGPWR handling.
* Add `IFF_RUNNING` support to netlink plugin along `IFF_UP`
* Implement `initctl stop|start|restart|reload|status <SVC>` and
`service <SVC> stop|start|restart|reload|status` on top
* Add support for JSON output, or similar, from `initctl show`, e.g.
`initctl show --json`
* Improve `initctl show SVC` output. Add service uptime, last ten SVC
logs/history (historian), etc. Similar to `systemctl show SVC`
* [Solaris SMF][] (Service Management Facility) has some interesting
features that may be well worth looking into adopting:
@@ -49,6 +40,13 @@ General
* `initctl add /sbin/service -n -- Service description`, for details
see above [Solaris SMF][] featuer, issue #55 and issue #69,
https://github.com/troglobit/finit/issues/69#issuecomment-287907610
* Changing the name of a pidfile, `pid:[/path/]file.pid`, after a
service has been started is not supported atm. The previous name will
not be (never) removed and the new name will not be created until the
process has been stopped and started again.
* PID files created in subdirectories to `/run` is not supported right
now inotify listeners should be automatically created (and removed)
when a subdirectory is added (or removed).
Init
@@ -85,14 +83,16 @@ system-level timed periodic tasks:
Proposed syntax:
# Crontab
cron @YY-mm-ddTHH:MM [LVLS] /path/to/cmd [ARGS] -- Optional descr
cron @SPEC [LVLS] /path/to/cmd [ARGS] -- Optional descr
# One-shot 'at' command
at @YY-mm-ddTHH:MM [LVLS] /path/to/cmd [ARGS] -- Optional descr
Notice the ISO date in notation. The runlevels is extra filtering
sugar. E.g., if cron service is only allowed in runlevels two or three
it will not start if system currently is in runlevel four.
Notice the ISO date in the `at` notation. The `cron @SPEC` could use
are mo loose notation, e.g. `@hourly`, `@midnight`, `@daily`, `@weekly`,
`@reboot`, etc. The runlevels is extra filtering sugar. E.g., if cron
service is only allowed in runlevels two or three it will not start if
system currently is in runlevel four.
To run a command as another user the `.conf` file must have a that
owner. E.g., `/etc/finit.d/extra.conf` may be owned by operator and
+4 -4
View File
@@ -5,7 +5,7 @@ Bootstrap
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
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
@@ -25,13 +25,13 @@ Bootstrap
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. Switch to the configured runlevel from `/etc/finit.conf`, default 2.
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.
23. Call 4th level hooks, `HOOK_SVC_UP`
24. If `runparts <DIR>` is set, [run-parts(8)][] is called on `<DIR>`
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`
+21 -3
View File
@@ -124,14 +124,32 @@ append="init=/sbin/finit"
Remember to also set up an initial `/etc/finit.conf` before rebooting!
Recovery
--------
To rescue a system with Finit, append the following to the kernel
command line:
```shell
append="init=/sbin/finit rescue"
```
This tells Finit to start in a very limited recovery mode, no services
are loaded, no filesystems are mounted or checked, and no networking is
enabled. The default Finit rescue mode configuration is installed into
`/lib/finit/rescue.conf`, which can be safely removed or changed.
By default the a root shell, without login, is started.
Debugging
---------
Add `finit_debug`, or `--debug`, to the kernel command line to enable
debug messages.
Edit, or append to, the kernel command line: remove `quiet` to enable
kernel messages and add `debug` to enable Finit debug messages.
```shell
append="init=/sbin/finit --debug"
append="init=/sbin/finit debug"
```
To debug startup issues, in particular issues with getty/login, try
+38
View File
@@ -0,0 +1,38 @@
Tips & Tricks with the kernel cmdline
=====================================
This document summarizes the different boot parameters that can be
passed on the Linux kernel command line. Not just limited to Finit.
* `debug`, or `--debug`
Enable debug mode. The former syntax also enable kernel debug, and
the latter only in Finit. Debug messages are printed to the console
until a syslog daemon has been started.
* `init=/bin/sh`
Bypass system default init and tell kernel to start a shell. Note,
this shell is very limited and does not support signals and has no
job control. Recommend using, and modifying, `rescue` mode instead.
* `panic=SEC`
By default the kernel does not reboot after a kernel panic. This
setting will cause a kernel reboot after SEC seconds.
* `quiet`
Suppress kernel logging to console, except for warnings and errors.
* `rescue`
Start Finit rescue mode; no network, no `fsck` of file systems in
`/etc/fstab`, no `/etc/rc.local`, no `runparts`. The configuration
is read from `/etc/rescue.conf`, can be modified by the operator.
* `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.
* `splash`
Display Finit splash screen with progress at bootstrap and shutdown.
For more on kernel boot paramaters, see the man page `bootparam(7)`.
+4 -3
View File
@@ -95,10 +95,11 @@ Built-in conditions:
- `net/route/default`
- `net/<IFNAME>/exist`
- `net/<IFNAME>/up`
- `net/<IFNAME>/running`
**Note:** `up` means administratively up, the interface flag `IFF_UP`,
not link up, `IFF_RUNNING`. This latter conditions is currently not
implemented by the `plugins/netlink.c` plugin.
**Note:** `up` means administratively up, the interface flag `IFF_UP`.
`running` is the `IFF_RUNNING` flag, meaning operatively up. The
difference is that `running` tells if the NIC has link.
Debugging
+145 -34
View File
@@ -2,6 +2,7 @@ Configuration
=============
* [Introduction](#introduction)
* [Service Wrapper Scripts](#service-wrapper-scripts)
* [Syntax](#syntax)
* [Limitations](#limitations)
* [/etc/finit.conf](#etcfinitconf)
@@ -16,7 +17,7 @@ or in combination with `/etc/finit.d/*.conf`. Finit 3 can even start a
system using only `/etc/finit.d/*.conf`, highly useful for package-based
Linux distributions -- each package can provide its own "script" file.
- `/etc/finit.conf`: main configuration file, read only once at boot
- `/etc/finit.conf`: main configuration file
- `/etc/finit.d/*.conf`: snippets, usually one service per file
Not all configuration directives are available in `/etc/finit.d/*.conf`
@@ -26,8 +27,15 @@ the section [Limitations](#limitations) below for details.
To add a new service, simply drop a `.conf` file in `/etc/finit.d` and
run `initctl reload`. (It is also possible to `SIGHUP` to PID 1, or
call `finit q`, but that has been deprecated with the `initctl` tool).
Any service read from this directory is flagged as a dynamic service, so
changes to or removal of `/etc/finit.d/*.conf` files, is detected.
Finit monitors all known active `.conf` files, so if you want to force
a restart of any service you can simply touch its corresponding `.conf`
file in `/etc/finit.d` and call `initctl reload`. Finit handle any
and all conditions and dependencies between services automatically.
It is also possible to drop `.conf` files in `/etc/finit.d/available/`
and use `initctl enable` to enable a service `.conf` file. This may be
useful in particular to Linux distributions that may want to install all
files for a package and let the user decide when to enable a service.
On `initctl reload` the following is checked for all services:
@@ -42,24 +50,63 @@ For more info on the different states of a service, see the separate
document [Finit Services](service.md).
Service Wrapper Scripts
-----------------------
If your service requires to run additional commands, executed before the
service is actually started, like the systemd `ExecStartPre`, you can
use a wrapper shell script to start your service.
The Finit service `.conf` file can be put into `/etc/finit.d/available`,
so you can control the service using `initctl`. Then use the path to
the wrapper script in the Finit `.conf` service stanza. The following
example employs a wrapper script in `/etc/start.d`.
**Example:**
* `/etc/finit.d/available/program.conf`:
```conf
service [235] <!> /etc/start.d/program -- Example Program
```
* `/etc/start.d/program:`
```shell
#!/bin/sh
# Prepare the command line options
OPTIONS="-u $(cat /etc/username)"
# Execute the program
exec /usr/bin/program $OPTIONS
```
**Note:**, that the example sets `<!>` to denote that it doesn't support
`SIGHUP`. That way Finit will stop/start such the service instead of
sending SIGHUP at restart/reload.
Syntax
------
* `module <MODULE>`
* `host <NAME>`, or `hostname <NAME>`
Set system hostname to NAME, unless `/etc/hostname` exists in which
case the contents of that file is used.
* `module <MODULE> [ARGS]`
Load a kernel module, with optional arguments
* `network <PATH>`
Script or program to bring up networking, with optional arguments
* `rlimit <hard|soft> RESOURCE <LIMIT|unlimited>`
Set the hard or soft limit for a resource. `RESOURCE` is a lower-case
string matching the `RLIMIT_` constants from `setrlimit(2)`, without
the prefix. E.g. to set `RLIMIT_CPU`, use `cpu`.
* `rlimit [hard|soft] RESOURCE <LIMIT|unlimited>` Set the hard or soft
limit for a resource, or both if that argument is omitted. `RESOURCE`
is the lower-case `RLIMIT_` string constants from `setrlimit(2)`,
without the prefix. E.g. to set `RLIMIT_CPU`, use `cpu`.
The limit is an integer that depends on the resource being modified,
see the man page, or the kernel `/proc/PID/limits` file, for more
information. Finit versions before v3.1 used `infinity` for
`unlimited`, which is still a supported keyword.
LIMIT is an integer that depends on the resource being modified, see
the man page, or the kernel `/proc/PID/limits` file, for details.
Finit versions before v3.1 used `infinity` for `unlimited`, which is
still supported, albeit deprecated.
```shell
# No process is allowed more than 8MB of address space
@@ -67,8 +114,14 @@ Syntax
# Core dumps may be arbitrarily large
rlimit soft core infinity
# CPU limit for all services, soft & hard = 10 sec
rlimit cpu 10
```
`rlimit` can be set globally, in `/etc/finit.conf`, or locally for
a set of task/run/services, in `/etc/finit.d/*.conf`.
* `runlevel <N>`
N is the runlevel number 1-9, where 6 is reserved for reboot.
Default is 2.
@@ -107,8 +160,30 @@ Syntax
Finit waits for another service, `/sbin/zebra`, to have created its
PID file in `/var/run/zebra.pid` before starting `ospfd`.
For a detailed description of conditions, and how to debug them,
see the [Finit Conditions](conditions.md) document.
Some services do not maintain a PID file and rather than patching each
application Finit provides a workaround. A `pid` keyword can be set
to have Finit automatically create (when starting) and later remove
(when stopping) the PID file. The file is created in the `/var/run`
directory using the `basename(1)` of the service. The default can be
modified with an optional argument:
pid[:[/path/to/]filename[.pid]]
For example, by adding `pid:/run/foo.pid` to the service `bar` that
PID file will, not only be created and removed automatically, but also
be used by the Finit condition subsystem. So another service/run/task
can depend on `<svc/foo>`.
If a service `bar` *does* maintain a PID file, but using `foo.pid`, we
can inform Finit of this by simplly prepending an `!` to the argument.
pid:!/run/foo.pid
Here Finit will *not* create/remove/touch the PID file, only use it
for the condition handling instead of the default PID file name.
For a detailed description of conditions, and how to debug them, see
the [Finit Conditions](conditions.md) document.
* `inetd service/proto[@iflist] <wait|nowait> [LVLS] /path/to/daemon args`
Launch a daemon when a client initiates a connection on an Internet
@@ -140,22 +215,39 @@ Syntax
* `runparts <DIR>`
Call [run-parts(8)][] on `DIR` to run start scripts. All executable
files, or scripts, in the directory are called, in alphabetic order.
The scripts in this directory are executed at the very end of runlevel
`S`, bootstrap.
It can be beneficial to use `S01name`, `S02othername`, etc. if there
is a dependency order between the scripts. Symlinks to existing
daemons can talso be used, but make sure they daemonize by default.
As the optional `/etc/rc.local` shell script, make sure that all your
Similar to the `/etc/rc.local` shell script, make sure that all your
services and programs either terminate or start in the background or
you will block Finit.
* `include <CONF>`
Include another configuration file. Absolute path required.
* `tty [LVLS] <DEV> [BAUD] [noclear] [nowait] [TERM]`
* `log size:200k count:5`
Log rotation for run/task/services using the `log` sub-option with
redirection to a log file. Global setting, applies to all services.
The size can be given as bytes, without a specifier, or in `k`, `M`,
or `G`, e.g. `size:10M`, or `size:3G`. A value of `size:0` disables
log rotation. The default is `200k`.
The count value is recommended to be between 1-5, with a default 5.
Setting count to 0 means the logfile will be truncated when the MAX
size limit is reached.
* `tty [LVLS] <DEV> [BAUD] [noclear] [nowait] [nologin] [TERM]`
`tty [LVLS] <CMD> <ARGS> [noclear] [nowait]`
The first variant of this option uses the built-in getty on the given
TTY device DEV, in the given runlevels. Default baud rate is `38400`.
TTY device DEV, in the given runlevels. The DEV may be the special
keyword `@console`, which is very useful on embedded systems. Default
baud rate is `38400`.
**Example:**
```conf
@@ -182,6 +274,11 @@ Syntax
embedded systems running multiple unused getty wastes both memory
and CPU cycles, so `wait` is the preferred default.
The `nologin` option disables getty and `/bin/login`, and gives the
user a root (login) shell on the given TTY `<DEV>` immediately.
Needless to say, this is a rather insecure option, but can be very
useful for developer builds, during board bringup, or similar.
Notice the ordering, the `TERM` option to the built-in getty must be
the last argument.
@@ -236,8 +333,19 @@ Without the `:ID` to the service the latter will overwrite the former
and only the old web server would be started and supervised.
The `run`, `task`, `service`, or `inetd` stanzas also allow the keyword
`log` to redirect `stderr` and `stdout` of the application to syslog,
using `logger`.
`log` to redirect `stderr` and `stdout` of the application to a file or
syslog using the native `logit` tool. The full syntax is:
log:/path/to/file
log:prio:facility.level,tag:ident
log:null
log
Log rotation is controlled using the global `log` setting.
**Example:**
service log:prio:user.warn,tag:ntpd /sbin/ntpd pool.ntp.org -- NTP daemon
Worth noting is that conditions is allowed for all these stanzas. For a
detailed description, see the [Conditions](conditions.md) document.
@@ -248,31 +356,34 @@ Limitations
To understand the limitations of `finit.conf` vs `finit.d` it is useful
to picture the different phases of the system: bootstrap, runtime, and
shutdown. The `finit.conf` file can be used for all possible settings,
but `finit.d/*.conf` can only be used for runtime settings.
shutdown.
### /etc/finit.conf
This file was the only way to set up and boot a system using Finit. It
is used for pre-runtime settings like system hostname, network bringup
and shutdown:
This file used to be the only way to set up and boot a Finit system.
Today it is mainly used for pre-runtime settings like system hostname,
network bringup and shutdown:
- `host`
- `mkdod`
- `network`
- `runparts`
- `host`, only at bootstrap, (runlevel `S`)
- `mknod`, only at bootstrap
- `network`, only at bootstrap
- `runparts`, only at bootstrap
- `include`
- `shtudown`
- `runlevel`
- `log`, global setting
- `shutdown`
- `runlevel`, only at bootstrap
- ... and all configuration stanzas from `/etc/finit.d` below
### /etc/finit.d
Support for partial `.conf` files in `/etc/finit.d` was added to handle
changes of the system configuration at runtime. It does *not support*
the above `finit.conf` settings described above, only the following:
Support for per-service `.conf` files in `/etc/finit.d` was added in
v3.0 to handle changes of the system configuration at runtime. As of
v3.1 `finit.conf` is also handled at runtime, except of course for any
stanza that only runs at bootstrap. However, a `/etc/finit.d/*.conf`
does *not support* the above `finit.conf` settings described above, only
the following:
- `module`, but only in runlevel `S`
- `module`, but only at bootstrap
- `service`
- `task`
- `run`
View File
View File
View File
View File
View File

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

+1
View File
@@ -1,3 +1,4 @@
pkglibdir = $(plugin_path)
AM_LDFLAGS = -module -avoid-version -shared
AM_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
AM_CPPFLAGS = -I$(top_srcdir)/src -U_FORTIFY_SOURCE
+3
View File
@@ -170,6 +170,9 @@ static void setup(void *arg)
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) {
+20 -23
View File
@@ -94,6 +94,17 @@ static void nl_route(struct nlmsghdr *nlmsg)
}
}
static void net_cond_set(char *ifname, char *cond, int set)
{
char msg[MAX_ARG_LEN];
snprintf(msg, sizeof(msg), "net/%s/%s", ifname, cond);
if (set)
cond_set(msg);
else
cond_clear(msg);
}
static void nl_link(struct nlmsghdr *nlmsg)
{
int la;
@@ -112,39 +123,25 @@ static void nl_link(struct nlmsghdr *nlmsg)
while (RTA_OK(a, la)) {
if (a->rta_type == IFLA_IFNAME) {
char msg[MAX_ARG_LEN];
strlcpy(ifname, RTA_DATA(a), sizeof(ifname));
switch (nlmsg->nlmsg_type) {
case RTM_NEWLINK:
/*
* New interface has appearad, or interface flags has changed.
* 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, ifi_change 0x%x", ifname, i->ifi_change);
if (i->ifi_change & IFF_UP) {
snprintf(msg, sizeof(msg), "net/%s/up", ifname);
if (i->ifi_flags & IFF_UP)
cond_set(msg);
else
cond_clear(msg);
if (string_compare("lo", ifname)) {
snprintf(msg, sizeof(msg), "net/%s/exist", ifname);
cond_set(msg);
}
} else {
snprintf(msg, sizeof(msg), "net/%s/exist", ifname);
cond_set(msg);
}
_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:
/* NOTE: Interface has dissapeared, not link down ... */
/* NOTE: Interface has disappeared, not link down ... */
_d("%s: Delete link", ifname);
snprintf(msg, sizeof(msg), "net/%s/exist", ifname);
cond_clear(msg);
net_cond_set(ifname, "exist", 0);
net_cond_set(ifname, "up", 0);
net_cond_set(ifname, "running", 0);
break;
case RTM_NEWADDR:
+18 -13
View File
@@ -50,7 +50,6 @@ static void pidfile_callback(void *arg, int fd, int events)
struct inotify_event *ev;
ssize_t sz, len;
char *basename;
svc_t *svc;
sz = read(fd, ev_buf, sizeof(ev_buf) - 1);
@@ -60,23 +59,16 @@ static void pidfile_callback(void *arg, int fd, int events)
}
ev_buf[sz] = 0;
for (ev = (void *)ev_buf; sz > (ssize_t)sizeof(*ev);
for (ev = (void *)ev_buf;
sz > (ssize_t)sizeof(*ev);
len = sizeof(*ev) + ev->len, ev = (void *)ev + len, sz -= len) {
/* ev = (void *)(ev + 1) + ev->len, sz -= sizeof(*ev) + ev->len) { */
if (!ev->mask || !strstr(ev->name, ".pid"))
continue;
basename = strtok(ev->name, ".");
if (!basename)
continue;
svc = svc_find_by_nameid(basename, 1);
svc = svc_find_by_pidfile(ev->name);
if (!svc)
continue;
/* TODO FIXME XXX WKZ check that pid is controlled by finit */
_d("%s: match %s", basename, svc->cmd);
mkcond(cond, sizeof(cond), svc->cmd);
if (ev->mask & (IN_CREATE | IN_ATTRIB | IN_MODIFY)) {
svc_started(svc);
@@ -120,10 +112,23 @@ static void pidfile_reconf(void *arg)
static void pidfile_init(void *arg)
{
char *path;
struct context *ctx = arg;
ctx->wd = inotify_add_watch(ctx->fd, _PATH_VARRUN,
IN_CREATE | IN_ATTRIB | IN_DELETE | IN_MODIFY);
/*
* The bootmisc plugin is responsible for setting up /var/run.
* and/or /run, with proper symlinks etc. We depend on bootmisc
* so it's safe here to query realpath() and set up inotify.
*/
path = realpath(_PATH_VARRUN, NULL);
if (!path) {
_pe("Failed ");
return;
}
ctx->wd = inotify_add_watch(ctx->fd, path, IN_CREATE | IN_ATTRIB | IN_DELETE | IN_MODIFY);
free(path);
if (ctx->wd < 0) {
_pe("inotify_add_watch()");
close(ctx->fd);
+1
View File
@@ -1,6 +1,7 @@
.deps/*
finit
initctl
logit
reboot
Makefile
Makefile.in
+21 -11
View File
@@ -1,14 +1,19 @@
EXTRA_DIST = rescue.conf
AM_CPPFLAGS = -U_FORTIFY_SOURCE
AM_CPPFLAGS += -D_XOPEN_SOURCE=600 -D_BSD_SOURCE -D_GNU_SOURCE -D_DEFAULT_SOURCE
if STATIC
AM_CPPFLAGS += -DENABLE_STATIC
AM_LDFLAGS = -static-libtool-libs
else
AM_CPPFLAGS += -DPLUGIN_PATH=\"$(pkglibdir)\"
AM_LDFLAGS = -export-dynamic
endif
bin_PROGRAMS = logit
sbin_PROGRAMS = finit initctl reboot
logit_SOURCES = logit.c
logit_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
finit_SOURCES = api.c \
cond.c cond-w.c cond.h \
telinit.c \
@@ -17,7 +22,8 @@ finit_SOURCES = api.c \
getty.c stty.c \
helpers.c helpers.h \
log.c log.h \
mdadm.c mount.c pid.c \
mdadm.c mount.c \
pid.c pid.h \
plugin.c plugin.h private.h \
service.c service.h \
sig.c sig.h \
@@ -38,7 +44,7 @@ finit_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
finit_CFLAGS += $(lite_CFLAGS) $(uev_CFLAGS)
finit_LDADD = $(lite_LIBS) $(uev_LIBS)
if STATIC
finit_LDADD += plugins/libplug.la
finit_LDADD += ../plugins/libplug.la
else
finit_LDADD += -ldl
endif
@@ -59,10 +65,11 @@ REBOOT_LNKS = shutdown halt poweroff suspend
# Hook in install to add finit and reboot symlink(s)
install-exec-hook:
@$(INSTALL_DATA) $(srcdir)/rescue.conf $(DESTDIR)$(pkglibdir)
@for file in $(INIT_LNKS); do \
lnk=$(DESTDIR)$(sbindir)/$$file; \
if [ -e $$lnk ]; then \
echo "Skipping $$lnk exists already."; \
echo "Skipping $$lnk exists."; \
else \
$(LN_S) finit $$lnk; \
fi; \
@@ -71,16 +78,17 @@ install-exec-hook:
echo "Non-finit reboot, skipping install."; \
else \
for file in $(REBOOT_LNKS); do \
link=$(DESTDIR)$(sbindir)/$$file; \
if [ -e $$link ]; then \
echo "$$link exists, skipping.";\
lnk=$(DESTDIR)$(sbindir)/$$file; \
if [ -e $$lnk ]; then \
echo "Skipping $$lnk exists."; \
else \
$(LN_S) reboot $$link; \
$(LN_S) reboot $$lnk; \
fi; \
done; \
fi
uninstall-hook:
@$(RM) $(DESTDIR)$(pkglibdir)/rescue.conf
@for file in $(INIT_LNKS); do \
lnk=`readlink $(DESTDIR)$(sbindir)/$$file`; \
if [ "$$lnk" != "finit" ]; then \
@@ -93,9 +101,11 @@ uninstall-hook:
echo "Non-finit reboot, skipping uninstall."; \
else \
for file in $(REBOOT_LNKS); do \
if [ "`readlink $$file`" != "reboot" ]; \
then continue; \
lnk=$(DESTDIR)$(sbindir)/$$file; \
dst=`readlink $$lnk`; \
if [ "$$dst" != "reboot" ]; then \
continue; \
fi; \
$(RM) $(DESTDIR)$(sbindir)/$$file; \
$(RM) $$lnk; \
done; \
fi
+6 -6
View File
@@ -342,6 +342,7 @@ static void api_cb(uev_t *w, void *arg, int events)
kill(wdogpid, SIGTERM);
do_sleep(1);
}
_d("wdog was %d, now %d is in charge", wdogpid, rq.runlevel);
wdogpid = rq.runlevel;
break;
@@ -380,13 +381,11 @@ static void api_cb(uev_t *w, void *arg, int events)
_d("Failed sending ACK/NACK back to client");
}
if (UEV_ERROR == events)
goto error;
leave:
close(sd);
if (UEV_ERROR == events)
goto error;
return;
error:
api_exit();
if (api_init(w->ctx))
@@ -430,8 +429,9 @@ error:
int api_exit(void)
{
return shutdown(api_watcher.fd, SHUT_RDWR) ||
close(api_watcher.fd);
uev_io_stop(&api_watcher);
return close(api_watcher.fd);
}
/**
-5
View File
@@ -27,11 +27,6 @@
#include "finit.h"
#include "svc.h"
typedef struct {
char *cmd;
int (*cb)(char *arg);
} command_t;
int client_connect (void);
int client_disconnect (void);
+55 -13
View File
@@ -28,6 +28,7 @@
#include "finit.h"
#include "cond.h"
#include "pid.h"
#include "service.h"
static int cond_set_gen(const char *path, unsigned int gen)
@@ -59,9 +60,27 @@ static void cond_bump_reconf(void)
cond_set_gen(COND_RECONF, rgen);
}
int cond_set_path(const char *path, enum cond_state new)
static int cond_checkpath(const char *path)
{
char buf[MAX_ARG_LEN], *dir;
strlcpy(buf, path, sizeof(buf));
dir = dirname(buf);
if (!dir) {
_e("Invalid path '%s' for condition", path);
return 1;
}
if (makepath(dir) && errno != EEXIST) {
_pe("Failed creating dir '%s' for condition '%s'", dir, path);
return 1;
}
return 0;
}
int cond_set_path(const char *path, enum cond_state new)
{
enum cond_state old;
unsigned int rgen;
@@ -77,16 +96,8 @@ int cond_set_path(const char *path, enum cond_state new)
switch (new) {
case COND_ON:
strlcpy(buf, path, sizeof(buf));
dir = dirname(buf);
if (!dir) {
_e("Invalid path '%s' for condition", path);
return 0;
}
if (makepath(dir) && errno != EEXIST) {
_pe("Failed creating dir '%s' for condition '%s'", dir, path);
return 0;
}
if (cond_checkpath(path))
return 0;
cond_set_gen(path, rgen);
break;
@@ -139,15 +150,38 @@ static void cond_update(const char *name)
void cond_set(const char *name)
{
_d("%s", name);
if (string_compare(name, "nop"))
return;
if (!cond_set_path(cond_path(name), COND_ON))
return;
cond_update(name);
}
void cond_set_oneshot(const char *name)
{
const char *path;
if (string_compare(name, "nop"))
return;
path = cond_path(name);
_d("s => %s", name, path);
if (cond_checkpath(path))
return;
symlink(COND_RECONF, path);
cond_update(name);
}
void cond_clear(const char *name)
{
_d("%s", name);
if (string_compare(name, "nop"))
return;
if (!cond_set_path(cond_path(name), COND_OFF))
return;
@@ -172,7 +206,13 @@ static int reassert(const char *fpath, const struct stat *sb, int tflg, struct F
if (tflg != FTW_F)
return 0;
nm = (char *)fpath + sizeof(COND_PATH);
nm = strstr((char *)fpath, COND_DIR);
if (!nm) {
_e("Incorrect condtion path %s, cannot reassert", fpath);
return 1;
}
nm += sizeof(COND_DIR);
_d("Reasserting %s => %s", fpath, nm);
cond_set(nm);
@@ -191,7 +231,9 @@ void cond_reassert(const char *type)
void cond_init(void)
{
if (makepath(COND_PATH) && errno != EEXIST) {
char path[MAX_ARG_LEN];
if (makepath(pid_runpath(COND_PATH, path, sizeof(path))) && errno != EEXIST) {
_pe("Failed creating condition base directory '%s'", COND_PATH);
return;
}
+4 -2
View File
@@ -26,6 +26,7 @@
#include "finit.h"
#include "cond.h"
#include "pid.h"
#include "service.h"
@@ -42,11 +43,12 @@ const char *condstr(enum cond_state s)
const char *cond_path(const char *name)
{
char tmp[MAX_ARG_LEN];
static char file[MAX_ARG_LEN];
snprintf(file, sizeof(file), COND_PATH "/%s", name);
snprintf(tmp, sizeof(tmp), COND_PATH "/%s", name);
return file;
return pid_runpath(tmp, file, sizeof(file));
}
unsigned int cond_get_gen(const char *path)
+9 -8
View File
@@ -3,8 +3,8 @@
#include <paths.h>
#define COND_PATH _PATH_VARRUN "finit/cond"
#define COND_SVC_PATH COND_PATH "/svc/"
#define COND_DIR "finit/cond"
#define COND_PATH _PATH_VARRUN COND_DIR
#define COND_RECONF COND_PATH "/reconf"
typedef enum cond_state {
@@ -21,12 +21,13 @@ enum cond_state cond_get (const char *name);
enum cond_state cond_get_agg (const char *names);
int cond_affects (const char *name, const char *names);
int cond_set_path(const char *path, enum cond_state new);
void cond_set (const char *name);
void cond_clear (const char *name);
void cond_reload (void);
void cond_reassert(const char *pat);
void cond_init (void);
int cond_set_path (const char *path, enum cond_state new);
void cond_set (const char *name);
void cond_set_oneshot (const char *name);
void cond_clear (const char *name);
void cond_reload (void);
void cond_reassert (const char *pat);
void cond_init (void);
#endif /* FINIT_COND_H_ */
+173 -41
View File
@@ -36,11 +36,15 @@
#include "service.h"
#include "tty.h"
#include "helpers.h"
#include "util.h"
#define BOOTSTRAP (runlevel == 0)
#define MATCH_CMD(l, c, x) \
(!strncasecmp(l, c, strlen(c)) && (x = (l) + strlen(c)))
int logfile_size_max = 200000; /* 200 kB */
int logfile_count_max = 5;
struct rlimit global_rlimit[RLIMIT_NLIMITS];
struct conf_change {
@@ -58,24 +62,85 @@ void conf_parse_cmdline(void)
{
int dbg = 0;
FILE *fp;
char line[LINE_SIZE], *cmdline, *tok;
fp = fopen("/proc/cmdline", "r");
if (fp) {
char line[LINE_SIZE];
fgets(line, sizeof(line), fp);
chomp(line);
_d("%s", line);
if (strstr(line, "finit_debug") || strstr(line, "--debug"))
dbg = 1;
if (!fp)
goto done;
if (!fgets(line, sizeof(line), fp)) {
fclose(fp);
goto done;
}
cmdline = chomp(line);
_d("%s", cmdline);
while ((tok = strtok(cmdline, " \t"))) {
cmdline = NULL;
/* Catches finit_debug (deprecated), --debug, and debug */
if (strstr(tok, "debug"))
dbg = 1;
if (string_compare(tok, "rescue") || string_compare(tok, "recover"))
rescue = 1;
if (string_compare(tok, "single") || string_compare(tok, "S"))
single = 1;
if (string_compare(tok, "splash"))
splash = 1;
}
fclose(fp);
done:
log_init(dbg);
}
static int kmod_exists(char *mod)
{
int found = 0;
FILE *fp;
char buf[256];
size_t len;
for (len = 0; mod[len]; len++) {
if (mod[len] == ' ' || mod[len] == '\t')
break;
}
fp = fopen("/proc/modules", "r");
if (!fp)
return 0;
while (!found && (fgets(buf, sizeof(buf), fp))) {
if (!strncmp(buf, mod, len))
found = 1;
}
fclose(fp);
return found;
}
static void kmod_load(char *line)
{
char *mod;
char cmd[CMD_SIZE];
if (runlevel != 0)
return;
mod = strip_line(line);
if (kmod_exists(mod))
return;
strcpy(cmd, "modprobe ");
strlcat(cmd, mod, sizeof(cmd));
run_interactive(cmd, "Loading kernel module %s", mod);
}
/* Convert optional "[!123456789S]" string into a bitmask */
int conf_parse_runlevels(char *runlevels)
{
@@ -200,11 +265,33 @@ char *rlim2str(int rlim)
return "unknown";
}
char *lim2str(struct rlimit *rlim)
{
char tmp[20];
static char buf[42];
memset(buf, 0, sizeof(buf));
if (RLIM_INFINITY == rlim->rlim_cur)
snprintf(tmp, sizeof(tmp), "unlimited, ");
else
snprintf(tmp, sizeof(tmp), "%llu, ", (unsigned long long)rlim->rlim_cur);
strlcat(buf, tmp, sizeof(buf));
if (RLIM_INFINITY == rlim->rlim_max)
snprintf(tmp, sizeof(tmp), "unlimited, ");
else
snprintf(tmp, sizeof(tmp), "%llu, ", (unsigned long long)rlim->rlim_max);
strlcat(buf, tmp, sizeof(buf));
return buf;
}
/* First form: `rlimit <hard|soft> RESOURCE LIMIT` */
void conf_parse_rlimit(char *line, struct rlimit arr[])
{
char *level, *limit, *val;
int resource = -1;
rlim_t cfg, *set;
rlim_t cfg;
level = strtok(line, " \t");
if (!level)
@@ -214,21 +301,18 @@ void conf_parse_rlimit(char *line, struct rlimit arr[])
if (!limit)
goto error;
val = strtok(NULL, " \t");
if (!val) {
/* Second form: `rlimit RESOURCE LIMIT` */
val = limit;
limit = level;
level = "both";
}
resource = str2rlim(limit);
if (resource < 0 || resource > RLIMIT_NLIMITS)
goto error;
val = strtok(NULL, " \t");
if (!val)
goto error;
if (!strcmp(level, "soft"))
set = &arr[resource].rlim_cur;
else if (!strcmp(level, "hard"))
set = &arr[resource].rlim_max;
else
goto error;
/* Official keyword from v3.1 is `unlimited`, from prlimit(1) */
if (!strcmp(val, "unlimited") || !strcmp(val, "infinity")) {
cfg = RLIM_INFINITY;
@@ -243,7 +327,15 @@ void conf_parse_rlimit(char *line, struct rlimit arr[])
}
}
*set = cfg;
if (!strcmp(level, "soft"))
arr[resource].rlim_cur = cfg;
else if (!strcmp(level, "hard"))
arr[resource].rlim_max = cfg;
else if (!strcmp(level, "both"))
arr[resource].rlim_max = arr[resource].rlim_cur = cfg;
else
goto error;
return;
error:
logit(LOG_WARNING, "rlimit: parse error");
@@ -254,7 +346,7 @@ static void parse_static(char *line)
char *x;
char cmd[CMD_SIZE];
if (BOOTSTRAP && MATCH_CMD(line, "host ", x)) {
if (BOOTSTRAP && (MATCH_CMD(line, "host ", x) || MATCH_CMD(line, "hostname ", x))) {
if (hostname) free(hostname);
hostname = strdup(strip_line(x));
return;
@@ -295,6 +387,26 @@ static void parse_static(char *line)
return;
}
if (MATCH_CMD(line, "log ", x)) {
char *tok;
static int size = 200000, count = 5;
tok = strtok(x, ":= ");
while (tok) {
if (!strncmp(tok, "size", 4))
size = strtobytes(strtok(NULL, ":= "));
else if (!strncmp(tok, "count", 5))
count = strtobytes(strtok(NULL, ":= "));
tok = strtok(NULL, ":= ");
}
if (size >= 0)
logfile_size_max = size;
if (count >= 0)
logfile_count_max = count;
}
if (MATCH_CMD(line, "shutdown ", x)) {
if (sdown) free(sdown);
sdown = strdup(strip_line(x));
@@ -322,7 +434,6 @@ static void parse_static(char *line)
static void parse_dynamic(char *line, struct rlimit rlimit[], char *file)
{
char *x;
char cmd[CMD_SIZE];
/* Skip comments, i.e. lines beginning with # */
if (MATCH_CMD(line, "#", x))
@@ -330,16 +441,7 @@ static void parse_dynamic(char *line, struct rlimit rlimit[], char *file)
/* Kernel module to load at bootstrap */
if (MATCH_CMD(line, "module ", x)) {
char *mod;
if (runlevel != 0)
return;
mod = strip_line(x);
strcpy(cmd, "modprobe ");
strlcat(cmd, mod, sizeof(cmd));
run_interactive(cmd, "Loading kernel module %s", mod);
kmod_load(x);
return;
}
@@ -463,7 +565,8 @@ static int parse_conf(char *file)
/* Set global limits */
for (int i = 0; i < RLIMIT_NLIMITS; i++) {
if (setrlimit(i, &global_rlimit[i]) == -1)
logit(LOG_WARNING, "rlimit: Failed setting %s", rlim2str(i));
logit(LOG_WARNING, "rlimit: Failed setting %s: %s",
rlim2str(i), lim2str(&global_rlimit[i]));
}
return 0;
@@ -481,6 +584,19 @@ int conf_reload(void)
svc_mark_dynamic();
tty_mark();
if (rescue) {
int rc;
char line[80] = "tty [12345] @console noclear nologin";
/* If rescue.conf is missing, fall back to a root shell */
rc = parse_conf(RESCUE_CONF);
if (rc)
tty_register(line, global_rlimit, NULL);
print(rc, "Entering rescue mode");
goto done;
}
/* First, read /etc/finit.conf */
parse_conf(FINIT_CONF);
@@ -488,13 +604,9 @@ int conf_reload(void)
num = scandir(rcsd, &e, NULL, alphasort);
if (num < 0) {
_d("Skipping %s, no files found ...", rcsd);
return 0;
goto done;
}
/* Update global limits in case operator used prlimit(1) on us */
for (i = 0; i < RLIMIT_NLIMITS; i++)
getrlimit(i, &global_rlimit[i]);
for (i = 0; i < num; i++) {
char *name = e[i]->d_name;
char path[LINE_SIZE];
@@ -542,9 +654,14 @@ int conf_reload(void)
free(e[num]);
free(e);
done:
/* Drop record of all .conf changes */
drop_changes();
/* Override configured runlevel, user said 'S' on /proc/cmdline */
if (BOOTSTRAP && single)
cfglevel = 1;
/*
* Set host name, from %DEFHOST, *.conf or /etc/hostname. The
* latter wins, if neither exists we default to "noname"
@@ -615,11 +732,22 @@ static int do_change(char *name, uint32_t mask)
return 0;
}
int conf_any_change(void)
{
if (TAILQ_EMPTY(&conf_change_list))
return 0;
return 1;
}
int conf_changed(char *file)
{
char *ptr;
if (file && (ptr = strrchr(file, '/')))
if (!file)
return 0;
if ((ptr = strrchr(file, '/')))
file = ++ptr;
if (conf_find(file))
@@ -717,6 +845,10 @@ int conf_monitor(uev_ctx_t *ctx)
{
int rc = 0;
/* Skip second run, when called from finit.c in rescue mode */
if (ctx && rescue)
return 0;
/*
* If only one watcher fails, that's OK. A user may have only
* one of /etc/finit.conf or /etc/finit.d in use, and may also
+4
View File
@@ -26,6 +26,9 @@
#include "svc.h"
extern int logfile_size_max;
extern int logfile_count_max;
extern struct rlimit global_rlimit[];
int str2rlim(char *str);
@@ -33,6 +36,7 @@ char *rlim2str(int rlim);
int conf_init (void);
void conf_reload (void);
int conf_any_change (void);
int conf_changed (char *file);
int conf_monitor (uev_ctx_t *ctx);
+14
View File
@@ -423,6 +423,20 @@ pid_t run_getty2(char *tty, char *cmd, char *args[], int noclear, int nowait, st
return pid;
}
pid_t run_sh(char *tty, int noclear, int nowait, struct rlimit rlimit[])
{
pid_t pid;
pid = fork();
if (!pid) {
prepare_tty(tty, B0, "finit-sh", rlimit);
if (activate_console(noclear, nowait))
_exit(sh(tty));
}
return pid;
}
int run_parts(char *dir, char *cmd)
{
struct dirent **e;
+76 -105
View File
@@ -53,6 +53,9 @@ int wdogpid = 0; /* No watchdog by default */
int runlevel = 0; /* Bootstrap 'S' */
int cfglevel = RUNLEVEL; /* Fallback if no configured runlevel */
int prevlevel = -1;
int rescue = 0; /* rescue mode from kernel cmdline */
int single = 0; /* single user mode from kernel cmdline */
int splash = 0; /* splash + progress enabled on kernel cmdline */
char *sdown = NULL;
char *network = NULL;
char *hostname = NULL;
@@ -81,14 +84,13 @@ static void banner(void)
fprintf(stderr, "\e[2K\e[1m%s %.*s\e[0m\n", buf, SCREEN_WIDTH - (int)strlen(buf) - 2, separator);
}
/* Requires /proc to be mounted */
static int fismnt(char *dir)
static int ismnt(char *file, char *dir)
{
FILE *fp;
int found = 0;
struct mntent *mnt;
fp = setmntent("/proc/mounts", "r");
fp = setmntent(file, "r");
if (!fp)
return 0; /* Dunno, maybe not */
@@ -103,6 +105,12 @@ static int fismnt(char *dir)
return found;
}
/* Requires /proc to be mounted */
static int fismnt(char *dir)
{
return ismnt("/proc/mounts", dir);
}
/*
* Check all filesystems in /etc/fstab with a fs_passno > 0
*/
@@ -150,54 +158,6 @@ static int fsck(int pass)
return 0;
}
static void networking(void)
{
FILE *fp;
/* Run user network start script if enabled */
if (network) {
run_interactive(network, "Starting networking: %s", network);
goto done;
}
/* Debian/Ubuntu/Busybox/RH/Suse */
if (!whichp("ifup"))
goto done;
fp = fopen("/etc/network/interfaces", "r");
if (fp) {
int i = 0;
char buf[160];
/* Bring up all 'auto' interfaces */
while (fgets(buf, sizeof(buf), fp)) {
char cmd[80];
char *line, *ifname = NULL;
chomp(buf);
line = strip_line(buf);
if (!strncmp(line, "auto", 4))
ifname = &line[5];
if (!strncmp(line, "allow-hotplug", 13))
ifname = &line[14];
if (!ifname)
continue;
snprintf(cmd, 80, "ifup %s", ifname);
run_interactive(cmd, "Bringing up interface %s", ifname);
i++;
}
fclose(fp);
}
done:
/* Fall back to bring up at least loopback */
ifconfig("lo", "127.0.0.1", "255.0.0.0", 1);
}
/*
* If everything goes south we can use this to give the operator an
* emergency shell to debug the problem -- Finit should not crash!
@@ -227,7 +187,7 @@ static void emergency_shell(void)
}
fprintf(stderr, "\n=> Embarrassingly, Finit has crashed. Check /dev/kmsg for details.\n");
fprintf(stderr, "=> To debug, add '--debug' to the kernel command line.\n\n");
fprintf(stderr, "=> To debug, add 'debug' to the kernel command line.\n\n");
/*
* Become session leader and set controlling TTY
@@ -255,15 +215,14 @@ static void emergency_shell(void)
static void finalize(void)
{
/*
* Network stuff
* Run startup scripts in the runparts directory, if any.
*/
_d("Setting up networking ...");
networking();
umask(022);
/* Hooks that rely on loopback, or basic networking being up. */
_d("Calling all network up hooks ...");
plugin_run_hooks(HOOK_NETWORK_UP);
if (runparts && fisdir(runparts) && !rescue) {
_d("Running startup scripts in %s ...", runparts);
run_parts(runparts, NULL);
if (conf_any_change())
service_reload_dynamic();
}
/*
* Start all tasks/services in the configured runlevel
@@ -280,19 +239,11 @@ static void finalize(void)
plugin_run_hooks(HOOK_SVC_UP);
service_step_all(SVC_TYPE_ANY);
/*
* Run startup scripts in the runparts directory, if any.
*/
if (runparts && fisdir(runparts)) {
_d("Running startup scripts in %s ...", runparts);
run_parts(runparts, NULL);
service_reload_dynamic();
}
/* Convenient SysV compat for when you just don't care ... */
if (!access(FINIT_RC_LOCAL, X_OK)) {
if (!access(FINIT_RC_LOCAL, X_OK) && !rescue) {
run_interactive(FINIT_RC_LOCAL, "Calling %s", FINIT_RC_LOCAL);
service_reload_dynamic();
if (conf_any_change())
service_reload_dynamic();
}
/* Hooks that should run at the very end */
@@ -324,19 +275,6 @@ int main(int argc, char* argv[])
if (getpid() != 1)
return client(argc, argv);
/* Set up canvas */
screen_init();
/*
* In case of emergency.
*/
emergency_shell();
/*
* Initial setup of signals, ignore all until we're up.
*/
sig_init();
/*
* Initalize event context.
*/
@@ -359,15 +297,30 @@ int main(int argc, char* argv[])
mount("none", "/proc/bus/usb", "usbfs", 0, NULL);
/*
* Parse kernel parameters, including log_init()
* Parse kernel command line (debug, rescue, splash, etc.)
* Also calls log_init() to set correct log level
*/
conf_parse_cmdline();
/* Set up canvas */
if (!rescue && !log_is_debug())
screen_init();
/*
* In case of emergency.
*/
emergency_shell();
/*
* Initial setup of signals, ignore all until we're up.
*/
sig_init();
/*
* Load plugins early, finit.conf may contain references to
* features implemented by plugins.
*/
plugin_init(&loop, PLUGIN_PATH);
plugin_init(&loop);
/*
* Hello world.
@@ -377,11 +330,17 @@ int main(int argc, char* argv[])
/*
* Check file filesystems in /etc/fstab
*/
for (int pass = 1; pass < 10; pass++) {
for (int pass = 1; pass < 10 && !rescue; pass++) {
if (fsck(pass))
break;
}
/*
* Initialize .conf system and load static /etc/finit.conf
* Also initializes global_rlimit[] for udevd, below.
*/
conf_init();
/*
* Some non-embedded systems without an initramfs may not have /dev mounted yet
* If they do, check if system has udevadm and perform cleanup from initramfs
@@ -395,8 +354,15 @@ int main(int argc, char* argv[])
makedir("/dev/pts", 0755);
mount("devpts", "/dev/pts", "devpts", 0, "gid=5,mode=620");
/* Some systems rely on /dev/shm being there, for `mount -a` below */
/*
* Some systems rely on us to both create /dev/shm and, to mount
* a tmpfs there. Any system with dbus needs shared memory, so
* mount it, unless its already mounted, but not if listed in
* the /etc/fstab file already.
*/
makedir("/dev/shm", 0755);
if (!fismnt("/dev/shm") && !ismnt("/etc/fstab", "/dev/shm"))
mount("shm", "/dev/shm", "tmpfs", 0, NULL);
/*
* New tmpfs based /run for volatile runtime data
@@ -450,11 +416,6 @@ int main(int argc, char* argv[])
}
}
/*
* Initialize .conf system and load static /etc/finit.conf
*/
conf_init();
/*
* Start built-in watchdog as soon as possible, if enabled
*/
@@ -463,12 +424,14 @@ int main(int argc, char* argv[])
/*
* Mount filesystems
*/
if (!rescue) {
#ifdef REMOUNT_ROOTFS
run("mount -n -o remount,rw /");
run("mount -n -o remount,rw /");
#endif
#ifdef SYSROOT
mount(SYSROOT, "/", NULL, MS_MOVE, NULL);
mount(SYSROOT, "/", NULL, MS_MOVE, NULL);
#endif
}
/* Debian has this little script to copy generated rules while the system was read-only */
if (fexist("/lib/udev/udev-finish"))
@@ -477,28 +440,35 @@ int main(int argc, char* argv[])
/* Bootstrap conditions, needed for hooks */
cond_init();
_d("Root FS up, calling hooks ...");
plugin_run_hooks(HOOK_ROOTFS_UP);
if (!rescue) {
_d("Root FS up, calling hooks ...");
plugin_run_hooks(HOOK_ROOTFS_UP);
umask(0);
if (run_interactive("mount -na", "Mounting filesystems"))
plugin_run_hooks(HOOK_MOUNT_ERROR);
umask(0);
if (run_interactive("mount -na", "Mounting filesystems"))
plugin_run_hooks(HOOK_MOUNT_ERROR);
run("swapon -ea");
umask(0022);
_d("Calling extra mount hook, after mount -a ...");
plugin_run_hooks(HOOK_MOUNT_POST);
run("swapon -ea");
umask(0022);
}
/* Base FS up, enable standard SysV init signals */
sig_setup(&loop);
if (!rescue) {
_d("Base FS up, calling hooks ...");
plugin_run_hooks(HOOK_BASEFS_UP);
}
/*
* Set up inotify watcher for /etc/finit.d and read all .conf
* files to figure out how to bootstrap the system.
*/
conf_monitor(&loop);
_d("Base FS up, calling hooks ...");
plugin_run_hooks(HOOK_BASEFS_UP);
/*
* Initalize state machine and start all bootstrap tasks
* NOTE: no network available!
@@ -508,6 +478,7 @@ int main(int argc, char* argv[])
/* Start new initctl API responder */
api_init(&loop);
umask(022);
/*
* Wait for all SVC_TYPE_RUNTASK to have completed their work in
+3
View File
@@ -96,6 +96,9 @@ extern int wdogpid;
extern int runlevel;
extern int cfglevel;
extern int prevlevel;
extern int rescue;
extern int single;
extern int splash;
extern char *rcsd;
extern char *sdown;
extern char *network;
+54
View File
@@ -243,6 +243,60 @@ int getty(char *tty, speed_t speed, char *term, char *user)
return do_login(name);
}
int sh(char *tty)
{
int fd;
char *arg0;
char *args[2] = {
NULL,
NULL
};
size_t len;
struct termios term;
/* Detach from initial controlling TTY */
vhangup();
fd = open(tty, O_RDWR);
if (fd < 0)
err(1, "Failed opening %s", tty);
dup2(fd, STDIN_FILENO);
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO);
if (ioctl(STDIN_FILENO, TIOCSCTTY, 1) < 0)
warn("Failed TIOCSCTTY");
/* The getty process is usually responsible for the UTMP login record */
utmp_set_login(tty, NULL);
/* Set up TTY, re-enabling ISIG et al. */
stty(fd, B0);
close(fd);
/* Start /bin/sh as a login shell, i.e. with a prefix '-' */
len = strlen(_PATH_BSHELL) + 2;
arg0 = malloc(len);
if (!arg0)
err(1, "Failed allocating memory");
snprintf(arg0, len, "-%s", _PATH_BSHELL);
args[0] = arg0;
/* Reenable Ctrl-D and Ctrl-C, and ... */
if (!tcgetattr(STDIN_FILENO, &term)) {
term.c_lflag |= ISIG;
term.c_cc[VEOF] = CTL('D');
term.c_cc[VINTR] = CTL('C');
tcsetattr(STDIN_FILENO, TCSANOW, &term);
}
/* ... unblock signals in general */
sig_unblock();
return execv(_PATH_BSHELL, args);
}
/**
* Local Variables:
* indent-tabs-mode: t
+79
View File
@@ -184,6 +184,9 @@ void set_hostname(char **hostname)
{
FILE *fp;
if (rescue)
goto done;
fp = fopen("/etc/hostname", "r");
if (fp) {
struct stat st;
@@ -204,10 +207,86 @@ void set_hostname(char **hostname)
fclose(fp);
}
done:
if (*hostname)
sethostname(*hostname, strlen(*hostname));
}
static void ifup(char *ifname, int updown)
{
char cmd[80];
if (updown) {
snprintf(cmd, sizeof(cmd), "ifup %s", ifname);
run_interactive(cmd, "Bringing up interface %s", ifname);
} else {
snprintf(cmd, sizeof(cmd), "ifdown -f %s", ifname);
run_interactive(cmd, "Taking down interface %s", ifname);
}
}
/*
* Bring up networking, but only if not single-user or rescue mode
*/
void networking(int updown)
{
FILE *fp;
/* No need to report errors if network is already down */
if (!prevlevel && !updown)
return;
if (updown)
_d("Setting up networking ...");
else
_d("Taking down networking ...");
/* Run user network start script if enabled */
if (updown && network) {
run_interactive(network, "Starting networking: %s", network);
goto done;
}
/* Debian/Ubuntu/Busybox/RH/Suse */
if (!whichp("ifup"))
goto done;
fp = fopen("/etc/network/interfaces", "r");
if (fp) {
char buf[160];
/* Bring up, or down, all 'auto' interfaces */
while (fgets(buf, sizeof(buf), fp)) {
char *line, *ifname = NULL;
chomp(buf);
line = strip_line(buf);
if (!strncmp(line, "auto", 4))
ifname = &line[5];
if (!strncmp(line, "allow-hotplug", 13))
ifname = &line[14];
if (!ifname)
continue;
ifup(ifname, updown);
}
fclose(fp);
}
done:
/* Fall back to bring up at least loopback */
ifconfig("lo", "127.0.0.1", "255.0.0.0", updown);
/* Hooks that rely on loopback, or basic networking being up. */
if (updown) {
_d("Calling all network up hooks ...");
plugin_run_hooks(HOOK_NETWORK_UP);
}
}
#ifndef HAVE_GETFSENT
static lfile_t *fstab = NULL;
+3 -3
View File
@@ -52,13 +52,11 @@ struct fstab *getfsent (void);
char *strip_line (char *line);
int getty (char *tty, speed_t speed, char *term, char *user);
int sh (char *tty);
int stty (int fd, speed_t speed);
speed_t stty_parse_speed(char *baud);
int pid_alive (pid_t pid);
char *pid_get_name (pid_t pid, char *name, size_t len);
void printv (const char *fmt, va_list ap);
void print (int action, const char *fmt, ...);
void print_desc (char *action, char *desc);
@@ -67,6 +65,7 @@ int print_result (int fail);
int getuser (char *username, char **home);
int getgroup (char *group);
void set_hostname (char **hostname);
void networking (int updown);
int complete (char *cmd, int pid);
int run (char *cmd);
@@ -74,6 +73,7 @@ int run_interactive (char *cmd, char *fmt, ...);
int exec_runtask (char *cmd, char *args[]);
pid_t run_getty (char *tty, char *baud, char *term, int noclear, int nowait, struct rlimit rlimit[]);
pid_t run_getty2 (char *tty, char *cmd, char *args[], int noclear, int nowait, struct rlimit rlimit[]);
pid_t run_sh (char *tty, int noclear, int nowait, struct rlimit rlimit[]);
int run_parts (char *dir, char *cmd);
static inline void create(char *path, mode_t mode, uid_t uid, gid_t gid)
+19 -10
View File
@@ -76,14 +76,15 @@ static void inetd_dgram_drop(int sd, const char *ifname)
char pkt_interface[17];
char buf[BUFSIZ];
do {
while (1) {
inetd_dgram_peek(sd, pkt_interface);
if(string_compare(pkt_interface, ifname)) {
recv(sd, buf, sizeof(buf), 0);
if (string_compare(pkt_interface, ifname)) {
if (recv(sd, buf, sizeof(buf), 0) < 0)
break;
continue;
}
} while (0);
break;
}
}
/* Peek into SOCK_STREAM on accepted client socket to figure out inbound interface */
@@ -158,6 +159,7 @@ static int get_stdin(svc_t *svc)
static void socket_cb(uev_t *w, void *arg, int events)
{
svc_t *svc = (svc_t *)arg, *task;
const char *conn = " connection";
int stdin;
_d("%s: Got socket event ...", svc->cmd);
@@ -207,11 +209,13 @@ static void socket_cb(uev_t *w, void *arg, int events)
task->inetd.cmd = svc->inetd.cmd;
task->inetd.type = svc->inetd.type;
memcpy(task->rlimit, svc->rlimit, sizeof(task->rlimit));
memcpy(task->cond, svc->cond, sizeof(task->cond));
memcpy(task->username, svc->username, sizeof(task->username));
memcpy(task->group, svc->group, sizeof(task->group));
memcpy(task->args, svc->args, sizeof(task->args));
snprintf(task->desc, sizeof(task->desc), "%52.52s connection", svc->desc);
strlcpy(task->desc, svc->desc, sizeof(task->desc) - strlen(conn));
strlcat(task->desc, conn, sizeof(task->desc));
task->stdin_fd = stdin;
service_step(task);
@@ -333,16 +337,21 @@ int inetd_start(inetd_t *inetd)
void inetd_stop(inetd_t *inetd)
{
if (!inetd || !inetd->svc) {
_e("Invalid inetd, cannot stop it...");
return;
}
if (inetd->watcher.fd != -1) {
_d("Stopping %s socket watcher ...", inetd->svc->cmd);
uev_io_stop(&inetd->watcher);
/* For dgram inetd services we block the parent SVC
* and halt the watcher, so don't close the socket! */
/*
* For dgram inetd services we block the parent SVC
* and halt the watcher, so don't close the socket!
*/
if (!svc_is_busy(inetd->svc)) {
_d("Shutting down inet socket %d ...", inetd->watcher.fd);
if (inetd->type == SOCK_STREAM)
shutdown(inetd->watcher.fd, SHUT_RDWR);
close(inetd->watcher.fd);
inetd->watcher.fd = -1;
}
+15 -5
View File
@@ -43,6 +43,11 @@
#define _PATH_COND _PATH_VARRUN "finit/cond/"
struct command {
char *cmd;
int (*cb)(char *arg);
};
int verbose = 0;
int runlevel = 0;
@@ -272,7 +277,7 @@ static int do_cond(char *cmd)
{
int c;
char *arg;
command_t command[] = {
struct command command[] = {
{ "show", do_cond_show },
{ "set", do_cond_set },
{ "clear", do_cond_clear },
@@ -411,6 +416,9 @@ static int show_status(char *arg)
runlevel = runlevel_get(NULL);
if (arg && arg[0]) {
long now = jiffies();
char buf[42] = "N/A";
svc = client_svc_find(arg);
if (!svc)
return 1;
@@ -418,6 +426,7 @@ static int show_status(char *arg)
printf("Service : %s\n", svc->cmd);
printf("Description : %s\n", svc->desc);
printf("PID : %d\n", svc->pid);
printf("Uptime : %s\n", svc->pid ? uptime(now - svc->start_time, buf, sizeof(buf)) : buf);
printf("Runlevels : %s\n", runlevel_string(runlevel, svc->runlevels));
printf("Status : %s\n", svc_status(svc));
printf("\n");
@@ -426,7 +435,7 @@ static int show_status(char *arg)
}
if (!verbose)
printheader(NULL, "# STATUS PID RUNLEVELS SERVICE DESCRIPTION", 0);
printheader(NULL, "# STATUS PID RUNLEVELS SERVICE DESCRIPTION", 0);
for (svc = client_svc_iterator(1); svc; svc = client_svc_iterator(0)) {
char jobid[10], args[512] = "", *lvls;
@@ -436,7 +445,7 @@ static int show_status(char *arg)
// else
snprintf(jobid, sizeof(jobid), "%d:%d", svc->job, svc->id);
printf("%-5s %7s ", jobid, svc_status(svc));
printf("%-9s %7s ", jobid, svc_status(svc));
if (svc_is_inetd(svc))
printf("inetd ");
else
@@ -457,7 +466,7 @@ static int show_status(char *arg)
else
name++;
printf("%-20.20s %-*.*s\n", name, adj, adj, svc->desc);
printf("%-16.16s %-*.*s\n", name, adj, adj, svc->desc);
continue;
}
@@ -537,6 +546,7 @@ static int usage(int rc)
" start <JOB|NAME>[:ID] Start service by job# or name, with optional ID\n"
" stop <JOB|NAME>[:ID] Stop/Pause a running service by job# or name\n"
" restart <JOB|NAME>[:ID] Restart (stop/start) service by job# or name\n"
" status <JOB|NAME>[:ID] Show service status, by job# or name\n"
" status | show Show status of services, default command\n"
"\n"
" runlevel [0-9] Show or set runlevel: 0 halt, 6 reboot\n"
@@ -559,7 +569,7 @@ int main(int argc, char *argv[])
{
int c;
char *cmd, arg[120];
command_t command[] = {
struct command command[] = {
{ "debug", toggle_debug },
{ "help", do_help },
{ "version", show_version },
+29 -1
View File
@@ -29,12 +29,22 @@
#include "finit.h"
#include "log.h"
#include "util.h"
static int up = 0;
static int debug = 0;
static int silent = SILENT_MODE; /* Completely silent, including boot */
static int loglevel = LOG_NOTICE;
static void muffler(void)
{
silent = SILENT_MODE;
/* User override from kernel cmdline */
if (splash)
silent = 0;
}
void log_init(int dbg)
{
if (dbg)
@@ -44,16 +54,27 @@ void log_init(int dbg)
loglevel = LOG_DEBUG;
else
loglevel = LOG_NOTICE;
muffler();
}
/* If we enabled terse mode at boot, restore to previous setting at shutdown */
void log_exit(void)
{
silent = SILENT_MODE;
muffler();
if (!silent) {
sched_yield();
fputs("\n", stderr);
}
/*
* Unless in debug mode at shutdown, Reinitialize screen,
* terminal may have been resized at runtime
*/
if (debug)
screen_exit();
else
screen_init();
}
void log_open(void)
@@ -91,12 +112,19 @@ void log_debug(void)
if (debug) {
silent = 0;
loglevel = LOG_DEBUG;
screen_exit();
} else {
silent = SILENT_MODE;
loglevel = LOG_NOTICE;
screen_init();
}
log_open();
/* Also toggle silent mode (progress) */
log_silent();
logit(LOG_NOTICE, "Debug mode %s", debug ? "enabled" : "disabled");
}
+1 -1
View File
@@ -33,7 +33,7 @@
* errors and debug messages. For all other user messages, see logit()
*
* The default log level is LOG_NOTICE. To toggle LOG_DEBUG messages,
* use `initctl debug` or add `--debug` to the kernel cmdline.
* use `initctl debug` or add `debug` to the kernel cmdline.
*/
#define _d(fmt, args...) logit(LOG_DEBUG, "%s():" fmt "\n", __func__, ##args)
#define _w(fmt, args...) logit(LOG_WARNING, "%s():" fmt "\n", __func__, ##args)
+286
View File
@@ -0,0 +1,286 @@
/*
* Copyright (c) 2018 Joachim Nilsson <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 <config.h>
#include <errno.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SYSLOG_NAMES
#include <syslog.h>
#include <unistd.h>
#include <sys/stat.h>
static const char version_info[] = PACKAGE_NAME " v" PACKAGE_VERSION;
static int create(char *path, mode_t mode, uid_t uid, gid_t gid)
{
return mknod(path, S_IFREG | mode, 0) || chown(path, uid, gid);
}
/*
* This function triggers a log rotates of @file when size >= @sz bytes
* At most @num old versions are kept and by default it starts gzipping
* .2 and older log files. If gzip is not available in $PATH then @num
* files are kept uncompressed.
*/
static int logrotate(char *file, int num, off_t sz)
{
int cnt;
struct stat st;
if (stat(file, &st))
return 1;
if (sz > 0 && S_ISREG(st.st_mode) && st.st_size > sz) {
if (num > 0) {
size_t len = strlen(file) + 10 + 1;
char ofile[len];
char nfile[len];
/* First age zipped log files */
for (cnt = num; cnt > 2; cnt--) {
snprintf(ofile, len, "%s.%d.gz", file, cnt - 1);
snprintf(nfile, len, "%s.%d.gz", file, cnt);
/* May fail because ofile doesn't exist yet, ignore. */
(void)rename(ofile, nfile);
}
for (cnt = num; cnt > 0; cnt--) {
snprintf(ofile, len, "%s.%d", file, cnt - 1);
snprintf(nfile, len, "%s.%d", file, cnt);
/* May fail because ofile doesn't exist yet, ignore. */
(void)rename(ofile, nfile);
if (cnt == 2 && !access(nfile, F_OK)) {
size_t len = 5 + strlen(nfile) + 1;
char cmd[len];
snprintf(cmd, len, "gzip %s", nfile);
system(cmd);
remove(nfile);
}
}
if (rename(file, nfile))
(void)truncate(file, 0);
else
create(file, st.st_mode, st.st_uid, st.st_gid);
} else {
if (truncate(file, 0))
syslog(LOG_ERR | LOG_PERROR, "Failed truncating %s during logrotate: %s", file, strerror(errno));
}
}
return 0;
}
static int checksz(FILE *fp, off_t sz)
{
struct stat st;
if (sz <= 0)
return 0;
if (!fstat(fileno(fp), &st) && st.st_size > sz) {
fclose(fp);
return 1;
}
return 0;
}
static int flogit(char *logfile, int num, off_t sz, char *buf, size_t len)
{
FILE *fp;
reopen:
fp = fopen(logfile, "a");
if (!fp) {
syslog(LOG_ERR | LOG_PERROR, "Failed opening %s: %s", logfile, strerror(errno));
return 1;
}
if (buf[0]) {
fprintf(fp, "%s\n", buf);
fsync(fileno(fp));
if (checksz(fp, sz))
return logrotate(logfile, num, sz);
} else {
while ((fgets(buf, len, stdin))) {
fputs(buf, fp);
fsync(fileno(fp));
if (checksz(fp, sz)) {
logrotate(logfile, num, sz);
buf[0] = 0;
goto reopen;
}
}
}
return fclose(fp);
}
static int logit(int level, char *buf, size_t len)
{
if (buf[0]) {
syslog(level, "%s", buf);
return 0;
}
while ((fgets(buf, len, stdin)))
syslog(level, "%s", buf);
return 0;
}
static int parse_prio(char *arg, int *f, int *l)
{
char *ptr;
ptr = strchr(arg, '.');
if (ptr) {
*ptr++ = 0;
for (int i = 0; facilitynames[i].c_name; i++) {
if (!strcmp(facilitynames[i].c_name, arg)) {
*f = facilitynames[i].c_val;
break;
}
}
arg = ptr;
}
for (int i = 0; prioritynames[i].c_name; i++) {
if (!strcmp(prioritynames[i].c_name, arg)) {
*l = prioritynames[i].c_val;
break;
}
}
return 0;
}
static int usage(int code)
{
fprintf(stderr, "Usage: logit [OPTIONS] [MESSAGE]\n"
"\n"
"Write MESSAGE (or stdin) to syslog, or file (with logrotate)\n"
"\n"
" -h This help text\n"
" -p PRIO Priority (numeric or facility.level pair)\n"
" -t TAG Log using the specified tag (defaults to user name)\n"
" -s Log to stderr as well as the system log\n"
"\n"
" -f FILE File to write log messages to, instead of syslog\n"
" -n SIZE Number of bytes before rotating, default: 200 kB\n"
" -r NUM Number of rotated files to keep, default: 5\n"
" -v Show program version\n"
"\n"
"This version of logit is distributed as part of Finit.\n"
"Bug report address: %s\n", PACKAGE_BUGREPORT);
return code;
}
int main(int argc, char *argv[])
{
int c, rc, num = 5;
int facility = LOG_USER;
int level = LOG_INFO;
int log_opts = LOG_NOWAIT;
off_t size = 200 * 1024;
char *ident = NULL, *logfile = NULL;
char buf[512] = "";
while ((c = getopt(argc, argv, "f:hn:p:r:st:v")) != EOF) {
switch (c) {
case 'f':
logfile = optarg;
break;
case 'h':
return usage(0);
case 'n':
size = atoi(optarg);
break;
case 'p':
if (parse_prio(optarg, &facility, &level))
return usage(1);
break;
case 'r':
num = atoi(optarg);
break;
case 's':
log_opts |= LOG_PERROR;
break;
case 't':
ident = optarg;
break;
case 'v': /* version */
fprintf(stderr, "%s\n", version_info);
return 0;
default:
return usage(1);
}
}
if (!ident)
ident = getenv("LOGNAME") ?: getenv("USER");
if (optind < argc) {
size_t pos = 0, len = sizeof(buf);
while (optind < argc) {
size_t bytes;
bytes = snprintf(&buf[pos], len, "%s ", argv[optind++]);
pos += bytes;
len -= bytes;
}
}
openlog(ident, log_opts, facility);
if (logfile)
rc = flogit(logfile, num, size, buf, sizeof(buf));
else
rc = logit(level, buf, sizeof(buf));
closelog();
return rc;
}
+116 -2
View File
@@ -1,7 +1,7 @@
/* Misc. utility functions and C-library extensions for finit and its plugins
/* PID and PID file helpers
*
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2015 Joachim Nilsson <troglobit@gmail.com>
* Copyright (c) 2008-2018 Joachim Nilsson <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -23,11 +23,14 @@
*/
#include <errno.h>
#include <paths.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <lite/lite.h>
#include "pid.h"
#include "svc.h"
#include "helpers.h"
@@ -90,6 +93,117 @@ char *pid_get_name(pid_t pid, char *name, size_t len)
return pname;
}
char *pid_file(svc_t *svc)
{
char fn[MAX_ARG_LEN];
static char path[MAX_ARG_LEN];
if (svc->pidfile[0]) {
if (svc->pidfile[0] == '!')
return &svc->pidfile[1];
return svc->pidfile;
}
snprintf(fn, sizeof(fn), "%s%s.pid", _PATH_VARRUN, basename(svc->cmd));
return pid_runpath(fn, path, sizeof(path));
}
int pid_file_create(svc_t *svc)
{
FILE *fp;
if (!svc->pidfile[0] || svc->pidfile[0] == '!')
return 1;
fp = fopen(svc->pidfile, "w");
if (!fp)
return 1;
fprintf(fp, "%d\n", svc->pid);
return fclose(fp);
}
static int pid_realpath(svc_t *svc, char *file)
{
int not = 0;
if (!file)
file = pid_file(svc);
if (file[0] == '!') {
not = 1;
file++;
}
pid_runpath(file, &svc->pidfile[not], sizeof(svc->pidfile) - not);
if (not)
svc->pidfile[0] = '!';
return 0;
}
/*
* This function parses a PID file @arg for @svc.
*
* The logic is explained below. Please note that using the first form
* of the syntax not only creates and removes the PID file, but it also
* calls touch to update the mtime on service_restart(), only applicable
* to processes that accept SIGHUP. This to ensure dependant services
* are sent SIGCONT properly on reload, otherwise their condition would
* never be asserted again after `initctl reload`.
*
* pid --> /run/$(basename).pid
* pid:foo --> /run/foo.pid
* pid:foo.pid --> /run/foo.pid
* pid:foo.tla --> /run/foo.tla.pid
* pid:/tmp/foo --> /tmp/foo.pid (Not handled by pidfile plugin!)
*
* An exclamation mark, or logial NOT, in the first character position
* indicates that Finit should *not* manage the PID file, and that the
* process uses a "non-standard" location. Eg. if service is 'bar'
* Finit would assume the PID file is /run/bar.pid and the below simply
* 'redirects' Finit to use the correct PID file.
*
* pid:!foo --> !/run/foo.pid
* pid:!/run/foo.pid --> !/run/foo.pid
*
* Note, nothing is created or removed by Finit in this latter form.
*/
int pid_file_parse(svc_t *svc, char *arg)
{
/* Sanity check ... */
if (!arg || !arg[0])
return 1;
/* 'pid:' implies argument following*/
if (!strncmp(arg, "pid:", 4)) {
int len, not = 0;
char path[MAX_ARG_LEN];
arg += 4;
if ((arg[0] == '!' && arg[1] == '/') || arg[0] == '/')
return pid_realpath(svc, arg);
if (arg[0] == '!') {
arg++;
not++;
}
len = snprintf(path, sizeof(path), "%s%s%s", not ? "!" : "", _PATH_VARRUN, arg);
if (len > 4 && strcmp(&path[len - 4], ".pid"))
strlcat(path, ".pid", sizeof(path));
return pid_realpath(svc, path);
}
/* 'pid' arg, no argument following */
if (!strcmp(arg, "pid"))
return pid_realpath(svc, NULL);
return 1;
}
/**
* Local Variables:
* indent-tabs-mode: t
+65
View File
@@ -0,0 +1,65 @@
/* PID and PID file helpers
*
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2018 Joachim Nilsson <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.
*/
#ifndef FINIT_PID_H_
#define FINIT_PID_H_
#include "svc.h"
int pid_alive (pid_t pid);
char *pid_get_name (pid_t pid, char *name, size_t len);
char *pid_file (svc_t *svc);
int pid_file_create (svc_t *svc);
int pid_file_parse (svc_t *svc, char *arg);
static inline char *pid_runpath(char *file, char *path, size_t len)
{
static int unknown = 1;
static char *prefix = "/var/run";
if (unknown) {
if (fisdir("/run"))
prefix = "/run";
unknown = 0;
}
if (!strncmp(file, "/var/run/", 9))
file += 9;
else if (!strncmp(file, "/run/", 5))
file += 5;
snprintf(path, len, "%s/%s", prefix, file);
return path;
}
#endif /* FINIT_PID_H_ */
/**
* Local Variables:
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+7 -6
View File
@@ -108,6 +108,9 @@ int plugin_register(plugin_t *plugin)
/* Not called, at the moment plugins cannot be unloaded. */
int plugin_unregister(plugin_t *plugin)
{
if (is_io_plugin(plugin))
uev_io_stop(&plugin->watcher);
#ifndef ENABLE_STATIC
TAILQ_REMOVE(&plugins, plugin, link);
@@ -196,10 +199,8 @@ void plugin_run_hook(hook_point_t no, void *arg)
* End recursion: any plugin hook => start service => SVC start
* hook => start service ... err ... wait a second
*/
if (HOOK_SVC_START == last) {
_d("End plugin recursion in our lifetime!");
if (HOOK_SVC_START == last)
return;
}
PLUGIN_ITERATOR(p, tmp) {
if (p->hook[no].cb) {
@@ -212,7 +213,7 @@ void plugin_run_hook(hook_point_t no, void *arg)
if (HOOK_SVC_START == no)
last = no;
cond_set(hook_cond[no]);
cond_set_oneshot(hook_cond[no]);
service_step_all(SVC_TYPE_RUNTASK);
if (HOOK_SVC_START == no)
@@ -384,11 +385,11 @@ static int load_plugins(char *path)
}
#endif /* ENABLE_STATIC */
int plugin_init(uev_ctx_t *ctx, char *path)
int plugin_init(uev_ctx_t *ctx)
{
int fail = 1;
if (!load_plugins(path))
if (!load_plugins(PLUGIN_PATH))
fail = init_plugins(ctx);
return fail;
+17 -8
View File
@@ -29,10 +29,6 @@
#include "svc.h"
#ifndef PLUGIN_PATH /* Fallback for --enable-static builds */
#define PLUGIN_PATH "/dev/null"
#endif
#define PLUGIN_DEP_MAX 10
/*
@@ -54,22 +50,35 @@
* Predefined hook points and corresponding conditions in Finit,
* for use by plugins and scripts. Recommended to use the task
* or run stanzas: task <hook/mount/error> /bin/rescue.sh
*
* Some of the below hooks cannot (currently) be realized as conditions.
* The idea was to rename them action scripts, with optional argument,
* according to the following scheme:
*
* - HOOK_SVC_RECONF :: action/svc/reconf
* - HOOK_SVC_LOST :: action/svc/lost
* - HOOK_SVC_START :: action/svc/start
* - HOOK_RUNLEVEL_CHANGE :: action/sys/runlevel
*
* However, the implementation did not turn out to be stable enough for
* general release, so it was pulled.
*/
#define HOOK_TYPES { \
/* Bootstrap hooks, runlevel [S] */ \
CHOOSE(HOOK_BANNER = 0, "hook/sys/banner"), \
CHOOSE(HOOK_ROOTFS_UP, "hook/mount/root"), \
CHOOSE(HOOK_MOUNT_ERROR, "hook/mount/error"), \
CHOOSE(HOOK_MOUNT_POST, "hook/mount/post"), \
CHOOSE(HOOK_BASEFS_UP, "hook/mount/all"), \
CHOOSE(HOOK_NETWORK_UP, "hook/net/up"), \
CHOOSE(HOOK_SVC_UP, "hook/svc/up"), \
CHOOSE(HOOK_SYSTEM_UP, "hook/sys/up"), \
\
/* Runtime hooks, runlevel [S1-9] */ \
CHOOSE(HOOK_SVC_RECONF, "hook/svc/reconf"), \
CHOOSE(HOOK_SVC_LOST, "hook/svc/lost"), \
CHOOSE(HOOK_SVC_START, "hook/svc/start"), \
CHOOSE(HOOK_RUNLEVEL_CHANGE, "hook/sys/runlevel"), \
CHOOSE(HOOK_SVC_RECONF, "nop"), \
CHOOSE(HOOK_SVC_LOST, "nop"), \
CHOOSE(HOOK_SVC_START, "nop"), \
CHOOSE(HOOK_RUNLEVEL_CHANGE, "nop"), \
\
/* Shutdown hooks, runlevel [06] */ \
CHOOSE(HOOK_SHUTDOWN, "hook/sys/shutdown"), \
+1 -1
View File
@@ -45,7 +45,7 @@ int plugin_exists (hook_point_t no);
void plugin_run_hook (hook_point_t no, void *arg);
void plugin_run_hooks (hook_point_t no);
int plugin_init (uev_ctx_t *ctx, char *path);
int plugin_init (uev_ctx_t *ctx);
void plugin_exit (void);
#endif /* FINIT_PRIVATE_H_ */
+1 -1
View File
@@ -207,7 +207,7 @@ int main(int argc, char *argv[])
if (c)
err(1, "Failed signalling init to %s", msg);
do_sleep(2);
do_sleep(5);
return 0;
}
+3
View File
@@ -0,0 +1,3 @@
runlevel 1
hostname rescue
tty [12345] @console noclear nologin
+217 -77
View File
@@ -25,6 +25,7 @@
#include "config.h" /* Generated by configure script */
#include <ctype.h> /* isblank() */
#include <sched.h> /* sched_yield() */
#include <string.h>
#include <sys/resource.h>
#include <sys/wait.h>
@@ -36,11 +37,13 @@
#include "finit.h"
#include "helpers.h"
#include "inetd.h"
#include "pid.h"
#include "private.h"
#include "sig.h"
#include "service.h"
#include "sm.h"
#include "tty.h"
#include "util.h"
#include "utmp-api.h"
#define RESPAWN_MAX 10 /* Prevent endless respawn of faulty services. */
@@ -60,7 +63,8 @@ static void service_timeout_cb(uev_t *w, void *arg, int events)
svc_t *svc = arg;
/* Ignore any UEV_ERROR, we're a one-shot cb so just run it. */
svc->timer_cb(svc);
if (svc->timer_cb)
svc->timer_cb(svc);
}
/**
@@ -106,6 +110,18 @@ static int service_timeout_cancel(svc_t *svc)
return err;
}
static void redirect_null(void)
{
FILE *fp;
fp = fopen("/dev/null", "w");
if (fp) {
dup2(fileno(fp), STDOUT_FILENO);
dup2(fileno(fp), STDERR_FILENO);
fclose(fp);
}
}
static int is_norespawn(void)
{
return sig_stopped() ||
@@ -122,7 +138,7 @@ static int is_norespawn(void)
*/
static int service_start(svc_t *svc)
{
int i, result = 0;
int i, result = 0, do_progress = 1;
pid_t pid;
sigset_t nmask, omask;
@@ -145,10 +161,15 @@ static int service_start(svc_t *svc)
return inetd_start(&svc->inetd);
#endif
if (svc_is_daemon(svc))
print_desc("Starting ", svc->desc);
else
print_desc("", svc->desc);
if (!svc->desc[0])
do_progress = 0;
if (do_progress) {
if (svc_is_daemon(svc))
print_desc("Starting ", svc->desc);
else
print_desc("", svc->desc);
}
/* Declare we're waiting for svc to create its pidfile */
svc_starting(svc);
@@ -210,30 +231,38 @@ static int service_start(svc_t *svc)
} else
#endif
if (svc->log) {
if (svc->log.enabled) {
int fd;
if (svc->log.null) {
redirect_null();
goto logit_done;
}
/*
* Open PTY to connect to logger. A pty isn't buffered
* like a pipe, and it eats newlines so they aren't logged
*/
fd = posix_openpt(O_RDWR);
if (fd == -1) {
svc->log = 0;
goto logger_err;
svc->log.enabled = 0;
goto logit_done;
}
if (grantpt(fd) == -1 || unlockpt(fd) == -1) {
close(fd);
svc->log = 0;
goto logger_err;
svc->log.enabled = 0;
goto logit_done;
}
/* SIGCHLD is still blocked for grantpt() and fork() */
sigprocmask(SIG_BLOCK, &nmask, NULL);
pid = fork();
if (pid == 0) {
int fds = open(ptsname(fd), O_RDONLY);
int fds;
char *tag = basename(svc->cmd);
char *prio = "daemon.info";
fds = open(ptsname(fd), O_RDONLY);
close(fd);
if (fds == -1)
_exit(0);
@@ -242,7 +271,22 @@ static int service_start(svc_t *svc)
/* Reset signals */
sig_unblock();
execlp("logger", "logger", "-t", svc->cmd, "-p", "daemon.info", NULL);
if (svc->log.file[0] == '/') {
char sz[20], num[3];
snprintf(sz, sizeof(sz), "%d", logfile_size_max);
snprintf(num, sizeof(num), "%d", logfile_count_max);
execlp("logit", "logit", "-f", svc->log.file, "-n", sz, "-r", num, NULL);
_exit(0);
}
if (svc->log.ident[0])
tag = svc->log.ident;
if (svc->log.prio[0])
prio = svc->log.prio;
execlp("logit", "logit", "-t", tag, "-p", prio, NULL);
_exit(0);
}
@@ -258,18 +302,13 @@ static int service_start(svc_t *svc)
dup2(fd, STDERR_FILENO);
close(fd);
}
} else {
FILE *fp;
fp = fopen("/dev/null", "w");
if (fp) {
dup2(fileno(fp), STDOUT_FILENO);
dup2(fileno(fp), STDERR_FILENO);
fclose(fp);
}
}
#ifdef REDIRECT_OUTPUT
else
redirect_null();
#endif
logger_err:
logit_done:
sig_unblock();
if (svc->inetd.cmd)
@@ -288,9 +327,9 @@ static int service_start(svc_t *svc)
}
} else
#endif
if (svc->log)
if (svc->log.enabled && !svc->log.null)
waitpid(pid, NULL, 0);
exit(status);
_exit(status);
} else if (log_is_debug()) {
char buf[CMD_SIZE] = "";
@@ -305,6 +344,7 @@ static int service_start(svc_t *svc)
}
svc->pid = pid;
svc->start_time = jiffies();
#ifdef INETD_ENABLED
if (svc_is_inetd_conn(svc) && svc->inetd.type == SOCK_STREAM)
@@ -314,13 +354,17 @@ static int service_start(svc_t *svc)
if (SVC_TYPE_RUN == svc->type) {
result = WEXITSTATUS(complete(svc->cmd, pid));
if (!svc_clean_bootstrap(svc)) {
svc->pid = 0;
svc->start_time = svc->pid = 0;
svc_set_state(svc, SVC_STOPPING_STATE);
}
}
if (svc_is_daemon(svc))
pid_file_create(svc);
sigprocmask(SIG_SETMASK, &omask, NULL);
print_result(result);
if (do_progress)
print_result(result);
/*
* Only run hook on successful start, and *after* having printed
@@ -349,10 +393,10 @@ static void service_kill(svc_t *svc)
return;
}
_d("%s: Sending SIGKILL to pid:%d", pid_get_name(svc->pid, NULL, 0), svc->pid);
if (runlevel != 1)
print_desc("Killing ", svc->desc);
_d("%s: Sending SIGKILL to pid:%d", pid_get_name(svc->pid, NULL, 0), svc->pid);
kill(svc->pid, SIGKILL);
/* Let SIGKILLs stand out, show result as [WARN] */
@@ -376,31 +420,31 @@ static int service_stop(svc_t *svc)
#ifdef INETD_ENABLED
if (svc_is_inetd(svc)) {
int do_print = runlevel != 1 && !svc_is_busy(svc);
int do_progress = runlevel != 1 && !svc_is_busy(svc);
if (do_print)
if (do_progress)
print_desc("Stopping ", svc->desc);
inetd_stop(&svc->inetd);
if (do_print)
if (do_progress)
print_result(0);
svc_set_state(svc, SVC_STOPPING_STATE);
return 0;
}
} else
#endif
service_timeout_cancel(svc);
if (svc->pid <= 1) {
_d("Bad PID %d for %s, SIGTERM", svc->pid, svc->desc);
if (svc->pid <= 1)
return 1;
}
if (SVC_TYPE_SERVICE != svc->type)
return 0;
_d("Sending SIGTERM to pid:%d name:%s", svc->pid, pid_get_name(svc->pid, NULL, 0));
svc_set_state(svc, SVC_STOPPING_STATE);
if (runlevel != 1)
print_desc("Stopping ", svc->desc);
_d("Sending SIGTERM to pid:%d name:%s", svc->pid, pid_get_name(svc->pid, NULL, 0));
res = kill(svc->pid, SIGTERM);
if (runlevel != 1)
@@ -421,6 +465,8 @@ static int service_stop(svc_t *svc)
*/
static int service_restart(svc_t *svc)
{
int rc;
/* Ignore if finit is SIGSTOP'ed */
if (is_norespawn())
return 1;
@@ -430,17 +476,29 @@ static int service_restart(svc_t *svc)
if (svc->pid <= 1) {
_d("Bad PID %d for %s, SIGHUP", svc->pid, svc->cmd);
svc->pid = 0;
svc->start_time = svc->pid = 0;
return 1;
}
print_desc("Restarting ", svc->desc);
_d("Sending SIGHUP to PID %d", svc->pid);
if (svc->desc[0])
print_desc("Restarting ", svc->desc);
rc = kill(svc->pid, SIGHUP);
/* Declare we're waiting for svc to re-assert/touch its pidfile */
svc_starting(svc);
_d("Sending SIGHUP to PID %d", svc->pid);
return print_result(kill(svc->pid, SIGHUP));
/* Service does not maintain a PID file on its own */
if (svc_has_pidfile(svc)) {
sched_yield();
touch(pid_file(svc));
}
if (svc->desc[0])
print_result(rc);
return rc;
}
/**
@@ -465,8 +523,38 @@ void service_reload_dynamic(void)
*/
void service_runlevel(int newlevel)
{
if (!rescue && runlevel <= 1 && newlevel > 1)
networking(1);
sm_set_runlevel(&sm, newlevel);
sm_step(&sm);
if (!rescue && runlevel <= 1)
networking(0);
}
/*
* log:/path/to/logfile,priority:facility.level,tag:ident
*/
static void parse_log(svc_t *svc, char *arg)
{
char *tok;
tok = strtok(arg, ":, ");
while (tok) {
if (!strcmp(tok, "log"))
svc->log.enabled = 1;
else if (!strcmp(tok, "null") || !strcmp(tok, "/dev/null"))
svc->log.null = 1;
else if (tok[0] == '/')
strlcpy(svc->log.file, tok, sizeof(svc->log.file));
else if (!strcmp(tok, "priority") || !strcmp(tok, "prio"))
strlcpy(svc->log.prio, strtok(NULL, ","), sizeof(svc->log.prio));
else if (!strcmp(tok, "tag") || !strcmp(tok, "identity") || !strcmp(tok, "ident"))
strlcpy(svc->log.ident, strtok(NULL, ","), sizeof(svc->log.ident));
tok = strtok(NULL, ":=, ");
}
}
/**
@@ -507,7 +595,7 @@ void service_runlevel(int newlevel)
*
* Service conditions can be: svc/<PATH> for PID files, net/<IFNAME>/up
* and net/<IFNAME>/exists. The condition handling is further described
* doc/conditions.md.
* docs/conditions.md.
*
* For multiple instances of the same command, e.g. multiple DHCP
* clients, the user must enter an ID, using the :ID syntax.
@@ -528,8 +616,9 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
#ifdef INETD_ENABLED
int forking = 0;
#endif
int log = 0, levels = 0;
char *username = NULL, *line;
int levels = 0;
char *line;
char *username = NULL, *log = NULL, *pid = NULL;
char *service = NULL, *proto = NULL, *ifaces = NULL;
char *cmd, *desc, *runlevels = NULL, *cond = NULL;
svc_t *svc;
@@ -551,6 +640,15 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
while (*desc && isblank(*desc))
desc++;
} else {
int pos;
/* Find "--\n" to denote empty/no description */
pos = (int)strlen(line) - 2;
if (pos > 0 && !strcmp(&line[pos], "--")) {
line[pos] = 0;
desc = &line[pos];
}
}
cmd = strtok(line, " ");
@@ -562,7 +660,7 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
}
while (cmd) {
if (cmd[0] == '@') /* @username[:group] */
if (cmd[0] == '@') /* @username[:group] */
username = &cmd[1];
else if (cmd[0] == '[') /* [runlevels] */
runlevels = &cmd[0];
@@ -576,10 +674,12 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
else if (!strncasecmp(cmd, "wait", 4))
forking = 0;
#endif
else if (!strncasecmp(cmd, "log", 3))
log = cmd;
else if (!strncasecmp(cmd, "pid", 3))
pid = cmd;
else if (cmd[0] != '/' && strchr(cmd, '/'))
service = cmd; /* inetd service/proto */
else if (!strncasecmp(cmd, "log", 3))
log = 1;
else
break;
@@ -664,9 +764,11 @@ recreate:
}
#endif
svc->log = log;
if (desc)
strlcpy(svc->desc, desc, sizeof(svc->desc));
/* Always clear svc PID file, for now. See TODO */
svc->pidfile[0] = 0;
/* Decode any optional pid:/optional/path/to/file.pid */
if (pid && svc_is_daemon(svc) && pid_file_parse(svc, pid))
_e("Invalid 'pid' argument to service: %s", pid);
if (username) {
char *ptr = strchr(username, ':');
@@ -694,6 +796,11 @@ recreate:
conf_parse_cond(svc, cond);
if (log)
parse_log(svc, log);
if (desc)
strlcpy(svc->desc, desc, sizeof(svc->desc));
#ifdef INETD_ENABLED
if (svc_is_inetd(svc)) {
char *iface, *name = service;
@@ -732,20 +839,52 @@ recreate:
else
svc_mark_clean(svc);
if (!file)
svc->protected = 1;
/* Free duped line, from above */
free(line);
return 0;
}
/*
* This function is called when cleaning up lingering (stopped) services
* after a .conf reload, as well as when an inetd connection terminates.
*
* We need to ensure we properly stop the service before removing it,
* including stopping any pending restart or SIGKILL timers before we
* proceed to free() the svc itself.
*
* Remember to not try to stop inetd connections, they only get here
* when already stopped, if we do we end up in a recursive loop.
*/
void service_unregister(svc_t *svc)
{
if (!svc)
return;
/*
* Only try stopping @svc if it's *not* an inetd connection.
* Prevents infinite recursion when called from service_step()
*/
if (!svc_is_inetd_conn(svc))
service_stop(svc);
if (svc_is_inetd(svc)) {
if (svc_is_busy(svc->inetd.svc)) {
svc_unblock(svc->inetd.svc);
service_step(svc->inetd.svc);
}
inetd_del(&svc->inetd);
}
svc_del(svc);
}
void service_monitor(pid_t lost)
{
svc_t *svc;
char pidfile[MAX_ARG_LEN];
if (fexist(SYNC_SHUTDOWN) || lost <= 1)
return;
@@ -764,19 +903,22 @@ void service_monitor(pid_t lost)
_d("collected %s(%d)", svc->cmd, lost);
/* Try removing PID file (in case service does not clean up after itself) */
snprintf(pidfile, sizeof(pidfile), "%s%s.pid", _PATH_VARRUN, basename(svc->cmd));
if (remove(pidfile)) {
if (errno != ENOENT)
logit(LOG_CRIT, "Failed removing service %s pidfile %s", basename(svc->cmd), pidfile);
if (svc_is_daemon(svc)) {
char *fn;
fn = pid_file(svc);
if (remove(fn) && errno != ENOENT)
logit(LOG_CRIT, "Failed removing service %s pidfile %s", basename(svc->cmd), fn);
}
/* No longer running, update books. */
svc->pid = 0;
service_step(svc);
svc->start_time = svc->pid = 0;
/* Clean out any bootstrap tasks, they've had their time in the sun. */
if (svc_clean_bootstrap(svc))
_d("collected bootstrap task %s(%d), removing.", svc->cmd, lost);
if (!service_step(svc)) {
/* Clean out any bootstrap tasks, they've had their time in the sun. */
if (svc_clean_bootstrap(svc))
_d("collected bootstrap task %s(%d), removing.", svc->cmd, lost);
}
sm_step(&sm);
}
@@ -790,13 +932,13 @@ static void service_retry(svc_t *svc)
if (svc->state != SVC_HALTED_STATE ||
svc->block != SVC_BLOCK_RESTARTING) {
_d("%s not crashing anymore", svc->desc);
_d("%s not crashing anymore", svc->cmd);
*restart_cnt = 0;
return;
}
if (*restart_cnt >= RESPAWN_MAX) {
logit(LOG_ERR, "%s keeps crashing, not restarting", svc->desc);
logit(LOG_ERR, "%s keeps crashing, not restarting", svc->cmd);
svc_crashing(svc);
*restart_cnt = 0;
service_step(svc);
@@ -805,7 +947,7 @@ static void service_retry(svc_t *svc)
(*restart_cnt)++;
_d("%s crashed, trying to start it again, attempt %d", svc->desc, *restart_cnt);
_d("%s crashed, trying to start it again, attempt %d", svc->cmd, *restart_cnt);
svc_unblock(svc);
service_step(svc);
@@ -827,7 +969,12 @@ static void svc_set_state(svc_t *svc, svc_state_t new)
}
}
void service_step(svc_t *svc)
/*
* Transition inetd/task/run/service
*
* Returns: non-zero if the @svc is no longer valid (removed)
*/
int service_step(svc_t *svc)
{
int err;
char *restart_cnt = (char *)&svc->restart_cnt;
@@ -852,12 +999,8 @@ restart:
case SVC_DONE_STATE:
#ifdef INETD_ENABLED
if (svc_is_inetd_conn(svc)) {
if (svc_is_busy(svc->inetd.svc)) {
svc_unblock(svc->inetd.svc);
service_step(svc->inetd.svc);
}
service_unregister(svc);
return;
return -1;
}
#endif
if (svc_is_changed(svc))
@@ -917,7 +1060,6 @@ restart:
case SVC_RUNNING_STATE:
if (!enabled) {
service_stop(svc);
svc_set_state(svc, SVC_STOPPING_STATE);
break;
}
@@ -930,7 +1072,7 @@ restart:
* Restart directly after the first crash,
* then retry after 2 sec
*/
_d("delayed restart of %s", svc->desc);
_d("delayed restart of %s", svc->cmd);
service_timeout_after(svc, 1, service_retry);
break;
}
@@ -951,7 +1093,6 @@ restart:
switch (cond) {
case COND_OFF:
service_stop(svc);
svc_set_state(svc, SVC_STOPPING_STATE);
break;
case COND_FLUX:
@@ -968,7 +1109,6 @@ restart:
service_restart(svc);
} else {
service_stop(svc);
svc_set_state(svc, SVC_STOPPING_STATE);
}
svc_mark_clean(svc);
}
@@ -980,7 +1120,6 @@ restart:
if (!enabled) {
kill(svc->pid, SIGCONT);
service_stop(svc);
svc_set_state(svc, SVC_STOPPING_STATE);
break;
}
@@ -1000,7 +1139,6 @@ restart:
case COND_OFF:
kill(svc->pid, SIGCONT);
service_stop(svc);
svc_set_state(svc, SVC_STOPPING_STATE);
break;
case COND_FLUX:
@@ -1013,6 +1151,8 @@ restart:
_d("%20s(%4d): -> %8s", svc->cmd, svc->pid, svc_status(svc));
goto restart;
}
return 0;
}
void service_step_all(int types)
+1 -1
View File
@@ -34,7 +34,7 @@ void service_unregister (svc_t *svc);
void service_runtask_clean (void);
void service_reload_dynamic (void);
void service_step (svc_t *svc);
int service_step (svc_t *svc);
void service_step_all (int types);
void service_bootstrap_cb (uev_t *w, void *arg, int events);
+17 -2
View File
@@ -27,6 +27,8 @@
*
* SIGHUP
* Same effect as init/telinit q, reloads *.conf in /etc/finit.d/
* Also restarts API (initctl) socket, like SysV init and systemd
* does on USR1 with their FIFO/D-Bus.
*
* SIGUSR1
* Calls shutdown hooks, including HOOK_SHUTDOWN, stops all running
@@ -131,8 +133,12 @@ void do_kill(int signo)
continue;
if (fgets(file, sizeof(file), fp)) {
if (file[0] != '@')
if (strstr(file, "gdbserver"))
_d("Skipping %s ...", file);
else if (file[0] != '@')
kill(pid, signo);
else
_d("Skipping %s ...", &file[1]);
}
fclose(fp);
}
@@ -179,6 +185,11 @@ void do_shutdown(shutop_t op)
return;
}
if (wdogpid) {
print(kill(wdogpid, SIGPWR) == 1, "Advising watchdog, system going down");
do_sleep(2);
}
/* Unmount any tmpfs before unmounting swap ... */
unmount_tmpfs();
run("swapoff -e -a");
@@ -201,7 +212,7 @@ void do_shutdown(shutop_t op)
int timeout = 10;
/* Wait here until the WDT reboots, or timeout with fallback */
print(kill(wdogpid, SIGPWR) == 1, "Pending watchdog reboot");
print(kill(wdogpid, SIGTERM) == 1, "Pending watchdog reboot");
while (timeout--)
do_sleep(1);
}
@@ -229,6 +240,10 @@ static void sighup_cb(uev_t *w, void *arg, int events)
return;
}
/* Restart initctl API domain socket, similar to systemd/SysV init */
api_exit();
api_init(w->ctx);
/* INIT_CMD_RELOAD: 'init q', 'initctl reload', and SIGHUP */
service_reload_dynamic();
}
+1 -1
View File
@@ -143,7 +143,7 @@ restart:
erase("/etc/nologin");
/* Make sure to (re)load all *.conf in /etc/finit.d/ */
if (runlevel != 0 && runlevel != 6)
if (conf_any_change())
conf_reload();
/* Reset once flag of runtasks */
+31 -7
View File
@@ -32,6 +32,7 @@
#include "finit.h"
#include "svc.h"
#include "helpers.h"
#include "pid.h"
#include "util.h"
/* Each svc_t needs a unique job# */
@@ -73,7 +74,7 @@ svc_t *svc_new(char *cmd, int id, int type)
strlcpy(svc->cmd, cmd, sizeof(svc->cmd));
/* Default description, if missing */
desc = rindex(cmd, '/');
desc = strrchr(cmd, '/');
if (desc)
desc++;
else
@@ -205,7 +206,7 @@ svc_t *svc_job_iterator(svc_t **iter, int first, int job)
* svc_foreach - Run a callback for each registered service
* @cb: Callback to run for each service
*/
void svc_foreach(void (*cb)(svc_t *))
void svc_foreach(int (*cb)(svc_t *))
{
svc_t *svc, *iter = NULL;
@@ -222,7 +223,7 @@ void svc_foreach(void (*cb)(svc_t *))
* @types: Mask of service types
* @cb: Callback to run for each matching type
*/
void svc_foreach_type(int types, void (*cb)(svc_t *))
void svc_foreach_type(int types, int (*cb)(svc_t *))
{
svc_t *svc, *iter = NULL;
@@ -342,6 +343,27 @@ svc_t *svc_find_by_nameid(char *name, int id)
return NULL;
}
/**
* svc_find_by_plidfile - Find an service object by its PID file
* @fn: PID file, can be absolute path or relative to /run
*
* Returns:
* A pointer to an &svc_t object, or %NULL if not found.
*/
svc_t *svc_find_by_pidfile(char *fn)
{
svc_t *svc, *iter = NULL;
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
char path[MAX_ARG_LEN];
if (string_compare(pid_runpath(fn, path, sizeof(path)), pid_file(svc)))
return svc;
}
return NULL;
}
/**
* svc_mark_dynamic - Mark dynamically loaded services for deletion.
*
@@ -356,8 +378,12 @@ void svc_mark_dynamic(void)
{
svc_t *svc, *iter = NULL;
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0))
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
if (svc->protected)
continue;
*((int *)&svc->dirty) = -1;
}
}
void svc_mark_dirty(svc_t *svc)
@@ -382,10 +408,8 @@ void svc_clean_dynamic(void (*cb)(svc_t *))
svc_t *svc, *iter = NULL;
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
if (svc->dirty == -1 && cb) {
if (svc->dirty == -1 && cb)
cb(svc);
svc_mark_clean(svc);
}
}
}
+19 -8
View File
@@ -90,8 +90,11 @@ typedef struct svc {
/* Service details */
pid_t pid;
char pidfile[MAX_ARG_LEN];
long start_time; /* Start time, as seconds since boot, from sysinfo() */
const svc_state_t state; /* Paused, Reloading, Restart, Running, ... */
svc_type_t type; /* Service, run, task, inetd, ... */
int protected; /* Services like dbus-daemon & udev by Finit */
const int dirty; /* -1: removal, 0: unmodified, 1: modified */
int starting; /* ... waiting for pidfile to be re-asserted */
int runlevels;
@@ -108,7 +111,13 @@ typedef struct svc {
int stdin_fd;
/* Set for services we need to redirect stdout/stderr to syslog */
int log;
struct {
char enabled;
char null;
char file[64];
char prio[20];
char ident[20];
} log;
/* Identity */
char username[MAX_USER_LEN];
@@ -134,14 +143,15 @@ svc_t *svc_find (char *cmd, int id);
svc_t *svc_find_by_pid (pid_t pid);
svc_t *svc_find_by_jobid (int job, int id);
svc_t *svc_find_by_nameid (char *name, int id);
svc_t *svc_find_by_pidfile (char *fn);
svc_t *svc_iterator (svc_t **iter, int first);
svc_t *svc_inetd_iterator (svc_t **iter, int first);
svc_t *svc_named_iterator (svc_t **iter, int first, char *cmd);
svc_t *svc_job_iterator (svc_t **iter, int first, int job);
void svc_foreach (void (*cb)(svc_t *));
void svc_foreach_type (int types, void (*cb)(svc_t *));
void svc_foreach (int (*cb)(svc_t *));
void svc_foreach_type (int types, int (*cb)(svc_t *));
svc_t *svc_stop_completed (void);
@@ -158,8 +168,14 @@ int svc_is_unique (svc_t *svc);
int svc_parse_jobstr (char *str, size_t len, int (*found)(svc_t *), int (not_found)(char *, int));
static inline int svc_is_inetd (svc_t *svc) { return svc && SVC_TYPE_INETD == svc->type; }
static inline int svc_is_inetd_conn(svc_t *svc) { return svc && SVC_TYPE_INETD_CONN == svc->type; }
static inline int svc_is_daemon (svc_t *svc) { return svc && SVC_TYPE_SERVICE == svc->type; }
static inline int svc_is_runtask (svc_t *svc) { return svc && (SVC_TYPE_RUNTASK & svc->type); }
static inline int svc_in_runlevel (svc_t *svc, int runlevel) { return svc && ISSET(svc->runlevels, runlevel); }
static inline int svc_has_sighup (svc_t *svc) { return svc && 0 != svc->sighup; }
static inline int svc_has_pidfile (svc_t *svc) { return svc_is_daemon(svc) && svc->pidfile[0] != 0 && svc->pidfile[0] != '!'; }
static inline void svc_starting (svc_t *svc) { svc->starting = 1; }
static inline void svc_started (svc_t *svc) { svc->starting = 0; }
@@ -169,11 +185,6 @@ static inline int svc_is_removed (svc_t *svc) { return svc && -1 == svc->dirty
static inline int svc_is_changed (svc_t *svc) { return svc && 0 != svc->dirty; }
static inline int svc_is_updated (svc_t *svc) { return svc && 1 == svc->dirty; }
static inline int svc_is_inetd (svc_t *svc) { return svc && SVC_TYPE_INETD == svc->type; }
static inline int svc_is_inetd_conn(svc_t *svc) { return svc && SVC_TYPE_INETD_CONN == svc->type; }
static inline int svc_is_daemon (svc_t *svc) { return svc && SVC_TYPE_SERVICE == svc->type; }
static inline int svc_is_runtask (svc_t *svc) { return svc && (SVC_TYPE_RUNTASK & svc->type); }
static inline int svc_is_blocked (svc_t *svc) { return svc->block != SVC_BLOCK_NONE; }
static inline int svc_is_busy (svc_t *svc) { return svc->block == SVC_BLOCK_BUSY; }
static inline void svc_unblock (svc_t *svc) { svc->block = SVC_BLOCK_NONE; }
+9 -1
View File
@@ -137,7 +137,7 @@ void tty_sweep(void)
int tty_register(char *line, struct rlimit rlimit[], char *file)
{
tty_node_t *entry;
int insert = 0, noclear = 0, nowait = 0;
int insert = 0, noclear = 0, nowait = 0, nologin = 0;
size_t i, num = 0;
char *tok, *cmd = NULL, *args[TTY_MAX_ARGS];
char *dev = NULL, *baud = NULL;
@@ -159,6 +159,8 @@ int tty_register(char *line, struct rlimit rlimit[], char *file)
noclear = 1;
else if (!strcmp(tok, "nowait"))
nowait = 1;
else if (!strcmp(tok, "nologin"))
nologin = 1;
else
args[num++] = tok;
@@ -241,6 +243,7 @@ int tty_register(char *line, struct rlimit rlimit[], char *file)
entry->data.term = term ? strdup(term) : NULL;
entry->data.noclear = noclear;
entry->data.nowait = nowait;
entry->data.nologin = nologin;
entry->data.runlevels = conf_parse_runlevels(runlevels);
/* External getty */
@@ -392,6 +395,11 @@ void tty_start(finit_tty_t *tty)
return;
}
if (tty->nologin) {
tty->pid = run_sh(dev, tty->noclear, tty->nowait, tty->rlimit);
return;
}
if (!tty->cmd)
tty->pid = run_getty(dev, tty->baud, tty->term, tty->noclear, tty->nowait, tty->rlimit);
else
+1
View File
@@ -38,6 +38,7 @@ typedef struct {
char *term;
int noclear;
int nowait;
int nologin;
int runlevels;
char *cmd; /* NULL when running built-in getty */
+98
View File
@@ -23,8 +23,12 @@
#include "config.h"
#include <ctype.h> /* isprint() */
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/sysinfo.h> /* sysinfo() */
#include <lite/lite.h> /* strlcat() */
#include "util.h"
int screen_rows = 24;
@@ -42,12 +46,92 @@ char *progname(char *arg0)
return prognm;
}
int strtobytes(char *arg)
{
int mod = 0, bytes;
size_t pos;
if (!arg)
return -1;
pos = strspn(arg, "0123456789");
if (arg[pos] != 0) {
if (arg[pos] == 'G')
mod = 3;
else if (arg[pos] == 'M')
mod = 2;
else if (arg[pos] == 'k')
mod = 1;
else
return -1;
arg[pos] = 0;
}
bytes = atoi(arg);
while (mod--)
bytes *= 1000;
return bytes;
}
void do_sleep(unsigned int sec)
{
while ((sec = sleep(sec)))
;
}
/* Seconds since boot, from sysinfo() */
long jiffies(void)
{
struct sysinfo si;
if (!sysinfo(&si))
return si.uptime;
return 0;
}
char *uptime(long secs, char *buf, size_t len)
{
long mins, hours, days, years;
char y[20] = "", d[20] = "", h[20] = "", m[20] = "", s[20] = "";
if (!buf) {
errno = EINVAL;
return NULL;
}
years = secs / 31556926;
secs = secs % 31556926;
days = secs / 86400;
secs = secs % 86400;
hours = secs / 3600;
secs = secs % 3600;
mins = secs / 60;
secs = secs % 60;
if (years)
snprintf(y, sizeof(y), "%ld year", years);
if (days)
snprintf(d, sizeof(d), "%ld day", days);
if (hours)
snprintf(h, sizeof(h), "%ld hour", hours);
if (mins)
snprintf(m, sizeof(m), "%ld min", mins);
if (secs)
snprintf(s, sizeof(s), "%ld sec", secs);
snprintf(buf, len, "%s%s%s%s%s%s%s%s%s",
y, years ? " " : "",
d, days ? " " : "",
h, hours ? " " : "",
m, mins ? " " : "",
s);
return buf;
}
/* Allowed characters in job/id/name */
static int isallowed(int ch)
{
@@ -73,6 +157,10 @@ char *sanitize(char *arg, size_t len)
return NULL;
}
/*
* Called at boot, and shutdown, to (re)initialize the
* screen size for print() et al.
*/
void screen_init(void)
{
if (!isatty(STDOUT_FILENO))
@@ -81,6 +169,16 @@ void screen_init(void)
initscr(&screen_rows, &screen_cols);
}
/*
* Called when debug mode is enabled to revert back
* to old-school safe defaults.
*/
void screen_exit(void)
{
screen_rows = 24;
screen_cols = 80;
}
/**
* Local Variables:
* indent-tabs-mode: t
+6
View File
@@ -39,10 +39,16 @@ extern char *prognm;
#include <lite/conio.h>
char *progname (char *arg0);
int strtobytes (char *arg);
void do_sleep (unsigned int sec);
long jiffies (void);
char *uptime (long secs, char *buf, size_t len);
char *sanitize (char *arg, size_t len);
void screen_init (void);
void screen_exit (void);
int screen_width (void);
#endif /* FINIT_UTIL_H_ */
+25 -6
View File
@@ -31,15 +31,19 @@
int running = 1;
int handover = 0;
int shutdown = 0;
static void sighandler(int signo)
{
if (signo == SIGTERM)
handover = 1;
if (signo == SIGPWR)
shutdown = 1;
running = 0;
}
static int init(char *progname, char *devnode, int timeout)
static int init(char *progname, char *devnode)
{
int fd;
@@ -51,20 +55,28 @@ static int init(char *progname, char *devnode, int timeout)
if (fd == -1)
return -1;
ioctl(fd, WDIOC_SETTIMEOUT, &timeout);
return fd;
}
static int loop(int fd, int period)
static int loop(int fd, int timeout)
{
int dummy = 0;
int period = timeout / 2;
ioctl(fd, WDIOC_SETTIMEOUT, &timeout);
while (running) {
ioctl(fd, WDIOC_KEEPALIVE, &dummy);
sleep(period);
}
/* System is going down, prepare to reboot system on TERM */
if (shutdown) {
timeout /= 3;
ioctl(fd, WDIOC_SETTIMEOUT, &timeout);
}
/* External watchdogd wants to take over ... */
if (handover) {
ioctl(fd, WDIOC_KEEPALIVE, &dummy);
return !write(fd, "V", 1);
@@ -81,13 +93,20 @@ int watchdog(char *progname)
if (pid == 0) {
int fd, ret;
fd = init(progname, WDT_DEVNODE, WDT_TIMEOUT);
fd = init(progname, WDT_DEVNODE);
if (fd == -1) {
_pe("Failed connecting to watchdog %s", WDT_DEVNODE);
_exit(1);
}
ret = loop(fd, WDT_TIMEOUT / 2);
ret = loop(fd, WDT_TIMEOUT);
while (!handover) {
/* Waiting for SIGTERM ... */
sleep(1);
/* Set lowest possible timeout on SIGTERM */
ioctl(fd, WDIOC_SETTIMEOUT, &shutdown);
}
close(fd);
_exit(ret);