Compare commits

..
69 Commits
Author SHA1 Message Date
Joachim Nilsson aa8d6a7294 Bump version for 1.10 release.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-11-27 22:33:24 +01:00
Joachim Nilsson a94dde403f Update NEWS to Markdown syntax and add info on next release.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-11-27 09:42:49 +01:00
Joachim Nilsson 9bb7e7b014 Change NEWS documentation from reST to Markdown
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-11-27 09:19:33 +01:00
Joachim Nilsson 02a97e8d7d Fix various problems with unchecked return values from syscalls.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-11-27 00:12:07 +01:00
Joachim Nilsson def759fe41 run_interactive(): Fix a potential file descriptor leak.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-11-26 23:45:20 +01:00
Joachim Nilsson 939cfc2476 pidfile_read(): Reindent.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-11-26 23:44:00 +01:00
Joachim Nilsson 7f2c73468f libite/rsync.c: Fix build regression from previous commit.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-11-26 23:37:04 +01:00
Joachim Nilsson 81a368f710 Fix problem with unchecked return value of mkdir(), wrap in makedir() macro.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-11-26 23:27:15 +01:00
Joachim Nilsson 4e975e4974 plugin.c:load_one() - Comment on resource leak, we never unload plugins atm.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-11-26 23:24:49 +01:00
Joachim Nilsson a296c2dd00 pidfile_read(): Fix potential integer overflow when reading PID
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-11-26 23:02:54 +01:00
Joachim Nilsson 5ff7994852 touch(): Check return value of mknod(), report error if errno != EEXIST.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-11-26 22:57:23 +01:00
Joachim Nilsson 1bdcef9a2c run_interactive(): Fix file descriptor leak when debug is enabled.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-11-26 22:49:31 +01:00
Joachim Nilsson f621117eb9 README: Update section on plugins with info on hooks and I/O plugins.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-11-26 18:48:25 +01:00
Joachim Nilsson 83cec7129a run_interactive(): Fix copy-paste bug introduced in 06b33c5.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-11-26 17:58:50 +01:00
Joachim Nilsson 06b33c58fd run_interactive(): Fix descriptor leak.
Make sure to close dup()'ed descriptors when we're done with them.
Thanks to Coverity Scan for finding this nasty one!

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-11-26 17:30:58 +01:00
Joachim Nilsson 8ce39f592c procname_kill(): Fix possible resource leak and let's use opendir() errno
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-11-26 17:22:55 +01:00
Joachim Nilsson d37c451e81 svc_start(): Fix out of bounds write to args[] array.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-11-26 17:20:27 +01:00
Joachim Nilsson a7ff1a61d5 svc_start(): Fix swapped arguments to dup2() and add close(fd), descriptor leak.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-11-26 17:17:47 +01:00
Joachim Nilsson 8349909f60 helpers.c:run_interactive() - Check arguments and return values better.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-11-26 17:08:00 +01:00
Joachim Nilsson 3a2cf30f47 README: Minor touch up.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-11-26 16:41:04 +01:00
Joachim Nilsson 9a3cab3645 TODO: Remove finished items now documented in README
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-11-26 16:40:43 +01:00
Joachim Nilsson 7dbc02f879 Standardize on two-space indented * for bullet lists in Markdown
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-11-26 16:13:53 +01:00
Joachim Nilsson a39f75744c Update TODO to Markdown syntax.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-11-26 16:08:59 +01:00
Joachim Nilsson 5742c6591a Change TODO documentation from reST to Markdown
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-11-26 15:59:34 +01:00
Joachim Nilsson 588901ee4c Update README to Markdown syntax.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-11-26 15:56:50 +01:00
Joachim Nilsson e30d2aae19 Change documentation from reST to Markdown
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-11-26 15:55:33 +01:00
Joachim Nilsson 463e4f12f8 Update Coverity URL and add section on hooks, plugins & callbacks.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-11-24 18:21:47 +01:00
Joachim Nilsson 01c2817005 Add support for Coverity Scan
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-11-24 13:49:18 +01:00
Joachim Nilsson 1a16aab970 queue.h: Upgrade to a newer slightly bugfiex version of OpenBSD queue.h
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-11-03 20:56:11 +01:00
Joachim Nilsson 8247344f0d helpers.c:set_hostname() - Fix resource and memory leaks.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-10-31 15:26:49 +01:00
Joachim Nilsson 2fdd64a2d8 helpers.c:run() - Fix resource and memory leaks.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-10-31 15:16:00 +01:00
Joachim Nilsson 22ed4e7f73 svc.c - Break out nested function.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-10-31 14:58:13 +01:00
Joachim Nilsson 327ac9f931 libite:rsync.c - Break out nested function.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-10-31 14:56:51 +01:00
Joachim Nilsson 5ad0c38fe8 Sanity check plugpath as well, no point in searching for plugins otherwise.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-10-30 22:11:23 +01:00
Joachim Nilsson 757911f149 Bump version for release and update copyright years.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-04-21 16:03:54 +02:00
Joachim Nilsson 35b771fb42 Add empty space for formatting.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-04-21 15:51:33 +02:00
Joachim Nilsson 720f1b0e5b Strip output when loading .conf files.
If not standard finit.conf, then we want to show just the base name.
E.g., loading first /etc/finit.conf then /etc/finit.d/services.conf

Loading configuration ............. vs
Loading services configuration ....

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-04-21 15:46:09 +02:00
Joachim Nilsson 292a3be515 lite.h: Add some helper string comparison methods.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-04-21 15:45:23 +02:00
Joachim Nilsson 5ed407e493 helpers.c: Fix mix of off-by-one errors in new print() code.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-04-21 14:09:23 +02:00
Joachim Nilsson 40988b901c Unify print_desc() & print_result() in print() and refactor ...
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-04-21 14:05:56 +02:00
Joachim Nilsson 26d49b2027 Yet another minor bugfix to new include function.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-04-21 12:05:55 +02:00
Joachim Nilsson 10386ee4de Bug fix and document new include <CONF> syntax.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-04-21 12:03:10 +02:00
Joachim Nilsson 773d2e65d6 README: Update docs on extended syntax and behavior for tty setting
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-04-21 11:17:31 +02:00
Joachim Nilsson 3e29d883fa tty.c:tty_start() - Fix strcmp() foobar from f6f2895, must use strncmp()
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-04-21 11:08:34 +02:00
Joachim Nilsson f6f2895524 Add support for a fallback shell if no tty is setup
Try to do better by the user, by default, if no tty is specified in the
finit.conf.  This way the user will at least have a way to interact with
the system and repair it.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-04-19 22:58:20 +02:00
Joachim Nilsson 62287f8fcc Add support for including .conf files.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-04-19 22:56:19 +02:00
Joachim Nilsson be3257f805 print_desc() - Allow arguments to be NULL.
Signed-off-by: Joachim Nilsson <joachim.nilsson@westermo.se>
2014-04-19 22:25:56 +02:00
Joachim Nilsson 1bf3aa528a Fix duplicate link and cleanup contact section.
Signed-off-by: Joachim Nilsson <joachim.nilsson@westermo.se>
2014-04-19 19:31:00 +02:00
Joachim Nilsson 056236c9f8 Freshen up README, TODO, and .conf example, spell check.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-04-19 19:19:57 +02:00
Joachim Nilsson 71fff76111 svc.[ch]: Fix possible out of bounds and NULL ptr deref
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-04-12 16:41:20 +02:00
Joachim Nilsson 1095724e5c libite: Fix cppcheck warnings in rsync unit test
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-04-12 16:34:57 +02:00
Joachim Nilsson e81c2f2f90 libite: Minor style cleanup of fsendfile()
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-04-12 16:21:41 +02:00
Joachim Nilsson 9f91b4c050 libite: Simplify and fix another memleak in copyfile()
- Simplify: reduce indentation depth
- Always check for error condition first, cleaner code
- Make sure buffer is always freed, use same exit everyhere
- Use readable, but still short, local variable names

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-04-12 16:11:59 +02:00
Joachim Nilsson 7ada824e3e Makefile: Add support for make check to run cppcheck
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-04-12 16:08:30 +02:00
Joachim Nilsson 7cf7591f0a run_getty(): Handle STDIO descriptors better.
The cppcheck tool raised an alert to the missing close() for
stdin when a console is opened for a getty.  This patch fixes
that warning and also makes the code slighlty more readable.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-04-12 15:15:43 +02:00
Joachim Nilsson 143a257c25 libite: Copy utility fixes and new functionality
- Add support for symlinks to copyfile()
- Fix memory leak in copy_filep()
- New function, fsendfile(), copy data between FILE streams

