Compare commits

..
147 Commits
Author SHA1 Message Date
Joachim Nilsson 9b361864fa Fix make dist target for v1.11 release.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-01-24 16:16:13 +01:00
Joachim Nilsson 41b0dc41a6 Update ChangeLog for v1.11 release.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-01-24 16:13:46 +01:00
Joachim Nilsson cab339c857 Simplify build example.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-01-24 16:07:55 +01:00
Joachim Nilsson dcb42602c9 Cleanup README for release.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-01-24 16:04:54 +01:00
Joachim Nilsson 9e446557b4 Change Coverity Scan branch to use 'dev' instead of master.
We don't want to run out of scan tokens for every README update.  This
also means the introduction of a new workflow.  All new development must
be staged to the dev branch before being merged to master.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-01-24 15:29:16 +01:00
Joachim Nilsson a3d76c58a4 Expand on how plugins can interact with system bootstrap.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-01-21 19:34:01 +01:00
Joachim Nilsson e0e0581d10 Trim slogan ...
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-01-21 13:29:35 +01:00
Joachim Nilsson ef75d5ec31 Cleanup Introduction and add Bootstrap section.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-01-21 13:25:24 +01:00
Joachim Nilsson dfeabd8bae Improve inetd syntax proposal
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-01-21 13:15:16 +01:00
Joachim Nilsson 7aa687bad9 Reindent to more 'pure' Markdown and remove fixed event lib TODO.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-01-19 21:24:06 +01:00
Joachim Nilsson c2ea2c1193 Reindent to more 'pure' Markdown.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-01-19 21:12:14 +01:00
Joachim Nilsson 291b22e987 Give up and add actual link to GIT commit.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-01-18 23:46:21 +01:00
Joachim Nilsson a091b69dd6 Another try ...
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-01-18 23:45:16 +01:00
Joachim Nilsson 887c84a0d1 Attempt to fix GIT commit auto linking.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-01-18 23:44:27 +01:00
Joachim Nilsson 5009d54ab8 Reindent to more 'pure' Markdown.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-01-18 23:43:04 +01:00
Joachim Nilsson 840ade6da7 Bump version for next release, fix make dist and rename NEWS --> CHANGELOG
- Bump version for coming 1.11 release
- Update `make dist` to use Kentzo's `git-archive-all` from
  https://github.com/Kentzo/git-archive-all
- Rename NEWS --> CHANGELOG and update for coming release
- Update CHANGELOG with info on the libuEv migration

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-01-18 23:22:39 +01:00
Joachim Nilsson 030aa70842 Simplify.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-01-18 22:29:34 +01:00
Joachim Nilsson dea3ae857b Steal controlling TTY on fallback console to enable job control.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-01-18 22:25:04 +01:00
Joachim Nilsson 9f5172b0d1 Try removing delayed start of TTYs, should not be needed anymore.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-01-18 21:40:09 +01:00
Joachim Nilsson e0529a5597 Unblock all signals blocked by finit when starting children
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-01-18 21:40:05 +01:00
Joachim Nilsson 425cd17e57 Initial conversion to use libuEv for all event handling.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-01-18 00:53:14 +01:00
Joachim Nilsson 0669a9cb81 Fix missing #include for copyfile()
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-01-18 00:46:06 +01:00
Joachim Nilsson 5e040449c4 Add libuEv as submodule for event handling.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-01-07 02:59:21 +01:00
Joachim Nilsson 074686b520 Use vfork() instead of fork() before exec()
If running on older Linux systems, or any BSD UNIX, vfork()
is more efficient when we are about to call exec() anyway.

For more info on vfork() vs fork(), see Stack Exchange:
http://stackoverflow.com/questions/4259629/what-is-the-difference-between-fork-and-vfork

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-01-06 23:38:47 +01:00
Joachim Nilsson d40f52357e Restructure and add section on Watchdog process supervision
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-01-06 21:45:14 +01:00
Joachim Nilsson 076f77a31b Update TODO: more on inetd and at support.
Also a minor fix to the README.

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

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

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

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

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

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

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

