Compare commits

..
104 Commits
Author SHA1 Message Date
Joachim Nilsson 849f3fbb28 Explain finit.conf commands more in README, update example .conf
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-06-07 14:09:46 +02:00
Joachim Nilsson 329acf24bb Bump version and start preparing docs for release of 1.8
Renamed ChangeLog to NEWS and fixed doc style to use ReST, like the
README and TODO files.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-06-07 09:16:00 +02:00
Joachim Nilsson bf40278131 Delay start of TTYs to let system stabilize at boot.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-06-06 18:19:27 +02:00
Joachim Nilsson 4f2cf52eff Minor cleanup. 2013-06-06 18:19:27 +02:00
Joachim Nilsson f96fb855ce tty: Clear PID to be able to respawn it.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-06-06 18:19:27 +02:00
Joachim Nilsson 65f0be8a55 Simplify banner further, let distributions patch us instead.
Revert crazy BANNER macro idea from 5ba7bc1.  It is simply too difficult to
set -DBANNER='"Some distributions specific text"' in a parent Makefile
without entering Shell/Make escape hell ... instead, downstream will
have to patch the banner() function.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-06-06 18:19:26 +02:00
Joachim Nilsson bcfcafdb7c tty: Use calloc() instead of malloc() to prevent uninitialized errors.
On some platforms GCC does not zero the heap. This can lead to
serious problems, e.g., tty->pid may be non-zero while never
having been started.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-06-06 18:19:26 +02:00
Joachim Nilsson c57bd066d1 Build fix, if ROOTDIR was set linking failed. Use TOPDIR internally.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-06-06 18:19:26 +02:00
Joachim Nilsson 4171fbdfd3 Store RUN_LVL in UTMP and change RUNLEVEL_BOOT from 10 to 0
Standard init implementations save current and previous runlevels
in utmp, now finit does too.  Also, the initial runlevel at boot
has changed from 10 to the more obvious 0.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-06-06 18:19:26 +02:00
Joachim Nilsson 0f60aa2289 Refactor TTY code to honor runlevels and use I/O plugin to watch /dev
Add support for runlevels to tty command and support for reading baud
rate and TERM variable from finit.conf.

The tty-watcher thread has been converted to a standard I/O plugin.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-06-06 18:19:26 +02:00
Joachim Nilsson f97aab4699 Rename stat_restart_counter --> restart_counter
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-06-06 18:19:18 +02:00
Joachim Nilsson 740d447442 Update Debian 6.0 example /etc/finit.conf and /etc/finit.d
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-06-04 13:12:53 +02:00
Joachim Nilsson 6448d6ccfa Coding style and whitespace fixes
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-06-04 09:25:11 +02:00
Joachim Nilsson 25cc9f3b9b Improve runlevel support by adding a bootstrap phase, also adds task/run cmd
Most systems need an early bootstrap phase for one-shot tasks and
necessary one-time probing.  This phase usually runs well before any
networking is setup.  This commit adds support for that 'S' runlevel,
and also extends the number of possible total runlevels to nine.

For the one-shot tasks that run in bootstrap two new finit.conf cmds
have been added:

   - task: For one-shot tasks that can be started in parallell
   - run:  For one-shot tasks that must run in sequence

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-06-04 09:25:05 +02:00
Joachim Nilsson e776838de9 Rename USE_UDEV & MDEV to SETUP_DEVFS and USE_MESSAGE_BUS to HAVE_DBUS
USE_UDEV,MDEV   => Unique SETUP_DEVFS for embedded or distro usage.
USE_MESSAGE_BUS => HAVE_DBUS

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-06-04 07:21:08 +02:00
Joachim Nilsson bf0cfe0693 Update and clarify TODO items, e.g., add info on new "task" and "run" stanzas
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-06-04 07:21:00 +02:00
Joachim Nilsson f690767507 Refactor .conf file parser and add support for runlevel N
This commit is a refactor of how arguments to finit.conf file settings
are parsed.  Not all settings are run directly, but only need the arg
for future use.  The code should be a lot easier to understand now.

Also, added support for specifying the desired runlevel in finit.conf

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-05-22 12:42:56 +02:00
Joachim Nilsson 4d57b14b5b Bugfix chomp() and set_hostname()
chomp():
        Removed first \n instead of last \n

set_hostname():
        If /etc/hostname exists we need to realloc the size of
        the current hostname variable. Also, only try to set
        the hostname if !NULL

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-05-22 12:41:59 +02:00
Joachim Nilsson 263036045a tty: Check input arguments for invalid tty before adding.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-05-22 12:36:19 +02:00
Joachim Nilsson 56ef3f75d3 Build: Make subdir build prettier.
The ROOTDIR variable was only set in the top-level Makefile,
so when building from a subdirectory the output was slightly
garbled.  Moved ROOTDIR declaration to common.mk.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-05-22 06:18:52 +02:00
Joachim Nilsson d0c902ab78 libite: Add strtonum() from OpenBSD
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-05-21 19:55:41 +02:00
Joachim Nilsson 5ba7bc1fdf Cleanup and simplify boot process messages
- Remove indentation of module loading and device node creation
- Clarify that we load kernel modules
- Clarify that we load Finit plugins
- Remove cls()
- Remove verbose condition for echo()
- Make banner a separate function with optional distribution banner
- Add a few neat ANSI escape sequences for cls(), clreol(), delline(), etc.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-05-21 12:52:06 +02:00
Joachim Nilsson 7e9ac7ba67 Fix indentation and ReST syntax.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-05-20 15:32:04 +02:00
Joachim Nilsson e2eaee9620 TODO: Add entry on mimicing Debian SysV init rcS.d, runs once at boot.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-05-20 15:25:14 +02:00
Joachim Nilsson b23ce7ab8e Update TODO
More inspiration and courage from the launchd Google Talk video!
Fascinating stuff about replacing init/inetd/cron/watchdogd that
I've been thinking about for ages!

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-05-19 23:39:23 +02:00
Joachim Nilsson 53127a7ce6 Update TODO
Move to use ReST syntax, like README, and update to reflect current
status of project.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-05-19 19:01:45 +02:00
Joachim Nilsson 011b73ba39 Fix issue with "Formatting of boot text changes in the middle of the boot."
This commit adds a line: "Loading kernel modules ..." before increasing
indentation level of module loading messages.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-05-19 19:01:45 +02:00
Mattias Walström 5d04a72a61 Add support for toggling the debug mode at runtime
This commit adds support for -d, --debug option to init, which can
be used to toggle the finit debug mode at runtime.

Signed-off-by: Mattias Walström <lazzer@gmail.com>
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-05-19 19:01:44 +02:00
Joachim Nilsson c3b76fdccf Add basic support for runlevels and bugfix FIFO I/O plugins
Like most other init implementations do, when entering runlevel 1, finit
creates the file /etc/nologin to prevent users from logging in during
single-user mode, this file is then removed upon leaving runlevel 1.

Also, bugfix how FIFO I/O plugins are handled in finit.  A FIFO will
need to be reopened by the server side when the client closes the pipe.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-05-19 19:01:44 +02:00
Mattias Walström ec95243dad libite: Fix memory leak in dir()
Signed-off-by: Mattias Walström <lazzer@gmail.com>
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-05-19 19:01:44 +02:00
Joachim Nilsson ae5d4a0bb2 Add support for user/distribution specific banner at startup.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-05-19 19:01:44 +02:00
Joachim Nilsson 0231f858e9 helpers.c: Make system message optional top run_interactive()
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-05-19 19:01:44 +02:00
Joachim Nilsson 5d6db9f76f tty.c: Minor cleanup and check global variable before dereferencing.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-05-19 19:01:44 +02:00
Mattias Walström 3bcefd2160 Add support for specifying TTYs and console TTY in finit.conf
This commit adds support for specifying TTY and console to be used
for starting a getty to login to the system

Add the following to your finit.conf to use this feature:

    tty ttyS0
    tty ttyUSB0
    console ttyS0

Signed-off-by: Mattias Walström <lazzer@gmail.com>
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-05-19 18:45:27 +02:00
Joachim Nilsson 89675403d8 Add support for service restart counter.
This commit adds a statistics counter to the finit svc_t process struct
which is incremented every time a process is restarted by the service
monitor.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-05-19 18:00:31 +02:00
Joachim Nilsson f277166354 sig.c: Use watchdogd to reboot system
This patch reorders the shutdown/reboot handler slightly and fixes
a bug in sleep().  It seems the sleep() syscall was interrupted by
receiving lots of SIGCHLD.  Unsurprisingly since we just sent all
processes SIGTERM, but unfortunate since that was too short time
to deliver SIGTERM to watchdogd.

We now call sleep() again, as long as it returns a non-zero value,
until at most two (2) seconds have passed.  During this time we
basically pend for watchdogd to do its job and let the WDT reboot
the system.  If the two second timeout passes we send SIGKILL and
forcibly reboot(RB_AUTOBOOT) the system.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-05-19 18:00:31 +02:00
Joachim Nilsson b212babc87 helpers.c: Fix run() argparser, assumed all commands have args. 2013-05-19 18:00:31 +02:00
Joachim Nilsson 6518c2d246 libite: Improve error handling for copyfile() and rsync()
When using the simple rsync() or copyfile() functions of libite some
error codes should not be interpreted as error.  I.e., if a file or
directory already exists when attempting to create it.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-05-19 18:00:31 +02:00
Joachim Nilsson c551228079 Makefile: Minor cleanup and only set ROOTDIR if unset already.
The ROOTDIR variable is used for pretty formatting during compilation.
Some users might want to have this display the build from the top of
their tree instead of the finit build tree.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-05-19 18:00:31 +02:00
Joachim Nilsson c1198087af TODO: Update with requests for more consoles and runlevel support 2013-05-19 18:00:31 +02:00
Joachim Nilsson 990ccc6d8b Merge pull request #2 from mattiaswal/eglibc
Add support for strlcpy and strlcat
2013-02-19 09:30:22 -08:00
Joachim Nilsson 56a16066b7 Merge pull request #1 from mattiaswal/tty
Add basic support to specify TTYs in configuration
2013-02-19 09:30:06 -08:00
Mattias Walström 407a47dd12 libite: Add strlcat and strlcpy.
These function only exist on uClibc and BSD, so if they
not already defined in string.h, define them here.
2013-01-29 13:29:45 +01:00
Mattias Walström 73b43b4f2b Add missing include <sys/stat.h> 2013-01-29 13:16:21 +01:00
Mattias Walström 5961748b2a Add basic support to specify login TTYs in configuration
This also adds support for monitor /dev for TTYs appering after boot,
USB-to-serial converters for example.

Some limitations: Baudrate (and other settings) is hardcoded for now,
should be read from config file.
2013-01-22 21:17:20 +01:00
Joachim Nilsson a18c5f3441 Update ChangeLog and bump version for release.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-10-08 12:05:21 +02:00
Joachim Nilsson 03c47a4020 Only cls() when verbose mode enabled, maybe we should remove it?
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-10-08 11:59:56 +02:00
Joachim Nilsson 77b0df3d07 Bugfix: Do not free() static string in new runparts directive
This is a bugfix to 785c21d, which introduced the new runparts
directive in finit.conf

- Do not attempt to free() a static string, use same approach as
  username and hostname.

- Do not overwrite hostname, set the correct variable if runparts
  directive is found in finit.conf

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-10-08 11:42:19 +02:00
Joachim Nilsson 7e3465a022 Clear recorded PID of lost service.
Many callbacks check their svc->pid to determine SVC_RELOAD or SVC_START,
they rely on it to be updated.  When a service is lost we must therefore
clear its recorded PID before asking the callback what to do.

Also, swap comparison in debug code for dumping service arguments ...

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-10-07 02:00:16 +02:00
Joachim Nilsson 04fd3f7a1b Add __FILE__ to _d() debug to see finit:plugin.c:enabled() ...
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-10-06 21:32:26 +02:00
Joachim Nilsson 685618691d Update ChangeLog and bump version for release. 2012-10-06 18:07:39 +02:00
Joachim Nilsson f29d2733c7 Fix incorrect use of variable arguments in run_parts() and simplify code
The run_parts() implementation used variable arguments in a bad way,
resulting in it not working properly.  Replaced va_*() code with a
simple cmd argument that's passed to each script called.

Also, the opendir()/readdir() code has been replaced with scandir()
using regular alphasort(). This simplifies the code somewhat as well.

Otherwise, minor cleanups.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-10-06 15:45:42 +02:00
Joachim Nilsson af59174e49 Prevent endless restart of non-existing services and support start-stop scripts
Sometimes people type in the wrong path to a service directive in
finit.conf, or the executable isn't installed.  This commit makes
sure to check if the command exists before attempting to start it.
This also means that we now require service commands to start with
/ to indicate an absolute path.  We used to search the PATH for a
suitable executable, using execvp(), but that's rather insecure as
well, so we now use only execv().

Also, added support for adding "start" or "stop" to entries found
in /etc/finit.d starting with SNNname, or KNNname, where NN is a
number.  This makes it possible to simply import sysvinit style
start scripts from /etc/rcS.d and /etc/rcN.d/.

The alsa-utils plugin also had some minor fixes, added -g option
to ignore non-existing soundcards and fixed cut-paste bug on the
_d() debug messages.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-10-06 13:56:26 +02:00
Joachim Nilsson 785c21d27b Support for overriding built-in default FINIT_RCSD in finit.conf
This commit adds support for the "runparts <DIR>" directive to
finit.conf.  Enabling the user to override the built-in default,
which by default is /etc/finit.d.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-10-05 18:50:21 +02:00
Joachim Nilsson 40c7a44d4f Skip . and .. in plugin loader and trigger error on failed plugin load.
Fix from field testing.  Need to skip "." and ".." directory entries
when loading plugins from /lib/finit/plugins.  Also, trigger an error
when a required plugin fails to load.  We need to print to console
since syslogd has not started yet.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-10-04 17:22:40 +02:00
Joachim Nilsson cbb50937cd Update ChangeLog and bump version.
New release, 1.5! :)

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-10-03 23:30:23 +02:00
Joachim Nilsson 83a4bf7947 Add dependency resolver for plugins.
This has been something I wanted to avoid, but then I stumbled so hard
on it myself I simply had to add it.  With this commit finit actually
comes of age -- it's now possible to do anything a modern init can --
only faster! :-)

Included in this commit is the OpenBSD version of sys/queue.h, which
unline all versions of the same file on Linux has the _FOREACH_SAFE
macros for iterating over a linked list.

The plugins are now in a TAILQ, loaded in alphabetic order and, unless
the dependency resolver says otherwise, added last in the queue.  So,
naming your plugins according to standard sysvinit rules: S01, S02,
etc. takes care of the most basic dependency resolution.  When that is
not sufficient, simply add a line ".depends = { "other_plugin",
"another_plugin" }," to your plugin_t definition.  Be careful though
for circular dependencies, we don't check for those.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-10-03 23:20:34 +02:00
Joachim Nilsson 0d7d5a9820 Setup standard FHS 2.3 structure in /var
This was missing from the 1.4 release due to it being hidden in one
of my private plugins. Sorry!

Also, add another log macro. Warnings are quite useful things to have.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-10-03 11:44:33 +02:00
Joachim Nilsson 65c9e7ebc6 Fix I/O plugin watcher, load plugins earlier to enable a new early hook!
Restructure start by calling the plugin loader earlier. This makes it
possible to run hooks even earlier.  This also adds a new hook:
HOOK_ROOTFS_UP which runs as soon as the system root (/) is available.

Another very notable change is the slow refactor of helpers.c into a finit
helper library called libite.so (-lite). This is a light-weight

Also, lots of misc. fixes all over the place. Signal handling still really
needs to be looked into once more!

Makefile:
        Add dependency handling for parallell build
        Add libite library

ChangeLog:
        Update with new 1.4 release. There is a lot of fixes!

libite/:
        Collection of utility functions and C library extensions for
        finit & its plugins

reboot.c:
        New reboot tool. Simply sends SIGINT to PID 1

finit.h:
        Cleanup old LISTEN_INITCTL define, code is in an optional plugin now

finit.c:
        Let mdev/udev run *after* cls()
        Add useful debug statement for /proc/cmdline
        Earlier plugin load => new early hook point
        Show OK/FAIL for total plugin load, not for each plugin => speedup

helpers.h:
        Rename syslog macros to prevent common name clashes (DEBUG/ERROR)
        Add __FILE__ to _e(), _d() and _pe() macros

helpers.c:
        In ifconfig() the addr and mask arguments are now optional
        The copyfile() has been moved to libite.so
        Temporarily remove const directive from some functions to build
        Use DFLSIG() macro in run_getty() to simplify code

plugin.h:
        Add new HOOK_ROOTFS_UP hook

plugin.c:
        Fix init_plugins() to actually register the plugin's I/O fd
        Skip verbose listing of all plugins in plugin_load_all()

svc.c:
        svc_start(): Dito

plugins/Makefile:
        Inherit CFLAGS and LDFLAGS, but make sure to filter out -rdynamic
        from LDFLAGS, it's used by the daemon, only

plugins/initctl.c:
        New includes after helpers.h refactor

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-10-02 08:25:50 +02:00
Joachim Nilsson c002b5301f plugins/hwclock: Use short-form -s/-w -u to work with BusyBox hwclock as well.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-10-02 06:39:26 +02:00
Joachim Nilsson 3f1c2f6211 Plugin loader and registration fixes
- Use RTLD_GLOBAL flag to tell dynamic loader to load dependent .so
  files as well.  Also lets other plugins use globally scoped symbols.

- Check for plugin hooks as well before dismissing plugin as unused.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-10-02 06:39:26 +02:00
Joachim Nilsson 5116cd66ef Greatly simplify svc hook for external plugins
This commit removes a lot of unnecessary overhead for handling external
service plugins.  Instead of traversing the plugin array every time a
service callback should run we set the plugin callback in the svc_t when
the plugin is registered.

Also, make sure to check for norespawn/SIGSTOP in svc_reload() as well.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-10-02 06:39:26 +02:00
Joachim Nilsson f55f68d032 Cleanup and refactor of public plugin API
Improve upon API names, both internal and external, to make it clearer
where methods are located and clarify responsibility.

Add new Makefile target "dev" to create untagged development snapshots.

Bump version for upcoming release.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-10-02 06:39:19 +02:00
Joachim Nilsson 5e99b5e735 Minor API change.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-09-29 15:13:13 +02:00
Joachim Nilsson d26852e07a README: Further cleanup
Remove prefix= from list of overridden environment variables in example.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-09-28 18:00:49 +02:00
Joachim Nilsson a90a7c04e4 README: Further updates, clarification and additions on, e.g., running finit.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-09-28 17:56:26 +02:00
Joachim Nilsson 14a1fb9cde Create /etc/finit.d at install and update README with v1.3 changes.
Updates to README include changed environment variables and a
clarification of why there is no default /etc/finit.conf after make
install.

Also, the /etc/finit.d directory is now created, as expected, by
make install.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-09-28 17:26:31 +02:00
Joachim Nilsson b373e199a8 Install fixes, $prefix supported better, strip binaries and .so files
- 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/
- Use the 'plugindir' environemnt variable instead of 'PLUGIN_DIR'

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-09-28 16:46:17 +02:00
Joachim Nilsson 149ed0e81c Minor header comment updates and bump version to 1.3
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-09-28 15:59:15 +02:00
Joachim Nilsson e32ca1fc83 Keep separate install/uninstall targets for exec, data and dev files.
Break up install/uninstall targets in top Makefile into separate
install-exec, install-data, and install-dev for packagers and
distributions wishing to call Makefile with different DESTDIR's
depending on building -bin or -devel package.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-09-28 14:23:29 +02:00
Joachim Nilsson 9aa90763b0 Support for installing plugin headers to system include/finit/ directory.
Minor cleanup of Makefile and added support for installing necessary
header files, for developing external plugins, to system include path.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-09-27 23:25:41 +02:00
Joachim Nilsson 06759d3544 Streamline plugin include files plugin.h, svc.h, and helpers.h
Move utility macros from finit.h to helpers.h and continue refactoring
and streamlining of public plugin API.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-09-27 22:10:07 +02:00
Joachim Nilsson ff73dab447 Slight cleanup of public API in helpers.c
Function renames:
  - set_procname() --> procname_set()
  - kill_procname() --> procname_kill()
  - get_pidname() --> pid_get_name()

Also added three new helper functions, for external plugins:
  - pid_alive()
  - pidfile_poll()
  - pidfile_read()

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-09-27 20:56:46 +02:00
Joachim Nilsson 0d70fa4cf0 Let plugins hook into service startup to notify 3rd party daemon.
This commit adds support for calling plugin hooks when all services
have been started properly. Useful for, e.g., a 3rd party service
monitor to trigger further events on.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-09-27 15:25:10 +02:00
Joachim Nilsson 103bf33b3c Remove finit.h from includes in svc.h, not needed.
Also, when 3rd party sources include svc.h they would get finit
internals included. Not good.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-09-27 13:14:00 +02:00
Joachim Nilsson 2b2fcb740c Fix installation paths and update README on building, bump version
The installation path for plugins was encoded wrong in the finit binary
if *not* unset, i.e., "prefix=".

Updated the README with information on all build related environment
variables.  Much of it is perhaps only needed for packagers and
distributions.

New version bump, v1.2 already.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-09-27 09:33:55 +02:00
Joachim Nilsson 7542f4e199 Update ChangeLog and bump version for release. 2012-09-26 23:17:18 +02:00
Joachim Nilsson 1fece1f9b5 Work around compiler error for breaking strict-aliasing rules
This commit fixes the following warning on an ARM eabi/uClibc system.
helpers.c:86: error: dereferencing pointer 'a' does break strict-aliasing rules

The fix is trivial. Simply set IPv4 addressing scheme in the
struct ifreq instead of the struct sockaddr_in, whic is just
a pointer into the same ifreq anyway.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-09-26 23:10:53 +02:00
Joachim Nilsson 814ff1f77e Fix build problem on ARM eabi/uClibc by removing unused Linux header file.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-09-26 23:00:46 +02:00
Joachim Nilsson fbfffbc9a4 Eliminate name clash with system signal.h header file.
Tried to solve the signal.h name clash by using #include_next, but
seeing as this is not recommended[1] and breaks builds on some cross
compilers, the files were simply renamed: signal.[ch] --> sig.[ch]

[1] - http://gcc.gnu.org/onlinedocs/cpp/Wrapper-Headers.html

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-09-26 22:57:25 +02:00
Joachim Nilsson e496913f5c README: Redo feature table into a definition list.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-09-26 13:53:25 +02:00
Joachim Nilsson 5bc9ff0e20 README: Slight syntax change in feature table
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-09-26 13:49:32 +02:00
Joachim Nilsson dd0220fd2c Update and clarify README
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-09-26 13:47:57 +02:00
Joachim Nilsson bb0a378f1c Rename README --> README.rst and symlink README to it.
This change is purely for people interacting with the GitHub interface.
The README itself is written in the plain text reST format.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-09-26 13:30:05 +02:00
Joachim Nilsson 2a025356d4 Bump version, update README and add TODO and dist: target to Makefile
Preparing for 1.0 release.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-09-26 13:20:21 +02:00
Joachim Nilsson c49d89dfe0 Revert new experimental libev backend due to time constraints
Due to time constraints I had to revert the new libev backend to the
service, I/O and signals monitor.  Employed instead is the tried and
tested signals based service monitor, with a small extension for an
additional I/O monitor using poll() for the I/O plugins to use.

Tried restoring the startx finit.conf directive on top of the service
implementation. However, it's currently not usable to run /usr/bin/startx
for any other user than root. I recommend using the examples/finit.conf
and run /usr/sbin/gdm instead.

finit.c:
        New run_loop() function, replaces libev ev_run().

helpers.c:
        Refactor start_process() into svc_start().

plugin.c:
        Add fds[] array for use in the io_monitor() called by the
        new run_loop().

signal.c:
        Ignore SIGCHLD. Handled by waitpid() in svc_monitor() now,
        which is called by the new run_loop().

svc.c:
        svc_register(): Optional @username parsing for the command line.
        svc_monitor(): Replaced libev callback with waitpid()
        svc_start(): Refactored to use most of helpers.c:start_process()

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-09-26 12:18:54 +02:00
Joachim Nilsson 75eb5cc043 Move fork() of console to run_getty() and remove startx conf option
New function helpers.c:run_getty() refactored from main(). Used to
start a default console getty.

Removed startx finit.conf option, superseded by service statement,
see examples/finit.conf for a working use case.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-09-25 15:20:55 +02:00
Joachim Nilsson dfa0fe6428 Refactor conf-file parser into a file of its own.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-09-25 14:49:33 +02:00
Joachim Nilsson 0e02429e75 Convert finit to use libev and fix so plugin ctors runs on dlopen().
Lots of cleanup and simplification of the main code in this commit.
Most notably libev has been added to take care of the main loop and
monitor services. Still TODO is migrating to use the libev signal
handling.

Convert initctl.c:listen_initctl() to a plugin instead.  This also
meant introducing a new form of I/O plugin to finit, also handled
by libev.

Load plugins *after* we've setup the base filesystem (BASEFS) in case
plugins reside on a filesystem not reachable before "mount -a" has run.
This also has the side effect of lining up nicely with the first level
plugin hooks.

If a plugin wants to hook up with a loded service we connect them by
their respective numeric IDs in plugin_register().  I.e., the service
monitor checks if a service has a registered callback, which in turn
decides if a service should be started, stopped or reloaded.

Rip out old EeePC distribution defines from finit.h, none of it really
applies anymore.  If you need distribution specific settings this is
the place to put them.