Also, minor whitespace and coding style cleanup.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-04-12 15:08:56 +02:00
Joachim Nilsson 1d98647c54 Add missing include for system header file
Only affects externally built plugins.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-04-12 14:31:31 +02:00
Joachim Nilsson 7cd52b36a1 Always print service start/stop at start of line
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-04-12 14:30:34 +02:00
Joachim Nilsson b033052647 TODO: Further simplify example inetd syntax.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-04-10 10:34:06 +02:00
Joachim Nilsson 4fcf2533a6 Minor indentation fix to TODO.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-04-10 10:29:06 +02:00
Joachim Nilsson a8a103a521 Update TODO with inetd proposal, and minor README cleanup.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-04-10 10:26:46 +02:00
Joachim Nilsson 12b09bb80b Improve CI status integration in README and minor cleanup.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-02-25 09:23:16 +01:00
Joachim Nilsson 49aaffcf9a Update README with CI status. 2014-02-25 00:00:43 +01:00
Joachim Nilsson afbe628f17 Travis CI integration
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-02-24 23:46:28 +01:00
Joachim Nilsson 1d6cbe31fe Initial support for restarting lost processes during norespawn
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-02-24 23:33:38 +01:00
Jonas Johansson cb874d7a94 Handle SIGHUP requst from service when switching runlevel
Signed-off-by: Jonas Johansson <jonasj76@gmail.com>
2014-02-24 23:33:38 +01:00
Joachim Nilsson d7598ca672 Update URL of example to new download FTP. 2013-06-08 15:37:31 +02:00
Joachim Nilsson ff8e494abd Update README with a slightly more clear and catchy intro. 2013-06-08 14:49:28 +02:00
Joachim Nilsson dfaa6dd3f8 Minor ReST syntax fix for improved display in GitHub
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-06-08 11:23:24 +02:00
36 changed files with 1499 additions and 954 deletions
+21
View File
@@ -0,0 +1,21 @@
# Travis CI integration -- https://travis-ci.org/troglobit/finit
language: c
compiler:
- gcc
env:
global:
# The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
# via the "travis encrypt" command using the project repo's public key
- secure: "eOiuHs02lG2Uv146K9dMqucGTWUJFEhpz1oAtwe+kPrRXsXWc20hYMO+DSpMgD05vSvNeQA6p7h7LdRFQ+/g/Obj27TsOE+RKkUvRAtdwzxnKVyii9C/nmML8cFw7rIA0VS8O9mAkVYeyDxNDupBp3e9DPCibhKPvqCvioTnyy4="
addons:
coverity_scan:
project:
name: "troglobit/finit"
description: "finit | Fast Init Replacement"
notification_email: troglobit@gmail.com
build_command: "make"
branch_pattern: master
script: make
+1 -1
View File
@@ -1,5 +1,5 @@
Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com> Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
Copyright (c) 2008-2012 Joachim Nilsson <troglobit@gmail.com> Copyright (c) 2008-2014 Joachim Nilsson <troglobit@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
+5 -2
View File
@@ -1,7 +1,7 @@
# Finit - Extremely fast /sbin/init replacement w/ I/O, hook & service plugins # Finit - Extremely fast /sbin/init replacement w/ I/O, hook & service plugins
# #
# Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com> # Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
# Copyright (c) 2008-2012 Joachim Nilsson <troglobit@gmail.com> # Copyright (c) 2008-2014 Joachim Nilsson <troglobit@gmail.com>
# #
# Permission is hereby granted, free of charge, to any person obtaining a copy # Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal # of this software and associated documentation files (the "Software"), to deal
@@ -26,7 +26,7 @@
uninstall-exec uninstall-data uninstall-dev uninstall-exec uninstall-data uninstall-dev
#VERSION ?= $(shell git tag -l | tail -1) #VERSION ?= $(shell git tag -l | tail -1)
VERSION ?= 1.8 VERSION ?= 1.10
NAME = finit NAME = finit
PKG = $(NAME)-$(VERSION) PKG = $(NAME)-$(VERSION)
DEV = $(NAME)-dev DEV = $(NAME)-dev
@@ -141,6 +141,9 @@ distclean: clean
$(MAKE) -C libite $@ $(MAKE) -C libite $@
$(MAKE) -C plugins $@ $(MAKE) -C plugins $@
check:
$(CHECK) *.c plugins/*.c libite/*.c
dist: dist:
@echo "Building xz tarball of $(PKG) in parent dir..." @echo "Building xz tarball of $(PKG) in parent dir..."
git archive --format=tar --prefix=$(PKG)/ $(VERSION) | xz >../$(ARCHIVE) git archive --format=tar --prefix=$(PKG)/ $(VERSION) | xz >../$(ARCHIVE)
+1 -1
View File
@@ -1 +1 @@
NEWS.rst NEWS.md
+206
View File
@@ -0,0 +1,206 @@
NEWS
====
1.10 (2014-11-27)
-----------------
Major bug fix release.
* Project now relies on static code analysis from Coverity, so this
release contains many serious bug fixes.
* Fix serious file descriptor and memory leaks in the following
functions. In particular the leaks in `run_interactive()` are very
serious since that function is called every time a service is
started and/or restarted! For details, see the GIT log:
* `helpers.c:run()`
* `helpers.c:run_interactive()`
* `helpers.c:set_hostname()`
* `helpers.c:procname_kill()`
* `svc.c:svc_start()`: Fix swapped arguments to dup2() and add
close(fd) to prevent descriptor leak.
* `svc.c:svc_start()`: Fix out of bounds write to local stack
variable, wrote off-by-one outside array.
* Several added checks for return values to `mknod()`, `mkdir()`,
`remove()`, etc.
* Convert to use Markdown for README, NEWS and TODO.
* Serious update to README and slight pruning of finished TODO items.
1.9 (2014-04-21)
----------------
* Bug fixes, code cleanup
* Add support for an include directive to `.conf` files
* Fallback to `/bin/sh` if user forgets tty setting
* Handle `SIGHUP` from service callback properly when switching runlevel
* Initial support for restarting lost services during `norespwan`
* Misc. major (memleak) and minor fixes and additions to `libite/lite.h`
1.8 (2013-06-07)
----------------
* Support for runlevels, with a bootstrap runlevel 'S'
* Support for saving previous and current runlevel to UTMP
* Support for new `finit.conf` commands: run, task, and runlevel
* Support for tty and console commands in `finit.conf`, like services
but for launching multiple getty logins
* New tty plugin to monitor TTYs coming and going, like USB TTYs
* Bugfixes to libite
1.7 (2012-10-08)
----------------
* Show `__FILE__` in `_d()` debug messages, useful for plugins with
similarily named callbacks. Also, only in debug mode anyway
* Make sure to cleanup recorded PID when a service is lost. Required
by service plugins for their callbacks to work.
* Bugfix: Do not `free()` static string in `finit.conf` parser
* Only clear screen when in verbose mode. Maybe this should be removed
altogether?
1.6 (2012-10-06)
----------------
* Skip . and .. in plugin loader and display error on failed plugins
* Support for overriding `/etc/finit.d` with `runparts DIR` in
`finit.conf`
* Revoke support for starting services not starting with a slash.
* Prevent endless restart of non-existing services in `finit.conf`
* Support for sysvinit style startstop scripts in `/etc/finit.d`
* Minor fix to alsa-utils plugin to silence on non-existing cards
1.5 (2012-10-03)
----------------
* Use bootmisc plugin to setup standard FHS 2.3 structure in `/var`
* Added `FLOG_WARN()` syslog macro, for plugins
* Add plugin dependency resolver. Checks `plugin_t` for `.depends`
1.4 (2012-10-02)
----------------
* Fix I/O plugin watcher and load plugins earlier for a new hook
* Start refactoring helpers.c into a libite.so (-lite). This means
other user space applications/daemons can make use of the neat toolbox
available in finit
* Use short-form -s/-w -u to work with BusyBox hwclock as well
* Use RTLD_GLOBAL flag to tell dynamic loader to load dependent .so
files as well. Lets other plugins use global symbols.
* Greatly simplify svc hook for external plugins and cleanup plugin API.
* And more ... see the GIT log for more details.
1.3 (2012-09-28)
----------------
* Cleanup public plugin API a bit and add new pid/pidfile funcs
* Add plugin hook to end of service startup
* Remove finit.h from svc.h, plugins should not need this.
* Move utility macros etc. to helpers.h
* Make `finit.h` daemon internal, only
* Move defines of FIFO, conf and rcS.d to Makefile => correct paths
* Add support for installing required headers in system include dir
* Better support for distributions and packagers with install-exec,
install-data, and install-dev targets in Makefile. Useful if you want
to call targets with different `$DESTDIR`!
* Makefile fixes for installation, paths encoded wrong
* Strip binaries + .so files, support for `$(CROSS)` toolchain strip
* Default install is now to `/sbin/finit` and `/usr/`
* Note change in `$PLUGIN_DIR` environemnt variable to `$plugindir`
1.2 (2012-09-27)
----------------
* Fix installation paths encoded in finit binary
* Update README with section on building and enviroment variables
1.1 (2012-09-27)
----------------
* Build fixes for ARM eabi/uClibc
* Rename signal.[ch]-->sig.[ch] to avoid name clash w/ system headers
1.0 (2012-09-26)
----------------
* New plugin based system for all odd extensions
* New service monitor that restarts services if they die
* New maintainer at GitHub http://github.com/troglobit/finit
* Add standard LICENSE and AUTHORS files
* New focus: embedded systems and small headless servers
0.6 (2010-06-14)
----------------
* don't start consolekit manually, dbus starts it (rtp)
* unmount all filesystems before rebooting
* disable `USE_VAR_RUN_RESOLVCONF` for Mandriva
* unset terminal type in Mandriva before running X
* remove extra sleep in finit-alt before calling services.sh (caio)
0.5 (2008-08-21)
----------------
* add option to start dbus and consolekit before the X server
* finit-alt listens to `/dev/initctl` to work with `reboot(8)` (smurfy)
* write runlevel to utmp, needed by Printerdrake (Pascal Terjan)
* fix ownership of `/var/run/utmp` (reported by Pascal Terjan)
* remove obsolete code to load AGP drivers
* conditional build of `/etc/resolveconf/run` support
* add support to `/var/run/resolvconf` in Mandriva (blino)
O.4 (2008-05-16)
----------------
* default username for finit-alt configurable in Makefile
* create loopback device node in finit-alt (for squashfs)
* add option to use built-in run-parts instead of `/bin/run-parts`
* ignore signal instead of setting to an empty handler (Metalshark)
* handle pam_console permissions in finit-alt for Mandriva
* add services.sh example and nash-hotplug patch for Mandriva
* mount `/proc/bus/usb` in Mandriva
* add runtime debug to finit-alt if finit_debug parameter is specified
* read configuration from `/etc/finit.conf`
* run getty with openvt on the virtual terminal
0.3 (2008-02-23)
----------------
* Change poweroff method to `reboot(RB_POWER_OFF)` (Metalshark)
* Remove duplicate `unionctl()` reimplementation error
* Fix string termination in path creation
* Mount `/var/lock` and `/var/run` as tmpfs
0.2 (2008-02-19)
----------------
* replace` system("touch")` with `touch()` in finit-mod (Metalshark)
* disable `NO_HCTOSYS` by default to match stock Eeepc kernel
* drop `system("rm -f")` to clean `/tmp`, its a fresh mounted tmpfs
* write ACPI sleep state to `/sys/power/state` instead of
`/proc/acpi/sleep` (Metalshark)
* use direct calls to set loopback instead of `system("ifconfig")`
* replace `system("cat")` and `system("dd")` with C implementation
* moved finit-mod and finit-alt helpers to `helpers.c`
* replace `system("echo;cat")` to draw shutdown splash with C calls
0.1 (2008-02-14)
----------------
* initial release
-159
View File
@@ -1,159 +0,0 @@
==============================================================================
NEWS
==============================================================================
1.8 (2013-06-07)
----------------
* Support for runlevels, with a bootstrap runlevel 'S'
* Support for saving previous and current runlevel to UTMP
* Support for new finit.conf commands: run, task, and runlevel
* Support for tty and console commands in finit.conf, like services but
for launching multiple getty logins
* New tty plugin to monitor TTYs coming and going, like USB TTYs
* Bugfixes to libite
1.7 (2012-10-08)
----------------
* Show __FILE__ in _d() debug messages, useful for plugins with
similarily named callbacks. Also, only in debug mode anyway
* Make sure to cleanup recorded PID when a service is lost. Required by
service plugins for their callbacks to work.
* Bugfix: Do not free() static string in finit.conf parser
* Only clear screen when in verbose mode. Maybe this should be removed
altogether?
1.6 (2012-10-06)
----------------
* Skip . and .. in plugin loader and display error on failed plugins
* Support for overriding /etc/finit.d with "runparts DIR" in finit.conf
* Revoke support for starting services not starting with a slash.
* Prevent endless restart of non-existing services in finit.conf
* Support for sysvinit style startstop scripts in /etc/finit.d
* Minor fix to alsa-utils plugin to silence on non-existing cards
1.5 (2012-10-03)
----------------
* Use bootmisc plugin to setup standard FHS 2.3 structure in /var
* Added FLOG_WARN() syslog macro, for plugins
* Add plugin dependency resolver. Checks plugin_t for .depends
1.4 (2012-10-02)
----------------
* Fix I/O plugin watcher and load plugins earlier for a new hook
* Start refactoring helpers.c into a libite.so (-lite). This means
other user space applications/daemons can make use of the neat toolbox
available in finit
* Use short-form -s/-w -u to work with BusyBox hwclock as well
* Use RTLD_GLOBAL flag to tell dynamic loader to load dependent .so
files as well. Lets other plugins use global symbols.
* Greatly simplify svc hook for external plugins and cleanup plugin API.
* And more... see the GIT log for more details.
1.3 (2012-09-28)
----------------
* Cleanup public plugin API a bit and add new pid/pidfile funcs
* Add plugin hook to end of service startup
* Remove finit.h from svc.h, plugins should not need this.
* Move utility macros etc. to helpers.h
* Make finit.h daemon internal, only
* Move defines of FIFO, conf and rcS.d to Makefile => correct paths
* Add support for installing required headers in system include dir
* Better support for distributions and packagers with install-exec,
install-data, and install-dev targets in Makefile. Useful if you want
to call targets with different $DESTDIR!
* Makefile fixes for installation, paths encoded wrong
* Strip binaries + .so files, support for $(CROSS) toolchain strip
* Default install is now to /sbin/finit and /usr/
* Note change in $PLUGIN_DIR environemnt variable to $plugindir
1.2 (2012-09-27)
----------------
* Fix installation paths encoded in finit binary
* Update README with section on building and enviroment variables
1.1 (2012-09-27)
----------------
* Build fixes for ARM eabi/uClibc
* Rename signal.[ch]-->sig.[ch] to avoid name clash w/ system headers
1.0 (2012-09-26)
----------------
* New plugin based system for all odd extensions
* New service monitor that restarts services if they die
* New maintainer at GitHub http://github.com/troglobit/finit
* Add standard LICENSE and AUTHORS files
* New focus: embedded systems and small headless servers
0.6 (2010-06-14)
----------------
* don't start consolekit manually, dbus starts it (rtp)
* unmount all filesystems before rebooting
* disable USE_VAR_RUN_RESOLVCONF for Mandriva
* unset terminal type in Mandriva before running X
* remove extra sleep in finit-alt before calling services.sh (caio)
0.5 (2008-08-21)
----------------
* add option to start dbus and consolekit before the X server
* finit-alt listens to /dev/initctl to work with reboot(8) (smurfy)
* write runlevel to utmp, needed by Printerdrake (Pascal Terjan)
* fix ownership of /var/run/utmp (reported by Pascal Terjan)
* remove obsolete code to load AGP drivers
* conditional build of /etc/resolveconf/run support
* add support to /var/run/resolvconf in Mandriva (blino)
O.4 (2008-05-16)
----------------
* default username for finit-alt configurable in Makefile
* create loopback device node in finit-alt (for squashfs)
* add option to use built-in run-parts instead of /bin/run-parts
* ignore signal instead of setting to an empty handler (Metalshark)
* handle pam_console permissions in finit-alt for Mandriva
* add services.sh example and nash-hotplug patch for Mandriva
* mount /proc/bus/usb in Mandriva
* add runtime debug to finit-alt if finit_debug parameter is specified
* read configuration from /etc/finit.conf
* run getty with openvt on the virtual terminal
0.3 (2008-02-23)
----------------
* Change poweroff method to reboot(RB_POWER_OFF) (Metalshark)
* Remove duplicate unionctl() reimplementation error
* Fix string termination in path creation
* Mount /var/lock and /var/run as tmpfs
0.2 (2008-02-19)
----------------
* replace system("touch") with touch() in finit-mod (Metalshark)
* disable NO_HCTOSYS by default to match stock Eeepc kernel
* drop system("rm -f") to clean /tmp, its a fresh mounted tmpfs
* write ACPI sleep state to /sys/power/state instead of /proc/acpi/sleep
(Metalshark)
* use direct calls to set loopback instead of system("ifconfig")
* replace system("cat") and system("dd") with C implementation
* moved finit-mod and finit-alt helpers to helpers.c
* replace system("echo;cat") to draw shutdown splash with C calls
0.1 (2008-02-14)
----------------
* initial release
.. Local Variables:
.. mode: rst
.. version-control: t
.. End:
+1 -1
View File
@@ -1 +1 @@
README.rst README.md
+390
View File
@@ -0,0 +1,390 @@
README
======
[![Build Status](https://travis-ci.org/troglobit/finit.png?branch=master)](https://travis-ci.org/troglobit/finit)
[![Coverity Scan Status](https://scan.coverity.com/projects/3545/badge.svg)](https://scan.coverity.com/projects/3545)
Init is the first process to run once a UNIX kernel has booted, it
always has PID 1 and is responsible for starting up the rest of the
system. Finit is a very small plugin based init with built in
[process supervision](https://en.wikipedia.org/wiki/Process_supervision)
similar to that of D.J. Bernstein's
[daemontools](http://cr.yp.to/daemontools.html) and Gerrit Pape's
[runit](http://smarden.org/runit/). Its focus is on small and embedded
GNU/Linux systems, although fully functional on standard server and
desktop installations.
Finit is fast because it is "scripted" with C and starts services in
parallel. Services are supervised and automatically restarted if they
fail. Services can have callbacks that are called before a service is
(re)started. For instance, before attempting to start a heavily
resource intensive service like IPsec or OpenVPN, a callback can check
if the outbound interface is up and has an IP address, or just check if
the service is disabled -- much like what a SysV init start script
usually does.
To extend finit with new functionality, hooks can be added at certain
points in the boot process that execute in sequence, which is useful for
certain satisfying preconditions or for synchronization purposes. One
can also create plugins to functionality to suit your own needs, the
initctl compatibility plugin that comes with finit is one such plugin.
Finit is not only fast, it's arguably one of the easiest to get started
with. A complete system can be booted with one simple configuration
file, `/etc/finit.conf`, see below for syntax.
Features
--------
**Process Supervision**
Start, monitor and restart services if they fail.
**Runlevels**
Finit supports standard runlevels if you want, but you don't need them
for simple installations.
**Plugins**
Extend and modify finit behavior. See examples in plugins/ directory.
Plugin capabilities:
* Service callbacks — modify service arguments, run/restart/stop
* Task/Run callbacks — a one-shot commands, executed in sequence
* Hooks — hook into the boot at predefined points to extend finit
* I/O — listen to external events and control finit behavior/services
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.
/etc/finit.conf
---------------
Contrary to most other script based init alternatives
([SysV init](https://en.wikipedia.org/wiki/Init),
[upstart](http://upstart.ubuntu.com/),
[systemd](http://www.freedesktop.org/wiki/Software/systemd/),
[OpenRC](http://www.gentoo.org/proj/en/base/openrc/) and the likes)
finit reads its configuration from `/etc/finit.conf`. Syntax:
* `check <DEV>`
Run fsck on a file system before mounting it
* `module <MODULE>`
Load a kernel module, with optional arguments
* `network <PATH>`
Script or program to bring up networking, with optional arguments
* `runlevel <N>`
N is the runlevel number 1-9, where 6 is reserved for reboot.
Default is 2.
* `run [LVLS] /path/to/cmd ARGS -- Optional description`
One-shot command to run in sequence when entering a runlevel, with
optional arguments and description. This command is guaranteed to
be completed before running the next command.
* `task LVLS] /path/to/cmd ARGS -- Optional description`
One-shot like 'run', but starts in parallel with the next command
* `service [LVLS] /path/to/daemon ARGS -- Optional description`
Service, or daemon, to be monitored and automatically restarted if
it exits prematurely. Please note that you often need to provide
a --foreground or --no-background argument to most daemons to
prevent them from forking off to the background.
* `runparts <PATH>`
Call run-parts(8) on a directory other than default ``/etc/finit.d``
* `include <CONF>`
Include another configuration file, ``/etc/finit.d``, or runparts
path is prepended to file if the file is not found or an absolute
path is not given
* `tty [LVLS] <DEV | /bin/sh>`
Start a getty on the given TTY device, in the given runlevels. When
no tty setting is given in `finit.conf`, or if `/bin/sh` is given as
argument instead of a device path, a single shell is started on the
default console. Useful for really bare-bones systems
See `finit.h` for the `#define GETTY` that is called, along with the
default baud rate.
* `console <DEV>`
Some embedded systems have a dedicated console port. This command
tells finit to not start getty, but instead print a friendly message
and wait for the user to activate the console with a key press before
starting getty.
When running `make install` no default `/etc/finit.conf` will be
provided since the system requirements differ too much. Try out the
Debian 6.0 example `/usr/share/doc/finit/finit.conf` configuration that
is capable of service monitoring SSH, sysklogd, gdm and a console getty!
/etc/finit.d
------------
At the end of the boot, when networking and all services are up, finit
calls its built-in run-parts(8) on the `/etc/finit.d/` directory, if
it exists. Similar to how the `/ec/rc.local` file works in most other
init daemons, only finit runs a directory of scripts. This replaces the
earlier support for a `/usr/sbin/services.sh` script in the original
finit.
Runlevels
---------
Basic support for [runlevels](http://en.wikipedia.org/wiki/Runlevel) is
included in Finit from v1.8. By default all services, tasks, run
commands and TTYs listed without a set of runlevels get a default set
`[234]` assigned. The default runlevel after boot is 2.
To specify an allowed set of runlevels for a `service`, `run` command, `task`,
or `tty`, add `[NNN]` to it in your `finit.conf`, like this:
run [S] /etc/init.d/acpid start -- Starting ACPI Daemon
task [S] /etc/init.d/kbd start -- Preparing console
service [S12345] /sbin/klogd -n -x -- Kernel log daemon
tty [12345] /dev/tty1
tty [2] /dev/tty2
tty [2] /dev/tty3
tty [2] /dev/tty4
tty [2] /dev/tty5
tty [2] /dev/tty6
In this example acpid is started once at bootstrap using a conventional
SysV init script. Here the run command was used, meaning the following
task command is not run until the init script has fully completed. Then
the keyboard setup script is called in parallel with spawning klogd as
a monitored service.
Tasks and services are started in parallel, while run commands are run
in the order listed and subsequent commands are not started until a run
command has completed.
Existing finit.conf files that lack runlevel setting will get a default
runlevel assigned, `[234]`.
Switching between runlevels can be done by calling init with a single
argument, e.g., `init 5` switches to runlevel 5.
Hooks, Callbacks & Plugins
--------------------------
Finit provides only the bare necessities for starting and supervising
processes, with an emphasis on *bare* -- for your convenience it does
however come with support for hooks, service callbacks and plugins that
can used to extend finit with. For your convenience a set of *optional*
plugins are available:
* *alsa-utils.so*: Restore and save ALSA sound settings on
startup/shutdown.
* *bootmisc.so*: Setup necessary files for UTMP, tracking logins
at boot.
* *dbus.so*: Setup and start system message bus, D-Bus, at boot.
* *hwclock.so*: Restore and save system clock from/to RTC on
startup/shutdown.
* *initctl.so*: Extends finit with a traditional initctl functionality.
* *resolvconf.so*: Setup necessary files for resolvconf at startup.
* *tty.so*: Watches /dev, using inotify, for new device nodes (TTY's) to
start/stop getty consoles on them on demand.
* *urandom.so*: Setup random seed at startup.
* *x11-common.so*: Setup necessary files for X-Window.
Usually you want to hook into the boot process once, simple hook plugins
like `bootmisc.so` are great for that purpose. They are called at each
hook point in the boot process, useful to insert some pre-bootstrap
mechanisms, like generating configuration files, restoring HW device
state, etc. Available hook points are:
* `HOOK_ROOTFS_UP`: When `finit.conf` has been read and `/` has is
mounted -- very early
* `HOOK_BASEFS_UP`: All of `/etc/fstab` is mounted, swap is available
and default init signals are setup
* `HOOK_NETWORK_UP`: System bootstrap, runlevel S, has completed and
networking is up (`lo` is up and the `network` script has run)
* `HOOK_SVC_UP`: All services in the active runlevel has been launched
* `HOOK_SYSTEM_UP`: All services *and* everything in `/etc/finit.d`
has been launched
* `HOOK_SHUTDOWN`: Called at shutdown/reboot, right before all
services are sent `SIGTERM`
Plugins like `initctl.so` and `tty.so` extend finit by acting on events,
they are called I/O plugins and are called from the finit main loop when
`poll()` detects an event. See the source code for `plugins/*.c` for
more help and ideas.
Callback plugins are called by finit them right before a process is
started, or restarted if it exits. The callback receive a pointer to
the `svc_t` (defined in `svc.h`) of the service, with all command line
parameters free to modify if needed. All the callback needs to do is
respond with one of: `SVC_STOP (0)` tells finit to *not* start the
service, `SVC_START (1)` to start the service, or `SVC_RELOAD (2)` to
have finit signal the process with `SIGHUP`.
Rebooting and Halting
---------------------
Finit handles `SIGUSR1` and `SIGUSR2` for reboot and halt, and listens
to `/dev/initctl` so system reboot and halt commands should also work.
This latter functionality is implemented in the optional `initctl.so`
plugin.
Building
--------
The finit build system does not employ the GNU Configure and Build System,
instead standard makefiles are used. The user is encouraged to make source
code changes, using defines and conditionally building plugins instead to
alter the behavior of finit.
The following environment variables are checked by the makefiles and control
what is built and where resulting binaries are installed.
* `ROOTDIR=`: Top directory for building complete system, used in pretty
printing.
* `VERSION=`: Defaults to the currently released version of finit,
e.g., 1.3 but can be overridden by packagers using this variable to
add a suffix or completely alter the version.
* `CFLAGS=`: Default `CFLAGS` are inherited from the build environment.
* `CPPFLAGS=`: Default `CPPFLAGS` are inherited from the build
environment.
* `LDFLAGS=`: Default `LDFLAGS` are inherited from the build
environment.
* `LDLIBS=`: Default `LIBLIBS` are inherited from the build environment.
* `prefix=`: Base prefix path for all files, except `sbinbdir` and
`sysconfdir`. Used in concert with the `DESTDIR` variable.
Defaults to `/usr`.
* `sbindir=`: Path to where resulting binaries should install to. Used
in concert with the `DESTDIR` variable.
Defaults to `/sbin`.
* `sysconfdir=`: Path to where finit configuration files should install
to. Used in concert with the `DESTDIR` variable.
Defaults to `/etc`, but is currently unused.
* `PLUGINS=`: List of stock finit plugins to build and install.
* `plugindir=`: Absolute path to where finit should look for dynamically
loadable plugins at runtime. At installation prepended by `DESTDIR`
and `prefix`.
Defaults to `/lib/finit/plugins`.
* `DESTDIR=`: Used by packagers and distributions when building a
relocatable bundle of files. Always prepended to the `prefix`
destination directory.
**Example**
$ tar xfJ finit-1.3.tar.xz
$ PLUGINS="initctl.so hwclock.so" DESTDIR=/tmp/finit/dst \
make -C finit-1.3/ clean install
make: Entering directory `/home/troglobit/finit-1.3'
CC finit.o
CC conf.o
CC helpers.o
CC sig.o
CC svc.o
CC plugin.o
CC strlcpy.o
LINK finit
CC plugins/initctl.o
PLUGIN plugins/initctl.so
CC plugins/hwclock.o
PLUGIN plugins/hwclock.so
INSTALL /tmp/finit/dst/sbin/finit
INSTALL /tmp/finit/dst/lib/finit/plugins/initctl.so
INSTALL /tmp/finit/dst/lib/finit/plugins/hwclock.so
make: Leaving directory `/home/troglobit/finit-1.3'
In this example the
[finit-1.3.tar.xz](ftp://troglobit.com/finit/finit-1.3.tar.xz)
archive is unpacked to the user's home directory, built and
installed to a temporary staging directory. The environment
variables `DESTDIR` and `PLUGINS` are changed to suit this
particular build.
Running
-------
The default install does not setup finit as the system default
`/sbin/init`, neither does it setup an initial `/etc/finit.conf`.
It is assumed that users of finit are competent enough to either setup
finit as their default `/sbin/init` or alter their respective Grub,
LOADLIN, LILO, U-Boot/Barebox or RedBoot boot loader configuration to
give the kernel the following extra command line:
init=/sbin/finit
Debugging
---------
Add `finit_debug`, or `--debug`, to the kernel command line to
enable trace messages. A console getty is always started, see the file
`finit.h` for more useful compile-time tweaks:
init=/sbin/finit --debug
Credits & Contact
-----------------
This is the continuation of the [original finit](http://helllabs.org/finit/)
by [Claudio Matsuoka](https://github.com/cmatsuoka), which in turn was
reverse engineered from syscalls of the
[EeePC fastinit](http://wiki.eeeuser.com/boot_process:the_boot_process)
-- "gaps filled with frog DNA ...".
Finit is currently being developed and maintained by
[Joachim Nilsson](http://troglobit.com) at
[GitHub](http://github.com/troglobit/finit). Please file bug reports, clone it,
or send pull requests for bug fixes and proposed extensions.
-272
View File
@@ -1,272 +0,0 @@
==============================================================================
Finit — A fast plugin-based /sbin/init with service monitoring
==============================================================================
Welcome to finit!
This is an extremely fast /sbin/init replacement with focus on small
embedded GNU/Linux systems. Based on Claudio Matsuoka's original finit_
with I/O, service and hook plugin extensions. The original was a
reimplementation of the EeePC fastinit_ daemon based on its system calls
with gaps filled with frog DNA.
In the world of finit we write C plugins that hook into and extend the
``main()`` loop of ``/sbin/init``, this is what gives the system its raw
performance and the user full control.
If you chose finit you know what you want, a fast no hassles boot!
Features
--------
**Service monitoring**
Restarting a service when it exits
**Plugins**
Extend and modify finit behavior. See examples in plugins/ directory.
Plugin capabilities:
* Service callbacks — should the service run/restart/stop?
* Task/Run callbacks — a one-shot command, should it run in sequence?
* Hooks — hook into the boot at predefined points to extend finit
* I/O — listen to external events and control finit behaviour/services
Most extensions and functionality not purely related to what an /sbin/init
needs to start a system from the original finit_ has been reactored into
plugins with either hooks or I/O demands.
/etc/finit.conf
---------------
Contrary to most script based init alternatives (`SysV init`_, upstart_,
OpenRC_ and the likes) finit instead reads its configuration from
``/etc/finit.conf``. Below is a brief list, see the source code for the
full list:
check
Run fsck on a file system before mounting it
module
Load a kernel module, with optional arguments
network
Script or program to bringup networking, with optional arguments
runlevel N
N is the runlevel number 1-9, where 6 is reserved for reboot
run [RUN_LVLS] /path/to/cmd ARGS -- Optional description
One-shot command to run in sequence when entering a runlevel, with
optional arguments and description. This command is guaranteed to
be completed before running the next command.
task [RUN_LVLS] /path/to/cmd ARGS -- Optional description
One-shot like 'run', but starts in parallel with the next command
service [RUN_LVLS] /path/to/daemon ARGS -- Optional description
Service, or daemon, to be monitored and automatically restarted if
it exits prematurely. Please note that you often need to provide
a --foreground or --no-background argument to most daemons to
prevent them from forking off to the background.
runparts
Call run-parts(8) on a directory other than the default /etc/finit.d
tty [RUN_LVLS] DEV
Run getty on the listed TTY device, in the given runlevels
console DEV
Some embedded systems have a dedicated console port. This command
tells finit to not start getty, but instead print a friendly message
and wait for the user to activate the console with a keypress before
starting getty.
When running ``make install`` no default ``/etc/finit.conf`` will be
provided since the system requirements differ too much. Try out the
Debian 6.0 example ``/usr/share/doc/finit/finit.conf`` configuration
that is capable of service monitoring SSH, sysklogd, gdm and a console
getty!
/etc/finit.d
------------
At the end of the boot, when networking and all services are up, finit
calls its built-in run-parts(8) on the ``/etc/finit.d/`` directory, if
it exists. Similar to how the ``/ec/rc.local`` file works in most other
inits, only finit runs a directory of scripts. This replaces the
earlier support for a ``/usr/sbin/services.sh`` script in the original
finit_.
Runlevels
---------
Support for runlevels_ is included in Finit from v1.8. By default all
services, tasks, run commands and TTYs listed without a set of runlevels
get a default set [234] assigned. The default runlevel after boot is 2.
To specify an allowed set of runlevels for a service, run command, task,
or tty, add [NNN] to it in finit.conf, like this:
run [S] /etc/init.d/acpid start -- Starting ACPI Daemon
task [S] /etc/init.d/kbd start -- Preparing console
service [S12345] /sbin/klogd -n -x -- Kernel log daemon
tty [12345] /dev/tty1
tty [2] /dev/tty2
tty [2] /dev/tty3
tty [2] /dev/tty4
tty [2] /dev/tty5
tty [2] /dev/tty6
In this example acpid is started once at bootstrap using a conventional
SysV init script. Here the run command was used, meaning the following
task command is not run until the init script has fully completed.
Tasks and services are started in parallell, while run commands are run
in the order listed and subsequent commands are not started until a run
command has completed.
Existing finit.conf files that lack runlevel setting will get a default
runlevel assigned, [234].
Switching between runlevels can be done by calling init with a single
argument, e.g., 'init 5' switches to runlevel 5.
Rebooting and Halting
---------------------
Finit handles SIGUSR1 and SIGUSR2 for reboot and halt, and listens to
``/dev/initctl`` so standard Linux reboot and halt commands should also
work.
Building
--------
The finit build system does not employ the GNU Configure and Build System,
instead standard makefiles are used. The user is encouraged to make source
code changes, using defines and conditionally building plugins instead to
alter the behavior of finit.
The following environment variables are checked by the makefiles and control
what is built and where resulting binaries are installed.
**ROOTDIR=**
Top directory for building complete system, used in pretty printing
**VERSION=**
Defaults to the currently released version of finit, e.g., 1.3 but can
be overridden by packages to add a suffix or completely alter the version.
**CFLAGS=**
Standard CFLAGS are inherited from the build enviornmant.
**CPPFLAGS=**
Standard CPPFLAGS are inherited from the build enviornmant.
**LDFLAGS=**
Standard LDFLAGS are inherited from the build enviornmant.
**LDLIBS=**
Standard LIBLIBS are inherited from the build enviornmant.
**prefix=**
Base prefix path for all files, except ``sbinbdir`` and ``sysconfdir``.
Used in concert with the ``DESTDIR`` variable. Defaults to ``/usr``
**sbindir=**
Path to where resulting binaries should install to. Used in concert
with the ``DESTDIR`` variable. Defaults to ``/sbin``
**sysconfdir=**
Path to where finit configuration files should install to. Used in
concert with the ``DESTDIR`` variable. Defaults to ``/etc``, but is
currently unused.
**PLUGINS=**
List of stock finit plugins to build and install.
**plugindir=**
Absolute path to where finit should look for dynamically loadable plugins
at runtime. At installation prepended by ``DESTDIR`` and ``prefix``.
Defaults to ``/lib/finit/plugins``
**DESTDIR=**
Used by packagers and distributions when building a relocatable
bundle of files. Alwawys prepended to the ``prefix`` destination
directory.
**Example**::
$ tar xfJ finit-1.3.tar.xz
$ PLUGINS="initctl.so hwclock.so" DESTDIR=/tmp/finit/dst \
make -C finit-1.3/ clean install
make: Entering directory `/home/troglobit/finit-1.3'
CC finit.o
CC conf.o
CC helpers.o
CC sig.o
CC svc.o
CC plugin.o
CC strlcpy.o
LINK finit
CC plugins/initctl.o
PLUGIN plugins/initctl.so
CC plugins/hwclock.o
PLUGIN plugins/hwclock.so
INSTALL /tmp/finit/dst/sbin/finit
INSTALL /tmp/finit/dst/lib/finit/plugins/initctl.so
INSTALL /tmp/finit/dst/lib/finit/plugins/hwclock.so
make: Leaving directory `/home/troglobit/finit-1.3'
In this example the `finit-1.3.tar.xz`_ archive is unpacked to the
user's home directory, built and installed to a temporary staging
directory. The enviroment variables ``DESTDIR`` and ``PLUGINS`` are
changed to suit this particular build.
Running
-------
The default install does not setup finit as the system default
``/sbin/init``, neither does it setup an initial ``/etc/finit.conf``.
It is assumed that users of finit are competent enough to either setup
finit as their default ``/sbin/init`` or alter their respective Grub,
LOADLIN, LILO, U-Boot/Barebox or RedBoot boot loader configuration to
give the kernel the following extra command line::
init=/sbin/finit
Debugging
---------
Add ``finit_debug``, or ``--debug``, to the kernel command line to
enable trace messages. A console getty is always started, see the file
``finit.h`` for more useful comile-time tweaks::
init=/sbin/finit --debug
Contact
-------
Finit is maintained collaborativly at http://github.com/troglobit/finit —
please file a bug report, clone it, or send pull requests for bug fixes and
proposed extensions, or become a co-maintainer by contacting the main author.
Regards
/Joachim Nilsson <troglobit@gmail.com>
.. _finit: http://helllabs.org/finit/
.. _fastinit: http://wiki.eeeuser.com/boot_process:the_boot_process
.. _`SysV init`: http://savannah.nongnu.org/projects/sysvinit
.. _upstart: http://upstart.ubuntu.com/
.. _runlevels: http://en.wikipedia.org/wiki/Runlevel
.. _openrc: http://www.gentoo.org/proj/en/base/openrc/
.. _`finit-1.3.tar.xz`: http://github.com/downloads/troglobit/finit/finit-1.3.tar.xz
+1 -1
View File
@@ -1 +1 @@
TODO.rst TODO.md
+98
View File
@@ -0,0 +1,98 @@
TODO
====
Unsorted TODO list of features and points of investigation that could be
useful for improving finit. But what is an improvement to finit? Well,
similiar to launchd, the goal of finit is to be a FAST replacement for:
* init
* inetd
* crond
* watchdogd
The main goal is to be FAST. Secondary goals are to be: small, simple
and with a very low dependency on external packages.
Inetd
-----
Simple way of running Internet services on demand, like the old inetd:
inetd SVC [RUNLVL] /path/to/daemon args -- description
Example:
# Inetd services, launched on demand
inetd ssh [2345] /usr/sbin/sshd -i -- SSH Daemon
In keeping with the finit tradition, an optional callback can be setup
to each inetd service. When a client connects the finit will call the
callback with a `struct in_pktinfo` argument which the callback then can
allowed or deny.
Priority
--------
The intent of finit is to monitor not just processes, but also to
be able to supervise the entire system and the behavior of certain
processes that declare themselves to be finit compliant.
* Integrate the ingenious libev to handle all events: signals, polling
fd's, etc. Because "Event driven software improves concurrency" --
Dave Zarzycki, Apple.
See the [launchd video](http://www.youtube.com/watch?v=cD_s6Fjdri8)
for more info!
* Add support for a /dev/watchdog plugin to replace watchdogd
* Integrate watchdog plugin with process/system supervisor to optionally
reboot the system when a process stops responding, or when a respawn
limit has been reached, as well as when system load gets too high.
Configuration
-------------
* Add support for `init <q | reload-configuration>` and `SIGHUP` to
have finit reload its `finit.conf`, but also
* Add support for inotify to automatically reload `finit.conf`
Runlevels
---------
* Implement `initctl stop|start|restart|reload|status <SVC>` and
`service <SVC> stop|start|restart|reload|status` on top
* Add PRE and POST hooks for when switching between runlevels
Miscellaneous
-------------
* Add support for `init -v,--version | version`
* Cleanup move sources from top-level directory to `src/` and `include/`
* Make sure to install `queue.h` to `$(PREFIX)/include/finit/queue.h`
* Move `finit.conf` "check" command to plugin which checks `/etc/fstab`
instead. This is the de-facto practice. But keep the check command
for really low-end systems w/o `/etc/fstab`.
Documentation
-------------
* Write man pages for finit and `finit.conf`, steal from the excellent
`pimd` man pages ...
* Update Debian `finit.conf` example with runlevels, `tty/console` and
dependency handling
Investigation
-------------
* [FHS changes](http://askubuntu.com/questions/57297/why-has-var-run-been-migrated-to-run)
affecting runtime status, plugins, etc.
-105
View File
@@ -1,105 +0,0 @@
==============================================================================
TODO
==============================================================================
Unsorted TODO list of features and points of investigation that could be
useful for improving finit. But what is an improvement to finit? Well,
similiar to launchd, the goal of finit is to be a FAST replacement for:
* init
* inetd
* crond
* watchdogd
The main goal is to be FAST. Secondary goals are to be: small, simple
and with a very low dependency on external packages.
Priority
--------
The intent of finit is to monitor not just processes, but also to
be able to supervise the entire system and the behavior of certain
processes that declare themselves to be finit compliant.
* Integrate the ingenious libev to handle all events: signals, polling
fd's, etc. Because "Event driven software improves concurrency" --
Dave Zarzycki, Apple. See the `launchd video`_ for more info!
* Add support for process and system supervision. Which could
be an API wrapping, e.g., TIPC and loadavg.
* Add support for a /dev/watchdog plugin to replace watchdogd
* Integrate watchdog plugin with process/system supervisor to
reboot the system when a process stops responding, or when
restarting it is imposible, as well as when system load gets
too high.
Configuration
-------------
* Add support for "init <q | reload-configuration>" and SIGHUP to
reload finit.conf, but also
* Add support for inotify to automatically reload finit.conf
Runlevels
---------
* Add support for "runlevel N" to finit.conf
* Improve support for runlevels: startup, running (services from
finit.conf), and shutdown as well as hooks when switching RL, startup
at RL 1 and a default run level.
* Implement initctl stop|start|restart|reload|status <SVC> and service
<SVC> stop|start|restart|reload|status on top
* Add PRE and POST hooks for when changing runlevels
* SysV init in Debian uses an rcS.d/ for scripts that should run once at
boot. These scripts are run before the actual runlevel, which is set
in inittab. We could use "task [S]" and "run [S]" (below) for this.
* Add support for a new runlevel 'S' that is started before all other
services in the selected runlevel.
Services and Tasks
------------------
Both the "task" and "boot" stanzas below are like "service", share the
same mechanism for registering callbacks. These callbacks can be used
to check a configuration db and return 1 (RUN), 2 (STOP), or 3 (RELOAD).
* Add support for "task [RUNLVL] ..." similar to services, but one-shot.
* Add support for "run [RUNLVL] ..." similar to task, but waits for
completion before continuing with the next task/service
* Add support for service/task/run dependencies
* Add support for "init list" to show running services
It is tempting to say that a task called at runlevel S would be a
blocking call, like run, but there are likely use-cases when you want to
call on-shot tasks in parallell with something else, even at boot. Hence
the differentiation between "task" and "run", which are essentially the
same, except for the "pause and wait for completion" that "run" has.
Miscellaneous
-------------
* Add support for "init -v,--version | version"
* Cleanup move sources from top-level directory to src/ and include/
* Make sure to install queue.h to $(PREFIX)/include/finit/queue.h
* Move finit.conf "check" command to plugin which checks /etc/fstab
instead. This is the de-facto practise. But keep the check command
for really low-end systems w/o /etc/fstab.
Documentation
-------------
* Write man pages for finit and finit.conf, steal from pimd man pages...
* Update Debian finit.conf example with runlevels, tty/console and
dependency handling
Investigation
-------------
* `FHS changes`_ affecting runtime status, plugins, etc.
.. _`launchd video`: http://www.youtube.com/watch?v=cD_s6Fjdri8
.. _`FHS changes`: http://askubuntu.com/questions/57297/why-has-var-run-been-migrated-to-run
..
.. Local Variables:
.. mode: rst
.. version-control: t
.. End:
+1
View File
@@ -5,6 +5,7 @@ ROOTDIR ?= $(TOPDIR)
JUNK = *~ *.bak *.aux *.dvi *.idx *.ind *.log *.ps *.map .*.d DEADJOE semantic.cache *.gdb *.elf core core.* JUNK = *~ *.bak *.aux *.dvi *.idx *.ind *.log *.ps *.map .*.d DEADJOE semantic.cache *.gdb *.elf core core.*
MAKE := @$(MAKE) MAKE := @$(MAKE)
MAKEFLAGS = --no-print-directory --silent MAKEFLAGS = --no-print-directory --silent
CHECK := cppcheck $(CPPFLAGS) --quiet --enable=all
INSTALL := install --backup=off INSTALL := install --backup=off
STRIPINST := $(INSTALL) -s --strip-program=$(CROSS)strip -m 0755 STRIPINST := $(INSTALL) -s --strip-program=$(CROSS)strip -m 0755
+178 -126
View File
@@ -86,141 +86,193 @@ int parse_runlevels(char *runlevels)
return bitmask; return bitmask;
} }
void parse_finit_conf(char *file) static int parse_conf(char *file)
{ {
FILE *fp; FILE *fp;
char line[LINE_SIZE]; char line[LINE_SIZE] = "";
char cmd[CMD_SIZE]; char cmd[CMD_SIZE];
char *x;
const char *err = NULL;
fp = fopen(file, "r");
if (!fp)
return 1;
/*
* If not standard finit.conf, then we want to show just the base name
* Loading configuration ............. vs
* Loading services configuration ....
*/
if (!string_match (file, FINIT_CONF)) {
/* Remove leading path */
x = strrchr(file, '/');
if (!x) x = file;
else x++;
/* Remove ending .conf */
strlcpy(line, x, sizeof(line));
x = strstr(line, ".conf");
if (x) *x = 0;
/* Add empty space. */
strcat(line, " ");
}
print(0, "Loading %sconfiguration", line);
while (!feof(fp)) {
if (!fgets(line, sizeof(line), fp))
continue;
chomp(line);
_d("conf: %s", line);
/* Skip comments. */
if (MATCH_CMD(line, "#", x))
continue;
/* Do this before mounting / read-write
* XXX: Move to plugin which checks /etc/fstab instead */
if (MATCH_CMD(line, "check ", x)) {
char *dev = strip_line(x);
strcpy(cmd, "/sbin/fsck -C -a ");
strlcat(cmd, dev, sizeof(cmd));
run_interactive(cmd, "Checking file system %s", dev);
continue;
}
if (MATCH_CMD(line, "user ", x)) {
if (username) free(username);
username = strdup(strip_line(x));
continue;
}
if (MATCH_CMD(line, "host ", x)) {
if (hostname) free(hostname);
hostname = strdup(strip_line(x));
continue;
}
if (MATCH_CMD(line, "module ", x)) {
char *mod = strip_line(x);
strcpy(cmd, "/sbin/modprobe ");
strlcat(cmd, mod, sizeof(cmd));
run_interactive(cmd, "Loading kernel module %s", mod);
continue;
}
if (MATCH_CMD(line, "mknod ", x)) {
char *dev = strip_line(x);
strcpy(cmd, "/bin/mknod ");
strlcat(cmd, dev, sizeof(cmd));
run_interactive(cmd, "Creating device node %s", dev);
continue;
}
if (MATCH_CMD(line, "network ", x)) {
if (network) free(network);
network = strdup(strip_line(x));
continue;
}
/* This is the directory from which executable scripts and
* any finit include files are read, default /etc/finit.d/ */
if (MATCH_CMD(line, "runparts ", x)) {
if (rcsd) free(rcsd);
rcsd = strdup(strip_line(x));
continue;
}
/* Parse any include file, use rcsd if absolute path not given */
if (MATCH_CMD(line, "include ", x)) {
char *file = strip_line(x);
strlcpy(cmd, file, sizeof(cmd));
if (!fexist(cmd)) {
/* ... try /etc/finit.d/ as prefix */
snprintf(cmd, sizeof(cmd), "%s/%s", rcsd, file);
if (!fexist(cmd))
continue;
}
parse_conf(cmd);
continue;
}
if (MATCH_CMD(line, "startx ", x)) {
svc_register(SVC_CMD_SERVICE, strip_line(x), username);
continue;
}
if (MATCH_CMD(line, "shutdown ", x)) {
if (sdown) free(sdown);
sdown = strdup(strip_line(x));
continue;
}
/* The desired runlevel to start when leaving
* bootstrap (S). Finit supports 1-9, but most
* systems only use 1-6, where 6 is reserved for
* reboot */
if (MATCH_CMD(line, "runlevel ", x)) {
char *token = strip_line(x);
cfglevel = strtonum(token, 1, 9, &err);
if (err)
cfglevel = RUNLEVEL;
if (cfglevel < 1 || cfglevel > 9 || cfglevel == 6)
cfglevel = 2; /* Fallback */
continue;
}
/* Monitored daemon, will be respawned on exit, as
* long as the (optional) service callback returns
* non-zero */
if (MATCH_CMD(line, "service ", x)) {
svc_register(SVC_CMD_SERVICE, x, NULL);
continue;
}
/* One-shot task, will not be respawned. Only runs if
* the (optional) service callback returns true */
if (MATCH_CMD(line, "task ", x)) {
svc_register(SVC_CMD_TASK, x, NULL);
continue;
}
/* Like task but waits for completion, useful w/ [S] */
if (MATCH_CMD(line, "run ", x)) {
svc_register(SVC_CMD_RUN, x, NULL);
continue;
}
if (MATCH_CMD(line, "console ", x)) {
if (console) free(console);
console = strdup(strip_line(x));
continue;
}
if (MATCH_CMD(line, "tty ", x)) {
tty_register(strip_line(x));
continue;
}
}
fclose(fp);
return 0;
}
int parse_finit_conf(char *file)
{
int result;
username = strdup(DEFUSER); username = strdup(DEFUSER);
hostname = strdup(DEFHOST); hostname = strdup(DEFHOST);
rcsd = strdup(FINIT_RCSD); rcsd = strdup(FINIT_RCSD);
if ((fp = fopen(file, "r")) != NULL) { result = parse_conf(file);
char *x; if (!tty_num())
const char *err = NULL; tty_register(FALLBACK_SHELL);
_d("Parse %s ...", file); return result;
while (!feof(fp)) {
if (!fgets(line, sizeof(line), fp))
continue;
chomp(line);
_d("conf: %s", line);
/* Skip comments. */
if (MATCH_CMD(line, "#", x))
continue;
/* Do this before mounting / read-write
* XXX: Move to plugin which checks /etc/fstab instead */
if (MATCH_CMD(line, "check ", x)) {
char *dev = strip_line(x);
strcpy(cmd, "/sbin/fsck -C -a ");
strlcat(cmd, dev, sizeof(cmd));
run_interactive(cmd, "Checking file system %s", dev);
continue;
}
if (MATCH_CMD(line, "user ", x)) {
if (username) free(username);
username = strdup(strip_line(x));
continue;
}
if (MATCH_CMD(line, "host ", x)) {
if (hostname) free(hostname);
hostname = strdup(strip_line(x));
continue;
}
if (MATCH_CMD(line, "module ", x)) {
char *mod = strip_line(x);
strcpy(cmd, "/sbin/modprobe ");
strlcat(cmd, mod, sizeof(cmd));
run_interactive(cmd, "Loading kernel module %s", mod);
continue;
}
if (MATCH_CMD(line, "mknod ", x)) {
char *dev = strip_line(x);
strcpy(cmd, "/bin/mknod ");
strlcat(cmd, dev, sizeof(cmd));
run_interactive(cmd, "Creating device node %s", dev);
continue;
}
if (MATCH_CMD(line, "network ", x)) {
if (network) free(network);
network = strdup(strip_line(x));
continue;
}
if (MATCH_CMD(line, "runparts ", x)) {
if (rcsd) free(rcsd);
rcsd = strdup(strip_line(x));
continue;
}
if (MATCH_CMD(line, "startx ", x)) {
svc_register(SVC_CMD_SERVICE, strip_line(x), username);
continue;
}
if (MATCH_CMD(line, "shutdown ", x)) {
if (sdown) free(sdown);
sdown = strdup(strip_line(x));
continue;
}
/* The desired runlevel to start when leaving
* bootstrap (S). Finit supports 1-9, but most
* systems only use 1-6, where 6 is reserved for
* reboot */
if (MATCH_CMD(line, "runlevel ", x)) {
char *token = strip_line(x);
cfglevel = strtonum(token, 1, 9, &err);
if (err)
cfglevel = RUNLEVEL;
if (cfglevel < 1 || cfglevel > 9 || cfglevel == 6)
cfglevel = 2; /* Fallback */
continue;
}
/* Monitored daemon, will be respawned on exit, as
* long as the (optional) service callback returns
* non-zero */
if (MATCH_CMD(line, "service ", x)) {
svc_register(SVC_CMD_SERVICE, x, NULL);
continue;
}
/* One-shot task, will not be respawned. Only runs if
* the (optional) service callback returns true */
if (MATCH_CMD(line, "task ", x)) {
svc_register(SVC_CMD_TASK, x, NULL);
continue;
}
/* Like task but waits for completion, useful w/ [S] */
if (MATCH_CMD(line, "run ", x)) {
svc_register(SVC_CMD_RUN, x, NULL);
continue;
}
if (MATCH_CMD(line, "console ", x)) {
if (console) free(console);
console = strdup(strip_line(x));
continue;
}
if (MATCH_CMD(line, "tty ", x)) {
tty_register(strip_line(x));
continue;
}
}
fclose(fp);
}
} }
+5 -5
View File
@@ -1,7 +1,7 @@
/* Finit - Extremely fast /sbin/init replacement w/ I/O, hook & service plugins /* Finit - Extremely fast /sbin/init replacement w/ I/O, hook & service plugins
* *
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com> * Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2012 Joachim Nilsson <troglobit@gmail.com> * Copyright (c) 2008-2014 Joachim Nilsson <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -181,8 +181,8 @@ int main(int argc, char* argv[])
mount("none", "/proc", "proc", 0, NULL); mount("none", "/proc", "proc", 0, NULL);
mount("none", "/proc/bus/usb", "usbfs", 0, NULL); mount("none", "/proc/bus/usb", "usbfs", 0, NULL);
mount("none", "/sys", "sysfs", 0, NULL); mount("none", "/sys", "sysfs", 0, NULL);
mkdir("/dev/pts", 0755); makedir("/dev/pts", 0755);
mkdir("/dev/shm", 0755); makedir("/dev/shm", 0755);
mount("none", "/dev/pts", "devpts", 0, "gid=5,mode=620"); mount("none", "/dev/pts", "devpts", 0, "gid=5,mode=620");
mount("none", "/dev/shm", "tmpfs", 0, NULL); mount("none", "/dev/shm", "tmpfs", 0, NULL);
umask(022); umask(022);
@@ -207,7 +207,7 @@ int main(int argc, char* argv[])
* all services, or service plugins won't have anything to * all services, or service plugins won't have anything to
* hook on to. * hook on to.
*/ */
print_desc("", "Loading Finit plugins"); print_desc("Loading plugins", NULL);
print_result(plugin_load_all(PLUGIN_PATH)); print_result(plugin_load_all(PLUGIN_PATH));
/* /*
@@ -250,7 +250,7 @@ int main(int argc, char* argv[])
run("/sbin/sysctl -e -p /etc/sysctl.conf >/dev/null"); run("/sbin/sysctl -e -p /etc/sysctl.conf >/dev/null");
/* Set initial hostname. */ /* Set initial hostname. */
set_hostname(hostname); set_hostname(&hostname);
ifconfig("lo", "127.0.0.1", "255.0.0.0", 1); ifconfig("lo", "127.0.0.1", "255.0.0.0", 1);
if (network) if (network)
+6 -7
View File
@@ -24,15 +24,14 @@ tty /dev/tty3
# Alternative method instead of runparts # Alternative method instead of runparts
#task [S] /etc/init.d/keyboard-setup start -- Setting up preliminary keymap #task [S] /etc/init.d/keyboard-setup start -- Setting up preliminary keymap
#task [S] /etc/init.d/acpid start -- Starting ACPI Daemon #task [S] /etc/init.d/acpid start -- Starting ACPI Daemon
#task [S] /etc/init.d/kbd start -- Preparing console #task [S] /etc/init.d/kbd start -- Preparing console
#run [2] /etc/init.d/networking start -- Start networking #run [2] /etc/init.d/networking start -- Start networking
# Services to be monitored and respawned as needed # Services to be monitored and respawned as needed
service [2345] /sbin/klogd -n -- Kernel logging server service [2345] /sbin/klogd -n -- Kernel logging server
service [2345] /sbin/syslogd -n -- Syslog server service [2345] /sbin/syslogd -n -- Syslog server
service [2345] /usr/sbin/sshd -D -- OpenSSH server service [3] /usr/sbin/gdm -- GNOME Display Manager
service [3] /usr/sbin/gdm -- GNOME Display Manager
# By default Finit looks for /etc/finit.d # By default Finit looks for /etc/finit.d
# runparts /etc/finit.d # runparts /etc/finit.d
+27 -22
View File
@@ -27,6 +27,7 @@
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <paths.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <sys/types.h> #include <sys/types.h>
@@ -35,41 +36,45 @@
/* Distribution specific configuration */ /* Distribution specific configuration */
#if defined EMBEDDED_SYSTEM #if defined EMBEDDED_SYSTEM
# define CONSOLE "/dev/console" # define CONSOLE _PATH_CONSOLE
# define SETUP_DEVFS "/sbin/mdev -s" # define SETUP_DEVFS "/sbin/mdev -s"
# define GETTY "/sbin/getty -L" # define GETTY "/sbin/getty -L"
# define GETTY_BUSYBOX # define GETTY_BUSYBOX
# define BAUDRATE 115200 # define BAUDRATE 115200
# define RUNLEVEL 2 # define RUNLEVEL 2
#else /* Debian/Ubuntu based distributions */ #else /* Debian/Ubuntu based distributions */
# define CONSOLE "/dev/tty1" # define CONSOLE "/dev/tty1"
# define SETUP_DEVFS "/sbin/udevd --daemon" # define SETUP_DEVFS "/sbin/udevd --daemon"
# define GETTY "/sbin/getty -8" # define GETTY "/sbin/getty -8"
# define GETTY_AGETTY # define GETTY_AGETTY
# define BAUDRATE 38400 # define BAUDRATE 38400
# define RUNLEVEL 2 # define RUNLEVEL 2
# define RANDOMSEED "/var/lib/urandom/random-seed" # define RANDOMSEED "/var/lib/urandom/random-seed"
# define REMOUNT_ROOTFS_RW # define REMOUNT_ROOTFS_RW
# define HAVE_DBUS # define HAVE_DBUS
#endif #endif
#ifndef FALLBACK_SHELL
# define FALLBACK_SHELL _PATH_BSHELL
#endif
#ifndef DEFUSER #ifndef DEFUSER
# define DEFUSER "root" # define DEFUSER "root"
#endif #endif
#ifndef DEFHOST #ifndef DEFHOST
# define DEFHOST "noname" # define DEFHOST "noname"
#endif #endif
/* Delay start of GETTY at boot. Must be > 0 */ /* Delay start of GETTY at boot. Must be > 0 */
#define DELAY_TTY 2 #define DELAY_TTY 2
#define CMD_SIZE 256 #define CMD_SIZE 256
#define LINE_SIZE 1024 #define LINE_SIZE 1024
#define BUF_SIZE 4096 #define BUF_SIZE 4096
#define INIT_MAGIC 0x03091969 #define INIT_MAGIC 0x03091969
#define INIT_CMD_RUNLVL 1 #define INIT_CMD_RUNLVL 1
#define INIT_CMD_DEBUG 2 #define INIT_CMD_DEBUG 2
struct init_request { struct init_request {
int magic; /* Magic number */ int magic; /* Magic number */
@@ -91,8 +96,8 @@ extern char *console;
extern char *__progname; extern char *__progname;
/* conf.c */ /* conf.c */
int parse_runlevels (char *runlevels); int parse_runlevels (char *runlevels);
void parse_finit_conf (char *file); int parse_finit_conf (char *file);
#endif /* FINIT_H_ */ #endif /* FINIT_H_ */
+132 -65
View File
@@ -1,7 +1,7 @@
/* Misc. utility functions and C-library extensions for finit and its plugins /* Misc. utility functions and C-library extensions for finit and its plugins
* *
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com> * Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2012 Joachim Nilsson <troglobit@gmail.com> * Copyright (c) 2008-2014 Joachim Nilsson <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -131,31 +131,31 @@ void ifconfig(char *ifname, char *addr, char *mask, int up)
*/ */
pid_t pidfile_read(char *pidfile) pid_t pidfile_read(char *pidfile)
{ {
pid_t pid = 0; pid_t pid = 0;
char buf[16]; char buf[16];
FILE *fp; FILE *fp;
if (!pidfile) { if (!pidfile) {
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
if (!fexist(pidfile)) if (!fexist(pidfile))
return -1; return -1;
fp = fopen(pidfile, "r"); fp = fopen(pidfile, "r");
if (!fp) if (!fp)
return -1; return -1;
if (fgets(buf, sizeof(buf), fp)) { if (fgets(buf, sizeof(buf), fp)) {
errno = 0; errno = 0;
pid = strtoul(buf, NULL, 0); pid = (pid_t)strtol(buf, NULL, 10);
if (errno) if (errno)
pid = 0; /* Failed conversion. */ pid = 0; /* Failed conversion. */
} }
fclose(fp); fclose(fp);
return pid; return pid;
} }
/** /**
@@ -270,12 +270,15 @@ int procname_kill(char *name, int signo)
DIR *dir; DIR *dir;
struct dirent *entry; struct dirent *entry;
dir = opendir("/proc"); if (!name) {
if (!dir || !name) {
errno = EINVAL; errno = EINVAL;
return 0; return 0;
} }
dir = opendir("/proc");
if (!dir)
return 0;
while ((entry = readdir(dir)) != NULL) { while ((entry = readdir(dir)) != NULL) {
/* Skip non-process entries in /proc */ /* Skip non-process entries in /proc */
if (!isdigit(*entry->d_name)) if (!isdigit(*entry->d_name))
@@ -330,25 +333,55 @@ static int print_timestamp(void)
return 0; return 0;
} }
void print_desc(char *action, char *desc) void print(int action, const char *fmt, ...)
{ {
char buf[80];
size_t len;
va_list ap;
const char success[] = " \e[1m[ OK ]\e[0m\n";
const char failure[] = " \e[7m[FAIL]\e[0m\n";
const char pending[] = " \e[1m[ \\/ ]\e[0m\n";
const char dots[] = " ....................................................................."; const char dots[] = " .....................................................................";
delline(); if (fmt) {
print_timestamp(); va_start(ap, fmt);
len = vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
write(STDERR_FILENO, action, strlen(action)); delline();
write(STDERR_FILENO, desc, strlen(desc)); print_timestamp();
write(STDERR_FILENO, dots, 60 - strlen(desc) - strlen(action)); /* pad with dots. */
write(STDERR_FILENO, "\r", 1);
write(STDERR_FILENO, buf, len);
write(STDERR_FILENO, dots, 60 - len); /* pad with dots. */
}
switch (action) {
case -1:
break;
case 0:
write(STDERR_FILENO, success, sizeof(success));
break;
case 1:
write(STDERR_FILENO, failure, sizeof(failure));
break;
default:
write(STDERR_FILENO, pending, sizeof(pending));
break;
}
}
void print_desc(char *action, char *desc)
{
print(-1, "%s%s", action ?: "", desc ?: "");
} }
int print_result(int fail) int print_result(int fail)
{ {
if (fail) print(!!fail, NULL);
fprintf(stderr, " \e[7m[FAIL]\e[0m\n");
else
fprintf(stderr, " \e[1m[ OK ]\e[0m\n");
return fail; return fail;
} }
@@ -374,7 +407,6 @@ int complete(char *cmd, int pid)
int run(char *cmd) int run(char *cmd)
{ {
int status, result, i = 0; int status, result, i = 0;
FILE *fp;
char *args[NUM_ARGS + 1], *arg, *backup; char *args[NUM_ARGS + 1], *arg, *backup;
pid_t pid; pid_t pid;
@@ -414,17 +446,18 @@ int run(char *cmd)
return 1; return 1;
} }
fp = fopen("/dev/null", "w");
pid = fork(); pid = fork();
if (0 == pid) { if (0 == pid) {
int i; int i;
FILE *fp;
struct sigaction sa; struct sigaction sa;
/* Reset signal handlers that were set by the parent process */ /* Reset signal handlers that were set by the parent process */
for (i = 1; i < NSIG; i++) for (i = 1; i < NSIG; i++)
DFLSIG(sa, i, 0); DFLSIG(sa, i, 0);
/* Redirect stdio if the caller requested so. */ /* Always redirect stdio for run() */
fp = fopen("/dev/null", "w");
if (fp) { if (fp) {
int fd = fileno(fp); int fd = fileno(fp);
@@ -437,14 +470,14 @@ int run(char *cmd)
_exit(1); /* Only if execv() fails. */ _exit(1); /* Only if execv() fails. */
} else if (-1 == pid) { } else if (-1 == pid) {
_pe("%s", args[0]); _pe("%s", args[0]);
free(backup);
return -1; return -1;
} }
status = complete(args[0], pid); status = complete(args[0], pid);
if (-1 == status) { if (-1 == status) {
if (fp) fclose(fp);
free(backup); free(backup);
return 1; return 1;
} }
@@ -459,7 +492,6 @@ int run(char *cmd)
* change their return code accordingly. --Jocke */ * change their return code accordingly. --Jocke */
} }
if (fp) fclose(fp);
free(backup); free(backup);
return result; return result;
@@ -470,27 +502,49 @@ int run_interactive(char *cmd, char *fmt, ...)
int status, oldout = 1, olderr = 2; int status, oldout = 1, olderr = 2;
char line[LINE_SIZE]; char line[LINE_SIZE];
va_list ap; va_list ap;
FILE *fp = tmpfile(); FILE *fp;
va_start(ap, fmt); if (!cmd) {
vsnprintf(line, sizeof(line), fmt, ap); errno = EINVAL;
va_end(ap); return 1;
}
if (fmt) {
va_start(ap, fmt);
vsnprintf(line, sizeof(line), fmt, ap);
va_end(ap);
if (fmt)
print_desc("", line); print_desc("", line);
}
/* Redirect output from cmd to a tempfile */
fp = tmpfile();
if (fp && !debug) { if (fp && !debug) {
oldout = dup(STDOUT_FILENO); oldout = dup(STDOUT_FILENO);
olderr = dup(STDERR_FILENO); olderr = dup(STDERR_FILENO);
dup2(fileno(fp), STDOUT_FILENO); dup2(fileno(fp), STDOUT_FILENO);
dup2(fileno(fp), STDERR_FILENO); dup2(fileno(fp), STDERR_FILENO);
} }
/* Run cmd ... */
status = run(cmd); status = run(cmd);
/* Restore stderr/stdout */
if (fp && !debug) { if (fp && !debug) {
dup2(oldout, STDOUT_FILENO); if (oldout >= 0) {
dup2(olderr, STDERR_FILENO); dup2(oldout, STDOUT_FILENO);
close(oldout);
}
if (olderr >= 0) {
dup2(olderr, STDERR_FILENO);
close(olderr);
}
} }
if (fmt) if (fmt)
print_result(status); print_result(status);
/* Dump any results of cmd on stderr after we've printed [ OK ] or [FAIL] */
if (fp && !debug) { if (fp && !debug) {
size_t len, written; size_t len, written;
@@ -499,9 +553,11 @@ int run_interactive(char *cmd, char *fmt, ...)
len = fread(line, 1, sizeof(line), fp); len = fread(line, 1, sizeof(line), fp);
written = fwrite(line, len, sizeof(char), stderr); written = fwrite(line, len, sizeof(char), stderr);
} while (len > 0 && written == len); } while (len > 0 && written == len);
fclose(fp);
} }
if (fp)
fclose(fp);
return status; return status;
} }
@@ -510,7 +566,7 @@ pid_t run_getty(char *cmd, char *args[], int console)
pid_t pid = fork(); pid_t pid = fork();
if (!pid) { if (!pid) {
int i; int i, fd;
char c; char c;
sigset_t nmask; sigset_t nmask;
struct sigaction sa; struct sigaction sa;
@@ -519,12 +575,13 @@ pid_t run_getty(char *cmd, char *args[], int console)
/* Detach from initial controlling TTY */ /* Detach from initial controlling TTY */
vhangup(); vhangup();
close(2); close(STDERR_FILENO);
close(1); close(STDOUT_FILENO);
close(0); close(STDIN_FILENO);
/* Attach TTY to console */ /* Attach TTY to console */
if (open(CONSOLE, O_RDWR) != 0) fd = open(CONSOLE, O_RDWR);
if (fd != STDIN_FILENO)
exit(1); exit(1);
dup2(0, STDIN_FILENO); dup2(0, STDIN_FILENO);
@@ -550,7 +607,7 @@ pid_t run_getty(char *cmd, char *args[], int console)
} }
if (console) { if (console) {
i = write(STDERR_FILENO, msg, sizeof(msg)); (void)write(STDERR_FILENO, msg, sizeof(msg));
while (read(STDIN_FILENO, &c, 1) == 1 && c != '\n') while (read(STDIN_FILENO, &c, 1) == 1 && c != '\n')
continue; continue;
} }
@@ -560,6 +617,9 @@ pid_t run_getty(char *cmd, char *args[], int console)
execv(cmd, args); execv(cmd, args);
} }
if (console)
close(fd);
exit(0); exit(0);
} }
@@ -664,26 +724,33 @@ void do_sleep(unsigned int sec)
; ;
} }
void set_hostname(char *hostname) void set_hostname(char **hostname)
{ {
FILE *fp; FILE *fp;
_d("Set hostname: %s", hostname); _d("Set hostname: %s", *hostname);
if ((fp = fopen("/etc/hostname", "r")) != NULL) { fp = fopen("/etc/hostname", "r");
if (fp) {
struct stat st; struct stat st;
fstat(fileno(fp), &st); if (fstat(fileno(fp), &st)) {
hostname = realloc(hostname, st.st_size); fclose(fp);
if (!hostname)
return; return;
}
fgets(hostname, st.st_size, fp); *hostname = realloc(*hostname, st.st_size);
chomp(hostname); if (!*hostname) {
fclose(fp);
return;
}
fgets(*hostname, st.st_size, fp);
chomp(*hostname);
fclose(fp); fclose(fp);
} }
if (hostname) if (*hostname)
sethostname(hostname, strlen(hostname)); sethostname(*hostname, strlen(*hostname));
} }
/** /**
+13 -3
View File
@@ -1,7 +1,7 @@
/* Misc. utility functions and C-library extensions for finit and its plugins /* Misc. utility functions and C-library extensions for finit and its plugins
* *
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com> * Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2012 Joachim Nilsson <troglobit@gmail.com> * Copyright (c) 2008-2014 Joachim Nilsson <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -42,7 +42,16 @@
#ifndef touch #ifndef touch
# define touch(x) mknod((x), S_IFREG|0644, 0) # define touch(x) do { if (mknod((x), S_IFREG|0644, 0) && errno != EEXIST) _pe("Failed creating %s", x); } while (0)
#endif
#ifndef makedir
# define makedir(x, p) do { if (mkdir(x, p) && errno != EEXIST) _pe("Failed creating directory %s", x); } while (0)
#endif
#ifndef makefifo
# define makefifo(x, p) do { if (mkfifo(x, p) && errno != EEXIST) _pe("Failed creating FIFO %s", x); } while (0)
#endif
#ifndef erase
# define erase(x) do { if (remove(x) && errno != ENOENT) _pe("Failed removing %s", x); } while (0)
#endif #endif
#ifndef chardev #ifndef chardev
# define chardev(x,m,maj,min) mknod((x), S_IFCHR|(m), makedev((maj),(min))) # define chardev(x,m,maj,min) mknod((x), S_IFCHR|(m), makedev((maj),(min)))
@@ -93,6 +102,7 @@ char *pid_get_name (pid_t pid, char *name, size_t len);
void procname_set (char *name, char *args[]); void procname_set (char *name, char *args[]);
int procname_kill (char *name, int signo); int procname_kill (char *name, int signo);
void print (int action, const char *fmt, ...);
void print_desc (char *action, char *desc); void print_desc (char *action, char *desc);
int print_result (int fail); int print_result (int fail);
int start_process (char *cmd, char *args[], int console); int start_process (char *cmd, char *args[], int console);
@@ -100,7 +110,7 @@ void chomp (char *str);
void do_sleep (unsigned int sec); void do_sleep (unsigned int sec);
int getuser (char *username); int getuser (char *username);
int getgroup (char *group); int getgroup (char *group);
void set_hostname (char *hostname); void set_hostname (char **hostname);
int complete (char *cmd, int pid); int complete (char *cmd, int pid);
int run (char *cmd); int run (char *cmd);
+1 -1
View File
@@ -1,6 +1,6 @@
# Finit libite -- Light-weight utility functions and C-library extensions # Finit libite -- Light-weight utility functions and C-library extensions
# #
# Copyright (c) 2008-2012 Joachim Nilsson <troglobit@gmail.com> # Copyright (c) 2008-2014 Joachim Nilsson <troglobit@gmail.com>
# #
# Permission is hereby granted, free of charge, to any person obtaining a copy # Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal # of this software and associated documentation files (the "Software"), to deal
+109 -50
View File
@@ -34,13 +34,14 @@
#include "lite.h" #include "lite.h"
static int __isdir_and_append_filename(char *src, char **dst); static int adjust_target(char *src, char **dst);
/** /**
* copyfile - Copy a file to another. * copyfile - Copy a file to another.
* @src: Source file. * @src: Source file.
* @dst: Target file. * @dst: Target file.
* @len: Number of bytes to copy, zero (0) for entire file. * @len: Number of bytes to copy, zero (0) for entire file.
* @sym: Should symlinks be recreated (1) or followed (0)
* *
* This is a C implementation of the command line cp(1) utility. It is one * This is a C implementation of the command line cp(1) utility. It is one
* of the classic missing links in the UNIX C library. This version is from * of the classic missing links in the UNIX C library. This version is from
@@ -54,58 +55,70 @@ static int __isdir_and_append_filename(char *src, char **dst);
* may also indicate that @src was empty. If @src is a directory errno * may also indicate that @src was empty. If @src is a directory errno
* will be set to %EISDIR since copyfile() is not recursive. * will be set to %EISDIR since copyfile() is not recursive.
*/ */
ssize_t copyfile(char *src, char *dst, int len) ssize_t copyfile(char *src, char *dst, int len, int sym)
{ {
char *buffer; char *buffer;
int s, d, n, isdir = 0, saved_errno = 0; int in, out, isdir = 0, saved_errno = 0;
ssize_t size = 0; ssize_t num, size = 0;
errno = 0; /* Reset before leaving this function. */ errno = 0;
// fprintf (stderr, "%s() src: %s, dst: %s, len: %d\n", __func__, src, dst, len);
buffer = malloc(BUFSIZ); buffer = malloc(BUFSIZ);
if (!buffer) if (!buffer)
return 0; return 0;
if (fisdir(src)) { if (fisdir(src)) {
errno = EISDIR; /* Error: source is a directory */ saved_errno = EISDIR; /* Error: source is a directory */
return 0; goto exit;
} }
/* Check if target is a directory, then append the src base filename. */ /* Check if target is a directory, then append src filename. */
isdir = __isdir_and_append_filename(src, &dst); isdir = adjust_target(src, &dst);
/* Len == 0 means copy entire file */ if (sym) {
if (len == 0) { size = readlink(src, buffer, BUFSIZ);
/* XXX: This feels a bit unsafe, but 2047 MiB may be sufficient for us. if (size > 0) {
* --Jocke 2008-08-11 */ if (size >= (ssize_t) BUFSIZ) {
len = INT_MAX; saved_errno = ENOBUFS;
} goto exit;
if ((s = open(src, O_RDONLY)) >= 0) {
if ((d =
open(dst, O_WRONLY | O_CREAT | O_TRUNC,
fmode(src))) >= 0) {
do {
int clen = len > BUFSIZ ? BUFSIZ : len;
if ((n = read(s, buffer, clen)) > 0) {
size += write(d, buffer, n);
}
len -= clen;
} }
while (len > 0 && n == BUFSIZ);
close(d); buffer[size] = 0;
} else { size = !symlink(buffer, dst);
saved_errno = errno; goto exit;
} }
close(s);
} else {
saved_errno = errno;
} }
/* 0: copy entire file */
if (len == 0)
len = INT_MAX; /* XXX: 2047 MiB should sufficient ... */
in = open(src, O_RDONLY);
if (in < 0) {
saved_errno = errno;
goto exit;
}
out = open(dst, O_WRONLY | O_CREAT | O_TRUNC, fmode(src));
if (out < 0) {
close(in);
saved_errno = errno;
goto exit;
}
do {
int clen = len > BUFSIZ ? BUFSIZ : len;
num = read(in, buffer, clen);
if (num > 0)
size += write(out, buffer, num);
len -= clen;
} while (len > 0 && num == BUFSIZ);
close(out);
close(in);
exit:
free(buffer); free(buffer);
if (isdir) if (isdir)
free(dst); free(dst);
@@ -135,12 +148,12 @@ int movefile(char *src, char *dst)
int isdir, result = 0; int isdir, result = 0;
/* Check if target is a directory, then append the src base filename. */ /* Check if target is a directory, then append the src base filename. */
isdir = __isdir_and_append_filename(src, &dst); isdir = adjust_target(src, &dst);
if (rename(src, dst)) { if (rename(src, dst)) {
if (errno == EXDEV) { if (errno == EXDEV) {
errno = 0; errno = 0;
copyfile(src, dst, 0); copyfile(src, dst, 0, 0);
if (errno) if (errno)
result = 1; result = 1;
else else
@@ -170,27 +183,30 @@ int movefile(char *src, char *dst)
int copy_filep(FILE *src, FILE *dst) int copy_filep(FILE *src, FILE *dst)
{ {
int result = 0; int result = 0;
char *buf = (char *)malloc(BUFSIZ); char *buf;
if (!src || !dst) if (!src || !dst)
return EINVAL; return EINVAL;
buf = (char *)malloc(BUFSIZ);
if (!buf) if (!buf)
return errno; return errno;
while (1) { while (1) {
errno = 0; errno = 0;
if (!fgets(buf, BUFSIZ, src)) { if (!fgets(buf, BUFSIZ, src)) {
if (errno == EINTR) { if (errno == EINTR) {
clearerr(src); clearerr(src);
continue; continue;
} }
if (feof(src)) if (feof(src))
break; break;
result = errno; result = errno;
goto exit; goto exit;
} }
while (EOF == fputs(buf, dst)) { while (EOF == fputs(buf, dst)) {
if (errno == EINTR) { if (errno == EINTR) {
clearerr(dst); clearerr(dst);
@@ -202,13 +218,58 @@ int copy_filep(FILE *src, FILE *dst)
} }
} }
exit: exit:
free(buf); free(buf);
return errno = result; return errno = result;
} }
/**
* fsendfile - copy data between file streams
* @out: Destination stream
* @in: Source stream
* @sz: Size in bytes to copy.
*
* @out may be NULL, in which case @sz bytes are read and discarded
* from @in. This is useful for streams where seeks are not
* permitted. Additionally @sz may be the special value zero (0) in
* which case fsendfile will copy until EOF is seen on @src.
*
* Returns:
* The number of bytes copied. If there was an error, -1 is returned
* and errno will be set accordingly.
*/
size_t fsendfile (FILE *out, FILE *in, size_t sz)
{
char *buf;
size_t blk = BUFSIZ, num = 0, tot = 0;
buf = (char *)malloc(BUFSIZ);
if (!buf)
return -1;
while (!sz || tot < sz) {
if (sz && ((sz - tot) < BUFSIZ))
blk = sz - tot;
num = fread(buf, 1, blk, in);
if (num == 0)
break;
if (out && (fwrite(buf, num, 1, out) != 1)) {
num = -1;
break;
}
tot += num;
}
free(buf);
return (num == (size_t)-1) ? (size_t)-1 : tot;
}
/* Tests if dst is a directory, if so, reallocates dst and appends src filename returning 1 */ /* Tests if dst is a directory, if so, reallocates dst and appends src filename returning 1 */
static int __isdir_and_append_filename(char *src, char **dst) static int adjust_target(char *src, char **dst)
{ {
int isdir = 0; int isdir = 0;
@@ -221,7 +282,6 @@ static int __isdir_and_append_filename(char *src, char **dst)
else else
ptr++; ptr++;
// fprintf (stderr, "Yes %s is a dir --> add %s\n", *dst, ptr);
tmp = malloc(strlen(*dst) + strlen(ptr) + 2); tmp = malloc(strlen(*dst) + strlen(ptr) + 2);
if (!tmp) { if (!tmp) {
errno = EISDIR; errno = EISDIR;
@@ -233,7 +293,6 @@ static int __isdir_and_append_filename(char *src, char **dst)
sprintf(tmp, "%s%s%s", *dst, slash ? "" : "/", ptr); sprintf(tmp, "%s%s%s", *dst, slash ? "" : "/", ptr);
*dst = tmp; *dst = tmp;
// fprintf (stderr, "NEW DST:%s\n", *dst);
} }
return isdir; return isdir;
@@ -254,7 +313,7 @@ int main(int argc, char *argv[])
printf("Copying file %s to %s\n", argv[1], argv[2]); printf("Copying file %s to %s\n", argv[1], argv[2]);
return copyfile(argv[1], argv[2], 0); return copyfile(argv[1], argv[2], 0, 0);
} }
#else #else
int main(void) int main(void)
@@ -285,7 +344,7 @@ int main(void)
if (fexist(files[i + 2])) if (fexist(files[i + 2]))
fprintf(stderr, "OK => %s\n", files[i + 2]); fprintf(stderr, "OK => %s\n", files[i + 2]);
remove(files[i + 2]); erase(files[i + 2]);
i += 3; i += 3;
} }
@@ -293,13 +352,13 @@ int main(void)
i = 0; i = 0;
while (files[i]) { while (files[i]) {
fprintf(stderr, "copyfile(%s, %s)\t", files[i], files[i + 1]); fprintf(stderr, "copyfile(%s, %s)\t", files[i], files[i + 1]);
if (!copyfile(files[i], files[i + 1], 0)) if (!copyfile(files[i], files[i + 1], 0, 0))
perror("Failed"); perror("Failed");
if (fexist(files[i + 2])) if (fexist(files[i + 2]))
fprintf(stderr, "OK => %s\n", files[i + 2]); fprintf(stderr, "OK => %s\n", files[i + 2]);
remove(files[i + 2]); erase(files[i + 2]);
i += 3; i += 3;
} }
@@ -312,7 +371,7 @@ int main(void)
* Local Variables: * Local Variables:
* compile-command: "gcc -g -I../include -o unittest -DUNITTEST copyfile.c && ./unittest" * compile-command: "gcc -g -I../include -o unittest -DUNITTEST copyfile.c && ./unittest"
* version-control: t * version-control: t
* kept-new-versions: 2 * indent-tabs-mode: t
* c-file-style: "ellemtel" * c-file-style: "linux"
* End: * End:
*/ */
+3 -3
View File
@@ -1,6 +1,6 @@
/* Functions for operating on files in directories. /* Functions for operating on files in directories.
* *
* Copyright (c) 2008-2012 Joachim Nilsson <troglobit@gmail.com> * Copyright (c) 2008-2014 Joachim Nilsson <troglobit@gmail.com>
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -142,13 +142,13 @@ int simulate_files(int creat)
if (creat) if (creat)
touch(files[i]); touch(files[i]);
else else
remove(files[i]); erase(files[i]);
} }
if (creat) if (creat)
symlink("config2.cfg", STARTUP_CONFIG); symlink("config2.cfg", STARTUP_CONFIG);
else else
remove(STARTUP_CONFIG); erase(STARTUP_CONFIG);
return 0; return 0;
} }
+33 -2
View File
@@ -1,7 +1,7 @@
/* Collection of utility funcs and C library extensions for finit & its plugins /* Collection of utility funcs and C library extensions for finit & its plugins
* *
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com> * Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2012 Joachim Nilsson <troglobit@gmail.com> * Copyright (c) 2008-2014 Joachim Nilsson <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -29,15 +29,17 @@
#include <string.h> #include <string.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/param.h> /* MAX(), isset(), setbit(), TRUE, FALSE, et consortes. :-) */
#include <unistd.h> #include <unistd.h>
int fexist (char *file); int fexist (char *file);
int fisdir (char *file); int fisdir (char *file);
mode_t fmode (char *file); mode_t fmode (char *file);
ssize_t copyfile (char *src, char *dst, int len); ssize_t copyfile (char *src, char *dst, int len, int sym);
int movefile (char *src, char *dst); int movefile (char *src, char *dst);
int copy_filep (FILE *src, FILE *dst); int copy_filep (FILE *src, FILE *dst);
size_t fsendfile (FILE *out, FILE *in, size_t sz);
int dir (const char *dir, const char *type, int (*filter) (const char *file), char ***list, int strip); int dir (const char *dir, const char *type, int (*filter) (const char *file), char ***list, int strip);
int rsync (char *src, char *dst, int delete, int (*filter) (const char *file)); int rsync (char *src, char *dst, int delete, int (*filter) (const char *file));
@@ -59,6 +61,35 @@ static inline int fisslashdir(char *dir)
return 0; return 0;
} }
/* Validate string, non NULL and not zero length */
static inline int string_valid (const char *s)
{
return s && strlen (s);
}
/* Relaxed comparison, e.g., sys_string_match("small", "smaller") => TRUE */
static inline int string_match (const char *a, const char *b)
{
size_t min = MIN(strlen (a), strlen (b));
return !strncasecmp (a, b, min);
}
/* Strict comparison, e.g., sys_string_match("small", "smaller") => FALSE */
static inline int string_compare (const char *a, const char *b)
{
return strlen (a) == strlen (b) && !strcmp (a, b);
}
/* Strict comparison, like sys_string_compare(), but case insensitive,
* e.g., sys_string_match("small", "SmAlL") => TRUE
*/
static inline int string_case_compare (const char *a, const char *b)
{
return strlen (a) == strlen (b) && !strcasecmp (a, b);
}
#endif /* FINIT_LITE_H_ */ #endif /* FINIT_LITE_H_ */
/** /**
+44 -31
View File
@@ -27,7 +27,8 @@
#include "lite.h" #include "lite.h"
#include "../helpers.h" #include "../helpers.h"
static int makedir(char *buf, size_t buf_len, char *dir, char *name, mode_t mode); static int copy(char *src, char *dst);
static int mdir(char *buf, size_t buf_len, char *dir, char *name, mode_t mode);
static int prune(char *dst, char **new_files, int new_num); static int prune(char *dst, char **new_files, int new_num);
@@ -58,26 +59,16 @@ int rsync(char *src, char *dst, int delete, int (*filter) (const char *file))
int i = 0, num = 0, result = 0; int i = 0, num = 0, result = 0;
char **files; /* Array of file names. */ char **files; /* Array of file names. */
void copy(char *src, char *dst)
{
errno = 0;
copyfile(src, dst, 0);
if (errno) {
if (errno == EEXIST)
errno = 0;
else
result++;
}
}
if (!fisdir(dst)) if (!fisdir(dst))
mkdir(dst, 0755); makedir(dst, 0755);
if (!fisdir(src)) { if (!fisdir(src)) {
if (!fexist(src)) if (!fexist(src))
return 1; return 1;
copy(src, dst); if (copy(src, dst))
result++;
return errno; return errno;
} }
@@ -90,7 +81,7 @@ int rsync(char *src, char *dst, int delete, int (*filter) (const char *file))
else else
ptr++; ptr++;
if (makedir(dest, sizeof(dest), dst, ptr, fmode(src))) if (mdir(dest, sizeof(dest), dst, ptr, fmode(src)))
return 1; return 1;
dst = dest; dst = dest;
} }
@@ -103,7 +94,7 @@ int rsync(char *src, char *dst, int delete, int (*filter) (const char *file))
char dst2[256]; char dst2[256];
strcat(source, "/"); strcat(source, "/");
if (makedir (dst2, sizeof(dst2), dst, files[i], fmode(source))) { if (mdir (dst2, sizeof(dst2), dst, files[i], fmode(source))) {
result++; result++;
continue; continue;
} }
@@ -111,7 +102,9 @@ int rsync(char *src, char *dst, int delete, int (*filter) (const char *file))
rsync(source, dst2, delete, filter); rsync(source, dst2, delete, filter);
continue; /* Next file/dir in @src to copy... */ continue; /* Next file/dir in @src to copy... */
} }
copy(source, dst);
if (copy(source, dst))
result++;
} }
/* We ignore any errors from the pruning, that phase albeit useful is only /* We ignore any errors from the pruning, that phase albeit useful is only
@@ -128,8 +121,23 @@ int rsync(char *src, char *dst, int delete, int (*filter) (const char *file))
return result; return result;
} }
static int copy(char *src, char *dst)
{
errno = 0;
copyfile(src, dst, 0, 1);
if (errno) {
if (errno != EEXIST)
return 1;
errno = 0;
}
return 0;
}
/* Creates dir/name @mode ... skipping / if dir already ends so. */ /* Creates dir/name @mode ... skipping / if dir already ends so. */
static int makedir(char *buf, size_t buf_len, char *dir, char *name, mode_t mode) static int mdir(char *buf, size_t buf_len, char *dir, char *name, mode_t mode)
{ {
snprintf(buf, buf_len, "%s%s%s/", dir, fisslashdir(dir) ? "" : "/", name); snprintf(buf, buf_len, "%s%s%s/", dir, fisslashdir(dir) ? "" : "/", name);
if (mkdir(buf, mode)) { if (mkdir(buf, mode)) {
@@ -142,26 +150,31 @@ static int makedir(char *buf, size_t buf_len, char *dir, char *name, mode_t mode
return 0; return 0;
} }
static int find(char *file, char **files, int num)
{
int n;
for (n = 0; n < num; n++)
if (!strncmp (files[n], file, MAX(strlen(files[n]), strlen(file))))
return 1;
return 0;
}
/* Prune old files, no longer existing on source, from destination directory. */ /* Prune old files, no longer existing on source, from destination directory. */
static int prune(char *dst, char **new_files, int new_num) static int prune(char *dst, char **new_files, int new_num)
{ {
int i, num, result = 0; int num, result = 0;
char **files; char **files;
int find(char *file) {
int n;
for (n = 0; n < new_num; n++)
if (!strncmp (new_files[n], file, MAX(strlen(new_files[n]), strlen(file))))
return 1;
return 0;
}
num = dir(dst, "", NULL, &files, 0); num = dir(dst, "", NULL, &files, 0);
if (num) { if (num) {
int i;
for (i = 0; i < num; i++) { for (i = 0; i < num; i++) {
if (!find(files[i])) { if (!find(files[i], new_files, new_num)) {
char *name; char *name;
size_t len = strlen(files[i]) + 2 + strlen(dst); size_t len = strlen(files[i]) + 2 + strlen(dst);
+4 -1
View File
@@ -159,7 +159,7 @@ plugin_t *plugin_find(char *name)
SEARCH_PLUGIN(name); SEARCH_PLUGIN(name);
if (name[0] != '/') { if (plugpath && name[0] != '/') {
int noext; int noext;
char path[CMD_SIZE]; char path[CMD_SIZE];
@@ -280,6 +280,9 @@ static int load_one(char *path, char *name)
snprintf(plugin, sizeof(plugin), "%s/%s%s", path, name, noext ? ".so" : ""); snprintf(plugin, sizeof(plugin), "%s/%s%s", path, name, noext ? ".so" : "");
_d("Loading plugin %s ...", basename(plugin)); _d("Loading plugin %s ...", basename(plugin));
/* Ignore leak, we do not support unloading of plugins atm.
* TODO: Add handle to list of loaded plugins, dlclose() on
* plugin_unregister() */
handle = dlopen(plugin, RTLD_LAZY | RTLD_GLOBAL); handle = dlopen(plugin, RTLD_LAZY | RTLD_GLOBAL);
if (!handle) { if (!handle) {
_e("Failed loading plugin %s: %s", plugin, dlerror()); _e("Failed loading plugin %s: %s", plugin, dlerror());
+21 -22
View File
@@ -39,25 +39,24 @@ static void setup(void *UNUSED(arg))
#endif #endif
_d("Setting up FHS structure in /var ..."); _d("Setting up FHS structure in /var ...");
mkdir("/var/cache", 0755); makedir("/var/cache", 0755);
mkdir("/var/games", 0755); makedir("/var/games", 0755);
mkdir("/var/lib", 0755); makedir("/var/lib", 0755);
mkdir("/var/lib/misc", 0755); makedir("/var/lib/misc", 0755);
mkdir("/var/lib/alarm", 0755); makedir("/var/lib/alarm", 0755);
mkdir("/var/lock", 0755); makedir("/var/lock", 0755);
mkdir("/var/log", 0755); makedir("/var/log", 0755);
mkdir("/var/mail", 0755); makedir("/var/mail", 0755);
mkdir("/var/opt", 0755); makedir("/var/opt", 0755);
mkdir("/var/run", 0755); makedir("/var/run", 0755);
mkdir("/var/spool", 0755); makedir("/var/spool", 0755);
mkdir("/var/spool/cron", 0755); makedir("/var/spool/cron", 0755);
mkdir("/var/tmp", 0755); makedir("/var/tmp", 0755);
mkdir("/var/empty", 0755); makedir("/var/empty", 0755);
_d("Setting up necessary UTMP files ..."); _d("Setting up necessary UTMP files ...");
touch("/var/run/utmp"); touch("/var/run/utmp");
chown("/var/run/utmp", 0, getgroup("utmp")); chown("/var/run/utmp", 0, getgroup("utmp"));
chmod("/var/run/utmp", 0664);
#ifdef RUNLEVEL #ifdef RUNLEVEL
memset(&entry, 0, sizeof(struct utmp)); memset(&entry, 0, sizeof(struct utmp));
@@ -71,16 +70,16 @@ static void setup(void *UNUSED(arg))
#ifdef TOUCH_ETC_NETWORK_RUN_IFSTATE #ifdef TOUCH_ETC_NETWORK_RUN_IFSTATE
touch("/etc/network/run/ifstate"); touch("/etc/network/run/ifstate");
#else #else
remove("/etc/network/run/ifstate"); erase("/etc/network/run/ifstate");
#endif #endif
_d("Setting up misc files ..."); _d("Setting up misc files ...");
mkdir("/var/run/lldpd", 0755); /* Needed by lldpd */ makedir("/var/run/lldpd", 0755); /* Needed by lldpd */
mkdir("/var/run/pluto", 0755); /* Needed by Openswan */ makedir("/var/run/pluto", 0755); /* Needed by Openswan */
mkdir("/var/run/quagga", 0755); /* Needed by Quagga */ makedir("/var/run/quagga", 0755); /* Needed by Quagga */
mkdir("/var/log/quagga", 0755); /* Needed by Quagga */ makedir("/var/log/quagga", 0755); /* Needed by Quagga */
mkdir("/var/run/sshd", 01755); /* OpenSSH */ makedir("/var/run/sshd", 01755); /* OpenSSH */
mkfifo("/dev/xconsole", 0640); /* sysklogd */ makefifo("/dev/xconsole", 0640); /* sysklogd */
chown("/dev/xconsole", 0, getgroup("tty")); chown("/dev/xconsole", 0, getgroup("tty"));
} }
+3 -3
View File
@@ -29,10 +29,10 @@ static void setup(void *UNUSED(arg))
{ {
#ifdef HAVE_DBUS #ifdef HAVE_DBUS
_d("Starting D-Bus ..."); _d("Starting D-Bus ...");
mkdir("/var/run/dbus", 0755); makedir("/var/run/dbus", 0755);
mkdir("/var/lock/subsys/messagebus", 0755); makedir("/var/lock/subsys/messagebus", 0755);
run("dbus-uuidgen --ensure"); run("dbus-uuidgen --ensure");
remove("/var/run/dbus/pid"); erase("/var/run/dbus/pid");
run_interactive("dbus-daemon --system", "Starting D-Bus"); run_interactive("dbus-daemon --system", "Starting D-Bus");
#endif #endif
} }
+2 -2
View File
@@ -1,7 +1,7 @@
/* Optional /dev/initctl FIFO monitor /* Optional /dev/initctl FIFO monitor
* *
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com> * Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2012 Joachim Nilsson <troglobit@gmail.com> * Copyright (c) 2008-2014 Joachim Nilsson <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -124,7 +124,7 @@ static void parse(void *UNUSED(arg), int fd, int UNUSED(events))
PLUGIN_INIT(plugin_init) PLUGIN_INIT(plugin_init)
{ {
_d("Setting up %s", FINIT_FIFO); _d("Setting up %s", FINIT_FIFO);
mkfifo(FINIT_FIFO, 0600); makefifo(FINIT_FIFO, 0600);
fifo_open(); fifo_open();
plugin_register(&plugin); plugin_register(&plugin);
+3 -3
View File
@@ -36,7 +36,7 @@ static void setup(void *UNUSED(arg))
#endif #endif
char line[LINE_SIZE]; char line[LINE_SIZE];
makepath("/var/run/console"); makedir("/var/run/console", 01777);
snprintf(line, sizeof(line), "/var/run/console/%s", username); snprintf(line, sizeof(line), "/var/run/console/%s", username);
touch(line); touch(line);
@@ -48,8 +48,8 @@ static void setup(void *UNUSED(arg))
} }
#endif #endif
mkdir("/tmp/.X11-unix", 01777); makedir("/tmp/.X11-unix", 01777);
mkdir("/tmp/.ICE-unix", 01777); makedir("/tmp/.ICE-unix", 01777);
} }
static plugin_t plugin = { static plugin_t plugin = {
+83 -3
View File
@@ -1,4 +1,4 @@
/* $OpenBSD: queue.h,v 1.36 2012/04/11 13:29:14 naddy Exp $ */ /* $OpenBSD: queue.h,v 1.38 2013/07/03 15:05:21 fgsch Exp $ */
/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */ /* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */
/* /*
@@ -316,6 +316,86 @@ struct { \
(head)->sqh_last = &(elm)->field.sqe_next; \ (head)->sqh_last = &(elm)->field.sqe_next; \
} while (0) } while (0)
/*
* XOR Simple queue definitions.
*/
#define XSIMPLEQ_HEAD(name, type) \
struct name { \
struct type *sqx_first; /* first element */ \
struct type **sqx_last; /* addr of last next element */ \
unsigned long sqx_cookie; \
}
#define XSIMPLEQ_ENTRY(type) \
struct { \
struct type *sqx_next; /* next element */ \
}
/*
* XOR Simple queue access methods.
*/
#define XSIMPLEQ_XOR(head, ptr) ((__typeof(ptr))((head)->sqx_cookie ^ \
(unsigned long)(ptr)))
#define XSIMPLEQ_FIRST(head) XSIMPLEQ_XOR(head, ((head)->sqx_first))
#define XSIMPLEQ_END(head) NULL
#define XSIMPLEQ_EMPTY(head) (XSIMPLEQ_FIRST(head) == XSIMPLEQ_END(head))
#define XSIMPLEQ_NEXT(head, elm, field) XSIMPLEQ_XOR(head, ((elm)->field.sqx_next))
#define XSIMPLEQ_FOREACH(var, head, field) \
for ((var) = XSIMPLEQ_FIRST(head); \
(var) != XSIMPLEQ_END(head); \
(var) = XSIMPLEQ_NEXT(head, var, field))
#define XSIMPLEQ_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = XSIMPLEQ_FIRST(head); \
(var) && ((tvar) = XSIMPLEQ_NEXT(head, var, field), 1); \
(var) = (tvar))
/*
* XOR Simple queue functions.
*/
#define XSIMPLEQ_INIT(head) do { \
arc4random_buf(&(head)->sqx_cookie, sizeof((head)->sqx_cookie)); \
(head)->sqx_first = XSIMPLEQ_XOR(head, NULL); \
(head)->sqx_last = XSIMPLEQ_XOR(head, &(head)->sqx_first); \
} while (0)
#define XSIMPLEQ_INSERT_HEAD(head, elm, field) do { \
if (((elm)->field.sqx_next = (head)->sqx_first) == \
XSIMPLEQ_XOR(head, NULL)) \
(head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \
(head)->sqx_first = XSIMPLEQ_XOR(head, (elm)); \
} while (0)
#define XSIMPLEQ_INSERT_TAIL(head, elm, field) do { \
(elm)->field.sqx_next = XSIMPLEQ_XOR(head, NULL); \
*(XSIMPLEQ_XOR(head, (head)->sqx_last)) = XSIMPLEQ_XOR(head, (elm)); \
(head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \
} while (0)
#define XSIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
if (((elm)->field.sqx_next = (listelm)->field.sqx_next) == \
XSIMPLEQ_XOR(head, NULL)) \
(head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \
(listelm)->field.sqx_next = XSIMPLEQ_XOR(head, (elm)); \
} while (0)
#define XSIMPLEQ_REMOVE_HEAD(head, field) do { \
if (((head)->sqx_first = XSIMPLEQ_XOR(head, \
(head)->sqx_first)->field.sqx_next) == XSIMPLEQ_XOR(head, NULL)) \
(head)->sqx_last = XSIMPLEQ_XOR(head, &(head)->sqx_first); \
} while (0)
#define XSIMPLEQ_REMOVE_AFTER(head, elm, field) do { \
if (((elm)->field.sqx_next = XSIMPLEQ_XOR(head, \
(elm)->field.sqx_next)->field.sqx_next) \
== XSIMPLEQ_XOR(head, NULL)) \
(head)->sqx_last = \
XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \
} while (0)
/* /*
* Tail queue definitions. * Tail queue definitions.
*/ */
@@ -553,12 +633,12 @@ struct { \
#define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \ #define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \
if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \ if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \
CIRCLEQ_END(head)) \ CIRCLEQ_END(head)) \
(head).cqh_last = (elm2); \ (head)->cqh_last = (elm2); \
else \ else \
(elm2)->field.cqe_next->field.cqe_prev = (elm2); \ (elm2)->field.cqe_next->field.cqe_prev = (elm2); \
if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \ if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \
CIRCLEQ_END(head)) \ CIRCLEQ_END(head)) \
(head).cqh_first = (elm2); \ (head)->cqh_first = (elm2); \
else \ else \
(elm2)->field.cqe_prev->field.cqe_next = (elm2); \ (elm2)->field.cqe_prev->field.cqe_next = (elm2); \
_Q_INVALIDATE((elm)->field.cqe_prev); \ _Q_INVALIDATE((elm)->field.cqe_prev); \
+4 -4
View File
@@ -1,7 +1,7 @@
/* Signal management - Be conservative with what finit responds to! /* Signal management - Be conservative with what finit responds to!
* *
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com> * Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2012 Joachim Nilsson <troglobit@gmail.com> * Copyright (c) 2008-2014 Joachim Nilsson <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -117,7 +117,7 @@ static void sigcont_handler(int sig, siginfo_t *info, void *UNUSED(ctx))
_d("Received SIGCONT(%d) from %s (PID %d)", _d("Received SIGCONT(%d) from %s (PID %d)",
sig, pid_get_name(info->si_pid, NULL, 0), info->si_pid); sig, pid_get_name(info->si_pid, NULL, 0), info->si_pid);
stopped = 0; stopped = 0;
remove(SYNC_STOPPED); erase(SYNC_STOPPED);
} }
/* /*
@@ -152,8 +152,8 @@ void sig_setup(void)
_d("Setup signals"); _d("Setup signals");
/* Cleanup any stale finit control files */ /* Cleanup any stale finit control files */
remove(SYNC_SHUTDOWN); erase(SYNC_SHUTDOWN);
remove(SYNC_STOPPED); erase(SYNC_STOPPED);
/* Standard SysV init calls ctrl-alt-delete handler */ /* Standard SysV init calls ctrl-alt-delete handler */
SETSIG(sa, SIGINT, shutdown_handler, 0); SETSIG(sa, SIGINT, shutdown_handler, 0);
+1 -1
View File
@@ -1,7 +1,7 @@
/* Signal management - Be conservative with what finit responds to! /* Signal management - Be conservative with what finit responds to!
* *
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com> * Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2012 Joachim Nilsson <troglobit@gmail.com> * Copyright (c) 2008-2014 Joachim Nilsson <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
+53 -26
View File
@@ -37,6 +37,7 @@
/* The registered services are kept in shared memory for easy read-only access /* The registered services are kept in shared memory for easy read-only access
* by 3rd party APIs. Mostly because of the ability to, from the outside, query * by 3rd party APIs. Mostly because of the ability to, from the outside, query
* liveness state of all daemons that should run. */ * liveness state of all daemons that should run. */
static int was_stopped = 0;
static int svc_counter = 0; /* Number of registered services to monitor. */ static int svc_counter = 0; /* Number of registered services to monitor. */
static svc_t *services = NULL; /* List of registered services, in shared memory. */ static svc_t *services = NULL; /* List of registered services, in shared memory. */
@@ -132,26 +133,28 @@ svc_t *svc_iterator(int restart)
void svc_bootstrap(void) void svc_bootstrap(void)
{ {
svc_t *svc; svc_t *svc;
svc_cmd_t cmd;
_d("Bootstrapping all services in runlevel S from %s", FINIT_CONF); _d("Bootstrapping all services in runlevel S from %s", FINIT_CONF);
for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) { for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
cmd = svc_enabled(svc, 0, NULL); svc_cmd_t cmd = svc_enabled(svc, 0, NULL);
if (SVC_START == cmd || (SVC_RELOAD == cmd)) if (SVC_START == cmd || (SVC_RELOAD == cmd))
svc_start(svc); svc_start(svc);
} }
} }
static int encode(int lvl)
{
if (!lvl)
return 0;
return lvl + '0';
}
static void utmp_save(int pre, int now) static void utmp_save(int pre, int now)
{ {
struct utmp utent; struct utmp utent;
int encode(int lvl)
{
if (!lvl) return 0;
return lvl + '0';
}
utent.ut_type = RUN_LVL; utent.ut_type = RUN_LVL;
utent.ut_pid = (encode(pre) << 8) | (encode(now) & 0xFF); utent.ut_pid = (encode(pre) << 8) | (encode(now) & 0xFF);
strlcpy(utent.ut_user, "runlevel", sizeof(utent.ut_user)); strlcpy(utent.ut_user, "runlevel", sizeof(utent.ut_user));
@@ -188,6 +191,8 @@ void svc_runlevel(int newlevel)
if (svc->pid) { if (svc->pid) {
if (run == SVC_STOP) if (run == SVC_STOP)
svc_stop(svc); svc_stop(svc);
else if (run == SVC_RELOAD)
svc_reload(svc);
} else { } else {
if (run == SVC_START) if (run == SVC_START)
svc_start(svc); svc_start(svc);
@@ -206,7 +211,7 @@ void svc_runlevel(int newlevel)
if (runlevel == 1) if (runlevel == 1)
touch("/etc/nologin"); /* Disable login in single-user mode */ touch("/etc/nologin"); /* Disable login in single-user mode */
else else
remove("/etc/nologin"); erase("/etc/nologin");
if (0 != prevlevel) if (0 != prevlevel)
tty_runlevel(runlevel); tty_runlevel(runlevel);
@@ -345,11 +350,29 @@ static int is_norespawn(void)
fexist("/tmp/norespawn"); fexist("/tmp/norespawn");
} }
static void restart_any_lost_procs(void)
{
svc_t *svc;
for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
if (svc->pid > 0 && pid_alive(svc->pid))
continue;
svc_start(svc);
}
}
void svc_monitor(void) void svc_monitor(void)
{ {
pid_t lost; pid_t lost;
svc_t *svc; svc_t *svc;
if (was_stopped && !is_norespawn()) {
was_stopped = 0;
restart_any_lost_procs();
return;
}
lost = waitpid(-1, NULL, WNOHANG); lost = waitpid(-1, NULL, WNOHANG);
if (lost < 1) if (lost < 1)
return; return;
@@ -358,8 +381,10 @@ void svc_monitor(void)
return; return;
/* Power user at the console, don't respawn tasks. */ /* Power user at the console, don't respawn tasks. */
if (is_norespawn()) if (is_norespawn()) {
was_stopped = 1;
return; return;
}
if (tty_respawn(lost)) if (tty_respawn(lost))
return; return;
@@ -400,13 +425,13 @@ void svc_monitor(void)
/* Remember: svc_enabled() must be called before calling svc_start() */ /* Remember: svc_enabled() must be called before calling svc_start() */
int svc_start(svc_t *svc) int svc_start(svc_t *svc)
{ {
int respawn = svc->pid != 0; int respawn;
pid_t pid; pid_t pid;
sigset_t nmask, omask; sigset_t nmask, omask;
char *args[MAX_NUM_SVC_ARGS];
if (!svc) if (!svc)
return 0; return 0;
respawn = svc->pid != 0;
/* Don't try and start service if it doesn't exist. */ /* Don't try and start service if it doesn't exist. */
if (!fexist(svc->cmd)) { if (!fexist(svc->cmd)) {
@@ -428,24 +453,25 @@ int svc_start(svc_t *svc)
else if (!respawn) else if (!respawn)
print_desc("Starting ", svc->desc); print_desc("Starting ", svc->desc);
/* Block sigchild while forking. */ /* Block sigchild while forking. */
sigemptyset(&nmask); sigemptyset(&nmask);
sigaddset(&nmask, SIGCHLD); sigaddset(&nmask, SIGCHLD);
sigprocmask(SIG_BLOCK, &nmask, &omask); sigprocmask(SIG_BLOCK, &nmask, &omask);
pid = fork(); pid = fork();
sigprocmask(SIG_SETMASK, &omask, NULL); sigprocmask(SIG_SETMASK, &omask, NULL);
if (pid == 0) { if (pid == 0) {
int i = 0; int i = 0;
int uid = getuser(svc->username); int uid = getuser(svc->username);
struct sigaction sa; struct sigaction sa;
char *args[MAX_NUM_SVC_ARGS];
sigemptyset(&nmask); sigemptyset(&nmask);
sigaddset(&nmask, SIGCHLD); sigaddset(&nmask, SIGCHLD);
sigprocmask(SIG_UNBLOCK, &nmask, NULL); sigprocmask(SIG_UNBLOCK, &nmask, NULL);
/* Reset signal handlers that were set by the parent process */ /* Reset signal handlers that were set by the parent process */
for (i = 1; i < NSIG; i++) for (i = 1; i < NSIG; i++)
DFLSIG(sa, i, 0); DFLSIG(sa, i, 0);
/* Set desired user */ /* Set desired user */
@@ -453,7 +479,7 @@ int svc_start(svc_t *svc)
setuid(uid); setuid(uid);
/* Serve copy of args to process in case it modifies them. */ /* Serve copy of args to process in case it modifies them. */
for (i = 0; svc->args[i][0] != 0 && i < MAX_NUM_SVC_ARGS; i++) for (i = 0; i < (MAX_NUM_SVC_ARGS - 1) && svc->args[i][0] != 0; i++)
args[i] = svc->args[i]; args[i] = svc->args[i];
args[i] = NULL; args[i] = NULL;
@@ -463,11 +489,12 @@ int svc_start(svc_t *svc)
fd = open(CONSOLE, O_WRONLY | O_APPEND); fd = open(CONSOLE, O_WRONLY | O_APPEND);
if (-1 != fd) { if (-1 != fd) {
dup2(STDOUT_FILENO, fd); dup2(fd, STDOUT_FILENO);
dup2(STDERR_FILENO, fd); dup2(fd, STDERR_FILENO);
close(fd);
} }
for (i = 0; args[i] && i < MAX_NUM_SVC_ARGS; i++) { for (i = 0; i < MAX_NUM_SVC_ARGS && args[i]; i++) {
char arg[MAX_ARG_LEN]; char arg[MAX_ARG_LEN];
snprintf(arg, sizeof(arg), "%s ", args[i]); snprintf(arg, sizeof(arg), "%s ", args[i]);
+21 -20
View File
@@ -1,7 +1,7 @@
/* Finit service monitor and generic API for managing svc_t structures /* Finit service monitor and generic API for managing svc_t structures
* *
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com> * Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2012 Joachim Nilsson <troglobit@gmail.com> * Copyright (c) 2008-2014 Joachim Nilsson <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -27,6 +27,7 @@
#include <errno.h> #include <errno.h>
#include <string.h> /* strerror() */ #include <string.h> /* strerror() */
#include <sys/ipc.h> /* IPC_CREAT */
#include <sys/shm.h> /* shmat() */ #include <sys/shm.h> /* shmat() */
#include <sys/types.h> /* pid_t */ #include <sys/types.h> /* pid_t */
@@ -57,21 +58,21 @@ typedef struct svc {
pid_t pid; pid_t pid;
svc_type_t type; svc_type_t type;
int reload; int reload;
int runlevels; int runlevels;
unsigned int restart_counter; /* Incremented for each restart by service monitor. */ unsigned int restart_counter; /* Incremented for each restart by service monitor. */
char cmd[MAX_ARG_LEN]; char cmd[MAX_ARG_LEN];
char args[MAX_NUM_SVC_ARGS][MAX_ARG_LEN]; char args[MAX_NUM_SVC_ARGS][MAX_ARG_LEN];
char desc[MAX_STR_LEN]; char desc[MAX_STR_LEN];
char username[MAX_USER_LEN]; char username[MAX_USER_LEN];
/* For external plugins. If @cb is set a plugin is loaded. /* For external plugins. If @cb is set a plugin is loaded.
* @dynamic: Set by plugins that want dynamic events. * @dynamic: Set by plugins that want dynamic events.
* @dynamic_stop: Set by plugins that allow dyn. events to stop it as well. * @dynamic_stop: Set by plugins that allow dyn. events to stop it as well.
* @private: Can be used freely by plugin, e.g., to store "states". * @private: Can be used freely by plugin, e.g., to store "states".
*/ */
int dynamic; int dynamic;
int dynamic_stop; int dynamic_stop;
int private; int private;
svc_cmd_t (*cb)(struct svc *svc, int event, void *event_arg); svc_cmd_t (*cb)(struct svc *svc, int event, void *event_arg);
} svc_t; } svc_t;
@@ -80,11 +81,11 @@ typedef struct svc_map svc_map_t;
/* Put services array in shm */ /* Put services array in shm */
static inline svc_t *finit_svc_connect(void) static inline svc_t *finit_svc_connect(void)
{ {
const long ID = FINIT_SHM_ID;
static void *ptr = (void *)-1; static void *ptr = (void *)-1;
if ((void *)-1 == ptr) { if ((void *)-1 == ptr) {
ptr = shmat (shmget (ID, sizeof(svc_t) * MAX_NUM_SVC, 0600 | IPC_CREAT), NULL, 0); ptr = shmat (shmget (FINIT_SHM_ID, sizeof(svc_t) * MAX_NUM_SVC,
0600 | IPC_CREAT), NULL, 0);
if ((void *)-1 == ptr) if ((void *)-1 == ptr)
return NULL; return NULL;
} }
@@ -92,18 +93,18 @@ static inline svc_t *finit_svc_connect(void)
return (svc_t *)ptr; return (svc_t *)ptr;
} }
svc_t *svc_new (void); svc_t *svc_new (void);
svc_t *svc_find (char *name); svc_t *svc_find (char *name);
svc_t *svc_iterator (int restart); svc_t *svc_iterator (int restart);
void svc_runlevel (int newlevel); void svc_runlevel (int newlevel);
int svc_register (int type, char *line, char *username); int svc_register (int type, char *line, char *username);
int svc_id_by_name (char *name); int svc_id_by_name (char *name);
svc_cmd_t svc_enabled (svc_t *svc, int event, void *arg); svc_cmd_t svc_enabled (svc_t *svc, int event, void *arg);
int svc_start (svc_t *svc); int svc_start (svc_t *svc);
int svc_start_by_name (char *name); int svc_start_by_name (char *name);
int svc_stop (svc_t *svc); int svc_stop (svc_t *svc);
int svc_reload (svc_t *svc); int svc_reload (svc_t *svc);
#endif /* FINIT_SVC_H_ */ #endif /* FINIT_SVC_H_ */
+18 -3
View File
@@ -102,6 +102,17 @@ tty_node_t *tty_find(char *dev)
return NULL; return NULL;
} }
size_t tty_num(void)
{
size_t num = 0;
tty_node_t *entry;
LIST_FOREACH(entry, &tty_list, link)
num++;
return num;
}
tty_node_t *tty_find_by_pid(pid_t pid) tty_node_t *tty_find_by_pid(pid_t pid)
{ {
tty_node_t *entry; tty_node_t *entry;
@@ -127,13 +138,17 @@ void tty_start(finit_tty_t *tty)
if (console && !strcmp(tty->name, console)) if (console && !strcmp(tty->name, console))
is_console = 1; is_console = 1;
if (!strncmp(tty->name, _PATH_DEV, strlen(_PATH_DEV))) {
#if defined(GETTY_AGETTY) #if defined(GETTY_AGETTY)
snprintf(line, sizeof(line), "%s %s %d %s", GETTY, tty->name, tty->baud, tty->term ?: ""); snprintf(line, sizeof(line), "%s %s %d %s", GETTY, tty->name, tty->baud, tty->term ?: "");
#elif defined(GETTY_BUSYBOX) #elif defined(GETTY_BUSYBOX)
snprintf(line, sizeof(line), "%s %d %s %s", GETTY, tty->baud, tty->name, tty->term ?: ""); snprintf(line, sizeof(line), "%s %d %s %s", GETTY, tty->baud, tty->name, tty->term ?: "");
#else #else
#error No GETTY defined! strlcpy(line, FALLBACK_CONSOLE, sizeof(line));
#endif #endif
} else {
strlcpy(line, tty->name, sizeof(line));
}
cmd = strtok(line, " "); cmd = strtok(line, " ");
args[i++] = basename(cmd); args[i++] = basename(cmd);
while ((arg = strtok(NULL, " "))) while ((arg = strtok(NULL, " ")))
+9 -8
View File
@@ -32,7 +32,7 @@
typedef struct { typedef struct {
char *name; char *name;
int baud; int baud;
char *term; char *term;
int runlevels; int runlevels;
int pid; int pid;
@@ -45,14 +45,15 @@ typedef struct tty_node {
//extern LIST_HEAD(, tty_node) tty_list; //extern LIST_HEAD(, tty_node) tty_list;
int tty_register (char *line); int tty_register (char *line);
tty_node_t *tty_find (char *dev); tty_node_t *tty_find (char *dev);
size_t tty_num (void);
tty_node_t *tty_find_by_pid (pid_t pid); tty_node_t *tty_find_by_pid (pid_t pid);
void tty_start (finit_tty_t *tty); void tty_start (finit_tty_t *tty);
void tty_stop (finit_tty_t *tty); void tty_stop (finit_tty_t *tty);
int tty_enabled (finit_tty_t *tty, int runlevel); int tty_enabled (finit_tty_t *tty, int runlevel);
int tty_respawn (pid_t pid); int tty_respawn (pid_t pid);
void tty_runlevel (int runlevel); void tty_runlevel (int runlevel);
#endif /* FINIT_TTY_H_ */ #endif /* FINIT_TTY_H_ */