Also, minor whitespace and coding style cleanup.

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

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-04-12 14:31:31 +02:00
Joachim Nilsson 7cd52b36a1 Always print service start/stop at start of line
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-04-12 14:30:34 +02:00
Joachim Nilsson b033052647 TODO: Further simplify example inetd syntax.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-04-10 10:34:06 +02:00
Joachim Nilsson 4fcf2533a6 Minor indentation fix to TODO.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-04-10 10:29:06 +02:00
Joachim Nilsson a8a103a521 Update TODO with inetd proposal, and minor README cleanup.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-04-10 10:26:46 +02:00
Joachim Nilsson 12b09bb80b Improve CI status integration in README and minor cleanup.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-02-25 09:23:16 +01:00
Joachim Nilsson 49aaffcf9a Update README with CI status. 2014-02-25 00:00:43 +01:00
Joachim Nilsson afbe628f17 Travis CI integration
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-02-24 23:46:28 +01:00
Joachim Nilsson 1d6cbe31fe Initial support for restarting lost processes during norespawn
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-02-24 23:33:38 +01:00
Jonas Johansson cb874d7a94 Handle SIGHUP requst from service when switching runlevel
Signed-off-by: Jonas Johansson <jonasj76@gmail.com>
2014-02-24 23:33:38 +01:00
Joachim Nilsson d7598ca672 Update URL of example to new download FTP. 2013-06-08 15:37:31 +02:00
Joachim Nilsson ff8e494abd Update README with a slightly more clear and catchy intro. 2013-06-08 14:49:28 +02:00
Joachim Nilsson dfaa6dd3f8 Minor ReST syntax fix for improved display in GitHub
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-06-08 11:23:24 +02:00
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
50 changed files with 3322 additions and 999 deletions
+3
View File
@@ -0,0 +1,3 @@
[submodule "libuev"]
path = libuev
url = https://github.com/troglobit/libuev.git
+21
View File
@@ -0,0 +1,21 @@
# Travis CI integration -- https://travis-ci.org/troglobit/finit
language: c
compiler:
- gcc
env:
global:
# The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
# via the "travis encrypt" command using the project repo's public key
- secure: "eOiuHs02lG2Uv146K9dMqucGTWUJFEhpz1oAtwe+kPrRXsXWc20hYMO+DSpMgD05vSvNeQA6p7h7LdRFQ+/g/Obj27TsOE+RKkUvRAtdwzxnKVyii9C/nmML8cFw7rIA0VS8O9mAkVYeyDxNDupBp3e9DPCibhKPvqCvioTnyy4="
addons:
coverity_scan:
project:
name: "troglobit/finit"
description: "finit | Fast & Extensible init for Linux"
notification_email: troglobit@gmail.com
build_command: "make"
branch_pattern: dev
script: make
Symlink
+1
View File
@@ -0,0 +1 @@
CHANGELOG.md
+278
View File
@@ -0,0 +1,278 @@
Change Log
==========
All notable changes to the project are documented in this file.
[1.11] - 2015-01-24
-------------------
The [libuEv] release.
### Changes
* Now using the asynchronous libuEv library for handling all events:
signals, timers and listening to sockets or file descriptors.
* Rename NEWS.md --> CHANGELOG.md, with symlinks for `make install`
* Attempt to align with http://keepachangelog.com/ for this file.
* Travis CI now only invokes Coverity Scan from the 'dev' branch. This
means that all development, except documentation updates, must go into
that branch.
### Fixes
* Fix bug with finit dying when no `tty` is defined in `finit.conf`, now
even the fallback shell has control over its TTY, see fix in GIT
commit [dea3ae8] for this.
[1.10] - 2014-11-27
-------------------
Major bug fix release.
### Changes
* Project now relies on static code analysis from Coverity, so this
release contains many serious bug fixes.
* Convert to use Markdown for README, NEWS and TODO.
* Serious update to README and slight pruning of finished TODO items.
### Fixes
* Fix serious file descriptor and memory leaks in the following
functions. In particular the leaks in `run_interactive()` are very
serious since that function is called every time a service is started
and/or restarted! For details, see the GIT log:
* `helpers.c:run()`
* `helpers.c:run_interactive()`
* `helpers.c:set_hostname()`
* `helpers.c:procname_kill()`
* `svc.c:svc_start()`: Fix swapped arguments to dup2() and add close(fd)
to prevent descriptor leak.
* `svc.c:svc_start()`: Fix out of bounds write to local stack variable,
wrote off-by-one outside array.
* Several added checks for return values to `mknod()`, `mkdir()`,
`remove()`, etc.
[1.9] - 2014-04-21
------------------
### Changes
* Add support for an include directive to `.conf` files
* Fallback to `/bin/sh` if user forgets tty setting
* Initial support for restarting lost services during `norespwan`
### Fixes
* Bug fixes, code cleanup
* Handle `SIGHUP` from service callback properly when switching runlevel
* Misc. major (memleak) and minor fixes and additions to `libite/lite.h`
[1.8] - 2013-06-07
------------------
### Changes
* 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
### Fixes
* Bugfixes to libite
[1.7] - 2012-10-08
------------------
### Changes
* 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.
* Only clear screen when in verbose mode. Maybe this should be removed
altogether?
### Fixes
* Bugfix: Do not `free()` static string in `finit.conf` parser
[1.6] - 2012-10-06
------------------
### Changes
* Skip `.` and `..` in plugin loader and display error when failing to
load 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`
### Fixes
* Minor fix to alsa-utils plugin to silence on non-existing cards
[1.5] - 2012-10-03
------------------
### Changes
* 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
------------------
### Changes
* 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.
### Fixes
* Fix I/O plugin watcher and load plugins earlier for a new hook
[1.3] - 2012-09-28
------------------
### Changes
* 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
------------------
### Changes
* Update README with section on building and enviroment variables
### Fixes
* Fix installation paths encoded in finit binary
[1.1] - 2012-09-27
------------------
### Changes
* Rename signal.[ch]-->sig.[ch] to avoid name clash w/ system headers
### Fixes
* Build fixes for ARM eabi/uClibc
[1.0] - 2012-09-26
------------------
### Changes
* 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)
[0.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
[libuEv]: https://github.com/troglobit/libuev
[dea3ae8]: https://github.com/troglobit/finit/commit/dea3ae8
[1.11]: https://github.com/troglobit/finit/compare/1.10...HEAD
[1.10]: https://github.com/troglobit/finit/compare/1.9...1.10
[1.9]: https://github.com/troglobit/finit/compare/1.8...1.9
[1.8]: https://github.com/troglobit/finit/compare/1.7...1.8
[1.7]: https://github.com/troglobit/finit/compare/1.6...1.7
[1.6]: https://github.com/troglobit/finit/compare/1.5...1.6
[1.5]: https://github.com/troglobit/finit/compare/1.4...1.5
[1.4]: https://github.com/troglobit/finit/compare/1.3...1.4
[1.3]: https://github.com/troglobit/finit/compare/1.2...1.3
[1.2]: https://github.com/troglobit/finit/compare/1.1...1.2
[1.1]: https://github.com/troglobit/finit/compare/1.0...1.1
[1.0]: https://github.com/troglobit/finit/compare/0.9...1.0
[0.9]: https://github.com/troglobit/finit/compare/0.8...0.9
[0.8]: https://github.com/troglobit/finit/compare/0.7...0.8
[0.7]: https://github.com/troglobit/finit/compare/0.6...0.7
[0.6]: https://github.com/troglobit/finit/compare/0.5...0.6
[0.5]: https://github.com/troglobit/finit/compare/0.4...0.5
[0.4]: https://github.com/troglobit/finit/compare/0.3...0.4
[0.3]: https://github.com/troglobit/finit/compare/0.2...0.3
[0.2]: https://github.com/troglobit/finit/compare/0.1...0.2
-103
View File
@@ -1,103 +0,0 @@
1.6 (20121006)
- Skip . and .. in plugin loader and display error on failed plugins
- Support for overriding /etc/finit.d with "runparts DIR" in finit.conf
- Revoke support for starting services not starting with a slash.
- Prevent endless restart of non-existing services in finit.conf
- Support for sysvinit style startstop scripts in /etc/finit.d
- Minor fix to alsa-utils plugin to silence on non-existing cards
1.5 (20121003)
- Use bootmisc plugin to setup standard FHS 2.3 structure in /var
- Added FLOG_WARN() syslog macro, for plugins
- Add plugin dependency resolver. Checks plugin_t for .depends
1.4 (20121002)
- Fix I/O plugin watcher and load plugins earlier for a new hook
- Start refactoring helpers.c into a libite.so (-lite). This
means other user space applications/daemons can make use of
the neat toolbox available in finit
- Use short-form -s/-w -u to work with BusyBox hwclock as well
- Use RTLD_GLOBAL flag to tell dynamic loader to load dependent
.so files as well. Lets other plugins use global symbols.
- Greatly simplify svc hook for external plugins and cleanup
the plugin API.
- And more... see the GIT log for more details.
1.3 (20120928)
- Cleanup public plugin API a bit and add new pid/pidfile funcs
- Add plugin hook to end of service startup
- Remove finit.h from svc.h, plugins should not need this.
- Move utility macros etc. to helpers.h
- Make finit.h daemon internal, only
- Move defines of FIFO, conf and rcS.d to Makefile => correct paths
- Add support for installing required headers in system include dir
- Better support for distributions and packagers with install-exec,
install-data, and install-dev targets in Makefile. Useful if you
want to call targets with different $DESTDIR!
- Makefile fixes for installation, paths encoded wrong
- Strip binaries + .so files, support for $(CROSS) toolchain strip
- Default install is now to /sbin/finit and /usr/
- Note change in $PLUGIN_DIR environemnt variable to $plugindir
1.2 (20120927)
- Fix installation paths encoded in finit binary
- Update README with section on building and enviroment variables
1.1 (20120927)
- Build fixes for ARM eabi/uClibc
- Rename signal.[ch]-->sig.[ch] to avoid name clash w/ system headers
1.0 (20120926)
- New plugin based system for all odd extensions
- New service monitor that restarts services if they die
- New maintainer at GitHub http://github.com/troglobit/finit
- Add standard LICENSE and AUTHORS files
- New focus: embedded systems and small headless servers
0.6 (20100614)
- don't start consolekit manually, dbus starts it (rtp)
- unmount all filesystems before rebooting
- disable USE_VAR_RUN_RESOLVCONF for Mandriva
- unset terminal type in Mandriva before running X
- remove extra sleep in finit-alt before calling services.sh (caio)
0.5 (20080821)
- add option to start dbus and consolekit before the X server
- finit-alt listens to /dev/initctl to work with reboot(8) (smurfy)
- write runlevel to utmp, needed by Printerdrake (Pascal Terjan)
- fix ownership of /var/run/utmp (reported by Pascal Terjan)
- remove obsolete code to load AGP drivers
- conditional build of /etc/resolveconf/run support
- add support to /var/run/resolvconf in Mandriva (blino)
O.4 (20080516)
- default username for finit-alt configurable in Makefile
- create loopback device node in finit-alt (for squashfs)
- add option to use built-in run-parts instead of /bin/run-parts
- ignore signal instead of setting to an empty handler (Metalshark)
- handle pam_console permissions in finit-alt for Mandriva
- add services.sh example and nash-hotplug patch for Mandriva
- mount /proc/bus/usb in Mandriva
- add runtime debug to finit-alt if finit_debug parameter is specified
- read configuration from /etc/finit.conf
- run getty with openvt on the virtual terminal
0.3 (20080223)
- Change poweroff method to reboot(RB_POWER_OFF) (Metalshark)
- Remove duplicate unionctl() reimplementation error
- Fix string termination in path creation
- Mount /var/lock and /var/run as tmpfs
0.2 (20080219)
- replace system("touch") with touch() in finit-mod (Metalshark)
- disable NO_HCTOSYS by default to match stock Eeepc kernel
- drop system("rm -f") to clean /tmp, its a fresh mounted tmpfs
- write ACPI sleep state to /sys/power/state instead of
/proc/acpi/sleep (Metalshark)
- use direct calls to set loopback instead of system("ifconfig")
- replace system("cat") and system("dd") with C implementation
- moved finit-mod and finit-alt helpers to helpers.c
- replace system("echo;cat") to draw shutdown splash with C calls
0.1 (20080214)
- initial release
+1 -1
View File
@@ -1,5 +1,5 @@
Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
Copyright (c) 2008-2012 Joachim Nilsson <troglobit@gmail.com>
Copyright (c) 2008-2014 Joachim Nilsson <troglobit@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
+35 -23
View File
@@ -1,7 +1,7 @@
# Finit - Extremely fast /sbin/init replacement w/ I/O, hook & service plugins
#
# Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
# Copyright (c) 2008-2012 Joachim Nilsson <troglobit@gmail.com>
# Copyright (c) 2008-2014 Joachim Nilsson <troglobit@gmail.com>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -25,24 +25,23 @@
install-exec install-data install-dev \
uninstall-exec uninstall-data uninstall-dev
# Top directory for building complete system, fall back to this directory
ROOTDIR = $(shell pwd)
#VERSION ?= $(shell git tag -l | tail -1)
VERSION ?= 1.6
VERSION ?= 1.11
NAME = finit
PKG = $(NAME)-$(VERSION)
DEV = $(NAME)-dev
ARCHIVE = $(PKG).tar.xz
ARCHTOOL = `which git-archive-all`
ARCHIVE = $(PKG).tar
ARCHIVEZ = ../$(ARCHIVE).xz
EXEC = finit reboot
HEADERS = plugin.h svc.h helpers.h queue.h
DISTFILES = LICENSE README ChangeLog finit.conf services
OBJS = finit.o conf.o helpers.o sig.o svc.o plugin.o
OBJS += strlcpy.o
DISTFILES = LICENSE README CHANGELOG finit.conf services
OBJS = finit.o conf.o helpers.o sig.o svc.o plugin.o tty.o
SRCS = $(OBJS:.o=.c)
DEPS = $(addprefix .,$(SRCS:.c=.d))
# Installation paths, always prepended with DESTDIR if set
TOPDIR = $(shell pwd)
prefix ?= /usr
sysconfdir ?= /etc
sbindir ?= /sbin
@@ -60,22 +59,24 @@ FINIT_RCSD ?= $(sysconfdir)/finit.d
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 += -Ilibite -Ilibuev
CPPFLAGS += -D_XOPEN_SOURCE=600 -D_BSD_SOURCE -D_GNU_SOURCE
CPPFLAGS += -DVERSION=\"$(VERSION)\" -DWHOAMI=\"`whoami`@`hostname`\"
CPPFLAGS += -DFINIT_FIFO=\"$(FINIT_FIFO)\" -DFINIT_CONF=\"$(FINIT_CONF)\"
CPPFLAGS += -DFINIT_RCSD=\"$(FINIT_RCSD)\" -DPLUGIN_PATH=\"$(plugindir)\"
LDFLAGS += -rdynamic -L$(ROOTDIR)/libite
DEPLIBS = libite/libite.so
LDFLAGS += -rdynamic -L$(TOPDIR)/libite
DEPLIBS = libite/libite.so libuev/libuev.a
LDLIBS += -ldl -lite
include common.mk
export libdir plugindir incdir ROOTDIR CPPFLAGS LDFLAGS LDLIBS
all: $(DEPLIBS) $(EXEC)
$(MAKE) -C plugins $@
+$(MAKE) -C plugins $@
$(DEPLIBS): Makefile
$(MAKE) -C libite all
+$(MAKE) -C libite all
+$(MAKE) -C libuev all
$(OBJS): Makefile
@@ -136,18 +137,32 @@ uninstall: uninstall-exec uninstall-data uninstall-dev
clean:
-@$(RM) $(OBJS) $(DEPS) $(EXEC)
$(MAKE) -C libite $@
$(MAKE) -C plugins $@
+$(MAKE) -C plugins $@
+$(MAKE) -C libite $@
+$(MAKE) -C libuev $@
distclean: clean
-@$(RM) $(JUNK) unittest *.o .*.d
$(MAKE) -C libite $@
$(MAKE) -C plugins $@
+$(MAKE) -C plugins $@
+$(MAKE) -C libite $@
+$(MAKE) -C libuev $@
check:
$(CHECK) *.c plugins/*.c libite/*.c
dist:
@if [ x"$(ARCHTOOL)" = x"" ]; then \
echo "Missing git-archive-all from https://github.com/Kentzo/git-archive-all"; \
exit 1; \
fi
@if [ -e $(ARCHIVEZ) ]; then \
echo "Distribution already exists."; \
exit 1; \
fi
@echo "Building xz tarball of $(PKG) in parent dir..."
git archive --format=tar --prefix=$(PKG)/ $(VERSION) | xz >../$(ARCHIVE)
@(cd ..; md5sum $(ARCHIVE) | tee $(ARCHIVE).md5)
@$(ARCHTOOL) ../$(ARCHIVE)
@xz ../$(ARCHIVE)
@md5sum $(ARCHIVEZ) | tee $(ARCHIVEZ).md5
dev: distclean
@echo "Building unstable xz $(DEV) in parent dir..."
@@ -158,9 +173,6 @@ dev: distclean
cd - >/dev/null; mv $$dir/$(DEV).tar.xz ../; cd ..; \
rm -rf $$dir; md5sum $(DEV).tar.xz | tee $(DEV).tar.xz.md5)
# Include automatically generated rules, such as:
# uncgi.o: .../some/dir/uncgi.c /usr/include/stdio.h
# but don't bother during clean!
ifneq ($(MAKECMDGOALS),clean)
ifneq ($(MAKECMDGOALS),distclean)
-include $(DEPS)
+1 -1
View File
@@ -1 +1 @@
README.rst
README.md
+468
View File
@@ -0,0 +1,468 @@
Finit | Fast & Extensible init for Linux
========================================
[![Build Status](https://travis-ci.org/troglobit/finit.png?branch=master)](https://travis-ci.org/troglobit/finit)
[![Coverity Scan Status](https://scan.coverity.com/projects/3545/badge.svg)](https://scan.coverity.com/projects/3545)
![Original Finit homepage image](images/finit.jpg "Finit in action!")
Table of Contents
-----------------
* [Introduction](#introduction)
* [Features](#features)
* [/etc/finit.conf](#etcfinitconf)
* [/etc/finit.d](#etcfinitd)
* [Bootstrap](#bootstrap)
* [Runlevels](#runlevels)
* [Hooks, Callbacks & Plugins](#hooks-callbacks--plugins)
* [Rebooting and Halting](#rebooting-and-halting)
* [Building](#building)
* [Running](#running)
* [Debugging](#debugging)
* [Origin & References](#origin--references)
Introduction
------------
Init is the first process to run once a UNIX kernel has booted, it
always has PID 1 and is responsible for starting up the rest of the
system. Finit is plugin-based with built in [process supervision][1]
similar to that of D.J. Bernstein's [daemontools][2] and Gerrit Pape's
[runit][3]. The main focus of Finit is on small and embedded GNU/Linux
systems, yet fully functional on standard server and desktop
installations as well.
Traditional [SysV init][4] style systems are scripted. For low-resource
embedded systems this can be quite resource intensive and cause longer
boot times. Finit is optimized to reduce context switches and forking
of processes to provide a very basic bootstrap written entirely in C.
Hence, there is no `/etc/init.d/rcS` script, or similar, but instead a
human-readable `/etc/finit.conf`. This file details what kernel modules
to load, programs to run and daemons to supervise.
The command line arguments given in `/etc/finit.conf` to each service
provide a default. Each service can register callbacks, using plugins,
to override and modify the behavior to suit the current runlevel and
system configuration. For instance, before starting a heavily resource
intensive service like IPsec or OpenVPN, a callback can check if the
outbound interface is up and has an IP address, or just check if the
service is disabled -- much like what a SysV init start script usually
does.
See [TroglOS][9] for an example of how to boot a small embedded system
with Finit.
Features
--------
**Process Supervision**
Start, monitor and restart services if they fail.
**Runlevels**
Runlevels is optional in Finit, but support for [SysV runlevels][5] is
available if needed. All services in runlevel S(1) are started first,
followed by the desired run-time runlevel. Runlevel S can be started in
sequence by using `run [S] cmd`. Changing runlevels at runtime is done
like any other init, e.g. <kbd>init 4</kbd>.
**Plugins**
Finit plugins can be either *boot hooks* into different stages of the
boot process or *service callbacks*, or both. A basic set of plugins
that extend and modify the basic behavior are bundled. See examples in
the `plugins/` directory.
Plugin capabilities:
* Service callbacks -- modify service arguments, run/restart/stop
* Task/Run callbacks -- a one-shot commands, executed in sequence
* Hooks -- hook into the boot at predefined points to extend finit
* I/O -- listen to external events and control finit behavior/services
Extensions and functionality not purely related to what an `/sbin/init`
needs to start a system are available as a set of plugins that either
hook into the boot process or respond to various I/O.
/etc/finit.conf
---------------
Contrary to most other script based init alternatives ([SysV init][4],
[upstart][6], [systemd][7], [OpenRC][8], etc.) Finit reads its entire
configuration from `/etc/finit.conf`.
Syntax:
* `check <DEV>`
Run fsck on a file system before mounting it
* `module <MODULE>`
Load a kernel module, with optional arguments
* `network <PATH>`
Script or program to bring up networking, with optional arguments
* `runlevel <N>`
N is the runlevel number 1-9, where 6 is reserved for reboot.
Default is 2.
* `run [LVLS] /path/to/cmd ARGS -- Optional description`
One-shot command to run in sequence when entering a runlevel, with
optional arguments and description. This command is guaranteed to be
completed before running the next command.
* `task [LVLS] /path/to/cmd ARGS -- Optional description`
One-shot like 'run', but starts in parallel with the next command
* `service [LVLS] /path/to/daemon ARGS -- Optional description`
Service, or daemon, to be monitored and automatically restarted if it
exits prematurely. Please note that you often need to provide a
--foreground or --no-background argument to most daemons to prevent
them from forking off to the background.
* `runparts <PATH>`
Call run-parts(8) on a directory other than default ``/etc/finit.d``
* `include <CONF>`
Include another configuration file, ``/etc/finit.d``, or runparts path
is prepended to file if the file is not found or an absolute path is
not given
* `tty [LVLS] <DEV | /bin/sh>`
Start a getty on the given TTY device, in the given runlevels. When
no tty setting is given in `finit.conf`, or if `/bin/sh` is given as
argument instead of a device path, a single shell is started on the
default console. Useful for really bare-bones systems
See `finit.h` for the `#define GETTY` that is called, along with the
default baud rate.
* `console <DEV>`
Some embedded systems have a dedicated console port. This command
tells finit to not start getty, but instead print a friendly message
and wait for the user to activate the console with a key press before
starting getty.
When running <kbd>make install</kbd> no default `/etc/finit.conf` will
be installed since system requirements differ too much. Try out the
Debian 6.0 example `/usr/share/doc/finit/finit.conf` configuration that
is capable of service monitoring SSH, sysklogd, gdm and a console getty!
/etc/finit.d
------------
At the end of the boot, when networking and all services are up, finit
calls its built-in run-parts(8) on the `/etc/finit.d/` directory, if it
exists. Similar to how the `/ec/rc.local` file works in most other init
daemons, only finit runs a directory of scripts. This replaces the
earlier support for a `/usr/sbin/services.sh` script in the original
finit.
Bootstrap
---------
1. Setup `/dev`
2. Parse `/etc/finit.conf`
3. Load all `.so` plugins
4. Remount/Pivot `/` to get R+W
5. Call 1st level hooks, `HOOK_ROOTFS_UP`
6. Mount `/etc/fstab` and swap, if available
7. Cleanup stale files from `/tmp/*` et al
8. Enable SysV init signals
9. Call 2nd level hooks, `HOOK_BASEFS_UP`
10. Start all 'S' runlevel tasks and services
11. Setup `/etc/sysctl.conf`
12. Setup hostname and loopback
13. Call `network` script, if set in `/etc/finit.conf`
14. Call 3rd level hooks, `HOOK_NETWORK_UP`
15. Switch to active runlevel, as set in `/etc/finit.conf`, default 2.
Here is where the rest of all tasks and services are started.
16. Call 4th level hooks, `HOOK_SVC_UP`
17. Run-parts in `/etc/finit.d`, if any
18. Call 5th level (last) hooks, `HOOK_SYSTEM_UP`
19. Start TTYs defined in `/etc/finit.conf`, or rescue on `/dev/console`
20. Enter main monitor loop
In (10) and (15) tasks and services defined in `/etc/finit.conf` are
started. Remember, all `service` and `task` stanzas are started in
parallel and `run` in sequence, and in the order listed. Hence, to
emulate a SysV `/etc/init.d/rcS` one could write a long file with only
`run` statments.
Notice the five hook points that are called at various point in the
bootstrap process. This is where plugins can extend the boot in any way
they please.
For instance, at `HOOK_BASEFS_UP` a plugin could read an XML file from a
USB stick, convert/copy its contents to the system's `/etc/` directory,
well before all 'S' runlevel tasks are started. This could be used with
system images that are created read-only and all configuration is stored
on external media.
Runlevels
---------
Basic support for [runlevels](http://en.wikipedia.org/wiki/Runlevel) is
included in Finit from v1.8. By default all services, tasks, run
commands and TTYs listed without a set of runlevels get a default set
`[234]` assigned. The default runlevel after boot is 2.
To specify an allowed set of runlevels for a `service`, `run` command, `task`,
or `tty`, add `[NNN]` to it in your `/etc/finit.conf`, like this:
service [S12345] /sbin/syslogd -n -x -- System log daemon
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 syslogd is first started, in parallel, and then acpid is
called using a conventional SysV init script. It is called with the run
command, meaning the following task command to start the kbd script is
not called until the acpid init script has fully completed. Then the
keyboard setup script is called in parallel with klogd as a monitored
service.
Again, tasks and services are started in parallel, while run commands
are called in the order listed and subsequent commands are not started
until a run command has completed.
Switching between runlevels can be done by calling init with a single
argument, e.g. <kbd>init 5</kbd> switches to runlevel 5.
Hooks, Callbacks & Plugins
--------------------------
Finit provides only the bare necessities for starting and supervising
processes, with an emphasis on *bare* -- for your convenience it does
however come with support for hooks, service callbacks and plugins that
can used to extend finit with. For your convenience a set of *optional*
plugins are available:
* *alsa-utils.so*: Restore and save ALSA sound settings on
startup/shutdown.
* *bootmisc.so*: Setup necessary files for UTMP, tracks logins at boot.
* *dbus.so*: Setup and start system message bus, D-Bus, at boot.
* *hwclock.so*: Restore and save system clock from/to RTC on
startup/shutdown.
* *initctl.so*: Extends finit with a traditional initctl functionality.
* *resolvconf.so*: Setup necessary files for resolvconf at startup.
* *tty.so*: Watches /dev, using inotify, for new device nodes (TTY's) to
start/stop getty consoles on them on demand.
* *urandom.so*: Setup random seed at startup.
* *x11-common.so*: Setup necessary files for X-Window.
Usually you want to hook into the boot process once, simple hook plugins
like `bootmisc.so` are great for that purpose. They are called at each
hook point in the boot process, useful to insert some pre-bootstrap
mechanisms, like generating configuration files, restoring HW device
state, etc. Available hook points are:
* `HOOK_ROOTFS_UP`: When `finit.conf` has been read and `/` has is
mounted -- very early
* `HOOK_BASEFS_UP`: All of `/etc/fstab` is mounted, swap is available
and default init signals are setup
* `HOOK_NETWORK_UP`: System bootstrap, runlevel S, has completed and
networking is up (`lo` is up and the `network` script has run)
* `HOOK_SVC_UP`: All services in the active runlevel has been launched
* `HOOK_SYSTEM_UP`: All services *and* everything in `/etc/finit.d`
has been launched
* `HOOK_SHUTDOWN`: Called at shutdown/reboot, right before all
services are sent `SIGTERM`
Plugins like `initctl.so` and `tty.so` extend finit by acting on events,
they are called I/O plugins and are called from the finit main loop when
`poll()` detects an event. See the source code for `plugins/*.c` for
more help and ideas.
Callback plugins are called by finit them right before a process is
started, or restarted if it exits. The callback receive a pointer to
the `svc_t` (defined in `svc.h`) of the service, with all command line
parameters free to modify if needed. All the callback needs to do is
respond with one of: `SVC_STOP (0)` tells finit to *not* start the
service, `SVC_START (1)` to start the service, or `SVC_RELOAD (2)` to
have finit signal the process with `SIGHUP`.
Rebooting and Halting
---------------------
Finit handles `SIGUSR1` and `SIGUSR2` for reboot and halt, and listens
to `/dev/initctl` so system reboot and halt commands should also work.
This latter functionality is implemented in the optional `initctl.so`
plugin.
Building
--------
The finit build system does not employ the GNU Configure and Build System,
instead standard makefiles are used. The user is encouraged to make source
code changes, using defines and conditionally building plugins instead to
alter the behavior of finit.
The following environment variables are checked by the makefiles and control
what is built and where resulting binaries are installed.
* `ROOTDIR=`: Top directory for building complete system, used in pretty
printing.
* `VERSION=`: Defaults to the currently released version of finit,
e.g., 1.3 but can be overridden by packagers using this variable to
add a suffix or completely alter the version.
* `CFLAGS=`: Default `CFLAGS` are inherited from the environment.
* `CPPFLAGS=`: Default `CPPFLAGS` are inherited from the environment.
* `LDFLAGS=`: Default `LDFLAGS` are inherited from the environment.
* `LDLIBS=`: Default `LIBLIBS` are inherited from the environment.
* `prefix=`: Base prefix path for all files, except `sbinbdir` and
`sysconfdir`. Used in concert with the `DESTDIR` variable.
Defaults to `/usr`.
* `sbindir=`: Path to where resulting binaries should install to. Used
in concert with the `DESTDIR` variable.
Defaults to `/sbin`.
* `sysconfdir=`: Path to where finit configuration files should install
to. Used in concert with the `DESTDIR` variable.
Defaults to `/etc`, but is currently unused.
* `PLUGINS=`: List of stock finit plugins to build and install.
* `plugindir=`: Absolute path to where finit should look for dynamically
loadable plugins at runtime. At installation prepended by `DESTDIR`
and `prefix`.
Defaults to `/lib/finit/plugins`.
* `DESTDIR=`: Used by packagers and distributions when building a
relocatable bundle of files. Always prepended to the `prefix`
destination directory.
**Example**
First, unpack the archive:
<kbd>$ tar xfJ finit-1.3.tar.xz; cd finit-1.3/</kbd>
Then build and install:
<kbd>$ PLUGINS="initctl.so hwclock.so" DESTDIR=/tmp/finit make install</kbd>
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/sbin/finit
INSTALL /tmp/finit/lib/finit/plugins/initctl.so
INSTALL /tmp/finit/lib/finit/plugins/hwclock.so
In this example the [finit-1.3.tar.xz][10] archive is unpacked to the
user's home directory, built and installed to a temporary staging
directory. The environment variables `DESTDIR` and `PLUGINS` are
changed to suit this particular build.
Running
-------
The default install does not setup finit as the system default
`/sbin/init`, neither does it setup an initial `/etc/finit.conf`.
It is assumed that users of finit are competent enough to either setup
finit as their default `/sbin/init` or alter their respective Grub,
LOADLIN, LILO, U-Boot/Barebox or RedBoot boot loader configuration to
give the kernel the following extra command line:
init=/sbin/finit
![Finit starting Debian 6.0](images/finit-screenshot.jpg "Finit screenshot")
Debugging
---------
Add `finit_debug`, or `--debug`, to the kernel command line to
enable trace messages. A console getty is always started, see the file
`finit.h` for more useful compile-time tweaks:
init=/sbin/finit --debug
Origin & References
-------------------
This is the continuation of the [original finit](http://helllabs.org/finit/)
by [Claudio Matsuoka](https://github.com/cmatsuoka), which in turn was
reverse engineered from syscalls of the
[EeePC fastinit](http://wiki.eeeuser.com/boot_process:the_boot_process)
-- "gaps filled with frog DNA ...".
Finit is currently being developed and maintained by
[Joachim Nilsson](http://troglobit.com) at
[GitHub](http://github.com/troglobit/finit). Please file bug reports, clone it,
or send pull requests for bug fixes and proposed extensions.
[1]: https://en.wikipedia.org/wiki/Process_supervision
[2]: http://cr.yp.to/daemontools.html
[3]: http://smarden.org/runit/
[4]: http://en.wikipedia.org/wiki/Init
[5]: http://en.wikipedia.org/wiki/Runlevel
[6]: http://upstart.ubuntu.com/
[7]: http://www.freedesktop.org/wiki/Software/systemd/
[8]: http://www.gentoo.org/proj/en/base/openrc/
[9]: https://github.com/troglobit/troglos
[10]: ftp://troglobit.com/finit/finit-1.3.tar.xz
-195
View File
@@ -1,195 +0,0 @@
==============================================================================
Finit — A fast plugin-based /sbin/init with service monitoring
==============================================================================
Welcome to finit!
This is an extremely fast /sbin/init replacement with focus on small
embedded GNU/Linux systems. Based on Claudio Matsuoka's original finit_
with I/O, service and hook plugin extensions. The original was a
reimplementation of the EeePC fastinit_ daemon based on its system
calls with gaps filled with frog DNA.
In the world of finit we write C plugins that hook into and extend the
``main()`` loop of ``/sbin/init``, this is what gives the system its raw
performance and the user full control.
If you chose finit you know what you want, a fast no hassles boot!
Features
--------
**Service monitoring**
Restarting a service when it exits
**Plugins**
Extend and modify finit behavior. See examples in plugins/ directory.
Plugin capabilities:
* Service callbacks — should the service run/restart/stop?
* Hooks — hook into the boot at predefined points to extend finit
* I/O — listen to external events and control finit behaviour/services
Most extensions and functionality not purely related to what an /sbin/init
needs to start a system from the original finit_ has been reactored into
plugins with either hooks or I/O demands.
/etc/finit.conf
---------------
Contrary to most script based init alternatives (`SysV init`_, upstart_,
OpenRC_ and the likes) finit instead reads its configuration from
``/etc/finit.conf``, see the source code for available options.
When running ``make install`` no default ``/etc/finit.conf`` will be
provided since the system requirements differ too much. Try out the
Debian 6.0 example ``/usr/share/doc/finit/finit.conf`` configuration
that is capable of service monitoring SSH, sysklogd, gdm and a console
getty!
/etc/finit.d
------------
At the end of the boot, when networking and all services are up, finit
calls its built-in run-parts(8) on the ``/etc/finit.d/`` directory, akin
to how the ``/ec/rc.local`` file works in most other inits, only finit
runs a directory of scripts. This replaces the earlier
``/usr/sbin/services.sh`` support of the original finit_.
Rebooting and Halting
---------------------
Finit handles SIGUSR1 and SIGUSR2 for reboot and halt, and listens to
``/dev/initctl`` so standard Linux reboot and halt commands should also
work.
Building
--------
The finit build system does not employ the GNU Configure and Build System,
instead standard makefiles are used. The user is encouraged to make source
code changes, using defines and conditionally building plugins instead to
alter the behavior of finit.
The following environment variables are checked by the makefiles and control
what is built and where resulting binaries are installed.
**ROOTDIR=**
Top directory for building complete system, used in pretty printing
**VERSION=**
Defaults to the currently released version of finit, e.g., 1.3 but can
be overridden by packages to add a suffix or completely alter the version.
**CFLAGS=**
Standard CFLAGS are inherited from the build enviornmant.
**CPPFLAGS=**
Standard CPPFLAGS are inherited from the build enviornmant.
**LDFLAGS=**
Standard LDFLAGS are inherited from the build enviornmant.
**LDLIBS=**
Standard LIBLIBS are inherited from the build enviornmant.
**prefix=**
Base prefix path for all files, except ``sbinbdir`` and ``sysconfdir``.
Used in concert with the ``DESTDIR`` variable. Defaults to ``/usr``
**sbindir=**
Path to where resulting binaries should install to. Used in concert
with the ``DESTDIR`` variable. Defaults to ``/sbin``
**sysconfdir=**
Path to where finit configuration files should install to. Used in
concert with the ``DESTDIR`` variable. Defaults to ``/etc``, but is
currently unused.
**PLUGINS=**
List of stock finit plugins to build and install.
**plugindir=**
Absolute path to where finit should look for dynamically loadable plugins
at runtime. At installation prepended by ``DESTDIR`` and ``prefix``.
Defaults to ``/lib/finit/plugins``
**DESTDIR=**
Used by packagers and distributions when building a relocatable
bundle of files. Alwawys prepended to the ``prefix`` destination
directory.
**Example**::
$ tar xfJ finit-1.3.tar.xz
$ PLUGINS="initctl.so hwclock.so" DESTDIR=/tmp/finit/dst \
make -C finit-1.3/ clean install
make: Entering directory `/home/troglobit/finit-1.3'
CC finit.o
CC conf.o
CC helpers.o
CC sig.o
CC svc.o
CC plugin.o
CC strlcpy.o
LINK finit
CC plugins/initctl.o
PLUGIN plugins/initctl.so
CC plugins/hwclock.o
PLUGIN plugins/hwclock.so
INSTALL /tmp/finit/dst/sbin/finit
INSTALL /tmp/finit/dst/lib/finit/plugins/initctl.so
INSTALL /tmp/finit/dst/lib/finit/plugins/hwclock.so
make: Leaving directory `/home/troglobit/finit-1.3'
In this example the `finit-1.3.tar.xz`_ archive is unpacked to the
user's home directory, built and installed to a temporary staging
directory. The enviroment variables ``DESTDIR`` and ``PLUGINS`` are
changed to suit this particular build.
Running
-------
The default install does not setup finit as the system default
``/sbin/init``, neither does it setup an initial ``/etc/finit.conf``.
It is assumed that users of finit are competent enough to either setup
finit as their default ``/sbin/init`` or alter their respective Grub,
LOADLIN, LILO, U-Boot/Barebox or RedBoot boot loader configuration to
give the kernel the following extra command line::
init=/sbin/finit
Debugging
---------
Add ``finit_debug``, or ``--debug``, to the kernel command line to
enable trace messages. A console getty is always started, see the file
``finit.h`` for more useful comile-time tweaks::
init=/sbin/finit --debug
Contact
-------
Finit is maintained collaborativly at http://github.com/troglobit/finit —
please file a bug report, clone it, or send pull requests for bug fixes and
proposed extensions, or become a co-maintainer by contacting the main author.
Regards
/Joachim Nilsson <troglobit@gmail.com>
.. _finit: http://helllabs.org/finit/
.. _fastinit: http://wiki.eeeuser.com/boot_process:the_boot_process
.. _`SysV init`: http://savannah.nongnu.org/projects/sysvinit
.. _upstart: http://upstart.ubuntu.com/
.. _openrc: http://www.gentoo.org/proj/en/base/openrc/
.. _`finit-1.3.tar.xz`: http://github.com/downloads/troglobit/finit/finit-1.3.tar.xz
-6
View File
@@ -1,6 +0,0 @@
* FHS changes, see http://askubuntu.com/questions/57297/why-has-var-run-been-migrated-to-run
* Look at Erik Troan's nash linuxrc parser for more inspiration
* Look at how to support a standard SysV init runlevel mechanism
* Arguments to finit, like to SysV init "init q" to reload finit.conf at runtime, etc.
* Implement initctl stop|start|reload <SVC> and service <SVC> stop|start|reload on top
* Write man pages for finit and finit.conf, steal from pimd man pages...
Symlink
+1
View File
@@ -0,0 +1 @@
TODO.md
+165
View File
@@ -0,0 +1,165 @@
Goals of Finit
==============
The intent of finit is to monitor not just processes, but to supervise
an entire system and the behavior of certain processes that declare
themselves to be finit compliant. Similar to launchd, the goal of
finit is to be a replacement for:
* init
* inetd
* crond
* watchdogd
A small and simple replacement, primarily for embedded systems, with a
very low dependency on external packages.
General
-------
* Add support for `init <q | reload-configuration>` and `SIGHUP` to
have finit reload its `finit.conf`, but also
* Add support for inotify to automatically reload `finit.conf`
* Implement `initctl stop|start|restart|reload|status <SVC>` and
`service <SVC> stop|start|restart|reload|status` on top
* Add PRE and POST hooks for when switching between runlevels
* Add support for `init -v,--version | version`
* Cleanup move sources from top-level directory to `src/` and `include/`
* Make sure to install `queue.h` to `$(PREFIX)/include/finit/queue.h`
* Move `finit.conf` "check" command to plugin which checks `/etc/fstab`
instead. This is the de-facto practice. But keep the check command
for really low-end systems w/o `/etc/fstab`.
Init
----
Finit in itself is not SysV Init compatible, it doesn't use `/etc/rc.d`
and `/etc/inet.d` scripts to boot the system. However, a plausible way
to achieve compatibility would be to add a plugin to finit which reads
`/etc/inittab` to be able to start standard Linux systems.
Inetd
-----
Simple way of running Internet services on demand, like the old inetd:
inetd PROTO/SERVICE <wait|nowait> [@USER[:GROUP]] /path/to/daemon args
Examples:
# Inetd services, launched on demand
inetd tcp/ssh nowait [2345] @root:root /usr/sbin/sshd -i
In keeping with the finit tradition, an optional callback can be setup
to each inetd service. When a client connects the finit will call the
callback with a `struct in_pktinfo` argument which the callback then can
allowed or deny.
Alternatively, borrowing from TCP wrappers by Wietse Venema, a set of
`allow` and `deny` directives can be added to `finit.conf` to control
inetd services. It could be what IP addreses, networks or interfaces
are allowed to connect to the given inetd services. To start with the
easiest (and what we need for WeOS at Westermo) is allow/deny per iface.
# Disable access to SSH
deny ssh all
# Allow SSH connections originating from eth0
allow ssh eth0
Another option, to further extend the Inetd capabilities, is a separate
`finetd.conf` to list services. This would be beneficial when running
an SSH service on different ports on different interfaces:
# Run SSH on port 22 on all interfaces except upstream
tcp ssh {
listen = *, !wan0
exec = dropbear -i
}
# Run SSH on non-standard port 222 for upstream interface
tcp 222 {
listen = wan0
exec = dropbear -i
wait = yes
}
# Run TFTP service on all interfaces except upstream interface
udp tftp {
listen = *, !wan0
exec = uftpd -i -t
user = root
}
Syntax very similar to [xinetd](http://en.wikipedia.org/wiki/Xinetd)
Crond
-----
Requirements are quite rudimentary, basic cron functionality, mainly
system-level timed periodic tasks:
* Periodically run a task, in a matching runlevel
* Optionally run as non-root (`crontab -e` as operator)
Proposed syntax:
# Crontab
cron @YY-mm-ddTHH:MM [LVLS] /path/to/cmd [ARGS] -- Optional descr
# One-shot 'at' command
at @YY-mm-ddTHH:MM [LVLS] /path/to/cmd [ARGS] -- Optional descr
Notice the ISO date in notation. The runlevels is extra filtering
sugar. E.g., if cron service is only allowed in runlevels two or three
it will not start if system currently is in runlevel four.
To run a command as another user the `.conf` file must have a that
owner. E.g., `/etc/finit.d/extra.conf` may be owned by operator and
only hold `cron ...` lines.
What would be extremely useful is if `initctl`, or a homegrown `at`,
could support the basic functionality of the `at` command directly from
the shell -- that way setting up one-time jobs would not entail
re-reading `/etc/finit.conf`
Watchdog
--------
Support for monitoring the health of the system and its processes.
* Add support for a `/dev/watchdog` plugin to replace `watchdogd`
* Integrate system supervisor to optionally reboot the system when a
process stops responding, or when a respawn limit has been reached,
as well as when system load gets too high.
* API for processes to register with the watchdog.
- Deeper monitoring of a process main loop
- If a process is not heard from within its subscribed period time
reboot system or restart process.
* Separate `/etc/watchdog.conf` configuration file, or a perhaps
support for `/etc/finit.d/PLUGIN.conf`?
* Support enable/disable watchdog features:
- Supervise processes,
- CPU loadavg,
- Watch for file descriptor leaks,
- etc.
Documentation
-------------
* Write man pages for finit and `finit.conf`, steal from the excellent
`pimd` man pages ...
* Update Debian `finit.conf` example with runlevels, `tty/console` and
dependency handling for Debian 8 (the dreaded systemd release).
Investigation
-------------
* [FHS changes](http://askubuntu.com/questions/57297/why-has-var-run-been-migrated-to-run)
affecting runtime status, plugins, etc.
+9 -5
View File
@@ -1,9 +1,13 @@
# Top directory for building complete system, fall back to this directory
ROOTDIR ?= $(TOPDIR)
# Some junk files we always want to be removed when doing a make clean.
JUNK = *~ *.bak *.aux *.dvi *.idx *.ind *.log *.ps *.map .*.d DEADJOE semantic.cache *.gdb *.elf core core.*
MAKE := @$(MAKE)
MAKEFLAGS = --no-print-directory --silent
INSTALL := install --backup=off
STRIPINST := $(INSTALL) -s --strip-program=$(CROSS)strip -m 0755
JUNK = *~ *.bak *.aux *.dvi *.idx *.ind *.log *.ps *.map .*.d DEADJOE semantic.cache *.gdb *.elf core core.*
MAKE := @$(MAKE)
MAKEFLAGS = --no-print-directory --silent
CHECK := cppcheck $(CPPFLAGS) --quiet --enable=all
INSTALL := install --backup=off
STRIPINST := $(INSTALL) -s --strip-program=$(CROSS)strip -m 0755
# Smart autodependecy generation via GCC -M.
.%.d: %.c
+228 -93
View File
@@ -21,123 +21,258 @@
* THE SOFTWARE.
*/
#include <ctype.h>
#include <string.h>
#include "finit.h"
#include "svc.h"
#include "tty.h"
#include "lite.h"
#include "helpers.h"
/* Match one command. */
#define MATCH_CMD(l, c, x) \
#define MATCH_CMD(l, c, x) \
(!strncmp(l, c, strlen(c)) && (x = (l) + strlen(c)))
static char *build_cmd(char *cmd, char *line, int len)
static char *strip_line(char *line)
{
int l;
char *c;
char *ptr;
/* Trim leading whitespace */
while (*line && (*line == ' ' || *line == '\t'))
while (*line && isblank(*line))
line++;
if (!cmd) {
cmd = malloc (strlen(line) + 1);
if (!cmd) {
_e("No memory left for '%s'", line);
return NULL;
}
*cmd = 0;
}
c = cmd + strlen(cmd);
for (l = 0; *line && *line != '#' && *line != '\t' && l < len; l++)
*c++ = *line++;
*c = 0;
/* Strip any comment at end of line */
ptr = line;
while (*ptr && *ptr != '#')
ptr++;
*ptr = 0;
_d("cmd = %s", cmd);
return cmd;
return line;
}
void parse_finit_conf(char *file)
/* Convert optional "[!123456789S]" string into a bitmask */
int parse_runlevels(char *runlevels)
{
int i, not = 0, bitmask = 0;
if (!runlevels)
runlevels = "[234]";
i = 1;
while (i) {
int level;
char lvl = runlevels[i++];
if (']' == lvl || 0 == lvl)
break;
if ('!' == lvl) {
not = 1;
bitmask = 0x3FE;
continue;
}
if ('s' == lvl || 'S' == lvl)
lvl = '0';
level = lvl - '0';
if (level > 9 || level < 0)
continue;
if (not)
CLRBIT(bitmask, level);
else
SETBIT(bitmask, level);
}
return bitmask;
}
static int parse_conf(char *file)
{
FILE *fp;
char line[LINE_SIZE];
char line[LINE_SIZE] = "";
char cmd[CMD_SIZE];
char *x;
const char *err = NULL;
fp = fopen(file, "r");
if (!fp)
return 1;
/*
* If not standard finit.conf, then we want to show just the base name
* Loading configuration ............. vs
* Loading services configuration ....
*/
if (!string_match (file, FINIT_CONF)) {
/* Remove leading path */
x = strrchr(file, '/');
if (!x) x = file;
else x++;
/* Remove ending .conf */
strlcpy(line, x, sizeof(line));
x = strstr(line, ".conf");
if (x) *x = 0;
/* Add empty space. */
strcat(line, " ");
}
print(0, "Loading %sconfiguration", line);
while (!feof(fp)) {
if (!fgets(line, sizeof(line), fp))
continue;
chomp(line);
_d("conf: %s", line);
/* Skip comments. */
if (MATCH_CMD(line, "#", x))
continue;
/* Do this before mounting / read-write
* XXX: Move to plugin which checks /etc/fstab instead */
if (MATCH_CMD(line, "check ", x)) {
char *dev = strip_line(x);
strcpy(cmd, "/sbin/fsck -C -a ");
strlcat(cmd, dev, sizeof(cmd));
run_interactive(cmd, "Checking file system %s", dev);
continue;
}
if (MATCH_CMD(line, "user ", x)) {
if (username) free(username);
username = strdup(strip_line(x));
continue;
}
if (MATCH_CMD(line, "host ", x)) {
if (hostname) free(hostname);
hostname = strdup(strip_line(x));
continue;
}
if (MATCH_CMD(line, "module ", x)) {
char *mod = strip_line(x);
strcpy(cmd, "/sbin/modprobe ");
strlcat(cmd, mod, sizeof(cmd));
run_interactive(cmd, "Loading kernel module %s", mod);
continue;
}
if (MATCH_CMD(line, "mknod ", x)) {
char *dev = strip_line(x);
strcpy(cmd, "/bin/mknod ");
strlcat(cmd, dev, sizeof(cmd));
run_interactive(cmd, "Creating device node %s", dev);
continue;
}
if (MATCH_CMD(line, "network ", x)) {
if (network) free(network);
network = strdup(strip_line(x));
continue;
}
/* This is the directory from which executable scripts and
* any finit include files are read, default /etc/finit.d/ */
if (MATCH_CMD(line, "runparts ", x)) {
if (rcsd) free(rcsd);
rcsd = strdup(strip_line(x));
continue;
}
/* Parse any include file, use rcsd if absolute path not given */
if (MATCH_CMD(line, "include ", x)) {
char *file = strip_line(x);
strlcpy(cmd, file, sizeof(cmd));
if (!fexist(cmd)) {
/* ... try /etc/finit.d/ as prefix */
snprintf(cmd, sizeof(cmd), "%s/%s", rcsd, file);
if (!fexist(cmd))
continue;
}
parse_conf(cmd);
continue;
}
if (MATCH_CMD(line, "startx ", x)) {
svc_register(SVC_CMD_SERVICE, strip_line(x), username);
continue;
}
if (MATCH_CMD(line, "shutdown ", x)) {
if (sdown) free(sdown);
sdown = strdup(strip_line(x));
continue;
}
/* The desired runlevel to start when leaving
* bootstrap (S). Finit supports 1-9, but most
* systems only use 1-6, where 6 is reserved for
* reboot */
if (MATCH_CMD(line, "runlevel ", x)) {
char *token = strip_line(x);
cfglevel = strtonum(token, 1, 9, &err);
if (err)
cfglevel = RUNLEVEL;
if (cfglevel < 1 || cfglevel > 9 || cfglevel == 6)
cfglevel = 2; /* Fallback */
continue;
}
/* Monitored daemon, will be respawned on exit, as
* long as the (optional) service callback returns
* non-zero */
if (MATCH_CMD(line, "service ", x)) {
svc_register(SVC_CMD_SERVICE, x, NULL);
continue;
}
/* One-shot task, will not be respawned. Only runs if
* the (optional) service callback returns true */
if (MATCH_CMD(line, "task ", x)) {
svc_register(SVC_CMD_TASK, x, NULL);
continue;
}
/* Like task but waits for completion, useful w/ [S] */
if (MATCH_CMD(line, "run ", x)) {
svc_register(SVC_CMD_RUN, x, NULL);
continue;
}
if (MATCH_CMD(line, "console ", x)) {
if (console) free(console);
console = strdup(strip_line(x));
continue;
}
if (MATCH_CMD(line, "tty ", x)) {
tty_register(strip_line(x));
continue;
}
}
fclose(fp);
return 0;
}
int parse_finit_conf(char *file)
{
int result;
/* Default username and hostname */
username = strdup(DEFUSER);
hostname = strdup(DEFHOST);
rcsd = strdup(FINIT_RCSD);
if ((fp = fopen(file, "r")) != NULL) {
char *x;
result = parse_conf(file);
if (!tty_num())
tty_register(FALLBACK_SHELL);
_d("Parse %s ...", file);
while (!feof(fp)) {
if (!fgets(line, sizeof(line), fp))
continue;
chomp(line);
_d("conf: %s", line);
/* Skip comments. */
if (MATCH_CMD(line, "#", x)) {
continue;
}
/* Do this before mounting / read-write */
if (MATCH_CMD(line, "check ", x)) {
strcpy(cmd, "/sbin/fsck -C -a ");
build_cmd(cmd, x, CMD_SIZE);
run_interactive(cmd, "Checking file system integrity on %s", x);
continue;
}
if (MATCH_CMD(line, "user ", x)) {
if (username) free(username);
username = build_cmd(NULL, x, USERNAME_SIZE);
continue;
}
if (MATCH_CMD(line, "host ", x)) {
if (hostname) free(hostname);
hostname = build_cmd(NULL, x, HOSTNAME_SIZE);
continue;
}
if (MATCH_CMD(line, "shutdown ", x)) {
if (sdown) free(sdown);
sdown = build_cmd(NULL, x, CMD_SIZE);
continue;
}
if (MATCH_CMD(line, "module ", x)) {
strcpy(cmd, "/sbin/modprobe ");
build_cmd(cmd, x, CMD_SIZE);
run_interactive(cmd, " Loading module %s", x);
continue;
}
if (MATCH_CMD(line, "mknod ", x)) {
strcpy(cmd, "/bin/mknod ");
build_cmd(cmd, x, CMD_SIZE);
run_interactive(cmd, " Creating device node %s", x);
continue;
}
if (MATCH_CMD(line, "network ", x)) {
if (network) free(network);
network = build_cmd(NULL, x, CMD_SIZE);
continue;
}
if (MATCH_CMD(line, "runparts ", x)) {
if (rcsd) free(rcsd);
hostname = build_cmd(NULL, x, CMD_SIZE);
continue;
}
if (MATCH_CMD(line, "startx ", x)) {
svc_register(x, username);
continue;
}
if (MATCH_CMD(line, "service ", x)) {
svc_register(x, NULL);
continue;
}
}
fclose(fp);
}
return result;
}
+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
:
+117 -47
View File
@@ -1,7 +1,7 @@
/* Finit - Extremely fast /sbin/init replacement w/ I/O, hook & service plugins
*
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2012 Joachim Nilsson <troglobit@gmail.com>
* Copyright (c) 2008-2014 Joachim Nilsson <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -26,6 +26,7 @@
#include <ctype.h>
#include <dirent.h>
#include <sys/stat.h> /* umask(), mkdir() */
#include <getopt.h>
#include "finit.h"
#include "helpers.h"
@@ -33,16 +34,20 @@
#include "plugin.h"
#include "svc.h"
#include "sig.h"
#include "tty.h"
#include "lite.h"
int debug = 0;
int verbose = 1;
char *sdown = NULL;
char *network = NULL;
char *username = NULL;
char *hostname = NULL;
char *rcsd = FINIT_RCSD;
int debug = 0;
int verbose = 1;
int runlevel = 0; /* Bootstrap */
int cfglevel = RUNLEVEL; /* Fallback if no configured runlevel */
int prevlevel = 0; /* HALT */
char *sdown = NULL;
char *network = NULL;
char *username = NULL;
char *hostname = NULL;
char *rcsd = NULL;
char *console = NULL;
static void parse_kernel_cmdline(void)
{
@@ -63,23 +68,97 @@ static void parse_kernel_cmdline(void)
}
}
static int run_loop(void)
static int usage(int rc)
{
while (1) {
svc_monitor();
plugin_monitor();
fprintf(stderr, "Usage: %s [OPTIONS] [RUNLEVEL]\n\n"
" -d, --debug Enable/Disable debug\n"
" -h, --help This help text\n\n", __progname);
return rc;
}
static int client(int argc, char *argv[])
{
int fd;
int c;
struct option long_options[] = {
{"debug", 0, NULL, 'd'},
{"help", 0, NULL, 'h'},
{NULL, 0, NULL, 0}
};
struct init_request rq = {
.magic = INIT_MAGIC,
.cmd = 0
};
while ((c = getopt_long (argc, argv, "h?d", long_options, NULL)) != EOF) {
switch(c) {
case 'd':
rq.cmd = INIT_CMD_DEBUG;
break;
case 'h':
case '?':
return usage(0);
default:
return usage(1);
}
}
if (!rq.cmd) {
if (argc < 2) {
fprintf(stderr, "Missing runlevel.\n");
return 1;
}
rq.cmd = INIT_CMD_RUNLVL;
rq.runlevel = (int)argv[1][0];
}
if (!fexist(FINIT_FIFO)) {
fprintf(stderr, "/sbin/init does not support %s!\n", FINIT_FIFO);
return 1;
}
fd = open(FINIT_FIFO, O_WRONLY);
if (-1 == fd) {
perror("Failed opening " FINIT_FIFO);
return 1;
}
write(fd, &rq, sizeof(rq));
close(fd);
return 0;
}
int main(int UNUSED(args), char *argv[])
static void banner(void)
{
delline();
echo("Finit version " VERSION " (" WHOAMI ") " __DATE__ " " __TIME__);
}
int main(int argc, char* argv[])
{
uev_ctx_t ctx;
if (getpid() != 1)
return client(argc, argv);
/*
* Hello world.
*/
banner();
/*
* Initial setup of signals, ignore all until we're up.
*/
sig_init();
/*
* Initalize event context.
*/
uev_init(&ctx);
/*
* Mount base file system, kernel is assumed to run devtmpfs for /dev
*/
@@ -88,8 +167,8 @@ int main(int UNUSED(args), char *argv[])
mount("none", "/proc", "proc", 0, NULL);
mount("none", "/proc/bus/usb", "usbfs", 0, NULL);
mount("none", "/sys", "sysfs", 0, NULL);
mkdir("/dev/pts", 0755);
mkdir("/dev/shm", 0755);
makedir("/dev/pts", 0755);
makedir("/dev/shm", 0755);
mount("none", "/dev/pts", "devpts", 0, "gid=5,mode=620");
mount("none", "/dev/shm", "tmpfs", 0, NULL);
umask(022);
@@ -99,17 +178,10 @@ int main(int UNUSED(args), char *argv[])
*/
parse_kernel_cmdline();
cls();
echo("finit " VERSION " (built " __DATE__ " " __TIME__ " by " WHOAMI ")");
/*
* Populate /dev and prepare for runtime events from kernel.
*/
#if defined(USE_UDEV)
run_interactive("udevd --daemon", "Populating device tree");
#elif defined (MDEV)
run_interactive(MDEV " -s", "Populating device tree");
#endif
run_interactive(SETUP_DEVFS, "Populating device tree");
/*
* Parse configuration file
@@ -121,20 +193,19 @@ int main(int UNUSED(args), char *argv[])
* all services, or service plugins won't have anything to
* hook on to.
*/
print_desc("", "Loading plugins");
print_result(plugin_load_all(PLUGIN_PATH));
print_desc("Loading plugins", NULL);
print_result(plugin_load_all(&ctx, PLUGIN_PATH));
/*
* Mount filesystems
*/
_d("Mount filesystems in /etc/fstab ...");
#ifdef REMOUNT_ROOTFS_RW
run("/bin/mount -n -o remount,rw /");
#endif
#ifdef SYSROOT
run(SYSROOT, "/", NULL, MS_MOVE, NULL);
#endif
_d("Root FS up, calling hooks ...");
plugin_run_hooks(HOOK_ROOTFS_UP);
@@ -146,14 +217,17 @@ int main(int UNUSED(args), char *argv[])
/* Cleanup stale files, if any still linger on. */
run_interactive("rm -rf /tmp/* /var/run/* /var/lock/*", "Cleanup temporary directories");
/*
* Base FS up, enable standard SysV init signals
*/
sig_setup();
/* Base FS up, enable standard SysV init signals */
sig_setup(&ctx);
_d("Base FS up, calling hooks ...");
plugin_run_hooks(HOOK_BASEFS_UP);
/*
* Start all bootstrap tasks, no network available!
*/
svc_bootstrap();
/*
* Network stuff
*/
@@ -162,23 +236,23 @@ int main(int UNUSED(args), char *argv[])
run("/sbin/sysctl -e -p /etc/sysctl.conf >/dev/null");
/* Set initial hostname. */
set_hostname(hostname);
set_hostname(&hostname);
ifconfig("lo", "127.0.0.1", "255.0.0.0", 1);
if (network)
run_interactive(network, "Starting networking: %s", network);
umask(022);
/*
* Hooks that rely on loopback, or basic networking being up.
*/
/* Hooks that rely on loopback, or basic networking being up. */
plugin_run_hooks(HOOK_NETWORK_UP);
/*
* Start service monitor framework
* Start all tasks/services in the configured runlevel
*/
_d("Starting all static services from %s", FINIT_CONF);
svc_start_all();
svc_runlevel(cfglevel);
_d("Running svc up hooks ...");
plugin_run_hooks(HOOK_SVC_UP);
/*
* Run startup scripts in /etc/finit.d/, if any.
@@ -188,20 +262,16 @@ int main(int UNUSED(args), char *argv[])
run_parts(rcsd, NULL);
}
/*
* Hooks that should run at the very end
*/
/* Hooks that should run at the very end */
plugin_run_hooks(HOOK_SYSTEM_UP);
/* Start GETTY on console */
_d("Starting getty on console ...");
run_getty(GETTY, argv);
/* Start TTYs */
tty_runlevel(runlevel);
/*
* Enter main loop to monior /dev/initctl and services
*/
_d("Entering main loop ...");
return run_loop();
return uev_run(&ctx, 0);
}
/**
+32 -7
View File
@@ -1,12 +1,37 @@
# Simple Debian finit.conf
# Sample Debian finit.conf
user admin
host testbed
# Devices to fsck at boot
check /dev/vda1
# Linux kernel modules to load
module button
module evdev
module loop
module psmouse
user admin
host testbed
# Runlevel to start after bootstrap, runlevel 'S'
runlevel 2
# Network bringup script
network service networking start
service /sbin/klogd -n -- Kernel logging server
service /sbin/syslogd -n -- Syslog server
service /usr/sbin/sshd -D -- OpenSSH server
service /usr/sbin/gdm -- GNOME Display Manager
# Virtual consoles to start getty on
tty /dev/tty1
tty /dev/tty2
tty /dev/tty3
# Alternative method instead of runparts
#task [S] /etc/init.d/keyboard-setup start -- Setting up preliminary keymap
#task [S] /etc/init.d/acpid start -- Starting ACPI Daemon
#task [S] /etc/init.d/kbd start -- Preparing console
#run [2] /etc/init.d/networking start -- Start networking
# Services to be monitored and respawned as needed
service [2345] /sbin/klogd -n -- Kernel logging server
service [2345] /sbin/syslogd -n -- Syslog server
service [3] /usr/sbin/gdm -- GNOME Display Manager
# By default Finit looks for /etc/finit.d
# runparts /etc/finit.d
+50 -25
View File
@@ -1,7 +1,7 @@
/* Finit - Extremely fast /sbin/init replacement w/ I/O, hook & service plugins
*
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2012 Joachim Nilsson <troglobit@gmail.com>
* Copyright (c) 2008-2013 Joachim Nilsson <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -27,49 +27,74 @@
#include <errno.h>
#include <fcntl.h>
#include <paths.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
/* Distribution configuration */
/* Distribution specific configuration */
#if defined EMBEDDED_SYSTEM
# define CONSOLE "/dev/console"
# define MDEV "/sbin/mdev"
# define GETTY "/sbin/getty -L 115200 ttyS0 vt100"
# define CONSOLE _PATH_CONSOLE
# define SETUP_DEVFS "/sbin/mdev -s"
# define GETTY "/sbin/getty -L"
# define GETTY_BUSYBOX
# define BAUDRATE 115200
# define RUNLEVEL 2
#else /* Debian/Ubuntu based distributions */
# define RANDOMSEED "/var/lib/urandom/random-seed"
# define CONSOLE "/dev/tty1"
# define GETTY "/sbin/getty -8 38400 tty1"
# define CONSOLE "/dev/tty1"
# define SETUP_DEVFS "/sbin/udevd --daemon"
# define GETTY "/sbin/getty -8"
# define GETTY_AGETTY
# define BAUDRATE 38400
# define RUNLEVEL 2
# define RANDOMSEED "/var/lib/urandom/random-seed"
# define REMOUNT_ROOTFS_RW
# define RUNLEVEL 2
# define USE_UDEV
# define USE_MESSAGE_BUS
# define HAVE_DBUS
#endif
#ifndef FALLBACK_SHELL
# define FALLBACK_SHELL _PATH_BSHELL
#endif
#ifndef DEFUSER
# define DEFUSER "root"
# define DEFUSER "root"
#endif
#ifndef DEFHOST
# define DEFHOST "noname"
# define DEFHOST "noname"
#endif
#define CMD_SIZE 256
#define LINE_SIZE 1024
#define BUF_SIZE 4096
#define USERNAME_SIZE 16
#define HOSTNAME_SIZE 32
#define CMD_SIZE 256
#define LINE_SIZE 1024
#define BUF_SIZE 4096
extern char *sdown;
extern char *network;
extern char *hostname;
extern char *username;
extern char *rcsd;
#define INIT_MAGIC 0x03091969
#define INIT_CMD_RUNLVL 1
#define INIT_CMD_DEBUG 2
struct init_request {
int magic; /* Magic number */
int cmd; /* What kind of request */
int runlevel; /* Runlevel to change to */
int sleeptime; /* Time between TERM and KILL */
char data[368];
};
extern int runlevel;
extern int cfglevel;
extern int prevlevel;
extern char *sdown;
extern char *network;
extern char *hostname;
extern char *username;
extern char *rcsd;
extern char *console;
extern char *__progname;
/* conf.c */
void parse_finit_conf(char *file);
int parse_runlevels (char *runlevels);
int parse_finit_conf (char *file);
#endif /* FINIT_H_ */
+207 -132
View File
@@ -1,7 +1,7 @@
/* Misc. utility functions and C-library extensions for finit and its plugins
*
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2012 Joachim Nilsson <troglobit@gmail.com>
* Copyright (c) 2008-2014 Joachim Nilsson <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -112,7 +112,7 @@ void ifconfig(char *ifname, char *addr, char *mask, int up)
ifr.ifr_flags &= ~IFF_UP;
ioctl(sock, SIOCSIFFLAGS, &ifr);
close(sock);
}
@@ -131,31 +131,31 @@ void ifconfig(char *ifname, char *addr, char *mask, int up)
*/
pid_t pidfile_read(char *pidfile)
{
pid_t pid = 0;
char buf[16];
FILE *fp;
pid_t pid = 0;
char buf[16];
FILE *fp;
if (!pidfile) {
errno = EINVAL;
return -1;
}
if (!pidfile) {
errno = EINVAL;
return -1;
}
if (!fexist(pidfile))
return -1;
if (!fexist(pidfile))
return -1;
fp = fopen(pidfile, "r");
if (!fp)
return -1;
fp = fopen(pidfile, "r");
if (!fp)
return -1;
if (fgets(buf, sizeof(buf), fp)) {
errno = 0;
pid = strtoul(buf, NULL, 0);
if (errno)
pid = 0; /* Failed conversion. */
}
fclose(fp);
if (fgets(buf, sizeof(buf), fp)) {
errno = 0;
pid = (pid_t)strtol(buf, NULL, 10);
if (errno)
pid = 0; /* Failed conversion. */
}
fclose(fp);
return pid;
return pid;
}
/**
@@ -250,21 +250,6 @@ char *pid_get_name(pid_t pid, char *name, size_t len)
return name;
}
/**
* procname_set - Change process name, as seen in process listnings
* @name: New name of process
* @args: The process' argv[] vector.
*/
void procname_set(char *name, char *args[])
{
size_t len = strlen(args[0]) + 1; /* Include terminating '\0' */
prctl(PR_SET_NAME, name, 0, 0, 0);
memset(args[0], 0, len);
strlcpy(args[0], name, len);
}
/**
* procname_kill - Send a signal to a process group by name.
* @name: Name of process to send signal to.
@@ -277,7 +262,7 @@ void procname_set(char *name, char *args[])
* Returns:
* Number of signals sent, i.e. number of processes who have received the signal.
*/
int procname_kill (char *name, int signo)
int procname_kill(char *name, int signo)
{
int result = 0;
char path[32], line[64];
@@ -285,23 +270,26 @@ int procname_kill (char *name, int signo)
DIR *dir;
struct dirent *entry;
dir = opendir("/proc");
if (!dir || !name) {
if (!name) {
errno = EINVAL;
return 0;
}
while ((entry = readdir (dir)) != NULL) {
dir = opendir("/proc");
if (!dir)
return 0;
while ((entry = readdir(dir)) != NULL) {
/* Skip non-process entries in /proc */
if (!isdigit (*entry->d_name))
if (!isdigit(*entry->d_name))
continue;
snprintf (path, sizeof(path), "/proc/%s/status", entry->d_name);
snprintf(path, sizeof(path), "/proc/%s/status", entry->d_name);
/* Skip non-readable files (protected?) */
if ((fp = fopen (path, "r")) == NULL)
if ((fp = fopen(path, "r")) == NULL)
continue;
if (fgets (line, sizeof (line), fp)) {
if (fgets(line, sizeof (line), fp)) {
char *pname = line + 6; /* Skip first part of line --> "Name:\t" */
if (strncmp(pname, name, strlen(pname) - 1) == 0) {
@@ -324,7 +312,7 @@ int procname_kill (char *name, int signo)
}
static int print_uptime(void)
static int print_timestamp(void)
{
#if defined(CONFIG_PRINTK_TIME)
FILE * uptimefile;
@@ -345,34 +333,80 @@ static int print_uptime(void)
return 0;
}
void print_desc(char *action, char *desc)
void print(int action, const char *fmt, ...)
{
const char home[] = "\r\e[K";
char buf[80];
size_t len;
va_list ap;
const char success[] = " \e[1m[ OK ]\e[0m\n";
const char failure[] = " \e[7m[FAIL]\e[0m\n";
const char pending[] = " \e[1m[ \\/ ]\e[0m\n";
const char dots[] = " .....................................................................";
write(STDERR_FILENO, home, strlen(home));
if (fmt) {
va_start(ap, fmt);
len = vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
print_uptime();
delline();
print_timestamp();
write(STDERR_FILENO, action, strlen(action));
write(STDERR_FILENO, desc, strlen(desc));
write(STDERR_FILENO, dots, 60 - strlen(desc) - strlen(action)); /* pad with dots. */
write(STDERR_FILENO, "\r", 1);
write(STDERR_FILENO, buf, len);
write(STDERR_FILENO, dots, 60 - len); /* pad with dots. */
}
switch (action) {
case -1:
break;
case 0:
write(STDERR_FILENO, success, sizeof(success));
break;
case 1:
write(STDERR_FILENO, failure, sizeof(failure));
break;
default:
write(STDERR_FILENO, pending, sizeof(pending));
break;
}
}
void print_desc(char *action, char *desc)
{
print(-1, "%s%s", action ?: "", desc ?: "");
}
int print_result(int fail)
{
if (fail)
fprintf(stderr, " \e[7m[FAIL]\e[0m\n");
else
fprintf(stderr, " \e[1m[ OK ]\e[0m\n");
print(!!fail, NULL);
return fail;
}
/* Wait for process completion, returns status of waitpid(2) syscall */
int complete(char *cmd, int pid)
{
int status = 0;
if (waitpid(pid, &status, 0) == -1) {
if (errno == EINTR)
_e("Caught unblocked signal waiting for %s, aborting.", cmd);
else if (errno == ECHILD)
_e("Caught SIGCHLD waiting for %s, aborting.", cmd);
else
_e("Failed starting %s, error %d: %s", cmd, errno, strerror (errno));
return -1;
}
return status;
}
int run(char *cmd)
{
int status, result, i = 0;
FILE *fp;
char *args[NUM_ARGS + 1], *arg, *backup;
pid_t pid;
@@ -383,7 +417,7 @@ int run(char *cmd)
/* Split command line into tokens of an argv[] array. */
args[i++] = strsep(&arg, "\t ");
do {
while (arg && i < NUM_ARGS) {
/* Handle run("su -c \"dbus-daemon --system\" messagebus");
* => "su", "-c", "\"dbus-daemon --system\"", "messagebus" */
if (*arg == '\'' || *arg == '"') {
@@ -398,7 +432,7 @@ int run(char *cmd)
} else {
args[i++] = strsep(&arg, "\t ");
}
} while (arg && i < NUM_ARGS);
}
args[i] = NULL;
#if 0
_e("Splitting: '%s' =>", cmd);
@@ -412,17 +446,18 @@ int run(char *cmd)
return 1;
}
fp = fopen("/dev/null", "w");
pid = fork();
pid = vfork();
if (0 == pid) {
int i;
FILE *fp;
struct sigaction sa;
/* Reset signal handlers that were set by the parent process */
for (i = 1; i < NSIG; i++)
for (i = 1; i < NSIG; i++)
DFLSIG(sa, i, 0);
/* Redirect stdio if the caller requested so. */
/* Always redirect stdio for run() */
fp = fopen("/dev/null", "w");
if (fp) {
int fd = fileno(fp);
@@ -431,24 +466,20 @@ int run(char *cmd)
dup2(fd, STDERR_FILENO);
}
sig_unblock();
execvp(args[0], args);
_exit(1); /* Only if execv() fails. */
} else if (-1 == pid) {
_pe("%s", args[0]);
free(backup);
return -1;
}
if (waitpid(pid, &status, 0) == -1) {
if (errno == EINTR)
_e("Caught unblocked signal waiting for %s, aborting.", args[0]);
else if (errno == ECHILD)
_e("Caught SIGCHLD waiting for %s, aborting.", args[0]);
else
_e("Failed starting %s, error %d: %s", args[0], errno, strerror (errno));
if (fp) fclose(fp);
status = complete(args[0], pid);
if (-1 == status) {
free(backup);
return 1;
}
@@ -463,7 +494,6 @@ int run(char *cmd)
* change their return code accordingly. --Jocke */
}
if (fp) fclose(fp);
free(backup);
return result;
@@ -474,25 +504,49 @@ int run_interactive(char *cmd, char *fmt, ...)
int status, oldout = 1, olderr = 2;
char line[LINE_SIZE];
va_list ap;
FILE *fp = tmpfile();
FILE *fp;
va_start(ap, fmt);
vsnprintf(line, sizeof(line), fmt, ap);
va_end(ap);
if (!cmd) {
errno = EINVAL;
return 1;
}
print_desc("", line);
if (fmt) {
va_start(ap, fmt);
vsnprintf(line, sizeof(line), fmt, ap);
va_end(ap);
print_desc("", line);
}
/* Redirect output from cmd to a tempfile */
fp = tmpfile();
if (fp && !debug) {
oldout = dup(STDOUT_FILENO);
olderr = dup(STDERR_FILENO);
dup2(fileno(fp), STDOUT_FILENO);
dup2(fileno(fp), STDERR_FILENO);
}
/* Run cmd ... */
status = run(cmd);
/* Restore stderr/stdout */
if (fp && !debug) {
dup2(oldout, STDOUT_FILENO);
dup2(olderr, STDERR_FILENO);
if (oldout >= 0) {
dup2(oldout, STDOUT_FILENO);
close(oldout);
}
if (olderr >= 0) {
dup2(olderr, STDERR_FILENO);
close(olderr);
}
}
print_result(status);
if (fmt)
print_result(status);
/* Dump any results of cmd on stderr after we've printed [ OK ] or [FAIL] */
if (fp && !debug) {
size_t len, written;
@@ -501,65 +555,71 @@ int run_interactive(char *cmd, char *fmt, ...)
len = fread(line, 1, sizeof(line), fp);
written = fwrite(line, len, sizeof(char), stderr);
} while (len > 0 && written == len);
fclose(fp);
}
if (fp)
fclose(fp);
return status;
}
pid_t run_getty(char *cmd, char *argv[])
pid_t run_getty(char *cmd, char *args[], int console)
{
pid_t pid = fork();
pid_t pid = vfork();
if (!pid) {
int i;
int fd;
char c;
sigset_t nmask;
struct sigaction sa;
/* Detach from initial controlling TTY */
vhangup();
if (console) {
/* Detach from initial controlling TTY */
vhangup();
close(2);
close(1);
close(0);
close(STDERR_FILENO);
close(STDOUT_FILENO);
close(STDIN_FILENO);
/* Attach TTY to console */
if (open(CONSOLE, O_RDWR) != 0)
exit(1);
/* Attach TTY to console */
fd = open(CONSOLE, O_RDWR);
if (fd != STDIN_FILENO)
exit(1);
sigemptyset(&nmask);
sigaddset(&nmask, SIGCHLD);
sigprocmask(SIG_UNBLOCK, &nmask, NULL);
dup2(0, STDIN_FILENO);
dup2(0, STDOUT_FILENO);
dup2(0, STDERR_FILENO);
/* Reset signal handlers that were set by the parent process */
for (i = 1; i < NSIG; i++)
DFLSIG(sa, i, 0);
prctl(PR_SET_NAME, "console", 0, 0, 0);
}
dup2(0, STDIN_FILENO);
dup2(0, STDOUT_FILENO);
dup2(0, STDERR_FILENO);
sig_unblock();
procname_set("console", argv);
setsid();
if (ioctl(STDIN_FILENO, TIOCSCTTY, 1) < 0)
_pe("Failed TIOCSCTTY");
while (!fexist(SYNC_SHUTDOWN)) {
static const char msg[] = "\nPlease press Enter to activate this console. ";
static const char msg[] = "\nPlease press Enter to activate this console.";
if (fexist(SYNC_STOPPED)) {
sleep(1);
continue;
}
i = write(STDERR_FILENO, msg, sizeof(msg) - 1);
while (read(STDIN_FILENO, &c, 1) == 1 && c != '\n')
continue;
if (console) {
(void)write(STDERR_FILENO, msg, sizeof(msg));
while (read(STDIN_FILENO, &c, 1) == 1 && c != '\n')
continue;
}
if (fexist(SYNC_STOPPED))
continue;
run(cmd);
execv(cmd, args);
}
if (console)
close(fd);
exit(0);
}
@@ -569,7 +629,7 @@ pid_t run_getty(char *cmd, char *argv[])
int run_parts(char *dir, char *cmd)
{
struct dirent **e;
int i, num;
volatile int i, num;
num = scandir(dir, &e, NULL, alphasort);
if (num < 0) {
@@ -609,9 +669,10 @@ int run_parts(char *dir, char *cmd)
}
args[j++] = NULL;
pid = fork();
pid = vfork();
if (!pid) {
_d("Calling %s ...", path);
sig_unblock();
execv(path, args);
exit(0);
}
@@ -649,34 +710,48 @@ int getgroup(char *group)
* Other convenience functions
*/
void cls(void)
{
static const char cls[] = "\e[2J\e[1;1H";
if (!debug)
fprintf (stderr, "%s", cls);
}
void chomp(char *str)
{
char *x;
char *x = strrchr(str, 0x0a);
if ((x = strchr((str), 0x0a)) != NULL)
if (x)
*x = 0;
}
void set_hostname(char *hostname)
/* Signal safe sleep ... we get a lot of SIGCHLD at reboot */
void do_sleep(unsigned int sec)
{
while ((sec = sleep(sec)))
;
}
void set_hostname(char **hostname)
{
FILE *fp;
_d("Set hostname: %s", hostname);
if ((fp = fopen("/etc/hostname", "r")) != NULL) {
fgets(hostname, HOSTNAME_SIZE, fp);
chomp(hostname);
_d("Set hostname: %s", *hostname);
fp = fopen("/etc/hostname", "r");
if (fp) {
struct stat st;
if (fstat(fileno(fp), &st)) {
fclose(fp);
return;
}
*hostname = realloc(*hostname, st.st_size);
if (!*hostname) {
fclose(fp);
return;
}
fgets(*hostname, st.st_size, fp);
chomp(*hostname);
fclose(fp);
}
sethostname(hostname, strlen(hostname));
if (*hostname)
sethostname(*hostname, strlen(*hostname));
}
/**
+41 -17
View File
@@ -1,7 +1,7 @@
/* Misc. utility functions and C-library extensions for finit and its plugins
*
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2012 Joachim Nilsson <troglobit@gmail.com>
* Copyright (c) 2008-2014 Joachim Nilsson <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -42,7 +42,16 @@
#ifndef touch
# define touch(x) mknod((x), S_IFREG|0644, 0)
# define touch(x) do { if (mknod((x), S_IFREG|0644, 0) && errno != EEXIST) _pe("Failed creating %s", x); } while (0)
#endif
#ifndef makedir
# define makedir(x, p) do { if (mkdir(x, p) && errno != EEXIST) _pe("Failed creating directory %s", x); } while (0)
#endif
#ifndef makefifo
# define makefifo(x, p) do { if (mkfifo(x, p) && errno != EEXIST) _pe("Failed creating FIFO %s", x); } while (0)
#endif
#ifndef erase
# define erase(x) do { if (remove(x) && errno != ENOENT) _pe("Failed removing %s", x); } while (0)
#endif
#ifndef chardev
# define chardev(x,m,maj,min) mknod((x), S_IFCHR|(m), makedev((maj),(min)))
@@ -56,16 +65,32 @@
#ifndef UNUSED
#define UNUSED(x) UNUSED_ ## x __attribute__ ((unused))
#endif
/* Esc[2JEsc[1;1H Clear screen and move cursor to 1,1 (upper left) pos. */
#define clrscr() fputs("\e[2J\e[1;1H", stderr)
/* Esc[K Erases from the current cursor position to the end of the current line. */
#define clreol() fputs("\e[K", stderr)
/* Esc[2K Erases the entire current line. */
#define delline() fputs("\e[2K", stderr)
/* Esc[Line;ColumnH Moves the cursor to the specified position (coordinates) */
#define gotoxy(x,y) fprintf(stderr, "\e[%d;%dH", y, x)
/* Esc[?25l (lower case L) Hide Cursor */
#define hidecursor() fputs("\e[?25l", stderr)
/* Esc[?25h (lower case H) Show Cursor */
#define showcursor() fputs("\e[?25h", stderr)
#define echo(fmt, args...) do { if (verbose) { fprintf(stderr, fmt "\n", ##args); } } while (0)
#define _d(fmt, args...) do { if (debug) { fprintf(stderr, "finit:%s() - " fmt "\n", __func__, ##args); } } while (0)
#define _e(fmt, args...) do { fprintf(stderr, "finit:%s:%s() - " fmt "\n", __FILE__, __func__, ##args); } while (0)
#define _pe(fmt, args...) do { fprintf(stderr, "finit:%s:%s() - " fmt ". Error %d: %s\n", __FILE__, __func__, ##args, errno, strerror(errno)); } while (0)
#define echo(fmt, args...) do { fprintf(stderr, fmt "\n", ##args); } while (0)
#define _d(fmt, args...) do { if (debug) { fprintf(stderr, "finit:%s:%s() - " fmt "\n", __FILE__, __func__, ##args); } } while (0)
#define _e(fmt, args...) do { fprintf(stderr, "finit:%s:%s() - " fmt "\n", __FILE__, __func__, ##args); } while (0)
#define _pe(fmt, args...) do { fprintf(stderr, "finit:%s:%s() - " fmt ". Error %d: %s\n", __FILE__, __func__, ##args, errno, strerror(errno)); } while (0)
#define ISSET(a,i) ((a & (1 << (i)) ? 1 : 0))
#define SETBIT(a,i) (a |= (1 << (i)))
#define CLRBIT(a,i) (a &= ~(1 << (i)))
extern int debug;
extern int verbose;
int makepath (char *path);
int makepath (char *path);
void ifconfig (char *ifname, char *addr, char *mask, int up);
pid_t pidfile_read (char *pidfile);
@@ -77,22 +102,21 @@ char *pid_get_name (pid_t pid, char *name, size_t len);
void procname_set (char *name, char *args[]);
int procname_kill (char *name, int signo);
void print_desc (char *action, char *desc);
void print (int action, const char *fmt, ...);
void print_desc (char *action, char *desc);
int print_result (int fail);
int start_process (char *cmd, char *args[], int console);
void cls (void);
void chomp (char *str);
void chomp (char *str);
void do_sleep (unsigned int sec);
int getuser (char *username);
int getgroup (char *group);
void set_hostname (char *hostname);
int getgroup (char *group);
void set_hostname (char **hostname);
int complete (char *cmd, int pid);
int run (char *cmd);
int run_interactive (char *cmd, char *fmt, ...);
pid_t run_getty (char *cmd, char *argv[]);
int run_parts (char *dir, char *cmd);
/* strlcpy.c */
size_t strlcpy(char *dst, const char *src, size_t siz);
pid_t run_getty (char *cmd, char *args[], int console);
int run_parts (char *dir, char *cmd);
#endif /* FINIT_HELPERS_H_ */
Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

+2 -1
View File
@@ -1,6 +1,6 @@
# Finit libite -- Light-weight utility functions and C-library extensions
#
# Copyright (c) 2008-2012 Joachim Nilsson <troglobit@gmail.com>
# Copyright (c) 2008-2014 Joachim Nilsson <troglobit@gmail.com>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -28,6 +28,7 @@ include ../common.mk
CFLAGS += -fPIC
HEADERS = lite.h
OBJS := copyfile.o dir.o fexist.o fisdir.o fmode.o rsync.o
OBJS += strlcpy.o strlcat.o strtonum.o
DEPS := $(addprefix ., $(OBJS:.o=.d))
VER = 0
+109 -49
View File
@@ -34,13 +34,14 @@
#include "lite.h"
static int __isdir_and_append_filename(char *src, char **dst);
static int adjust_target(char *src, char **dst);
/**
* copyfile - Copy a file to another.
* @src: Source file.
* @dst: Target file.
* @len: Number of bytes to copy, zero (0) for entire file.
* @sym: Should symlinks be recreated (1) or followed (0)
*
* This is a C implementation of the command line cp(1) utility. It is one
* of the classic missing links in the UNIX C library. This version is from
@@ -54,58 +55,70 @@ static int __isdir_and_append_filename(char *src, char **dst);
* may also indicate that @src was empty. If @src is a directory errno
* will be set to %EISDIR since copyfile() is not recursive.
*/
ssize_t copyfile(char *src, char *dst, int len)
ssize_t copyfile(char *src, char *dst, int len, int sym)
{
char *buffer;
int s, d, n, isdir = 0, saved_errno = 0;
ssize_t size = 0;
int in, out, isdir = 0, saved_errno = 0;
ssize_t num, size = 0;
errno = 0; /* Reset before leaving this function. */
// fprintf (stderr, "%s() src: %s, dst: %s, len: %d\n", __func__, src, dst, len);
errno = 0;
buffer = malloc(BUFSIZ);
if (!buffer)
return 0;
if (fisdir(src)) {
errno = EISDIR; /* Error: source is a directory */
return 0;
saved_errno = EISDIR; /* Error: source is a directory */
goto exit;
}
/* Check if target is a directory, then append the src base filename. */
isdir = __isdir_and_append_filename(src, &dst);
/* Check if target is a directory, then append src filename. */
isdir = adjust_target(src, &dst);
/* Len == 0 means copy entire file */
if (len == 0) {
/* XXX: This feels a bit unsafe, but 2047 MiB may be sufficient for us.
* --Jocke 2008-08-11 */
len = INT_MAX;
}
if ((s = open(src, O_RDONLY)) >= 0) {
if ((d =
open(dst, O_WRONLY | O_CREAT | O_TRUNC,
fmode(src))) >= 0) {
do {
int clen = len > BUFSIZ ? BUFSIZ : len;
if ((n = read(s, buffer, clen)) > 0) {
size += write(d, buffer, n);
}
len -= clen;
if (sym) {
size = readlink(src, buffer, BUFSIZ);
if (size > 0) {
if (size >= (ssize_t) BUFSIZ) {
saved_errno = ENOBUFS;
goto exit;
}
while (len > 0 && n == BUFSIZ);
close(d);
} else {
saved_errno = errno;
buffer[size] = 0;
size = !symlink(buffer, dst);
goto exit;
}
close(s);
} else {
saved_errno = errno;
}
/* 0: copy entire file */
if (len == 0)
len = INT_MAX; /* XXX: 2047 MiB should sufficient ... */
in = open(src, O_RDONLY);
if (in < 0) {
saved_errno = errno;
goto exit;
}
out = open(dst, O_WRONLY | O_CREAT | O_TRUNC, fmode(src));
if (out < 0) {
close(in);
saved_errno = errno;
goto exit;
}
do {
int clen = len > BUFSIZ ? BUFSIZ : len;
num = read(in, buffer, clen);
if (num > 0)
size += write(out, buffer, num);
len -= clen;
} while (len > 0 && num == BUFSIZ);
close(out);
close(in);
exit:
free(buffer);
if (isdir)
free(dst);
@@ -135,12 +148,12 @@ int movefile(char *src, char *dst)
int isdir, result = 0;
/* Check if target is a directory, then append the src base filename. */
isdir = __isdir_and_append_filename(src, &dst);
isdir = adjust_target(src, &dst);
if (rename(src, dst)) {
if (errno == EXDEV) {
errno = 0;
copyfile(src, dst, 0);
copyfile(src, dst, 0, 0);
if (errno)
result = 1;
else
@@ -170,26 +183,30 @@ int movefile(char *src, char *dst)
int copy_filep(FILE *src, FILE *dst)
{
int result = 0;
char *buf = (char *)malloc(BUFSIZ);
char *buf;
if (!src || !dst)
return EINVAL;
buf = (char *)malloc(BUFSIZ);
if (!buf)
return errno;
while (1) {
errno = 0;
if (!fgets(buf, BUFSIZ, src)) {
if (errno == EINTR) {
clearerr(src);
continue;
}
if (feof(src))
break;
result = errno;
goto exit;
}
while (EOF == fputs(buf, dst)) {
if (errno == EINTR) {
clearerr(dst);
@@ -201,13 +218,58 @@ int copy_filep(FILE *src, FILE *dst)
}
}
exit:
exit:
free(buf);
return errno = result;
}
/**
* fsendfile - copy data between file streams
* @out: Destination stream
* @in: Source stream
* @sz: Size in bytes to copy.
*
* @out may be NULL, in which case @sz bytes are read and discarded
* from @in. This is useful for streams where seeks are not
* permitted. Additionally @sz may be the special value zero (0) in
* which case fsendfile will copy until EOF is seen on @src.
*
* Returns:
* The number of bytes copied. If there was an error, -1 is returned
* and errno will be set accordingly.
*/
size_t fsendfile (FILE *out, FILE *in, size_t sz)
{
char *buf;
size_t blk = BUFSIZ, num = 0, tot = 0;
buf = (char *)malloc(BUFSIZ);
if (!buf)
return -1;
while (!sz || tot < sz) {
if (sz && ((sz - tot) < BUFSIZ))
blk = sz - tot;
num = fread(buf, 1, blk, in);
if (num == 0)
break;
if (out && (fwrite(buf, num, 1, out) != 1)) {
num = -1;
break;
}
tot += num;
}
free(buf);
return (num == (size_t)-1) ? (size_t)-1 : tot;
}
/* Tests if dst is a directory, if so, reallocates dst and appends src filename returning 1 */
static int __isdir_and_append_filename(char *src, char **dst)
static int adjust_target(char *src, char **dst)
{
int isdir = 0;
@@ -220,7 +282,6 @@ static int __isdir_and_append_filename(char *src, char **dst)
else
ptr++;
// fprintf (stderr, "Yes %s is a dir --> add %s\n", *dst, ptr);
tmp = malloc(strlen(*dst) + strlen(ptr) + 2);
if (!tmp) {
errno = EISDIR;
@@ -232,7 +293,6 @@ static int __isdir_and_append_filename(char *src, char **dst)
sprintf(tmp, "%s%s%s", *dst, slash ? "" : "/", ptr);
*dst = tmp;
// fprintf (stderr, "NEW DST:%s\n", *dst);
}
return isdir;
@@ -253,7 +313,7 @@ int main(int argc, char *argv[])
printf("Copying file %s to %s\n", argv[1], argv[2]);
return copyfile(argv[1], argv[2], 0);
return copyfile(argv[1], argv[2], 0, 0);
}
#else
int main(void)
@@ -284,7 +344,7 @@ int main(void)
if (fexist(files[i + 2]))
fprintf(stderr, "OK => %s\n", files[i + 2]);
remove(files[i + 2]);
erase(files[i + 2]);
i += 3;
}
@@ -292,13 +352,13 @@ int main(void)
i = 0;
while (files[i]) {
fprintf(stderr, "copyfile(%s, %s)\t", files[i], files[i + 1]);
if (!copyfile(files[i], files[i + 1], 0))
if (!copyfile(files[i], files[i + 1], 0, 0))
perror("Failed");
if (fexist(files[i + 2]))
fprintf(stderr, "OK => %s\n", files[i + 2]);
remove(files[i + 2]);
erase(files[i + 2]);
i += 3;
}
@@ -311,7 +371,7 @@ int main(void)
* Local Variables:
* compile-command: "gcc -g -I../include -o unittest -DUNITTEST copyfile.c && ./unittest"
* version-control: t
* kept-new-versions: 2
* c-file-style: "ellemtel"
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+8 -7
View File
@@ -1,6 +1,6 @@
/* Functions for operating on files in directories.
*
* Copyright (c) 2008-2012 Joachim Nilsson <troglobit@gmail.com>
* Copyright (c) 2008-2014 Joachim Nilsson <troglobit@gmail.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -94,7 +94,7 @@ int dir(const char *dir, const char *type, int (*filter) (const char *file), cha
n = scandir(dir, &namelist, matcher, alphasort);
if (n < 0) {
perror("scandir");
} else {
} else if (n > 0) {
files = (char **)malloc(n * sizeof(char *));
for (i = 0; i < n; i++) {
if (files) {
@@ -109,11 +109,12 @@ int dir(const char *dir, const char *type, int (*filter) (const char *file), cha
}
free(namelist[i]);
}
free(namelist);
if (num)
*list = files;
}
if (num)
*list = files;
if (namelist)
free(namelist);
return num;
}
@@ -141,13 +142,13 @@ int simulate_files(int creat)
if (creat)
touch(files[i]);
else
remove(files[i]);
erase(files[i]);
}
if (creat)
symlink("config2.cfg", STARTUP_CONFIG);
else
remove(STARTUP_CONFIG);
erase(STARTUP_CONFIG);
return 0;
}
+43 -2
View File
@@ -1,7 +1,7 @@
/* Collection of utility funcs and C library extensions for finit & its plugins
*
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2012 Joachim Nilsson <troglobit@gmail.com>
* Copyright (c) 2008-2014 Joachim Nilsson <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -29,19 +29,31 @@
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/param.h> /* MAX(), isset(), setbit(), TRUE, FALSE, et consortes. :-) */
#include <unistd.h>
int fexist (char *file);
int fisdir (char *file);
mode_t fmode (char *file);
ssize_t copyfile (char *src, char *dst, int len);
ssize_t copyfile (char *src, char *dst, int len, int sym);
int movefile (char *src, char *dst);
int copy_filep (FILE *src, FILE *dst);
size_t fsendfile (FILE *out, FILE *in, size_t sz);
int dir (const char *dir, const char *type, int (*filter) (const char *file), char ***list, int strip);
int rsync (char *src, char *dst, int delete, int (*filter) (const char *file));
#ifndef strlcpy
size_t strlcpy (char *dst, const char *src, size_t siz);
#endif
#ifndef strlcat
size_t strlcat (char *dst, const char *src, size_t siz);
#endif
#ifndef strtonum
long long strtonum (const char *numstr, long long minval, long long maxval, const char **errstrp);
#endif
static inline int fisslashdir(char *dir)
{
if (!dir) return 0;
@@ -49,6 +61,35 @@ static inline int fisslashdir(char *dir)
return 0;
}
/* Validate string, non NULL and not zero length */
static inline int string_valid (const char *s)
{
return s && strlen (s);
}
/* Relaxed comparison, e.g., sys_string_match("small", "smaller") => TRUE */
static inline int string_match (const char *a, const char *b)
{
size_t min = MIN(strlen (a), strlen (b));
return !strncasecmp (a, b, min);
}
/* Strict comparison, e.g., sys_string_match("small", "smaller") => FALSE */
static inline int string_compare (const char *a, const char *b)
{
return strlen (a) == strlen (b) && !strcmp (a, b);
}
/* Strict comparison, like sys_string_compare(), but case insensitive,
* e.g., sys_string_match("small", "SmAlL") => TRUE
*/
static inline int string_case_compare (const char *a, const char *b)
{
return strlen (a) == strlen (b) && !strcasecmp (a, b);
}
#endif /* FINIT_LITE_H_ */
/**
+52 -30
View File
@@ -27,7 +27,8 @@
#include "lite.h"
#include "../helpers.h"
static int makedir(char *buf, size_t buf_len, char *dir, char *name, mode_t mode);
static int copy(char *src, char *dst);
static int mdir(char *buf, size_t buf_len, char *dir, char *name, mode_t mode);
static int prune(char *dst, char **new_files, int new_num);
@@ -58,21 +59,16 @@ int rsync(char *src, char *dst, int delete, int (*filter) (const char *file))
int i = 0, num = 0, result = 0;
char **files; /* Array of file names. */
void copy(char *src, char *dst)
{
errno = 0;
copyfile(src, dst, 0);
if (errno) result++;
}
if (!fisdir(dst))
mkdir(dst, 0755);
makedir(dst, 0755);
if (!fisdir(src)) {
if (!fexist(src))
return 1;
copy(src, dst);
if (copy(src, dst))
result++;
return errno;
}
@@ -85,7 +81,7 @@ int rsync(char *src, char *dst, int delete, int (*filter) (const char *file))
else
ptr++;
if (makedir(dest, sizeof(dest), dst, ptr, fmode(src)))
if (mdir(dest, sizeof(dest), dst, ptr, fmode(src)))
return 1;
dst = dest;
}
@@ -98,7 +94,7 @@ int rsync(char *src, char *dst, int delete, int (*filter) (const char *file))
char dst2[256];
strcat(source, "/");
if (makedir (dst2, sizeof(dst2), dst, files[i], fmode(source))) {
if (mdir (dst2, sizeof(dst2), dst, files[i], fmode(source))) {
result++;
continue;
}
@@ -106,7 +102,9 @@ int rsync(char *src, char *dst, int delete, int (*filter) (const char *file))
rsync(source, dst2, delete, filter);
continue; /* Next file/dir in @src to copy... */
}
copy(source, dst);
if (copy(source, dst))
result++;
}
/* We ignore any errors from the pruning, that phase albeit useful is only
@@ -123,36 +121,60 @@ int rsync(char *src, char *dst, int delete, int (*filter) (const char *file))
return result;
}
/* Creates dir/name @mode ... skipping / if dir already ends so. */
static int makedir(char *buf, size_t buf_len, char *dir, char *name, mode_t mode)
static int copy(char *src, char *dst)
{
snprintf(buf, buf_len, "%s%s%s/", dir, fisslashdir(dir) ? "" : "/", name);
if (mkdir(buf, mode))
return 1;
errno = 0;
copyfile(src, dst, 0, 1);
if (errno) {
if (errno != EEXIST)
return 1;
errno = 0;
}
return 0;
}
/* Creates dir/name @mode ... skipping / if dir already ends so. */
static int mdir(char *buf, size_t buf_len, char *dir, char *name, mode_t mode)
{
snprintf(buf, buf_len, "%s%s%s/", dir, fisslashdir(dir) ? "" : "/", name);
if (mkdir(buf, mode)) {
if (EEXIST != errno)
return 1;
errno = 0;
}
return 0;
}
static int find(char *file, char **files, int num)
{
int n;
for (n = 0; n < num; n++)
if (!strncmp (files[n], file, MAX(strlen(files[n]), strlen(file))))
return 1;
return 0;
}
/* Prune old files, no longer existing on source, from destination directory. */
static int prune(char *dst, char **new_files, int new_num)
{
int i, num, result = 0;
int num, result = 0;
char **files;
int find(char *file) {
int n;
for (n = 0; n < new_num; n++)
if (!strncmp (new_files[n], file, MAX(strlen(new_files[n]), strlen(file))))
return 1;
return 0;
}
num = dir(dst, "", NULL, &files, 0);
if (num) {
int i;
for (i = 0; i < num; i++) {
if (!find(files[i])) {
if (!find(files[i], new_files, new_num)) {
char *name;
size_t len = strlen(files[i]) + 2 + strlen(dst);
+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:
*/
+3
View File
@@ -19,6 +19,7 @@
#include <sys/types.h>
#include <string.h>
#ifndef strlcpy
/*
* Copy src to string dst of size siz. At most siz-1 characters
* will be copied. Always NUL terminates (unless siz == 0).
@@ -50,6 +51,8 @@ strlcpy(char *dst, const char *src, size_t siz)
return(s - src - 1); /* count does not include NUL */
}
#endif
/**
* Local Variables:
* version-control: t
+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
Submodule
+1
Submodule libuev added at 5c7a6f1163
+22 -56
View File
@@ -36,10 +36,8 @@
#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 char *plugpath = NULL; /* Set by first load. */
static TAILQ_HEAD(, plugin) plugins = TAILQ_HEAD_INITIALIZER(plugins);
static void check_plugin_depends(plugin_t *plugin);
@@ -69,15 +67,8 @@ int plugin_register(plugin_t *plugin)
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++;
if (is_io_plugin(plugin))
inuse++;
}
if (plugin->svc.cb) {
svc_t *svc = svc_find(plugin->name);
@@ -124,9 +115,9 @@ int plugin_unregister(plugin_t *plugin)
}
// _d("Comparing %s against plugin %s", str, p->name);
#define SEARCH_PLUGIN(str) \
PLUGIN_ITERATOR(p, tmp) { \
_d("Comparing %s against plugin %s", str, p->name); \
if (!strcmp(p->name, str)) \
return p; \
}
@@ -159,7 +150,7 @@ plugin_t *plugin_find(char *name)
SEARCH_PLUGIN(name);
if (name[0] != '/') {
if (plugpath && name[0] != '/') {
int noext;
char path[CMD_SIZE];
@@ -189,57 +180,29 @@ void plugin_run_hooks(hook_point_t no)
}
/* Generic libev I/O callback, looks up correct plugin and calls its callback */
static void generic_io_cb(int fd, int events)
static void generic_io_cb(uev_ctx_t *UNUSED(ctx), uev_t *w, void *arg, int events)
{
plugin_t *p, *tmp;
plugin_t *p = (plugin_t *)arg;
/* Find matching plugin, pick first matching fd */
PLUGIN_ITERATOR(p, tmp) {
if (is_io_plugin(p) && p->io.fd == fd) {
_d("Calling I/O %s from runloop...", basename(p->name));
p->io.cb(p->io.arg, fd, events);
break;
}
}
}
if (is_io_plugin(p) && p->io.fd == w->fd) {
_d("Calling I/O %s from runloop...", basename(p->name));
p->io.cb(p->io.arg, w->fd, events);
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].fd, fds[i].revents);
}
break;
/* Update fd, may be changed by plugin callback, e.g., if FIFO */
if (p->io.fd != w->fd)
uev_io_set (w, p->io.fd, p->io.flags);
}
}
/* Setup any I/O callbacks for plugins that use them */
static void init_plugins(void)
static void init_plugins(uev_ctx_t *ctx)
{
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;
uev_io_init(ctx, &p->watcher, generic_io_cb, p, p->io.fd, p->io.flags);
}
}
}
@@ -275,6 +238,9 @@ static int load_one(char *path, char *name)
snprintf(plugin, sizeof(plugin), "%s/%s%s", path, name, noext ? ".so" : "");
_d("Loading plugin %s ...", basename(plugin));
/* Ignore leak, we do not support unloading of plugins atm.
* TODO: Add handle to list of loaded plugins, dlclose() on
* plugin_unregister() */
handle = dlopen(plugin, RTLD_LAZY | RTLD_GLOBAL);
if (!handle) {
_e("Failed loading plugin %s: %s", plugin, dlerror());
@@ -300,9 +266,9 @@ static void check_plugin_depends(plugin_t *plugin)
int i;
for (i = 0; i < PLUGIN_DEP_MAX && plugin->depends[i]; i++) {
_d("Plugin %s depends on %s ...", plugin->name, plugin->depends[i]);
// _d("Plugin %s depends on %s ...", plugin->name, plugin->depends[i]);
if (plugin_find(plugin->depends[i])) {
_d("OK plugin %s was already loaded.", plugin->depends[i]);
// _d("OK plugin %s was already loaded.", plugin->depends[i]);
continue;
}
@@ -310,7 +276,7 @@ static void check_plugin_depends(plugin_t *plugin)
}
}
int plugin_load_all(char *path)
int plugin_load_all(uev_ctx_t *ctx, char *path)
{
int fail = 0;
DIR *dp = opendir(path);
@@ -333,7 +299,7 @@ int plugin_load_all(char *path)
}
closedir(dp);
init_plugins();
init_plugins(ctx);
return fail;
}
+6 -3
View File
@@ -24,13 +24,13 @@
#ifndef FINIT_PLUGIN_H_
#define FINIT_PLUGIN_H_
#include <poll.h>
#include "queue.h" /* BSD sys/queue.h API */
#include "svc.h"
#include "libuev/uev.h"
#define PLUGIN_DEP_MAX 10
#define PLUGIN_IO_READ POLLIN
#define PLUGIN_IO_WRITE POLLOUT
#define PLUGIN_IO_READ UEV_READ
#define PLUGIN_IO_WRITE UEV_WRITE
#define PLUGIN_INIT(x) static void __attribute__ ((constructor)) x(void)
#define PLUGIN_EXIT(x) static void __attribute__ ((destructor)) x(void)
@@ -79,6 +79,9 @@ typedef struct plugin {
/* BSD sys/queue.h linked list node. */
TAILQ_ENTRY(plugin) link;
/* Event loop handler, used internally by Finit */
uev_t watcher;
/* Plugin name, defaults to basename of plugin path if unset.
* NOTE: Must be same as @cmd for service plugins! */
char *name;
+2 -1
View File
@@ -4,8 +4,9 @@ CPPFLAGS += -I..
LDFLAGS := $(filter-out -rdynamic, $(LDFLAGS))
LDFLAGS += -shared
PLUGINS ?= initctl.so alsa-utils.so bootmisc.so dbus.so hwclock.so \
resolvconf.so urandom.so x11-common.so
resolvconf.so urandom.so x11-common.so tty.so
DEPS = $(addprefix .,$(PLUGINS:.so=.d))
TOPDIR ?= $(shell pwd)
include ../common.mk
+21 -22
View File
@@ -39,25 +39,24 @@ static void setup(void *UNUSED(arg))
#endif
_d("Setting up FHS structure in /var ...");
mkdir("/var/cache", 0755);
mkdir("/var/games", 0755);
mkdir("/var/lib", 0755);
mkdir("/var/lib/misc", 0755);
mkdir("/var/lib/alarm", 0755);
mkdir("/var/lock", 0755);
mkdir("/var/log", 0755);
mkdir("/var/mail", 0755);
mkdir("/var/opt", 0755);
mkdir("/var/run", 0755);
mkdir("/var/spool", 0755);
mkdir("/var/spool/cron", 0755);
mkdir("/var/tmp", 0755);
mkdir("/var/empty", 0755);
makedir("/var/cache", 0755);
makedir("/var/games", 0755);
makedir("/var/lib", 0755);
makedir("/var/lib/misc", 0755);
makedir("/var/lib/alarm", 0755);
makedir("/var/lock", 0755);
makedir("/var/log", 0755);
makedir("/var/mail", 0755);
makedir("/var/opt", 0755);
makedir("/var/run", 0755);
makedir("/var/spool", 0755);
makedir("/var/spool/cron", 0755);
makedir("/var/tmp", 0755);
makedir("/var/empty", 0755);
_d("Setting up necessary UTMP files ...");
touch("/var/run/utmp");
chown("/var/run/utmp", 0, getgroup("utmp"));
chmod("/var/run/utmp", 0664);
#ifdef RUNLEVEL
memset(&entry, 0, sizeof(struct utmp));
@@ -71,16 +70,16 @@ static void setup(void *UNUSED(arg))
#ifdef TOUCH_ETC_NETWORK_RUN_IFSTATE
touch("/etc/network/run/ifstate");
#else
remove("/etc/network/run/ifstate");
erase("/etc/network/run/ifstate");
#endif
_d("Setting up misc files ...");
mkdir("/var/run/lldpd", 0755); /* Needed by lldpd */
mkdir("/var/run/pluto", 0755); /* Needed by Openswan */
mkdir("/var/run/quagga", 0755); /* Needed by Quagga */
mkdir("/var/log/quagga", 0755); /* Needed by Quagga */
mkdir("/var/run/sshd", 01755); /* OpenSSH */
mkfifo("/dev/xconsole", 0640); /* sysklogd */
makedir("/var/run/lldpd", 0755); /* Needed by lldpd */
makedir("/var/run/pluto", 0755); /* Needed by Openswan */
makedir("/var/run/quagga", 0755); /* Needed by Quagga */
makedir("/var/log/quagga", 0755); /* Needed by Quagga */
makedir("/var/run/sshd", 01755); /* OpenSSH */
makefifo("/dev/xconsole", 0640); /* sysklogd */
chown("/dev/xconsole", 0, getgroup("tty"));
}
+4 -4
View File
@@ -27,12 +27,12 @@
static void setup(void *UNUSED(arg))
{
#ifdef USE_MESSAGE_BUS
#ifdef HAVE_DBUS
_d("Starting D-Bus ...");
mkdir("/var/run/dbus", 0755);
mkdir("/var/lock/subsys/messagebus", 0755);
makedir("/var/run/dbus", 0755);
makedir("/var/lock/subsys/messagebus", 0755);
run("dbus-uuidgen --ensure");
remove("/var/run/dbus/pid");
erase("/var/run/dbus/pid");
run_interactive("dbus-daemon --system", "Starting D-Bus");
#endif
}
+59 -35
View File
@@ -1,7 +1,7 @@
/* Optional /dev/initctl FIFO monitor
*
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2012 Joachim Nilsson <troglobit@gmail.com>
* Copyright (c) 2008-2014 Joachim Nilsson <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -27,82 +27,106 @@
#include <signal.h>
#include <string.h>
#include <unistd.h> /* read() */
#include <sys/stat.h>
#include "helpers.h"
#include "plugin.h"
#include "sig.h"
#include "finit.h"
#define INIT_MAGIC 0x03091969
#define INIT_CMD_RUNLVL 1
static void parse(void *arg, int fd, int events);
struct init_request {
int magic; /* Magic number */
int cmd; /* What kind of request */
int runlevel; /* Runlevel to change to */
int sleeptime; /* Time between TERM and KILL */
char data[368];
static plugin_t plugin = {
.io = {
.cb = parse,
.flags = PLUGIN_IO_READ,
},
};
static void fifo_open(void)
{
plugin.io.fd = open(FINIT_FIFO, O_RDONLY | O_NONBLOCK);
if (-1 == plugin.io.fd) {
_e("Failed opening %s FIFO, error %d: %s", FINIT_FIFO, errno, strerror(errno));
return;
}
}
/* Standard reboot/shutdown utilities talk to init using /dev/initctl.
* We should check if the fifo was recreated and reopen it.
*/
static void read_initctl(void *UNUSED(arg), int fd, int UNUSED(events))
static void parse(void *UNUSED(arg), int fd, int UNUSED(events))
{
struct init_request request;
struct init_request rq;
_d("Receiving request on %s...", FINIT_FIFO);
while (1) {
ssize_t len = read(fd, &request, sizeof(request));
ssize_t len = read(fd, &rq, sizeof(rq));
if (-1 == len) {
_d("Error %d", errno);
break; /* Probably EAGAIN */
if (len <= 0) {
if (-1 == len) {
if (EINTR == errno)
continue;
if (EAGAIN == errno)
break;
_e("Failed reading initctl request, error %d: %s", errno, strerror(errno));
}
break;
}
if (request.magic != INIT_MAGIC)
continue;
if (rq.magic != INIT_MAGIC || len != sizeof(rq)) {
_e("Invalid initctl request.");
break;
}
_d("Magic OK...");
if (request.cmd == INIT_CMD_RUNLVL) {
switch (request.runlevel) {
if (rq.cmd == INIT_CMD_RUNLVL) {
switch (rq.runlevel) {
case '0':
_d("Halting system (SIGUSR2)");
do_shutdown(SIGUSR2);
break;
case 's':
case 'S':
_d("Cannot enter bootstrap after boot ...");
rq.runlevel = '1';
/* Fall through to regular processing */
case '1'...'5':
case '7'...'9':
_d("Setting new runlevel %c", rq.runlevel);
svc_runlevel(rq.runlevel - '0');
break;
case '6':
_d("Rebooting system (SIGUSR1)");
do_shutdown(SIGUSR1);
break;
default:
_d("Unsupported runlevel: %d", request.runlevel);
_d("Unsupported runlevel: %d", rq.runlevel);
break;
}
} else if (rq.cmd == INIT_CMD_DEBUG) {
debug = !debug;
} else {
_d("Unsupported cmd: %d", request.cmd);
_d("Unsupported cmd: %d", rq.cmd);
}
}
}
static plugin_t plugin = {
.io = {
.cb = read_initctl,
.flags = PLUGIN_IO_READ,
},
};
close(fd);
fifo_open();
}
PLUGIN_INIT(plugin_init)
{
_d("Setting up %s", FINIT_FIFO);
mkfifo(FINIT_FIFO, 0600);
plugin.io.fd = open(FINIT_FIFO, O_RDONLY | O_NONBLOCK);
if (-1 == plugin.io.fd) {
_e("Failed opening %s FIFO, error %d: %s", FINIT_FIFO, errno, strerror(errno));
return;
}
makefifo(FINIT_FIFO, 0600);
fifo_open();
plugin_register(&plugin);
}
+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:
*/
+3 -2
View File
@@ -26,16 +26,17 @@
#include <sys/stat.h>
#include "finit.h"
#include "libite/lite.h"
#include "helpers.h"
#include "plugin.h"
static void setup(void *UNUSED(arg))
{
#ifdef RANDOMSEED
copyfile(RANDOMSEED, "/dev/urandom", 0);
copyfile(RANDOMSEED, "/dev/urandom", 0, 0);
unlink(RANDOMSEED);
umask(077);
copyfile("/dev/urandom", RANDOMSEED, 4096);
copyfile("/dev/urandom", RANDOMSEED, 4096, 0);
umask(0);
#endif
}
+3 -3
View File
@@ -36,7 +36,7 @@ static void setup(void *UNUSED(arg))
#endif
char line[LINE_SIZE];
makepath("/var/run/console");
makedir("/var/run/console", 01777);
snprintf(line, sizeof(line), "/var/run/console/%s", username);
touch(line);
@@ -48,8 +48,8 @@ static void setup(void *UNUSED(arg))
}
#endif
mkdir("/tmp/.X11-unix", 01777);
mkdir("/tmp/.ICE-unix", 01777);
makedir("/tmp/.X11-unix", 01777);
makedir("/tmp/.ICE-unix", 01777);
}
static plugin_t plugin = {
+4 -5
View File
@@ -1,7 +1,7 @@
/* Private header file for main finit daemon, not for plugins
*
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2012 Joachim Nilsson <troglobit@gmail.com>
* Copyright (c) 2008-2013 Joachim Nilsson <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -28,12 +28,11 @@
#include "svc.h"
#include "plugin.h"
void svc_start_all (void);
void svc_monitor (void);
void svc_bootstrap (void);
void svc_monitor (pid_t lost);
void plugin_run_hooks (hook_point_t no);
int plugin_load_all (char *path);
void plugin_monitor (void);
int plugin_load_all (uev_ctx_t *ctx, char *path);
#endif /* FINIT_PRIVATE_H_ */
+83 -3
View File
@@ -1,4 +1,4 @@
/* $OpenBSD: queue.h,v 1.36 2012/04/11 13:29:14 naddy Exp $ */
/* $OpenBSD: queue.h,v 1.38 2013/07/03 15:05:21 fgsch Exp $ */
/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */
/*
@@ -316,6 +316,86 @@ struct { \
(head)->sqh_last = &(elm)->field.sqe_next; \
} while (0)
/*
* XOR Simple queue definitions.
*/
#define XSIMPLEQ_HEAD(name, type) \
struct name { \
struct type *sqx_first; /* first element */ \
struct type **sqx_last; /* addr of last next element */ \
unsigned long sqx_cookie; \
}
#define XSIMPLEQ_ENTRY(type) \
struct { \
struct type *sqx_next; /* next element */ \
}
/*
* XOR Simple queue access methods.
*/
#define XSIMPLEQ_XOR(head, ptr) ((__typeof(ptr))((head)->sqx_cookie ^ \
(unsigned long)(ptr)))
#define XSIMPLEQ_FIRST(head) XSIMPLEQ_XOR(head, ((head)->sqx_first))
#define XSIMPLEQ_END(head) NULL
#define XSIMPLEQ_EMPTY(head) (XSIMPLEQ_FIRST(head) == XSIMPLEQ_END(head))
#define XSIMPLEQ_NEXT(head, elm, field) XSIMPLEQ_XOR(head, ((elm)->field.sqx_next))
#define XSIMPLEQ_FOREACH(var, head, field) \
for ((var) = XSIMPLEQ_FIRST(head); \
(var) != XSIMPLEQ_END(head); \
(var) = XSIMPLEQ_NEXT(head, var, field))
#define XSIMPLEQ_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = XSIMPLEQ_FIRST(head); \
(var) && ((tvar) = XSIMPLEQ_NEXT(head, var, field), 1); \
(var) = (tvar))
/*
* XOR Simple queue functions.
*/
#define XSIMPLEQ_INIT(head) do { \
arc4random_buf(&(head)->sqx_cookie, sizeof((head)->sqx_cookie)); \
(head)->sqx_first = XSIMPLEQ_XOR(head, NULL); \
(head)->sqx_last = XSIMPLEQ_XOR(head, &(head)->sqx_first); \
} while (0)
#define XSIMPLEQ_INSERT_HEAD(head, elm, field) do { \
if (((elm)->field.sqx_next = (head)->sqx_first) == \
XSIMPLEQ_XOR(head, NULL)) \
(head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \
(head)->sqx_first = XSIMPLEQ_XOR(head, (elm)); \
} while (0)
#define XSIMPLEQ_INSERT_TAIL(head, elm, field) do { \
(elm)->field.sqx_next = XSIMPLEQ_XOR(head, NULL); \
*(XSIMPLEQ_XOR(head, (head)->sqx_last)) = XSIMPLEQ_XOR(head, (elm)); \
(head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \
} while (0)
#define XSIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
if (((elm)->field.sqx_next = (listelm)->field.sqx_next) == \
XSIMPLEQ_XOR(head, NULL)) \
(head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \
(listelm)->field.sqx_next = XSIMPLEQ_XOR(head, (elm)); \
} while (0)
#define XSIMPLEQ_REMOVE_HEAD(head, field) do { \
if (((head)->sqx_first = XSIMPLEQ_XOR(head, \
(head)->sqx_first)->field.sqx_next) == XSIMPLEQ_XOR(head, NULL)) \
(head)->sqx_last = XSIMPLEQ_XOR(head, &(head)->sqx_first); \
} while (0)
#define XSIMPLEQ_REMOVE_AFTER(head, elm, field) do { \
if (((elm)->field.sqx_next = XSIMPLEQ_XOR(head, \
(elm)->field.sqx_next)->field.sqx_next) \
== XSIMPLEQ_XOR(head, NULL)) \
(head)->sqx_last = \
XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \
} while (0)
/*
* Tail queue definitions.
*/
@@ -553,12 +633,12 @@ struct { \
#define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \
if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \
CIRCLEQ_END(head)) \
(head).cqh_last = (elm2); \
(head)->cqh_last = (elm2); \
else \
(elm2)->field.cqe_next->field.cqe_prev = (elm2); \
if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \
CIRCLEQ_END(head)) \
(head).cqh_first = (elm2); \
(head)->cqh_first = (elm2); \
else \
(elm2)->field.cqe_prev->field.cqe_next = (elm2); \
_Q_INVALIDATE((elm)->field.cqe_prev); \
+67 -33
View File
@@ -1,7 +1,7 @@
/* Signal management - Be conservative with what finit responds to!
*
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2012 Joachim Nilsson <troglobit@gmail.com>
* Copyright (c) 2008-2014 Joachim Nilsson <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -47,22 +47,28 @@
#include "private.h"
#include "sig.h"
static int stopped = 0;
static int stopped = 0;
static uev_t sigint_watcher, sigpwr_watcher;
static uev_t sigchld_watcher;
static uev_t sigstop_watcher, sigtstp_watcher, sigcont_watcher;
void do_shutdown (int sig)
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);
sleep(1);
/* Call all shutdown hooks, this is the last call before rebooting... */
plugin_run_hooks(HOOK_SHUTDOWN);
/* Wait for WDT to timeout, should be no more than ~1 sec. */
do_sleep(2);
_d("Sending SIGKILL to remaining processes.");
kill(-1, SIGKILL);
@@ -82,40 +88,37 @@ void do_shutdown (int sig)
}
/*
* Shut down on INT USR1 USR2
* Shut down on INT PWR
*/
static void shutdown_handler(int sig, siginfo_t *info, void *UNUSED(ctx))
static void sigint_cb(uev_ctx_t *UNUSED(ctx), uev_t *w, void *UNUSED(arg), int UNUSED(events))
{
_d("Rebooting on signal %d from %s (PID %d)",
sig, pid_get_name(info->si_pid, NULL, 0), info->si_pid);
do_shutdown(sig);
do_shutdown(w->signo);
}
/*
* SIGCHLD: one of our children has died
*/
static void chld_handler(int UNUSED(sig), siginfo_t *UNUSED(info), void *UNUSED(ctx))
static void sigchld_cb(uev_ctx_t *UNUSED(ctx), uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events))
{
/* Do nothing, the svc_monitor() is the designated child reaper. */
svc_monitor(waitpid(-1, NULL, WNOHANG));
}
/*
* SIGSTOP: Paused by user or netflash
* SIGSTOP/SIGTSTP: Paused by user or netflash
*/
static void sigstop_handler(int sig, siginfo_t *info, void *UNUSED(ctx))
static void sigstop_cb(uev_ctx_t *UNUSED(ctx), uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events))
{
_d("Received SIGSTOP(%d) from %s (PID %d)",
sig, pid_get_name(info->si_pid, NULL, 0), info->si_pid);
touch(SYNC_STOPPED);
stopped ++;
stopped++;
}
static void sigcont_handler(int sig, siginfo_t *info, void *UNUSED(ctx))
/*
* SIGCONT: Restart service monitor
*/
static void sigcont_cb(uev_ctx_t *UNUSED(ctx), uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events))
{
_d("Received SIGCONT(%d) from %s (PID %d)",
sig, pid_get_name(info->si_pid, NULL, 0), info->si_pid);
stopped = 0;
remove(SYNC_STOPPED);
erase(SYNC_STOPPED);
}
/*
@@ -129,6 +132,11 @@ int sig_stopped(void)
/*
* Inital signal setup - ignore everything but SIGCHLD until we're capable of responding
*/
static void chld_handler(int UNUSED(sig), siginfo_t *UNUSED(info), void *UNUSED(ctx))
{
/* NOP */
}
void sig_init(void)
{
int i;
@@ -140,26 +148,49 @@ void sig_init(void)
SETSIG(sa, SIGCHLD, chld_handler, SA_RESTART);
}
/*
* Unblock all signals blocked by finit when starting children
*/
void sig_unblock(void)
{
int i;
sigset_t nmask;
struct sigaction sa;
sigemptyset(&nmask);
sigaddset(&nmask, SIGCHLD);
sigaddset(&nmask, SIGINT);
sigaddset(&nmask, SIGPWR);
sigaddset(&nmask, SIGSTOP);
sigaddset(&nmask, SIGTSTP);
sigaddset(&nmask, SIGCONT);
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);
}
/*
* Setup limited set of SysV compatible signals to respond to
*/
void sig_setup(void)
void sig_setup(uev_ctx_t *ctx)
{
struct sigaction sa;
_d("Setup signals");
/* Cleanup any stale finit control files */
remove(SYNC_SHUTDOWN);
remove(SYNC_STOPPED);
erase(SYNC_SHUTDOWN);
erase(SYNC_STOPPED);
/* Standard SysV init calls ctrl-alt-delete handler */
SETSIG(sa, SIGINT, shutdown_handler, 0);
SETSIG(sa, SIGPWR, shutdown_handler, 0);
uev_signal_init(ctx, &sigint_watcher, sigint_cb, NULL, SIGINT);
uev_signal_init(ctx, &sigpwr_watcher, sigint_cb, NULL, SIGPWR);
/* 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);
// uev_signal_init(&ctx, &sigusr1_watcher, reopen_initctl_cb, NULL, SIGUSR1);
// uev_signal_init(&ctx, &sigusr2_watcher, pwrdwn_cb, NULL, SIGUSR2);
/* Init must ignore SIGTERM. May otherwise get false SIGTERM in forked children! */
IGNSIG(sa, SIGTERM, 0);
@@ -170,10 +201,13 @@ void sig_setup(void)
/* We don't have any /etc/inittab yet, reread finit.conf? */
IGNSIG(sa, SIGHUP, 0);
/* After initial bootstrap of Finit we call the service monitor to reap children */
uev_signal_init(ctx, &sigchld_watcher, sigchld_cb, NULL, SIGCHLD);
/* Stopping init is a bit tricky. */
SETSIG(sa, SIGSTOP, sigstop_handler, 0);
SETSIG(sa, SIGTSTP, sigstop_handler, 0);
SETSIG(sa, SIGCONT, sigcont_handler, 0);
uev_signal_init(ctx, &sigstop_watcher, sigstop_cb, NULL, SIGSTOP);
uev_signal_init(ctx, &sigtstp_watcher, sigstop_cb, NULL, SIGTSTP);
uev_signal_init(ctx, &sigcont_watcher, sigcont_cb, NULL, SIGCONT);
/* Disable CTRL-ALT-DELETE from kernel, we handle shutdown gracefully with SIGINT, above */
reboot(RB_DISABLE_CAD);
+4 -2
View File
@@ -1,7 +1,7 @@
/* Signal management - Be conservative with what finit responds to!
*
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2012 Joachim Nilsson <troglobit@gmail.com>
* Copyright (c) 2008-2014 Joachim Nilsson <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -26,6 +26,7 @@
#define FINIT_SIG_H_
#include <signal.h>
#include "libuev/uev.h"
#define SYNC_SHUTDOWN "/var/lock/finit.shutdown"
#define SYNC_STOPPED "/var/lock/finit.stopped"
@@ -57,7 +58,8 @@
void do_shutdown (int sig);
int sig_stopped (void);
void sig_init (void);
void sig_setup (void);
void sig_unblock (void);
void sig_setup (uev_ctx_t *ctx);
#endif /* FINIT_SIG_H_ */
+214 -67
View File
@@ -1,7 +1,7 @@
/* Finit service monitor and heneric API for managing svc_t structures
/* Finit service monitor, task starter and generic API for managing svc_t
*
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2012 Joachim Nilsson <troglobit@gmail.com>
* Copyright (c) 2008-2013 Joachim Nilsson <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -24,17 +24,20 @@
#include <string.h>
#include <sys/wait.h>
#include <utmp.h>
#include "finit.h"
#include "helpers.h"
#include "private.h"
#include "sig.h"
#include "tty.h"
#include "lite.h"
#include "svc.h"
/* The registered services are kept in shared memory for easy read-only access
* by 3rd party APIs. Mostly because of the ability to, from the outside, query
* liveness state of all daemons that should run. */
static int was_stopped = 0;
static int svc_counter = 0; /* Number of registered services to monitor. */
static svc_t *services = NULL; /* List of registered services, in shared memory. */
@@ -122,25 +125,132 @@ svc_t *svc_iterator(int restart)
}
/**
* svc_register - Register a non-backgrounding service to be monitored
* svc_bootstrap - Start bootstrap services and tasks
*
* System startup, runlevel S, where only services, tasks and
* run commands absolutely essential to bootstrap are located.
*/
void svc_bootstrap(void)
{
svc_t *svc;
_d("Bootstrapping all services in runlevel S from %s", FINIT_CONF);
for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
svc_cmd_t cmd = svc_enabled(svc, 0, NULL);
if (SVC_START == cmd || (SVC_RELOAD == cmd))
svc_start(svc);
}
}
static int encode(int lvl)
{
if (!lvl)
return 0;
return lvl + '0';
}
static void utmp_save(int pre, int now)
{
struct utmp utent;
utent.ut_type = RUN_LVL;
utent.ut_pid = (encode(pre) << 8) | (encode(now) & 0xFF);
strlcpy(utent.ut_user, "runlevel", sizeof(utent.ut_user));
setutent();
pututline(&utent);
endutent();
}
/**
* svc_runlevel - Change to a new runlevel
* @newlevel: New runlevel to activate
*
* Stops all services not in @newlevel and starts, or lets continue to run,
* those in @newlevel. Also updates @prevlevel and active @runlevel.
*/
void svc_runlevel(int newlevel)
{
svc_t *svc;
if (runlevel == newlevel)
return;
if (newlevel < 0 || newlevel > 9)
return;
prevlevel = runlevel;
runlevel = newlevel;
utmp_save(prevlevel, newlevel);
for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
int run = svc_enabled(svc, 0, NULL);
if (svc->pid) {
if (run == SVC_STOP)
svc_stop(svc);
else if (run == SVC_RELOAD)
svc_reload(svc);
} else {
if (run == SVC_START)
svc_start(svc);
}
}
if (0 == runlevel) {
do_shutdown(SIGUSR2);
return;
}
if (6 == runlevel) {
do_shutdown(SIGUSR1);
return;
}
if (runlevel == 1)
touch("/etc/nologin"); /* Disable login in single-user mode */
else
erase("/etc/nologin");
if (0 != prevlevel)
tty_runlevel(runlevel);
}
/**
* svc_register - Register service, task or run commands
* @type: %SVC_CMD_SERVICE(0), %SVC_CMD_TASK(1), %SVC_CMD_RUN(2)
* @line: A complete command line with -- separated description text
* @username: Optional username to run service as, or %NULL to run as root
*
* Actually, the @line can optionally start with a username, denoted by
* an @ character. Like this:
* This function is used to register commands to be run on different
* system runlevels with optional username. The @type argument details
* if it's service to bo monitored/respawned (daemon), a one-shot task
* or a command that must run in sequence and not in parallell, like
* service and task commands do.
*
* "service [@username] /path/to/daemon -- Description text"
* The @line can optionally start with a username, denoted by an @
* character. Like this:
*
* The [] brackets means the argument is optional. If the username is
* left out the daemon is started as root.
* "service @username [!0-6,S] /path/to/daemon arg -- Description text"
* "task @username [!0-6,S] /path/to/task arg -- Description text"
* "run @username [!0-6,S] /path/to/cmd arg -- Description text"
*
* If the username is left out the command is started as root.
* The [] brackets are there to denote the allowed runlevels. Allowed
* runlevels mimic that of SysV init with the addition of the 'S'
* runlevel, which is only run once at startup. It can be seen as the
* system bootstrap. If a task or run command is listed in more than the
* [S] runlevel they will be called when changing runlevel.
*
* Returns:
* POSIX OK(0) on success, or non-zero errno exit status on failure.
*/
int svc_register(char *line, char *username)
int svc_register(int type, char *line, char *username)
{
int i = 0;
char *cmd, *desc;
char *cmd, *desc, *runlevels = NULL;
svc_t *svc;
if (!line) {
@@ -159,8 +269,13 @@ int svc_register(char *line, char *username)
return errno = ENOENT;
}
if (cmd[0] == '@') { /* @username */
username = &cmd[1];
while (cmd) {
if (cmd[0] == '@') /* @username */
username = &cmd[1];
else if (cmd[0] == '[') /* [runlevels] */
runlevels = &cmd[0];
else
break;
/* Check if valid command follows... */
cmd = strtok(NULL, " ");
@@ -170,21 +285,28 @@ int svc_register(char *line, char *username)
svc = svc_new();
if (!svc) {
_e("Out of memorym, cannot register service %s", cmd);
_e("Out of memory, cannot register service %s", cmd);
return errno = ENOMEM;
}
svc->type = type;
if (desc)
strlcpy(svc->desc, desc + 3, sizeof(svc->desc));
if (username)
strlcpy(svc->username, username, sizeof(svc->username));
strlcpy(svc->cmd, cmd, sizeof(svc->cmd));
strlcpy(svc->args[i++], cmd, sizeof(svc->args[0]));
strlcpy(svc->cmd, cmd, sizeof(svc->cmd));
strlcpy(svc->args[i++], cmd, sizeof(svc->args[0]));
while ((cmd = strtok(NULL, " ")))
strlcpy(svc->args[i++], cmd, sizeof(svc->args[0]));
svc->args[i][0] = 0;
svc->runlevels = parse_runlevels(runlevels);
_d("Service %s runlevel 0x%2x", svc->cmd, svc->runlevels);
return 0;
}
@@ -210,6 +332,9 @@ svc_cmd_t svc_enabled(svc_t *svc, int event, void *arg)
return SVC_STOP;
}
if (!ISSET(svc->runlevels, runlevel))
return SVC_STOP;
/* Is there a service plugin registered? */
if (svc->cb)
return svc->cb(svc, event, arg);
@@ -225,41 +350,68 @@ static int is_norespawn(void)
fexist("/tmp/norespawn");
}
void svc_monitor(void)
static void restart_any_lost_procs(void)
{
pid_t lost;
svc_t *svc;
lost = waitpid(-1, NULL, WNOHANG);
if (lost < 1)
for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
if (svc->pid > 0 && pid_alive(svc->pid))
continue;
svc_start(svc);
}
}
void svc_monitor(pid_t lost)
{
svc_t *svc;
if (was_stopped && !is_norespawn()) {
was_stopped = 0;
restart_any_lost_procs();
return;
}
if (fexist(SYNC_SHUTDOWN) || lost <= 1)
return;
/* Power user at the console, don't respawn tasks. */
if (is_norespawn())
if (is_norespawn()) {
was_stopped = 1;
return;
}
if (tty_respawn(lost))
return;
for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
char *name = basename(svc->cmd);
if (lost != svc->pid)
continue;
_d("Ouch, lost pid %d - %s(%d)", lost, name, svc->pid);
if (SVC_CMD_SERVICE != svc->type) {
svc->pid = 0;
continue;
}
_d("Ouch, lost pid %d - %s(%d)", lost, basename(svc->cmd), svc->pid);
/* No longer running, update books. */
svc->pid = 0;
if (sig_stopped()) {
_e("Stopped, not respawning killed processes.");
break;
}
/* Cleanup any lingering or semi-restarting tasks before respawning */
_d("Sending SIGTERM to service group %s", name);
procname_kill(name, SIGTERM);
_d("Sending SIGTERM to service group %s", basename(svc->cmd));
procname_kill(basename(svc->cmd), SIGTERM);
/* Restarting lost service. */
if (svc_enabled(svc, 0, NULL))
if (svc_enabled(svc, 0, NULL)) {
svc->restart_counter++;
svc_start(svc);
}
break;
}
@@ -268,13 +420,13 @@ void svc_monitor(void)
/* Remember: svc_enabled() must be called before calling svc_start() */
int svc_start(svc_t *svc)
{
int respawn = svc->pid != 0;
int respawn;
pid_t pid;
sigset_t nmask, omask;
char *args[MAX_NUM_SVC_ARGS];
sigset_t nmask, omask;
if (!svc)
return 0;
respawn = svc->pid != 0;
/* Don't try and start service if it doesn't exist. */
if (!fexist(svc->cmd)) {
@@ -291,27 +443,30 @@ int svc_start(svc_t *svc)
if (is_norespawn())
return 0;
if (!respawn)
if (SVC_CMD_SERVICE != svc->type)
print_desc("", svc->desc);
else if (!respawn)
print_desc("Starting ", svc->desc);
/* Block sigchild while forking. */
sigemptyset(&nmask);
sigaddset(&nmask, SIGCHLD);
sigprocmask(SIG_BLOCK, &nmask, &omask);
/* Block sigchild while forking. */
sigemptyset(&nmask);
sigaddset(&nmask, SIGCHLD);
sigprocmask(SIG_BLOCK, &nmask, &omask);
pid = fork();
sigprocmask(SIG_SETMASK, &omask, NULL);
pid = vfork();
sigprocmask(SIG_SETMASK, &omask, NULL);
if (pid == 0) {
int i = 0;
int uid = getuser(svc->username);
struct sigaction sa;
char *args[MAX_NUM_SVC_ARGS];
sigemptyset(&nmask);
sigaddset(&nmask, SIGCHLD);
sigprocmask(SIG_UNBLOCK, &nmask, NULL);
sigemptyset(&nmask);
sigaddset(&nmask, SIGCHLD);
sigprocmask(SIG_UNBLOCK, &nmask, NULL);
/* Reset signal handlers that were set by the parent process */
for (i = 1; i < NSIG; i++)
for (i = 1; i < NSIG; i++)
DFLSIG(sa, i, 0);
/* Set desired user */
@@ -319,7 +474,7 @@ int svc_start(svc_t *svc)
setuid(uid);
/* Serve copy of args to process in case it modifies them. */
for (i = 0; svc->args[i][0] != 0 && i < MAX_NUM_SVC_ARGS; i++)
for (i = 0; i < (MAX_NUM_SVC_ARGS - 1) && svc->args[i][0] != 0; i++)
args[i] = svc->args[i];
args[i] = NULL;
@@ -327,17 +482,18 @@ int svc_start(svc_t *svc)
int fd;
char buf[CMD_SIZE] = "";
fd = open (CONSOLE, O_WRONLY | O_APPEND);
fd = open(CONSOLE, O_WRONLY | O_APPEND);
if (-1 != fd) {
dup2(STDOUT_FILENO, fd);
dup2(STDERR_FILENO, fd);
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO);
close(fd);
}
for (i = 0; args[i] && i < MAX_NUM_SVC_ARGS; i++) {
for (i = 0; i < MAX_NUM_SVC_ARGS && args[i]; i++) {
char arg[MAX_ARG_LEN];
snprintf(arg, sizeof(arg), "%s ", args[i]);
if ((sizeof(buf) - strlen(buf)) < strlen(arg))
if (strlen(arg) < (sizeof(buf) - strlen(buf)))
strcat(buf, arg);
}
_e("%starting %s: %s", respawn ? "Res" : "S", svc->cmd, buf);
@@ -351,7 +507,9 @@ int svc_start(svc_t *svc)
}
svc->pid = pid;
if (!respawn)
if (SVC_CMD_RUN == svc->type)
print_result(WEXITSTATUS(complete(svc->cmd, pid)));
else if (!respawn)
print_result(svc->pid > 1 ? 0 : 1);
return 0;
@@ -379,14 +537,21 @@ int svc_stop(svc_t *svc)
if (svc->pid <= 1) {
_d("Bad PID %d for %s, SIGTERM", svc->pid, svc->desc);
svc->pid = 0;
svc->restart_counter = 0;
return 1;
}
print_desc("Stopping ", svc->desc);
if (SVC_CMD_SERVICE != svc->type)
return 0;
if (runlevel != 1)
print_desc("Stopping ", svc->desc);
_d("Sending SIGTERM to pid:%d name:'%s'", svc->pid, pid_get_name(svc->pid, NULL, 0));
res = kill(svc->pid, SIGTERM);
print_result(res);
if (runlevel != 1)
print_result(res);
svc->pid = 0;
svc->restart_counter = 0;
return res;
}
@@ -412,24 +577,6 @@ int svc_reload(svc_t *svc)
return kill(svc->pid, SIGHUP);
}
void svc_start_all(void)
{
svc_t *svc;
svc_cmd_t cmd;
for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
cmd = svc_enabled(svc, 0, NULL);
if (SVC_START == cmd || (SVC_RELOAD == cmd && svc->pid == 0))
svc_start(svc);
else if (SVC_RELOAD == cmd)
svc_reload(svc);
}
_d("Running svc up hooks ...");
plugin_run_hooks(HOOK_SVC_UP);
}
/**
* Local Variables:
* compile-command: "gcc -g -DUNITTEST -o unittest svc.c"
+30 -19
View File
@@ -1,7 +1,7 @@
/* Finit service monitor and heneric API for managing svc_t structures
/* Finit service monitor and generic API for managing svc_t structures
*
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2012 Joachim Nilsson <troglobit@gmail.com>
* Copyright (c) 2008-2014 Joachim Nilsson <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -27,6 +27,7 @@
#include <errno.h>
#include <string.h> /* strerror() */
#include <sys/ipc.h> /* IPC_CREAT */
#include <sys/shm.h> /* shmat() */
#include <sys/types.h> /* pid_t */
@@ -36,6 +37,12 @@ typedef enum {
SVC_RELOAD /* Enabled, needs restart */
} svc_cmd_t;
typedef enum {
SVC_CMD_SERVICE = 0, /* Monitored, will be respawned */
SVC_CMD_TASK, /* One-shot, runs in parallell */
SVC_CMD_RUN /* Like task, but wait for completion */
} svc_type_t;
#define FINIT_SHM_ID 0x494E4954 /* "INIT", see ascii(7) */
#define MAX_ARG_LEN 64
#define MAX_STR_LEN 64
@@ -49,20 +56,23 @@ typedef enum {
* initctl <stop|start|restart> service */
typedef struct svc {
pid_t pid;
svc_type_t type;
int reload;
int runlevels;
unsigned int restart_counter; /* Incremented for each restart by service monitor. */
char cmd[MAX_ARG_LEN];
char args[MAX_NUM_SVC_ARGS][MAX_ARG_LEN];
char desc[MAX_STR_LEN];
char username[MAX_USER_LEN];
char username[MAX_USER_LEN];
/* For external plugins. If @cb is set a plugin is loaded.
* @dynamic: Set by plugins that want dynamic events.
* @dynamic: Set by plugins that want dynamic events.
* @dynamic_stop: Set by plugins that allow dyn. events to stop it as well.
* @private: Can be used freely by plugin, e.g., to store "states".
* @private: Can be used freely by plugin, e.g., to store "states".
*/
int dynamic;
int dynamic_stop;
int private;
int dynamic;
int dynamic_stop;
int private;
svc_cmd_t (*cb)(struct svc *svc, int event, void *event_arg);
} svc_t;
@@ -71,11 +81,11 @@ typedef struct svc_map svc_map_t;
/* Put services array in shm */
static inline svc_t *finit_svc_connect(void)
{
const long ID = FINIT_SHM_ID;
static void *ptr = (void *)-1;
if ((void *)-1 == ptr) {
ptr = shmat (shmget (ID, sizeof(svc_t) * MAX_NUM_SVC, 0600 | IPC_CREAT), NULL, 0);
ptr = shmat (shmget (FINIT_SHM_ID, sizeof(svc_t) * MAX_NUM_SVC,
0600 | IPC_CREAT), NULL, 0);
if ((void *)-1 == ptr)
return NULL;
}
@@ -83,17 +93,18 @@ static inline svc_t *finit_svc_connect(void)
return (svc_t *)ptr;
}
svc_t *svc_new (void);
svc_t *svc_find (char *name);
svc_t *svc_iterator (int restart);
svc_t *svc_new (void);
svc_t *svc_find (char *name);
svc_t *svc_iterator (int restart);
void svc_runlevel (int newlevel);
int svc_register (char *line, char *username);
int svc_id_by_name (char *name);
int svc_register (int type, char *line, char *username);
int svc_id_by_name (char *name);
svc_cmd_t svc_enabled (svc_t *svc, int event, void *arg);
int svc_start (svc_t *svc);
int svc_start_by_name (char *name);
int svc_stop (svc_t *svc);
int svc_reload (svc_t *svc);
int svc_start (svc_t *svc);
int svc_start_by_name (char *name);
int svc_stop (svc_t *svc);
int svc_reload (svc_t *svc);
#endif /* FINIT_SVC_H_ */
+226
View File
@@ -0,0 +1,226 @@
/* Finit TTY handling
*
* Copyright (c) 2013 Mattias Walström <lazzer@gmail.com>
* Copyright (c) 2013 Joachim Nilsson <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <signal.h>
#include <sys/wait.h>
#include "finit.h"
#include "helpers.h"
#include "lite.h"
#include "tty.h"
LIST_HEAD(, tty_node) tty_list = LIST_HEAD_INITIALIZER();
/* tty [!1-9,S] <DEV> [BAUD[,BAUD,...]] [TERM] */
int tty_register(char *line)
{
tty_node_t *entry;
int insert = 0, baud = 0;
char *cmd, *dev;
char *runlevels = NULL, *term = NULL;
if (!line) {
_e("Invalid input argument.");
return errno = EINVAL;
}
cmd = strtok(line, " ");
if (!cmd) {
incomplete:
_e("Incomplete tty, cannot register.");
return errno = EINVAL;
}
if (cmd[0] == '[') { /* [runlevels] */
runlevels = &cmd[0];
dev = strtok(NULL, " ");
if (!dev)
goto incomplete;
} else {
dev = cmd;
}
cmd = strtok(NULL, " ");
if (cmd) {
baud = strtonum(cmd, 50, 4000000, NULL);
term = strtok(NULL, " ");
}
entry = tty_find(dev);
if (!entry) {
insert = 1;
entry = calloc(1, sizeof(*entry));
if (!entry)
return errno = ENOMEM;
}
entry->data.name = strdup(dev);
if (!baud)
baud = BAUDRATE;
entry->data.baud = baud;
entry->data.term = term ? strdup(term) : NULL;
entry->data.runlevels = parse_runlevels(runlevels);
_d("Registering tty %s at %d baud with term=%s on runlevels %s", dev, baud, term ?: "N/A", runlevels);
if (insert)
LIST_INSERT_HEAD(&tty_list, entry, link);
return 0;
}
tty_node_t *tty_find(char *dev)
{
tty_node_t *entry;
LIST_FOREACH(entry, &tty_list, link) {
if (!strcmp(dev, entry->data.name))
return entry;
}
return NULL;
}
size_t tty_num(void)
{
size_t num = 0;
tty_node_t *entry;
LIST_FOREACH(entry, &tty_list, link)
num++;
return num;
}
tty_node_t *tty_find_by_pid(pid_t pid)
{
tty_node_t *entry;
LIST_FOREACH(entry, &tty_list, link) {
if (entry->data.pid == pid)
return entry;
}
return NULL;
}
void tty_start(finit_tty_t *tty)
{
int i = 0, is_console = 0;
char *cmd, *arg;
char line[FILENAME_MAX];
char *args[42];
if (tty->pid)
return;
if (console && !strcmp(tty->name, console))
is_console = 1;
if (!strncmp(tty->name, _PATH_DEV, strlen(_PATH_DEV))) {
#if defined(GETTY_AGETTY)
snprintf(line, sizeof(line), "%s %s %d %s", GETTY, tty->name, tty->baud, tty->term ?: "");
#elif defined(GETTY_BUSYBOX)
snprintf(line, sizeof(line), "%s %d %s %s", GETTY, tty->baud, tty->name, tty->term ?: "");
#else
strlcpy(line, FALLBACK_SHELL, sizeof(line));
#endif
} else {
strlcpy(line, tty->name, sizeof(line));
}
cmd = strtok(line, " ");
args[i++] = basename(cmd);
while ((arg = strtok(NULL, " ")))
args[i++] = arg;
args[i] = NULL;
_d("Starting %s: %s on %s", is_console ? "console" : "TTY", cmd, tty->name);
tty->pid = run_getty(cmd, args, is_console);
}
void tty_stop(finit_tty_t *tty)
{
if (!tty->pid)
return;
_d("Stopping TTY %s", tty->name);
kill(tty->pid, SIGTERM);
do_sleep(2);
kill(tty->pid, SIGKILL);
waitpid(tty->pid, NULL, 0);
tty->pid = 0;
}
int tty_enabled(finit_tty_t *tty, int runlevel)
{
if (!tty)
return 0;
if (!ISSET(tty->runlevels, runlevel))
return 0;
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:
*/
+66
View File
@@ -0,0 +1,66 @@
/* Finit TTY handling
*
* Copyright (c) 2013 Mattias Walström <lazzer@gmail.com>
* Copyright (c) 2013 Joachim Nilsson <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef FINIT_TTY_H_
#define FINIT_TTY_H_
#include "queue.h" /* BSD sys/queue.h API */
#define EVENT_SIZE ((sizeof(struct inotify_event) + 20))
typedef struct {
char *name;
int baud;
char *term;
int runlevels;
int pid;
} finit_tty_t;
typedef struct tty_node {
LIST_ENTRY(tty_node) link;
finit_tty_t data;
} tty_node_t;
//extern LIST_HEAD(, tty_node) tty_list;
int tty_register (char *line);
tty_node_t *tty_find (char *dev);
size_t tty_num (void);
tty_node_t *tty_find_by_pid (pid_t pid);
void tty_start (finit_tty_t *tty);
void tty_stop (finit_tty_t *tty);
int tty_enabled (finit_tty_t *tty, int runlevel);
int tty_respawn (pid_t pid);
void tty_runlevel (int runlevel);
#endif /* FINIT_TTY_H_ */
/**
* Local Variables:
* version-control: t
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/