mirror of
https://github.com/troglobit/finit.git
synced 2026-10-12 10:12:32 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aa8d6a7294 | ||
|
|
a94dde403f | ||
|
|
9bb7e7b014 | ||
|
|
02a97e8d7d | ||
|
|
def759fe41 | ||
|
|
939cfc2476 | ||
|
|
7f2c73468f | ||
|
|
81a368f710 | ||
|
|
4e975e4974 | ||
|
|
a296c2dd00 | ||
|
|
5ff7994852 | ||
|
|
1bdcef9a2c | ||
|
|
f621117eb9 | ||
|
|
83cec7129a | ||
|
|
06b33c58fd | ||
|
|
8ce39f592c | ||
|
|
d37c451e81 | ||
|
|
a7ff1a61d5 | ||
|
|
8349909f60 | ||
|
|
3a2cf30f47 | ||
|
|
9a3cab3645 | ||
|
|
7dbc02f879 | ||
|
|
a39f75744c | ||
|
|
5742c6591a | ||
|
|
588901ee4c | ||
|
|
e30d2aae19 | ||
|
|
463e4f12f8 | ||
|
|
01c2817005 | ||
|
|
1a16aab970 | ||
|
|
8247344f0d | ||
|
|
2fdd64a2d8 | ||
|
|
22ed4e7f73 | ||
|
|
327ac9f931 | ||
|
|
5ad0c38fe8 | ||
|
|
757911f149 | ||
|
|
35b771fb42 | ||
|
|
720f1b0e5b | ||
|
|
292a3be515 | ||
|
|
5ed407e493 | ||
|
|
40988b901c | ||
|
|
26d49b2027 | ||
|
|
10386ee4de | ||
|
|
773d2e65d6 | ||
|
|
3e29d883fa | ||
|
|
f6f2895524 | ||
|
|
62287f8fcc | ||
|
|
be3257f805 | ||
|
|
1bf3aa528a | ||
|
|
056236c9f8 | ||
|
|
71fff76111 | ||
|
|
1095724e5c | ||
|
|
e81c2f2f90 | ||
|
|
9f91b4c050 | ||
|
|
7ada824e3e | ||
|
|
7cf7591f0a | ||
|
|
143a257c25 | ||
|
|
1d98647c54 | ||
|
|
7cd52b36a1 | ||
|
|
b033052647 | ||
|
|
4fcf2533a6 | ||
|
|
a8a103a521 | ||
|
|
12b09bb80b | ||
|
|
49aaffcf9a | ||
|
|
afbe628f17 | ||
|
|
1d6cbe31fe | ||
|
|
cb874d7a94 | ||
|
|
d7598ca672 | ||
|
|
ff8e494abd | ||
|
|
dfaa6dd3f8 | ||
|
|
849f3fbb28 | ||
|
|
329acf24bb | ||
|
|
bf40278131 | ||
|
|
4f2cf52eff | ||
|
|
f96fb855ce | ||
|
|
65f0be8a55 | ||
|
|
bcfcafdb7c | ||
|
|
c57bd066d1 | ||
|
|
4171fbdfd3 | ||
|
|
0f60aa2289 | ||
|
|
f97aab4699 | ||
|
|
740d447442 | ||
|
|
6448d6ccfa | ||
|
|
25cc9f3b9b | ||
|
|
e776838de9 | ||
|
|
bf0cfe0693 | ||
|
|
f690767507 | ||
|
|
4d57b14b5b | ||
|
|
263036045a | ||
|
|
56ef3f75d3 | ||
|
|
d0c902ab78 | ||
|
|
5ba7bc1fdf | ||
|
|
7e9ac7ba67 | ||
|
|
e2eaee9620 | ||
|
|
b23ce7ab8e | ||
|
|
53127a7ce6 | ||
|
|
011b73ba39 | ||
|
|
5d04a72a61 | ||
|
|
c3b76fdccf | ||
|
|
ec95243dad | ||
|
|
ae5d4a0bb2 | ||
|
|
0231f858e9 | ||
|
|
5d6db9f76f | ||
|
|
3bcefd2160 | ||
|
|
89675403d8 | ||
|
|
f277166354 | ||
|
|
b212babc87 | ||
|
|
6518c2d246 | ||
|
|
c551228079 | ||
|
|
c1198087af | ||
|
|
990ccc6d8b | ||
|
|
56a16066b7 | ||
|
|
407a47dd12 | ||
|
|
73b43b4f2b | ||
|
|
5961748b2a | ||
|
|
a18c5f3441 | ||
|
|
03c47a4020 | ||
|
|
77b0df3d07 | ||
|
|
7e3465a022 | ||
|
|
04fd3f7a1b |
+21
@@ -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,103 +0,0 @@
|
||||
1.6 (20121006)
|
||||
- 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 (20121003)
|
||||
- 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 (20121002)
|
||||
- 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
|
||||
the plugin API.
|
||||
- And more... see the GIT log for more details.
|
||||
|
||||
1.3 (20120928)
|
||||
- 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 (20120927)
|
||||
- Fix installation paths encoded in finit binary
|
||||
- Update README with section on building and enviroment variables
|
||||
|
||||
1.1 (20120927)
|
||||
- Build fixes for ARM eabi/uClibc
|
||||
- Rename signal.[ch]-->sig.[ch] to avoid name clash w/ system headers
|
||||
|
||||
1.0 (20120926)
|
||||
- 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 (20100614)
|
||||
- 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 (20080821)
|
||||
- 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 (20080516)
|
||||
- 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 (20080223)
|
||||
- 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 (20080219)
|
||||
- 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 (20080214)
|
||||
- initial release
|
||||
@@ -1,5 +1,5 @@
|
||||
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
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Finit - Extremely fast /sbin/init replacement w/ I/O, hook & service plugins
|
||||
#
|
||||
# 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
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -25,24 +25,21 @@
|
||||
install-exec install-data install-dev \
|
||||
uninstall-exec uninstall-data uninstall-dev
|
||||
|
||||
# Top directory for building complete system, fall back to this directory
|
||||
ROOTDIR = $(shell pwd)
|
||||
|
||||
#VERSION ?= $(shell git tag -l | tail -1)
|
||||
VERSION ?= 1.6
|
||||
VERSION ?= 1.10
|
||||
NAME = finit
|
||||
PKG = $(NAME)-$(VERSION)
|
||||
DEV = $(NAME)-dev
|
||||
ARCHIVE = $(PKG).tar.xz
|
||||
EXEC = finit reboot
|
||||
HEADERS = plugin.h svc.h helpers.h queue.h
|
||||
DISTFILES = LICENSE README ChangeLog finit.conf services
|
||||
OBJS = finit.o conf.o helpers.o sig.o svc.o plugin.o
|
||||
OBJS += strlcpy.o
|
||||
DISTFILES = LICENSE README NEWS finit.conf services
|
||||
OBJS = finit.o conf.o helpers.o sig.o svc.o plugin.o tty.o
|
||||
SRCS = $(OBJS:.o=.c)
|
||||
DEPS = $(addprefix .,$(SRCS:.c=.d))
|
||||
|
||||
# Installation paths, always prepended with DESTDIR if set
|
||||
TOPDIR = $(shell pwd)
|
||||
prefix ?= /usr
|
||||
sysconfdir ?= /etc
|
||||
sbindir ?= /sbin
|
||||
@@ -64,7 +61,7 @@ CPPFLAGS += -Ilibite -D_XOPEN_SOURCE=600 -D_BSD_SOURCE -D_GNU_SOURCE
|
||||
CPPFLAGS += -DVERSION=\"$(VERSION)\" -DWHOAMI=\"`whoami`@`hostname`\"
|
||||
CPPFLAGS += -DFINIT_FIFO=\"$(FINIT_FIFO)\" -DFINIT_CONF=\"$(FINIT_CONF)\"
|
||||
CPPFLAGS += -DFINIT_RCSD=\"$(FINIT_RCSD)\" -DPLUGIN_PATH=\"$(plugindir)\"
|
||||
LDFLAGS += -rdynamic -L$(ROOTDIR)/libite
|
||||
LDFLAGS += -rdynamic -L$(TOPDIR)/libite
|
||||
DEPLIBS = libite/libite.so
|
||||
LDLIBS += -ldl -lite
|
||||
|
||||
@@ -144,6 +141,9 @@ distclean: clean
|
||||
$(MAKE) -C libite $@
|
||||
$(MAKE) -C plugins $@
|
||||
|
||||
check:
|
||||
$(CHECK) *.c plugins/*.c libite/*.c
|
||||
|
||||
dist:
|
||||
@echo "Building xz tarball of $(PKG) in parent dir..."
|
||||
git archive --format=tar --prefix=$(PKG)/ $(VERSION) | xz >../$(ARCHIVE)
|
||||
@@ -158,9 +158,6 @@ dev: distclean
|
||||
cd - >/dev/null; mv $$dir/$(DEV).tar.xz ../; cd ..; \
|
||||
rm -rf $$dir; md5sum $(DEV).tar.xz | tee $(DEV).tar.xz.md5)
|
||||
|
||||
# Include automatically generated rules, such as:
|
||||
# uncgi.o: .../some/dir/uncgi.c /usr/include/stdio.h
|
||||
# but don't bother during clean!
|
||||
ifneq ($(MAKECMDGOALS),clean)
|
||||
ifneq ($(MAKECMDGOALS),distclean)
|
||||
-include $(DEPS)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,390 @@
|
||||
README
|
||||
======
|
||||
[](https://travis-ci.org/troglobit/finit)
|
||||
[](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.
|
||||
|
||||
-195
@@ -1,195 +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?
|
||||
* 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``, see the source code for available options.
|
||||
|
||||
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, akin
|
||||
to how the ``/ec/rc.local`` file works in most other inits, only finit
|
||||
runs a directory of scripts. This replaces the earlier
|
||||
``/usr/sbin/services.sh`` support of the original finit_.
|
||||
|
||||
|
||||
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/
|
||||
.. _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,6 +0,0 @@
|
||||
* FHS changes, see http://askubuntu.com/questions/57297/why-has-var-run-been-migrated-to-run
|
||||
* Look at Erik Troan's nash linuxrc parser for more inspiration
|
||||
* Look at how to support a standard SysV init runlevel mechanism
|
||||
* Arguments to finit, like to SysV init "init q" to reload finit.conf at runtime, etc.
|
||||
* Implement initctl stop|start|reload <SVC> and service <SVC> stop|start|reload on top
|
||||
* Write man pages for finit and finit.conf, steal from pimd man pages...
|
||||
@@ -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.
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
# Top directory for building complete system, fall back to this directory
|
||||
ROOTDIR ?= $(TOPDIR)
|
||||
|
||||
# Some junk files we always want to be removed when doing a make clean.
|
||||
JUNK = *~ *.bak *.aux *.dvi *.idx *.ind *.log *.ps *.map .*.d DEADJOE semantic.cache *.gdb *.elf core core.*
|
||||
MAKE := @$(MAKE)
|
||||
MAKEFLAGS = --no-print-directory --silent
|
||||
INSTALL := install --backup=off
|
||||
STRIPINST := $(INSTALL) -s --strip-program=$(CROSS)strip -m 0755
|
||||
JUNK = *~ *.bak *.aux *.dvi *.idx *.ind *.log *.ps *.map .*.d DEADJOE semantic.cache *.gdb *.elf core core.*
|
||||
MAKE := @$(MAKE)
|
||||
MAKEFLAGS = --no-print-directory --silent
|
||||
CHECK := cppcheck $(CPPFLAGS) --quiet --enable=all
|
||||
INSTALL := install --backup=off
|
||||
STRIPINST := $(INSTALL) -s --strip-program=$(CROSS)strip -m 0755
|
||||
|
||||
# Smart autodependecy generation via GCC -M.
|
||||
.%.d: %.c
|
||||
|
||||
@@ -21,123 +21,258 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "finit.h"
|
||||
#include "svc.h"
|
||||
#include "tty.h"
|
||||
#include "lite.h"
|
||||
#include "helpers.h"
|
||||
|
||||
/* Match one command. */
|
||||
#define MATCH_CMD(l, c, x) \
|
||||
#define MATCH_CMD(l, c, x) \
|
||||
(!strncmp(l, c, strlen(c)) && (x = (l) + strlen(c)))
|
||||
|
||||
|
||||
static char *build_cmd(char *cmd, char *line, int len)
|
||||
static char *strip_line(char *line)
|
||||
{
|
||||
int l;
|
||||
char *c;
|
||||
char *ptr;
|
||||
|
||||
/* Trim leading whitespace */
|
||||
while (*line && (*line == ' ' || *line == '\t'))
|
||||
while (*line && isblank(*line))
|
||||
line++;
|
||||
|
||||
if (!cmd) {
|
||||
cmd = malloc (strlen(line) + 1);
|
||||
if (!cmd) {
|
||||
_e("No memory left for '%s'", line);
|
||||
return NULL;
|
||||
}
|
||||
*cmd = 0;
|
||||
}
|
||||
c = cmd + strlen(cmd);
|
||||
for (l = 0; *line && *line != '#' && *line != '\t' && l < len; l++)
|
||||
*c++ = *line++;
|
||||
*c = 0;
|
||||
/* Strip any comment at end of line */
|
||||
ptr = line;
|
||||
while (*ptr && *ptr != '#')
|
||||
ptr++;
|
||||
*ptr = 0;
|
||||
|
||||
_d("cmd = %s", cmd);
|
||||
return cmd;
|
||||
return line;
|
||||
}
|
||||
|
||||
void parse_finit_conf(char *file)
|
||||
/* Convert optional "[!123456789S]" string into a bitmask */
|
||||
int parse_runlevels(char *runlevels)
|
||||
{
|
||||
int i, not = 0, bitmask = 0;
|
||||
|
||||
if (!runlevels)
|
||||
runlevels = "[234]";
|
||||
i = 1;
|
||||
while (i) {
|
||||
int level;
|
||||
char lvl = runlevels[i++];
|
||||
|
||||
if (']' == lvl || 0 == lvl)
|
||||
break;
|
||||
if ('!' == lvl) {
|
||||
not = 1;
|
||||
bitmask = 0x3FE;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ('s' == lvl || 'S' == lvl)
|
||||
lvl = '0';
|
||||
|
||||
level = lvl - '0';
|
||||
if (level > 9 || level < 0)
|
||||
continue;
|
||||
|
||||
if (not)
|
||||
CLRBIT(bitmask, level);
|
||||
else
|
||||
SETBIT(bitmask, level);
|
||||
}
|
||||
|
||||
return bitmask;
|
||||
}
|
||||
|
||||
static int parse_conf(char *file)
|
||||
{
|
||||
FILE *fp;
|
||||
char line[LINE_SIZE];
|
||||
char line[LINE_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;
|
||||
|
||||
/* Default username and hostname */
|
||||
username = strdup(DEFUSER);
|
||||
hostname = strdup(DEFHOST);
|
||||
rcsd = strdup(FINIT_RCSD);
|
||||
|
||||
if ((fp = fopen(file, "r")) != NULL) {
|
||||
char *x;
|
||||
result = parse_conf(file);
|
||||
if (!tty_num())
|
||||
tty_register(FALLBACK_SHELL);
|
||||
|
||||
_d("Parse %s ...", file);
|
||||
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 */
|
||||
if (MATCH_CMD(line, "check ", x)) {
|
||||
strcpy(cmd, "/sbin/fsck -C -a ");
|
||||
build_cmd(cmd, x, CMD_SIZE);
|
||||
run_interactive(cmd, "Checking file system integrity on %s", x);
|
||||
continue;
|
||||
}
|
||||
if (MATCH_CMD(line, "user ", x)) {
|
||||
if (username) free(username);
|
||||
username = build_cmd(NULL, x, USERNAME_SIZE);
|
||||
continue;
|
||||
}
|
||||
if (MATCH_CMD(line, "host ", x)) {
|
||||
if (hostname) free(hostname);
|
||||
hostname = build_cmd(NULL, x, HOSTNAME_SIZE);
|
||||
continue;
|
||||
}
|
||||
if (MATCH_CMD(line, "shutdown ", x)) {
|
||||
if (sdown) free(sdown);
|
||||
sdown = build_cmd(NULL, x, CMD_SIZE);
|
||||
continue;
|
||||
}
|
||||
if (MATCH_CMD(line, "module ", x)) {
|
||||
strcpy(cmd, "/sbin/modprobe ");
|
||||
build_cmd(cmd, x, CMD_SIZE);
|
||||
run_interactive(cmd, " Loading module %s", x);
|
||||
continue;
|
||||
}
|
||||
if (MATCH_CMD(line, "mknod ", x)) {
|
||||
strcpy(cmd, "/bin/mknod ");
|
||||
build_cmd(cmd, x, CMD_SIZE);
|
||||
run_interactive(cmd, " Creating device node %s", x);
|
||||
continue;
|
||||
}
|
||||
if (MATCH_CMD(line, "network ", x)) {
|
||||
if (network) free(network);
|
||||
network = build_cmd(NULL, x, CMD_SIZE);
|
||||
continue;
|
||||
}
|
||||
if (MATCH_CMD(line, "runparts ", x)) {
|
||||
if (rcsd) free(rcsd);
|
||||
hostname = build_cmd(NULL, x, CMD_SIZE);
|
||||
continue;
|
||||
}
|
||||
if (MATCH_CMD(line, "startx ", x)) {
|
||||
svc_register(x, username);
|
||||
continue;
|
||||
}
|
||||
if (MATCH_CMD(line, "service ", x)) {
|
||||
svc_register(x, NULL);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Executable
+65
@@ -0,0 +1,65 @@
|
||||
#!/bin/sh
|
||||
### BEGIN INIT INFO
|
||||
# Provides: keyboard-setup
|
||||
# Required-Start: mountkernfs
|
||||
# Required-Stop:
|
||||
# Should-Start: keymap udev
|
||||
# X-Start-Before: checkroot
|
||||
# Default-Start: S
|
||||
# Default-Stop:
|
||||
# X-Interactive: true
|
||||
# Short-Description: Set preliminary keymap
|
||||
# Description: Set the console keyboard as early as possible
|
||||
# so during the file systems checks the administrator
|
||||
# can interact. At this stage of the boot process
|
||||
# only the ASCII symbols are supported.
|
||||
### END INIT INFO
|
||||
|
||||
set -e
|
||||
|
||||
# This script is not used by keyboard-configuration. It is used
|
||||
# jointly by console-setup and console-setup-mini
|
||||
|
||||
test -f /bin/setupcon || exit 0
|
||||
|
||||
if [ -f /lib/lsb/init-functions ]; then
|
||||
. /lib/lsb/init-functions
|
||||
else
|
||||
log_action_begin_msg () {
|
||||
echo -n "$@... "
|
||||
}
|
||||
|
||||
log_action_end_msg () {
|
||||
if [ "$1" -eq 0 ]; then
|
||||
echo done.
|
||||
else
|
||||
echo failed.
|
||||
fi
|
||||
}
|
||||
fi
|
||||
|
||||
case "$1" in
|
||||
stop)
|
||||
# keyboard-setup isn't a daemon
|
||||
;;
|
||||
start|force-reload|restart|reload)
|
||||
case `readlink /proc/self/fd/2` in
|
||||
/dev/tty[0-9]*|/dev/vc/[0-9]*|/dev/console)
|
||||
log_action_begin_msg "Setting preliminary keymap"
|
||||
if setupcon -k; then
|
||||
log_action_end_msg 0
|
||||
else
|
||||
log_action_end_msg $?
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
*)
|
||||
echo 'Usage: /etc/init.d/keyboard-setup {start|reload|restart|force-reload|stop}'
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
Executable
+81
@@ -0,0 +1,81 @@
|
||||
#!/bin/sh
|
||||
### BEGIN INIT INFO
|
||||
# Provides: acpid
|
||||
# Required-Start: $remote_fs $syslog
|
||||
# Required-Stop: $remote_fs $syslog
|
||||
# X-Start-Before: kdm gdm xdm hal
|
||||
# X-Stop-After: kdm gdm xdm hal
|
||||
# Default-Start: 2 3 4 5
|
||||
# Default-Stop:
|
||||
# Short-Description: Start the Advanced Configuration and Power Interface daemon
|
||||
# Description: Provide a socket for X11, hald and others to multiplex
|
||||
# kernel ACPI events.
|
||||
### END INIT INFO
|
||||
|
||||
set -e
|
||||
|
||||
ACPID="/usr/sbin/acpid"
|
||||
DEFAULTS="/etc/default/acpid"
|
||||
|
||||
# Check for daemon presence
|
||||
[ -x "$ACPID" ] || exit 0
|
||||
|
||||
OPTIONS=""
|
||||
MODULES=""
|
||||
# Include acpid defaults if available
|
||||
[ -r "$DEFAULTS" ] && . "$DEFAULTS"
|
||||
|
||||
# Get lsb functions
|
||||
. /lib/lsb/init-functions
|
||||
|
||||
# As the name says. If the kernel supports modules, it'll try to load
|
||||
# the ones listed in "MODULES".
|
||||
load_modules() {
|
||||
[ -f /proc/modules ] || return 0
|
||||
if [ "$MODULES" = "all" ]; then
|
||||
MODULES="$(sed -rn 's#^(/lib/modules/[^/]+/)?kernel/(drivers|ubuntu)/acpi/([^/]+/)*(.*)\.ko:.*#\4#p' "/lib/modules/$(uname -r)/modules.dep")"
|
||||
fi
|
||||
|
||||
if [ -z "$MODULES" ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
log_begin_msg "Loading ACPI kernel modules..."
|
||||
# work around a bug in initramfs which leaks this env var Launchpad #291619
|
||||
# and a bug in modprobe --all --quiet which doesn't load all modules and
|
||||
# exits with non-zero exit status Debian #504088
|
||||
unset MODPROBE_OPTIONS
|
||||
modprobe --all --use-blacklist $MODULES 2>/dev/null
|
||||
log_end_msg $?
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
load_modules || true
|
||||
log_begin_msg "Starting ACPI services..."
|
||||
start-stop-daemon --start --quiet --oknodo --exec "$ACPID" -- $OPTIONS
|
||||
log_end_msg $?
|
||||
;;
|
||||
stop)
|
||||
log_begin_msg "Stopping ACPI services..."
|
||||
start-stop-daemon --stop --quiet --oknodo --retry 2 --exec "$ACPID"
|
||||
log_end_msg $?
|
||||
;;
|
||||
restart)
|
||||
$0 stop
|
||||
sleep 1
|
||||
$0 start
|
||||
;;
|
||||
reload|force-reload)
|
||||
log_begin_msg "Reloading ACPI services..."
|
||||
start-stop-daemon --stop --signal 1 --exec "$ACPID"
|
||||
log_end_msg $?
|
||||
;;
|
||||
status)
|
||||
status_of_proc "$ACPID" acpid
|
||||
;;
|
||||
*)
|
||||
log_success_msg "Usage: /etc/init.d/acpid {start|stop|restart|reload|force-reload|status}"
|
||||
exit 1
|
||||
esac
|
||||
|
||||
Executable
+259
@@ -0,0 +1,259 @@
|
||||
#!/bin/sh
|
||||
### BEGIN INIT INFO
|
||||
# Provides: kbd
|
||||
# Required-Start: $remote_fs
|
||||
# Required-Stop:
|
||||
# Default-Start: S
|
||||
# Default-Stop:
|
||||
# X-Interactive: true
|
||||
# Description: Set console screen modes and fonts
|
||||
# Short-Description: Prepare console
|
||||
### END INIT INFO
|
||||
|
||||
# This is the boot script for the `kbd' package.
|
||||
# It loads parameters from /etc/kbd/config and maybe loads
|
||||
# default font and map.
|
||||
# (c) 1997 Yann Dirson
|
||||
|
||||
PKG=kbd
|
||||
if [ -r /etc/$PKG/config ]; then
|
||||
. /etc/$PKG/config
|
||||
fi
|
||||
|
||||
if [ -d /etc/$PKG/config.d ]; then
|
||||
for i in `run-parts --list /etc/$PKG/config.d `; do
|
||||
. $i
|
||||
done
|
||||
fi
|
||||
|
||||
# do some magic with the variables for compatibility with the config
|
||||
# file of console-tools
|
||||
for vc in '' `set | grep "^.*_vc[0-9][0-9]*=" | sed 's/^.*\(_vc[0-9][0-9]*\)=.*/\1/'`
|
||||
do
|
||||
eval [ '"'\${SCREEN_FONT$vc}'"' ] && eval CONSOLE_FONT$vc=\${CONSOLE_FONT$vc:-\${SCREEN_FONT$vc}}
|
||||
eval [ '"'\${SCREEN_FONT_MAP$vc}'"' ] && eval FONT_MAP$vc=\${FONT_MAP$vc:-\${SCREEN_FONT_MAP$vc}}
|
||||
eval [ '"'\${APP_CHARSET_MAP$vc}'"' ] && eval CONSOLE_MAP$vc=\${CONSOLE_MAP$vc:-\${APP_CHARSET_MAP$vc}}
|
||||
done
|
||||
|
||||
. /lib/lsb/init-functions
|
||||
|
||||
PATH=/sbin:/bin:/usr/sbin:/usr/bin
|
||||
SETFONT_OPT="-v"
|
||||
|
||||
if which setupcon >/dev/null
|
||||
then
|
||||
HAVE_SETUPCON=yes
|
||||
fi
|
||||
|
||||
# set DEVICE_PREFIX depending on devfs/udev
|
||||
if [ -d /dev/vc ]; then
|
||||
DEVICE_PREFIX="/dev/vc/"
|
||||
else
|
||||
DEVICE_PREFIX="/dev/tty"
|
||||
fi
|
||||
|
||||
# determine the system charmap
|
||||
ENV_FILE=''
|
||||
[ -r /etc/environment ] && ENV_FILE="/etc/environment"
|
||||
[ -r /etc/default/locale ] && ENV_FILE="/etc/default/locale"
|
||||
[ "$ENV_FILE" ] && CHARMAP=$(set -a && . "$ENV_FILE" && locale charmap)
|
||||
if [ "$CHARMAP" = "UTF-8" -a -z "$CONSOLE_MAP" ]
|
||||
then
|
||||
UNICODE_MODE=yes
|
||||
fi
|
||||
|
||||
reset_vga_palette ()
|
||||
{
|
||||
if [ -f /proc/fb ]; then
|
||||
# They have a framebuffer device.
|
||||
# That means we have work to do...
|
||||
echo -n "]R"
|
||||
fi
|
||||
}
|
||||
|
||||
unicode_start_stop ()
|
||||
{
|
||||
vc=$1
|
||||
if [ -n "$UNICODE_MODE" -a -z "`eval echo \\$CONSOLE_MAP_vc$vc`" ]; then
|
||||
action=unicode_start
|
||||
else
|
||||
action=unicode_stop
|
||||
fi
|
||||
if [ "${CONSOLE_FONT}" ]; then
|
||||
$action "${CONSOLE_FONT}" < ${DEVICE_PREFIX}$vc > ${DEVICE_PREFIX}$vc 2> /dev/null || true
|
||||
else
|
||||
$action < ${DEVICE_PREFIX}$vc > ${DEVICE_PREFIX}$vc 2> /dev/null || true
|
||||
fi
|
||||
}
|
||||
|
||||
setup ()
|
||||
{
|
||||
# be sure the main program is installed
|
||||
which setfont >/dev/null || return
|
||||
|
||||
VT="no"
|
||||
# If we can't access the console, quit
|
||||
CONSOLE_TYPE=`fgconsole 2>/dev/null` || return
|
||||
|
||||
if [ ! $CONSOLE_TYPE = "serial" ]; then
|
||||
readlink /proc/self/fd/0 | grep -q -e /dev/vc -e '/dev/tty[^p]' -e /dev/console
|
||||
if [ $? -eq 0 ]; then
|
||||
VT="yes"
|
||||
reset_vga_palette
|
||||
fi
|
||||
fi
|
||||
|
||||
[ $VT = "no" ] && return
|
||||
|
||||
# start vcstime
|
||||
if [ "${DO_VCSTIME}" = "yes" ] && which vcstime >/dev/null; then
|
||||
[ "$VERBOSE" != "no" ] && log_action_begin_msg "Starting clock on text console"
|
||||
vcstime &
|
||||
[ "$VERBOSE" != "no" ] && log_action_end_msg 0
|
||||
fi
|
||||
|
||||
if [ -d /etc/init ] && which initctl >/dev/null; then
|
||||
# Upstart
|
||||
LIST_CONSOLES=`cd /etc/init; find -name 'tty*.conf' -printf '%f ' | sed -e 's/[^0-9 ]//g'`
|
||||
else
|
||||
# traditional SysV init
|
||||
LIST_CONSOLES=`sed -e '/^ *#/d' /etc/inittab | grep -e '\<tty[0-9]*\>' | awk -F: '{printf "%s ", $1}'`
|
||||
fi
|
||||
|
||||
# Global default font+map
|
||||
if [ -z "${HAVE_SETUPCON}" -a "${CONSOLE_FONT}" ]; then
|
||||
[ "$VERBOSE" != "no" ] && log_action_begin_msg "Setting up general console font"
|
||||
sfm="${FONT_MAP}" && [ "$sfm" ] && sfm="-u $sfm"
|
||||
acm="${CONSOLE_MAP}" && [ "$acm" ] && acm="-m $acm"
|
||||
|
||||
# Set for the first 6 VCs (as they are allocated in /etc/inittab)
|
||||
for vc in $LIST_CONSOLES
|
||||
do
|
||||
if ! ( unicode_start_stop $vc \
|
||||
&& setfont -C ${DEVICE_PREFIX}$vc ${SETFONT_OPT} $sfm ${CONSOLE_FONT} $acm )
|
||||
then
|
||||
[ "$VERBOSE" != "no" ] && log_action_end_msg 1
|
||||
break
|
||||
fi
|
||||
done
|
||||
[ "$VERBOSE" != "no" ] && log_action_end_msg 0
|
||||
fi
|
||||
|
||||
# Default to Unicode mode for new VTs?
|
||||
if [ -f /sys/module/vt/parameters/default_utf8 ]; then
|
||||
if [ -n "$UNICODE_MODE" ]; then
|
||||
echo 1
|
||||
else
|
||||
echo 0
|
||||
fi > /sys/module/vt/parameters/default_utf8
|
||||
fi
|
||||
|
||||
# Per-VC font+sfm
|
||||
PERVC_FONTS="`set | grep "^CONSOLE_FONT_vc[0-9]*=" | tr -d \' `"
|
||||
if [ -z "${HAVE_SETUPCON}" -a "${PERVC_FONTS}" ]; then
|
||||
[ "$VERBOSE" != "no" ] && log_action_begin_msg "Setting up per-VC fonts"
|
||||
for font in ${PERVC_FONTS}
|
||||
do
|
||||
# extract VC and FONTNAME info from variable setting
|
||||
vc=`echo $font | cut -b16- | cut -d= -f1`
|
||||
eval font=\$CONSOLE_FONT_vc$vc
|
||||
# eventually find an associated SFM
|
||||
eval sfm=\${FONT_MAP_vc${vc}}
|
||||
[ "$sfm" ] && sfm="-u $sfm"
|
||||
if ! ( unicode_start_stop $vc \
|
||||
&& setfont -C ${DEVICE_PREFIX}$vc ${SETFONT_OPT} $sfm $font )
|
||||
then
|
||||
[ "$VERBOSE" != "no" ] && log_action_end_msg 1
|
||||
break
|
||||
fi
|
||||
done
|
||||
[ "$VERBOSE" != "no" ] && log_action_end_msg 0
|
||||
fi
|
||||
|
||||
|
||||
# Per-VC ACMs
|
||||
PERVC_ACMS="`set | grep "^CONSOLE_MAP_vc[0-9]*=" | tr -d \' `"
|
||||
if [ -z "${HAVE_SETUPCON}" -a "${PERVC_ACMS}" ]; then
|
||||
[ "$VERBOSE" != "no" ] && log_action_begin_msg "Setting up per-VC ACM's"
|
||||
for acm in ${PERVC_ACMS}
|
||||
do
|
||||
# extract VC and ACM_FONTNAME info from variable setting
|
||||
vc=`echo $acm | cut -b15- | cut -d= -f1`
|
||||
eval acm=\$CONSOLE_MAP_vc$vc
|
||||
if ! setfont -C "${DEVICE_PREFIX}$vc" ${SETFONT_OPT} -m "$acm"; then
|
||||
[ "$VERBOSE" != "no" ] && log_action_end_msg 1
|
||||
break
|
||||
fi
|
||||
done
|
||||
[ "$VERBOSE" != "no" ] && log_action_end_msg 0
|
||||
fi
|
||||
|
||||
|
||||
# screensaver stuff
|
||||
setterm_args=""
|
||||
if [ "$BLANK_TIME" ]; then
|
||||
setterm_args="$setterm_args -blank $BLANK_TIME"
|
||||
fi
|
||||
if [ "$BLANK_DPMS" ]; then
|
||||
setterm_args="$setterm_args -powersave $BLANK_DPMS"
|
||||
fi
|
||||
if [ "$POWERDOWN_TIME" ]; then
|
||||
setterm_args="$setterm_args -powerdown $POWERDOWN_TIME"
|
||||
fi
|
||||
if [ "$setterm_args" ]; then
|
||||
setterm $setterm_args
|
||||
fi
|
||||
|
||||
# Keyboard rate and delay
|
||||
KBDRATE_ARGS=""
|
||||
if [ -n "$KEYBOARD_RATE" ]; then
|
||||
KBDRATE_ARGS="-r $KEYBOARD_RATE"
|
||||
fi
|
||||
if [ -n "$KEYBOARD_DELAY" ]; then
|
||||
KBDRATE_ARGS="$KBDRATE_ARGS -d $KEYBOARD_DELAY"
|
||||
fi
|
||||
if [ -n "$KBDRATE_ARGS" ]; then
|
||||
[ "$VERBOSE" != "no" ] && log_action_begin_msg "Setting keyboard rate and delay"
|
||||
kbdrate -s $KBDRATE_ARGS
|
||||
[ "$VERBOSE" != "no" ] && log_action_end_msg 0
|
||||
fi
|
||||
|
||||
# Inform gpm if present, of potential changes.
|
||||
if [ -f /var/run/gpm.pid ]; then
|
||||
kill -s WINCH `cat /var/run/gpm.pid` 2> /dev/null
|
||||
fi
|
||||
|
||||
# Allow user to remap keys on the console
|
||||
if [ -z "${HAVE_SETUPCON}" -a -r /etc/$PKG/remap ]; then
|
||||
dumpkeys < ${DEVICE_PREFIX}1 | sed -f /etc/$PKG/remap | loadkeys --quiet
|
||||
fi
|
||||
|
||||
# Set LEDS here
|
||||
if [ -n "$LEDS" ]; then
|
||||
for i in $LIST_CONSOLES
|
||||
do
|
||||
setleds -D $LEDS < $DEVICE_PREFIX$i
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
start|reload|restart|force-reload)
|
||||
if [ -n "$HAVE_SETUPCON" ]
|
||||
then
|
||||
log_action_msg "Setting console screen modes"
|
||||
else
|
||||
log_action_msg "Setting console screen modes and fonts"
|
||||
fi
|
||||
setup
|
||||
[ -z "$HAVE_SETUPCON" ] || log_action_msg "Skipping font and keymap setup (handled by console-setup)"
|
||||
;;
|
||||
stop)
|
||||
;;
|
||||
*)
|
||||
setup
|
||||
;;
|
||||
esac
|
||||
|
||||
:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* Finit - Extremely fast /sbin/init replacement w/ I/O, hook & service plugins
|
||||
*
|
||||
* 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
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <ctype.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/stat.h> /* umask(), mkdir() */
|
||||
#include <getopt.h>
|
||||
|
||||
#include "finit.h"
|
||||
#include "helpers.h"
|
||||
@@ -33,16 +34,20 @@
|
||||
#include "plugin.h"
|
||||
#include "svc.h"
|
||||
#include "sig.h"
|
||||
#include "tty.h"
|
||||
#include "lite.h"
|
||||
|
||||
int debug = 0;
|
||||
int verbose = 1;
|
||||
char *sdown = NULL;
|
||||
char *network = NULL;
|
||||
char *username = NULL;
|
||||
char *hostname = NULL;
|
||||
char *rcsd = FINIT_RCSD;
|
||||
|
||||
int debug = 0;
|
||||
int verbose = 1;
|
||||
int runlevel = 0; /* Bootstrap */
|
||||
int cfglevel = RUNLEVEL; /* Fallback if no configured runlevel */
|
||||
int prevlevel = 0; /* HALT */
|
||||
char *sdown = NULL;
|
||||
char *network = NULL;
|
||||
char *username = NULL;
|
||||
char *hostname = NULL;
|
||||
char *rcsd = NULL;
|
||||
char *console = NULL;
|
||||
|
||||
static void parse_kernel_cmdline(void)
|
||||
{
|
||||
@@ -63,18 +68,106 @@ static void parse_kernel_cmdline(void)
|
||||
}
|
||||
}
|
||||
|
||||
static int usage(int rc)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s [OPTIONS] [RUNLEVEL]\n\n"
|
||||
" -d, --debug Enable/Disable debug\n"
|
||||
" -h, --help This help text\n\n", __progname);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int client(int argc, char *argv[])
|
||||
{
|
||||
int fd;
|
||||
int c;
|
||||
struct option long_options[] = {
|
||||
{"debug", 0, NULL, 'd'},
|
||||
{"help", 0, NULL, 'h'},
|
||||
{NULL, 0, NULL, 0}
|
||||
};
|
||||
struct init_request rq = {
|
||||
.magic = INIT_MAGIC,
|
||||
.cmd = 0
|
||||
};
|
||||
|
||||
while ((c = getopt_long (argc, argv, "h?d", long_options, NULL)) != EOF) {
|
||||
switch(c) {
|
||||
case 'd':
|
||||
rq.cmd = INIT_CMD_DEBUG;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
case '?':
|
||||
return usage(0);
|
||||
default:
|
||||
return usage(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (!rq.cmd) {
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "Missing runlevel.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
rq.cmd = INIT_CMD_RUNLVL;
|
||||
rq.runlevel = (int)argv[1][0];
|
||||
}
|
||||
|
||||
if (!fexist(FINIT_FIFO)) {
|
||||
fprintf(stderr, "/sbin/init does not support %s!\n", FINIT_FIFO);
|
||||
return 1;
|
||||
}
|
||||
|
||||
fd = open(FINIT_FIFO, O_WRONLY);
|
||||
if (-1 == fd) {
|
||||
perror("Failed opening " FINIT_FIFO);
|
||||
return 1;
|
||||
}
|
||||
write(fd, &rq, sizeof(rq));
|
||||
close(fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int run_loop(void)
|
||||
{
|
||||
int delay = DELAY_TTY ?: 1;
|
||||
|
||||
_d("Entering main loop ...");
|
||||
while (1) {
|
||||
svc_monitor();
|
||||
plugin_monitor();
|
||||
|
||||
/* Delayed start of TTYs to let the system stabilize
|
||||
* after switching runlevels. */
|
||||
if (delay) {
|
||||
if (--delay == 0)
|
||||
tty_runlevel(runlevel);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int UNUSED(args), char *argv[])
|
||||
static void banner(void)
|
||||
{
|
||||
delline();
|
||||
echo("Finit version " VERSION " (" WHOAMI ") " __DATE__ " " __TIME__);
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
if (getpid() != 1)
|
||||
return client(argc, argv);
|
||||
|
||||
/*
|
||||
* Hello world.
|
||||
*/
|
||||
banner();
|
||||
|
||||
/*
|
||||
* Initial setup of signals, ignore all until we're up.
|
||||
*/
|
||||
@@ -88,8 +181,8 @@ int main(int UNUSED(args), char *argv[])
|
||||
mount("none", "/proc", "proc", 0, NULL);
|
||||
mount("none", "/proc/bus/usb", "usbfs", 0, NULL);
|
||||
mount("none", "/sys", "sysfs", 0, NULL);
|
||||
mkdir("/dev/pts", 0755);
|
||||
mkdir("/dev/shm", 0755);
|
||||
makedir("/dev/pts", 0755);
|
||||
makedir("/dev/shm", 0755);
|
||||
mount("none", "/dev/pts", "devpts", 0, "gid=5,mode=620");
|
||||
mount("none", "/dev/shm", "tmpfs", 0, NULL);
|
||||
umask(022);
|
||||
@@ -99,17 +192,10 @@ int main(int UNUSED(args), char *argv[])
|
||||
*/
|
||||
parse_kernel_cmdline();
|
||||
|
||||
cls();
|
||||
echo("finit " VERSION " (built " __DATE__ " " __TIME__ " by " WHOAMI ")");
|
||||
|
||||
/*
|
||||
* Populate /dev and prepare for runtime events from kernel.
|
||||
*/
|
||||
#if defined(USE_UDEV)
|
||||
run_interactive("udevd --daemon", "Populating device tree");
|
||||
#elif defined (MDEV)
|
||||
run_interactive(MDEV " -s", "Populating device tree");
|
||||
#endif
|
||||
run_interactive(SETUP_DEVFS, "Populating device tree");
|
||||
|
||||
/*
|
||||
* Parse configuration file
|
||||
@@ -121,20 +207,19 @@ int main(int UNUSED(args), char *argv[])
|
||||
* all services, or service plugins won't have anything to
|
||||
* hook on to.
|
||||
*/
|
||||
print_desc("", "Loading plugins");
|
||||
print_desc("Loading plugins", NULL);
|
||||
print_result(plugin_load_all(PLUGIN_PATH));
|
||||
|
||||
/*
|
||||
* Mount filesystems
|
||||
*/
|
||||
_d("Mount filesystems in /etc/fstab ...");
|
||||
|
||||
#ifdef REMOUNT_ROOTFS_RW
|
||||
run("/bin/mount -n -o remount,rw /");
|
||||
#endif
|
||||
#ifdef SYSROOT
|
||||
run(SYSROOT, "/", NULL, MS_MOVE, NULL);
|
||||
#endif
|
||||
|
||||
_d("Root FS up, calling hooks ...");
|
||||
plugin_run_hooks(HOOK_ROOTFS_UP);
|
||||
|
||||
@@ -146,14 +231,17 @@ int main(int UNUSED(args), char *argv[])
|
||||
/* Cleanup stale files, if any still linger on. */
|
||||
run_interactive("rm -rf /tmp/* /var/run/* /var/lock/*", "Cleanup temporary directories");
|
||||
|
||||
/*
|
||||
* Base FS up, enable standard SysV init signals
|
||||
*/
|
||||
/* Base FS up, enable standard SysV init signals */
|
||||
sig_setup();
|
||||
|
||||
_d("Base FS up, calling hooks ...");
|
||||
plugin_run_hooks(HOOK_BASEFS_UP);
|
||||
|
||||
/*
|
||||
* Start all bootstrap tasks, no network available!
|
||||
*/
|
||||
svc_bootstrap();
|
||||
|
||||
/*
|
||||
* Network stuff
|
||||
*/
|
||||
@@ -162,23 +250,23 @@ int main(int UNUSED(args), char *argv[])
|
||||
run("/sbin/sysctl -e -p /etc/sysctl.conf >/dev/null");
|
||||
|
||||
/* Set initial hostname. */
|
||||
set_hostname(hostname);
|
||||
set_hostname(&hostname);
|
||||
|
||||
ifconfig("lo", "127.0.0.1", "255.0.0.0", 1);
|
||||
if (network)
|
||||
run_interactive(network, "Starting networking: %s", network);
|
||||
umask(022);
|
||||
|
||||
/*
|
||||
* Hooks that rely on loopback, or basic networking being up.
|
||||
*/
|
||||
/* Hooks that rely on loopback, or basic networking being up. */
|
||||
plugin_run_hooks(HOOK_NETWORK_UP);
|
||||
|
||||
/*
|
||||
* Start service monitor framework
|
||||
* Start all tasks/services in the configured runlevel
|
||||
*/
|
||||
_d("Starting all static services from %s", FINIT_CONF);
|
||||
svc_start_all();
|
||||
svc_runlevel(cfglevel);
|
||||
|
||||
_d("Running svc up hooks ...");
|
||||
plugin_run_hooks(HOOK_SVC_UP);
|
||||
|
||||
/*
|
||||
* Run startup scripts in /etc/finit.d/, if any.
|
||||
@@ -188,19 +276,12 @@ int main(int UNUSED(args), char *argv[])
|
||||
run_parts(rcsd, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Hooks that should run at the very end
|
||||
*/
|
||||
/* Hooks that should run at the very end */
|
||||
plugin_run_hooks(HOOK_SYSTEM_UP);
|
||||
|
||||
/* Start GETTY on console */
|
||||
_d("Starting getty on console ...");
|
||||
run_getty(GETTY, argv);
|
||||
|
||||
/*
|
||||
* Enter main loop to monior /dev/initctl and services
|
||||
*/
|
||||
_d("Entering main loop ...");
|
||||
return run_loop();
|
||||
}
|
||||
|
||||
|
||||
+32
-7
@@ -1,12 +1,37 @@
|
||||
# Simple Debian finit.conf
|
||||
# Sample Debian finit.conf
|
||||
user admin
|
||||
host testbed
|
||||
|
||||
# Devices to fsck at boot
|
||||
check /dev/vda1
|
||||
|
||||
# Linux kernel modules to load
|
||||
module button
|
||||
module evdev
|
||||
module loop
|
||||
module psmouse
|
||||
user admin
|
||||
host testbed
|
||||
|
||||
# Runlevel to start after bootstrap, runlevel 'S'
|
||||
runlevel 2
|
||||
|
||||
# Network bringup script
|
||||
network service networking start
|
||||
service /sbin/klogd -n -- Kernel logging server
|
||||
service /sbin/syslogd -n -- Syslog server
|
||||
service /usr/sbin/sshd -D -- OpenSSH server
|
||||
service /usr/sbin/gdm -- GNOME Display Manager
|
||||
|
||||
# Virtual consoles to start getty on
|
||||
tty /dev/tty1
|
||||
tty /dev/tty2
|
||||
tty /dev/tty3
|
||||
|
||||
# Alternative method instead of runparts
|
||||
#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/kbd start -- Preparing console
|
||||
#run [2] /etc/init.d/networking start -- Start networking
|
||||
|
||||
# Services to be monitored and respawned as needed
|
||||
service [2345] /sbin/klogd -n -- Kernel logging server
|
||||
service [2345] /sbin/syslogd -n -- Syslog server
|
||||
service [3] /usr/sbin/gdm -- GNOME Display Manager
|
||||
|
||||
# By default Finit looks for /etc/finit.d
|
||||
# runparts /etc/finit.d
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* Finit - Extremely fast /sbin/init replacement w/ I/O, hook & service plugins
|
||||
*
|
||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||
* Copyright (c) 2008-2012 Joachim Nilsson <troglobit@gmail.com>
|
||||
* Copyright (c) 2008-2013 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -27,49 +27,77 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <paths.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* Distribution configuration */
|
||||
|
||||
/* Distribution specific configuration */
|
||||
#if defined EMBEDDED_SYSTEM
|
||||
# define CONSOLE "/dev/console"
|
||||
# define MDEV "/sbin/mdev"
|
||||
# define GETTY "/sbin/getty -L 115200 ttyS0 vt100"
|
||||
# define CONSOLE _PATH_CONSOLE
|
||||
# define SETUP_DEVFS "/sbin/mdev -s"
|
||||
# define GETTY "/sbin/getty -L"
|
||||
# define GETTY_BUSYBOX
|
||||
# define BAUDRATE 115200
|
||||
# define RUNLEVEL 2
|
||||
#else /* Debian/Ubuntu based distributions */
|
||||
# define RANDOMSEED "/var/lib/urandom/random-seed"
|
||||
# define CONSOLE "/dev/tty1"
|
||||
# define GETTY "/sbin/getty -8 38400 tty1"
|
||||
# define CONSOLE "/dev/tty1"
|
||||
# define SETUP_DEVFS "/sbin/udevd --daemon"
|
||||
# define GETTY "/sbin/getty -8"
|
||||
# define GETTY_AGETTY
|
||||
# define BAUDRATE 38400
|
||||
# define RUNLEVEL 2
|
||||
# define RANDOMSEED "/var/lib/urandom/random-seed"
|
||||
# define REMOUNT_ROOTFS_RW
|
||||
# define RUNLEVEL 2
|
||||
# define USE_UDEV
|
||||
# define USE_MESSAGE_BUS
|
||||
# define HAVE_DBUS
|
||||
#endif
|
||||
|
||||
#ifndef FALLBACK_SHELL
|
||||
# define FALLBACK_SHELL _PATH_BSHELL
|
||||
#endif
|
||||
|
||||
#ifndef DEFUSER
|
||||
# define DEFUSER "root"
|
||||
# define DEFUSER "root"
|
||||
#endif
|
||||
#ifndef DEFHOST
|
||||
# define DEFHOST "noname"
|
||||
# define DEFHOST "noname"
|
||||
#endif
|
||||
|
||||
#define CMD_SIZE 256
|
||||
#define LINE_SIZE 1024
|
||||
#define BUF_SIZE 4096
|
||||
#define USERNAME_SIZE 16
|
||||
#define HOSTNAME_SIZE 32
|
||||
/* Delay start of GETTY at boot. Must be > 0 */
|
||||
#define DELAY_TTY 2
|
||||
|
||||
extern char *sdown;
|
||||
extern char *network;
|
||||
extern char *hostname;
|
||||
extern char *username;
|
||||
extern char *rcsd;
|
||||
#define CMD_SIZE 256
|
||||
#define LINE_SIZE 1024
|
||||
#define BUF_SIZE 4096
|
||||
|
||||
#define INIT_MAGIC 0x03091969
|
||||
#define INIT_CMD_RUNLVL 1
|
||||
#define INIT_CMD_DEBUG 2
|
||||
|
||||
struct init_request {
|
||||
int magic; /* Magic number */
|
||||
int cmd; /* What kind of request */
|
||||
int runlevel; /* Runlevel to change to */
|
||||
int sleeptime; /* Time between TERM and KILL */
|
||||
char data[368];
|
||||
};
|
||||
|
||||
extern int runlevel;
|
||||
extern int cfglevel;
|
||||
extern int prevlevel;
|
||||
extern char *sdown;
|
||||
extern char *network;
|
||||
extern char *hostname;
|
||||
extern char *username;
|
||||
extern char *rcsd;
|
||||
extern char *console;
|
||||
extern char *__progname;
|
||||
|
||||
/* conf.c */
|
||||
void parse_finit_conf(char *file);
|
||||
int parse_runlevels (char *runlevels);
|
||||
int parse_finit_conf (char *file);
|
||||
|
||||
#endif /* FINIT_H_ */
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* Misc. utility functions and C-library extensions for finit and its plugins
|
||||
*
|
||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||
* Copyright (c) 2008-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
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -112,7 +112,7 @@ void ifconfig(char *ifname, char *addr, char *mask, int up)
|
||||
ifr.ifr_flags &= ~IFF_UP;
|
||||
|
||||
ioctl(sock, SIOCSIFFLAGS, &ifr);
|
||||
|
||||
|
||||
close(sock);
|
||||
}
|
||||
|
||||
@@ -131,31 +131,31 @@ void ifconfig(char *ifname, char *addr, char *mask, int up)
|
||||
*/
|
||||
pid_t pidfile_read(char *pidfile)
|
||||
{
|
||||
pid_t pid = 0;
|
||||
char buf[16];
|
||||
FILE *fp;
|
||||
pid_t pid = 0;
|
||||
char buf[16];
|
||||
FILE *fp;
|
||||
|
||||
if (!pidfile) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (!pidfile) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!fexist(pidfile))
|
||||
return -1;
|
||||
if (!fexist(pidfile))
|
||||
return -1;
|
||||
|
||||
fp = fopen(pidfile, "r");
|
||||
if (!fp)
|
||||
return -1;
|
||||
fp = fopen(pidfile, "r");
|
||||
if (!fp)
|
||||
return -1;
|
||||
|
||||
if (fgets(buf, sizeof(buf), fp)) {
|
||||
errno = 0;
|
||||
pid = strtoul(buf, NULL, 0);
|
||||
if (errno)
|
||||
pid = 0; /* Failed conversion. */
|
||||
}
|
||||
fclose(fp);
|
||||
if (fgets(buf, sizeof(buf), fp)) {
|
||||
errno = 0;
|
||||
pid = (pid_t)strtol(buf, NULL, 10);
|
||||
if (errno)
|
||||
pid = 0; /* Failed conversion. */
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
return pid;
|
||||
return pid;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -250,21 +250,6 @@ char *pid_get_name(pid_t pid, char *name, size_t len)
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* procname_set - Change process name, as seen in process listnings
|
||||
* @name: New name of process
|
||||
* @args: The process' argv[] vector.
|
||||
*/
|
||||
void procname_set(char *name, char *args[])
|
||||
{
|
||||
size_t len = strlen(args[0]) + 1; /* Include terminating '\0' */
|
||||
|
||||
prctl(PR_SET_NAME, name, 0, 0, 0);
|
||||
memset(args[0], 0, len);
|
||||
strlcpy(args[0], name, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* procname_kill - Send a signal to a process group by name.
|
||||
* @name: Name of process to send signal to.
|
||||
@@ -277,7 +262,7 @@ void procname_set(char *name, char *args[])
|
||||
* Returns:
|
||||
* Number of signals sent, i.e. number of processes who have received the signal.
|
||||
*/
|
||||
int procname_kill (char *name, int signo)
|
||||
int procname_kill(char *name, int signo)
|
||||
{
|
||||
int result = 0;
|
||||
char path[32], line[64];
|
||||
@@ -285,23 +270,26 @@ int procname_kill (char *name, int signo)
|
||||
DIR *dir;
|
||||
struct dirent *entry;
|
||||
|
||||
dir = opendir("/proc");
|
||||
if (!dir || !name) {
|
||||
if (!name) {
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
while ((entry = readdir (dir)) != NULL) {
|
||||
dir = opendir("/proc");
|
||||
if (!dir)
|
||||
return 0;
|
||||
|
||||
while ((entry = readdir(dir)) != NULL) {
|
||||
/* Skip non-process entries in /proc */
|
||||
if (!isdigit (*entry->d_name))
|
||||
if (!isdigit(*entry->d_name))
|
||||
continue;
|
||||
|
||||
snprintf (path, sizeof(path), "/proc/%s/status", entry->d_name);
|
||||
snprintf(path, sizeof(path), "/proc/%s/status", entry->d_name);
|
||||
/* Skip non-readable files (protected?) */
|
||||
if ((fp = fopen (path, "r")) == NULL)
|
||||
if ((fp = fopen(path, "r")) == NULL)
|
||||
continue;
|
||||
|
||||
if (fgets (line, sizeof (line), fp)) {
|
||||
if (fgets(line, sizeof (line), fp)) {
|
||||
char *pname = line + 6; /* Skip first part of line --> "Name:\t" */
|
||||
|
||||
if (strncmp(pname, name, strlen(pname) - 1) == 0) {
|
||||
@@ -324,7 +312,7 @@ int procname_kill (char *name, int signo)
|
||||
}
|
||||
|
||||
|
||||
static int print_uptime(void)
|
||||
static int print_timestamp(void)
|
||||
{
|
||||
#if defined(CONFIG_PRINTK_TIME)
|
||||
FILE * uptimefile;
|
||||
@@ -345,34 +333,80 @@ static int print_uptime(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void print_desc(char *action, char *desc)
|
||||
void print(int action, const char *fmt, ...)
|
||||
{
|
||||
const char home[] = "\r\e[K";
|
||||
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[] = " .....................................................................";
|
||||
|
||||
write(STDERR_FILENO, home, strlen(home));
|
||||
if (fmt) {
|
||||
va_start(ap, fmt);
|
||||
len = vsnprintf(buf, sizeof(buf), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
print_uptime();
|
||||
delline();
|
||||
print_timestamp();
|
||||
|
||||
write(STDERR_FILENO, action, strlen(action));
|
||||
write(STDERR_FILENO, desc, strlen(desc));
|
||||
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)
|
||||
{
|
||||
if (fail)
|
||||
fprintf(stderr, " \e[7m[FAIL]\e[0m\n");
|
||||
else
|
||||
fprintf(stderr, " \e[1m[ OK ]\e[0m\n");
|
||||
|
||||
print(!!fail, NULL);
|
||||
return fail;
|
||||
}
|
||||
|
||||
/* Wait for process completion, returns status of waitpid(2) syscall */
|
||||
int complete(char *cmd, int pid)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
if (waitpid(pid, &status, 0) == -1) {
|
||||
if (errno == EINTR)
|
||||
_e("Caught unblocked signal waiting for %s, aborting.", cmd);
|
||||
else if (errno == ECHILD)
|
||||
_e("Caught SIGCHLD waiting for %s, aborting.", cmd);
|
||||
else
|
||||
_e("Failed starting %s, error %d: %s", cmd, errno, strerror (errno));
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int run(char *cmd)
|
||||
{
|
||||
int status, result, i = 0;
|
||||
FILE *fp;
|
||||
char *args[NUM_ARGS + 1], *arg, *backup;
|
||||
pid_t pid;
|
||||
|
||||
@@ -383,7 +417,7 @@ int run(char *cmd)
|
||||
|
||||
/* Split command line into tokens of an argv[] array. */
|
||||
args[i++] = strsep(&arg, "\t ");
|
||||
do {
|
||||
while (arg && i < NUM_ARGS) {
|
||||
/* Handle run("su -c \"dbus-daemon --system\" messagebus");
|
||||
* => "su", "-c", "\"dbus-daemon --system\"", "messagebus" */
|
||||
if (*arg == '\'' || *arg == '"') {
|
||||
@@ -398,7 +432,7 @@ int run(char *cmd)
|
||||
} else {
|
||||
args[i++] = strsep(&arg, "\t ");
|
||||
}
|
||||
} while (arg && i < NUM_ARGS);
|
||||
}
|
||||
args[i] = NULL;
|
||||
#if 0
|
||||
_e("Splitting: '%s' =>", cmd);
|
||||
@@ -412,17 +446,18 @@ int run(char *cmd)
|
||||
return 1;
|
||||
}
|
||||
|
||||
fp = fopen("/dev/null", "w");
|
||||
pid = fork();
|
||||
if (0 == pid) {
|
||||
int i;
|
||||
FILE *fp;
|
||||
struct sigaction sa;
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Redirect stdio if the caller requested so. */
|
||||
/* Always redirect stdio for run() */
|
||||
fp = fopen("/dev/null", "w");
|
||||
if (fp) {
|
||||
int fd = fileno(fp);
|
||||
|
||||
@@ -435,20 +470,14 @@ int run(char *cmd)
|
||||
_exit(1); /* Only if execv() fails. */
|
||||
} else if (-1 == pid) {
|
||||
_pe("%s", args[0]);
|
||||
free(backup);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (waitpid(pid, &status, 0) == -1) {
|
||||
if (errno == EINTR)
|
||||
_e("Caught unblocked signal waiting for %s, aborting.", args[0]);
|
||||
else if (errno == ECHILD)
|
||||
_e("Caught SIGCHLD waiting for %s, aborting.", args[0]);
|
||||
else
|
||||
_e("Failed starting %s, error %d: %s", args[0], errno, strerror (errno));
|
||||
|
||||
if (fp) fclose(fp);
|
||||
status = complete(args[0], pid);
|
||||
if (-1 == status) {
|
||||
free(backup);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -463,7 +492,6 @@ int run(char *cmd)
|
||||
* change their return code accordingly. --Jocke */
|
||||
}
|
||||
|
||||
if (fp) fclose(fp);
|
||||
free(backup);
|
||||
|
||||
return result;
|
||||
@@ -474,25 +502,49 @@ int run_interactive(char *cmd, char *fmt, ...)
|
||||
int status, oldout = 1, olderr = 2;
|
||||
char line[LINE_SIZE];
|
||||
va_list ap;
|
||||
FILE *fp = tmpfile();
|
||||
FILE *fp;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(line, sizeof(line), fmt, ap);
|
||||
va_end(ap);
|
||||
if (!cmd) {
|
||||
errno = EINVAL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
print_desc("", line);
|
||||
if (fmt) {
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(line, sizeof(line), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
print_desc("", line);
|
||||
}
|
||||
|
||||
/* Redirect output from cmd to a tempfile */
|
||||
fp = tmpfile();
|
||||
if (fp && !debug) {
|
||||
oldout = dup(STDOUT_FILENO);
|
||||
olderr = dup(STDERR_FILENO);
|
||||
dup2(fileno(fp), STDOUT_FILENO);
|
||||
dup2(fileno(fp), STDERR_FILENO);
|
||||
}
|
||||
|
||||
/* Run cmd ... */
|
||||
status = run(cmd);
|
||||
|
||||
/* Restore stderr/stdout */
|
||||
if (fp && !debug) {
|
||||
dup2(oldout, STDOUT_FILENO);
|
||||
dup2(olderr, STDERR_FILENO);
|
||||
if (oldout >= 0) {
|
||||
dup2(oldout, STDOUT_FILENO);
|
||||
close(oldout);
|
||||
}
|
||||
if (olderr >= 0) {
|
||||
dup2(olderr, STDERR_FILENO);
|
||||
close(olderr);
|
||||
}
|
||||
}
|
||||
print_result(status);
|
||||
|
||||
if (fmt)
|
||||
print_result(status);
|
||||
|
||||
/* Dump any results of cmd on stderr after we've printed [ OK ] or [FAIL] */
|
||||
if (fp && !debug) {
|
||||
size_t len, written;
|
||||
|
||||
@@ -501,65 +553,73 @@ int run_interactive(char *cmd, char *fmt, ...)
|
||||
len = fread(line, 1, sizeof(line), fp);
|
||||
written = fwrite(line, len, sizeof(char), stderr);
|
||||
} while (len > 0 && written == len);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
if (fp)
|
||||
fclose(fp);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
pid_t run_getty(char *cmd, char *argv[])
|
||||
pid_t run_getty(char *cmd, char *args[], int console)
|
||||
{
|
||||
pid_t pid = fork();
|
||||
|
||||
if (!pid) {
|
||||
int i;
|
||||
int i, fd;
|
||||
char c;
|
||||
sigset_t nmask;
|
||||
struct sigaction sa;
|
||||
|
||||
/* Detach from initial controlling TTY */
|
||||
vhangup();
|
||||
if (console) {
|
||||
/* Detach from initial controlling TTY */
|
||||
vhangup();
|
||||
|
||||
close(2);
|
||||
close(1);
|
||||
close(0);
|
||||
close(STDERR_FILENO);
|
||||
close(STDOUT_FILENO);
|
||||
close(STDIN_FILENO);
|
||||
|
||||
/* Attach TTY to console */
|
||||
if (open(CONSOLE, O_RDWR) != 0)
|
||||
exit(1);
|
||||
/* Attach TTY to console */
|
||||
fd = open(CONSOLE, O_RDWR);
|
||||
if (fd != STDIN_FILENO)
|
||||
exit(1);
|
||||
|
||||
dup2(0, STDIN_FILENO);
|
||||
dup2(0, STDOUT_FILENO);
|
||||
dup2(0, STDERR_FILENO);
|
||||
|
||||
prctl(PR_SET_NAME, "console", 0, 0, 0);
|
||||
}
|
||||
sigemptyset(&nmask);
|
||||
sigaddset(&nmask, SIGCHLD);
|
||||
sigprocmask(SIG_UNBLOCK, &nmask, NULL);
|
||||
|
||||
/* 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);
|
||||
|
||||
dup2(0, STDIN_FILENO);
|
||||
dup2(0, STDOUT_FILENO);
|
||||
dup2(0, STDERR_FILENO);
|
||||
|
||||
procname_set("console", argv);
|
||||
|
||||
while (!fexist(SYNC_SHUTDOWN)) {
|
||||
static const char msg[] = "\nPlease press Enter to activate this console. ";
|
||||
static const char msg[] = "\nPlease press Enter to activate this console.";
|
||||
|
||||
if (fexist(SYNC_STOPPED)) {
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
i = write(STDERR_FILENO, msg, sizeof(msg) - 1);
|
||||
while (read(STDIN_FILENO, &c, 1) == 1 && c != '\n')
|
||||
continue;
|
||||
|
||||
if (console) {
|
||||
(void)write(STDERR_FILENO, msg, sizeof(msg));
|
||||
while (read(STDIN_FILENO, &c, 1) == 1 && c != '\n')
|
||||
continue;
|
||||
}
|
||||
if (fexist(SYNC_STOPPED))
|
||||
continue;
|
||||
|
||||
run(cmd);
|
||||
execv(cmd, args);
|
||||
}
|
||||
|
||||
if (console)
|
||||
close(fd);
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@@ -649,34 +709,48 @@ int getgroup(char *group)
|
||||
* Other convenience functions
|
||||
*/
|
||||
|
||||
void cls(void)
|
||||
{
|
||||
static const char cls[] = "\e[2J\e[1;1H";
|
||||
|
||||
if (!debug)
|
||||
fprintf (stderr, "%s", cls);
|
||||
}
|
||||
|
||||
void chomp(char *str)
|
||||
{
|
||||
char *x;
|
||||
char *x = strrchr(str, 0x0a);
|
||||
|
||||
if ((x = strchr((str), 0x0a)) != NULL)
|
||||
if (x)
|
||||
*x = 0;
|
||||
}
|
||||
|
||||
void set_hostname(char *hostname)
|
||||
/* Signal safe sleep ... we get a lot of SIGCHLD at reboot */
|
||||
void do_sleep(unsigned int sec)
|
||||
{
|
||||
while ((sec = sleep(sec)))
|
||||
;
|
||||
}
|
||||
|
||||
void set_hostname(char **hostname)
|
||||
{
|
||||
FILE *fp;
|
||||
|
||||
_d("Set hostname: %s", hostname);
|
||||
if ((fp = fopen("/etc/hostname", "r")) != NULL) {
|
||||
fgets(hostname, HOSTNAME_SIZE, fp);
|
||||
chomp(hostname);
|
||||
_d("Set hostname: %s", *hostname);
|
||||
fp = fopen("/etc/hostname", "r");
|
||||
if (fp) {
|
||||
struct stat st;
|
||||
|
||||
if (fstat(fileno(fp), &st)) {
|
||||
fclose(fp);
|
||||
return;
|
||||
}
|
||||
|
||||
*hostname = realloc(*hostname, st.st_size);
|
||||
if (!*hostname) {
|
||||
fclose(fp);
|
||||
return;
|
||||
}
|
||||
|
||||
fgets(*hostname, st.st_size, fp);
|
||||
chomp(*hostname);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
sethostname(hostname, strlen(hostname));
|
||||
if (*hostname)
|
||||
sethostname(*hostname, strlen(*hostname));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* Misc. utility functions and C-library extensions for finit and its plugins
|
||||
*
|
||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||
* Copyright (c) 2008-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
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -42,7 +42,16 @@
|
||||
|
||||
|
||||
#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
|
||||
#ifndef chardev
|
||||
# define chardev(x,m,maj,min) mknod((x), S_IFCHR|(m), makedev((maj),(min)))
|
||||
@@ -56,16 +65,32 @@
|
||||
#ifndef UNUSED
|
||||
#define UNUSED(x) UNUSED_ ## x __attribute__ ((unused))
|
||||
#endif
|
||||
/* Esc[2JEsc[1;1H Clear screen and move cursor to 1,1 (upper left) pos. */
|
||||
#define clrscr() fputs("\e[2J\e[1;1H", stderr)
|
||||
/* Esc[K Erases from the current cursor position to the end of the current line. */
|
||||
#define clreol() fputs("\e[K", stderr)
|
||||
/* Esc[2K Erases the entire current line. */
|
||||
#define delline() fputs("\e[2K", stderr)
|
||||
/* Esc[Line;ColumnH Moves the cursor to the specified position (coordinates) */
|
||||
#define gotoxy(x,y) fprintf(stderr, "\e[%d;%dH", y, x)
|
||||
/* Esc[?25l (lower case L) Hide Cursor */
|
||||
#define hidecursor() fputs("\e[?25l", stderr)
|
||||
/* Esc[?25h (lower case H) Show Cursor */
|
||||
#define showcursor() fputs("\e[?25h", stderr)
|
||||
|
||||
#define echo(fmt, args...) do { if (verbose) { fprintf(stderr, fmt "\n", ##args); } } while (0)
|
||||
#define _d(fmt, args...) do { if (debug) { fprintf(stderr, "finit:%s() - " fmt "\n", __func__, ##args); } } while (0)
|
||||
#define _e(fmt, args...) do { fprintf(stderr, "finit:%s:%s() - " fmt "\n", __FILE__, __func__, ##args); } while (0)
|
||||
#define _pe(fmt, args...) do { fprintf(stderr, "finit:%s:%s() - " fmt ". Error %d: %s\n", __FILE__, __func__, ##args, errno, strerror(errno)); } while (0)
|
||||
#define echo(fmt, args...) do { fprintf(stderr, fmt "\n", ##args); } while (0)
|
||||
#define _d(fmt, args...) do { if (debug) { fprintf(stderr, "finit:%s:%s() - " fmt "\n", __FILE__, __func__, ##args); } } while (0)
|
||||
#define _e(fmt, args...) do { fprintf(stderr, "finit:%s:%s() - " fmt "\n", __FILE__, __func__, ##args); } while (0)
|
||||
#define _pe(fmt, args...) do { fprintf(stderr, "finit:%s:%s() - " fmt ". Error %d: %s\n", __FILE__, __func__, ##args, errno, strerror(errno)); } while (0)
|
||||
|
||||
#define ISSET(a,i) ((a & (1 << (i)) ? 1 : 0))
|
||||
#define SETBIT(a,i) (a |= (1 << (i)))
|
||||
#define CLRBIT(a,i) (a &= ~(1 << (i)))
|
||||
|
||||
extern int debug;
|
||||
extern int verbose;
|
||||
|
||||
int makepath (char *path);
|
||||
int makepath (char *path);
|
||||
void ifconfig (char *ifname, char *addr, char *mask, int up);
|
||||
|
||||
pid_t pidfile_read (char *pidfile);
|
||||
@@ -77,22 +102,21 @@ char *pid_get_name (pid_t pid, char *name, size_t len);
|
||||
void procname_set (char *name, char *args[]);
|
||||
int procname_kill (char *name, int signo);
|
||||
|
||||
void print_desc (char *action, char *desc);
|
||||
void print (int action, const char *fmt, ...);
|
||||
void print_desc (char *action, char *desc);
|
||||
int print_result (int fail);
|
||||
int start_process (char *cmd, char *args[], int console);
|
||||
void cls (void);
|
||||
void chomp (char *str);
|
||||
void chomp (char *str);
|
||||
void do_sleep (unsigned int sec);
|
||||
int getuser (char *username);
|
||||
int getgroup (char *group);
|
||||
void set_hostname (char *hostname);
|
||||
int getgroup (char *group);
|
||||
void set_hostname (char **hostname);
|
||||
|
||||
int complete (char *cmd, int pid);
|
||||
int run (char *cmd);
|
||||
int run_interactive (char *cmd, char *fmt, ...);
|
||||
pid_t run_getty (char *cmd, char *argv[]);
|
||||
int run_parts (char *dir, char *cmd);
|
||||
|
||||
/* strlcpy.c */
|
||||
size_t strlcpy(char *dst, const char *src, size_t siz);
|
||||
pid_t run_getty (char *cmd, char *args[], int console);
|
||||
int run_parts (char *dir, char *cmd);
|
||||
|
||||
#endif /* FINIT_HELPERS_H_ */
|
||||
|
||||
|
||||
+2
-1
@@ -1,6 +1,6 @@
|
||||
# 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
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -28,6 +28,7 @@ include ../common.mk
|
||||
CFLAGS += -fPIC
|
||||
HEADERS = lite.h
|
||||
OBJS := copyfile.o dir.o fexist.o fisdir.o fmode.o rsync.o
|
||||
OBJS += strlcpy.o strlcat.o strtonum.o
|
||||
DEPS := $(addprefix ., $(OBJS:.o=.d))
|
||||
|
||||
VER = 0
|
||||
|
||||
+109
-49
@@ -34,13 +34,14 @@
|
||||
|
||||
#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.
|
||||
* @src: Source file.
|
||||
* @dst: Target 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
|
||||
* 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
|
||||
* 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;
|
||||
int s, d, n, isdir = 0, saved_errno = 0;
|
||||
ssize_t size = 0;
|
||||
int in, out, isdir = 0, saved_errno = 0;
|
||||
ssize_t num, size = 0;
|
||||
|
||||
errno = 0; /* Reset before leaving this function. */
|
||||
// fprintf (stderr, "%s() src: %s, dst: %s, len: %d\n", __func__, src, dst, len);
|
||||
errno = 0;
|
||||
|
||||
buffer = malloc(BUFSIZ);
|
||||
if (!buffer)
|
||||
return 0;
|
||||
|
||||
if (fisdir(src)) {
|
||||
errno = EISDIR; /* Error: source is a directory */
|
||||
return 0;
|
||||
saved_errno = EISDIR; /* Error: source is a directory */
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Check if target is a directory, then append the src base filename. */
|
||||
isdir = __isdir_and_append_filename(src, &dst);
|
||||
/* Check if target is a directory, then append src filename. */
|
||||
isdir = adjust_target(src, &dst);
|
||||
|
||||
/* Len == 0 means copy entire file */
|
||||
if (len == 0) {
|
||||
/* XXX: This feels a bit unsafe, but 2047 MiB may be sufficient for us.
|
||||
* --Jocke 2008-08-11 */
|
||||
len = INT_MAX;
|
||||
}
|
||||
|
||||
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;
|
||||
if (sym) {
|
||||
size = readlink(src, buffer, BUFSIZ);
|
||||
if (size > 0) {
|
||||
if (size >= (ssize_t) BUFSIZ) {
|
||||
saved_errno = ENOBUFS;
|
||||
goto exit;
|
||||
}
|
||||
while (len > 0 && n == BUFSIZ);
|
||||
|
||||
close(d);
|
||||
} else {
|
||||
saved_errno = errno;
|
||||
buffer[size] = 0;
|
||||
size = !symlink(buffer, dst);
|
||||
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);
|
||||
if (isdir)
|
||||
free(dst);
|
||||
@@ -135,12 +148,12 @@ int movefile(char *src, char *dst)
|
||||
int isdir, result = 0;
|
||||
|
||||
/* 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 (errno == EXDEV) {
|
||||
errno = 0;
|
||||
copyfile(src, dst, 0);
|
||||
copyfile(src, dst, 0, 0);
|
||||
if (errno)
|
||||
result = 1;
|
||||
else
|
||||
@@ -170,26 +183,30 @@ int movefile(char *src, char *dst)
|
||||
int copy_filep(FILE *src, FILE *dst)
|
||||
{
|
||||
int result = 0;
|
||||
char *buf = (char *)malloc(BUFSIZ);
|
||||
char *buf;
|
||||
|
||||
if (!src || !dst)
|
||||
return EINVAL;
|
||||
|
||||
buf = (char *)malloc(BUFSIZ);
|
||||
if (!buf)
|
||||
return errno;
|
||||
|
||||
while (1) {
|
||||
errno = 0;
|
||||
if (!fgets(buf, BUFSIZ, src)) {
|
||||
if (errno == EINTR) {
|
||||
clearerr(src);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (feof(src))
|
||||
break;
|
||||
|
||||
result = errno;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
while (EOF == fputs(buf, dst)) {
|
||||
if (errno == EINTR) {
|
||||
clearerr(dst);
|
||||
@@ -201,13 +218,58 @@ int copy_filep(FILE *src, FILE *dst)
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
exit:
|
||||
free(buf);
|
||||
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 */
|
||||
static int __isdir_and_append_filename(char *src, char **dst)
|
||||
static int adjust_target(char *src, char **dst)
|
||||
{
|
||||
int isdir = 0;
|
||||
|
||||
@@ -220,7 +282,6 @@ static int __isdir_and_append_filename(char *src, char **dst)
|
||||
else
|
||||
ptr++;
|
||||
|
||||
// fprintf (stderr, "Yes %s is a dir --> add %s\n", *dst, ptr);
|
||||
tmp = malloc(strlen(*dst) + strlen(ptr) + 2);
|
||||
if (!tmp) {
|
||||
errno = EISDIR;
|
||||
@@ -232,7 +293,6 @@ static int __isdir_and_append_filename(char *src, char **dst)
|
||||
|
||||
sprintf(tmp, "%s%s%s", *dst, slash ? "" : "/", ptr);
|
||||
*dst = tmp;
|
||||
// fprintf (stderr, "NEW DST:%s\n", *dst);
|
||||
}
|
||||
|
||||
return isdir;
|
||||
@@ -253,7 +313,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
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
|
||||
int main(void)
|
||||
@@ -284,7 +344,7 @@ int main(void)
|
||||
if (fexist(files[i + 2]))
|
||||
fprintf(stderr, "OK => %s\n", files[i + 2]);
|
||||
|
||||
remove(files[i + 2]);
|
||||
erase(files[i + 2]);
|
||||
i += 3;
|
||||
}
|
||||
|
||||
@@ -292,13 +352,13 @@ int main(void)
|
||||
i = 0;
|
||||
while (files[i]) {
|
||||
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");
|
||||
|
||||
if (fexist(files[i + 2]))
|
||||
fprintf(stderr, "OK => %s\n", files[i + 2]);
|
||||
|
||||
remove(files[i + 2]);
|
||||
erase(files[i + 2]);
|
||||
i += 3;
|
||||
}
|
||||
|
||||
@@ -311,7 +371,7 @@ int main(void)
|
||||
* Local Variables:
|
||||
* compile-command: "gcc -g -I../include -o unittest -DUNITTEST copyfile.c && ./unittest"
|
||||
* version-control: t
|
||||
* kept-new-versions: 2
|
||||
* c-file-style: "ellemtel"
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
|
||||
+8
-7
@@ -1,6 +1,6 @@
|
||||
/* 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
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
@@ -94,7 +94,7 @@ int dir(const char *dir, const char *type, int (*filter) (const char *file), cha
|
||||
n = scandir(dir, &namelist, matcher, alphasort);
|
||||
if (n < 0) {
|
||||
perror("scandir");
|
||||
} else {
|
||||
} else if (n > 0) {
|
||||
files = (char **)malloc(n * sizeof(char *));
|
||||
for (i = 0; i < n; i++) {
|
||||
if (files) {
|
||||
@@ -109,11 +109,12 @@ int dir(const char *dir, const char *type, int (*filter) (const char *file), cha
|
||||
}
|
||||
free(namelist[i]);
|
||||
}
|
||||
free(namelist);
|
||||
if (num)
|
||||
*list = files;
|
||||
}
|
||||
|
||||
if (num)
|
||||
*list = files;
|
||||
if (namelist)
|
||||
free(namelist);
|
||||
|
||||
return num;
|
||||
}
|
||||
@@ -141,13 +142,13 @@ int simulate_files(int creat)
|
||||
if (creat)
|
||||
touch(files[i]);
|
||||
else
|
||||
remove(files[i]);
|
||||
erase(files[i]);
|
||||
}
|
||||
|
||||
if (creat)
|
||||
symlink("config2.cfg", STARTUP_CONFIG);
|
||||
else
|
||||
remove(STARTUP_CONFIG);
|
||||
erase(STARTUP_CONFIG);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
+43
-2
@@ -1,7 +1,7 @@
|
||||
/* Collection of utility funcs and C library extensions for finit & its plugins
|
||||
*
|
||||
* 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
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -29,19 +29,31 @@
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h> /* MAX(), isset(), setbit(), TRUE, FALSE, et consortes. :-) */
|
||||
#include <unistd.h>
|
||||
|
||||
int fexist (char *file);
|
||||
int fisdir (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 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 rsync (char *src, char *dst, int delete, int (*filter) (const char *file));
|
||||
|
||||
#ifndef strlcpy
|
||||
size_t strlcpy (char *dst, const char *src, size_t siz);
|
||||
#endif
|
||||
#ifndef strlcat
|
||||
size_t strlcat (char *dst, const char *src, size_t siz);
|
||||
#endif
|
||||
#ifndef strtonum
|
||||
long long strtonum (const char *numstr, long long minval, long long maxval, const char **errstrp);
|
||||
#endif
|
||||
|
||||
static inline int fisslashdir(char *dir)
|
||||
{
|
||||
if (!dir) return 0;
|
||||
@@ -49,6 +61,35 @@ static inline int fisslashdir(char *dir)
|
||||
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_ */
|
||||
|
||||
/**
|
||||
|
||||
+52
-30
@@ -27,7 +27,8 @@
|
||||
#include "lite.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);
|
||||
|
||||
|
||||
@@ -58,21 +59,16 @@ int rsync(char *src, char *dst, int delete, int (*filter) (const char *file))
|
||||
int i = 0, num = 0, result = 0;
|
||||
char **files; /* Array of file names. */
|
||||
|
||||
void copy(char *src, char *dst)
|
||||
{
|
||||
errno = 0;
|
||||
copyfile(src, dst, 0);
|
||||
if (errno) result++;
|
||||
}
|
||||
|
||||
if (!fisdir(dst))
|
||||
mkdir(dst, 0755);
|
||||
makedir(dst, 0755);
|
||||
|
||||
if (!fisdir(src)) {
|
||||
if (!fexist(src))
|
||||
return 1;
|
||||
|
||||
copy(src, dst);
|
||||
if (copy(src, dst))
|
||||
result++;
|
||||
|
||||
return errno;
|
||||
}
|
||||
|
||||
@@ -85,7 +81,7 @@ int rsync(char *src, char *dst, int delete, int (*filter) (const char *file))
|
||||
else
|
||||
ptr++;
|
||||
|
||||
if (makedir(dest, sizeof(dest), dst, ptr, fmode(src)))
|
||||
if (mdir(dest, sizeof(dest), dst, ptr, fmode(src)))
|
||||
return 1;
|
||||
dst = dest;
|
||||
}
|
||||
@@ -98,7 +94,7 @@ int rsync(char *src, char *dst, int delete, int (*filter) (const char *file))
|
||||
char dst2[256];
|
||||
|
||||
strcat(source, "/");
|
||||
if (makedir (dst2, sizeof(dst2), dst, files[i], fmode(source))) {
|
||||
if (mdir (dst2, sizeof(dst2), dst, files[i], fmode(source))) {
|
||||
result++;
|
||||
continue;
|
||||
}
|
||||
@@ -106,7 +102,9 @@ int rsync(char *src, char *dst, int delete, int (*filter) (const char *file))
|
||||
rsync(source, dst2, delete, filter);
|
||||
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
|
||||
@@ -123,36 +121,60 @@ int rsync(char *src, char *dst, int delete, int (*filter) (const char *file))
|
||||
return result;
|
||||
}
|
||||
|
||||
/* 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 copy(char *src, char *dst)
|
||||
{
|
||||
snprintf(buf, buf_len, "%s%s%s/", dir, fisslashdir(dir) ? "" : "/", name);
|
||||
if (mkdir(buf, mode))
|
||||
return 1;
|
||||
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. */
|
||||
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);
|
||||
if (mkdir(buf, mode)) {
|
||||
if (EEXIST != errno)
|
||||
return 1;
|
||||
|
||||
errno = 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. */
|
||||
static int prune(char *dst, char **new_files, int new_num)
|
||||
{
|
||||
int i, num, result = 0;
|
||||
int num, result = 0;
|
||||
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);
|
||||
if (num) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
if (!find(files[i])) {
|
||||
if (!find(files[i], new_files, new_num)) {
|
||||
char *name;
|
||||
size_t len = strlen(files[i]) + 2 + strlen(dst);
|
||||
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
/* $OpenBSD: strlcat.c,v 1.13 2005/08/08 08:05:37 espie Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef strlcat
|
||||
/*
|
||||
* Appends src to string dst of size siz (unlike strncat, siz is the
|
||||
* full size of dst, not space left). At most siz-1 characters
|
||||
* will be copied. Always NUL terminates (unless siz <= strlen(dst)).
|
||||
* Returns strlen(src) + MIN(siz, strlen(initial dst)).
|
||||
* If retval >= siz, truncation occurred.
|
||||
*/
|
||||
size_t
|
||||
strlcat(char *dst, const char *src, size_t siz)
|
||||
{
|
||||
char *d = dst;
|
||||
const char *s = src;
|
||||
size_t n = siz;
|
||||
size_t dlen;
|
||||
|
||||
/* Find the end of dst and adjust bytes left but don't go past end */
|
||||
while (n-- != 0 && *d != '\0')
|
||||
d++;
|
||||
dlen = d - dst;
|
||||
n = siz - dlen;
|
||||
|
||||
if (n == 0)
|
||||
return(dlen + strlen(s));
|
||||
while (*s != '\0') {
|
||||
if (n != 1) {
|
||||
*d++ = *s;
|
||||
n--;
|
||||
}
|
||||
s++;
|
||||
}
|
||||
*d = '\0';
|
||||
|
||||
return(dlen + (s - src)); /* count does not include NUL */
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* version-control: t
|
||||
* c-file-style: "bsd"
|
||||
* End:
|
||||
*/
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef strlcpy
|
||||
/*
|
||||
* Copy src to string dst of size siz. At most siz-1 characters
|
||||
* will be copied. Always NUL terminates (unless siz == 0).
|
||||
@@ -50,6 +51,8 @@ strlcpy(char *dst, const char *src, size_t siz)
|
||||
return(s - src - 1); /* count does not include NUL */
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* version-control: t
|
||||
@@ -0,0 +1,67 @@
|
||||
/* $OpenBSD: strtonum.c,v 1.6 2004/08/03 19:38:01 millert Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2004 Ted Unangst and Todd Miller
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifndef strtonum
|
||||
#define INVALID 1
|
||||
#define TOOSMALL 2
|
||||
#define TOOLARGE 3
|
||||
|
||||
long long
|
||||
strtonum(const char *numstr, long long minval, long long maxval,
|
||||
const char **errstrp)
|
||||
{
|
||||
long long ll = 0;
|
||||
char *ep;
|
||||
int error = 0;
|
||||
struct errval {
|
||||
const char *errstr;
|
||||
int err;
|
||||
} ev[4] = {
|
||||
{ NULL, 0 },
|
||||
{ "invalid", EINVAL },
|
||||
{ "too small", ERANGE },
|
||||
{ "too large", ERANGE },
|
||||
};
|
||||
|
||||
ev[0].err = errno;
|
||||
errno = 0;
|
||||
if (minval > maxval)
|
||||
error = INVALID;
|
||||
else {
|
||||
ll = strtoll(numstr, &ep, 10);
|
||||
if (numstr == ep || *ep != '\0')
|
||||
error = INVALID;
|
||||
else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval)
|
||||
error = TOOSMALL;
|
||||
else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval)
|
||||
error = TOOLARGE;
|
||||
}
|
||||
if (errstrp != NULL)
|
||||
*errstrp = ev[error].errstr;
|
||||
errno = ev[error].err;
|
||||
if (error)
|
||||
ll = 0;
|
||||
|
||||
return (ll);
|
||||
}
|
||||
#endif
|
||||
@@ -124,9 +124,9 @@ int plugin_unregister(plugin_t *plugin)
|
||||
}
|
||||
|
||||
|
||||
// _d("Comparing %s against plugin %s", str, p->name);
|
||||
#define SEARCH_PLUGIN(str) \
|
||||
PLUGIN_ITERATOR(p, tmp) { \
|
||||
_d("Comparing %s against plugin %s", str, p->name); \
|
||||
if (!strcmp(p->name, str)) \
|
||||
return p; \
|
||||
}
|
||||
@@ -159,7 +159,7 @@ plugin_t *plugin_find(char *name)
|
||||
|
||||
SEARCH_PLUGIN(name);
|
||||
|
||||
if (name[0] != '/') {
|
||||
if (plugpath && name[0] != '/') {
|
||||
int noext;
|
||||
char path[CMD_SIZE];
|
||||
|
||||
@@ -189,15 +189,20 @@ void plugin_run_hooks(hook_point_t no)
|
||||
}
|
||||
|
||||
/* Generic libev I/O callback, looks up correct plugin and calls its callback */
|
||||
static void generic_io_cb(int fd, int events)
|
||||
static void generic_io_cb(struct pollfd *io)
|
||||
{
|
||||
plugin_t *p, *tmp;
|
||||
|
||||
/* Find matching plugin, pick first matching fd */
|
||||
PLUGIN_ITERATOR(p, tmp) {
|
||||
if (is_io_plugin(p) && p->io.fd == fd) {
|
||||
if (is_io_plugin(p) && p->io.fd == io->fd) {
|
||||
_d("Calling I/O %s from runloop...", basename(p->name));
|
||||
p->io.cb(p->io.arg, fd, events);
|
||||
p->io.cb(p->io.arg, io->fd, io->events);
|
||||
|
||||
/* Update fd, may be changed by plugin callback, e.g., if FIFO */
|
||||
io->fd = p->io.fd;
|
||||
io->events = p->io.flags;
|
||||
io->revents = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -221,7 +226,7 @@ void plugin_monitor(void)
|
||||
/* Traverse all I/O fds and run callbacks */
|
||||
for (i = 0; i < num_fds; i++) {
|
||||
if (fds[i].revents)
|
||||
generic_io_cb(fds[i].fd, fds[i].revents);
|
||||
generic_io_cb(&fds[i]);
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -275,6 +280,9 @@ static int load_one(char *path, char *name)
|
||||
snprintf(plugin, sizeof(plugin), "%s/%s%s", path, name, noext ? ".so" : "");
|
||||
|
||||
_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);
|
||||
if (!handle) {
|
||||
_e("Failed loading plugin %s: %s", plugin, dlerror());
|
||||
@@ -300,9 +308,9 @@ static void check_plugin_depends(plugin_t *plugin)
|
||||
int i;
|
||||
|
||||
for (i = 0; i < PLUGIN_DEP_MAX && plugin->depends[i]; i++) {
|
||||
_d("Plugin %s depends on %s ...", plugin->name, plugin->depends[i]);
|
||||
// _d("Plugin %s depends on %s ...", plugin->name, plugin->depends[i]);
|
||||
if (plugin_find(plugin->depends[i])) {
|
||||
_d("OK plugin %s was already loaded.", plugin->depends[i]);
|
||||
// _d("OK plugin %s was already loaded.", plugin->depends[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -4,8 +4,9 @@ CPPFLAGS += -I..
|
||||
LDFLAGS := $(filter-out -rdynamic, $(LDFLAGS))
|
||||
LDFLAGS += -shared
|
||||
PLUGINS ?= initctl.so alsa-utils.so bootmisc.so dbus.so hwclock.so \
|
||||
resolvconf.so urandom.so x11-common.so
|
||||
resolvconf.so urandom.so x11-common.so tty.so
|
||||
DEPS = $(addprefix .,$(PLUGINS:.so=.d))
|
||||
TOPDIR ?= $(shell pwd)
|
||||
|
||||
include ../common.mk
|
||||
|
||||
|
||||
+21
-22
@@ -39,25 +39,24 @@ static void setup(void *UNUSED(arg))
|
||||
#endif
|
||||
|
||||
_d("Setting up FHS structure in /var ...");
|
||||
mkdir("/var/cache", 0755);
|
||||
mkdir("/var/games", 0755);
|
||||
mkdir("/var/lib", 0755);
|
||||
mkdir("/var/lib/misc", 0755);
|
||||
mkdir("/var/lib/alarm", 0755);
|
||||
mkdir("/var/lock", 0755);
|
||||
mkdir("/var/log", 0755);
|
||||
mkdir("/var/mail", 0755);
|
||||
mkdir("/var/opt", 0755);
|
||||
mkdir("/var/run", 0755);
|
||||
mkdir("/var/spool", 0755);
|
||||
mkdir("/var/spool/cron", 0755);
|
||||
mkdir("/var/tmp", 0755);
|
||||
mkdir("/var/empty", 0755);
|
||||
makedir("/var/cache", 0755);
|
||||
makedir("/var/games", 0755);
|
||||
makedir("/var/lib", 0755);
|
||||
makedir("/var/lib/misc", 0755);
|
||||
makedir("/var/lib/alarm", 0755);
|
||||
makedir("/var/lock", 0755);
|
||||
makedir("/var/log", 0755);
|
||||
makedir("/var/mail", 0755);
|
||||
makedir("/var/opt", 0755);
|
||||
makedir("/var/run", 0755);
|
||||
makedir("/var/spool", 0755);
|
||||
makedir("/var/spool/cron", 0755);
|
||||
makedir("/var/tmp", 0755);
|
||||
makedir("/var/empty", 0755);
|
||||
|
||||
_d("Setting up necessary UTMP files ...");
|
||||
touch("/var/run/utmp");
|
||||
chown("/var/run/utmp", 0, getgroup("utmp"));
|
||||
chmod("/var/run/utmp", 0664);
|
||||
|
||||
#ifdef RUNLEVEL
|
||||
memset(&entry, 0, sizeof(struct utmp));
|
||||
@@ -71,16 +70,16 @@ static void setup(void *UNUSED(arg))
|
||||
#ifdef TOUCH_ETC_NETWORK_RUN_IFSTATE
|
||||
touch("/etc/network/run/ifstate");
|
||||
#else
|
||||
remove("/etc/network/run/ifstate");
|
||||
erase("/etc/network/run/ifstate");
|
||||
#endif
|
||||
|
||||
_d("Setting up misc files ...");
|
||||
mkdir("/var/run/lldpd", 0755); /* Needed by lldpd */
|
||||
mkdir("/var/run/pluto", 0755); /* Needed by Openswan */
|
||||
mkdir("/var/run/quagga", 0755); /* Needed by Quagga */
|
||||
mkdir("/var/log/quagga", 0755); /* Needed by Quagga */
|
||||
mkdir("/var/run/sshd", 01755); /* OpenSSH */
|
||||
mkfifo("/dev/xconsole", 0640); /* sysklogd */
|
||||
makedir("/var/run/lldpd", 0755); /* Needed by lldpd */
|
||||
makedir("/var/run/pluto", 0755); /* Needed by Openswan */
|
||||
makedir("/var/run/quagga", 0755); /* Needed by Quagga */
|
||||
makedir("/var/log/quagga", 0755); /* Needed by Quagga */
|
||||
makedir("/var/run/sshd", 01755); /* OpenSSH */
|
||||
makefifo("/dev/xconsole", 0640); /* sysklogd */
|
||||
chown("/dev/xconsole", 0, getgroup("tty"));
|
||||
}
|
||||
|
||||
|
||||
+4
-4
@@ -27,12 +27,12 @@
|
||||
|
||||
static void setup(void *UNUSED(arg))
|
||||
{
|
||||
#ifdef USE_MESSAGE_BUS
|
||||
#ifdef HAVE_DBUS
|
||||
_d("Starting D-Bus ...");
|
||||
mkdir("/var/run/dbus", 0755);
|
||||
mkdir("/var/lock/subsys/messagebus", 0755);
|
||||
makedir("/var/run/dbus", 0755);
|
||||
makedir("/var/lock/subsys/messagebus", 0755);
|
||||
run("dbus-uuidgen --ensure");
|
||||
remove("/var/run/dbus/pid");
|
||||
erase("/var/run/dbus/pid");
|
||||
run_interactive("dbus-daemon --system", "Starting D-Bus");
|
||||
#endif
|
||||
}
|
||||
|
||||
+59
-35
@@ -1,7 +1,7 @@
|
||||
/* Optional /dev/initctl FIFO monitor
|
||||
*
|
||||
* 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
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -27,82 +27,106 @@
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h> /* read() */
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "helpers.h"
|
||||
#include "plugin.h"
|
||||
#include "sig.h"
|
||||
#include "finit.h"
|
||||
|
||||
#define INIT_MAGIC 0x03091969
|
||||
#define INIT_CMD_RUNLVL 1
|
||||
static void parse(void *arg, int fd, int events);
|
||||
|
||||
struct init_request {
|
||||
int magic; /* Magic number */
|
||||
int cmd; /* What kind of request */
|
||||
int runlevel; /* Runlevel to change to */
|
||||
int sleeptime; /* Time between TERM and KILL */
|
||||
char data[368];
|
||||
static plugin_t plugin = {
|
||||
.io = {
|
||||
.cb = parse,
|
||||
.flags = PLUGIN_IO_READ,
|
||||
},
|
||||
};
|
||||
|
||||
static void fifo_open(void)
|
||||
{
|
||||
plugin.io.fd = open(FINIT_FIFO, O_RDONLY | O_NONBLOCK);
|
||||
if (-1 == plugin.io.fd) {
|
||||
_e("Failed opening %s FIFO, error %d: %s", FINIT_FIFO, errno, strerror(errno));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Standard reboot/shutdown utilities talk to init using /dev/initctl.
|
||||
* We should check if the fifo was recreated and reopen it.
|
||||
*/
|
||||
static void read_initctl(void *UNUSED(arg), int fd, int UNUSED(events))
|
||||
static void parse(void *UNUSED(arg), int fd, int UNUSED(events))
|
||||
{
|
||||
struct init_request request;
|
||||
struct init_request rq;
|
||||
|
||||
_d("Receiving request on %s...", FINIT_FIFO);
|
||||
while (1) {
|
||||
ssize_t len = read(fd, &request, sizeof(request));
|
||||
ssize_t len = read(fd, &rq, sizeof(rq));
|
||||
|
||||
if (-1 == len) {
|
||||
_d("Error %d", errno);
|
||||
break; /* Probably EAGAIN */
|
||||
if (len <= 0) {
|
||||
if (-1 == len) {
|
||||
if (EINTR == errno)
|
||||
continue;
|
||||
|
||||
if (EAGAIN == errno)
|
||||
break;
|
||||
|
||||
_e("Failed reading initctl request, error %d: %s", errno, strerror(errno));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (request.magic != INIT_MAGIC)
|
||||
continue;
|
||||
if (rq.magic != INIT_MAGIC || len != sizeof(rq)) {
|
||||
_e("Invalid initctl request.");
|
||||
break;
|
||||
}
|
||||
|
||||
_d("Magic OK...");
|
||||
if (request.cmd == INIT_CMD_RUNLVL) {
|
||||
switch (request.runlevel) {
|
||||
if (rq.cmd == INIT_CMD_RUNLVL) {
|
||||
switch (rq.runlevel) {
|
||||
case '0':
|
||||
_d("Halting system (SIGUSR2)");
|
||||
do_shutdown(SIGUSR2);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
case 'S':
|
||||
_d("Cannot enter bootstrap after boot ...");
|
||||
rq.runlevel = '1';
|
||||
/* Fall through to regular processing */
|
||||
|
||||
case '1'...'5':
|
||||
case '7'...'9':
|
||||
_d("Setting new runlevel %c", rq.runlevel);
|
||||
svc_runlevel(rq.runlevel - '0');
|
||||
break;
|
||||
|
||||
case '6':
|
||||
_d("Rebooting system (SIGUSR1)");
|
||||
do_shutdown(SIGUSR1);
|
||||
break;
|
||||
|
||||
default:
|
||||
_d("Unsupported runlevel: %d", request.runlevel);
|
||||
_d("Unsupported runlevel: %d", rq.runlevel);
|
||||
break;
|
||||
}
|
||||
} else if (rq.cmd == INIT_CMD_DEBUG) {
|
||||
debug = !debug;
|
||||
} else {
|
||||
_d("Unsupported cmd: %d", request.cmd);
|
||||
_d("Unsupported cmd: %d", rq.cmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static plugin_t plugin = {
|
||||
.io = {
|
||||
.cb = read_initctl,
|
||||
.flags = PLUGIN_IO_READ,
|
||||
},
|
||||
};
|
||||
close(fd);
|
||||
fifo_open();
|
||||
}
|
||||
|
||||
PLUGIN_INIT(plugin_init)
|
||||
{
|
||||
_d("Setting up %s", FINIT_FIFO);
|
||||
mkfifo(FINIT_FIFO, 0600);
|
||||
|
||||
plugin.io.fd = open(FINIT_FIFO, O_RDONLY | O_NONBLOCK);
|
||||
if (-1 == plugin.io.fd) {
|
||||
_e("Failed opening %s FIFO, error %d: %s", FINIT_FIFO, errno, strerror(errno));
|
||||
return;
|
||||
}
|
||||
makefifo(FINIT_FIFO, 0600);
|
||||
|
||||
fifo_open();
|
||||
plugin_register(&plugin);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
/* Optional TTY Watcher, used to catch new TTYs that are discovered, e.g., USB
|
||||
*
|
||||
* Copyright (c) 2013 Mattias Walström <lazzer@gmail.com>
|
||||
* Copyright (c) 2013 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h> /* O_RDONLY et al */
|
||||
#include <unistd.h> /* read() */
|
||||
#include <sys/inotify.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "finit.h"
|
||||
#include "helpers.h"
|
||||
#include "plugin.h"
|
||||
#include "tty.h"
|
||||
|
||||
static void watcher(void *arg, int fd, int events);
|
||||
|
||||
static plugin_t plugin = {
|
||||
.io = {
|
||||
.cb = watcher,
|
||||
.flags = PLUGIN_IO_READ,
|
||||
},
|
||||
};
|
||||
|
||||
static void setup(void)
|
||||
{
|
||||
plugin.io.fd = inotify_init1(IN_NONBLOCK);
|
||||
if (-1 == plugin.io.fd || inotify_add_watch(plugin.io.fd, "/dev", IN_CREATE | IN_DELETE) < 0)
|
||||
_e("Failed starting TTY watcher: %s", strerror(errno));
|
||||
}
|
||||
|
||||
static void watcher(void *UNUSED(arg), int fd, int UNUSED(events))
|
||||
{
|
||||
int len = 0;
|
||||
char buf[EVENT_SIZE], name[42];
|
||||
tty_node_t *entry;
|
||||
struct inotify_event *notified = (struct inotify_event *)buf;
|
||||
|
||||
while ((len = read(fd, buf, sizeof(buf)))) {
|
||||
if (-1 == len) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
|
||||
snprintf(name, sizeof(name), "/dev/%s", notified->name);
|
||||
entry = tty_find(name);
|
||||
if (entry && tty_enabled(&entry->data, runlevel)) {
|
||||
if (notified->mask & IN_CREATE)
|
||||
tty_start(&entry->data);
|
||||
else if (entry->data.pid)
|
||||
tty_stop(&entry->data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PLUGIN_INIT(plugin_init)
|
||||
{
|
||||
setup();
|
||||
plugin_register(&plugin);
|
||||
}
|
||||
|
||||
PLUGIN_EXIT(plugin_exit)
|
||||
{
|
||||
plugin_unregister(&plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* version-control: t
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -36,7 +36,7 @@ static void setup(void *UNUSED(arg))
|
||||
#endif
|
||||
char line[LINE_SIZE];
|
||||
|
||||
makepath("/var/run/console");
|
||||
makedir("/var/run/console", 01777);
|
||||
snprintf(line, sizeof(line), "/var/run/console/%s", username);
|
||||
touch(line);
|
||||
|
||||
@@ -48,8 +48,8 @@ static void setup(void *UNUSED(arg))
|
||||
}
|
||||
#endif
|
||||
|
||||
mkdir("/tmp/.X11-unix", 01777);
|
||||
mkdir("/tmp/.ICE-unix", 01777);
|
||||
makedir("/tmp/.X11-unix", 01777);
|
||||
makedir("/tmp/.ICE-unix", 01777);
|
||||
}
|
||||
|
||||
static plugin_t plugin = {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* Private header file for main finit daemon, not for plugins
|
||||
*
|
||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||
* Copyright (c) 2008-2012 Joachim Nilsson <troglobit@gmail.com>
|
||||
* Copyright (c) 2008-2013 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -28,7 +28,7 @@
|
||||
#include "svc.h"
|
||||
#include "plugin.h"
|
||||
|
||||
void svc_start_all (void);
|
||||
void svc_bootstrap (void);
|
||||
void svc_monitor (void);
|
||||
|
||||
void plugin_run_hooks (hook_point_t no);
|
||||
|
||||
@@ -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 $ */
|
||||
|
||||
/*
|
||||
@@ -316,6 +316,86 @@ struct { \
|
||||
(head)->sqh_last = &(elm)->field.sqe_next; \
|
||||
} 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.
|
||||
*/
|
||||
@@ -553,12 +633,12 @@ struct { \
|
||||
#define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \
|
||||
if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \
|
||||
CIRCLEQ_END(head)) \
|
||||
(head).cqh_last = (elm2); \
|
||||
(head)->cqh_last = (elm2); \
|
||||
else \
|
||||
(elm2)->field.cqe_next->field.cqe_prev = (elm2); \
|
||||
if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \
|
||||
CIRCLEQ_END(head)) \
|
||||
(head).cqh_first = (elm2); \
|
||||
(head)->cqh_first = (elm2); \
|
||||
else \
|
||||
(elm2)->field.cqe_prev->field.cqe_next = (elm2); \
|
||||
_Q_INVALIDATE((elm)->field.cqe_prev); \
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* Signal management - Be conservative with what finit responds to!
|
||||
*
|
||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||
* Copyright (c) 2008-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
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -49,7 +49,6 @@
|
||||
|
||||
static int stopped = 0;
|
||||
|
||||
|
||||
void do_shutdown (int sig)
|
||||
{
|
||||
touch(SYNC_SHUTDOWN);
|
||||
@@ -57,12 +56,15 @@ void do_shutdown (int sig)
|
||||
if (sdown)
|
||||
run_interactive(sdown, "Calling shutdown hook: %s", sdown);
|
||||
|
||||
/* Call all shutdown hooks before rebooting... */
|
||||
plugin_run_hooks(HOOK_SHUTDOWN);
|
||||
|
||||
/* Here is where we signal watchdogd to do a forced reset for us */
|
||||
_d("Sending SIGTERM to all processes.");
|
||||
kill(-1, SIGTERM);
|
||||
|
||||
sleep(1);
|
||||
/* Call all shutdown hooks, this is the last call before rebooting... */
|
||||
plugin_run_hooks(HOOK_SHUTDOWN);
|
||||
/* Wait for WDT to timeout, should be no more than ~1 sec. */
|
||||
do_sleep(2);
|
||||
|
||||
_d("Sending SIGKILL to remaining processes.");
|
||||
kill(-1, SIGKILL);
|
||||
@@ -108,14 +110,14 @@ static void sigstop_handler(int sig, siginfo_t *info, void *UNUSED(ctx))
|
||||
_d("Received SIGSTOP(%d) from %s (PID %d)",
|
||||
sig, pid_get_name(info->si_pid, NULL, 0), info->si_pid);
|
||||
touch(SYNC_STOPPED);
|
||||
stopped ++;
|
||||
stopped++;
|
||||
}
|
||||
static void sigcont_handler(int sig, siginfo_t *info, void *UNUSED(ctx))
|
||||
{
|
||||
_d("Received SIGCONT(%d) from %s (PID %d)",
|
||||
sig, pid_get_name(info->si_pid, NULL, 0), info->si_pid);
|
||||
stopped = 0;
|
||||
remove(SYNC_STOPPED);
|
||||
erase(SYNC_STOPPED);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -150,8 +152,8 @@ void sig_setup(void)
|
||||
_d("Setup signals");
|
||||
|
||||
/* Cleanup any stale finit control files */
|
||||
remove(SYNC_SHUTDOWN);
|
||||
remove(SYNC_STOPPED);
|
||||
erase(SYNC_SHUTDOWN);
|
||||
erase(SYNC_STOPPED);
|
||||
|
||||
/* Standard SysV init calls ctrl-alt-delete handler */
|
||||
SETSIG(sa, SIGINT, shutdown_handler, 0);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* Signal management - Be conservative with what finit responds to!
|
||||
*
|
||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||
* Copyright (c) 2008-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
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* Finit service monitor and heneric API for managing svc_t structures
|
||||
/* Finit service monitor, task starter and generic API for managing svc_t
|
||||
*
|
||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||
* Copyright (c) 2008-2012 Joachim Nilsson <troglobit@gmail.com>
|
||||
* Copyright (c) 2008-2013 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -24,17 +24,20 @@
|
||||
|
||||
#include <string.h>
|
||||
#include <sys/wait.h>
|
||||
#include <utmp.h>
|
||||
|
||||
#include "finit.h"
|
||||
#include "helpers.h"
|
||||
#include "private.h"
|
||||
#include "sig.h"
|
||||
#include "tty.h"
|
||||
#include "lite.h"
|
||||
#include "svc.h"
|
||||
|
||||
/* 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
|
||||
* 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 svc_t *services = NULL; /* List of registered services, in shared memory. */
|
||||
|
||||
@@ -122,25 +125,132 @@ svc_t *svc_iterator(int restart)
|
||||
}
|
||||
|
||||
/**
|
||||
* svc_register - Register a non-backgrounding service to be monitored
|
||||
* svc_bootstrap - Start bootstrap services and tasks
|
||||
*
|
||||
* System startup, runlevel S, where only services, tasks and
|
||||
* run commands absolutely essential to bootstrap are located.
|
||||
*/
|
||||
void svc_bootstrap(void)
|
||||
{
|
||||
svc_t *svc;
|
||||
|
||||
_d("Bootstrapping all services in runlevel S from %s", FINIT_CONF);
|
||||
for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
|
||||
svc_cmd_t cmd = svc_enabled(svc, 0, NULL);
|
||||
|
||||
if (SVC_START == cmd || (SVC_RELOAD == cmd))
|
||||
svc_start(svc);
|
||||
}
|
||||
}
|
||||
|
||||
static int encode(int lvl)
|
||||
{
|
||||
if (!lvl)
|
||||
return 0;
|
||||
|
||||
return lvl + '0';
|
||||
}
|
||||
|
||||
static void utmp_save(int pre, int now)
|
||||
{
|
||||
struct utmp utent;
|
||||
|
||||
utent.ut_type = RUN_LVL;
|
||||
utent.ut_pid = (encode(pre) << 8) | (encode(now) & 0xFF);
|
||||
strlcpy(utent.ut_user, "runlevel", sizeof(utent.ut_user));
|
||||
|
||||
setutent();
|
||||
pututline(&utent);
|
||||
endutent();
|
||||
}
|
||||
|
||||
/**
|
||||
* svc_runlevel - Change to a new runlevel
|
||||
* @newlevel: New runlevel to activate
|
||||
*
|
||||
* Stops all services not in @newlevel and starts, or lets continue to run,
|
||||
* those in @newlevel. Also updates @prevlevel and active @runlevel.
|
||||
*/
|
||||
void svc_runlevel(int newlevel)
|
||||
{
|
||||
svc_t *svc;
|
||||
|
||||
if (runlevel == newlevel)
|
||||
return;
|
||||
|
||||
if (newlevel < 0 || newlevel > 9)
|
||||
return;
|
||||
|
||||
prevlevel = runlevel;
|
||||
runlevel = newlevel;
|
||||
utmp_save(prevlevel, newlevel);
|
||||
|
||||
for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
|
||||
int run = svc_enabled(svc, 0, NULL);
|
||||
|
||||
if (svc->pid) {
|
||||
if (run == SVC_STOP)
|
||||
svc_stop(svc);
|
||||
else if (run == SVC_RELOAD)
|
||||
svc_reload(svc);
|
||||
} else {
|
||||
if (run == SVC_START)
|
||||
svc_start(svc);
|
||||
}
|
||||
}
|
||||
|
||||
if (0 == runlevel) {
|
||||
do_shutdown(SIGUSR2);
|
||||
return;
|
||||
}
|
||||
if (6 == runlevel) {
|
||||
do_shutdown(SIGUSR1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (runlevel == 1)
|
||||
touch("/etc/nologin"); /* Disable login in single-user mode */
|
||||
else
|
||||
erase("/etc/nologin");
|
||||
|
||||
if (0 != prevlevel)
|
||||
tty_runlevel(runlevel);
|
||||
}
|
||||
|
||||
/**
|
||||
* svc_register - Register service, task or run commands
|
||||
* @type: %SVC_CMD_SERVICE(0), %SVC_CMD_TASK(1), %SVC_CMD_RUN(2)
|
||||
* @line: A complete command line with -- separated description text
|
||||
* @username: Optional username to run service as, or %NULL to run as root
|
||||
*
|
||||
* Actually, the @line can optionally start with a username, denoted by
|
||||
* an @ character. Like this:
|
||||
* This function is used to register commands to be run on different
|
||||
* system runlevels with optional username. The @type argument details
|
||||
* if it's service to bo monitored/respawned (daemon), a one-shot task
|
||||
* or a command that must run in sequence and not in parallell, like
|
||||
* service and task commands do.
|
||||
*
|
||||
* "service [@username] /path/to/daemon -- Description text"
|
||||
* The @line can optionally start with a username, denoted by an @
|
||||
* character. Like this:
|
||||
*
|
||||
* The [] brackets means the argument is optional. If the username is
|
||||
* left out the daemon is started as root.
|
||||
* "service @username [!0-6,S] /path/to/daemon arg -- Description text"
|
||||
* "task @username [!0-6,S] /path/to/task arg -- Description text"
|
||||
* "run @username [!0-6,S] /path/to/cmd arg -- Description text"
|
||||
*
|
||||
* If the username is left out the command is started as root.
|
||||
|
||||
* The [] brackets are there to denote the allowed runlevels. Allowed
|
||||
* runlevels mimic that of SysV init with the addition of the 'S'
|
||||
* runlevel, which is only run once at startup. It can be seen as the
|
||||
* system bootstrap. If a task or run command is listed in more than the
|
||||
* [S] runlevel they will be called when changing runlevel.
|
||||
*
|
||||
* Returns:
|
||||
* POSIX OK(0) on success, or non-zero errno exit status on failure.
|
||||
*/
|
||||
int svc_register(char *line, char *username)
|
||||
int svc_register(int type, char *line, char *username)
|
||||
{
|
||||
int i = 0;
|
||||
char *cmd, *desc;
|
||||
char *cmd, *desc, *runlevels = NULL;
|
||||
svc_t *svc;
|
||||
|
||||
if (!line) {
|
||||
@@ -159,8 +269,13 @@ int svc_register(char *line, char *username)
|
||||
return errno = ENOENT;
|
||||
}
|
||||
|
||||
if (cmd[0] == '@') { /* @username */
|
||||
username = &cmd[1];
|
||||
while (cmd) {
|
||||
if (cmd[0] == '@') /* @username */
|
||||
username = &cmd[1];
|
||||
else if (cmd[0] == '[') /* [runlevels] */
|
||||
runlevels = &cmd[0];
|
||||
else
|
||||
break;
|
||||
|
||||
/* Check if valid command follows... */
|
||||
cmd = strtok(NULL, " ");
|
||||
@@ -170,21 +285,28 @@ int svc_register(char *line, char *username)
|
||||
|
||||
svc = svc_new();
|
||||
if (!svc) {
|
||||
_e("Out of memorym, cannot register service %s", cmd);
|
||||
_e("Out of memory, cannot register service %s", cmd);
|
||||
return errno = ENOMEM;
|
||||
}
|
||||
|
||||
svc->type = type;
|
||||
|
||||
if (desc)
|
||||
strlcpy(svc->desc, desc + 3, sizeof(svc->desc));
|
||||
|
||||
if (username)
|
||||
strlcpy(svc->username, username, sizeof(svc->username));
|
||||
strlcpy(svc->cmd, cmd, sizeof(svc->cmd));
|
||||
strlcpy(svc->args[i++], cmd, sizeof(svc->args[0]));
|
||||
|
||||
strlcpy(svc->cmd, cmd, sizeof(svc->cmd));
|
||||
|
||||
strlcpy(svc->args[i++], cmd, sizeof(svc->args[0]));
|
||||
while ((cmd = strtok(NULL, " ")))
|
||||
strlcpy(svc->args[i++], cmd, sizeof(svc->args[0]));
|
||||
svc->args[i][0] = 0;
|
||||
|
||||
svc->runlevels = parse_runlevels(runlevels);
|
||||
_d("Service %s runlevel 0x%2x", svc->cmd, svc->runlevels);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -210,6 +332,9 @@ svc_cmd_t svc_enabled(svc_t *svc, int event, void *arg)
|
||||
return SVC_STOP;
|
||||
}
|
||||
|
||||
if (!ISSET(svc->runlevels, runlevel))
|
||||
return SVC_STOP;
|
||||
|
||||
/* Is there a service plugin registered? */
|
||||
if (svc->cb)
|
||||
return svc->cb(svc, event, arg);
|
||||
@@ -225,11 +350,29 @@ static int is_norespawn(void)
|
||||
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)
|
||||
{
|
||||
pid_t lost;
|
||||
svc_t *svc;
|
||||
|
||||
if (was_stopped && !is_norespawn()) {
|
||||
was_stopped = 0;
|
||||
restart_any_lost_procs();
|
||||
return;
|
||||
}
|
||||
|
||||
lost = waitpid(-1, NULL, WNOHANG);
|
||||
if (lost < 1)
|
||||
return;
|
||||
@@ -238,28 +381,42 @@ void svc_monitor(void)
|
||||
return;
|
||||
|
||||
/* Power user at the console, don't respawn tasks. */
|
||||
if (is_norespawn())
|
||||
if (is_norespawn()) {
|
||||
was_stopped = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (tty_respawn(lost))
|
||||
return;
|
||||
|
||||
for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
|
||||
char *name = basename(svc->cmd);
|
||||
|
||||
if (lost != svc->pid)
|
||||
continue;
|
||||
|
||||
_d("Ouch, lost pid %d - %s(%d)", lost, name, svc->pid);
|
||||
if (SVC_CMD_SERVICE != svc->type) {
|
||||
svc->pid = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
_d("Ouch, lost pid %d - %s(%d)", lost, basename(svc->cmd), svc->pid);
|
||||
|
||||
/* No longer running, update books. */
|
||||
svc->pid = 0;
|
||||
|
||||
if (sig_stopped()) {
|
||||
_e("Stopped, not respawning killed processes.");
|
||||
break;
|
||||
}
|
||||
|
||||
/* Cleanup any lingering or semi-restarting tasks before respawning */
|
||||
_d("Sending SIGTERM to service group %s", name);
|
||||
procname_kill(name, SIGTERM);
|
||||
_d("Sending SIGTERM to service group %s", basename(svc->cmd));
|
||||
procname_kill(basename(svc->cmd), SIGTERM);
|
||||
|
||||
/* Restarting lost service. */
|
||||
if (svc_enabled(svc, 0, NULL))
|
||||
if (svc_enabled(svc, 0, NULL)) {
|
||||
svc->restart_counter++;
|
||||
svc_start(svc);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -268,13 +425,13 @@ void svc_monitor(void)
|
||||
/* Remember: svc_enabled() must be called before calling svc_start() */
|
||||
int svc_start(svc_t *svc)
|
||||
{
|
||||
int respawn = svc->pid != 0;
|
||||
int respawn;
|
||||
pid_t pid;
|
||||
sigset_t nmask, omask;
|
||||
char *args[MAX_NUM_SVC_ARGS];
|
||||
sigset_t nmask, omask;
|
||||
|
||||
if (!svc)
|
||||
return 0;
|
||||
respawn = svc->pid != 0;
|
||||
|
||||
/* Don't try and start service if it doesn't exist. */
|
||||
if (!fexist(svc->cmd)) {
|
||||
@@ -291,27 +448,30 @@ int svc_start(svc_t *svc)
|
||||
if (is_norespawn())
|
||||
return 0;
|
||||
|
||||
if (!respawn)
|
||||
if (SVC_CMD_SERVICE != svc->type)
|
||||
print_desc("", svc->desc);
|
||||
else if (!respawn)
|
||||
print_desc("Starting ", svc->desc);
|
||||
|
||||
/* Block sigchild while forking. */
|
||||
sigemptyset(&nmask);
|
||||
sigaddset(&nmask, SIGCHLD);
|
||||
sigprocmask(SIG_BLOCK, &nmask, &omask);
|
||||
/* Block sigchild while forking. */
|
||||
sigemptyset(&nmask);
|
||||
sigaddset(&nmask, SIGCHLD);
|
||||
sigprocmask(SIG_BLOCK, &nmask, &omask);
|
||||
|
||||
pid = fork();
|
||||
sigprocmask(SIG_SETMASK, &omask, NULL);
|
||||
sigprocmask(SIG_SETMASK, &omask, NULL);
|
||||
if (pid == 0) {
|
||||
int i = 0;
|
||||
int uid = getuser(svc->username);
|
||||
struct sigaction sa;
|
||||
char *args[MAX_NUM_SVC_ARGS];
|
||||
|
||||
sigemptyset(&nmask);
|
||||
sigaddset(&nmask, SIGCHLD);
|
||||
sigprocmask(SIG_UNBLOCK, &nmask, NULL);
|
||||
sigemptyset(&nmask);
|
||||
sigaddset(&nmask, SIGCHLD);
|
||||
sigprocmask(SIG_UNBLOCK, &nmask, NULL);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Set desired user */
|
||||
@@ -319,7 +479,7 @@ int svc_start(svc_t *svc)
|
||||
setuid(uid);
|
||||
|
||||
/* 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] = NULL;
|
||||
|
||||
@@ -327,17 +487,18 @@ int svc_start(svc_t *svc)
|
||||
int fd;
|
||||
char buf[CMD_SIZE] = "";
|
||||
|
||||
fd = open (CONSOLE, O_WRONLY | O_APPEND);
|
||||
fd = open(CONSOLE, O_WRONLY | O_APPEND);
|
||||
if (-1 != fd) {
|
||||
dup2(STDOUT_FILENO, fd);
|
||||
dup2(STDERR_FILENO, fd);
|
||||
dup2(fd, STDOUT_FILENO);
|
||||
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];
|
||||
|
||||
snprintf(arg, sizeof(arg), "%s ", args[i]);
|
||||
if ((sizeof(buf) - strlen(buf)) < strlen(arg))
|
||||
if (strlen(arg) < (sizeof(buf) - strlen(buf)))
|
||||
strcat(buf, arg);
|
||||
}
|
||||
_e("%starting %s: %s", respawn ? "Res" : "S", svc->cmd, buf);
|
||||
@@ -351,7 +512,9 @@ int svc_start(svc_t *svc)
|
||||
}
|
||||
svc->pid = pid;
|
||||
|
||||
if (!respawn)
|
||||
if (SVC_CMD_RUN == svc->type)
|
||||
print_result(WEXITSTATUS(complete(svc->cmd, pid)));
|
||||
else if (!respawn)
|
||||
print_result(svc->pid > 1 ? 0 : 1);
|
||||
|
||||
return 0;
|
||||
@@ -379,14 +542,21 @@ int svc_stop(svc_t *svc)
|
||||
if (svc->pid <= 1) {
|
||||
_d("Bad PID %d for %s, SIGTERM", svc->pid, svc->desc);
|
||||
svc->pid = 0;
|
||||
svc->restart_counter = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
print_desc("Stopping ", svc->desc);
|
||||
if (SVC_CMD_SERVICE != svc->type)
|
||||
return 0;
|
||||
|
||||
if (runlevel != 1)
|
||||
print_desc("Stopping ", svc->desc);
|
||||
_d("Sending SIGTERM to pid:%d name:'%s'", svc->pid, pid_get_name(svc->pid, NULL, 0));
|
||||
res = kill(svc->pid, SIGTERM);
|
||||
print_result(res);
|
||||
if (runlevel != 1)
|
||||
print_result(res);
|
||||
svc->pid = 0;
|
||||
svc->restart_counter = 0;
|
||||
|
||||
return res;
|
||||
}
|
||||
@@ -412,24 +582,6 @@ int svc_reload(svc_t *svc)
|
||||
return kill(svc->pid, SIGHUP);
|
||||
}
|
||||
|
||||
void svc_start_all(void)
|
||||
{
|
||||
svc_t *svc;
|
||||
svc_cmd_t cmd;
|
||||
|
||||
for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
|
||||
cmd = svc_enabled(svc, 0, NULL);
|
||||
if (SVC_START == cmd || (SVC_RELOAD == cmd && svc->pid == 0))
|
||||
svc_start(svc);
|
||||
else if (SVC_RELOAD == cmd)
|
||||
svc_reload(svc);
|
||||
}
|
||||
|
||||
_d("Running svc up hooks ...");
|
||||
plugin_run_hooks(HOOK_SVC_UP);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* compile-command: "gcc -g -DUNITTEST -o unittest svc.c"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* Finit service monitor and heneric 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-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
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -27,6 +27,7 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h> /* strerror() */
|
||||
#include <sys/ipc.h> /* IPC_CREAT */
|
||||
#include <sys/shm.h> /* shmat() */
|
||||
#include <sys/types.h> /* pid_t */
|
||||
|
||||
@@ -36,6 +37,12 @@ typedef enum {
|
||||
SVC_RELOAD /* Enabled, needs restart */
|
||||
} svc_cmd_t;
|
||||
|
||||
typedef enum {
|
||||
SVC_CMD_SERVICE = 0, /* Monitored, will be respawned */
|
||||
SVC_CMD_TASK, /* One-shot, runs in parallell */
|
||||
SVC_CMD_RUN /* Like task, but wait for completion */
|
||||
} svc_type_t;
|
||||
|
||||
#define FINIT_SHM_ID 0x494E4954 /* "INIT", see ascii(7) */
|
||||
#define MAX_ARG_LEN 64
|
||||
#define MAX_STR_LEN 64
|
||||
@@ -49,20 +56,23 @@ typedef enum {
|
||||
* initctl <stop|start|restart> service */
|
||||
typedef struct svc {
|
||||
pid_t pid;
|
||||
svc_type_t type;
|
||||
int reload;
|
||||
int runlevels;
|
||||
unsigned int restart_counter; /* Incremented for each restart by service monitor. */
|
||||
char cmd[MAX_ARG_LEN];
|
||||
char args[MAX_NUM_SVC_ARGS][MAX_ARG_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.
|
||||
* @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.
|
||||
* @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_stop;
|
||||
int private;
|
||||
int dynamic;
|
||||
int dynamic_stop;
|
||||
int private;
|
||||
svc_cmd_t (*cb)(struct svc *svc, int event, void *event_arg);
|
||||
} svc_t;
|
||||
|
||||
@@ -71,11 +81,11 @@ typedef struct svc_map svc_map_t;
|
||||
/* Put services array in shm */
|
||||
static inline svc_t *finit_svc_connect(void)
|
||||
{
|
||||
const long ID = FINIT_SHM_ID;
|
||||
static void *ptr = (void *)-1;
|
||||
|
||||
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)
|
||||
return NULL;
|
||||
}
|
||||
@@ -83,17 +93,18 @@ static inline svc_t *finit_svc_connect(void)
|
||||
return (svc_t *)ptr;
|
||||
}
|
||||
|
||||
svc_t *svc_new (void);
|
||||
svc_t *svc_find (char *name);
|
||||
svc_t *svc_iterator (int restart);
|
||||
svc_t *svc_new (void);
|
||||
svc_t *svc_find (char *name);
|
||||
svc_t *svc_iterator (int restart);
|
||||
void svc_runlevel (int newlevel);
|
||||
|
||||
int svc_register (char *line, char *username);
|
||||
int svc_id_by_name (char *name);
|
||||
int svc_register (int type, char *line, char *username);
|
||||
int svc_id_by_name (char *name);
|
||||
svc_cmd_t svc_enabled (svc_t *svc, int event, void *arg);
|
||||
int svc_start (svc_t *svc);
|
||||
int svc_start_by_name (char *name);
|
||||
int svc_stop (svc_t *svc);
|
||||
int svc_reload (svc_t *svc);
|
||||
int svc_start (svc_t *svc);
|
||||
int svc_start_by_name (char *name);
|
||||
int svc_stop (svc_t *svc);
|
||||
int svc_reload (svc_t *svc);
|
||||
|
||||
#endif /* FINIT_SVC_H_ */
|
||||
|
||||
|
||||
@@ -0,0 +1,226 @@
|
||||
/* Finit TTY handling
|
||||
*
|
||||
* Copyright (c) 2013 Mattias Walström <lazzer@gmail.com>
|
||||
* Copyright (c) 2013 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <signal.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include "finit.h"
|
||||
#include "helpers.h"
|
||||
#include "lite.h"
|
||||
#include "tty.h"
|
||||
|
||||
LIST_HEAD(, tty_node) tty_list = LIST_HEAD_INITIALIZER();
|
||||
|
||||
|
||||
/* tty [!1-9,S] <DEV> [BAUD[,BAUD,...]] [TERM] */
|
||||
int tty_register(char *line)
|
||||
{
|
||||
tty_node_t *entry;
|
||||
int insert = 0, baud = 0;
|
||||
char *cmd, *dev;
|
||||
char *runlevels = NULL, *term = NULL;
|
||||
|
||||
if (!line) {
|
||||
_e("Invalid input argument.");
|
||||
return errno = EINVAL;
|
||||
}
|
||||
|
||||
cmd = strtok(line, " ");
|
||||
if (!cmd) {
|
||||
incomplete:
|
||||
_e("Incomplete tty, cannot register.");
|
||||
return errno = EINVAL;
|
||||
}
|
||||
|
||||
if (cmd[0] == '[') { /* [runlevels] */
|
||||
runlevels = &cmd[0];
|
||||
dev = strtok(NULL, " ");
|
||||
if (!dev)
|
||||
goto incomplete;
|
||||
} else {
|
||||
dev = cmd;
|
||||
}
|
||||
|
||||
cmd = strtok(NULL, " ");
|
||||
if (cmd) {
|
||||
baud = strtonum(cmd, 50, 4000000, NULL);
|
||||
term = strtok(NULL, " ");
|
||||
}
|
||||
|
||||
entry = tty_find(dev);
|
||||
if (!entry) {
|
||||
insert = 1;
|
||||
entry = calloc(1, sizeof(*entry));
|
||||
if (!entry)
|
||||
return errno = ENOMEM;
|
||||
}
|
||||
|
||||
entry->data.name = strdup(dev);
|
||||
if (!baud)
|
||||
baud = BAUDRATE;
|
||||
entry->data.baud = baud;
|
||||
entry->data.term = term ? strdup(term) : NULL;
|
||||
entry->data.runlevels = parse_runlevels(runlevels);
|
||||
_d("Registering tty %s at %d baud with term=%s on runlevels %s", dev, baud, term ?: "N/A", runlevels);
|
||||
|
||||
if (insert)
|
||||
LIST_INSERT_HEAD(&tty_list, entry, link);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
tty_node_t *tty_find(char *dev)
|
||||
{
|
||||
tty_node_t *entry;
|
||||
|
||||
LIST_FOREACH(entry, &tty_list, link) {
|
||||
if (!strcmp(dev, entry->data.name))
|
||||
return entry;
|
||||
}
|
||||
|
||||
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 *entry;
|
||||
|
||||
LIST_FOREACH(entry, &tty_list, link) {
|
||||
if (entry->data.pid == pid)
|
||||
return entry;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void tty_start(finit_tty_t *tty)
|
||||
{
|
||||
int i = 0, is_console = 0;
|
||||
char *cmd, *arg;
|
||||
char line[FILENAME_MAX];
|
||||
char *args[42];
|
||||
|
||||
if (tty->pid)
|
||||
return;
|
||||
|
||||
if (console && !strcmp(tty->name, console))
|
||||
is_console = 1;
|
||||
|
||||
if (!strncmp(tty->name, _PATH_DEV, strlen(_PATH_DEV))) {
|
||||
#if defined(GETTY_AGETTY)
|
||||
snprintf(line, sizeof(line), "%s %s %d %s", GETTY, tty->name, tty->baud, tty->term ?: "");
|
||||
#elif defined(GETTY_BUSYBOX)
|
||||
snprintf(line, sizeof(line), "%s %d %s %s", GETTY, tty->baud, tty->name, tty->term ?: "");
|
||||
#else
|
||||
strlcpy(line, FALLBACK_CONSOLE, sizeof(line));
|
||||
#endif
|
||||
} else {
|
||||
strlcpy(line, tty->name, sizeof(line));
|
||||
}
|
||||
cmd = strtok(line, " ");
|
||||
args[i++] = basename(cmd);
|
||||
while ((arg = strtok(NULL, " ")))
|
||||
args[i++] = arg;
|
||||
args[i] = NULL;
|
||||
|
||||
_d("Starting %s: %s on %s", is_console ? "console" : "TTY", cmd, tty->name);
|
||||
tty->pid = run_getty(cmd, args, is_console);
|
||||
}
|
||||
|
||||
void tty_stop(finit_tty_t *tty)
|
||||
{
|
||||
if (!tty->pid)
|
||||
return;
|
||||
|
||||
_d("Stopping TTY %s", tty->name);
|
||||
kill(tty->pid, SIGTERM);
|
||||
do_sleep(2);
|
||||
kill(tty->pid, SIGKILL);
|
||||
waitpid(tty->pid, NULL, 0);
|
||||
tty->pid = 0;
|
||||
}
|
||||
|
||||
int tty_enabled(finit_tty_t *tty, int runlevel)
|
||||
{
|
||||
if (!tty)
|
||||
return 0;
|
||||
|
||||
if (!ISSET(tty->runlevels, runlevel))
|
||||
return 0;
|
||||
else if (fexist(tty->name))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* TTY monitor, called by svc_monitor() */
|
||||
int tty_respawn(pid_t pid)
|
||||
{
|
||||
tty_node_t *entry = tty_find_by_pid(pid);
|
||||
|
||||
if (!entry)
|
||||
return 0;
|
||||
|
||||
/* Clear PID to be able to respawn it. */
|
||||
entry->data.pid = 0;
|
||||
|
||||
if (!tty_enabled(&entry->data, runlevel))
|
||||
tty_stop(&entry->data);
|
||||
else
|
||||
tty_start(&entry->data);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Start all TTYs that exist in the system and are allowed at this runlevel */
|
||||
void tty_runlevel(int runlevel)
|
||||
{
|
||||
tty_node_t *entry;
|
||||
|
||||
LIST_FOREACH(entry, &tty_list, link) {
|
||||
if (!tty_enabled(&entry->data, runlevel))
|
||||
tty_stop(&entry->data);
|
||||
else
|
||||
tty_start(&entry->data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* version-control: t
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,66 @@
|
||||
/* Finit TTY handling
|
||||
*
|
||||
* Copyright (c) 2013 Mattias Walström <lazzer@gmail.com>
|
||||
* Copyright (c) 2013 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef FINIT_TTY_H_
|
||||
#define FINIT_TTY_H_
|
||||
|
||||
#include "queue.h" /* BSD sys/queue.h API */
|
||||
|
||||
#define EVENT_SIZE ((sizeof(struct inotify_event) + 20))
|
||||
|
||||
typedef struct {
|
||||
char *name;
|
||||
int baud;
|
||||
char *term;
|
||||
int runlevels;
|
||||
|
||||
int pid;
|
||||
} finit_tty_t;
|
||||
|
||||
typedef struct tty_node {
|
||||
LIST_ENTRY(tty_node) link;
|
||||
finit_tty_t data;
|
||||
} tty_node_t;
|
||||
|
||||
//extern LIST_HEAD(, tty_node) tty_list;
|
||||
|
||||
int tty_register (char *line);
|
||||
tty_node_t *tty_find (char *dev);
|
||||
size_t tty_num (void);
|
||||
tty_node_t *tty_find_by_pid (pid_t pid);
|
||||
void tty_start (finit_tty_t *tty);
|
||||
void tty_stop (finit_tty_t *tty);
|
||||
int tty_enabled (finit_tty_t *tty, int runlevel);
|
||||
int tty_respawn (pid_t pid);
|
||||
void tty_runlevel (int runlevel);
|
||||
|
||||
#endif /* FINIT_TTY_H_ */
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* version-control: t
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
Reference in New Issue
Block a user