Make hookpoint names (#defines) clearer: after BASEFS, after networking,
after all setup, etc.

Use #inlude_next <signal.h> in signal.h to include system header file!

Simplify service monitor: move essential code to svc.c and rip out
the TIPC dependency. Write your own service.so plugin, or wait for
a more complete example of how to extend service monitoring using
the primitives in svc.c

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-09-25 14:23:23 +02:00
Joachim Nilsson 5dda9051ac Refactor main() into more functions and convert #ifdef hell into plugins.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-09-21 03:32:07 +02:00
Joachim Nilsson 239772d667 Add basic support for dynamically loadable plugins
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-09-21 00:33:46 +02:00
Joachim Nilsson a0fa877520 Move example configuration files to examples subdirectory
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-09-21 00:31:13 +02:00
Joachim Nilsson 23ef745985 Remove deprecated finit implementations, see the 0.6-pre tag for reference.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-09-20 17:54:29 +02:00
Joachim Nilsson 077a7e82e0 Debian now boots to X!
finit.conf:
        Use this as /etc/finit.conf on a Debian 6.0 based system with X
        installed and sysklogd instead of rsyslogd.  Works.

services:
        Alternative method for extending the finit boot procedure. Simply
        place this script file in an /etc/finit.d/ directory.  The script
        uses the standard run-parts tool to chain load other start scripts.

helpers.c:
        o New functions:
          - run(): home grown system() replacement
          - run_interactive(): display progress and status when called

        o Bugfix start_process(), make sure to use same signal setup for
          children as in run() and run_interactive(). Also, use execvp()
          instead of execv() to allow searching $PATH for executables.

finit.h:
        o Move signal specific code to new signal.h.
        o Bypass verbosity setting to let echo() always print to screen.

finit.c:
        o Make run_parts() the default, remove external deps, it works.

        o Use run() and run_interactive() to speed up execution further
          on embedded systems where forking is expensive.

        o Kernel cmdline "quiet" should not close STDIO since this makes
          it impossible to run some daemons and start scripts.  Instead,
          we let "quiet" toggle the finit verbosity setting.

        o Remove kernel cmdline "--verbose" (Upstart compat), to be used
          to enable verbose finit when kernel should be quiet.

        o Setup kernel specific settings in /etc/sysctl.conf

        o Fix D-Bus startup problems. Probably what caused X from not
          working initially. Silly rabbit.

        o Use system() workaround to start X, cannot get it to start
          at all using run() or run_interactive() at the moment.

signal.h:
        New file, header file for signal.c.  Was about time.

signal.c:
        Remove blocking of SIGCHLD from sig_setup(), instead we setup
        SIGCHLD early in sig_init() to handle fork() in run() & C:o.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-09-20 17:50:53 +02:00
Joachim Nilsson d21dc2b477 Westermo service starter and supervisor, inspired by daemontools
finit.c:
        o New service and shell_service stanzas for finit.conf
        o Run service_startup() before /etc/finit.d/ hooks
        o Run service_monitor() at end of startup

helpers.c:
        o Several new functions:
          - print_desc() displays a service starting up
          - print_result() shows if service started OK or not
          - start_process() is used by the services framework

svc.c:
        Generic API for managing svc_t structures

ipc.o:
        TIPC based framework for communicating with the service monitor.
        E.g., to relay (re)configuration signals from a Web/CLI
        front-end via finit to one or many setup daemons, and back.

services.c:
        Service monitor framework

strlcpy.c:
        Secure strncpy() replacement from OpenBSD under the free ISC License.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-09-20 01:16:00 +02:00
Joachim Nilsson c0356b5c7a Massive cleanup to be able to boot Debian 6.0
Update license and copyright information details in all files.
Much cleanup by moving hard coded strings/data to #defines and using more
common default values for each such #define.

finit.c:
        o Make sdown[], startx[] allocated strings by default NULL
        o This fixes the issues where the shutdown handler segfaulted
        o Add ability to handle NULL input to build_cmd() by allocating space
        o Ignore kernel cmdline "quiet" if in debug mode
        o Add support for "network" stanza in finit.conf
        o Mount -n to skip removing /etc/mtab
        o Call swapon to enable swap if enabled in /etc/fstab
        o Cleanup /tmp, /var/run and /var/lock
        o Move sig_setup() *after* mount, sig_init() otoh runs early
        o Start initctl monitor before forking off startx/getty process
        o The startx process is now the console process. Only a getty is
          started when in debug mode. Otherwise only X is started if it
          is properly setup in /etc/finit.conf
        o NOTE: Currently X evdev does not work!
        o Support for /usr/sbin/services.sh has been replaced with finit
          now instead supporting builtin run-parts for /etc/finit.d/

helpers.c:
        o Bug fixes in run_parts() and also added chdir(oldpwd) at bottom.
        o New functions:
          - getuser() similar to getgroup()
          - cls() clear screen, only runs when not in debug mode
          - set_procname() used to set name "console" on console process
          - set_hostname() encapsulates /etc/hostname and sethostname()

signal.c:
        o Split sig_setup() in two: sig_init() and sig_setup()
          The former to be called as soon as possible, while latter is
          supposed to run when the base filesystem is properly up.
        o Remove hard coded distribution specific progress bar write()
        o Add debug messages to do_shutdown()
        o Remove any lingering sync files in sig_setup()

initctl.c:
        o Add debug messages and a new default: case to catch stray runlevels

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-09-19 18:06:12 +02:00
Joachim Nilsson 855c7d8251 Assume kernel has devtmpfs enabled --> cleanup device creation & mount
Cleanup device creation and initial mount by assuming that the kernel
has devtmpfs enabled.  This is the default for most modern GNU/Linux
distributions.  See http://lwn.net/Articles/331818/ for more info.

Also, since finit is targeted at deeply embedded systems hooks for the
BusyBox udev replacement, mdev has been added.  If MDEV is defined in
the build it will take care of both hotplugging of devices and initial
setup of /dev

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-09-17 16:05:41 +02:00
Joachim Nilsson 2f527215d0 Compat kernel command line debug option --verbose
Check for "--verbose", as well as "finit_debug", on kernel command
line to enable debugging of finit.  The former is a compatibility
option with upstart, see http://upstart.ubuntu.com/wiki/Debugging

Add the following to the kernel command line to enable:

    "init=/sbin/finit --verbose"

Without the quote characters.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-09-17 11:09:35 +02:00
Joachim Nilsson 5da4f4cfc3 Add support for standard UNIX comment chars in finit.conf
finit.c:
        Skip standard UNIX comment character '#' if it appears at the
        beginning of a row in finit.conf

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-09-17 10:43:06 +02:00
Joachim Nilsson b0aec188bc Further cleanup, move signal setup to a file of its own.
finit.c:
        o Perform signal setup as soon as possible, no need to do any
          mounting of /proc or /sys beforehand
        o Move signal setup and callbacks to a file of its own
        o Use more #defines for hard coded strings
        o Use a more neutral default hostname

signal.c:
        o New file, for setup and signal handlers
        o Add support for SIGSTOP/SIGSTP and SIGCONT.  This pauses finit
          respawning of xinit/shell.  Useful for, e.g., debugging
        o Document each ignored and handled signal better
        o Disable SIGUSR1 and SIGUSR2 for now, will be reenabled later

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-09-17 10:41:18 +02:00
Joachim Nilsson 4657d9713a Minor cleanup. Moved code around a bit, to functions, away from main().
This commit is in preparation for importing the Westermo code changes.
Slowly refactoring the finit core into a more modularized unit to be a
bit more maintainable.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-09-17 01:51:37 +02:00
Joachim Nilsson a654d99b92 Archive previous versions for reference.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-09-14 13:23:17 +02:00
Joachim Nilsson e2c4a6ceaf Remove optional --directisa call to hwclock, this is the default anyway.
This is a followup to Olivier Blin's patch from 88ffb93 in that it
applies the same patch to finit-mod.c that is already in finit.c, or
finit-alt.c as it was called then.

Also, the optional --directisa argument to hwclock is not necessary.
The hwclock utility has a built-in fallback to use excplicit I/O over
the /dev/rtc in case the latter does not exist.  See the hwclock(8) man
page for more information on this.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-09-14 13:11:31 +02:00
Joachim Nilsson 5816c9cab9 Embedded finit for small embedded Linux systems and servers.
o Make finit-alt.c the new finit.c, save old finit.c as finit-org.c
o Keep original finit-alt.c for reference.
o Update README and ChangeLog with direction of this fork
o Correct ChangeLog date for v0.1 and set release date for
  the 0.6-pre release to 20100614, which is the last commit
  by the original author.
o Add standard LICENSE file for MIT License
o Add standard AUTHORS file to document history of project
o Bump version to 1.0-pre to distance fork from original

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-09-14 13:10:39 +02:00
63 changed files with 7003 additions and 1649 deletions
+4
View File
@@ -1,2 +1,6 @@
*.o
.*.d
*.so
*.gz
*.map
finit
+6
View File
@@ -0,0 +1,6 @@
Current Maintainer(s):
* Joachim Nilsson <troglobit@gmail.com>
Original Author(s):
* Claudio Matsuoka <cmatsuoka@gmail.com>
-47
View File
@@ -1,47 +0,0 @@
0.6 ()
- 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 (20081214)
- initial release
+20
View File
@@ -0,0 +1,20 @@
Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
Copyright (c) 2008-2012 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.
+137 -66
View File
@@ -1,91 +1,162 @@
CC = gcc
CFLAGS = -Os -Wall -DVERSION=\"$(VERSION)\" -DWHOAMI=\"`whoami`@`hostname`\"
LD = gcc
LDFLAGS =
LIBS =
VERSION = 0.6-pre
PKG = finit-$(VERSION)
DFILES = Makefile README finit.c finit-mod.c finit-alt.c helpers.c helpers.h \
patches/*patch contrib/services.sh* contrib/Makefile.*
BINS = finit-mod finit-alt finit-mdv #finit-exb
# 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>
#
# 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.
.PHONY: all install clean distclean dist \
install-exec install-data install-dev \
uninstall-exec uninstall-data uninstall-dev
#VERSION ?= $(shell git tag -l | tail -1)
VERSION ?= 1.8
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 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))
#### Configurable parameters
# Installation paths, always prepended with DESTDIR if set
TOPDIR = $(shell pwd)
prefix ?= /usr
sysconfdir ?= /etc
sbindir ?= /sbin
libdir ?= /lib
plugindir ?= $(libdir)/finit/plugins
incdir = $(prefix)/include/finit
datadir = $(prefix)/share/doc/finit
mandir = $(prefix)/share/man/man8
# Default user for finit-alt if not "user"
#DEFUSER = fred
# The initctl FIFO, should probably be in /run, not /dev
FINIT_FIFO ?= /dev/initctl
FINIT_CONF ?= $(sysconfdir)/finit.conf
FINIT_RCSD ?= $(sysconfdir)/finit.d
# Disable annoying gcc warning
CFLAGS += -U_FORTIFY_SOURCE
CFLAGS += -W -Wall -Werror -Os
# Disable annoying gcc warning for "warn_unused_result", see GIT 37af997
CPPFLAGS += -U_FORTIFY_SOURCE
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$(TOPDIR)/libite
DEPLIBS = libite/libite.so
LDLIBS += -ldl -lite
# Use -march=pentium-m to build for Eeepc
#CFLAGS += -march=pentium-m
include common.mk
export libdir plugindir incdir ROOTDIR CPPFLAGS LDFLAGS LDLIBS
# Omit the first /sbin/hwclock if CONFIG_RTC_HCTOSYS is enabled in the kernel
#CFLAGS += -DNO_HCTOSYS
all: $(DEPLIBS) $(EXEC)
$(MAKE) -C plugins $@
# Append -directisa to /sbin/hwclock lines if the user has disabled
# CONFIG_GENRTC and enabled CONFIG_RTC but not enabled CONFIG_HPET_TIMER
# and CONFIG_HPET_RTC_IRQ.
#CFLAGS += -DDIRECTISA
$(DEPLIBS): Makefile
$(MAKE) -C libite all
# Use built-in run-parts instead of /bin/run-parts
CFLAGS += -DBUILTIN_RUNPARTS
$(OBJS): Makefile
#### End of configurable parameters
finit: $(OBJS) $(DEPLIBS)
reboot: reboot.o $(DEPLIBS)
install-exec: all
@$(INSTALL) -d $(DESTDIR)$(FINIT_RCSD)
@$(INSTALL) -d $(DESTDIR)$(sbindir)
@for file in $(EXEC); do \
printf " INSTALL $(DESTDIR)$(sbindir)/$$file\n"; \
$(STRIPINST) $$file $(DESTDIR)$(sbindir)/$$file; \
done
$(MAKE) -C libite install-exec
$(MAKE) -C plugins install
ifneq ($(DEFUSER),)
CFLAGS += -DDEFUSER=\"$(DEFUSER)\"
endif
install-data:
@$(INSTALL) -d $(DESTDIR)$(datadir)
@$(INSTALL) -d $(DESTDIR)$(mandir)
@for file in $(DISTFILES); do \
printf " INSTALL $(DESTDIR)$(datadir)/$$file\n"; \
$(INSTALL) -m 0644 $$file $(DESTDIR)$(datadir)/$$file; \
done
.c.o:
$(CC) -c $(CFLAGS) -o $*.o $<
install-dev:
@$(INSTALL) -d $(DESTDIR)$(incdir)
@for file in $(HEADERS); do \
printf " INSTALL $(DESTDIR)$(incdir)/$$file\n"; \
$(INSTALL) -m 0644 $$file $(DESTDIR)$(incdir)/$$file; \
done
$(MAKE) -C libite install-dev install-exec
all: $(BINS)
install: install-exec install-data install-dev
finit: finit.o
$(LD) $(LDFLAGS) -o $@ $+ $(LIBS)
strip $@
uninstall-exec:
-@for file in $(EXEC); do \
printf " REMOVE $(DESTDIR)$(sbindir)/$$file\n"; \
rm $(DESTDIR)$(sbindir)/$$file 2>/dev/null; \
done
-@rmdir $(DESTDIR)$(sbindir) 2>/dev/null
-@rmdir $(DESTDIR)$(FINIT_RCSD) 2>/dev/null
$(MAKE) -C libite uninstall
$(MAKE) -C plugins uninstall
finit-mod: finit-mod.o helpers.o
$(LD) $(LDFLAGS) -o $@ $+ $(LIBS)
strip $@
uninstall-data:
@for file in $(DISTFILES); do \
printf " REMOVE $(DESTDIR)$(datadir)/$$file\n"; \
rm $(DESTDIR)$(datadir)/$$file 2>/dev/null; \
done
-@rmdir $(DESTDIR)$(mandir)
-@rmdir $(DESTDIR)$(datadir)
finit-alt: finit-alt.o helpers.o
$(LD) $(LDFLAGS) -o $@ $+ $(LIBS)
strip $@
uninstall-dev:
-@$(RM) -rf $(DESTDIR)$(incdir)
finit-mdv: finit-mdv.o helpers.o
$(LD) $(LDFLAGS) -o $@ $+ $(LIBS)
strip $@
finit-mdv.o: finit-alt.c Makefile
$(CC) -c $(CFLAGS) -DDIST_MDV -o $@ finit-alt.c
finit-exb: finit-exb.o helpers.o
$(LD) $(LDFLAGS) -o $@ $+ $(LIBS)
strip $@
finit-exb.o: finit-alt.c Makefile
$(CC) -c $(CFLAGS) -DDIST_EEEXUBUNTU -o $@ finit-alt.c
uninstall: uninstall-exec uninstall-data uninstall-dev
clean:
rm -f *.o core *~ $(BINS)
-@$(RM) $(OBJS) $(DEPS) $(EXEC)
$(MAKE) -C libite $@
$(MAKE) -C plugins $@
finit.o: finit.c Makefile
finit-mod.o: finit-mod.c Makefile
helpers.o: helpers.c Makefile
distclean: clean
-@$(RM) $(JUNK) unittest *.o .*.d
$(MAKE) -C libite $@
$(MAKE) -C plugins $@
dist:
rm -Rf $(PKG)
mkdir -p $(PKG)/contrib $(PKG)/patches
for i in $(DFILES); do cp $$i $(PKG)/`dirname $$i`; done
tar cf - $(PKG) | gzip -c > $(PKG).tar.gz
rm -Rf $(PKG)
ls -l $(PKG).tar.gz
@echo "Building xz tarball of $(PKG) in parent dir..."
git archive --format=tar --prefix=$(PKG)/ $(VERSION) | xz >../$(ARCHIVE)
@(cd ..; md5sum $(ARCHIVE) | tee $(ARCHIVE).md5)
dev: distclean
@echo "Building unstable xz $(DEV) in parent dir..."
-@$(RM) -f ../$(DEV).tar.xz*
@(dir=`mktemp -d`; mkdir $$dir/$(DEV); cp -a . $$dir/$(DEV); \
cd $$dir; tar --exclude=.git --exclude=contrib \
-c -J -f $(DEV).tar.xz $(DEV); \
cd - >/dev/null; mv $$dir/$(DEV).tar.xz ../; cd ..; \
rm -rf $$dir; md5sum $(DEV).tar.xz | tee $(DEV).tar.xz.md5)
ifneq ($(MAKECMDGOALS),clean)
ifneq ($(MAKECMDGOALS),distclean)
-include $(DEPS)
endif
endif
Symlink
+1
View File
@@ -0,0 +1 @@
NEWS.rst
+159
View File
@@ -0,0 +1,159 @@
==============================================================================
NEWS
==============================================================================
1.8 (2013-06-07)
----------------
* Support for runlevels, with a bootstrap runlevel 'S'
* Support for saving previous and current runlevel to UTMP
* Support for new finit.conf commands: run, task, and runlevel
* Support for tty and console commands in finit.conf, like services but
for launching multiple getty logins
* New tty plugin to monitor TTYs coming and going, like USB TTYs
* Bugfixes to libite
1.7 (2012-10-08)
----------------
* Show __FILE__ in _d() debug messages, useful for plugins with
similarily named callbacks. Also, only in debug mode anyway
* Make sure to cleanup recorded PID when a service is lost. Required by
service plugins for their callbacks to work.
* Bugfix: Do not free() static string in finit.conf parser
* Only clear screen when in verbose mode. Maybe this should be removed
altogether?
1.6 (2012-10-06)
----------------
* Skip . and .. in plugin loader and display error on failed plugins
* Support for overriding /etc/finit.d with "runparts DIR" in finit.conf
* Revoke support for starting services not starting with a slash.
* Prevent endless restart of non-existing services in finit.conf
* Support for sysvinit style startstop scripts in /etc/finit.d
* Minor fix to alsa-utils plugin to silence on non-existing cards
1.5 (2012-10-03)
----------------
* Use bootmisc plugin to setup standard FHS 2.3 structure in /var
* Added FLOG_WARN() syslog macro, for plugins
* Add plugin dependency resolver. Checks plugin_t for .depends
1.4 (2012-10-02)
----------------
* Fix I/O plugin watcher and load plugins earlier for a new hook
* Start refactoring helpers.c into a libite.so (-lite). This means
other user space applications/daemons can make use of the neat toolbox
available in finit
* Use short-form -s/-w -u to work with BusyBox hwclock as well
* Use RTLD_GLOBAL flag to tell dynamic loader to load dependent .so
files as well. Lets other plugins use global symbols.
* Greatly simplify svc hook for external plugins and cleanup plugin API.
* And more... see the GIT log for more details.
1.3 (2012-09-28)
----------------
* Cleanup public plugin API a bit and add new pid/pidfile funcs
* Add plugin hook to end of service startup
* Remove finit.h from svc.h, plugins should not need this.
* Move utility macros etc. to helpers.h
* Make finit.h daemon internal, only
* Move defines of FIFO, conf and rcS.d to Makefile => correct paths
* Add support for installing required headers in system include dir
* Better support for distributions and packagers with install-exec,
install-data, and install-dev targets in Makefile. Useful if you want
to call targets with different $DESTDIR!
* Makefile fixes for installation, paths encoded wrong
* Strip binaries + .so files, support for $(CROSS) toolchain strip
* Default install is now to /sbin/finit and /usr/
* Note change in $PLUGIN_DIR environemnt variable to $plugindir
1.2 (2012-09-27)
----------------
* Fix installation paths encoded in finit binary
* Update README with section on building and enviroment variables
1.1 (2012-09-27)
----------------
* Build fixes for ARM eabi/uClibc
* Rename signal.[ch]-->sig.[ch] to avoid name clash w/ system headers
1.0 (2012-09-26)
----------------
* New plugin based system for all odd extensions
* New service monitor that restarts services if they die
* New maintainer at GitHub http://github.com/troglobit/finit
* Add standard LICENSE and AUTHORS files
* New focus: embedded systems and small headless servers
0.6 (2010-06-14)
----------------
* don't start consolekit manually, dbus starts it (rtp)
* unmount all filesystems before rebooting
* disable USE_VAR_RUN_RESOLVCONF for Mandriva
* unset terminal type in Mandriva before running X
* remove extra sleep in finit-alt before calling services.sh (caio)
0.5 (2008-08-21)
----------------
* add option to start dbus and consolekit before the X server
* finit-alt listens to /dev/initctl to work with reboot(8) (smurfy)
* write runlevel to utmp, needed by Printerdrake (Pascal Terjan)
* fix ownership of /var/run/utmp (reported by Pascal Terjan)
* remove obsolete code to load AGP drivers
* conditional build of /etc/resolveconf/run support
* add support to /var/run/resolvconf in Mandriva (blino)
O.4 (2008-05-16)
----------------
* default username for finit-alt configurable in Makefile
* create loopback device node in finit-alt (for squashfs)
* add option to use built-in run-parts instead of /bin/run-parts
* ignore signal instead of setting to an empty handler (Metalshark)
* handle pam_console permissions in finit-alt for Mandriva
* add services.sh example and nash-hotplug patch for Mandriva
* mount /proc/bus/usb in Mandriva
* add runtime debug to finit-alt if finit_debug parameter is specified
* read configuration from /etc/finit.conf
* run getty with openvt on the virtual terminal
0.3 (2008-02-23)
----------------
* Change poweroff method to reboot(RB_POWER_OFF) (Metalshark)
* Remove duplicate unionctl() reimplementation error
* Fix string termination in path creation
* Mount /var/lock and /var/run as tmpfs
0.2 (2008-02-19)
----------------
* replace system("touch") with touch() in finit-mod (Metalshark)
* disable NO_HCTOSYS by default to match stock Eeepc kernel
* drop system("rm -f") to clean /tmp, its a fresh mounted tmpfs
* write ACPI sleep state to /sys/power/state instead of /proc/acpi/sleep
(Metalshark)
* use direct calls to set loopback instead of system("ifconfig")
* replace system("cat") and system("dd") with C implementation
* moved finit-mod and finit-alt helpers to helpers.c
* replace system("echo;cat") to draw shutdown splash with C calls
0.1 (2008-02-14)
----------------
* initial release
.. Local Variables:
.. mode: rst
.. version-control: t
.. End:
-48
View File
@@ -1,48 +0,0 @@
Finit is a reimplementation of the Eeepc "fastinit" program based on its
system calls with gaps filled with frog DNA.
Finit's purpose is to build upon the general workings of fastinit and
improve/optimize it for Xandros or alternative distributions running on
the Eeepc. Finit comes in three flavors: finit is a replica of the Asus
fastinit, finit-mod is an improved drop-in replacement for fastinit,
and finit-alt is a generic replacement for other systems. Finit-mod
and finit-alt were much improved with patches from Metalshark.
See more information at http://helllabs.org/finit/
Usage scenarios
---------------
1. Replace the original Eeepc 702 fastinit (finit-mod)
2. Allow fast booting in alternative Linux distributions running on the
Eeepc and other netbooks (finit-alt)
Finit-alt is distribution-specific. Currently it generates a finit-mdv
executable for Mandriva 2008/2008.1 systems. Smurfy ported it to
eeeXubuntu, and parts of his port have been merged to finit-alt.
Finit-alt features
------------------
Finit-alt reads configuration information from /etc/finit.conf. See
the source code for available options.
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.
Debugging
---------
Add finit_debug to the kernel parameter line to enable trace messages
and to run a shell after the X server.
Symlink
+1
View File
@@ -0,0 +1 @@
README.rst
-4
View File
@@ -1,4 +0,0 @@
Experimental eeeXubuntu support merged from smurfy's port, see
http://forum.eeeuser.com/viewtopic.php?id=15685
-33
View File
@@ -1,33 +0,0 @@
Mandriva 2008
-------------
1 - Add init=/sbin/finit-mdv to the kernel boot line
2 - Provide a suitable /usr/sbin/services.sh, this is the one I use in my
test system running e17:
mkdir /var/lock/subsys
chmod 1777 /var/lock/subsys
/etc/init.d/network start
dhclient eth0
/sbin/start_udev&
/etc/init.d/portmap start
/etc/init.d/nfs-common start
If you use KDE or need more services, see examples in contrib/
3 - Create /etc/finit.conf with user, module, filesystems to check and
hostname parameters. See the included finit.conf for more information.
If no user is specified, user "user" will be used as default.
4 - Set the pointer device in the X server configuration to /dev/input/mice
Mandriva 2008.1
---------------
If you have a stuck nash-hotplug consuming 100% of CPU after the boot, you
may want to patch mkinitrd using patches/mkinitrd-6.0.34-nash-hotplug.patch
+272
View File
@@ -0,0 +1,272 @@
==============================================================================
Finit — A fast plugin-based /sbin/init with service monitoring
==============================================================================
Welcome to finit!
This is an extremely fast /sbin/init replacement with focus on small
embedded GNU/Linux systems. Based on Claudio Matsuoka's original finit_
with I/O, service and hook plugin extensions. The original was a
reimplementation of the EeePC fastinit_ daemon based on its system calls
with gaps filled with frog DNA.
In the world of finit we write C plugins that hook into and extend the
``main()`` loop of ``/sbin/init``, this is what gives the system its raw
performance and the user full control.
If you chose finit you know what you want, a fast no hassles boot!
Features
--------
**Service monitoring**
Restarting a service when it exits
**Plugins**
Extend and modify finit behavior. See examples in plugins/ directory.
Plugin capabilities:
* Service callbacks — should the service run/restart/stop?
* Task/Run callbacks — a one-shot command, should it run in sequence?
* Hooks — hook into the boot at predefined points to extend finit
* I/O — listen to external events and control finit behaviour/services
Most extensions and functionality not purely related to what an /sbin/init
needs to start a system from the original finit_ has been reactored into
plugins with either hooks or I/O demands.
/etc/finit.conf
---------------
Contrary to most script based init alternatives (`SysV init`_, upstart_,
OpenRC_ and the likes) finit instead reads its configuration from
``/etc/finit.conf``. Below is a brief list, see the source code for the
full list:
check
Run fsck on a file system before mounting it
module
Load a kernel module, with optional arguments
network
Script or program to bringup networking, with optional arguments
runlevel N
N is the runlevel number 1-9, where 6 is reserved for reboot
run [RUN_LVLS] /path/to/cmd ARGS -- Optional description
One-shot command to run in sequence when entering a runlevel, with
optional arguments and description. This command is guaranteed to
be completed before running the next command.
task [RUN_LVLS] /path/to/cmd ARGS -- Optional description
One-shot like 'run', but starts in parallel with the next command
service [RUN_LVLS] /path/to/daemon ARGS -- Optional description
Service, or daemon, to be monitored and automatically restarted if
it exits prematurely. Please note that you often need to provide
a --foreground or --no-background argument to most daemons to
prevent them from forking off to the background.
runparts
Call run-parts(8) on a directory other than the default /etc/finit.d
tty [RUN_LVLS] DEV
Run getty on the listed TTY device, in the given runlevels
console DEV
Some embedded systems have a dedicated console port. This command
tells finit to not start getty, but instead print a friendly message
and wait for the user to activate the console with a keypress before
starting getty.
When running ``make install`` no default ``/etc/finit.conf`` will be
provided since the system requirements differ too much. Try out the
Debian 6.0 example ``/usr/share/doc/finit/finit.conf`` configuration
that is capable of service monitoring SSH, sysklogd, gdm and a console
getty!
/etc/finit.d
------------
At the end of the boot, when networking and all services are up, finit
calls its built-in run-parts(8) on the ``/etc/finit.d/`` directory, if
it exists. Similar to how the ``/ec/rc.local`` file works in most other
inits, only finit runs a directory of scripts. This replaces the
earlier support for a ``/usr/sbin/services.sh`` script in the original
finit_.
Runlevels
---------
Support for runlevels_ is included in Finit from v1.8. By default all
services, tasks, run commands and TTYs listed without a set of runlevels
get a default set [234] assigned. The default runlevel after boot is 2.
To specify an allowed set of runlevels for a service, run command, task,
or tty, add [NNN] to it in finit.conf, like this:
run [S] /etc/init.d/acpid start -- Starting ACPI Daemon
task [S] /etc/init.d/kbd start -- Preparing console
service [S12345] /sbin/klogd -n -x -- Kernel log daemon
tty [12345] /dev/tty1
tty [2] /dev/tty2
tty [2] /dev/tty3
tty [2] /dev/tty4
tty [2] /dev/tty5
tty [2] /dev/tty6
In this example acpid is started once at bootstrap using a conventional
SysV init script. Here the run command was used, meaning the following
task command is not run until the init script has fully completed.
Tasks and services are started in parallell, while run commands are run
in the order listed and subsequent commands are not started until a run
command has completed.
Existing finit.conf files that lack runlevel setting will get a default
runlevel assigned, [234].
Switching between runlevels can be done by calling init with a single
argument, e.g., 'init 5' switches to runlevel 5.
Rebooting and Halting
---------------------
Finit handles SIGUSR1 and SIGUSR2 for reboot and halt, and listens to
``/dev/initctl`` so standard Linux reboot and halt commands should also
work.
Building
--------
The finit build system does not employ the GNU Configure and Build System,
instead standard makefiles are used. The user is encouraged to make source
code changes, using defines and conditionally building plugins instead to
alter the behavior of finit.
The following environment variables are checked by the makefiles and control
what is built and where resulting binaries are installed.
**ROOTDIR=**
Top directory for building complete system, used in pretty printing
**VERSION=**
Defaults to the currently released version of finit, e.g., 1.3 but can
be overridden by packages to add a suffix or completely alter the version.
**CFLAGS=**
Standard CFLAGS are inherited from the build enviornmant.
**CPPFLAGS=**
Standard CPPFLAGS are inherited from the build enviornmant.
**LDFLAGS=**
Standard LDFLAGS are inherited from the build enviornmant.
**LDLIBS=**
Standard LIBLIBS are inherited from the build enviornmant.
**prefix=**
Base prefix path for all files, except ``sbinbdir`` and ``sysconfdir``.
Used in concert with the ``DESTDIR`` variable. Defaults to ``/usr``
**sbindir=**
Path to where resulting binaries should install to. Used in concert
with the ``DESTDIR`` variable. Defaults to ``/sbin``
**sysconfdir=**
Path to where finit configuration files should install to. Used in
concert with the ``DESTDIR`` variable. Defaults to ``/etc``, but is
currently unused.
**PLUGINS=**
List of stock finit plugins to build and install.
**plugindir=**
Absolute path to where finit should look for dynamically loadable plugins
at runtime. At installation prepended by ``DESTDIR`` and ``prefix``.
Defaults to ``/lib/finit/plugins``
**DESTDIR=**
Used by packagers and distributions when building a relocatable
bundle of files. Alwawys prepended to the ``prefix`` destination
directory.
**Example**::
$ tar xfJ finit-1.3.tar.xz
$ PLUGINS="initctl.so hwclock.so" DESTDIR=/tmp/finit/dst \
make -C finit-1.3/ clean install
make: Entering directory `/home/troglobit/finit-1.3'
CC finit.o
CC conf.o
CC helpers.o
CC sig.o
CC svc.o
CC plugin.o
CC strlcpy.o
LINK finit
CC plugins/initctl.o
PLUGIN plugins/initctl.so
CC plugins/hwclock.o
PLUGIN plugins/hwclock.so
INSTALL /tmp/finit/dst/sbin/finit
INSTALL /tmp/finit/dst/lib/finit/plugins/initctl.so
INSTALL /tmp/finit/dst/lib/finit/plugins/hwclock.so
make: Leaving directory `/home/troglobit/finit-1.3'
In this example the `finit-1.3.tar.xz`_ archive is unpacked to the
user's home directory, built and installed to a temporary staging
directory. The enviroment variables ``DESTDIR`` and ``PLUGINS`` are
changed to suit this particular build.
Running
-------
The default install does not setup finit as the system default
``/sbin/init``, neither does it setup an initial ``/etc/finit.conf``.
It is assumed that users of finit are competent enough to either setup
finit as their default ``/sbin/init`` or alter their respective Grub,
LOADLIN, LILO, U-Boot/Barebox or RedBoot boot loader configuration to
give the kernel the following extra command line::
init=/sbin/finit
Debugging
---------
Add ``finit_debug``, or ``--debug``, to the kernel command line to
enable trace messages. A console getty is always started, see the file
``finit.h`` for more useful comile-time tweaks::
init=/sbin/finit --debug
Contact
-------
Finit is maintained collaborativly at http://github.com/troglobit/finit —
please file a bug report, clone it, or send pull requests for bug fixes and
proposed extensions, or become a co-maintainer by contacting the main author.
Regards
/Joachim Nilsson <troglobit@gmail.com>
.. _finit: http://helllabs.org/finit/
.. _fastinit: http://wiki.eeeuser.com/boot_process:the_boot_process
.. _`SysV init`: http://savannah.nongnu.org/projects/sysvinit
.. _upstart: http://upstart.ubuntu.com/
.. _runlevels: http://en.wikipedia.org/wiki/Runlevel
.. _openrc: http://www.gentoo.org/proj/en/base/openrc/
.. _`finit-1.3.tar.xz`: http://github.com/downloads/troglobit/finit/finit-1.3.tar.xz
Symlink
+1
View File
@@ -0,0 +1 @@
TODO.rst
+105
View File
@@ -0,0 +1,105 @@
==============================================================================
TODO
==============================================================================
Unsorted TODO list of features and points of investigation that could be
useful for improving finit. But what is an improvement to finit? Well,
similiar to launchd, the goal of finit is to be a FAST replacement for:
* init
* inetd
* crond
* watchdogd
The main goal is to be FAST. Secondary goals are to be: small, simple
and with a very low dependency on external packages.
Priority
--------
The intent of finit is to monitor not just processes, but also to
be able to supervise the entire system and the behavior of certain
processes that declare themselves to be finit compliant.
* Integrate the ingenious libev to handle all events: signals, polling
fd's, etc. Because "Event driven software improves concurrency" --
Dave Zarzycki, Apple. See the `launchd video`_ for more info!
* Add support for process and system supervision. Which could
be an API wrapping, e.g., TIPC and loadavg.
* Add support for a /dev/watchdog plugin to replace watchdogd
* Integrate watchdog plugin with process/system supervisor to
reboot the system when a process stops responding, or when
restarting it is imposible, as well as when system load gets
too high.
Configuration
-------------
* Add support for "init <q | reload-configuration>" and SIGHUP to
reload finit.conf, but also
* Add support for inotify to automatically reload finit.conf
Runlevels
---------
* Add support for "runlevel N" to finit.conf
* Improve support for runlevels: startup, running (services from
finit.conf), and shutdown as well as hooks when switching RL, startup
at RL 1 and a default run level.
* Implement initctl stop|start|restart|reload|status <SVC> and service
<SVC> stop|start|restart|reload|status on top
* Add PRE and POST hooks for when changing runlevels
* SysV init in Debian uses an rcS.d/ for scripts that should run once at
boot. These scripts are run before the actual runlevel, which is set
in inittab. We could use "task [S]" and "run [S]" (below) for this.
* Add support for a new runlevel 'S' that is started before all other
services in the selected runlevel.
Services and Tasks
------------------
Both the "task" and "boot" stanzas below are like "service", share the
same mechanism for registering callbacks. These callbacks can be used
to check a configuration db and return 1 (RUN), 2 (STOP), or 3 (RELOAD).
* Add support for "task [RUNLVL] ..." similar to services, but one-shot.
* Add support for "run [RUNLVL] ..." similar to task, but waits for
completion before continuing with the next task/service
* Add support for service/task/run dependencies
* Add support for "init list" to show running services
It is tempting to say that a task called at runlevel S would be a
blocking call, like run, but there are likely use-cases when you want to
call on-shot tasks in parallell with something else, even at boot. Hence
the differentiation between "task" and "run", which are essentially the
same, except for the "pause and wait for completion" that "run" has.
Miscellaneous
-------------
* Add support for "init -v,--version | version"
* Cleanup move sources from top-level directory to src/ and include/
* Make sure to install queue.h to $(PREFIX)/include/finit/queue.h
* Move finit.conf "check" command to plugin which checks /etc/fstab
instead. This is the de-facto practise. But keep the check command
for really low-end systems w/o /etc/fstab.
Documentation
-------------
* Write man pages for finit and finit.conf, steal from pimd man pages...
* Update Debian finit.conf example with runlevels, tty/console and
dependency handling
Investigation
-------------
* `FHS changes`_ affecting runtime status, plugins, etc.
.. _`launchd video`: http://www.youtube.com/watch?v=cD_s6Fjdri8
.. _`FHS changes`: http://askubuntu.com/questions/57297/why-has-var-run-been-migrated-to-run
..
.. Local Variables:
.. mode: rst
.. version-control: t
.. End:
+28
View File
@@ -0,0 +1,28 @@
# 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
# Smart autodependecy generation via GCC -M.
.%.d: %.c
@$(SHELL) -ec "$(CC) -MM $(CFLAGS) $(CPPFLAGS) $< \
| sed 's,.*: ,$*.o $@ : ,g' > $@; \
[ -s $@ ] || rm -f $@"
# Override default implicit rules
%.o: %.c
@printf " CC $(subst $(ROOTDIR)/,,$(shell pwd)/$@)\n"
@$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
%: %.o
@printf " LINK $(subst $(ROOTDIR)/,,$(shell pwd)/$@)\n"
@$(CC) $(CFLAGS) $(LDFLAGS) -Wl,-Map,$@.map -o $@ $^ $(LDLIBS$(LDLIBS-$(@)))
%.so: %.o
@printf " PLUGIN $(subst $(ROOTDIR)/,,$(shell pwd)/$@)\n"
@$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS)
+233
View File
@@ -0,0 +1,233 @@
/* Parser for finit.conf
*
* Copyright (c) 2012 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 <ctype.h>
#include <string.h>
#include "finit.h"
#include "svc.h"
#include "tty.h"
#include "lite.h"
#include "helpers.h"
#define MATCH_CMD(l, c, x) \
(!strncmp(l, c, strlen(c)) && (x = (l) + strlen(c)))
static char *strip_line(char *line)
{
char *ptr;
/* Trim leading whitespace */
while (*line && isblank(*line))
line++;
/* Strip any comment at end of line */
ptr = line;
while (*ptr && *ptr != '#')
ptr++;
*ptr = 0;
return line;
}
/* 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;
}
void parse_finit_conf(char *file)
{
FILE *fp;
char line[LINE_SIZE];
char cmd[CMD_SIZE];
username = strdup(DEFUSER);
hostname = strdup(DEFHOST);
rcsd = strdup(FINIT_RCSD);
if ((fp = fopen(file, "r")) != NULL) {
char *x;
const char *err = NULL;
_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
* XXX: Move to plugin which checks /etc/fstab instead */
if (MATCH_CMD(line, "check ", x)) {
char *dev = strip_line(x);
strcpy(cmd, "/sbin/fsck -C -a ");
strlcat(cmd, dev, sizeof(cmd));
run_interactive(cmd, "Checking file system %s", dev);
continue;
}
if (MATCH_CMD(line, "user ", x)) {
if (username) free(username);
username = strdup(strip_line(x));
continue;
}
if (MATCH_CMD(line, "host ", x)) {
if (hostname) free(hostname);
hostname = strdup(strip_line(x));
continue;
}
if (MATCH_CMD(line, "module ", x)) {
char *mod = strip_line(x);
strcpy(cmd, "/sbin/modprobe ");
strlcat(cmd, mod, sizeof(cmd));
run_interactive(cmd, "Loading kernel module %s", mod);
continue;
}
if (MATCH_CMD(line, "mknod ", x)) {
char *dev = strip_line(x);
strcpy(cmd, "/bin/mknod ");
strlcat(cmd, dev, sizeof(cmd));
run_interactive(cmd, "Creating device node %s", dev);
continue;
}
if (MATCH_CMD(line, "network ", x)) {
if (network) free(network);
network = strdup(strip_line(x));
continue;
}
if (MATCH_CMD(line, "runparts ", x)) {
if (rcsd) free(rcsd);
rcsd = strdup(strip_line(x));
continue;
}
if (MATCH_CMD(line, "startx ", x)) {
svc_register(SVC_CMD_SERVICE, strip_line(x), username);
continue;
}
if (MATCH_CMD(line, "shutdown ", x)) {
if (sdown) free(sdown);
sdown = strdup(strip_line(x));
continue;
}
/* The desired runlevel to start when leaving
* bootstrap (S). Finit supports 1-9, but most
* systems only use 1-6, where 6 is reserved for
* reboot */
if (MATCH_CMD(line, "runlevel ", x)) {
char *token = strip_line(x);
cfglevel = strtonum(token, 1, 9, &err);
if (err)
cfglevel = RUNLEVEL;
if (cfglevel < 1 || cfglevel > 9 || cfglevel == 6)
cfglevel = 2; /* Fallback */
continue;
}
/* Monitored daemon, will be respawned on exit, as
* long as the (optional) service callback returns
* non-zero */
if (MATCH_CMD(line, "service ", x)) {
svc_register(SVC_CMD_SERVICE, x, NULL);
continue;
}
/* One-shot task, will not be respawned. Only runs if
* the (optional) service callback returns true */
if (MATCH_CMD(line, "task ", x)) {
svc_register(SVC_CMD_TASK, x, NULL);
continue;
}
/* Like task but waits for completion, useful w/ [S] */
if (MATCH_CMD(line, "run ", x)) {
svc_register(SVC_CMD_RUN, x, NULL);
continue;
}
if (MATCH_CMD(line, "console ", x)) {
if (console) free(console);
console = strdup(strip_line(x));
continue;
}
if (MATCH_CMD(line, "tty ", x)) {
tty_register(strip_line(x));
continue;
}
}
fclose(fp);
}
}
/**
* Local Variables:
* version-control: t
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
-88
View File
@@ -1,88 +0,0 @@
CC = gcc
CFLAGS = -Os -Wall -DVERSION=\"$(VERSION)\" -DWHOAMI=\"`whoami`@`hostname`\"
LD = gcc
LDFLAGS =
LIBS =
VERSION = 0.6-pre
PKG = finit-$(VERSION)
DFILES = Makefile README finit.c finit-mod.c finit-alt.c helpers.c helpers.h \
patches/*patch contrib/services.sh*
BINS = finit-mod finit-alt finit-mdv #finit-exb
#### Configurable parameters
# Default user for finit-alt if not "user"
#DEFUSER = fred
# Use -march=pentium-m to build for Eeepc
#CFLAGS += -march=pentium-m
# Omit the first /sbin/hwclock if CONFIG_RTC_HCTOSYS is enabled in the kernel
CFLAGS += -DNO_HCTOSYS
# Append -directisa to /sbin/hwclock lines if the user has disabled
# CONFIG_GENRTC and enabled CONFIG_RTC but not enabled CONFIG_HPET_TIMER
# and CONFIG_HPET_RTC_IRQ.
#CFLAGS += -DDIRECTISA
# Use built-in run-parts instead of /bin/run-parts
CFLAGS += -DBUILTIN_RUNPARTS
#### End of configurable parameters
ifneq ($(DEFUSER),)
CFLAGS += -DDEFUSER=\"$(DEFUSER)\"
endif
.c.o:
$(CC) -c $(CFLAGS) -o $*.o $<
all: $(BINS)
finit: finit.o
$(LD) $(LDFLAGS) -o $@ $+ $(LIBS)
strip $@
finit-mod: finit-mod.o helpers.o
$(LD) $(LDFLAGS) -o $@ $+ $(LIBS)
strip $@
finit-alt: finit-alt.o helpers.o
$(LD) $(LDFLAGS) -o $@ $+ $(LIBS)
strip $@
finit-mdv: finit-mdv.o helpers.o
$(LD) $(LDFLAGS) -o $@ $+ $(LIBS)
strip $@
finit-mdv.o: finit-alt.c Makefile
$(CC) -c $(CFLAGS) -DDIST_MDV -o $@ finit-alt.c
finit-exb: finit-exb.o helpers.o
$(LD) $(LDFLAGS) -o $@ $+ $(LIBS)
strip $@
finit-exb.o: finit-alt.c Makefile
$(CC) -c $(CFLAGS) -DDIST_EEEXUBUNTU -o $@ finit-alt.c
clean:
rm -f *.o core *~ $(BINS)
finit.o: finit.c Makefile
finit-mod.o: finit-mod.c Makefile
helpers.o: helpers.c Makefile
dist:
rm -Rf $(PKG)
mkdir -p $(PKG)/contrib $(PKG)/patches
for i in $(DFILES); do cp $$i $(PKG)/`dirname $$i`; done
tar cf - $(PKG) | gzip -c > $(PKG).tar.gz
rm -Rf $(PKG)
ls -l $(PKG).tar.gz
+65
View File
@@ -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
+81
View File
@@ -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
+259
View File
@@ -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
:
-20
View File
@@ -1,20 +0,0 @@
#!/bin/sh
#
# Example /usr/sbin/services.sh that can be used in a Mandriva 2008 system
# running KDE
mkdir /var/lock/subsys
chmod 1777 /var/lock/subsys
/sbin/start_udev
mkdir /var/run/dbus
/etc/init.d/messagebus start
/etc/init.d/haldaemon start
/etc/init.d/alsa start
/etc/init.d/sound start
/etc/init.d/crond start
/etc/init.d/network-up start
/etc/init.d/network start
#/etc/init.d/sshd start
/etc/init.d/syslog start
/sbin/pam_console_apply
#kbuildsycoca --noincremental
-28
View File
@@ -1,28 +0,0 @@
#!/bin/sh
# Else oocalc will crash
mknod /dev/random c 1 8
mkdir /var/lock/subsys
chmod 1777 /var/lock/subsys
mkdir /var/run/dbus
mkdir /var/run/netreport
/etc/init.d/messagebus start
/sbin/start_udev.simple
for module in `/bin/grep -hv '#' /etc/modprobe.preload /etc/modprobe.preload.d/*`; do
/sbin/modprobe $module
done
# Need to find a way to apply udev config
chmod 0666 /dev/ptmx
/etc/init.d/network-up start
/etc/init.d/network start
/etc/init.d/acpid start
/etc/init.d/haldaemon start
sleep 10
for i in /etc/rc5.d/S*; do
$i status > /dev/null 2>&1 || $i start
done
-44
View File
@@ -1,44 +0,0 @@
#!/bin/sh
# precaution, if the hotplug tag exists in mkinitrd
killall nash-hotplug &
#give some priority to the user processes
renice -5 -u gdium
# Else oocalc will crash
mknod /dev/random c 1 8 &
mkdir /var/lock/subsys &
chmod 1777 /var/lock/subsys
mkdir /var/run/dbus &
mkdir /var/run/netreport &
mkdir /var/run/ConsoleKit &
mkdir /var/log &
/etc/init.d/haldaemon start &
sleep 25
# postpone udev and others startup, they are too slow
# limit the amount of udev childs, should speed up a little
export UDEV_MAX_CHILDS=2
export UDEV_MAX_CHILDS_RUNNING=2
/sbin/start_udev
/sbin/swapon -a &
chmod 0666 /dev/null
chmod 0666 /dev/ptmx
/etc/init.d/alsa start
/etc/init.d/network start
for module in `/bin/grep -hv '#' /etc/modprobe.preload /etc/modprobe.preload.d/*`; do
/sbin/modprobe $module
done
# restore (hopefully) the priority to the user processes
renice 0 -u gdium
# fuse status always say 0
/sbin/service fuse start
for i in /etc/rc5.d/S*; do
$i status > /dev/null 2>&1 || $i start
done
# enable this to stop bootchart when testing
(sleep 30; /sbin/bootchartd stop)&
-621
View File
@@ -1,621 +0,0 @@
/*
Improved fast init
Copyright (c) 2008 Claudio Matsuoka
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <sys/mount.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#include <sys/reboot.h>
#include <sys/wait.h>
#include <linux/fs.h>
#include <utmp.h>
#include "helpers.h"
#ifndef DEFUSER
#define DEFUSER "user"
#endif
/* Distribution configuration */
#if defined DIST_MDV /* Mandriva */
#define RANDOMSEED "/var/lib/random-seed"
#define SYSROOT "/sysroot"
#define GETTY "/usr/bin/openvt /sbin/mingetty tty2"
#define RUNPARTS "/usr/bin/run-parts"
#define REMOUNT_ROOTFS_RW
#define MAKE_DEVICES
#define MAKE_DEV_VCS
#define PAM_CONSOLE
#define LISTEN_INITCTL
#define RUNLEVEL 5
#define USE_MESSAGE_BUS
#elif defined DIST_EEEXUBUNTU /* eeeXubuntu */
#define RANDOMSEED "/var/lib/urandom/random-seed"
#define SYSROOT "/sysroot"
#define GETTY "/usr/bin/openvt /sbin/getty 38400 tty2"
#define RUNPARTS "/bin/run-parts"
#define REMOUNT_ROOTFS_RW
#define MAKE_DEVICES
#define TOUCH_ETC_NETWORK_RUN_IFSTATE
#define LISTEN_INITCTL
#else /* original Eeepc distribution */
#define RANDOMSEED "/var/lib/urandom/random-seed"
#define SYSROOT "/mnt"
#define GETTY "/usr/bin/openvt /sbin/getty 38400 tty2"
#define RUNPARTS "/bin/run-parts"
#define TOUCH_ETC_NETWORK_RUN_IFSTATE
#define USE_ETC_RESOLVCONF_RUN
#endif
#ifdef DIRECTISA
#define HWCLOCK_DIRECTISA " --directisa"
#else
#define HWCLOCK_DIRECTISA
#endif
/* From sysvinit */
/* Set a signal handler. */
#define SETSIG(sa, sig, fun, flags) \
do { \
sa.sa_handler = fun; \
sa.sa_flags = flags; \
sigemptyset(&sa.sa_mask); \
sigaction(sig, &sa, NULL); \
} while (0)
#ifdef LISTEN_INITCTL
#define INIT_MAGIC 0x03091969
#define INIT_CMD_RUNLVL 1
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];
};
#endif
#define touch(x) mknod((x), S_IFREG|0644, 0)
#define chardev(x,m,maj,min) mknod((x), S_IFCHR|(m), makedev((maj),(min)))
#define blkdev(x,m,maj,min) mknod((x), S_IFBLK|(m), makedev((maj),(min)))
#define MATCH_CMD(l,c,x) \
((!strncmp((l), (c), strlen((c)))) && ((x) = (l) + strlen((c))))
#define _d(x...) do { if (debug) { printf(x); printf("\n"); } } while (0)
#define LINE_SIZE 1024
#define CMD_SIZE 256
#define USERNAME_SIZE 16
#define HOSTNAME_SIZE 32
void shutdown(int);
void signal_handler(int);
void chld_handler(int);
static int debug = 0;
static char sdown[CMD_SIZE];
static void build_cmd(char *cmd, char *x, int len)
{
int l;
char *c;
c = cmd + strlen(cmd);
/* skip spaces */
for (; *x && (*x == ' ' || *x == '\t'); x++);
/* copy next arg */
for (l = 0; *x && *x != '#' && *x != '\t' && l < len; l++)
*c++ = *x++;
*c = 0;
_d("cmd = %s", cmd);
}
#ifdef LISTEN_INITCTL
/* Standard reboot/shutdown utilities talk to init using /dev/initctl.
* We should check if the fifo was recreated and reopen it.
*/
static void listen_initctl()
{
if (!fork()) {
int ctl;
fd_set fds;
struct init_request request;
mkfifo("/dev/initctl", 0600);
ctl = open("/dev/initctl", O_RDONLY);
while (1) {
FD_ZERO(&fds);
FD_SET(ctl, &fds);
if (select(ctl + 1, &fds, NULL, NULL, NULL) <= 0)
continue;
read(ctl, &request, sizeof(request));
if (request.magic != INIT_MAGIC)
continue;
if (request.cmd == INIT_CMD_RUNLVL) {
switch (request.runlevel) {
case '0':
shutdown(SIGUSR2);
break;
case '6':
shutdown(SIGUSR1);
}
}
}
}
}
#endif
int main()
{
int i;
FILE *f;
char line[LINE_SIZE];
struct sigaction sa, act;
sigset_t nmask, nmask2;
char username[USERNAME_SIZE] = DEFUSER;
char hostname[HOSTNAME_SIZE] = "eviltwin";
char cmd[CMD_SIZE];
char startx[CMD_SIZE] = "xinit";
#ifdef USE_ETC_RESOLVCONF_RUN
DIR *dir;
struct dirent *d;
#endif
#ifdef RUNLEVEL
struct utmp entry;
#endif
#ifdef PAM_CONSOLE
int fd;
#endif
chdir("/");
umask(022);
/*
* Signal management
*/
for (i = 1; i < NSIG; i++)
SETSIG(sa, i, SIG_IGN, SA_RESTART);
SETSIG(sa, SIGINT, shutdown, 0);
SETSIG(sa, SIGPWR, SIG_IGN, 0);
SETSIG(sa, SIGUSR1, shutdown, 0);
SETSIG(sa, SIGUSR2, shutdown, 0);
SETSIG(sa, SIGTERM, SIG_IGN, 0);
SETSIG(sa, SIGALRM, SIG_IGN, 0);
SETSIG(sa, SIGHUP, SIG_IGN, 0);
SETSIG(sa, SIGCONT, SIG_IGN, SA_RESTART);
SETSIG(sa, SIGCHLD, chld_handler, SA_RESTART);
/* Block sigchild while forking */
sigemptyset(&nmask);
sigaddset(&nmask, SIGCHLD);
sigprocmask(SIG_BLOCK, &nmask, NULL);
reboot(RB_DISABLE_CAD);
mount("none", "/proc", "proc", 0, NULL);
mount("none", "/sys", "sysfs", 0, NULL);
/*
* Parse kernel parameters
*/
if ((f = fopen("/proc/cmdline", "r")) != NULL) {
fgets(line, LINE_SIZE, f);
if ((strstr(line, "finit_debug"))) {
debug = 1;
}
if (strstr(line, "quiet")) {
close(0);
close(1);
close(2);
}
fclose(f);
}
_d("finit-alt " VERSION " (built " __DATE__ " " __TIME__ " by " WHOAMI ")");
setsid();
/*
* Parse configuration file
*/
if ((f = fopen("/etc/finit.conf", "r")) != NULL) {
char *x;
while (!feof(f)) {
fgets(line, LINE_SIZE, f);
chomp(line);
_d("conf: %s", line);
/* Do this before mounting / read-write */
if (MATCH_CMD(line, "check ", x)) {
strcpy(cmd, "/sbin/fsck -C -a ");
build_cmd(cmd, x, CMD_SIZE);
system(cmd);
continue;
}
if (MATCH_CMD(line, "user ", x)) {
*username = 0;
build_cmd(username, x, USERNAME_SIZE);
continue;
}
if (MATCH_CMD(line, "startx ", x)) {
*startx = 0;
build_cmd(startx, x, CMD_SIZE);
continue;
}
if (MATCH_CMD(line, "host ", x)) {
*hostname = 0;
build_cmd(hostname, x, HOSTNAME_SIZE);
continue;
}
if (MATCH_CMD(line, "shutdown ", x)) {
*sdown = 0;
build_cmd(sdown, x, CMD_SIZE);
continue;
}
if (MATCH_CMD(line, "module ", x)) {
strcpy(cmd, "/sbin/modprobe ");
build_cmd(cmd, x, CMD_SIZE);
system(cmd);
continue;
}
#ifdef MAKE_DEVICES
/* This is used if the system uses udev and doesn't
* mount /dev as tmpfs in the initrd, or if it doesn't
* use an initrd. Mount /dev as tmpfs and create basic
* device nodes.
*/
if (MATCH_CMD(line, "mountdev", x)) {
mount("none", "/dev", "tmpfs", 0, "mode=0755");
chardev("/dev/null", 0666, 1, 3);
blkdev("/dev/sda1", 0660, 8, 1);
blkdev("/dev/sda2", 0660, 8, 2);
blkdev("/dev/sda3", 0660, 8, 3);
blkdev("/dev/sda4", 0660, 8, 4);
blkdev("/dev/sda5", 0660, 8, 5);
blkdev("/dev/sda6", 0660, 8, 6);
#ifdef MAKE_DEV_VCS
/* Caio reports that newer X.org needs these */
blkdev("/dev/vcs1", 0660, 7, 1);
blkdev("/dev/vcs2", 0660, 7, 2);
blkdev("/dev/vcs3", 0660, 7, 3);
blkdev("/dev/vcs4", 0660, 7, 4);
blkdev("/dev/vcsa1", 0660, 7, 129);
blkdev("/dev/vcsa2", 0660, 7, 130);
blkdev("/dev/vcsa3", 0660, 7, 131);
blkdev("/dev/vcsa4", 0660, 7, 132);
#endif
continue;
}
/* This works only if /dev is tmpfs! If not, create
* devices statically on the filesystem
*/
if (MATCH_CMD(line, "mknod ", x)) {
strcpy(cmd, "/bin/mknod ");
build_cmd(cmd, x, CMD_SIZE);
system(cmd);
continue;
}
#endif
}
fclose(f);
}
/*
* Mount filesystems
*/
_d("mount filesystems");
#ifdef REMOUNT_ROOTFS_RW
system("/bin/mount -n -o remount,rw /");
#endif
umask(0);
#ifdef MAKE_DEVICES
mkdir("/dev/shm", 0755);
mkdir("/dev/pts", 0755);
#endif
mount("none", "/dev/pts", "devpts", 0, "gid=5,mode=620");
mount("none", "/dev/shm", "tmpfs", 0, NULL);
mount("none", "/tmp", "tmpfs", 0, "mode=1777,size=128m");
mount("none", "/var/run", "tmpfs", 0, "mode=0755");
mount("none", "/var/lock", "tmpfs", 0, "mode=1777");
mount("none", "/proc/bus/usb", "usbfs", 0, NULL);
mount(SYSROOT, "/", NULL, MS_MOVE, NULL);
_d("make devices");
#ifdef MAKE_DEVICES
mkdir("/dev/input", 0755);
chardev("/dev/urandom", 0666, 1, 9);
chardev("/dev/ptmx", 0666, 5, 2);
chardev("/dev/null", 0666, 1, 3);
chmod("/dev/null", 0666);
chardev("/dev/mem", 0640, 1, 1);
chardev("/dev/tty0", 0660, 4, 0);
chardev("/dev/tty1", 0660, 4, 1);
chardev("/dev/tty2", 0660, 4, 2);
chardev("/dev/tty3", 0660, 4, 3);
chardev("/dev/input/mice", 0660, 13, 63);
chardev("/dev/input/event0", 0660, 13, 64);
chardev("/dev/agpgart", 0660, 10, 175);
blkdev("/dev/loop0", 0600, 7, 0);
#endif
unlink("/etc/mtab");
system("mount -a");
umask(0022);
/*
* Time adjustments
*/
_d("adjust clock");
#ifndef NO_HCTOSYS
system("/sbin/hwclock --hctosys" HWCLOCK_DIRECTISA);
#endif
/*
* Network stuff
*/
#ifdef USE_ETC_RESOLVCONF_RUN
makepath("/dev/shm/network");
makepath("/dev/shm/resolvconf/interface");
if ((dir = opendir("/etc/resolvconf/run/interface")) != NULL) {
while ((d = readdir(dir)) != NULL) {
if (isalnum(d->d_name[0]))
continue;
snprintf(line, LINE_SIZE,
"/etc/resolvconf/run/interface/%s", d->d_name);
unlink(line);
}
closedir(dir);
}
#endif
#ifdef USE_VAR_RUN_RESOLVCONF
makepath("/var/run/resolvconf/interface");
symlink("../../../etc/resolv.conf", "/var/run/resolvconf/resolv.conf");
#endif
touch("/var/run/utmp");
chown("/var/run/utmp", 0, getgroup("utmp"));
chmod("/var/run/utmp", 0664);
#ifdef RUNLEVEL
memset(&entry, 0, sizeof(struct utmp));
entry.ut_type = RUN_LVL;
entry.ut_pid = '0' + RUNLEVEL;
setutent();
pututline(&entry);
endutent();
#endif
#ifdef USE_ETC_RESOLVCONF_RUN
touch("/etc/resolvconf/run/enable-updates");
chdir("/etc/resolvconf/run/interface");
#ifdef BUILTIN_RUNPARTS
run_parts("/etc/resolvconf/update.d", "-i", NULL);
#else
system(RUNPARTS " --arg=i /etc/resolvconf/update.d");
#endif
chdir("/");
#endif
#ifdef TOUCH_ETC_NETWORK_RUN_IFSTATE
touch("/etc/network/run/ifstate");
#endif
if ((f = fopen("/etc/hostname", "r")) != NULL) {
fgets(hostname, HOSTNAME_SIZE, f);
chomp(hostname);
fclose(f);
}
sethostname(hostname, strlen(hostname));
ifconfig("lo", "127.0.0.1", "255.0.0.0", 1);
/*
* Set random seed
*/
copyfile(RANDOMSEED, "/dev/urandom", 0);
unlink(RANDOMSEED);
umask(077);
copyfile("/dev/urandom", RANDOMSEED, 4096);
umask(0);
/*
* Console setup (for X)
*/
makepath("/var/run/console");
snprintf(line, LINE_SIZE, "/var/run/console/%s", username);
touch(line);
#ifdef PAM_CONSOLE
if ((fd = open("/var/run/console/console.lock", O_CREAT|O_WRONLY|O_TRUNC, 0644)) >= 0) {
write(fd, username, strlen(username));
close(fd);
system("/sbin/pam_console_apply");
}
#endif
/*
* Misc setup
*/
mkdir("/tmp/.X11-unix", 01777);
mkdir("/tmp/.ICE-unix", 01777);
umask(022);
system(GETTY "&");
_d("forking");
if (!fork()) {
/* child process */
vhangup();
close(2);
close(1);
close(0);
if (open("/dev/tty1", O_RDWR) != 0)
exit(1);
sigemptyset(&act.sa_mask);
act.sa_handler = SIG_DFL;
sigemptyset(&nmask2);
sigaddset(&nmask2, SIGCHLD);
sigprocmask(SIG_UNBLOCK, &nmask2, NULL);
for (i = 1; i < NSIG; i++)
sigaction(i, &sa, NULL);
dup2(0, 0);
dup2(0, 1);
dup2(0, 2);
#ifdef USE_MESSAGE_BUS
_d("dbus");
mkdir("/var/run/dbus", 0755);
mkdir("/var/lock/subsys/messagebus", 0755);
system("dbus-uuidgen --ensure;dbus-daemon --system");
#endif
#ifdef LISTEN_INITCTL
listen_initctl();
#endif
/* Prevents bash from running loadkeys */
unsetenv("TERM");
/* ConsoleKit needs this */
setenv("DISPLAY", ":0", 1);
while (access("/tmp/shutdown", F_OK) < 0) {
_d("start X as %s\n", username);
if (debug) {
snprintf(line, LINE_SIZE,
"su -l %s -c \"%s\"", username, startx);
system(line);
system("/bin/sh");
} else {
snprintf(line, LINE_SIZE,
"su -l %s -c \"%s\" &> /dev/null",
username, startx);
system(line);
}
}
exit(0);
}
/* parent process */
/* sleep(1); */
system("/usr/sbin/services.sh &>/dev/null&");
while (1) {
sigemptyset(&nmask);
pselect(0, NULL, NULL, NULL, NULL, &nmask);
}
}
/*
* Shut down on INT USR1 USR2
*/
void shutdown(int sig)
{
touch("/tmp/shutdown");
if (sdown) {
system(sdown);
}
kill(-1, SIGTERM);
write(1, "\033[?25l\033[30;40m", 14);
copyfile("/boot/shutdown.fb", "/dev/fb/0", 0);
sleep(2);
system("/usr/sbin/alsactl store > /dev/null 2>&1");
system("/sbin/hwclock --systohc" HWCLOCK_DIRECTISA);
kill(-1, SIGKILL);
sync();
sync();
system("/bin/umount -a;/bin/mount -n -o remount,ro /");
//system("/sbin/unionctl.static / --remove / > /dev/null 2>&1");
if (sig == SIGINT || sig == SIGUSR1)
reboot(RB_AUTOBOOT);
reboot(RB_POWER_OFF);
}
/*
* SIGCHLD: one of our children has died
*/
void chld_handler(int sig)
{
int status;
while (waitpid(-1, &status, WNOHANG) != 0) {
if (errno == ECHILD)
break;
}
}
-322
View File
@@ -1,322 +0,0 @@
/*
Improved fast init
Copyright (c) 2008 Claudio Matsuoka
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.
*/
/*
Changelog from the original Eeepc fastinit:
- Use mknod() instead of close(open()) call to create empty file
- Fix random seed initialization
- Don't try to handle signal 0, SIGKILL or SIGSTOP
- Implement makepath() to avoid system("mkdir -p")
- Omit first hwclock if user has CONFIG_RTC_HCTOSYS in kernel (by Metalshark)
- Add –directisa to hwclock if user has disabled CONFIG_GENRTC and enabled
CONFIG_RTC but not CONFIG_HPET_TIMER and CONFIG_HPET_RTC_IRQ (by Metalshark)
- Drop system() call to clean /tmp, it's a fresh mounted tmpfs
- Set loopback interface using direct calls instead of system("ifconfig")
- Copy 4096 data block in C instead of system("cat") or system("dd")
- Draw shutdown splash screen using C calls instead of system("echo;cat")
- Change poweroff method to reboot(RB_POWER_OFF) (by Metalshark)
- Mount /var/run and /var/lock as tmpfs
- Use SIG_IGN instead of empty signal handler (by Metalshark)
- Add built-in run-parts option to be used instead of system("run-parts")
- Reuse cmdline buffer as hostname and filename buffers
- Open terminal in vt2 using openvt
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <sys/mount.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#include <sys/reboot.h>
#include <sys/wait.h>
#include <linux/fs.h>
#include "helpers.h"
#ifdef DIRECTISA
#define HWCLOCK_DIRECTISA " --directisa"
#else
#define HWCLOCK_DIRECTISA
#endif
/* From sysvinit */
/* Set a signal handler. */
#define SETSIG(sa, sig, fun, flags) \
do { \
sa.sa_handler = fun; \
sa.sa_flags = flags; \
sigemptyset(&sa.sa_mask); \
sigaction(sig, &sa, NULL); \
} while (0)
#define touch(x) mknod((x), S_IFREG|0644, 0)
#define LINE_SIZE 1024
void shutdown(int);
void chld_handler(int);
int main()
{
int i;
FILE *f;
char line[LINE_SIZE];
int fd;
DIR *dir;
struct dirent *d;
struct sigaction sa, act;
char *x;
sigset_t nmask, nmask2;
puts("finit-mod " VERSION " (built " __DATE__ " " __TIME__
" by " WHOAMI ")");
chdir("/");
umask(022);
/*
* Signal management
*/
for (i = 1; i < NSIG; i++)
SETSIG(sa, i, SIG_IGN, SA_RESTART);
SETSIG(sa, SIGINT, shutdown, 0);
SETSIG(sa, SIGPWR, SIG_IGN, 0);
SETSIG(sa, SIGUSR1, shutdown, 0);
SETSIG(sa, SIGUSR2, shutdown, 0);
SETSIG(sa, SIGTERM, SIG_IGN, 0);
SETSIG(sa, SIGALRM, SIG_IGN, 0);
SETSIG(sa, SIGHUP, SIG_IGN, 0);
SETSIG(sa, SIGCONT, SIG_IGN, SA_RESTART);
SETSIG(sa, SIGCHLD, chld_handler, SA_RESTART);
/* Block sigchild while forking */
sigemptyset(&nmask);
sigaddset(&nmask, SIGCHLD);
sigprocmask(SIG_BLOCK, &nmask, NULL);
reboot(RB_DISABLE_CAD);
/*
* Parse kernel parameters
*/
if ((f = fopen("/proc/cmdline", "r")) != NULL) {
fgets(line, LINE_SIZE, f);
if (strstr(line, "quiet")) {
close(0);
close(1);
close(2);
}
fclose(f);
}
setsid();
/*
* Mount filesystems
*/
mount("proc", "/proc", "proc", 0, NULL);
mount("sysfs", "/sys", "sysfs", 0, NULL);
mount("devpts", "/dev/pts", "devpts", 0, "gid=5,mode=620");
mount("tmpfs", "/dev/shm", "tmpfs", 0, NULL);
mount("tmpfs", "/tmp", "tmpfs", 0, "mode=1777,size=128m");
mount("tmpfs", "/var/run", "tmpfs", 0, "mode=0755");
mount("tmpfs", "/var/lock", "tmpfs", 0, "mode=1777");
mount("/mnt", "/", NULL, MS_MOVE, NULL);
/*
* Time adjustments
*/
if ((fd = open("/etc/adjtime", O_CREAT|O_WRONLY|O_TRUNC, 0644)) >= 0) {
write(fd, "0.0 0 0.0\n", 10);
close(fd);
}
#ifndef NO_HCTOSYS
system("/sbin/hwclock --hctosys --localtime" HWCLOCK_DIRECTISA);
#endif
/*
* Network stuff
*/
makepath("/dev/shm/network");
makepath("/dev/shm/resolvconf/interface");
if ((dir = opendir("/etc/resolvconf/run/interface")) != NULL) {
while ((d = readdir(dir)) != NULL) {
if (isalnum(d->d_name[0]))
continue;
snprintf(line, LINE_SIZE,
"/etc/resolvconf/run/interface/%s", d->d_name);
unlink(line);
}
closedir(dir);
}
touch("/var/run/utmp");
touch("/etc/resolvconf/run/enable-updates");
chdir("/etc/resolvconf/run/interface");
#ifdef BUILTIN_RUNPARTS
run_parts("/etc/resolvconf/update.d", "-i", NULL);
#else
system("/bin/run-parts --arg=-i /etc/resolvconf/update.d");
#endif
chdir("/");
touch("/etc/network/run/ifstate");
if ((f = fopen("/etc/hostname", "r")) != NULL) {
fgets(line, LINE_SIZE, f);
if ((x = strchr(line, 0x0a)) != NULL)
*x = 0;
sethostname(line, strlen(line));
fclose(f);
}
ifconfig("lo", "127.0.0.1", "255.0.0.0", 1);
/*
* Set random seed
*/
copyfile("/var/lib/urandom/random-seed", "/dev/urandom", 0);
unlink("/var/lib/urandom/random-seed");
umask(077);
copyfile("/dev/urandom", "/var/lib/urandom/random-seed", 4096);
/*
* Misc setup
*/
unlink("/var/run/.clean");
unlink("/var/lock/.clean");
umask(0);
mkdir("/tmp/.X11-unix", 01777);
mkdir("/tmp/.ICE-unix", 01777);
umask(022);
system("/usr/bin/openvt /sbin/getty 38400 tty2&");
if (!fork()) {
/* child process */
vhangup();
close(2);
close(1);
close(0);
if (open("/dev/tty1", O_RDWR) != 0)
exit(1);
sigemptyset(&act.sa_mask);
act.sa_handler = SIG_DFL;
sigemptyset(&nmask2);
sigaddset(&nmask2, SIGCHLD);
sigprocmask(SIG_UNBLOCK, &nmask2, NULL);
for (i = 1; i < NSIG; i++)
sigaction(i, &sa, NULL);
dup2(0, 0);
dup2(0, 1);
dup2(0, 2);
touch("/tmp/nologin");
while (access("/tmp/shutdown", F_OK) < 0)
system("su -c startx -l user &> /dev/null");
exit(0);
}
/* parent process */
sleep(1);
system("/usr/sbin/services.sh &>/dev/null&");
while (1) {
sigemptyset(&nmask);
pselect(0, NULL, NULL, NULL, NULL, &nmask);
}
}
/*
* Shut down on INT USR1 USR2
*/
void shutdown(int sig)
{
touch("/tmp/shutdown");
kill(-1, SIGTERM);
write(1, "\033[?25l\033[30;40m", 14);
copyfile("/boot/shutdown.fb", "/dev/fb/0", 0);
sleep(2);
system("/usr/sbin/alsactl store > /dev/null 2>&1");
system("/sbin/hwclock --systohc --localtime" HWCLOCK_DIRECTISA);
kill(-1, SIGKILL);
sync();
sync();
system("/bin/mount -n -o remount,ro /");
system("/sbin/unionctl.static / --remove / > /dev/null 2>&1");
if (sig == SIGINT || sig == SIGUSR1)
reboot(RB_AUTOBOOT);
reboot(RB_POWER_OFF);
}
/*
* SIGCHLD: one of our children has died
*/
void chld_handler(int sig)
{
int status;
while (waitpid(-1, &status, WNOHANG) != 0) {
if (errno == ECHILD)
break;
}
}
+247 -235
View File
@@ -1,282 +1,294 @@
/* 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>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <sys/mount.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <ctype.h>
#include <dirent.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#include <sys/reboot.h>
#include <sys/wait.h>
#include <linux/fs.h>
#include <sys/stat.h> /* umask(), mkdir() */
#include <getopt.h>
#include "finit.h"
#include "helpers.h"
#include "private.h"
#include "plugin.h"
#include "svc.h"
#include "sig.h"
#include "tty.h"
#include "lite.h"
/* From sysvinit */
/* Set a signal handler. */
#define SETSIG(sa, sig, fun, flags) \
do { \
sa.sa_handler = fun; \
sa.sa_flags = flags; \
sigemptyset(&sa.sa_mask); \
sigaction(sig, &sa, NULL); \
} while(0)
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;
#define touch(x) close(open((x), O_CREAT|O_WRONLY|O_TRUNC, 0644))
static void parse_kernel_cmdline(void)
{
FILE *fp;
char line[LINE_SIZE];
if ((fp = fopen("/proc/cmdline", "r")) != NULL) {
fgets(line, sizeof(line), fp);
_d("Kernel command line: %s", line);
void shutdown(int);
void signal_handler(int);
void chld_handler(int);
if (strstr(line, "finit_debug") || strstr(line, "--debug"))
debug = 1;
if (!debug && strstr(line, "quiet"))
verbose = 0;
int main()
fclose(fp);
}
}
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 i;
FILE *f;
char line[2096];
int fd;
DIR *dir;
struct dirent *d;
char filename[1024];
struct sigaction sa, act;
char hline[1024];
char *x;
sigset_t nmask, nmask2;
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;
}
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);
chdir("/");
umask(022);
/*
* Signal management
* Hello world.
*/
for (i = 1; i < NSIG; i++)
SETSIG(sa, i, SIG_IGN, SA_RESTART);
banner();
SETSIG(sa, SIGINT, shutdown, 0);
SETSIG(sa, SIGPWR, signal_handler, 0);
SETSIG(sa, SIGUSR1, shutdown, 0);
SETSIG(sa, SIGUSR2, shutdown, 0);
SETSIG(sa, SIGTERM, signal_handler, 0);
SETSIG(sa, SIGKILL, signal_handler, 0);
SETSIG(sa, SIGALRM, signal_handler, 0);
SETSIG(sa, SIGHUP, signal_handler, 0);
SETSIG(sa, SIGSTOP, signal_handler, SA_RESTART);
SETSIG(sa, SIGCONT, signal_handler, SA_RESTART);
SETSIG(sa, SIGCHLD, chld_handler, SA_RESTART);
/* Block sigchild while forking */
sigemptyset(&nmask);
sigaddset(&nmask, SIGCHLD);
sigprocmask(SIG_BLOCK, &nmask, NULL);
/*
* Initial setup of signals, ignore all until we're up.
*/
sig_init();
reboot(RB_DISABLE_CAD);
/*
* Mount base file system, kernel is assumed to run devtmpfs for /dev
*/
chdir("/");
umask(0);
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);
mount("none", "/dev/pts", "devpts", 0, "gid=5,mode=620");
mount("none", "/dev/shm", "tmpfs", 0, NULL);
umask(022);
/*
* Parse kernel parameters
*/
if ((f = fopen("/proc/cmdline", "r")) != NULL) {
fgets(line, 2095, f);
if (strstr(line, "quiet")) {
close(0);
close(1);
close(2);
}
fclose(f);
}
parse_kernel_cmdline();
setsid();
/*
* Populate /dev and prepare for runtime events from kernel.
*/
run_interactive(SETUP_DEVFS, "Populating device tree");
/*
* Parse configuration file
*/
parse_finit_conf(FINIT_CONF);
/*
* Load plugins. Must run after finit.conf has registered
* all services, or service plugins won't have anything to
* hook on to.
*/
print_desc("", "Loading Finit plugins");
print_result(plugin_load_all(PLUGIN_PATH));
/*
* Mount filesystems
*/
mount("proc", "/proc", "proc", 0, NULL);
mount("sysfs", "/sys", "sysfs", 0, NULL);
mount("devpts", "/dev/pts", "devpts", 0, "gid=5,mode=620");
mount("tmpfs", "/dev/shm", "tmpfs", 0, NULL);
mount("tmpfs", "/tmp", "tmpfs", 0, "mode=1777,size=128m");
mount("/mnt", "/", NULL, MS_MOVE, NULL);
#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);
umask(0);
run("/bin/mount -na");
run("/sbin/swapon -ea");
umask(0022);
/* 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 */
sig_setup();
_d("Base FS up, calling hooks ...");
plugin_run_hooks(HOOK_BASEFS_UP);
/*
* Time adjustments
* Start all bootstrap tasks, no network available!
*/
if ((fd = open("/etc/adjtime", O_CREAT|O_WRONLY|O_TRUNC, 0644)) >= 0) {
write(fd, "0.0 0 0.0\n", 10);
close(fd);
}
system("/sbin/hwclock --hctosys --localtime");
svc_bootstrap();
/*
* Network stuff
*/
system("mkdir -p /dev/shm/network");
system("mkdir -p /dev/shm/resolvconf/interface");
if ((dir = opendir("/etc/resolvconf/run/interface")) != NULL) {
while ((d = readdir(dir)) != NULL) {
if (isalnum(d->d_name[0]))
continue;
sprintf(filename, "/etc/resolvconf/run/interface/%s",
d->d_name);
unlink(filename);
}
/* Setup kernel specific settings, e.g. allow broadcast ping, etc. */
run("/sbin/sysctl -e -p /etc/sysctl.conf >/dev/null");
closedir(dir);
}
/* Set initial hostname. */
set_hostname(hostname);
touch("/var/run/utmp");
touch("/etc/resolvconf/run/enable-updates");
chdir("/etc/resolvconf/run/interface");
system("/bin/run-parts --arg=-i /etc/resolvconf/update.d");
chdir("/");
touch("/etc/network/run/ifstate");
if ((f = fopen("/etc/hostname", "r")) != NULL) {
fgets(hline, 1023, f);
if ((x = strchr(hline, 0x0a)) != NULL)
*x = 0;
sethostname(hline, strlen(hline));
fclose(f);
}
system("/sbin/ifconfig lo 127.0.0.1 netmask 255.0.0.0 up > /dev/null");
/*
* Set random seed
*/
/* Bug: the eeepc never sets its random seed from file */
system("/bin/cat /var/lib/urandom/random-seed >/dev/urandom "
"> /dev/null 2>&1");
unlink("/var/lib/urandom/random-seed");
umask(077);
system("/bin/dd if=/dev/urandom of=/var/lib/urandom/random-seed "
"bs=4096 count=1 >/dev/null 2>&1");
/*
* Misc setup
*/
/* not really needed, /tmp is a fresh mounted tmpfs */
system("/bin/rm -rf /tmp/* /tmp/.* 2>/dev/null");
unlink("/var/run/.clean");
unlink("/var/lock/.clean");
umask(0);
mkdir("/tmp/.X11-unix", 01777);
mkdir("/tmp/.ICE-unix", 01777);
ifconfig("lo", "127.0.0.1", "255.0.0.0", 1);
if (network)
run_interactive(network, "Starting networking: %s", network);
umask(022);
if (!fork()) {
/* child process */
/* Hooks that rely on loopback, or basic networking being up. */
plugin_run_hooks(HOOK_NETWORK_UP);
vhangup();
/*
* Start all tasks/services in the configured runlevel
*/
svc_runlevel(cfglevel);
close(2);
close(1);
close(0);
_d("Running svc up hooks ...");
plugin_run_hooks(HOOK_SVC_UP);
if (open("/dev/tty1", O_RDWR, 0))
exit(1);
sigemptyset(&act.sa_mask);
act.sa_handler = SIG_DFL;
sigemptyset(&nmask2);
sigaddset(&nmask2, SIGCHLD);
sigprocmask(SIG_UNBLOCK, &nmask2, NULL);
/* Bug: no signal 0 */
for (i = 0; i < NSIG; i++)
sigaction(i, &sa, NULL);
dup2(0, 0);
dup2(0, 1);
dup2(0, 2);
touch("/tmp/nologin");
while (access("/tmp/shutdown", F_OK) < 0)
system("su -c startx -l user &> /dev/null");
exit(0);
/*
* Run startup scripts in /etc/finit.d/, if any.
*/
if (rcsd && fisdir(rcsd)) {
_d("Running startup scripts in %s ...", rcsd);
run_parts(rcsd, NULL);
}
/* parent process */
system("/sbin/getty 38400 tty3 &");
sleep(1);
system("/usr/sbin/services.sh &> /dev/null &");
/* Hooks that should run at the very end */
plugin_run_hooks(HOOK_SYSTEM_UP);
while (1) {
sigemptyset(&nmask);
pselect(0, NULL, NULL, NULL, NULL, &nmask);
}
/*
* Enter main loop to monior /dev/initctl and services
*/
return run_loop();
}
/*
* Shut down on INT USR1 USR2
/**
* Local Variables:
* version-control: t
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
void shutdown(int sig)
{
int fd;
system("/usr/bin/touch /tmp/shutdown");
kill(-1, SIGTERM);
system("/bin/echo -e \"\033[?25l\033[30;40m\"; "
"/bin/cp /boot/shutdown.fb /dev/fb/0");
sleep(1);
sleep(1);
system("/usr/sbin/alsactl store > /dev/null 2>&1");
system("/sbin/hwclock --systohc --localtime");
kill(-1, SIGKILL);
sync();
sync();
system("/bin/mount -n -o remount,ro /");
system("/sbin/unionctl.static / --remove / > /dev/null 2>&1");
if (sig == SIGINT || sig == SIGUSR1)
reboot(RB_AUTOBOOT);
if ((fd = open("/proc/acpi/sleep", O_WRONLY)) >= 0) {
write(fd, "5", 1);
close(fd);
}
}
/*
* SIGCHLD: one of our children has died
*/
void chld_handler(int sig)
{
int status;
while (waitpid(-1, &status, WNOHANG) != 0) {
if (errno == ECHILD)
break;
}
}
/*
* We got a signal (PWR TERM ALRM HUP STOP CONT)
*/
void signal_handler(int sig)
{
/* do nothing */
}
+38 -6
View File
@@ -1,6 +1,38 @@
user fred
module intel-agp
module p4-clockmod
check /dev/sda3
host eviltwin
startx /usr/bin/startx
# 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
# Runlevel to start after bootstrap, runlevel 'S'
runlevel 2
# Network bringup script
network service networking start
# 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 [2345] /usr/sbin/sshd -D -- OpenSSH server
service [3] /usr/sbin/gdm -- GNOME Display Manager
# By default Finit looks for /etc/finit.d
# runparts /etc/finit.d
+105
View File
@@ -0,0 +1,105 @@
/* Finit - Extremely fast /sbin/init replacement w/ I/O, hook & service plugins
*
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@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
* 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_H_
#define FINIT_H_
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
/* Distribution specific configuration */
#if defined EMBEDDED_SYSTEM
# define CONSOLE "/dev/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 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 HAVE_DBUS
#endif
#ifndef DEFUSER
# define DEFUSER "root"
#endif
#ifndef DEFHOST
# define DEFHOST "noname"
#endif
/* Delay start of GETTY at boot. Must be > 0 */
#define DELAY_TTY 2
#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 */
int parse_runlevels (char *runlevels);
void parse_finit_conf (char *file);
#endif /* FINIT_H_ */
/**
* Local Variables:
* version-control: t
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+587 -77
View File
@@ -1,4 +1,28 @@
/* 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>
*
* 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 <ctype.h> /* isdigit() */
#include <string.h>
#include <limits.h>
#include <stdlib.h>
@@ -7,42 +31,56 @@
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/prctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#ifdef BUILTIN_RUNPARTS
#include <dirent.h>
#include <stdarg.h>
#include <sys/wait.h>
#endif
#include <grp.h>
#include <pwd.h>
#include "finit.h"
#include "helpers.h"
#include "private.h"
#include "sig.h"
#include "lite.h"
#define NUM_ARGS 16
#define NUM_SCRIPTS 128 /* ought to be enough for anyone */
/*
* Helpers to replace system() calls
*/
int makepath(char *p)
int makepath(char *path)
{
char *x, path[PATH_MAX];
char buf[PATH_MAX];
char *x = buf;
int ret;
x = path;
if (!path) {
errno = EINVAL;
return -1;
}
do {
do { *x++ = *p++; } while (*p && *p != '/');
do {
*x++ = *path++;
} while (*path && *path != '/');
*x = 0;
ret = mkdir(path, 0777);
} while (*p && (*p != '/' || *(p + 1))); /* ignore trailing slash */
ret = mkdir(buf, 0777);
} while (*path && (*path != '/' || *(path + 1))); /* ignore trailing slash */
return ret;
}
void ifconfig(char *name, char *inet, char *mask, int up)
void ifconfig(char *ifname, char *addr, char *mask, int up)
{
struct ifreq ifr;
struct sockaddr_in *a = (struct sockaddr_in *)&ifr.ifr_addr;
@@ -52,14 +90,18 @@ void ifconfig(char *name, char *inet, char *mask, int up)
return;
memset(&ifr, 0, sizeof (ifr));
strncpy(ifr.ifr_name, name, IFNAMSIZ);
a->sin_family = AF_INET;
strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
ifr.ifr_addr.sa_family = AF_INET;
if (up) {
inet_aton(inet, &a->sin_addr);
ioctl(sock, SIOCSIFADDR, &ifr);
inet_aton(mask, &a->sin_addr);
ioctl(sock, SIOCSIFNETMASK, &ifr);
if (addr) {
inet_aton(addr, &a->sin_addr);
ioctl(sock, SIOCSIFADDR, &ifr);
}
if (mask) {
inet_aton(mask, &a->sin_addr);
ioctl(sock, SIOCSIFNETMASK, &ifr);
}
}
ioctl(sock, SIOCGIFFLAGS, &ifr);
@@ -74,97 +116,530 @@ void ifconfig(char *name, char *inet, char *mask, int up)
close(sock);
}
#define BUF_SIZE 4096
void copyfile(char *src, char *dst, int size)
/**
* pidfile_read - Reads a PID value from a pidfile.
* @pidfile: File containing PID, usually in /var/run/<PROC>.pid
*
* This function takes a @pidfile and returns the PID found therein.
*
* Returns:
* On invalid @pidfile -1 and @errno set to %EINVAL, when @pidfile does not exist -1
* and errno set to %ENOENT. When the pidfile is empty or when its contents cannot
* be translated this function returns zero (0), on success this function returns
* a PID value greater than one. PID 1 is reserved for the system init process.
*/
pid_t pidfile_read(char *pidfile)
{
char buffer[BUF_SIZE];
int s, d, n;
pid_t pid = 0;
char buf[16];
FILE *fp;
/* Size == 0 means copy entire file */
if (size == 0)
size = INT_MAX;
if (!pidfile) {
errno = EINVAL;
return -1;
}
if ((s = open(src, O_RDONLY)) >= 0) {
if ((d = open(dst, O_WRONLY | O_CREAT, 0644)) >= 0) {
do {
int csize = size > BUF_SIZE ? BUF_SIZE : size;
if ((n = read(s, buffer, csize)) > 0)
write(d, buffer, n);
size -= csize;
} while (size > 0 && n == BUF_SIZE);
close(d);
}
close(s);
if (!fexist(pidfile))
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);
return pid;
}
/**
* pidfile_poll - Poll for the existence of a pidfile and return PID
* @cmd: Process name, or command, called to expect a pidfile
* @path: Path to pidfile to poll for
*
* This function polls for the pidfile at @path for at most 5 seconds
* before timing out. If the file is created within that time span the
* file is read and its PID contents returned.
*
* Returns:
* The PID read from @path, or zero on timeout.
*/
pid_t pidfile_poll(char *cmd, char *path)
{
pid_t pid = 0;
int tries = 0;
/* Timeout = 100 * 50ms = 5s */
while (!fexist(path) && tries++ < 100) {
/* Wait 50ms between retries */
usleep(50000);
}
if (!fexist(path)) {
_e("Timeout! No PID found for %s, pidfile %s does not exist?", cmd, path);
pid = 0;
} else {
pid = pidfile_read(path);
}
return pid;
}
#ifdef BUILTIN_RUNPARTS
#define NUM_SCRIPTS 128 /* ought to be enough for anyone */
#define NUM_ARGS 16
static int cmp(const void *s1, const void *s2)
/**
* pid_alive - Check if a given process ID is running
* @pid: Process ID to check for.
*
* Returns:
* %TRUE(1) if pid is alive (/proc/pid exists), otherwise %FALSE(0)
*/
int pid_alive(pid_t pid)
{
return strcmp(*(char **)s1, *(char **)s2);
char name[24]; /* Enough for max pid_t */
snprintf(name, sizeof(name), "/proc/%d", pid);
return fexist(name);
}
int run_parts(char *dir, ...)
/**
* pid_get_name - Find name of a process
* @pid: PID of process to find.
* @name: Pointer to buffer where to return process name, may be %NULL
* @len: Length in bytes of @name buffer.
*
* If @name is %NULL, or @len is zero the function will return
* a static string. This may be useful to one-off calls.
*
* Returns:
* %NULL on error, otherwise a va
*/
char *pid_get_name(pid_t pid, char *name, size_t len)
{
DIR *d;
struct dirent *e;
struct stat st;
char *ent[NUM_SCRIPTS];
int i, num = 0, argnum = 1;
char *args[NUM_ARGS];
va_list ap;
int ret = 1;
FILE *fp;
char path[32];
static char line[64];
if (chdir(dir))
return -1;
if (!name || len == 0)
name = line;
if ((d = opendir(dir)) == NULL)
return -1;
snprintf(path, sizeof(path), "/proc/%d/status", pid);
if ((fp = fopen(path, "r")) != NULL) {
if (fgets(line, sizeof (line), fp)) {
char *pname = line + 6; /* Skip first part of line --> "Name:\t" */
va_start(ap, dir);
while (argnum < NUM_ARGS && (args[argnum++] = va_arg(ap, char *)));
va_end(ap);
chomp(pname);
strlcpy(name, pname, len);
ret = 0; /* Found it! */
}
while ((e = readdir(d))) {
if (e->d_type == DT_REG && stat(e->d_name, &st) == 0) {
if (st.st_mode & S_IXUSR) {
ent[num++] = strdup(e->d_name);
if (num >= NUM_SCRIPTS)
break;
fclose(fp);
}
if (ret)
return NULL;
return name;
}
/**
* procname_kill - Send a signal to a process group by name.
* @name: Name of process to send signal to.
* @signo: Signal to send.
*
* Send a signal to a running process (group). This function searches
* for a given process @name and sends a signal, @signo, to each
* process ID matching that @name.
*
* Returns:
* Number of signals sent, i.e. number of processes who have received the signal.
*/
int procname_kill(char *name, int signo)
{
int result = 0;
char path[32], line[64];
FILE *fp;
DIR *dir;
struct dirent *entry;
dir = opendir("/proc");
if (!dir || !name) {
errno = EINVAL;
return 0;
}
while ((entry = readdir(dir)) != NULL) {
/* Skip non-process entries in /proc */
if (!isdigit(*entry->d_name))
continue;
snprintf(path, sizeof(path), "/proc/%s/status", entry->d_name);
/* Skip non-readable files (protected?) */
if ((fp = fopen(path, "r")) == NULL)
continue;
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) {
int error = errno;
if (kill(atoi(entry->d_name), signo)) {
FLOG_ERROR("Failed signalling(%d) %s: %s!", signo, name, strerror(error));
} else {
result++; /* Track number of processes we deliver the signal to. */
}
}
}
fclose(fp);
}
closedir(d);
closedir(dir);
if (num == 0)
return 0;
return result;
}
qsort(ent, num, sizeof(char *), cmp);
static int print_timestamp(void)
{
#if defined(CONFIG_PRINTK_TIME)
FILE * uptimefile;
float num1, num2;
char uptime_str[30];
if((uptimefile = fopen("/proc/uptime", "r")) == NULL)
return 1;
fgets(uptime_str, 20, uptimefile);
fclose(uptimefile);
sscanf(uptime_str, "%f %f", &num1, &num2);
sprintf(uptime_str, "[ %.6f ]", num1);
write(STDERR_FILENO, uptime_str, strlen(uptime_str));
#endif
return 0;
}
void print_desc(char *action, char *desc)
{
const char dots[] = " .....................................................................";
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. */
}
int print_result(int fail)
{
if (fail)
fprintf(stderr, " \e[7m[FAIL]\e[0m\n");
else
fprintf(stderr, " \e[1m[ OK ]\e[0m\n");
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;
/* We must create a copy that is possible to modify. */
backup = arg = strdup(cmd);
if (!arg)
return 1; /* Failed allocating a string to be modified. */
/* Split command line into tokens of an argv[] array. */
args[i++] = strsep(&arg, "\t ");
while (arg && i < NUM_ARGS) {
/* Handle run("su -c \"dbus-daemon --system\" messagebus");
* => "su", "-c", "\"dbus-daemon --system\"", "messagebus" */
if (*arg == '\'' || *arg == '"') {
char *p, delim[2] = " ";
delim[0] = arg[0];
args[i++] = arg++;
strsep(&arg, delim);
p = arg - 1;
*p = *delim;
*arg++ = 0;
} else {
args[i++] = strsep(&arg, "\t ");
}
}
args[i] = NULL;
#if 0
_e("Splitting: '%s' =>", cmd);
for (i = 0; args[i]; i++)
_e("\t%s", args[i]);
#endif
if (i == NUM_ARGS && args[i]) {
_e("Command too long: %s", cmd);
free(backup);
errno = EOVERFLOW;
return 1;
}
fp = fopen("/dev/null", "w");
pid = fork();
if (0 == pid) {
int i;
struct sigaction sa;
/* Reset signal handlers that were set by the parent process */
for (i = 1; i < NSIG; i++)
DFLSIG(sa, i, 0);
/* Redirect stdio if the caller requested so. */
if (fp) {
int fd = fileno(fp);
dup2(fd, STDIN_FILENO);
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO);
}
execvp(args[0], args);
_exit(1); /* Only if execv() fails. */
} else if (-1 == pid) {
_pe("%s", args[0]);
return -1;
}
status = complete(args[0], pid);
if (-1 == status) {
if (fp) fclose(fp);
free(backup);
return 1;
}
result = WEXITSTATUS(status);
if (WIFEXITED(status)) {
_d("Started %s and ended OK: %d", args[0], result);
} else if (WIFSIGNALED(status)) {
_d("Process %s terminated by signal %d", args[0], WTERMSIG(status));
if (!result)
result = 1; /* Must alert callee that the command did complete successfully.
* This is necessary since not all programs trap signals and
* change their return code accordingly. --Jocke */
}
if (fp) fclose(fp);
free(backup);
return result;
}
int run_interactive(char *cmd, char *fmt, ...)
{
int status, oldout = 1, olderr = 2;
char line[LINE_SIZE];
va_list ap;
FILE *fp = tmpfile();
va_start(ap, fmt);
vsnprintf(line, sizeof(line), fmt, ap);
va_end(ap);
if (fmt)
print_desc("", line);
if (fp && !debug) {
oldout = dup(STDOUT_FILENO);
olderr = dup(STDERR_FILENO);
dup2(fileno(fp), STDOUT_FILENO);
dup2(fileno(fp), STDERR_FILENO);
}
status = run(cmd);
if (fp && !debug) {
dup2(oldout, STDOUT_FILENO);
dup2(olderr, STDERR_FILENO);
}
if (fmt)
print_result(status);
if (fp && !debug) {
size_t len, written;
rewind(fp);
do {
len = fread(line, 1, sizeof(line), fp);
written = fwrite(line, len, sizeof(char), stderr);
} while (len > 0 && written == len);
fclose(fp);
}
return status;
}
pid_t run_getty(char *cmd, char *args[], int console)
{
pid_t pid = fork();
if (!pid) {
int i;
char c;
sigset_t nmask;
struct sigaction sa;
if (console) {
/* Detach from initial controlling TTY */
vhangup();
close(2);
close(1);
close(0);
/* Attach TTY to console */
if (open(CONSOLE, O_RDWR) != 0)
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++)
DFLSIG(sa, i, 0);
while (!fexist(SYNC_SHUTDOWN)) {
static const char msg[] = "\nPlease press Enter to activate this console.";
if (fexist(SYNC_STOPPED)) {
sleep(1);
continue;
}
if (console) {
i = write(STDERR_FILENO, msg, sizeof(msg));
while (read(STDIN_FILENO, &c, 1) == 1 && c != '\n')
continue;
}
if (fexist(SYNC_STOPPED))
continue;
execv(cmd, args);
}
exit(0);
}
return pid;
}
int run_parts(char *dir, char *cmd)
{
struct dirent **e;
int i, num;
num = scandir(dir, &e, NULL, alphasort);
if (num < 0) {
_d("No files found in %s, skipping ...", dir);
return -1;
}
for (i = 0; i < num; i++) {
args[0] = ent[i];
if (!fork()) {
execv(ent[i], args);
int j = 0, status;
pid_t pid = 0;
mode_t mode;
char *args[NUM_ARGS];
char *name = e[i]->d_name;
char path[CMD_SIZE];
snprintf(path, sizeof(path), "%s/%s", dir, name);
mode = fmode(path);
if (!S_ISEXEC(mode) || S_ISDIR(mode)) {
_d("Skipping %s ...", path);
continue;
}
/* Fill in args[], starting with full path to executable */
args[j++] = path;
/* If the callee didn't supply a run_parts() argument */
if (!cmd) {
/* Check if S<NUM>service or K<NUM>service notation is used */
_d("Checking if %s is a sysvinit startstop script ...", name);
if (name[0] == 'S' && isdigit(name[1])) {
args[j++] = "start";
} else if (name[0] == 'K' && isdigit(name[1])) {
args[j++] = "stop";
}
} else {
args[j++] = cmd;
}
args[j++] = NULL;
pid = fork();
if (!pid) {
_d("Calling %s ...", path);
execv(path, args);
exit(0);
}
wait(NULL);
free(ent[i]);
waitpid(pid, &status, 0);
}
while (num--)
free(e[num]);
free(e);
return 0;
}
int getgroup(char *s)
int getuser(char *username)
{
struct passwd *usr;
if (!username || (usr = getpwnam(username)) == NULL)
return -1;
return usr->pw_uid;
}
int getgroup(char *group)
{
struct group *grp;
if ((grp = getgrnam(s)) == NULL)
if ((grp = getgrnam(group)) == NULL)
return -1;
return grp->gr_gid;
@@ -174,12 +649,47 @@ int getgroup(char *s)
* Other convenience functions
*/
void chomp(char *s)
void chomp(char *str)
{
char *x;
char *x = strrchr(str, 0x0a);
if ((x = strchr((s), 0x0a)) != NULL)
if (x)
*x = 0;
}
#endif
/* 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) {
struct stat st;
fstat(fileno(fp), &st);
hostname = realloc(hostname, st.st_size);
if (!hostname)
return;
fgets(hostname, st.st_size, fp);
chomp(hostname);
fclose(fp);
}
if (hostname)
sethostname(hostname, strlen(hostname));
}
/**
* Local Variables:
* version-control: t
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+115 -10
View File
@@ -1,14 +1,119 @@
#ifndef __FINIT_HELPERS_H
#define __FINIT_HELPERS_H
/* 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>
*
* 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.
*/
int makepath (char *);
void ifconfig (char *, char *, char *, int);
void copyfile (char *, char *, int);
void chomp (char *);
int getgroup (char *);
#ifndef FINIT_HELPERS_H_
#define FINIT_HELPERS_H_
#ifdef BUILTIN_RUNPARTS
int run_parts (char *, ...);
#include <stdio.h>
#include <syslog.h>
#define DO_LOG(level, fmt, args...) \
{ \
openlog("finit", LOG_CONS | LOG_PID, LOG_DAEMON); \
syslog(level, fmt, ##args); \
closelog(); \
}
#define FLOG_DEBUG(fmt, args...) DO_LOG(LOG_DEBUG, fmt, ##args)
#define FLOG_WARN(fmt, args...) DO_LOG(LOG_WARNING, fmt, ##args)
#define FLOG_ERROR(fmt, args...) DO_LOG(LOG_CRIT, fmt, ##args)
#define FLOG_PERROR(fmt, args...) DO_LOG(LOG_CRIT, fmt ". Error %d: %s", ##args, errno, strerror(errno))
#ifndef touch
# define touch(x) mknod((x), S_IFREG|0644, 0)
#endif
#ifndef chardev
# define chardev(x,m,maj,min) mknod((x), S_IFCHR|(m), makedev((maj),(min)))
#endif
#ifndef blkdev
# define blkdev(x,m,maj,min) mknod((x), S_IFBLK|(m), makedev((maj),(min)))
#endif
#ifndef S_ISEXEC
# define S_ISEXEC(m) (((m) & S_IXUSR) == S_IXUSR)
#endif
#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 { 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);
void ifconfig (char *ifname, char *addr, char *mask, int up);
pid_t pidfile_read (char *pidfile);
pid_t pidfile_poll (char *cmd, char *path);
int pid_alive (pid_t pid);
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);
int print_result (int fail);
int start_process (char *cmd, char *args[], int console);
void chomp (char *str);
void do_sleep (unsigned int sec);
int getuser (char *username);
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 *args[], int console);
int run_parts (char *dir, char *cmd);
#endif /* FINIT_HELPERS_H_ */
/**
* Local Variables:
* version-control: t
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+80
View File
@@ -0,0 +1,80 @@
# Finit libite -- Light-weight utility functions and C-library extensions
#
# Copyright (c) 2008-2012 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.
.EXPORT_ALL_VARIABLES:
.PHONY: all install clean
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
LIBNAME = libite
TARGET = $(LIBNAME).so
VERLIB = $(TARGET).$(VER)
STATICLIB = $(LIBNAME).a
CHECK_FLAGS = $(CFLAGS) $(CPPFLAGS)
all: $(TARGET)
$(OBJS): Makefile
$(TARGET): $(OBJS)
@printf " LINK %s\n" $@
# @$(AR) $(ARFLAGS) $(STATICLIB) $(OBJS)
@$(CC) $(LDFLAGS) -shared $(OBJS) -lrt -lcrypt -Wl,-soname,$@ -o $@
@ln -sf $@ $(VERLIB)
install-exec: all
@install -d $(DESTDIR)$(libdir)
@echo " INSTALL $(DESTDIR)$(libdir)/$(TARGET)"
@$(STRIPINST) $(TARGET) $(DESTDIR)$(libdir)/$(TARGET)
@ln -sf $(TARGET) $(DESTDIR)$(libdir)/$(VERLIB)
install-dev:
@for file in $(HEADERS); do \
printf " INSTALL $(DESTDIR)$(incdir)/$$file\n"; \
$(INSTALL) -m 0644 $$file $(DESTDIR)$(incdir)/$$file; \
done
install: install-dev install-exec
uninstall:
-@$(RM) $(DESTDIR)$(libdir)/$(VERLIB)
-@$(RM) $(DESTDIR)$(libdir)/$(TARGET)
clean: uninstall
-@$(RM) $(OBJS) $(DEPS) $(TARGET) $(VERLIB) $(STATICLIB)
distclean: clean
-@$(RM) $(JUNK) unittest *.o .*.d *.unittest
ifneq ($(MAKECMDGOALS),clean)
ifneq ($(MAKECMDGOALS),distclean)
-include $(DEPS)
endif
endif
+318
View File
@@ -0,0 +1,318 @@
/* Fastinit (finit) copyfile() implementation.
*
* Copyright (c) 2008 Claudio Matsuoka <http://helllabs.org/finit/>
*
* 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>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/param.h> /* MAX(), isset(), setbit(), TRUE, FALSE, et consortes. :-) */
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include "lite.h"
static int __isdir_and_append_filename(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.
*
* 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
* the finit project, http://helllabs.org/finit/, which is a reimplementation
* of fastinit for the Asus EeePC.
*
* Only some small changes to save stack space have been introduced.
*
* Returns:
* The number of bytes copied, zero may be error (check errno!), but it
* 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)
{
char *buffer;
int s, d, n, isdir = 0, saved_errno = 0;
ssize_t size = 0;
errno = 0; /* Reset before leaving this function. */
// fprintf (stderr, "%s() src: %s, dst: %s, len: %d\n", __func__, src, dst, len);
buffer = malloc(BUFSIZ);
if (!buffer)
return 0;
if (fisdir(src)) {
errno = EISDIR; /* Error: source is a directory */
return 0;
}
/* Check if target is a directory, then append the src base filename. */
isdir = __isdir_and_append_filename(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;
}
while (len > 0 && n == BUFSIZ);
close(d);
} else {
saved_errno = errno;
}
close(s);
} else {
saved_errno = errno;
}
free(buffer);
if (isdir)
free(dst);
errno = saved_errno;
return size;
}
/**
* movefile - Move a file to another location
* @src: Source file.
* @dst: Target file, or location.
*
* This is a C implementation of the command line mv(1) utility.
* Usually the rename() API is sufficient, but not when moving across
* file system boundaries.
*
* The @src argument must include the full path to the source file,
* whereas the @dst argument may only be a directory, in which case the
* same file name from @src is used.
*
* Returns:
* POSIX OK(0), or non-zero with errno set.
*/
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);
if (rename(src, dst)) {
if (errno == EXDEV) {
errno = 0;
copyfile(src, dst, 0);
if (errno)
result = 1;
else
result = remove(src);
} else {
result = 1;
}
}
if (isdir)
free(dst);
return result;
}
/**
* copy_filep - Copy between FILE *fp.
* @src: Source FILE.
* @dst: Destination FILE.
*
* Function takes signals into account and will restart the syscalls as long
* as error is %EINTR.
*
* Returns:
* POSIX OK(0), or non-zero with errno set on error.
*/
int copy_filep(FILE *src, FILE *dst)
{
int result = 0;
char *buf = (char *)malloc(BUFSIZ);
if (!src || !dst)
return EINVAL;
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);
continue;
}
result = errno;
goto exit;
}
}
exit:
free(buf);
return errno = result;
}
/* 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)
{
int isdir = 0;
if (fisdir(*dst)) {
int slash = 0;
char *tmp, *ptr = strrchr(src, '/');
if (!ptr)
ptr = src;
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;
return 0;
}
isdir = 1; /* Free dst before exit! */
slash = fisslashdir(*dst);
sprintf(tmp, "%s%s%s", *dst, slash ? "" : "/", ptr);
*dst = tmp;
// fprintf (stderr, "NEW DST:%s\n", *dst);
}
return isdir;
}
#ifdef UNITTEST
#include <stdio.h>
/* XXX: Make a real set of unit tests ... */
#if 0
int main(int argc, char *argv[])
{
if (argc < 3) {
fprintf(stderr,
"Usage: %s <src> <dst>\nCopies the <src> file to the <dst> file.\n",
argv[0]);
return 1;
}
printf("Copying file %s to %s\n", argv[1], argv[2]);
return copyfile(argv[1], argv[2], 0);
}
#else
int main(void)
{
int i = 0;
char *files[] = {
"/etc/passwd", "/tmp/tok", "/tmp/tok",
"/etc/passwd", "/tmp/", "/tmp/passwd",
"/etc/passwd", "/tmp", "/tmp/passwd",
NULL
};
FILE *src, *dst;
fprintf(stderr, "\n=>Start testing copy_filep()\n");
while (files[i]) {
fprintf(stderr, "copy_filep(%s, %s)\t", files[i],
files[i + 1]);
src = fopen(files[i], "r");
dst = fopen(files[i + 1], "w");
if (copy_filep(src, dst))
perror("Failed");
if (src)
fclose(src);
if (dst)
fclose(dst);
if (fexist(files[i + 2]))
fprintf(stderr, "OK => %s\n", files[i + 2]);
remove(files[i + 2]);
i += 3;
}
printf("\n\n=>Start testing copyfile()\n");
i = 0;
while (files[i]) {
fprintf(stderr, "copyfile(%s, %s)\t", files[i], files[i + 1]);
if (!copyfile(files[i], files[i + 1], 0))
perror("Failed");
if (fexist(files[i + 2]))
fprintf(stderr, "OK => %s\n", files[i + 2]);
remove(files[i + 2]);
i += 3;
}
return 0;
}
#endif
#endif /* UNITTEST */
/**
* 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"
* End:
*/
+229
View File
@@ -0,0 +1,229 @@
/* Functions for operating on files in directories.
*
* Copyright (c) 2008-2012 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
* 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 <assert.h>
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static const char *matcher_type = NULL;
static int (*matcher_filter) (const char *file) = NULL;
static int matcher(const struct dirent *entry)
{
char *pos = strrchr(entry->d_name, '.');
if (matcher_filter && !matcher_filter(entry->d_name))
/* User matcher overrides the rest. */
return 0;
/* Skip current dir "." from list of files. */
if ((1 == strlen(entry->d_name) && entry->d_name[0] == '.') ||
(2 == strlen(entry->d_name) && !strcmp(entry->d_name, "..")))
return 0;
/* filetype == "" */
if (matcher_type[0] == 0)
return 1;
/* Entry has no "." */
if (!pos)
return 0;
return !strcmp(pos, matcher_type);
}
/**
* dir - List all files of a certain type in the given directory.
* @dir: Base directory for dir operation.
* @type: File type suffix, e.g. ".cfg".
* @filter: Optional file name filter.
* @list: Pointer to an array of file names.
* @strip: Flag, if set dir() strips the file type.
*
* This function returns a @list of files, matching the @type suffix,
* in the given directory @dir.
*
* The @list argument is a pointer to where to store the dynamically
* allocated list of file names. This list should be free'd by first
* calling free() on each file name and then on the list itself.
*
* If @filter is not %NULL it will be called for each file found. If
* @filter returns non-zero the @file argument will be included in the
* resulting @list. If @filter returns zero for given @file it will
* be discarded.
*
* If the @strip flag is set the resulting @list of files has their
* file type stripped, including the dot. So a match "config0.cfg"
* would be returned as "config0".
*
* Returns:
* Number of files in @list, zero if no matching files of @type.
*/
int dir(const char *dir, const char *type, int (*filter) (const char *file), char ***list, int strip)
{
int i, n, num = 0;
char **files;
struct dirent **namelist;
assert(list);
if (!dir)
/* Assuming current directory */
dir = ".";
if (!type)
/* Assuming all files. */
type = "";
matcher_type = type;
matcher_filter = filter;
n = scandir(dir, &namelist, matcher, alphasort);
if (n < 0) {
perror("scandir");
} else if (n > 0) {
files = (char **)malloc(n * sizeof(char *));
for (i = 0; i < n; i++) {
if (files) {
char *name = namelist[i]->d_name;
char *type = strrchr(name, '.');
if (type && strip)
*type = 0;
files[i] = strdup(name);
num++;
}
free(namelist[i]);
}
if (num)
*list = files;
}
if (namelist)
free(namelist);
return num;
}
#ifdef UNITTEST
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "otn/c.h"
#define DIR_TYPE_IMAGE ".img"
#define DIR_TYPE_SYSLOG ""
#define DIR_TYPE_CONFIG ".cfg"
#define STARTUP_CONFIG "startup-config.cfg"
int simulate_files(int creat)
{
int i;
char *files[] =
{ "config0.cfg", "config1.cfg", "config2.cfg", "config3.cfg",
"rr109.img", "rx100.img", "rx107.img", "rm957.img", "messages"
};
for (i = 0; i < ARRAY_ELEMENTS(files); i++) {
if (creat)
touch(files[i]);
else
remove(files[i]);
}
if (creat)
symlink("config2.cfg", STARTUP_CONFIG);
else
remove(STARTUP_CONFIG);
return 0;
}
static int cfg_dir_filter(const char *file)
{
/* Skip the STARTUP_CONFIG file, it is a symbolic link to the
* current startup configuration. */
return ! !strcmp(file, STARTUP_CONFIG);
}
int main(int argc, char *argv[])
{
int i, num;
char *type = DIR_TYPE_CONFIG;
char **files;
int once = 1;
int is_startup_config(const char *entry) {
static char file[80];
if (once) {
int len = readlink(STARTUP_CONFIG, file, sizeof(file));
if (len == -1)
return 0;
file[len] = 0;
once = 0; /* Only once per call to dir() */
}
//printf ("Comparing link %s with entry %s\n", file, entry);
return !strcmp(file, entry);
}
simulate_files(1);
if (argc >= 2) {
if (!strcasecmp("CONFIG", argv[1])) {
type = DIR_TYPE_CONFIG;
system("ls -l *" DIR_TYPE_CONFIG);
}
if (!strcasecmp("IMAGE", argv[1])) {
type = DIR_TYPE_IMAGE;
system("ls -l *" DIR_TYPE_IMAGE);
}
if (!strcasecmp("SYSLOG", argv[1])) {
type = DIR_TYPE_SYSLOG;
system("ls -l *");
}
}
num = dir(NULL, type, cfg_dir_filter, &files, 0);
if (num) {
for (i = 0; i < num; i++) {
printf("%s", files[i]);
if (is_startup_config(files[i]))
printf(" --> startup-config");
printf("\n");
free(files[i]);
}
free(files);
}
simulate_files(0);
return 0;
}
#endif /* UNITTEST */
/**
* Local Variables:
* compile-command: "gcc -g -DUNITTEST -o unittest dir.c"
* version-control: t
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+53
View File
@@ -0,0 +1,53 @@
/* Check if file exists
*
* Copyright (c) 2008 Claudio Matsuoka <http://helllabs.org/finit/>
*
* 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 <unistd.h>
/**
* fexist - Check if a file exists in the file system.
* @file: File to look for, with full path.
*
* Returns:
* %TRUE(1) if the file exists, otherwise %FALSE(0).
*/
int fexist(char *file)
{
if (!file) {
errno = EINVAL;
return 0; /* Doesn't exist ... */
}
if (-1 == access(file, F_OK))
return 0;
return 1;
}
/**
* Local Variables:
* version-control: t
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+51
View File
@@ -0,0 +1,51 @@
/* Check if directory exists
*
* Copyright (c) 2008 Claudio Matsuoka <http://helllabs.org/finit/>
*
* 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 <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
/**
* fexist - Check if a file exists and is a directory.
* @file: File to look for, with full path.
*
* Returns:
* %TRUE(1) if the file exists and is a directory, otherwise %FALSE(0).
*/
int fisdir(char *file)
{
struct stat sb;
if (!stat(file, &sb) && S_ISDIR(sb.st_mode))
return 1;
return 0;
}
/**
* Local Variables:
* version-control: t
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+57
View File
@@ -0,0 +1,57 @@
/* File mode bit operations
*
* Copyright (c) 2008 Claudio Matsuoka <http://helllabs.org/finit/>
*
* 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 <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
/**
* fmode - Return a file's mode bits.
* @file: File to look for, with full path.
*
* Returns:
* The mode bits or zero when @file does not exist and errno set to %ENOENT.
*/
mode_t fmode(char *file)
{
struct stat sb;
if (!file) {
errno = EINVAL;
return 0;
}
if (!stat(file, &sb))
return sb.st_mode;
return 0;
}
/**
* Local Variables:
* version-control: t
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+71
View File
@@ -0,0 +1,71 @@
/* 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>
*
* 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_LITE_H_
#define FINIT_LITE_H_
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#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);
int movefile (char *src, char *dst);
int copy_filep (FILE *src, FILE *dst);
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;
if (strlen (dir) > 0) return dir[strlen (dir) - 1] == '/';
return 0;
}
#endif /* FINIT_LITE_H_ */
/**
* Local Variables:
* version-control: t
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+289
View File
@@ -0,0 +1,289 @@
/* Micro "rsync" implementation.
*
* Copyright (c) 2011, 2012 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
* 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 <stdlib.h> /* NULL, free() */
#include <string.h> /* strlen() */
#include <strings.h> /* rindex() */
#include <stdio.h>
#include <sys/param.h> /* MAX(), isset(), setbit(), TRUE, FALSE, et consortes. :-) */
#include <sys/stat.h>
#include <sys/types.h>
#include "lite.h"
#include "../helpers.h"
static int makedir(char *buf, size_t buf_len, char *dir, char *name, mode_t mode);
static int prune(char *dst, char **new_files, int new_num);
/**
* rsync - Synchronize contents and optionally remove non-existing backups
* @src: Source directory
* @dst: Destination directory
* @delete: Prune files from @dst that no longer exist in @src.
* @filter: Optional filtering function for source directory.
*
* This is a miniature implementation of the famous rsync for local use only.
* In fact, it is not even a true rsync since it copies all files from @src
* to @dst. The @delete option is useful for creating backups, when set all
* files removed from src since last backup are pruned from the destination
* (backup) directory.
*
* The filter callback, @filter, if provided, is used to determine what files to
* include from the source directory when backing up. If a file is to be skipped
* the callback should simply return zero.
*
* Returns:
* POSIX OK(0), or non-zero with @errno set on error.
*/
int rsync(char *src, char *dst, int delete, int (*filter) (const char *file))
{
char source[256];
char dest[256];
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) {
if (errno == EEXIST)
errno = 0;
else
result++;
}
}
if (!fisdir(dst))
mkdir(dst, 0755);
if (!fisdir(src)) {
if (!fexist(src))
return 1;
copy(src, dst);
return errno;
}
/* Copy dir as well? */
if (!fisslashdir(src)) {
char *ptr = rindex(src, '/');
if (!ptr)
ptr = src;
else
ptr++;
if (makedir(dest, sizeof(dest), dst, ptr, fmode(src)))
return 1;
dst = dest;
}
num = dir(src, "", filter, &files, 0);
for (i = 0; i < num; i++) {
/* Recursively copy sub-directries */
snprintf(source, sizeof(source), "%s%s%s", src, fisslashdir(src) ? "" : "/", files[i]);
if (fisdir(source)) {
char dst2[256];
strcat(source, "/");
if (makedir (dst2, sizeof(dst2), dst, files[i], fmode(source))) {
result++;
continue;
}
rsync(source, dst2, delete, filter);
continue; /* Next file/dir in @src to copy... */
}
copy(source, dst);
}
/* We ignore any errors from the pruning, that phase albeit useful is only
* cosmetic. --Jocke 2011-03-24 */
if (delete)
prune(dst, files, num);
if (num) {
for (i = 0; i < num; i++)
free(files[i]);
free(files);
}
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)
{
snprintf(buf, buf_len, "%s%s%s/", dir, fisslashdir(dir) ? "" : "/", name);
if (mkdir(buf, mode)) {
if (EEXIST != errno)
return 1;
errno = 0;
}
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;
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) {
for (i = 0; i < num; i++) {
if (!find(files[i])) {
char *name;
size_t len = strlen(files[i]) + 2 + strlen(dst);
name = malloc(len);
if (name) {
snprintf(name, len, "%s%s%s", dst, fisslashdir(dst) ? "" : "/", files[i]);
if (remove(name))
result++;
free(name);
}
}
free(files[i]);
}
free(files);
}
return result;
}
#ifdef UNITTEST
#define BASE "/tmp/.unittest/"
#define SRC BASE "src/"
#define DST BASE "dst/"
char *files[] = {
SRC "sub1/1.tst",
SRC "sub1/2.tst",
SRC "sub1/3.tst",
SRC "sub2/4.tst",
SRC "sub2/5.tst",
SRC "sub2/6.tst",
SRC "sub3/7.tst",
SRC "sub3/8.tst",
SRC "sub3/9.tst",
NULL
};
void cleanup_test(void)
{
system("rm -rf " BASE);
}
void setup_test(void)
{
int i;
char cmd[256];
mode_t dir_modes[] = { 755, 700 };
mode_t file_modes[] = { 644, 600 };
cleanup_test();
mkdir(BASE, 0755);
mkdir(SRC, 0755);
mkdir(DST, 0755);
for (i = 0; files[i]; i++) {
snprintf(cmd, sizeof(cmd), "mkdir -m %d -p `dirname %s`",
dir_modes[i % 2], files[i]);
system(cmd);
snprintf(cmd, sizeof(cmd), "touch %s; chmod %d %s", files[i],
file_modes[i % 2], files[i]);
system(cmd);
}
}
int run_test()
{
#if 0
setup_test();
puts("Before:");
system("tree -np " BASE);
rsync(SRC, DST, 0, NULL);
puts("After:");
system("tree -np " BASE);
cleanup_test();
#endif
setup_test();
rsync(BASE "src", DST, 0, NULL);
puts("Only partial rsync of src <-- No slash!");
system("tree -np " BASE);
#if 0
cleanup_test();
setup_test();
rsync(BASE "src/sub1", BASE "dst", 0, NULL);
puts("Only partial rsync of src/sub1 <-- No slashes!!");
system("tree -np " BASE);
cleanup_test();
setup_test();
rsync(BASE "src/sub1/", DST, 0, NULL);
puts("Only partial rsync of src/sub1/");
system("tree -np " BASE);
cleanup_test();
setup_test();
rsync(BASE "src/sub1", DST, 0, NULL);
puts("Only partial rsync of src/sub1 <-- No slash!");
system("tree -np " BASE);
rsync("/etc", "/var/tmp", 0, NULL);
puts("Real life test:");
system("tree -np /var/tmp");
#endif
return 0;
}
int main(int argc, char *argv[])
{
atexit(cleanup_test);
return run_test();
}
#endif /* UNITTEST */
/**
* Local Variables:
* compile-command: "make -f rsync.mk"
* version-control: t
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+22
View File
@@ -0,0 +1,22 @@
# Unittest makefile for rsync.c
.PHONY: clean
SRC = rsync.c
OBJS = dir.o copyfile.o fexist.o fisdir.o fmode.o
UNIT = rsync.unittest
#CPPFLAGS = -DDEBUG -I../../.. -I../../include
all: build run
clean:
@rm -f $(OBJS) $(UNIT)
# This rule also forces a cleanup of built objects to not leave any object files
# lingering in the tree to interfere with cross builds.
build: clean $(OBJS)
$(CC) $(CFLAGS) $(CPPFLAGS) -o $(UNIT) -DUNITTEST $(SRC) $(OBJS)
@rm -f $(OBJS)
run:
@./$(UNIT)
+66
View File
@@ -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:
*/
+61
View File
@@ -0,0 +1,61 @@
/* $OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert 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 strlcpy
/*
* Copy src to string dst of size siz. At most siz-1 characters
* will be copied. Always NUL terminates (unless siz == 0).
* Returns strlen(src); if retval >= siz, truncation occurred.
*/
size_t
strlcpy(char *dst, const char *src, size_t siz)
{
char *d = dst;
const char *s = src;
size_t n = siz;
/* Copy as many bytes as will fit */
if (n != 0) {
while (--n != 0) {
if ((*d++ = *s++) == '\0')
break;
}
}
/* Not enough room in dst, add NUL and traverse rest of src */
if (n == 0) {
if (siz != 0)
*d = '\0'; /* NUL-terminate dst */
while (*s++)
;
}
return(s - src - 1); /* count does not include NUL */
}
#endif
/**
* Local Variables:
* version-control: t
* c-file-style: "bsd"
* End:
*/
+67
View File
@@ -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
+352
View File
@@ -0,0 +1,352 @@
/* Plugin based services architecture for finit
*
* Copyright (c) 2012 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 <dlfcn.h> /* dlopen() et al */
#include <dirent.h> /* readdir() et al */
#include <poll.h>
#include <string.h>
#include "finit.h"
#include "private.h"
#include "helpers.h"
#include "plugin.h"
#include "queue.h" /* BSD sys/queue.h API */
#include "lite.h"
#define is_io_plugin(p) ((p)->io.cb && (p)->io.fd >= 0)
static char *plugpath = NULL; /* Set by first load. */
static size_t num_fds = 0;
static struct pollfd fds[MAX_NUM_FDS];
static TAILQ_HEAD(, plugin) plugins = TAILQ_HEAD_INITIALIZER(plugins);
static void check_plugin_depends(plugin_t *plugin);
int plugin_register(plugin_t *plugin)
{
int i, inuse = 0;
if (!plugin) {
errno = EINVAL;
return 1;
}
if (!plugin->name) {
Dl_info info;
if (!dladdr(plugin, &info) || !info.dli_fname)
plugin->name = "unknown";
else
plugin->name = (char *)info.dli_fname;
}
/* Already registered? */
if (plugin_find(plugin->name)) {
_d("... %s already loaded.", plugin->name);
return 0;
}
check_plugin_depends(plugin);
if (is_io_plugin(plugin)) {
if (num_fds + 1 >= MAX_NUM_FDS) {
num_fds = MAX_NUM_SVC;
errno = ENOMEM;
return 1;
}
num_fds++;
inuse++;
}
if (plugin->svc.cb) {
svc_t *svc = svc_find(plugin->name);
if (svc) {
inuse++;
svc->cb = plugin->svc.cb;
svc->dynamic = plugin->svc.dynamic;
svc->dynamic_stop = plugin->svc.dynamic_stop;
}
}
for (i = 0; i < HOOK_MAX_NUM; i++) {
if (plugin->hook[i].cb)
inuse++;
}
if (!inuse) {
_d("No service \"%s\" loaded, and no I/O or finit hooks, skipping plugin.", basename(plugin->name));
return 1;
}
TAILQ_INSERT_TAIL(&plugins, plugin, link);
return 0;
}
int plugin_unregister(plugin_t *plugin)
{
TAILQ_REMOVE(&plugins, plugin, link);
if (plugin->svc.cb) {
svc_t *svc = svc_find(plugin->name);
if (svc) {
svc->cb = NULL;
svc->dynamic = 0;
}
}
/* XXX: Unfinished, add cleanup code here! */
return 0;
}
// _d("Comparing %s against plugin %s", str, p->name);
#define SEARCH_PLUGIN(str) \
PLUGIN_ITERATOR(p, tmp) { \
if (!strcmp(p->name, str)) \
return p; \
}
/**
* plugin_find - Find a plugin by name
* @name: With or without path, or .so extension
*
* This function uses an opporunistic search for a suitable plugin and
* returns the first match. Albeit with at least some measure of
* heuristics.
*
* First it checks for an exact match. If no match is found and @name
* starts with a slash the search ends. Otherwise a new search with the
* plugin path prepended to @name is made. Also, if @name does not end
* with .so it too is added to @name before searching.
*
* Returns:
* On success the pointer to the matching &plugin_t is returned,
* otherwise %NULL is returned.
*/
plugin_t *plugin_find(char *name)
{
plugin_t *p, *tmp;
if (!name) {
errno = EINVAL;
return NULL;
}
SEARCH_PLUGIN(name);
if (name[0] != '/') {
int noext;
char path[CMD_SIZE];
noext = strcmp(name + strlen(name) - 3, ".so");
snprintf (path, sizeof(path), "%s%s%s%s", plugpath,
fisslashdir(plugpath) ? "" : "/",
name, noext ? ".so" : "");
SEARCH_PLUGIN(path);
}
errno = ENOENT;
return NULL;
}
/* Private daemon API *******************************************************/
void plugin_run_hooks(hook_point_t no)
{
plugin_t *p, *tmp;
PLUGIN_ITERATOR(p, tmp) {
if (p->hook[no].cb) {
_d("Calling %s hook n:o %d from runloop...", basename(p->name), no);
p->hook[no].cb(p->hook[no].arg);
}
}
}
/* Generic libev I/O callback, looks up correct plugin and calls its callback */
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 == io->fd) {
_d("Calling I/O %s from runloop...", basename(p->name));
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;
}
}
}
void plugin_monitor(void)
{
int ret;
size_t i;
while ((ret = poll(fds, num_fds, 500))) {
if (-1 == ret) {
if (EINTR == errno)
continue;
_e("Failed polling I/O plugin descriptors, error %d: %s",
errno, strerror(errno));
break;
}
/* Traverse all I/O fds and run callbacks */
for (i = 0; i < num_fds; i++) {
if (fds[i].revents)
generic_io_cb(&fds[i]);
}
break;
}
}
/* Setup any I/O callbacks for plugins that use them */
static void init_plugins(void)
{
int i = 0;
plugin_t *p, *tmp;
PLUGIN_ITERATOR(p, tmp) {
if (is_io_plugin(p)) {
_d("Initializing plugin %s for I/O", basename(p->name));
fds[i].revents = 0;
fds[i].events = p->io.flags;
fds[i++].fd = p->io.fd;
}
}
}
/**
* load_one - Load one plugin
* @path: Path to finit plugins, usually %PLUGIN_PATH
* @name: Name of plugin, optionally ending in ".so"
*
* Loads a plugin from @path/@name[.so]. Note, if ".so" is missing from
* the plugin @name it is added before attempting to load.
*
* It is up to the plugin itself ot register itself as a "ctor" with the
* %PLUGIN_INIT macro so that plugin_register() is called automatically.
*
* Returns:
* POSIX OK(0) on success, non-zero otherwise.
*/
static int load_one(char *path, char *name)
{
int noext;
char plugin[CMD_SIZE];
void *handle;
if (!path || !fisdir(path) || !name) {
errno = EINVAL;
return 1;
}
/* Compose full path, with optional .so extension, to plugin */
noext = strcmp(name + strlen(name) - 3, ".so");
snprintf(plugin, sizeof(plugin), "%s/%s%s", path, name, noext ? ".so" : "");
_d("Loading plugin %s ...", basename(plugin));
handle = dlopen(plugin, RTLD_LAZY | RTLD_GLOBAL);
if (!handle) {
_e("Failed loading plugin %s: %s", plugin, dlerror());
return 1;
}
return 0;
}
/**
* check_plugin_depends - Check and load any plugins this one depends on.
* @plugin: Plugin with possible depends to check
*
* Very simple dependency resolver, should actually load the plugin of
* the correct .name, but currently loads a matching filename.
*
* Works, but only for now. A better way might be to have a try_load()
* that actually loads all plugins and checks their &plugin_t for the
* correct .name.
*/
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]);
if (plugin_find(plugin->depends[i])) {
// _d("OK plugin %s was already loaded.", plugin->depends[i]);
continue;
}
load_one(plugpath, plugin->depends[i]);
}
}
int plugin_load_all(char *path)
{
int fail = 0;
DIR *dp = opendir(path);
struct dirent *entry;
if (!dp) {
_e("Failed, cannot open plugin directory %s: %s", path, strerror(errno));
return 1;
}
plugpath = path;
while ((entry = readdir(dp))) {
if (entry->d_name[0] == '.')
continue; /* Skip . and .. directories */
// print_desc(" Loading plugin ", basename(plugin));
if (load_one(path, entry->d_name))
fail++;
// print_result(result);
}
closedir(dp);
init_plugins();
return fail;
}
/**
* Local Variables:
* version-control: t
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+124
View File
@@ -0,0 +1,124 @@
/* Plugin based services architecture for finit
*
* Copyright (c) 2012 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_PLUGIN_H_
#define FINIT_PLUGIN_H_
#include <poll.h>
#include "queue.h" /* BSD sys/queue.h API */
#include "svc.h"
#define PLUGIN_DEP_MAX 10
#define PLUGIN_IO_READ POLLIN
#define PLUGIN_IO_WRITE POLLOUT
#define PLUGIN_INIT(x) static void __attribute__ ((constructor)) x(void)
#define PLUGIN_EXIT(x) static void __attribute__ ((destructor)) x(void)
#define PLUGIN_ITERATOR(x, tmp) TAILQ_FOREACH_SAFE(x, &plugins, link, tmp)
/*
* Predefined hook points for easier plugin debugging
*/
typedef enum {
HOOK_ROOTFS_UP = 0,
HOOK_BASEFS_UP,
HOOK_NETWORK_UP,
HOOK_SYSTEM_UP,
HOOK_SVC_UP,
HOOK_SHUTDOWN,
HOOK_MAX_NUM
} hook_point_t;
/**
* plugin_t - Finit &plugin_t object
* @link: BSD sys/queue.h linked list node
* @name: Plugin name, or identifier to match against a &svc_t object
* @svc: Service callback for a loaded &svc_t object
* @hook: Hook callback definitions
* @io: I/O hook callback
*
* To setup an &svc_t object callback for a service monitor the @name
* must match the @svc_t @cmd exactly for them to "pair".
*
* A &plugin_t object may contain a service callback, several hooks
* and/or an I/O callback as well. This way all critical extensions
* to finit can fit in one single plugin, if needed.
*
* The "dynamic events" discussed in the svc callback is for external
* service plugins to implement. However, it can be anything that
* can cause a service to need to SIGHUP at runtime. E.g., acquiring
* a DHCP lease, or an interface going UP/DOWN. The event itself can
* be passed as an integer @event and any optional argument @event_arg
*
* It is up to the external service plugin to track these events and
* relay them to each @dynamic service plugins' callback. I.e., to
* all those with the dynamic flag set.
*/
typedef struct plugin {
/* BSD sys/queue.h linked list node. */
TAILQ_ENTRY(plugin) link;
/* Plugin name, defaults to basename of plugin path if unset.
* NOTE: Must be same as @cmd for service plugins! */
char *name;
/* Service callback to be called once per lap of runloop. */
struct {
int dynamic; /* Callback wants external events as well. */
int dynamic_stop; /* Callback allows dynamic events to stop. */
svc_cmd_t (*cb)(svc_t *svc, int event, void *event_arg);
} svc;
/* List of hook callbacks. */
struct {
void *arg; /* Optional argument to callback func. */
void (*cb)(void *arg);
} hook[HOOK_MAX_NUM];
/* I/O Plugin */
struct {
int fd, flags; /* 1:READ, 2:WRITE */
void *arg;
void (*cb)(void *arg, int fd, int events);
} io;
char *depends[PLUGIN_DEP_MAX]; /* List of other .name's this depends on. */
} plugin_t;
/* Public plugin API */
int plugin_register (plugin_t *plugin);
int plugin_unregister (plugin_t *plugin);
/* Helper API */
plugin_t *plugin_find (char *name);
#endif /* FINIT_PLUGIN_H_ */
/**
* Local Variables:
* version-control: t
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+37
View File
@@ -0,0 +1,37 @@
# Plugin based services architecture for finit -*-Makefile-*-
CFLAGS += -fPIC -Os
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 tty.so
DEPS = $(addprefix .,$(PLUGINS:.so=.d))
TOPDIR ?= $(shell pwd)
include ../common.mk
all: $(PLUGINS)
clean:
-@$(RM) $(PLUGINS) *.o
distclean: clean
-@$(RM) $(JUNK) $(DEPS)
install: all
@install -d $(DESTDIR)$(plugindir)
@for plugin in $(PLUGINS); do \
echo " INSTALL $(DESTDIR)$(plugindir)/$$plugin"; \
$(STRIPINST) $$plugin $(DESTDIR)$(plugindir)/$$plugin; \
done
uninstall:
-@for plugin in $(PLUGINS); do \
echo " RM $(DESTDIR)$(plugindir)/$$plugin"; \
rm $(DESTDIR)$(plugindir)/$$plugin 2>/dev/null; \
done
-@rmdir $(DESTDIR)$(plugindir) 2>/dev/null
ifneq ($(MAKECMDGOALS),clean)
-include $(DEPS)
endif
+66
View File
@@ -0,0 +1,66 @@
/* Save and restore ALSA sound settings using alsactl
*
* Copyright (c) 2012 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 "finit.h"
#include "helpers.h"
#include "plugin.h"
static void save(void *UNUSED(arg))
{
_d("Saving sound settings ...");
run_interactive("/usr/sbin/alsactl -g store", "Saving sound settings");
}
static void restore(void *UNUSED(arg))
{
_d("Restoring sound settings ...");
run_interactive("/usr/sbin/alsactl -g restore", "Restoring sound settings");
}
static plugin_t plugin = {
.hook[HOOK_BASEFS_UP] = {
.cb = restore
},
.hook[HOOK_SHUTDOWN] = {
.cb = save
}
};
PLUGIN_INIT(plugin_init)
{
plugin_register(&plugin);
}
PLUGIN_EXIT(plugin_exit)
{
plugin_unregister(&plugin);
}
/**
* Local Variables:
* version-control: t
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+110
View File
@@ -0,0 +1,110 @@
/* Setup necessary files for UTMP, tracking logins
*
* Copyright (c) 2012 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 <string.h>
#include <utmp.h>
#include "finit.h"
#include "helpers.h"
#include "plugin.h"
/*
* Setup standard FHS 2.3 structure in /var, and
* write runlevel to UTMP, needed by, e.g., printerdrake.
*/
static void setup(void *UNUSED(arg))
{
#ifdef RUNLEVEL
struct utmp entry;
#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);
_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));
entry.ut_type = RUN_LVL;
entry.ut_pid = '0' + RUNLEVEL;
setutent();
pututline(&entry);
endutent();
#endif
#ifdef TOUCH_ETC_NETWORK_RUN_IFSTATE
touch("/etc/network/run/ifstate");
#else
remove("/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 */
chown("/dev/xconsole", 0, getgroup("tty"));
}
static plugin_t plugin = {
.name = "bootmisc",
.hook[HOOK_BASEFS_UP] = {
.cb = setup
},
};
PLUGIN_INIT(plugin_init)
{
plugin_register(&plugin);
}
PLUGIN_EXIT(plugin_exit)
{
plugin_unregister(&plugin);
}
/**
* Local Variables:
* version-control: t
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+63
View File
@@ -0,0 +1,63 @@
/* Setup and start system message bus, D-Bus
*
* Copyright (c) 2012 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 "finit.h"
#include "helpers.h"
#include "plugin.h"
static void setup(void *UNUSED(arg))
{
#ifdef HAVE_DBUS
_d("Starting D-Bus ...");
mkdir("/var/run/dbus", 0755);
mkdir("/var/lock/subsys/messagebus", 0755);
run("dbus-uuidgen --ensure");
remove("/var/run/dbus/pid");
run_interactive("dbus-daemon --system", "Starting D-Bus");
#endif
}
static plugin_t plugin = {
.hook[HOOK_NETWORK_UP] = {
.cb = setup
},
.depends = { "bootmisc", },
};
PLUGIN_INIT(plugin_init)
{
plugin_register(&plugin);
}
PLUGIN_EXIT(plugin_exit)
{
plugin_unregister(&plugin);
}
/**
* Local Variables:
* version-control: t
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+67
View File
@@ -0,0 +1,67 @@
/* Save and restore RTC using hwclock
*
* Copyright (c) 2012 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 "finit.h"
#include "helpers.h"
#include "plugin.h"
static void save(void *UNUSED(arg))
{
_d("Saving system clock to RTC ...");
/* -w,--systohc, -u,--utc */
run_interactive("/sbin/hwclock -w -u", "Saving system time (UTC) to RTC");
}
static void restore(void *UNUSED(arg))
{
_d("Restoring system clock from RTC ...");
/* -s,--hctosys, -u,--utc */
run_interactive("/sbin/hwclock -s -u", "Restoring system clock (UTC) from RTC");
}
static plugin_t plugin = {
.hook[HOOK_BASEFS_UP] = {
.cb = restore
},
.hook[HOOK_SHUTDOWN] = {
.cb = save
}
};
PLUGIN_INIT(plugin_init)
{
plugin_register(&plugin);
}
PLUGIN_EXIT(plugin_exit)
{
plugin_unregister(&plugin);
}
/**
* Local Variables:
* version-control: t
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+144
View File
@@ -0,0 +1,144 @@
/* Optional /dev/initctl FIFO monitor
*
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2012 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 <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"
static void parse(void *arg, int fd, int events);
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 parse(void *UNUSED(arg), int fd, int UNUSED(events))
{
struct init_request rq;
_d("Receiving request on %s...", FINIT_FIFO);
while (1) {
ssize_t len = read(fd, &rq, sizeof(rq));
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 (rq.magic != INIT_MAGIC || len != sizeof(rq)) {
_e("Invalid initctl request.");
break;
}
_d("Magic OK...");
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", rq.runlevel);
break;
}
} else if (rq.cmd == INIT_CMD_DEBUG) {
debug = !debug;
} else {
_d("Unsupported cmd: %d", rq.cmd);
}
}
close(fd);
fifo_open();
}
PLUGIN_INIT(plugin_init)
{
_d("Setting up %s", FINIT_FIFO);
mkfifo(FINIT_FIFO, 0600);
fifo_open();
plugin_register(&plugin);
}
PLUGIN_EXIT(plugin_exit)
{
plugin_unregister(&plugin);
}
/**
* Local Variables:
* version-control: t
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+90
View File
@@ -0,0 +1,90 @@
/* Setup necessary files for resolvconf
*
* Copyright (c) 2012 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 "finit.h"
#include "helpers.h"
#include "plugin.h"
static void setup(void *UNUSED(arg))
{
#ifdef USE_ETC_RESOLVCONF_RUN
DIR *dir;
struct dirent *d;
#endif
_d("Setting up the resolver ...");
#ifdef USE_ETC_RESOLVCONF_RUN
makepath("/dev/shm/network");
makepath("/dev/shm/resolvconf/interface");
if ((dir = opendir("/etc/resolvconf/run/interface")) != NULL) {
while ((d = readdir(dir)) != NULL) {
if (isalnum(d->d_name[0]))
continue;
snprintf(line, sizeof(line),
"/etc/resolvconf/run/interface/%s", d->d_name);
unlink(line);
}
closedir(dir);
}
#endif
#ifdef USE_VAR_RUN_RESOLVCONF
makepath("/var/run/resolvconf/interface");
symlink("../../../etc/resolv.conf", "/var/run/resolvconf/resolv.conf");
#endif
#ifdef USE_ETC_RESOLVCONF_RUN
touch("/etc/resolvconf/run/enable-updates");
chdir("/etc/resolvconf/run/interface");
run_parts("/etc/resolvconf/update.d", "-i");
chdir("/");
#endif /* USE_ETC_RESOLVCONF_RUN */
}
static plugin_t plugin = {
.hook[HOOK_BASEFS_UP] = {
.cb = setup
},
.depends = { "bootmisc", },
};
PLUGIN_INIT(plugin_init)
{
plugin_register(&plugin);
}
PLUGIN_EXIT(plugin_exit)
{
plugin_unregister(&plugin);
}
/**
* Local Variables:
* version-control: t
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+94
View File
@@ -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:
*/
+66
View File
@@ -0,0 +1,66 @@
/* Setup random seed
*
* Copyright (c) 2012 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 <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "finit.h"
#include "helpers.h"
#include "plugin.h"
static void setup(void *UNUSED(arg))
{
#ifdef RANDOMSEED
copyfile(RANDOMSEED, "/dev/urandom", 0);
unlink(RANDOMSEED);
umask(077);
copyfile("/dev/urandom", RANDOMSEED, 4096);
umask(0);
#endif
}
static plugin_t plugin = {
.hook[HOOK_BASEFS_UP] = {
.cb = setup
},
.depends = { "bootmisc", }
};
PLUGIN_INIT(plugin_init)
{
plugin_register(&plugin);
}
PLUGIN_EXIT(plugin_exit)
{
plugin_unregister(&plugin);
}
/**
* Local Variables:
* version-control: t
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+78
View File
@@ -0,0 +1,78 @@
/* Console setup (for X)
*
* Copyright (c) 2012 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 <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "finit.h"
#include "helpers.h"
#include "plugin.h"
static void setup(void *UNUSED(arg))
{
#ifdef PAM_CONSOLE
int fd;
#endif
char line[LINE_SIZE];
makepath("/var/run/console");
snprintf(line, sizeof(line), "/var/run/console/%s", username);
touch(line);
#ifdef PAM_CONSOLE
if ((fd = open("/var/run/console/console.lock", O_CREAT|O_WRONLY|O_TRUNC, 0644)) >= 0) {
write(fd, username, strlen(username));
close(fd);
run("/sbin/pam_console_apply");
}
#endif
mkdir("/tmp/.X11-unix", 01777);
mkdir("/tmp/.ICE-unix", 01777);
}
static plugin_t plugin = {
.hook[HOOK_NETWORK_UP] = {
.cb = setup
},
.depends = { "bootmisc", }
};
PLUGIN_INIT(plugin_init)
{
plugin_register(&plugin);
}
PLUGIN_EXIT(plugin_exit)
{
plugin_unregister(&plugin);
}
/**
* Local Variables:
* version-control: t
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+46
View File
@@ -0,0 +1,46 @@
/* Private header file for main finit daemon, not for plugins
*
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@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
* 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_PRIVATE_H_
#define FINIT_PRIVATE_H_
#include "svc.h"
#include "plugin.h"
void svc_bootstrap (void);
void svc_monitor (void);
void plugin_run_hooks (hook_point_t no);
int plugin_load_all (char *path);
void plugin_monitor (void);
#endif /* FINIT_PRIVATE_H_ */
/**
* Local Variables:
* version-control: t
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+568
View File
@@ -0,0 +1,568 @@
/* $OpenBSD: queue.h,v 1.36 2012/04/11 13:29:14 naddy Exp $ */
/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */
/*
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)queue.h 8.5 (Berkeley) 8/20/94
*/
#ifndef _SYS_QUEUE_H_
#define _SYS_QUEUE_H_
/*
* This file defines five types of data structures: singly-linked lists,
* lists, simple queues, tail queues, and circular queues.
*
*
* A singly-linked list is headed by a single forward pointer. The elements
* are singly linked for minimum space and pointer manipulation overhead at
* the expense of O(n) removal for arbitrary elements. New elements can be
* added to the list after an existing element or at the head of the list.
* Elements being removed from the head of the list should use the explicit
* macro for this purpose for optimum efficiency. A singly-linked list may
* only be traversed in the forward direction. Singly-linked lists are ideal
* for applications with large datasets and few or no removals or for
* implementing a LIFO queue.
*
* A list is headed by a single forward pointer (or an array of forward
* pointers for a hash table header). The elements are doubly linked
* so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before
* or after an existing element or at the head of the list. A list
* may only be traversed in the forward direction.
*
* A simple queue is headed by a pair of pointers, one the head of the
* list and the other to the tail of the list. The elements are singly
* linked to save space, so elements can only be removed from the
* head of the list. New elements can be added to the list before or after
* an existing element, at the head of the list, or at the end of the
* list. A simple queue may only be traversed in the forward direction.
*
* A tail queue is headed by a pair of pointers, one to the head of the
* list and the other to the tail of the list. The elements are doubly
* linked so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before or
* after an existing element, at the head of the list, or at the end of
* the list. A tail queue may be traversed in either direction.
*
* A circle queue is headed by a pair of pointers, one to the head of the
* list and the other to the tail of the list. The elements are doubly
* linked so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before or after
* an existing element, at the head of the list, or at the end of the list.
* A circle queue may be traversed in either direction, but has a more
* complex end of list detection.
*
* For details on the use of these macros, see the queue(3) manual page.
*/
#if defined(QUEUE_MACRO_DEBUG) || (defined(_KERNEL) && defined(DIAGNOSTIC))
#define _Q_INVALIDATE(a) (a) = ((void *)-1)
#else
#define _Q_INVALIDATE(a)
#endif
/*
* Singly-linked List definitions.
*/
#define SLIST_HEAD(name, type) \
struct name { \
struct type *slh_first; /* first element */ \
}
#define SLIST_HEAD_INITIALIZER(head) \
{ NULL }
#define SLIST_ENTRY(type) \
struct { \
struct type *sle_next; /* next element */ \
}
/*
* Singly-linked List access methods.
*/
#define SLIST_FIRST(head) ((head)->slh_first)
#define SLIST_END(head) NULL
#define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head))
#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
#define SLIST_FOREACH(var, head, field) \
for((var) = SLIST_FIRST(head); \
(var) != SLIST_END(head); \
(var) = SLIST_NEXT(var, field))
#define SLIST_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = SLIST_FIRST(head); \
(var) && ((tvar) = SLIST_NEXT(var, field), 1); \
(var) = (tvar))
/*
* Singly-linked List functions.
*/
#define SLIST_INIT(head) { \
SLIST_FIRST(head) = SLIST_END(head); \
}
#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
(elm)->field.sle_next = (slistelm)->field.sle_next; \
(slistelm)->field.sle_next = (elm); \
} while (0)
#define SLIST_INSERT_HEAD(head, elm, field) do { \
(elm)->field.sle_next = (head)->slh_first; \
(head)->slh_first = (elm); \
} while (0)
#define SLIST_REMOVE_AFTER(elm, field) do { \
(elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \
} while (0)
#define SLIST_REMOVE_HEAD(head, field) do { \
(head)->slh_first = (head)->slh_first->field.sle_next; \
} while (0)
#define SLIST_REMOVE(head, elm, type, field) do { \
if ((head)->slh_first == (elm)) { \
SLIST_REMOVE_HEAD((head), field); \
} else { \
struct type *curelm = (head)->slh_first; \
\
while (curelm->field.sle_next != (elm)) \
curelm = curelm->field.sle_next; \
curelm->field.sle_next = \
curelm->field.sle_next->field.sle_next; \
_Q_INVALIDATE((elm)->field.sle_next); \
} \
} while (0)
/*
* List definitions.
*/
#define LIST_HEAD(name, type) \
struct name { \
struct type *lh_first; /* first element */ \
}
#define LIST_HEAD_INITIALIZER(head) \
{ NULL }
#define LIST_ENTRY(type) \
struct { \
struct type *le_next; /* next element */ \
struct type **le_prev; /* address of previous next element */ \
}
/*
* List access methods
*/
#define LIST_FIRST(head) ((head)->lh_first)
#define LIST_END(head) NULL
#define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head))
#define LIST_NEXT(elm, field) ((elm)->field.le_next)
#define LIST_FOREACH(var, head, field) \
for((var) = LIST_FIRST(head); \
(var)!= LIST_END(head); \
(var) = LIST_NEXT(var, field))
#define LIST_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = LIST_FIRST(head); \
(var) && ((tvar) = LIST_NEXT(var, field), 1); \
(var) = (tvar))
/*
* List functions.
*/
#define LIST_INIT(head) do { \
LIST_FIRST(head) = LIST_END(head); \
} while (0)
#define LIST_INSERT_AFTER(listelm, elm, field) do { \
if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \
(listelm)->field.le_next->field.le_prev = \
&(elm)->field.le_next; \
(listelm)->field.le_next = (elm); \
(elm)->field.le_prev = &(listelm)->field.le_next; \
} while (0)
#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
(elm)->field.le_prev = (listelm)->field.le_prev; \
(elm)->field.le_next = (listelm); \
*(listelm)->field.le_prev = (elm); \
(listelm)->field.le_prev = &(elm)->field.le_next; \
} while (0)
#define LIST_INSERT_HEAD(head, elm, field) do { \
if (((elm)->field.le_next = (head)->lh_first) != NULL) \
(head)->lh_first->field.le_prev = &(elm)->field.le_next;\
(head)->lh_first = (elm); \
(elm)->field.le_prev = &(head)->lh_first; \
} while (0)
#define LIST_REMOVE(elm, field) do { \
if ((elm)->field.le_next != NULL) \
(elm)->field.le_next->field.le_prev = \
(elm)->field.le_prev; \
*(elm)->field.le_prev = (elm)->field.le_next; \
_Q_INVALIDATE((elm)->field.le_prev); \
_Q_INVALIDATE((elm)->field.le_next); \
} while (0)
#define LIST_REPLACE(elm, elm2, field) do { \
if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \
(elm2)->field.le_next->field.le_prev = \
&(elm2)->field.le_next; \
(elm2)->field.le_prev = (elm)->field.le_prev; \
*(elm2)->field.le_prev = (elm2); \
_Q_INVALIDATE((elm)->field.le_prev); \
_Q_INVALIDATE((elm)->field.le_next); \
} while (0)
/*
* Simple queue definitions.
*/
#define SIMPLEQ_HEAD(name, type) \
struct name { \
struct type *sqh_first; /* first element */ \
struct type **sqh_last; /* addr of last next element */ \
}
#define SIMPLEQ_HEAD_INITIALIZER(head) \
{ NULL, &(head).sqh_first }
#define SIMPLEQ_ENTRY(type) \
struct { \
struct type *sqe_next; /* next element */ \
}
/*
* Simple queue access methods.
*/
#define SIMPLEQ_FIRST(head) ((head)->sqh_first)
#define SIMPLEQ_END(head) NULL
#define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head))
#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next)
#define SIMPLEQ_FOREACH(var, head, field) \
for((var) = SIMPLEQ_FIRST(head); \
(var) != SIMPLEQ_END(head); \
(var) = SIMPLEQ_NEXT(var, field))
#define SIMPLEQ_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = SIMPLEQ_FIRST(head); \
(var) && ((tvar) = SIMPLEQ_NEXT(var, field), 1); \
(var) = (tvar))
/*
* Simple queue functions.
*/
#define SIMPLEQ_INIT(head) do { \
(head)->sqh_first = NULL; \
(head)->sqh_last = &(head)->sqh_first; \
} while (0)
#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \
if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \
(head)->sqh_last = &(elm)->field.sqe_next; \
(head)->sqh_first = (elm); \
} while (0)
#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \
(elm)->field.sqe_next = NULL; \
*(head)->sqh_last = (elm); \
(head)->sqh_last = &(elm)->field.sqe_next; \
} while (0)
#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
(head)->sqh_last = &(elm)->field.sqe_next; \
(listelm)->field.sqe_next = (elm); \
} while (0)
#define SIMPLEQ_REMOVE_HEAD(head, field) do { \
if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
(head)->sqh_last = &(head)->sqh_first; \
} while (0)
#define SIMPLEQ_REMOVE_AFTER(head, elm, field) do { \
if (((elm)->field.sqe_next = (elm)->field.sqe_next->field.sqe_next) \
== NULL) \
(head)->sqh_last = &(elm)->field.sqe_next; \
} while (0)
/*
* Tail queue definitions.
*/
#define TAILQ_HEAD(name, type) \
struct name { \
struct type *tqh_first; /* first element */ \
struct type **tqh_last; /* addr of last next element */ \
}
#define TAILQ_HEAD_INITIALIZER(head) \
{ NULL, &(head).tqh_first }
#define TAILQ_ENTRY(type) \
struct { \
struct type *tqe_next; /* next element */ \
struct type **tqe_prev; /* address of previous next element */ \
}
/*
* tail queue access methods
*/
#define TAILQ_FIRST(head) ((head)->tqh_first)
#define TAILQ_END(head) NULL
#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
#define TAILQ_LAST(head, headname) \
(*(((struct headname *)((head)->tqh_last))->tqh_last))
/* XXX */
#define TAILQ_PREV(elm, headname, field) \
(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
#define TAILQ_EMPTY(head) \
(TAILQ_FIRST(head) == TAILQ_END(head))
#define TAILQ_FOREACH(var, head, field) \
for((var) = TAILQ_FIRST(head); \
(var) != TAILQ_END(head); \
(var) = TAILQ_NEXT(var, field))
#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = TAILQ_FIRST(head); \
(var) != TAILQ_END(head) && \
((tvar) = TAILQ_NEXT(var, field), 1); \
(var) = (tvar))
#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
for((var) = TAILQ_LAST(head, headname); \
(var) != TAILQ_END(head); \
(var) = TAILQ_PREV(var, headname, field))
#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \
for ((var) = TAILQ_LAST(head, headname); \
(var) != TAILQ_END(head) && \
((tvar) = TAILQ_PREV(var, headname, field), 1); \
(var) = (tvar))
/*
* Tail queue functions.
*/
#define TAILQ_INIT(head) do { \
(head)->tqh_first = NULL; \
(head)->tqh_last = &(head)->tqh_first; \
} while (0)
#define TAILQ_INSERT_HEAD(head, elm, field) do { \
if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
(head)->tqh_first->field.tqe_prev = \
&(elm)->field.tqe_next; \
else \
(head)->tqh_last = &(elm)->field.tqe_next; \
(head)->tqh_first = (elm); \
(elm)->field.tqe_prev = &(head)->tqh_first; \
} while (0)
#define TAILQ_INSERT_TAIL(head, elm, field) do { \
(elm)->field.tqe_next = NULL; \
(elm)->field.tqe_prev = (head)->tqh_last; \
*(head)->tqh_last = (elm); \
(head)->tqh_last = &(elm)->field.tqe_next; \
} while (0)
#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
(elm)->field.tqe_next->field.tqe_prev = \
&(elm)->field.tqe_next; \
else \
(head)->tqh_last = &(elm)->field.tqe_next; \
(listelm)->field.tqe_next = (elm); \
(elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
} while (0)
#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
(elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
(elm)->field.tqe_next = (listelm); \
*(listelm)->field.tqe_prev = (elm); \
(listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
} while (0)
#define TAILQ_REMOVE(head, elm, field) do { \
if (((elm)->field.tqe_next) != NULL) \
(elm)->field.tqe_next->field.tqe_prev = \
(elm)->field.tqe_prev; \
else \
(head)->tqh_last = (elm)->field.tqe_prev; \
*(elm)->field.tqe_prev = (elm)->field.tqe_next; \
_Q_INVALIDATE((elm)->field.tqe_prev); \
_Q_INVALIDATE((elm)->field.tqe_next); \
} while (0)
#define TAILQ_REPLACE(head, elm, elm2, field) do { \
if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \
(elm2)->field.tqe_next->field.tqe_prev = \
&(elm2)->field.tqe_next; \
else \
(head)->tqh_last = &(elm2)->field.tqe_next; \
(elm2)->field.tqe_prev = (elm)->field.tqe_prev; \
*(elm2)->field.tqe_prev = (elm2); \
_Q_INVALIDATE((elm)->field.tqe_prev); \
_Q_INVALIDATE((elm)->field.tqe_next); \
} while (0)
/*
* Circular queue definitions.
*/
#define CIRCLEQ_HEAD(name, type) \
struct name { \
struct type *cqh_first; /* first element */ \
struct type *cqh_last; /* last element */ \
}
#define CIRCLEQ_HEAD_INITIALIZER(head) \
{ CIRCLEQ_END(&head), CIRCLEQ_END(&head) }
#define CIRCLEQ_ENTRY(type) \
struct { \
struct type *cqe_next; /* next element */ \
struct type *cqe_prev; /* previous element */ \
}
/*
* Circular queue access methods
*/
#define CIRCLEQ_FIRST(head) ((head)->cqh_first)
#define CIRCLEQ_LAST(head) ((head)->cqh_last)
#define CIRCLEQ_END(head) ((void *)(head))
#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next)
#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev)
#define CIRCLEQ_EMPTY(head) \
(CIRCLEQ_FIRST(head) == CIRCLEQ_END(head))
#define CIRCLEQ_FOREACH(var, head, field) \
for((var) = CIRCLEQ_FIRST(head); \
(var) != CIRCLEQ_END(head); \
(var) = CIRCLEQ_NEXT(var, field))
#define CIRCLEQ_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = CIRCLEQ_FIRST(head); \
(var) != CIRCLEQ_END(head) && \
((tvar) = CIRCLEQ_NEXT(var, field), 1); \
(var) = (tvar))
#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \
for((var) = CIRCLEQ_LAST(head); \
(var) != CIRCLEQ_END(head); \
(var) = CIRCLEQ_PREV(var, field))
#define CIRCLEQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \
for ((var) = CIRCLEQ_LAST(head, headname); \
(var) != CIRCLEQ_END(head) && \
((tvar) = CIRCLEQ_PREV(var, headname, field), 1); \
(var) = (tvar))
/*
* Circular queue functions.
*/
#define CIRCLEQ_INIT(head) do { \
(head)->cqh_first = CIRCLEQ_END(head); \
(head)->cqh_last = CIRCLEQ_END(head); \
} while (0)
#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
(elm)->field.cqe_next = (listelm)->field.cqe_next; \
(elm)->field.cqe_prev = (listelm); \
if ((listelm)->field.cqe_next == CIRCLEQ_END(head)) \
(head)->cqh_last = (elm); \
else \
(listelm)->field.cqe_next->field.cqe_prev = (elm); \
(listelm)->field.cqe_next = (elm); \
} while (0)
#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \
(elm)->field.cqe_next = (listelm); \
(elm)->field.cqe_prev = (listelm)->field.cqe_prev; \
if ((listelm)->field.cqe_prev == CIRCLEQ_END(head)) \
(head)->cqh_first = (elm); \
else \
(listelm)->field.cqe_prev->field.cqe_next = (elm); \
(listelm)->field.cqe_prev = (elm); \
} while (0)
#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \
(elm)->field.cqe_next = (head)->cqh_first; \
(elm)->field.cqe_prev = CIRCLEQ_END(head); \
if ((head)->cqh_last == CIRCLEQ_END(head)) \
(head)->cqh_last = (elm); \
else \
(head)->cqh_first->field.cqe_prev = (elm); \
(head)->cqh_first = (elm); \
} while (0)
#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \
(elm)->field.cqe_next = CIRCLEQ_END(head); \
(elm)->field.cqe_prev = (head)->cqh_last; \
if ((head)->cqh_first == CIRCLEQ_END(head)) \
(head)->cqh_first = (elm); \
else \
(head)->cqh_last->field.cqe_next = (elm); \
(head)->cqh_last = (elm); \
} while (0)
#define CIRCLEQ_REMOVE(head, elm, field) do { \
if ((elm)->field.cqe_next == CIRCLEQ_END(head)) \
(head)->cqh_last = (elm)->field.cqe_prev; \
else \
(elm)->field.cqe_next->field.cqe_prev = \
(elm)->field.cqe_prev; \
if ((elm)->field.cqe_prev == CIRCLEQ_END(head)) \
(head)->cqh_first = (elm)->field.cqe_next; \
else \
(elm)->field.cqe_prev->field.cqe_next = \
(elm)->field.cqe_next; \
_Q_INVALIDATE((elm)->field.cqe_prev); \
_Q_INVALIDATE((elm)->field.cqe_next); \
} while (0)
#define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \
if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \
CIRCLEQ_END(head)) \
(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); \
else \
(elm2)->field.cqe_prev->field.cqe_next = (elm2); \
_Q_INVALIDATE((elm)->field.cqe_prev); \
_Q_INVALIDATE((elm)->field.cqe_next); \
} while (0)
#endif /* !_SYS_QUEUE_H_ */
+37
View File
@@ -0,0 +1,37 @@
/* reboot for finit
*
* Copyright (c) 2009-2012 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>
int main (void)
{
return !!kill(1, SIGINT);
}
/**
* Local Variables:
* version-control: t
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
Executable
+15
View File
@@ -0,0 +1,15 @@
#!/bin/sh
# Alternative boot method for other distributions than Debian 6.0
# Place this file in a /etc/finit.d/ directory. At boot finit will
# run all files, using its built-in run_parts(), in that directory.
#
# Here we chain load Debian /etc/rcS.d and /etc/rc2.d directories
# in sequence using the standard run-parts tool.
run-parts /etc/rcS.d --arg=start
run-parts /etc/rc2.d --arg=start
# You can also place other commands in this services file, akin to
# the old finit /usr/sbin/services.sh (not supported anymore).
#service acpid start
#service networking start
#service ssh start
+191
View File
@@ -0,0 +1,191 @@
/* 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>
*
* 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.
*
* The standard SysV init only responds to the following signals:
* SIGHUP
* Has the same effect as telinit q.
*
* SIGUSR1
* On receipt of this signals, init closes and re-opens its control
* fifo, /dev/initctl. Useful for bootscripts when /dev is remounted.
*
* SIGINT
* Normally the kernel sends this signal to init when CTRL-ALT-DEL is
* pressed. It activates the ctrlaltdel action.
*
* SIGWINCH
* The kernel sends this signal when the KeyboardSignal key is hit.
* It activates the kbrequest action.
*/
#include <sys/reboot.h>
#include <sys/wait.h>
#include "finit.h"
#include "helpers.h"
#include "plugin.h"
#include "private.h"
#include "sig.h"
static int stopped = 0;
void do_shutdown (int sig)
{
touch(SYNC_SHUTDOWN);
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);
/* Wait for WDT to timeout, should be no more than ~1 sec. */
do_sleep(2);
_d("Sending SIGKILL to remaining processes.");
kill(-1, SIGKILL);
sync();
sync();
_d("Unmounting file systems, remounting / read-only.");
run("/bin/umount -fa 2>/dev/null");
run("/bin/mount -n -o remount,ro / 2>/dev/null");
run("/sbin/swapoff -ea");
_d("%s.", sig == SIGINT || sig == SIGUSR1 ? "Rebooting" : "Halting");
if (sig == SIGINT || sig == SIGUSR1)
reboot(RB_AUTOBOOT);
reboot(RB_POWER_OFF);
}
/*
* Shut down on INT USR1 USR2
*/
static void shutdown_handler(int sig, siginfo_t *info, void *UNUSED(ctx))
{
_d("Rebooting on signal %d from %s (PID %d)",
sig, pid_get_name(info->si_pid, NULL, 0), info->si_pid);
do_shutdown(sig);
}
/*
* SIGCHLD: one of our children has died
*/
static void chld_handler(int UNUSED(sig), siginfo_t *UNUSED(info), void *UNUSED(ctx))
{
/* Do nothing, the svc_monitor() is the designated child reaper. */
}
/*
* SIGSTOP: Paused by user or netflash
*/
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++;
}
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);
}
/*
* Is SIGSTOP asserted?
*/
int sig_stopped(void)
{
return stopped;
}
/*
* Inital signal setup - ignore everything but SIGCHLD until we're capable of responding
*/
void sig_init(void)
{
int i;
struct sigaction sa;
for (i = 1; i < NSIG; i++)
IGNSIG(sa, i, SA_RESTART);
SETSIG(sa, SIGCHLD, chld_handler, SA_RESTART);
}
/*
* Setup limited set of SysV compatible signals to respond to
*/
void sig_setup(void)
{
struct sigaction sa;
_d("Setup signals");
/* Cleanup any stale finit control files */
remove(SYNC_SHUTDOWN);
remove(SYNC_STOPPED);
/* Standard SysV init calls ctrl-alt-delete handler */
SETSIG(sa, SIGINT, shutdown_handler, 0);
SETSIG(sa, SIGPWR, shutdown_handler, 0);
/* Ignore SIGUSR1/2 for now, only BusyBox init implements them as reboot+halt. */
// SETSIG2(sa, SIGUSR1, reopen_initctl, 0);
// SETSIG2(sa, SIGUSR2, pwrdwn_handler, 0);
/* Init must ignore SIGTERM. May otherwise get false SIGTERM in forked children! */
IGNSIG(sa, SIGTERM, 0);
/* Some C APIs may need SIGALRM for implementing timers. */
IGNSIG(sa, SIGALRM, 0);
/* We don't have any /etc/inittab yet, reread finit.conf? */
IGNSIG(sa, SIGHUP, 0);
/* Stopping init is a bit tricky. */
SETSIG(sa, SIGSTOP, sigstop_handler, 0);
SETSIG(sa, SIGTSTP, sigstop_handler, 0);
SETSIG(sa, SIGCONT, sigcont_handler, 0);
/* Disable CTRL-ALT-DELETE from kernel, we handle shutdown gracefully with SIGINT, above */
reboot(RB_DISABLE_CAD);
setsid();
}
/**
* Local Variables:
* version-control: t
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+70
View File
@@ -0,0 +1,70 @@
/* 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>
*
* 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_SIG_H_
#define FINIT_SIG_H_
#include <signal.h>
#define SYNC_SHUTDOWN "/var/lock/finit.shutdown"
#define SYNC_STOPPED "/var/lock/finit.stopped"
#define SETSIG(sa, sig, fun, flags) \
do { \
sa.sa_sigaction = fun; \
sa.sa_flags = SA_SIGINFO | flags; \
sigemptyset(&sa.sa_mask); \
sigaction(sig, &sa, NULL); \
} while (0)
#define IGNSIG(sa, sig, flags) \
do { \
sa.sa_handler = SIG_IGN; \
sa.sa_flags = flags; \
sigemptyset(&sa.sa_mask); \
sigaction(sig, &sa, NULL); \
} while (0)
#define DFLSIG(sa, sig, flags) \
do { \
sa.sa_handler = SIG_DFL; \
sa.sa_flags = flags; \
sigemptyset(&sa.sa_mask); \
sigaction(sig, &sa, NULL); \
} while (0)
void do_shutdown (int sig);
int sig_stopped (void);
void sig_init (void);
void sig_setup (void);
#endif /* FINIT_SIG_H_ */
/**
* Local Variables:
* version-control: t
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+565
View File
@@ -0,0 +1,565 @@
/* Finit service monitor, task starter and generic API for managing svc_t
*
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@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
* 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 <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 svc_counter = 0; /* Number of registered services to monitor. */
static svc_t *services = NULL; /* List of registered services, in shared memory. */
/* Connect to/create shared memory area of registered servies */
static void __connect_shm(void)
{
if (!services) {
services = finit_svc_connect();
if (!services) {
/* This should never happen, but if it does we're probably
* knee-deep in more serious problems already... */
_e("Failed allocating shared memory, error %d: %s", errno, strerror (errno));
abort();
}
}
}
/**
* svc_new - Create a new service object
*
* Returns:
* A pointer to an empty &svc_t object, or %NULL if out of empty slots.
*/
svc_t *svc_new(void)
{
svc_t *svc = NULL;
__connect_shm();
if (svc_counter < MAX_NUM_SVC) {
svc = &services[svc_counter++];
memset(svc, 0, sizeof(*svc));
} else {
errno = ENOMEM;
return NULL;
}
return svc;
}
/**
* svc_find - Find a service object by its full path name
* @name: Full path name, e.g., /sbin/syslogd
*
* Returns:
* A pointer to an &svc_t object, or %NULL if not found.
*/
svc_t *svc_find(char *name)
{
int i;
__connect_shm();
for (i = 0; i < svc_counter; i++) {
svc_t *svc = &services[i];
if (!strncmp(name, svc->cmd, strlen(svc->cmd))) {
_d("Found a matching svc for %s", name);
return svc;
}
}
return NULL;
}
/**
* svc_iterator - Iterates over all registered services.
* @restart: Get first &svc_t object by setting @restart
*
* Returns:
* The first &svc_t when @restart is set, otherwise the next &svc_t until
* the end when %NULL is returned.
*/
svc_t *svc_iterator(int restart)
{
static int i = 0;
__connect_shm();
if (restart)
i = 0;
if (i >= svc_counter)
return NULL;
return &services[i++];
}
/**
* 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;
svc_cmd_t cmd;
_d("Bootstrapping all services in runlevel S from %s", FINIT_CONF);
for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
cmd = svc_enabled(svc, 0, NULL);
if (SVC_START == cmd || (SVC_RELOAD == cmd))
svc_start(svc);
}
}
static void utmp_save(int pre, int now)
{
struct utmp utent;
int encode(int lvl)
{
if (!lvl) return 0;
return lvl + '0';
}
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_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
remove("/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
*
* 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.
*
* The @line can optionally start with a username, denoted by an @
* character. Like this:
*
* "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(int type, char *line, char *username)
{
int i = 0;
char *cmd, *desc, *runlevels = NULL;
svc_t *svc;
if (!line) {
_e("Invalid input argument.");
return errno = EINVAL;
}
desc = strstr(line, "-- ");
if (desc)
*desc = 0;
cmd = strtok(line, " ");
if (!cmd) {
incomplete:
_e("Incomplete service, cannot register.");
return errno = ENOENT;
}
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, " ");
if (!cmd)
goto incomplete;
}
svc = svc_new();
if (!svc) {
_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]));
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;
}
/**
* svc_enabled - Should the service run?
* @svc: Pointer to &svc_t object
* @event: Dynamic event, opaque flag passed to callback
* @arg: Event argument, used only by external service plugins.
*
* This method calls an associated service callback, if registered by a
* plugin, and returns the &svc_cmd_t status. If no plugin is registered
* the service is statically enabled in /etc/finit.conf and the result
* will always be %SVC_START.
*
* Returns:
* Either one of %SVC_START, %SVC_STOP, %SVC_RELOAD.
*/
svc_cmd_t svc_enabled(svc_t *svc, int event, void *arg)
{
if (!svc) {
errno = EINVAL;
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);
/* No service plugin, default to start, since listed in finit.conf */
return SVC_START;
}
static int is_norespawn(void)
{
return sig_stopped() ||
fexist("/mnt/norespawn") ||
fexist("/tmp/norespawn");
}
void svc_monitor(void)
{
pid_t lost;
svc_t *svc;
lost = waitpid(-1, NULL, WNOHANG);
if (lost < 1)
return;
if (fexist(SYNC_SHUTDOWN) || lost <= 1)
return;
/* Power user at the console, don't respawn tasks. */
if (is_norespawn())
return;
if (tty_respawn(lost))
return;
for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
if (lost != svc->pid)
continue;
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", basename(svc->cmd));
procname_kill(basename(svc->cmd), SIGTERM);
/* Restarting lost service. */
if (svc_enabled(svc, 0, NULL)) {
svc->restart_counter++;
svc_start(svc);
}
break;
}
}
/* Remember: svc_enabled() must be called before calling svc_start() */
int svc_start(svc_t *svc)
{
int respawn = svc->pid != 0;
pid_t pid;
sigset_t nmask, omask;
char *args[MAX_NUM_SVC_ARGS];
if (!svc)
return 0;
/* Don't try and start service if it doesn't exist. */
if (!fexist(svc->cmd)) {
char msg[80];
snprintf(msg, sizeof(msg), "Service %s does not exist!", svc->cmd);
print_desc("", msg);
print_result(1);
return 0;
}
/* Ignore if finit is SIGSTOP'ed */
if (is_norespawn())
return 0;
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);
pid = fork();
sigprocmask(SIG_SETMASK, &omask, NULL);
if (pid == 0) {
int i = 0;
int uid = getuser(svc->username);
struct sigaction sa;
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++)
DFLSIG(sa, i, 0);
/* Set desired user */
if (uid >= 0)
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++)
args[i] = svc->args[i];
args[i] = NULL;
if (debug) {
int fd;
char buf[CMD_SIZE] = "";
fd = open(CONSOLE, O_WRONLY | O_APPEND);
if (-1 != fd) {
dup2(STDOUT_FILENO, fd);
dup2(STDERR_FILENO, fd);
}
for (i = 0; args[i] && i < MAX_NUM_SVC_ARGS; i++) {
char arg[MAX_ARG_LEN];
snprintf(arg, sizeof(arg), "%s ", args[i]);
if (strlen(arg) < (sizeof(buf) - strlen(buf)))
strcat(buf, arg);
}
_e("%starting %s: %s", respawn ? "Res" : "S", svc->cmd, buf);
}
/* XXX: Maybe change to use execve() to be able to launch scripts? */
execv(svc->cmd, args);
/* Only reach this point if exec() fails. */
exit(0);
}
svc->pid = pid;
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;
}
int svc_start_by_name(char *name)
{
svc_t *svc = svc_find(name);
if (svc && svc_enabled(svc, 0, NULL))
return svc_start(svc);
return 1;
}
int svc_stop(svc_t *svc)
{
int res = 1;
if (!svc) {
_e("Failed, no svc pointer.");
return 1;
}
if (svc->pid <= 1) {
_d("Bad PID %d for %s, SIGTERM", svc->pid, svc->desc);
svc->pid = 0;
svc->restart_counter = 0;
return 1;
}
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);
if (runlevel != 1)
print_result(res);
svc->pid = 0;
svc->restart_counter = 0;
return res;
}
int svc_reload(svc_t *svc)
{
/* Ignore if finit is SIGSTOP'ed */
if (is_norespawn())
return 0;
if (!svc) {
_e("Failed, no svc pointer.");
return 1;
}
if (svc->pid <= 1) {
_d("Bad PID %d for %s, SIGHUP", svc->pid, svc->cmd);
svc->pid = 0;
return 1;
}
_d("Sending SIGHUP to PID %d", svc->pid);
return kill(svc->pid, SIGHUP);
}
/**
* Local Variables:
* compile-command: "gcc -g -DUNITTEST -o unittest svc.c"
* version-control: t
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+116
View File
@@ -0,0 +1,116 @@
/* 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>
*
* 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_SVC_H_
#define FINIT_SVC_H_
#include <errno.h>
#include <string.h> /* strerror() */
#include <sys/shm.h> /* shmat() */
#include <sys/types.h> /* pid_t */
typedef enum {
SVC_STOP = 0, /* Disabled */
SVC_START, /* Enabled */
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
#define MAX_USER_LEN 16
#define MAX_NUM_FDS 64 /* Max number of I/O plugins */
#define MAX_NUM_SVC 64 /* Enough? */
#define MAX_NUM_SVC_ARGS 16
/* Default enable for all services, can be stopped by means
* of issuing an initctl call. E.g.
* 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];
/* For external plugins. If @cb is set a plugin is loaded.
* @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".
*/
int dynamic;
int dynamic_stop;
int private;
svc_cmd_t (*cb)(struct svc *svc, int event, void *event_arg);
} svc_t;
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);
if ((void *)-1 == ptr)
return NULL;
}
return (svc_t *)ptr;
}
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 (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);
#endif /* FINIT_SVC_H_ */
/**
* Local Variables:
* version-control: t
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+211
View File
@@ -0,0 +1,211 @@
/* 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;
}
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 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
#error No GETTY defined!
#endif
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:
*/
+65
View File
@@ -0,0 +1,65 @@
/* 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);
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:
*/