Compare commits

...
9 Commits
Author SHA1 Message Date
Joachim Nilsson 65c9e7ebc6 Fix I/O plugin watcher, load plugins earlier to enable a new early hook!
Restructure start by calling the plugin loader earlier. This makes it
possible to run hooks even earlier.  This also adds a new hook:
HOOK_ROOTFS_UP which runs as soon as the system root (/) is available.

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

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

Makefile:
        Add dependency handling for parallell build
        Add libite library

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

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

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

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

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

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

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

plugin.h:
        Add new HOOK_ROOTFS_UP hook

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

svc.c:
        svc_start(): Dito

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

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

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

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

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

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

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

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

Bump version for upcoming release.

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

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

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

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-09-28 17:26:31 +02:00
27 changed files with 1512 additions and 282 deletions
+12
View File
@@ -1,3 +1,15 @@
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) 1.3 (20120928)
- Cleanup public plugin API a bit and add new pid/pidfile funcs - Cleanup public plugin API a bit and add new pid/pidfile funcs
- Add plugin hook to end of service startup - Add plugin hook to end of service startup
+38 -19
View File
@@ -26,13 +26,15 @@
uninstall-exec uninstall-data uninstall-dev uninstall-exec uninstall-data uninstall-dev
# Top directory for building complete system, fall back to this directory # Top directory for building complete system, fall back to this directory
ROOTDIR ?= $(shell pwd) ROOTDIR = $(shell pwd)
#VERSION ?= $(shell git tag -l | tail -1) #VERSION ?= $(shell git tag -l | tail -1)
VERSION ?= 1.3 VERSION ?= 1.4
EXEC = finit NAME = finit
PKG = $(EXEC)-$(VERSION) PKG = $(NAME)-$(VERSION)
DEV = $(NAME)-dev
ARCHIVE = $(PKG).tar.xz ARCHIVE = $(PKG).tar.xz
EXEC = finit reboot
HEADERS = plugin.h svc.h helpers.h HEADERS = plugin.h svc.h helpers.h
DISTFILES = LICENSE README ChangeLog finit.conf services DISTFILES = LICENSE README ChangeLog finit.conf services
OBJS = finit.o conf.o helpers.o sig.o svc.o plugin.o OBJS = finit.o conf.o helpers.o sig.o svc.o plugin.o
@@ -44,7 +46,8 @@ DEPS = $(addprefix .,$(SRCS:.c=.d))
prefix ?= /usr prefix ?= /usr
sysconfdir ?= /etc sysconfdir ?= /etc
sbindir ?= /sbin sbindir ?= /sbin
plugindir ?= /lib/finit/plugins libdir ?= /lib
plugindir ?= $(libdir)/finit/plugins
incdir = $(prefix)/include/finit incdir = $(prefix)/include/finit
datadir = $(prefix)/share/doc/finit datadir = $(prefix)/share/doc/finit
mandir = $(prefix)/share/man/man8 mandir = $(prefix)/share/man/man8
@@ -57,30 +60,37 @@ FINIT_RCSD ?= $(sysconfdir)/finit.d
CFLAGS += -W -Wall -Werror -Os CFLAGS += -W -Wall -Werror -Os
# Disable annoying gcc warning for "warn_unused_result", see GIT 37af997 # Disable annoying gcc warning for "warn_unused_result", see GIT 37af997
CPPFLAGS += -U_FORTIFY_SOURCE CPPFLAGS += -U_FORTIFY_SOURCE
CPPFLAGS += -D_XOPEN_SOURCE=600 -D_BSD_SOURCE -D_GNU_SOURCE CPPFLAGS += -Ilibite -D_XOPEN_SOURCE=600 -D_BSD_SOURCE -D_GNU_SOURCE
CPPFLAGS += -DVERSION=\"$(VERSION)\" -DWHOAMI=\"`whoami`@`hostname`\" CPPFLAGS += -DVERSION=\"$(VERSION)\" -DWHOAMI=\"`whoami`@`hostname`\"
CPPFLAGS += -DFINIT_FIFO=\"$(FINIT_FIFO)\" -DFINIT_CONF=\"$(FINIT_CONF)\" CPPFLAGS += -DFINIT_FIFO=\"$(FINIT_FIFO)\" -DFINIT_CONF=\"$(FINIT_CONF)\"
CPPFLAGS += -DFINIT_RCSD=\"$(FINIT_RCSD)\" -DPLUGIN_PATH=\"$(plugindir)\" CPPFLAGS += -DFINIT_RCSD=\"$(FINIT_RCSD)\" -DPLUGIN_PATH=\"$(plugindir)\"
LDFLAGS += -rdynamic LDFLAGS += -rdynamic -L$(ROOTDIR)/libite
LDLIBS += -ldl DEPLIBS = libite/libite.so
LDLIBS += -ldl -lite
include common.mk include common.mk
export plugindir ROOTDIR CPPFLAGS export libdir plugindir incdir ROOTDIR CPPFLAGS LDFLAGS LDLIBS
all: Makefile $(EXEC) all: $(DEPLIBS) $(EXEC)
$(MAKE) -C plugins $@ $(MAKE) -C plugins $@
$(DEPLIBS): Makefile
$(MAKE) -C libite all
$(OBJS): Makefile $(OBJS): Makefile
$(EXEC): $(OBJS) finit: $(OBJS) $(DEPLIBS)
reboot: reboot.o $(DEPLIBS)
install-exec: all install-exec: all
@$(INSTALL) -d $(DESTDIR)$(sysconfdir) @$(INSTALL) -d $(DESTDIR)$(FINIT_RCSD)
@$(INSTALL) -d $(DESTDIR)$(sbindir) @$(INSTALL) -d $(DESTDIR)$(sbindir)
@for file in $(EXEC); do \ @for file in $(EXEC); do \
printf " INSTALL $(DESTDIR)$(sbindir)/$$file\n"; \ printf " INSTALL $(DESTDIR)$(sbindir)/$$file\n"; \
$(STRIPINST) $$file $(DESTDIR)$(sbindir)/$$file; \ $(STRIPINST) $$file $(DESTDIR)$(sbindir)/$$file; \
done done
$(MAKE) -C libite install-exec
$(MAKE) -C plugins install $(MAKE) -C plugins install
install-data: install-data:
@@ -97,6 +107,7 @@ install-dev:
printf " INSTALL $(DESTDIR)$(incdir)/$$file\n"; \ printf " INSTALL $(DESTDIR)$(incdir)/$$file\n"; \
$(INSTALL) -m 0644 $$file $(DESTDIR)$(incdir)/$$file; \ $(INSTALL) -m 0644 $$file $(DESTDIR)$(incdir)/$$file; \
done done
$(MAKE) -C libite install-dev install-exec
install: install-exec install-data install-dev install: install-exec install-data install-dev
@@ -106,7 +117,8 @@ uninstall-exec:
rm $(DESTDIR)$(sbindir)/$$file 2>/dev/null; \ rm $(DESTDIR)$(sbindir)/$$file 2>/dev/null; \
done done
-@rmdir $(DESTDIR)$(sbindir) 2>/dev/null -@rmdir $(DESTDIR)$(sbindir) 2>/dev/null
-@rmdir $(DESTDIR)$(sysconfdir) 2>/dev/null -@rmdir $(DESTDIR)$(FINIT_RCSD) 2>/dev/null
$(MAKE) -C libite uninstall
$(MAKE) -C plugins uninstall $(MAKE) -C plugins uninstall
uninstall-data: uninstall-data:
@@ -118,20 +130,18 @@ uninstall-data:
-@rmdir $(DESTDIR)$(datadir) -@rmdir $(DESTDIR)$(datadir)
uninstall-dev: uninstall-dev:
-@for file in $(HEADERS); do \ -@$(RM) -rf $(DESTDIR)$(incdir)
printf " REMOVE $(DESTDIR)$(incdir)/$$file\n"; \
rm $(DESTDIR)$(incdir)/$$file 2>/dev/null; \
done
-@rmdir $(DESTDIR)$(incdir)
uninstall: uninstall-exec uninstall-data uninstall-dev uninstall: uninstall-exec uninstall-data uninstall-dev
clean: clean:
-@$(RM) $(OBJS) $(DEPS) $(EXEC) -@$(RM) $(OBJS) $(DEPS) $(EXEC)
$(MAKE) -C libite $@
$(MAKE) -C plugins $@ $(MAKE) -C plugins $@
distclean: clean distclean: clean
-@$(RM) $(JUNK) unittest *.o -@$(RM) $(JUNK) unittest *.o .*.d
$(MAKE) -C libite $@
$(MAKE) -C plugins $@ $(MAKE) -C plugins $@
dist: dist:
@@ -139,6 +149,15 @@ dist:
git archive --format=tar --prefix=$(PKG)/ $(VERSION) | xz >../$(ARCHIVE) git archive --format=tar --prefix=$(PKG)/ $(VERSION) | xz >../$(ARCHIVE)
@(cd ..; md5sum $(ARCHIVE) | tee $(ARCHIVE).md5) @(cd ..; md5sum $(ARCHIVE) | tee $(ARCHIVE).md5)
dev: distclean
@echo "Building unstable xz $(DEV) in parent dir..."
-@$(RM) -f ../$(DEV).tar.xz*
@(dir=`mktemp -d`; mkdir $$dir/$(DEV); cp -a . $$dir/$(DEV); \
cd $$dir; tar --exclude=.git --exclude=contrib \
-c -J -f $(DEV).tar.xz $(DEV); \
cd - >/dev/null; mv $$dir/$(DEV).tar.xz ../; cd ..; \
rm -rf $$dir; md5sum $(DEV).tar.xz | tee $(DEV).tar.xz.md5)
# Include automatically generated rules, such as: # Include automatically generated rules, such as:
# uncgi.o: .../some/dir/uncgi.c /usr/include/stdio.h # uncgi.o: .../some/dir/uncgi.c /usr/include/stdio.h
# but don't bother during clean! # but don't bother during clean!
+74 -48
View File
@@ -4,19 +4,17 @@
Welcome to finit! Welcome to finit!
This is a heavily extended version of the original /sbin/init replacement This is an extremely fast /sbin/init replacement with focus on small
finit_. The original was a reimplementation of the EeePC "fastinit" daemon embedded GNU/Linux systems. Based on Claudio Matsuoka's original finit_
based on its system calls with gaps filled with frog DNA. 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.
Focus of this extended version is on small embedded GNU/Linux systems and In the world of finit we write C plugins that hook into and extend the
headless miniature servers with a need for extremely fast boot. In such ``main()`` loop of ``/sbin/init``, this is what gives the system its raw
environments configurations rarely change and setup is rather static and performance and the user full control.
straight forward.
In the world of finit we write C "scripts" to boot our system, this is what If you chose finit you know what you want, a fast no hassles boot!
gives the system its raw performance and the user full control.
If you chose finit you know what you want, a fast boot with no hassle.
Features Features
@@ -41,31 +39,35 @@ plugins with either hooks or I/O demands.
/etc/finit.conf /etc/finit.conf
--------------- ---------------
Contrary to most script based init alternatives (SysV init_, upstart_, OpenRC_ Contrary to most script based init alternatives (`SysV init`_, upstart_,
and the likes) finit reads its configuration from /etc/finit.conf, see the OpenRC_ and the likes) finit instead reads its configuration from
source code for available options. ``/etc/finit.conf``, see the source code for available options.
Try out the examples/finit.conf for a Debian 6.0 example configuration When running ``make install`` no default ``/etc/finit.conf`` will be
capable of service monitoring SSH, sysklogd, gdm and a console getty! 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 /etc/finit.d
------------ ------------
At the end of the boot, when networking and all services are up, finit calls At the end of the boot, when networking and all services are up, finit
its built-in run-parts(8) on the /etc/finit.d/ directory, akin to how the calls its built-in run-parts(8) on the ``/etc/finit.d/`` directory, akin
/ec/rc.local file works in most other inits, only finit runs a directory of to how the ``/ec/rc.local`` file works in most other inits, only finit
scripts. This replaces the earlier /usr/sbin/services.sh support of the runs a directory of scripts. This replaces the earlier
original finit_. ``/usr/sbin/services.sh`` support of the original finit_.
Rebooting and Halting Rebooting and Halting
--------------------- ---------------------
Finit handles SIGUSR1 and SIGUSR2 for reboot and halt, and listens to Finit handles SIGUSR1 and SIGUSR2 for reboot and halt, and listens to
/dev/initctl so standard Linux reboot and halt commands should also ``/dev/initctl`` so standard Linux reboot and halt commands should also
work. work.
Building Building
-------- --------
@@ -80,15 +82,8 @@ what is built and where resulting binaries are installed.
**ROOTDIR=** **ROOTDIR=**
Top directory for building complete system, used in pretty printing Top directory for building complete system, used in pretty printing
**PLUGINS=**
List of stock finit plugins to build and install.
**PLUGIN_DIR=**
Absolute path to where finit should look for dynamically loadable plugins
at runtime. At installation prepended by ''DESTDIR'' and ''prefix''-
**VERSION=** **VERSION=**
Defaults to the currently released version of finit, e.g., 1.2 but can 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. be overridden by packages to add a suffix or completely alter the version.
**CFLAGS=** **CFLAGS=**
@@ -104,24 +99,37 @@ what is built and where resulting binaries are installed.
Standard LIBLIBS are inherited from the build enviornmant. Standard LIBLIBS are inherited from the build enviornmant.
**prefix=** **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 Path to where resulting binaries should install to. Used in concert
with the ''DESTDIR'' variable. Defaults to /usr/local with the ``DESTDIR`` variable. Defaults to ``/sbin``
**sysconfdir=** **sysconfdir=**
Used after ''prefix'' to create the path to finit.conf configuration Path to where finit configuration files should install to. Used in
file. Defaults to /etc 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=** **DESTDIR=**
Used by packagers and distributions when building a relocatable Used by packagers and distributions when building a relocatable
bundle of files. Alwawys prepended to the ''prefix'' destination bundle of files. Alwawys prepended to the ``prefix`` destination
directory. directory.
**Example**:: **Example**::
$ tar xfJ finit-1.2.tar.xz $ tar xfJ finit-1.3.tar.xz
$ PLUGINS="initctl.so hwclock.so" prefix= DESTDIR=/tmp/finit/dst \ $ PLUGINS="initctl.so hwclock.so" DESTDIR=/tmp/finit/dst \
make -C finit-1.2/ clean install make -C finit-1.3/ clean install
make: Entering directory `/home/troglobit/finit-1.2' make: Entering directory `/home/troglobit/finit-1.3'
CC finit.o CC finit.o
CC conf.o CC conf.o
CC helpers.o CC helpers.o
@@ -137,25 +145,42 @@ what is built and where resulting binaries are installed.
INSTALL /tmp/finit/dst/sbin/finit INSTALL /tmp/finit/dst/sbin/finit
INSTALL /tmp/finit/dst/lib/finit/plugins/initctl.so INSTALL /tmp/finit/dst/lib/finit/plugins/initctl.so
INSTALL /tmp/finit/dst/lib/finit/plugins/hwclock.so INSTALL /tmp/finit/dst/lib/finit/plugins/hwclock.so
make: Leaving directory `/home/troglobit/finit-1.2' make: Leaving directory `/home/troglobit/finit-1.3'
In this example the finit-1.2.tar.xz archive is unpacked to the user's In this example the `finit-1.3.tar.xz`_ archive is unpacked to the
home directory, built and installed to a temporary staging directory. user's home directory, built and installed to a temporary staging
The enviroment variables ''prefix'', ''DESTDIR'' and ''PLUGINS'' are all directory. The enviroment variables ``DESTDIR`` and ``PLUGINS`` are
changed to suit this particular build. 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 Debugging
--------- ---------
Add finit_debug, or --debug, to the kernel command line to enable trace Add ``finit_debug``, or ``--debug``, to the kernel command line to
messages. A console getty is always started, see the file finit.h for enable trace messages. A console getty is always started, see the file
more useful comile-time tweaks. ``finit.h`` for more useful comile-time tweaks::
init=/sbin/finit --debug
Contact Contact
------- -------
Finit is maintained collaborativly at https://github.com/troglobit/finit — 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 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. proposed extensions, or become a co-maintainer by contacting the main author.
@@ -163,7 +188,8 @@ Regards
/Joachim Nilsson <troglobit@gmail.com> /Joachim Nilsson <troglobit@gmail.com>
.. _finit: http://helllabs.org/finit/ .. _finit: http://helllabs.org/finit/
.. _init: http://savannah.nongnu.org/projects/sysvinit .. _fastinit: http://wiki.eeeuser.com/boot_process:the_boot_process
.. _`SysV init`: http://savannah.nongnu.org/projects/sysvinit
.. _upstart: http://upstart.ubuntu.com/ .. _upstart: http://upstart.ubuntu.com/
.. _openrc: http://www.gentoo.org/proj/en/base/openrc/ .. _openrc: http://www.gentoo.org/proj/en/base/openrc/
.. _`finit-1.3.tar.xz`: http://github.com/downloads/troglobit/finit/finit-1.3.tar.xz
+1 -1
View File
@@ -2,7 +2,7 @@
JUNK = *~ *.bak *.aux *.dvi *.idx *.ind *.log *.ps *.map .*.d DEADJOE semantic.cache *.gdb *.elf core core.* JUNK = *~ *.bak *.aux *.dvi *.idx *.ind *.log *.ps *.map .*.d DEADJOE semantic.cache *.gdb *.elf core core.*
MAKE := @$(MAKE) MAKE := @$(MAKE)
MAKEFLAGS = --no-print-directory --silent MAKEFLAGS = --no-print-directory --silent
INSTALL := install -b INSTALL := install --backup=off
STRIPINST := $(INSTALL) -s --strip-program=$(CROSS)strip -m 0755 STRIPINST := $(INSTALL) -s --strip-program=$(CROSS)strip -m 0755
# Smart autodependecy generation via GCC -M. # Smart autodependecy generation via GCC -M.
+26 -20
View File
@@ -49,6 +49,7 @@ static void parse_kernel_cmdline(void)
if ((fp = fopen("/proc/cmdline", "r")) != NULL) { if ((fp = fopen("/proc/cmdline", "r")) != NULL) {
fgets(line, sizeof(line), fp); fgets(line, sizeof(line), fp);
_d("Kernel command line: %s", line);
if (strstr(line, "finit_debug") || strstr(line, "--debug")) if (strstr(line, "finit_debug") || strstr(line, "--debug"))
debug = 1; debug = 1;
@@ -64,7 +65,7 @@ static int run_loop(void)
{ {
while (1) { while (1) {
svc_monitor(); svc_monitor();
io_monitor(); plugin_monitor();
} }
return 0; return 0;
@@ -91,15 +92,6 @@ int main(int UNUSED(args), char *argv[])
mount("none", "/dev/shm", "tmpfs", 0, NULL); mount("none", "/dev/shm", "tmpfs", 0, NULL);
umask(022); umask(022);
/*
* 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
/* /*
* Parse kernel parameters * Parse kernel parameters
*/ */
@@ -108,11 +100,28 @@ int main(int UNUSED(args), char *argv[])
cls(); cls();
echo("finit " VERSION " (built " __DATE__ " " __TIME__ " by " WHOAMI ")"); 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
/* /*
* Parse configuration file * Parse configuration file
*/ */
parse_finit_conf(FINIT_CONF); parse_finit_conf(FINIT_CONF);
/*
* Load plugins. Must run after finit.conf has registered
* all services, or service plugins won't have anything to
* hook on to.
*/
print_desc("", "Loading plugins");
print_result(plugin_load_all(PLUGIN_PATH));
/* /*
* Mount filesystems * Mount filesystems
*/ */
@@ -124,6 +133,9 @@ int main(int UNUSED(args), char *argv[])
#ifdef SYSROOT #ifdef SYSROOT
run(SYSROOT, "/", NULL, MS_MOVE, NULL); run(SYSROOT, "/", NULL, MS_MOVE, NULL);
#endif #endif
_d("Root FS up, calling hooks ...");
plugin_run_hooks(HOOK_ROOTFS_UP);
umask(0); umask(0);
run("/bin/mount -na"); run("/bin/mount -na");
run("/sbin/swapon -ea"); run("/sbin/swapon -ea");
@@ -137,14 +149,8 @@ int main(int UNUSED(args), char *argv[])
*/ */
sig_setup(); sig_setup();
/* _d("Base FS up, calling hooks ...");
* Load plugins and run first level hooks. plugin_run_hooks(HOOK_BASEFS_UP);
*/
_d("Loading plugins ...");
load_plugins(PLUGIN_PATH);
_d("Running first level hooks ...");
run_hooks(HOOK_BASEFS_UP);
/* /*
* Network stuff * Network stuff
@@ -164,7 +170,7 @@ int main(int UNUSED(args), char *argv[])
/* /*
* Hooks that rely on loopback, or basic networking being up. * Hooks that rely on loopback, or basic networking being up.
*/ */
run_hooks(HOOK_NETWORK_UP); plugin_run_hooks(HOOK_NETWORK_UP);
/* /*
* Start service monitor framework * Start service monitor framework
@@ -181,7 +187,7 @@ int main(int UNUSED(args), char *argv[])
/* /*
* Hooks that should run at the very end * Hooks that should run at the very end
*/ */
run_hooks(HOOK_SYSTEM_UP); plugin_run_hooks(HOOK_SYSTEM_UP);
/* Start GETTY on console */ /* Start GETTY on console */
_d("Starting getty on console ..."); _d("Starting getty on console ...");
-2
View File
@@ -39,14 +39,12 @@
# define CONSOLE "/dev/console" # define CONSOLE "/dev/console"
# define MDEV "/sbin/mdev" # define MDEV "/sbin/mdev"
# define GETTY "/sbin/getty -L 115200 ttyS0 vt100" # define GETTY "/sbin/getty -L 115200 ttyS0 vt100"
# define LISTEN_INITCTL
#else /* Debian/Ubuntu based distributions */ #else /* Debian/Ubuntu based distributions */
# define RANDOMSEED "/var/lib/urandom/random-seed" # define RANDOMSEED "/var/lib/urandom/random-seed"
# define CONSOLE "/dev/tty1" # define CONSOLE "/dev/tty1"
# define GETTY "/sbin/getty -8 38400 tty1" # define GETTY "/sbin/getty -8 38400 tty1"
# define REMOUNT_ROOTFS_RW # define REMOUNT_ROOTFS_RW
# define RUNLEVEL 2 # define RUNLEVEL 2
# define LISTEN_INITCTL
# define USE_UDEV # define USE_UDEV
# define USE_MESSAGE_BUS # define USE_MESSAGE_BUS
#endif #endif
+21 -42
View File
@@ -48,6 +48,7 @@
#include "helpers.h" #include "helpers.h"
#include "private.h" #include "private.h"
#include "sig.h" #include "sig.h"
#include "lite.h"
#define NUM_ARGS 16 #define NUM_ARGS 16
#define NUM_SCRIPTS 128 /* ought to be enough for anyone */ #define NUM_SCRIPTS 128 /* ought to be enough for anyone */
@@ -93,10 +94,14 @@ void ifconfig(char *ifname, char *addr, char *mask, int up)
ifr.ifr_addr.sa_family = AF_INET; ifr.ifr_addr.sa_family = AF_INET;
if (up) { if (up) {
inet_aton(addr, &a->sin_addr); if (addr) {
ioctl(sock, SIOCSIFADDR, &ifr); inet_aton(addr, &a->sin_addr);
inet_aton(mask, &a->sin_addr); ioctl(sock, SIOCSIFADDR, &ifr);
ioctl(sock, SIOCSIFNETMASK, &ifr); }
if (mask) {
inet_aton(mask, &a->sin_addr);
ioctl(sock, SIOCSIFNETMASK, &ifr);
}
} }
ioctl(sock, SIOCGIFFLAGS, &ifr); ioctl(sock, SIOCGIFFLAGS, &ifr);
@@ -112,30 +117,6 @@ void ifconfig(char *ifname, char *addr, char *mask, int up)
} }
void copyfile(char *src, char *dst, int size)
{
char buffer[BUF_SIZE];
int s, d, n;
/* Size == 0 means copy entire file */
if (size == 0)
size = INT_MAX;
if ((s = open(src, O_RDONLY)) >= 0) {
if ((d = open(dst, O_WRONLY | O_CREAT, 0644)) >= 0) {
do {
int csize = size > BUF_SIZE ? BUF_SIZE : size;
if ((n = read(s, buffer, csize)) > 0)
write(d, buffer, n);
size -= csize;
} while (size > 0 && n == BUF_SIZE);
close(d);
}
close(s);
}
}
/** /**
* pidfile_read - Reads a PID value from a pidfile. * pidfile_read - Reads a PID value from a pidfile.
* @pidfile: File containing PID, usually in /var/run/<PROC>.pid * @pidfile: File containing PID, usually in /var/run/<PROC>.pid
@@ -148,7 +129,7 @@ void copyfile(char *src, char *dst, int size)
* be translated this function returns zero (0), on success this function returns * be translated this function returns zero (0), on success this function returns
* a PID value greater than one. PID 1 is reserved for the system init process. * a PID value greater than one. PID 1 is reserved for the system init process.
*/ */
pid_t pidfile_read(const char *pidfile) pid_t pidfile_read(char *pidfile)
{ {
pid_t pid = 0; pid_t pid = 0;
char buf[16]; char buf[16];
@@ -189,7 +170,7 @@ pid_t pidfile_read(const char *pidfile)
* Returns: * Returns:
* The PID read from @path, or zero on timeout. * The PID read from @path, or zero on timeout.
*/ */
pid_t pidfile_poll(char *cmd, const char *path) pid_t pidfile_poll(char *cmd, char *path)
{ {
pid_t pid = 0; pid_t pid = 0;
int tries = 0; int tries = 0;
@@ -275,7 +256,7 @@ char *pid_get_name(pid_t pid, char *name, size_t len)
* @name: New name of process * @name: New name of process
* @args: The process' argv[] vector. * @args: The process' argv[] vector.
*/ */
void procname_set(const char *name, char *args[]) void procname_set(char *name, char *args[])
{ {
size_t len = strlen(args[0]) + 1; /* Include terminating '\0' */ size_t len = strlen(args[0]) + 1; /* Include terminating '\0' */
@@ -296,7 +277,7 @@ void procname_set(const char *name, char *args[])
* Returns: * Returns:
* Number of signals sent, i.e. number of processes who have received the signal. * Number of signals sent, i.e. number of processes who have received the signal.
*/ */
int procname_kill (const char *name, int signo) int procname_kill (char *name, int signo)
{ {
int result = 0; int result = 0;
char path[32], line[64]; char path[32], line[64];
@@ -327,7 +308,7 @@ int procname_kill (const char *name, int signo)
int error = errno; int error = errno;
if (kill(atoi(entry->d_name), signo)) { if (kill(atoi(entry->d_name), signo)) {
ERROR("Failed signalling(%d) %s: %s!", signo, name, strerror(error)); FLOG_ERROR("Failed signalling(%d) %s: %s!", signo, name, strerror(error));
} else { } else {
result++; /* Track number of processes we deliver the signal to. */ result++; /* Track number of processes we deliver the signal to. */
} }
@@ -364,7 +345,7 @@ static int print_uptime(void)
return 0; return 0;
} }
void print_descr(char *action, char *descr) void print_desc(char *action, char *desc)
{ {
const char home[] = "\r\e[K"; const char home[] = "\r\e[K";
const char dots[] = " ....................................................................."; const char dots[] = " .....................................................................";
@@ -374,8 +355,8 @@ void print_descr(char *action, char *descr)
print_uptime(); print_uptime();
write(STDERR_FILENO, action, strlen(action)); write(STDERR_FILENO, action, strlen(action));
write(STDERR_FILENO, descr, strlen(descr)); write(STDERR_FILENO, desc, strlen(desc));
write(STDERR_FILENO, dots, 60 - strlen(descr) - strlen(action)); /* pad with dots. */ write(STDERR_FILENO, dots, 60 - strlen(desc) - strlen(action)); /* pad with dots. */
} }
int print_result(int fail) int print_result(int fail)
@@ -499,7 +480,7 @@ int run_interactive(char *cmd, char *fmt, ...)
vsnprintf(line, sizeof(line), fmt, ap); vsnprintf(line, sizeof(line), fmt, ap);
va_end(ap); va_end(ap);
print_descr("", line); print_desc("", line);
if (fp && !debug) { if (fp && !debug) {
oldout = dup(STDOUT_FILENO); oldout = dup(STDOUT_FILENO);
olderr = dup(STDERR_FILENO); olderr = dup(STDERR_FILENO);
@@ -547,15 +528,13 @@ pid_t run_getty(char *cmd, char *argv[])
if (open(CONSOLE, O_RDWR) != 0) if (open(CONSOLE, O_RDWR) != 0)
exit(1); exit(1);
sigemptyset(&sa.sa_mask);
sa.sa_handler = SIG_DFL;
sigemptyset(&nmask); sigemptyset(&nmask);
sigaddset(&nmask, SIGCHLD); sigaddset(&nmask, SIGCHLD);
sigprocmask(SIG_UNBLOCK, &nmask, NULL); sigprocmask(SIG_UNBLOCK, &nmask, NULL);
for (i = 1; i < NSIG; i++) /* Reset signal handlers that were set by the parent process */
sigaction(i, &sa, NULL); for (i = 1; i < NSIG; i++)
DFLSIG(sa, i, 0);
dup2(0, STDIN_FILENO); dup2(0, STDIN_FILENO);
dup2(0, STDOUT_FILENO); dup2(0, STDOUT_FILENO);
+16 -18
View File
@@ -31,12 +31,14 @@
#define DO_LOG(level, fmt, args...) \ #define DO_LOG(level, fmt, args...) \
{ \ { \
openlog("finit", LOG_CONS | LOG_PID, LOG_DAEMON); \ openlog("finit", LOG_CONS | LOG_PID, LOG_DAEMON); \
syslog(LOG_DEBUG, fmt, ##args); \ syslog(level, fmt, ##args); \
closelog(); \ closelog(); \
} }
#define DEBUG(fmt, args...) DO_LOG(LOG_DEBUG, fmt, ##args) #define FLOG_DEBUG(fmt, args...) DO_LOG(LOG_DEBUG, fmt, ##args)
#define ERROR(fmt, args...) DO_LOG(LOG_CRIT, fmt, ##args) #define FLOG_ERROR(fmt, args...) DO_LOG(LOG_CRIT, fmt, ##args)
#define FLOG_PERROR(fmt, args...) DO_LOG(LOG_CRIT, fmt ". Error %d: %s", ##args, errno, strerror(errno))
#ifndef touch #ifndef touch
# define touch(x) mknod((x), S_IFREG|0644, 0) # define touch(x) mknod((x), S_IFREG|0644, 0)
@@ -47,36 +49,32 @@
#ifndef blkdev #ifndef blkdev
# define blkdev(x,m,maj,min) mknod((x), S_IFBLK|(m), makedev((maj),(min))) # define blkdev(x,m,maj,min) mknod((x), S_IFBLK|(m), makedev((maj),(min)))
#endif #endif
#ifndef fexist
# define fexist(x) (access(x, F_OK) != -1)
#endif
#ifndef UNUSED #ifndef UNUSED
#define UNUSED(x) UNUSED_ ## x __attribute__ ((unused)) #define UNUSED(x) UNUSED_ ## x __attribute__ ((unused))
#endif #endif
#define echo(fmt, args...) do { if (1) { fprintf(stderr, fmt "\n", ##args); } } while (0) #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 _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() - " 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() - " fmt ". Error %d: %s\n", __func__, ##args, errno, strerror(errno)); } 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)
extern int debug; extern int debug;
extern int verbose; extern int verbose;
int makepath (char *path); int makepath (char *path);
void ifconfig (char *ifname, char *addr, char *mask, int up); void ifconfig (char *ifname, char *addr, char *mask, int up);
void copyfile (char *src, char *dst, int size);
pid_t pidfile_read (const char *pidfile); pid_t pidfile_read (char *pidfile);
pid_t pidfile_poll (char *cmd, const char *path); pid_t pidfile_poll (char *cmd, char *path);
int pid_alive (pid_t pid); int pid_alive (pid_t pid);
char *pid_get_name (pid_t pid, char *name, size_t len); char *pid_get_name (pid_t pid, char *name, size_t len);
void procname_set (const char *name, char *args[]); void procname_set (char *name, char *args[]);
int procname_kill (const char *name, int signo); int procname_kill (char *name, int signo);
void print_descr (char *action, char *descr); void print_desc (char *action, char *desc);
int print_result (int fail); int print_result (int fail);
int start_process (char *cmd, char *args[], int console); int start_process (char *cmd, char *args[], int console);
void cls (void); void cls (void);
+79
View File
@@ -0,0 +1,79 @@
# Finit libite -- Light-weight utility functions and C-library extensions
#
# Copyright (c) 2008-2012 Joachim Nilsson <troglobit@gmail.com>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
.EXPORT_ALL_VARIABLES:
.PHONY: all install clean
include ../common.mk
CFLAGS += -fPIC
HEADERS = lite.h
OBJS := copyfile.o dir.o fexist.o fisdir.o fmode.o rsync.o
DEPS := $(addprefix ., $(OBJS:.o=.d))
VER = 0
LIBNAME = libite
TARGET = $(LIBNAME).so
VERLIB = $(TARGET).$(VER)
STATICLIB = $(LIBNAME).a
CHECK_FLAGS = $(CFLAGS) $(CPPFLAGS)
all: $(TARGET)
$(OBJS): Makefile
$(TARGET): $(OBJS)
@printf " LINK %s\n" $@
# @$(AR) $(ARFLAGS) $(STATICLIB) $(OBJS)
@$(CC) $(LDFLAGS) -shared $(OBJS) -lrt -lcrypt -Wl,-soname,$@ -o $@
@ln -sf $@ $(VERLIB)
install-exec: all
@install -d $(DESTDIR)$(libdir)
@echo " INSTALL $(DESTDIR)$(libdir)/$(TARGET)"
@$(STRIPINST) $(TARGET) $(DESTDIR)$(libdir)/$(TARGET)
@ln -sf $(TARGET) $(DESTDIR)$(libdir)/$(VERLIB)
install-dev:
@for file in $(HEADERS); do \
printf " INSTALL $(DESTDIR)$(incdir)/$$file\n"; \
$(INSTALL) -m 0644 $$file $(DESTDIR)$(incdir)/$$file; \
done
install: install-dev install-exec
uninstall:
-@$(RM) $(DESTDIR)$(libdir)/$(VERLIB)
-@$(RM) $(DESTDIR)$(libdir)/$(TARGET)
clean: uninstall
-@$(RM) $(OBJS) $(DEPS) $(TARGET) $(VERLIB) $(STATICLIB)
distclean: clean
-@$(RM) $(JUNK) unittest *.o .*.d *.unittest
ifneq ($(MAKECMDGOALS),clean)
ifneq ($(MAKECMDGOALS),distclean)
-include $(DEPS)
endif
endif
+317
View File
@@ -0,0 +1,317 @@
/* Fastinit (finit) copyfile() implementation.
*
* Copyright (c) 2008 Claudio Matsuoka <http://helllabs.org/finit/>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/param.h> /* MAX(), isset(), setbit(), TRUE, FALSE, et consortes. :-) */
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include "lite.h"
static int __isdir_and_append_filename(char *src, char **dst);
/**
* copyfile - Copy a file to another.
* @src: Source file.
* @dst: Target file.
* @len: Number of bytes to copy, zero (0) for entire file.
*
* This is a C implementation of the command line cp(1) utility. It is one
* of the classic missing links in the UNIX C library. This version is from
* the finit project, http://helllabs.org/finit/, which is a reimplementation
* of fastinit for the Asus EeePC.
*
* Only some small changes to save stack space have been introduced.
*
* Returns:
* The number of bytes copied, zero may be error (check errno!), but it
* may also indicate that @src was empty. If @src is a directory errno
* will be set to %EISDIR since copyfile() is not recursive.
*/
ssize_t copyfile(char *src, char *dst, int len)
{
char *buffer;
int s, d, n, isdir = 0, saved_errno = 0;
ssize_t size = 0;
errno = 0; /* Reset before leaving this function. */
// fprintf (stderr, "%s() src: %s, dst: %s, len: %d\n", __func__, src, dst, len);
buffer = malloc(BUFSIZ);
if (!buffer)
return 0;
if (fisdir(src)) {
errno = EISDIR; /* Error: source is a directory */
return 0;
}
/* Check if target is a directory, then append the src base filename. */
isdir = __isdir_and_append_filename(src, &dst);
/* Len == 0 means copy entire file */
if (len == 0) {
/* XXX: This feels a bit unsafe, but 2047 MiB may be sufficient for us.
* --Jocke 2008-08-11 */
len = INT_MAX;
}
if ((s = open(src, O_RDONLY)) >= 0) {
if ((d =
open(dst, O_WRONLY | O_CREAT | O_TRUNC,
fmode(src))) >= 0) {
do {
int clen = len > BUFSIZ ? BUFSIZ : len;
if ((n = read(s, buffer, clen)) > 0) {
size += write(d, buffer, n);
}
len -= clen;
}
while (len > 0 && n == BUFSIZ);
close(d);
} else {
saved_errno = errno;
}
close(s);
} else {
saved_errno = errno;
}
free(buffer);
if (isdir)
free(dst);
errno = saved_errno;
return size;
}
/**
* movefile - Move a file to another location
* @src: Source file.
* @dst: Target file, or location.
*
* This is a C implementation of the command line mv(1) utility.
* Usually the rename() API is sufficient, but not when moving across
* file system boundaries.
*
* The @src argument must include the full path to the source file,
* whereas the @dst argument may only be a directory, in which case the
* same file name from @src is used.
*
* Returns:
* POSIX OK(0), or non-zero with errno set.
*/
int movefile(char *src, char *dst)
{
int isdir, result = 0;
/* Check if target is a directory, then append the src base filename. */
isdir = __isdir_and_append_filename(src, &dst);
if (rename(src, dst)) {
if (errno == EXDEV) {
errno = 0;
copyfile(src, dst, 0);
if (errno)
result = 1;
else
result = remove(src);
} else {
result = 1;
}
}
if (isdir)
free(dst);
return result;
}
/**
* copy_filep - Copy between FILE *fp.
* @src: Source FILE.
* @dst: Destination FILE.
*
* Function takes signals into account and will restart the syscalls as long
* as error is %EINTR.
*
* Returns:
* POSIX OK(0), or non-zero with errno set on error.
*/
int copy_filep(FILE *src, FILE *dst)
{
int result = 0;
char *buf = (char *)malloc(BUFSIZ);
if (!src || !dst)
return EINVAL;
if (!buf)
return errno;
while (1) {
if (!fgets(buf, BUFSIZ, src)) {
if (errno == EINTR) {
clearerr(src);
continue;
}
if (feof(src))
break;
result = errno;
goto exit;
}
while (EOF == fputs(buf, dst)) {
if (errno == EINTR) {
clearerr(dst);
continue;
}
result = errno;
goto exit;
}
}
exit:
free(buf);
return errno = result;
}
/* Tests if dst is a directory, if so, reallocates dst and appends src filename returning 1 */
static int __isdir_and_append_filename(char *src, char **dst)
{
int isdir = 0;
if (fisdir(*dst)) {
int slash = 0;
char *tmp, *ptr = strrchr(src, '/');
if (!ptr)
ptr = src;
else
ptr++;
// fprintf (stderr, "Yes %s is a dir --> add %s\n", *dst, ptr);
tmp = malloc(strlen(*dst) + strlen(ptr) + 2);
if (!tmp) {
errno = EISDIR;
return 0;
}
isdir = 1; /* Free dst before exit! */
slash = fisslashdir(*dst);
sprintf(tmp, "%s%s%s", *dst, slash ? "" : "/", ptr);
*dst = tmp;
// fprintf (stderr, "NEW DST:%s\n", *dst);
}
return isdir;
}
#ifdef UNITTEST
#include <stdio.h>
/* XXX: Make a real set of unit tests ... */
#if 0
int main(int argc, char *argv[])
{
if (argc < 3) {
fprintf(stderr,
"Usage: %s <src> <dst>\nCopies the <src> file to the <dst> file.\n",
argv[0]);
return 1;
}
printf("Copying file %s to %s\n", argv[1], argv[2]);
return copyfile(argv[1], argv[2], 0);
}
#else
int main(void)
{
int i = 0;
char *files[] = {
"/etc/passwd", "/tmp/tok", "/tmp/tok",
"/etc/passwd", "/tmp/", "/tmp/passwd",
"/etc/passwd", "/tmp", "/tmp/passwd",
NULL
};
FILE *src, *dst;
fprintf(stderr, "\n=>Start testing copy_filep()\n");
while (files[i]) {
fprintf(stderr, "copy_filep(%s, %s)\t", files[i],
files[i + 1]);
src = fopen(files[i], "r");
dst = fopen(files[i + 1], "w");
if (copy_filep(src, dst))
perror("Failed");
if (src)
fclose(src);
if (dst)
fclose(dst);
if (fexist(files[i + 2]))
fprintf(stderr, "OK => %s\n", files[i + 2]);
remove(files[i + 2]);
i += 3;
}
printf("\n\n=>Start testing copyfile()\n");
i = 0;
while (files[i]) {
fprintf(stderr, "copyfile(%s, %s)\t", files[i], files[i + 1]);
if (!copyfile(files[i], files[i + 1], 0))
perror("Failed");
if (fexist(files[i + 2]))
fprintf(stderr, "OK => %s\n", files[i + 2]);
remove(files[i + 2]);
i += 3;
}
return 0;
}
#endif
#endif /* UNITTEST */
/**
* Local Variables:
* compile-command: "gcc -g -I../include -o unittest -DUNITTEST copyfile.c && ./unittest"
* version-control: t
* kept-new-versions: 2
* c-file-style: "ellemtel"
* End:
*/
+228
View File
@@ -0,0 +1,228 @@
/* Functions for operating on files in directories.
*
* Copyright (c) 2008-2012 Joachim Nilsson <troglobit@gmail.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <assert.h>
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static const char *matcher_type = NULL;
static int (*matcher_filter) (const char *file) = NULL;
static int matcher(const struct dirent *entry)
{
char *pos = strrchr(entry->d_name, '.');
if (matcher_filter && !matcher_filter(entry->d_name))
/* User matcher overrides the rest. */
return 0;
/* Skip current dir "." from list of files. */
if ((1 == strlen(entry->d_name) && entry->d_name[0] == '.') ||
(2 == strlen(entry->d_name) && !strcmp(entry->d_name, "..")))
return 0;
/* filetype == "" */
if (matcher_type[0] == 0)
return 1;
/* Entry has no "." */
if (!pos)
return 0;
return !strcmp(pos, matcher_type);
}
/**
* dir - List all files of a certain type in the given directory.
* @dir: Base directory for dir operation.
* @type: File type suffix, e.g. ".cfg".
* @filter: Optional file name filter.
* @list: Pointer to an array of file names.
* @strip: Flag, if set dir() strips the file type.
*
* This function returns a @list of files, matching the @type suffix,
* in the given directory @dir.
*
* The @list argument is a pointer to where to store the dynamically
* allocated list of file names. This list should be free'd by first
* calling free() on each file name and then on the list itself.
*
* If @filter is not %NULL it will be called for each file found. If
* @filter returns non-zero the @file argument will be included in the
* resulting @list. If @filter returns zero for given @file it will
* be discarded.
*
* If the @strip flag is set the resulting @list of files has their
* file type stripped, including the dot. So a match "config0.cfg"
* would be returned as "config0".
*
* Returns:
* Number of files in @list, zero if no matching files of @type.
*/
int dir(const char *dir, const char *type, int (*filter) (const char *file), char ***list, int strip)
{
int i, n, num = 0;
char **files;
struct dirent **namelist;
assert(list);
if (!dir)
/* Assuming current directory */
dir = ".";
if (!type)
/* Assuming all files. */
type = "";
matcher_type = type;
matcher_filter = filter;
n = scandir(dir, &namelist, matcher, alphasort);
if (n < 0) {
perror("scandir");
} else {
files = (char **)malloc(n * sizeof(char *));
for (i = 0; i < n; i++) {
if (files) {
char *name = namelist[i]->d_name;
char *type = strrchr(name, '.');
if (type && strip)
*type = 0;
files[i] = strdup(name);
num++;
}
free(namelist[i]);
}
free(namelist);
}
if (num)
*list = files;
return num;
}
#ifdef UNITTEST
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "otn/c.h"
#define DIR_TYPE_IMAGE ".img"
#define DIR_TYPE_SYSLOG ""
#define DIR_TYPE_CONFIG ".cfg"
#define STARTUP_CONFIG "startup-config.cfg"
int simulate_files(int creat)
{
int i;
char *files[] =
{ "config0.cfg", "config1.cfg", "config2.cfg", "config3.cfg",
"rr109.img", "rx100.img", "rx107.img", "rm957.img", "messages"
};
for (i = 0; i < ARRAY_ELEMENTS(files); i++) {
if (creat)
touch(files[i]);
else
remove(files[i]);
}
if (creat)
symlink("config2.cfg", STARTUP_CONFIG);
else
remove(STARTUP_CONFIG);
return 0;
}
static int cfg_dir_filter(const char *file)
{
/* Skip the STARTUP_CONFIG file, it is a symbolic link to the
* current startup configuration. */
return ! !strcmp(file, STARTUP_CONFIG);
}
int main(int argc, char *argv[])
{
int i, num;
char *type = DIR_TYPE_CONFIG;
char **files;
int once = 1;
int is_startup_config(const char *entry) {
static char file[80];
if (once) {
int len = readlink(STARTUP_CONFIG, file, sizeof(file));
if (len == -1)
return 0;
file[len] = 0;
once = 0; /* Only once per call to dir() */
}
//printf ("Comparing link %s with entry %s\n", file, entry);
return !strcmp(file, entry);
}
simulate_files(1);
if (argc >= 2) {
if (!strcasecmp("CONFIG", argv[1])) {
type = DIR_TYPE_CONFIG;
system("ls -l *" DIR_TYPE_CONFIG);
}
if (!strcasecmp("IMAGE", argv[1])) {
type = DIR_TYPE_IMAGE;
system("ls -l *" DIR_TYPE_IMAGE);
}
if (!strcasecmp("SYSLOG", argv[1])) {
type = DIR_TYPE_SYSLOG;
system("ls -l *");
}
}
num = dir(NULL, type, cfg_dir_filter, &files, 0);
if (num) {
for (i = 0; i < num; i++) {
printf("%s", files[i]);
if (is_startup_config(files[i]))
printf(" --> startup-config");
printf("\n");
free(files[i]);
}
free(files);
}
simulate_files(0);
return 0;
}
#endif /* UNITTEST */
/**
* Local Variables:
* compile-command: "gcc -g -DUNITTEST -o unittest dir.c"
* version-control: t
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+53
View File
@@ -0,0 +1,53 @@
/* Check if file exists
*
* Copyright (c) 2008 Claudio Matsuoka <http://helllabs.org/finit/>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <errno.h>
#include <unistd.h>
/**
* fexist - Check if a file exists in the file system.
* @file: File to look for, with full path.
*
* Returns:
* %TRUE(1) if the file exists, otherwise %FALSE(0).
*/
int fexist(char *file)
{
if (!file) {
errno = EINVAL;
return 0; /* Doesn't exist ... */
}
if (-1 == access(file, F_OK))
return 0;
return 1;
}
/**
* Local Variables:
* version-control: t
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+51
View File
@@ -0,0 +1,51 @@
/* Check if directory exists
*
* Copyright (c) 2008 Claudio Matsuoka <http://helllabs.org/finit/>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
/**
* fexist - Check if a file exists and is a directory.
* @file: File to look for, with full path.
*
* Returns:
* %TRUE(1) if the file exists and is a directory, otherwise %FALSE(0).
*/
int fisdir(char *file)
{
struct stat sb;
if (!stat(file, &sb) && S_ISDIR(sb.st_mode))
return 1;
return 0;
}
/**
* Local Variables:
* version-control: t
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+57
View File
@@ -0,0 +1,57 @@
/* File mode bit operations
*
* Copyright (c) 2008 Claudio Matsuoka <http://helllabs.org/finit/>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
/**
* fmode - Return a file's mode bits.
* @file: File to look for, with full path.
*
* Returns:
* The mode bits or zero when @file does not exist and errno set to %ENOENT.
*/
mode_t fmode(char *file)
{
struct stat sb;
if (!file) {
errno = EINVAL;
return 0; /* Doesn't exist ... */
}
if (!stat(file, &sb))
return sb.st_mode;
return 0;
}
/**
* Local Variables:
* version-control: t
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+61
View File
@@ -0,0 +1,61 @@
/* Collection of utility funcs and C library extensions for finit & its plugins
*
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2012 Joachim Nilsson <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef FINIT_LITE_H_
#define FINIT_LITE_H_
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
int fexist (char *file);
int fisdir (char *file);
mode_t fmode (char *file);
ssize_t copyfile (char *src, char *dst, int len);
int movefile (char *src, char *dst);
int copy_filep (FILE *src, FILE *dst);
int dir (const char *dir, const char *type, int (*filter) (const char *file), char ***list, int strip);
int rsync (char *src, char *dst, int delete, int (*filter) (const char *file));
static inline int fisslashdir(char *dir)
{
if (!dir) return 0;
if (strlen (dir) > 0) return dir[strlen (dir) - 1] == '/';
return 0;
}
#endif /* FINIT_LITE_H_ */
/**
* Local Variables:
* version-control: t
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+280
View File
@@ -0,0 +1,280 @@
/* Micro "rsync" implementation.
*
* Copyright (c) 2011, 2012 Joachim Nilsson <troglobit@gmail.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <errno.h>
#include <stdlib.h> /* NULL, free() */
#include <string.h> /* strlen() */
#include <strings.h> /* rindex() */
#include <stdio.h>
#include <sys/param.h> /* MAX(), isset(), setbit(), TRUE, FALSE, et consortes. :-) */
#include <sys/stat.h>
#include <sys/types.h>
#include "lite.h"
#include "../helpers.h"
static int makedir(char *buf, size_t buf_len, char *dir, char *name, mode_t mode);
static int prune(char *dst, char **new_files, int new_num);
/**
* rsync - Synchronize contents and optionally remove non-existing backups
* @src: Source directory
* @dst: Destination directory
* @delete: Prune files from @dst that no longer exist in @src.
* @filter: Optional filtering function for source directory.
*
* This is a miniature implementation of the famous rsync for local use only.
* In fact, it is not even a true rsync since it copies all files from @src
* to @dst. The @delete option is useful for creating backups, when set all
* files removed from src since last backup are pruned from the destination
* (backup) directory.
*
* The filter callback, @filter, if provided, is used to determine what files to
* include from the source directory when backing up. If a file is to be skipped
* the callback should simply return zero.
*
* Returns:
* POSIX OK(0), or non-zero with @errno set on error.
*/
int rsync(char *src, char *dst, int delete, int (*filter) (const char *file))
{
char source[256];
char dest[256];
int i = 0, num = 0, result = 0;
char **files; /* Array of file names. */
void copy(char *src, char *dst)
{
errno = 0;
copyfile(src, dst, 0);
if (errno) result++;
}
if (!fisdir(dst))
mkdir(dst, 0755);
if (!fisdir(src)) {
if (!fexist(src))
return 1;
copy(src, dst);
return errno;
}
/* Copy dir as well? */
if (!fisslashdir(src)) {
char *ptr = rindex(src, '/');
if (!ptr)
ptr = src;
else
ptr++;
if (makedir(dest, sizeof(dest), dst, ptr, fmode(src)))
return 1;
dst = dest;
}
num = dir(src, "", filter, &files, 0);
for (i = 0; i < num; i++) {
/* Recursively copy sub-directries */
snprintf(source, sizeof(source), "%s%s%s", src, fisslashdir(src) ? "" : "/", files[i]);
if (fisdir(source)) {
char dst2[256];
strcat(source, "/");
if (makedir (dst2, sizeof(dst2), dst, files[i], fmode(source))) {
result++;
continue;
}
rsync(source, dst2, delete, filter);
continue; /* Next file/dir in @src to copy... */
}
copy(source, dst);
}
/* We ignore any errors from the pruning, that phase albeit useful is only
* cosmetic. --Jocke 2011-03-24 */
if (delete)
prune(dst, files, num);
if (num) {
for (i = 0; i < num; i++)
free(files[i]);
free(files);
}
return result;
}
/* Creates dir/name @mode ... skipping / if dir already ends so. */
static int makedir(char *buf, size_t buf_len, char *dir, char *name, mode_t mode)
{
snprintf(buf, buf_len, "%s%s%s/", dir, fisslashdir(dir) ? "" : "/", name);
if (mkdir(buf, mode))
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;
char **files;
int find(char *file) {
int n;
for (n = 0; n < new_num; n++)
if (!strncmp (new_files[n], file, MAX(strlen(new_files[n]), strlen(file))))
return 1;
return 0;
}
num = dir(dst, "", NULL, &files, 0);
if (num) {
for (i = 0; i < num; i++) {
if (!find(files[i])) {
char *name;
size_t len = strlen(files[i]) + 2 + strlen(dst);
name = malloc(len);
if (name) {
snprintf(name, len, "%s%s%s", dst, fisslashdir(dst) ? "" : "/", files[i]);
if (remove(name))
result++;
free(name);
}
}
free(files[i]);
}
free(files);
}
return result;
}
#ifdef UNITTEST
#define BASE "/tmp/.unittest/"
#define SRC BASE "src/"
#define DST BASE "dst/"
char *files[] = {
SRC "sub1/1.tst",
SRC "sub1/2.tst",
SRC "sub1/3.tst",
SRC "sub2/4.tst",
SRC "sub2/5.tst",
SRC "sub2/6.tst",
SRC "sub3/7.tst",
SRC "sub3/8.tst",
SRC "sub3/9.tst",
NULL
};
void cleanup_test(void)
{
system("rm -rf " BASE);
}
void setup_test(void)
{
int i;
char cmd[256];
mode_t dir_modes[] = { 755, 700 };
mode_t file_modes[] = { 644, 600 };
cleanup_test();
mkdir(BASE, 0755);
mkdir(SRC, 0755);
mkdir(DST, 0755);
for (i = 0; files[i]; i++) {
snprintf(cmd, sizeof(cmd), "mkdir -m %d -p `dirname %s`",
dir_modes[i % 2], files[i]);
system(cmd);
snprintf(cmd, sizeof(cmd), "touch %s; chmod %d %s", files[i],
file_modes[i % 2], files[i]);
system(cmd);
}
}
int run_test()
{
#if 0
setup_test();
puts("Before:");
system("tree -np " BASE);
rsync(SRC, DST, 0, NULL);
puts("After:");
system("tree -np " BASE);
cleanup_test();
#endif
setup_test();
rsync(BASE "src", DST, 0, NULL);
puts("Only partial rsync of src <-- No slash!");
system("tree -np " BASE);
#if 0
cleanup_test();
setup_test();
rsync(BASE "src/sub1", BASE "dst", 0, NULL);
puts("Only partial rsync of src/sub1 <-- No slashes!!");
system("tree -np " BASE);
cleanup_test();
setup_test();
rsync(BASE "src/sub1/", DST, 0, NULL);
puts("Only partial rsync of src/sub1/");
system("tree -np " BASE);
cleanup_test();
setup_test();
rsync(BASE "src/sub1", DST, 0, NULL);
puts("Only partial rsync of src/sub1 <-- No slash!");
system("tree -np " BASE);
rsync("/etc", "/var/tmp", 0, NULL);
puts("Real life test:");
system("tree -np /var/tmp");
#endif
return 0;
}
int main(int argc, char *argv[])
{
atexit(cleanup_test);
return run_test();
}
#endif /* UNITTEST */
/**
* Local Variables:
* compile-command: "make -f rsync.mk"
* version-control: t
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+22
View File
@@ -0,0 +1,22 @@
# Unittest makefile for rsync.c
.PHONY: clean
SRC = rsync.c
OBJS = dir.o copyfile.o fexist.o fisdir.o fmode.o
UNIT = rsync.unittest
#CPPFLAGS = -DDEBUG -I../../.. -I../../include
all: build run
clean:
@rm -f $(OBJS) $(UNIT)
# This rule also forces a cleanup of built objects to not leave any object files
# lingering in the tree to interfere with cross builds.
build: clean $(OBJS)
$(CC) $(CFLAGS) $(CPPFLAGS) -o $(UNIT) -DUNITTEST $(SRC) $(OBJS)
@rm -f $(OBJS)
run:
@./$(UNIT)
+39 -33
View File
@@ -32,7 +32,6 @@
#include "private.h" #include "private.h"
#include "helpers.h" #include "helpers.h"
#include "plugin.h" #include "plugin.h"
#include "svc.h"
#define is_io_plugin(p) ((p)->io.cb && (p)->io.fd >= 0) #define is_io_plugin(p) ((p)->io.cb && (p)->io.fd >= 0)
@@ -42,7 +41,7 @@ static LIST_HEAD(, plugin) plugins = LIST_HEAD_INITIALIZER();
int plugin_register(plugin_t *plugin) int plugin_register(plugin_t *plugin)
{ {
int inuse = 0; int i, inuse = 0;
if (!plugin) { if (!plugin) {
errno = EINVAL; errno = EINVAL;
@@ -69,17 +68,23 @@ int plugin_register(plugin_t *plugin)
} }
if (plugin->svc.cb) { if (plugin->svc.cb) {
svc_t *svc = svc_find_by_name(plugin->name); svc_t *svc = svc_find(plugin->name);
if (svc) { if (svc) {
plugin->svc.id = svc_id(svc);
svc->plugin = &plugin->svc;
inuse++; inuse++;
svc->cb = plugin->svc.cb;
svc->dynamic = plugin->svc.dynamic;
svc->dynamic_stop = plugin->svc.dynamic_stop;
} }
} }
for (i = 0; i < HOOK_MAX_NUM; i++) {
if (plugin->hook[i].cb)
inuse++;
}
if (!inuse) { if (!inuse) {
_e("No service \"%s\" loaded, skipping plugin.", basename(plugin->name)); _d("No service \"%s\" loaded, and no I/O or finit hooks, skipping plugin.", basename(plugin->name));
return 1; return 1;
} }
@@ -92,13 +97,22 @@ int plugin_unregister(plugin_t *plugin)
{ {
LIST_REMOVE(plugin, link); LIST_REMOVE(plugin, link);
if (plugin->svc.cb) {
svc_t *svc = svc_find(plugin->name);
if (svc) {
svc->cb = NULL;
svc->dynamic = 0;
}
}
/* XXX: Unfinished, add cleanup code here! */ /* XXX: Unfinished, add cleanup code here! */
return 0; return 0;
} }
/* Private daemon API *******************************************************/ /* Private daemon API *******************************************************/
void run_hooks(hook_point_t no) void plugin_run_hooks(hook_point_t no)
{ {
plugin_t *p; plugin_t *p;
@@ -110,18 +124,6 @@ void run_hooks(hook_point_t no)
} }
} }
void run_services(void)
{
plugin_t *p;
PLUGIN_ITERATOR(p) {
if (p->svc.cb) {
_d("Calling svc %s from runloop...", basename(p->name));
p->svc.cb(p->svc.arg, 0);
}
}
}
/* Generic libev I/O callback, looks up correct plugin and calls its callback */ /* 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(int fd, int events)
{ {
@@ -137,7 +139,7 @@ static void generic_io_cb(int fd, int events)
} }
} }
void io_monitor(void) void plugin_monitor(void)
{ {
int ret; int ret;
size_t i; size_t i;
@@ -171,15 +173,16 @@ static void init_plugins(void)
PLUGIN_ITERATOR(p) { PLUGIN_ITERATOR(p) {
if (is_io_plugin(p)) { if (is_io_plugin(p)) {
_d("Initializing plugin %s for I/O", basename(p->name)); _d("Initializing plugin %s for I/O", basename(p->name));
fds[i].revents = 0; fds[i].revents = 0;
fds[i].events = p->io.flags; fds[i].events = p->io.flags;
fds[num_fds++].fd = p->io.fd; fds[i++].fd = p->io.fd;
} }
} }
} }
int load_plugins(char *path) int plugin_load_all(char *path)
{ {
int fail = 0;
DIR *dp = opendir(path); DIR *dp = opendir(path);
struct dirent *entry; struct dirent *entry;
@@ -192,25 +195,28 @@ int load_plugins(char *path)
char *ext = entry->d_name + strlen(entry->d_name) - 3; char *ext = entry->d_name + strlen(entry->d_name) - 3;
if (!strcmp(ext, ".so")) { if (!strcmp(ext, ".so")) {
int result = 0;
void *handle; void *handle;
char filename[1024]; char plugin[1024];
snprintf(filename, sizeof(filename), "%s/%s", path, entry->d_name); snprintf(plugin, sizeof(plugin), "%s/%s", path, entry->d_name);
print_descr(" Loading plugin ", basename(filename)); // print_desc(" Loading plugin ", basename(plugin));
handle = dlopen(filename, RTLD_LAZY); handle = dlopen(plugin, RTLD_LAZY | RTLD_GLOBAL);
if (!handle) { if (!handle) {
_d("Failed loading plugin %s: %s", filename, dlerror()); _d("Failed loading plugin %s: %s", plugin, dlerror());
print_result(1); result = 1;
return 1;
} }
print_result(0); if (result)
fail++;
// print_result(result);
} }
} }
closedir(dp); closedir(dp);
init_plugins(); init_plugins();
return 0; return fail;
} }
/** /**
+9 -13
View File
@@ -26,6 +26,7 @@
#include <poll.h> #include <poll.h>
#include <sys/queue.h> /* BSD sys/queue.h API */ #include <sys/queue.h> /* BSD sys/queue.h API */
#include "svc.h"
#define PLUGIN_IO_READ POLLIN #define PLUGIN_IO_READ POLLIN
#define PLUGIN_IO_WRITE POLLOUT #define PLUGIN_IO_WRITE POLLOUT
@@ -39,7 +40,8 @@
* Predefined hook points for easier plugin debugging * Predefined hook points for easier plugin debugging
*/ */
typedef enum { typedef enum {
HOOK_BASEFS_UP = 0, HOOK_ROOTFS_UP = 0,
HOOK_BASEFS_UP,
HOOK_NETWORK_UP, HOOK_NETWORK_UP,
HOOK_SYSTEM_UP, HOOK_SYSTEM_UP,
HOOK_SVC_UP, HOOK_SVC_UP,
@@ -65,7 +67,8 @@ typedef enum {
* The "dynamic events" discussed in the svc callback is for external * The "dynamic events" discussed in the svc callback is for external
* service plugins to implement. However, it can be anything that * service plugins to implement. However, it can be anything that
* can cause a service to need to SIGHUP at runtime. E.g., acquiring * can cause a service to need to SIGHUP at runtime. E.g., acquiring
* a DHCP lease, or an interface going UP/DOWN. * a DHCP lease, or an interface going UP/DOWN. The event itself can
* be passed as an integer @event and any optional argument @event_arg
* *
* It is up to the external service plugin to track these events and * It is up to the external service plugin to track these events and
* relay them to each @dynamic service plugins' callback. I.e., to * relay them to each @dynamic service plugins' callback. I.e., to
@@ -80,14 +83,10 @@ typedef struct plugin {
char *name; char *name;
/* Service callback to be called once per lap of runloop. */ /* Service callback to be called once per lap of runloop. */
struct plugin_svc { struct {
/* Private */ int dynamic; /* Callback wants external events as well. */
int id; /* Service ID# to match this service plugin against, set on installation. */ int dynamic_stop; /* Callback allows dynamic events to stop. */
/* Public */ svc_cmd_t (*cb)(svc_t *svc, int event, void *event_arg);
void *arg; /* Optional argument to callback func, set by plugin. */
int dynamic; /* Reload (SIGHUP) on dynamic event? Set by plugin. */
int private; /* For callbacks to use freely, possibly to store "states", set by plugin. */
int (*cb)(void *arg, int event);
} svc; } svc;
/* List of hook callbacks. */ /* List of hook callbacks. */
@@ -104,9 +103,6 @@ typedef struct plugin {
} io; } io;
} plugin_t; } plugin_t;
/* Used by svc.h */
typedef struct plugin_svc plugin_svc_t;
/* Public plugin API */ /* Public plugin API */
int plugin_register (plugin_t *plugin); int plugin_register (plugin_t *plugin);
int plugin_unregister (plugin_t *plugin); int plugin_unregister (plugin_t *plugin);
+3 -2
View File
@@ -1,7 +1,8 @@
# Plugin based services architecture for finit -*-Makefile-*- # Plugin based services architecture for finit -*-Makefile-*-
CFLAGS = -fPIC -g -Os CFLAGS += -fPIC -Os
CPPFLAGS += -I.. CPPFLAGS += -I..
LDFLAGS = -shared LDFLAGS := $(filter-out -rdynamic, $(LDFLAGS))
LDFLAGS += -shared
PLUGINS ?= initctl.so alsa-utils.so bootmisc.so dbus.so hwclock.so \ 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
DEPS = $(addprefix .,$(PLUGINS:.so=.d)) DEPS = $(addprefix .,$(PLUGINS:.so=.d))
+4 -2
View File
@@ -28,13 +28,15 @@
static void save(void *UNUSED(arg)) static void save(void *UNUSED(arg))
{ {
_d("Saving system clock to RTC ..."); _d("Saving system clock to RTC ...");
run_interactive("/sbin/hwclock --systohc --utc", "Saving system time (UTC) to RTC"); /* -w,--systohc, -u,--utc */
run_interactive("/sbin/hwclock -w -u", "Saving system time (UTC) to RTC");
} }
static void restore(void *UNUSED(arg)) static void restore(void *UNUSED(arg))
{ {
_d("Restoring system clock from RTC ..."); _d("Restoring system clock from RTC ...");
run_interactive("/sbin/hwclock --hctosys --utc", "Restoring system clock (UTC) from RTC"); /* -s,--hctosys, -u,--utc */
run_interactive("/sbin/hwclock -s -u", "Restoring system clock (UTC) from RTC");
} }
static plugin_t plugin = { static plugin_t plugin = {
+2
View File
@@ -26,9 +26,11 @@
#include <fcntl.h> /* O_RDONLY et al */ #include <fcntl.h> /* O_RDONLY et al */
#include <signal.h> #include <signal.h>
#include <string.h> #include <string.h>
#include <unistd.h> /* read() */
#include "helpers.h" #include "helpers.h"
#include "plugin.h" #include "plugin.h"
#include "sig.h"
#define INIT_MAGIC 0x03091969 #define INIT_MAGIC 0x03091969
#define INIT_CMD_RUNLVL 1 #define INIT_CMD_RUNLVL 1
+7 -5
View File
@@ -25,13 +25,15 @@
#ifndef FINIT_PRIVATE_H_ #ifndef FINIT_PRIVATE_H_
#define FINIT_PRIVATE_H_ #define FINIT_PRIVATE_H_
#include "svc.h"
#include "plugin.h" #include "plugin.h"
/* plugin.c */ void svc_start_all (void);
void run_hooks (hook_point_t no); void svc_monitor (void);
void run_services (void);
int load_plugins (char *path); void plugin_run_hooks (hook_point_t no);
void io_monitor (void); int plugin_load_all (char *path);
void plugin_monitor (void);
#endif /* FINIT_PRIVATE_H_ */ #endif /* FINIT_PRIVATE_H_ */
+37
View File
@@ -0,0 +1,37 @@
/* reboot for finit
*
* Copyright (c) 2009-2012 Joachim Nilsson <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <signal.h>
int main (void)
{
return !!kill(1, SIGINT);
}
/**
* Local Variables:
* version-control: t
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+1 -1
View File
@@ -62,7 +62,7 @@ void do_shutdown (int sig)
sleep(1); sleep(1);
/* Call all shutdown hooks, this is the last call before rebooting... */ /* Call all shutdown hooks, this is the last call before rebooting... */
run_hooks(HOOK_SHUTDOWN); plugin_run_hooks(HOOK_SHUTDOWN);
_d("Sending SIGKILL to remaining processes."); _d("Sending SIGKILL to remaining processes.");
kill(-1, SIGKILL); kill(-1, SIGKILL);
+60 -53
View File
@@ -29,6 +29,7 @@
#include "helpers.h" #include "helpers.h"
#include "private.h" #include "private.h"
#include "sig.h" #include "sig.h"
#include "lite.h"
#include "svc.h" #include "svc.h"
/* The registered services are kept in shared memory for easy read-only access /* The registered services are kept in shared memory for easy read-only access
@@ -64,9 +65,8 @@ svc_t *svc_new(void)
__connect_shm(); __connect_shm();
if (svc_counter < MAX_NUM_SVC) { if (svc_counter < MAX_NUM_SVC) {
svc = &services[svc_counter]; svc = &services[svc_counter++];
memset(svc, 0, sizeof(*svc)); memset(svc, 0, sizeof(*svc));
svc->id = svc_counter++;
} else { } else {
errno = ENOMEM; errno = ENOMEM;
return NULL; return NULL;
@@ -76,29 +76,13 @@ svc_t *svc_new(void)
} }
/** /**
* svc_find_by_id - Find a service object by its logical ID# * svc_find - Find a service object by its full path name
* @id: Logical ID#
*
* Returns:
* A pointer to an &svc_t object, or %NULL if not found.
*/
svc_t *svc_find_by_id(int id)
{
__connect_shm();
if (id >= svc_counter)
return NULL;
return &services[id];
}
/**
* svc_find_by_name - Find a service object by its full path name
* @name: Full path name, e.g., /sbin/syslogd * @name: Full path name, e.g., /sbin/syslogd
* *
* Returns: * Returns:
* A pointer to an &svc_t object, or %NULL if not found. * A pointer to an &svc_t object, or %NULL if not found.
*/ */
svc_t *svc_find_by_name(char *name) svc_t *svc_find(char *name)
{ {
int i; int i;
@@ -125,16 +109,16 @@ svc_t *svc_find_by_name(char *name)
*/ */
svc_t *svc_iterator(int restart) svc_t *svc_iterator(int restart)
{ {
static int id = 0; static int i = 0;
__connect_shm(); __connect_shm();
if (restart) if (restart)
id = 0; i = 0;
if (id >= svc_counter) if (i >= svc_counter)
return NULL; return NULL;
return &services[id++]; return &services[i++];
} }
/** /**
@@ -156,7 +140,7 @@ svc_t *svc_iterator(int restart)
int svc_register(char *line, char *username) int svc_register(char *line, char *username)
{ {
int i = 0; int i = 0;
char *cmd, *descr; char *cmd, *desc;
svc_t *svc; svc_t *svc;
if (!line) { if (!line) {
@@ -164,9 +148,9 @@ int svc_register(char *line, char *username)
return errno = EINVAL; return errno = EINVAL;
} }
descr = strstr(line, "-- "); desc = strstr(line, "-- ");
if (descr) if (desc)
*descr = 0; *desc = 0;
cmd = strtok(line, " "); cmd = strtok(line, " ");
if (!cmd) { if (!cmd) {
@@ -190,8 +174,8 @@ int svc_register(char *line, char *username)
return errno = ENOMEM; return errno = ENOMEM;
} }
if (descr) if (desc)
strlcpy(svc->descr, descr + 3, sizeof(svc->descr)); strlcpy(svc->desc, desc + 3, sizeof(svc->desc));
if (username) if (username)
strlcpy(svc->username, username, sizeof(svc->username)); strlcpy(svc->username, username, sizeof(svc->username));
strlcpy(svc->cmd, cmd, sizeof(svc->cmd)); strlcpy(svc->cmd, cmd, sizeof(svc->cmd));
@@ -207,8 +191,9 @@ int svc_register(char *line, char *username)
/** /**
* svc_enabled - Should the service run? * svc_enabled - Should the service run?
* @svc: Pointer to &svc_t object * @svc: Pointer to &svc_t object
* @dynamic: Dynamic event, opaque flag passed to callback * @event: Dynamic event, opaque flag passed to callback
* @arg: Event argument, used only by external service plugins.
* *
* This method calls an associated service callback, if registered by a * This method calls an associated service callback, if registered by a
* plugin, and returns the &svc_cmd_t status. If no plugin is registered * plugin, and returns the &svc_cmd_t status. If no plugin is registered
@@ -218,19 +203,19 @@ int svc_register(char *line, char *username)
* Returns: * Returns:
* Either one of %SVC_START, %SVC_STOP, %SVC_RELOAD. * Either one of %SVC_START, %SVC_STOP, %SVC_RELOAD.
*/ */
svc_cmd_t svc_enabled(svc_t *svc, int dynamic) svc_cmd_t svc_enabled(svc_t *svc, int event, void *arg)
{ {
if (!svc) { if (!svc) {
errno = EINVAL; errno = EINVAL;
return SVC_STOP; return SVC_STOP;
} }
if (!svc->plugin) { /* Is there a service plugin registered? */
/* Unknown service, default to enabled. */ if (svc->cb)
return SVC_START; return svc->cb(svc, event, arg);
}
return svc->plugin->cb(svc, dynamic); /* No service plugin, default to start, since listed in finit.conf */
return SVC_START;
} }
static int is_norespawn(void) static int is_norespawn(void)
@@ -273,7 +258,7 @@ void svc_monitor(void)
procname_kill(name, SIGTERM); procname_kill(name, SIGTERM);
/* Restarting lost service. */ /* Restarting lost service. */
if (svc_enabled(svc, 0)) if (svc_enabled(svc, 0, NULL))
svc_start(svc); svc_start(svc);
break; break;
@@ -285,6 +270,7 @@ int svc_start(svc_t *svc)
{ {
int respawn = svc->pid != 0; int respawn = svc->pid != 0;
pid_t pid; pid_t pid;
sigset_t nmask, omask;
char *args[MAX_NUM_SVC_ARGS]; char *args[MAX_NUM_SVC_ARGS];
/* Ignore if finit is SIGSTOP'ed */ /* Ignore if finit is SIGSTOP'ed */
@@ -292,14 +278,24 @@ int svc_start(svc_t *svc)
return 0; return 0;
if (!respawn) if (!respawn)
print_descr("Starting ", svc->descr); print_desc("Starting ", svc->desc);
/* Block sigchild while forking. */
sigemptyset(&nmask);
sigaddset(&nmask, SIGCHLD);
sigprocmask(SIG_BLOCK, &nmask, &omask);
pid = fork(); pid = fork();
sigprocmask(SIG_SETMASK, &omask, NULL);
if (pid == 0) { if (pid == 0) {
int i = 0; int i = 0;
int uid = getuser(svc->username); int uid = getuser(svc->username);
struct sigaction sa; struct sigaction sa;
sigemptyset(&nmask);
sigaddset(&nmask, SIGCHLD);
sigprocmask(SIG_UNBLOCK, &nmask, NULL);
/* Reset signal handlers that were set by the parent process */ /* Reset signal handlers that were set by the parent process */
for (i = 1; i < NSIG; i++) for (i = 1; i < NSIG; i++)
DFLSIG(sa, i, 0); DFLSIG(sa, i, 0);
@@ -314,16 +310,23 @@ int svc_start(svc_t *svc)
args[i] = NULL; args[i] = NULL;
if (debug) { if (debug) {
int fd = open (CONSOLE, O_WRONLY | O_APPEND); int fd;
char buf[256] = "";
fd = open (CONSOLE, O_WRONLY | O_APPEND);
if (-1 != fd) { if (-1 != fd) {
dup2(STDOUT_FILENO, fd); dup2(STDOUT_FILENO, fd);
dup2(STDERR_FILENO, fd); dup2(STDERR_FILENO, fd);
} }
_e("%starting %s ", respawn ? "Res" : "S", svc->cmd); for (i = 0; args[i] && i < MAX_NUM_SVC_ARGS; i++) {
for (i = 0; args[i] && i < MAX_NUM_SVC_ARGS; i++) char arg[MAX_ARG_LEN];
_e("%s ", args[i]);
_e(""); snprintf(arg, sizeof(arg), "%s ", args[i]);
if ((sizeof(buf) - strlen(buf)) < strlen(arg))
strcat(buf, arg);
}
_e("%starting %s: %s", respawn ? "Res" : "S", svc->cmd, buf);
} }
execvp(svc->cmd, args); execvp(svc->cmd, args);
@@ -339,9 +342,9 @@ int svc_start(svc_t *svc)
int svc_start_by_name(char *name) int svc_start_by_name(char *name)
{ {
svc_t *svc = svc_find_by_name(name); svc_t *svc = svc_find(name);
if (svc && svc_enabled(svc, 0)) if (svc && svc_enabled(svc, 0, NULL))
return svc_start(svc); return svc_start(svc);
return 1; return 1;
@@ -357,12 +360,12 @@ int svc_stop(svc_t *svc)
} }
if (svc->pid <= 1) { if (svc->pid <= 1) {
_d("Bad PID %d for %s, SIGTERM", svc->pid, svc->descr); _d("Bad PID %d for %s, SIGTERM", svc->pid, svc->desc);
svc->pid = 0; svc->pid = 0;
return 1; return 1;
} }
print_descr("Stopping ", svc->descr); print_desc("Stopping ", svc->desc);
_d("Sending SIGTERM to pid:%d name:'%s'", svc->pid, pid_get_name(svc->pid, NULL, 0)); _d("Sending SIGTERM to pid:%d name:'%s'", svc->pid, pid_get_name(svc->pid, NULL, 0));
res = kill(svc->pid, SIGTERM); res = kill(svc->pid, SIGTERM);
print_result(res); print_result(res);
@@ -373,6 +376,10 @@ int svc_stop(svc_t *svc)
int svc_reload(svc_t *svc) int svc_reload(svc_t *svc)
{ {
/* Ignore if finit is SIGSTOP'ed */
if (is_norespawn())
return 0;
if (!svc) { if (!svc) {
_e("Failed, no svc pointer."); _e("Failed, no svc pointer.");
return 1; return 1;
@@ -394,15 +401,15 @@ void svc_start_all(void)
svc_cmd_t cmd; svc_cmd_t cmd;
for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) { for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
cmd = svc_enabled(svc, 0); cmd = svc_enabled(svc, 0, NULL);
if (cmd == SVC_START || (cmd == SVC_RELOAD && svc->pid == 0)) if (SVC_START == cmd || (SVC_RELOAD == cmd && svc->pid == 0))
svc_start(svc); svc_start(svc);
else if (cmd == SVC_RELOAD) else if (SVC_RELOAD == cmd)
svc_reload(svc); svc_reload(svc);
} }
_d("Running svc up hooks ..."); _d("Running svc up hooks ...");
run_hooks(HOOK_SVC_UP); plugin_run_hooks(HOOK_SVC_UP);
} }
+14 -23
View File
@@ -30,8 +30,6 @@
#include <sys/shm.h> /* shmat() */ #include <sys/shm.h> /* shmat() */
#include <sys/types.h> /* pid_t */ #include <sys/types.h> /* pid_t */
#include "plugin.h"
typedef enum { typedef enum {
SVC_STOP = 0, /* Disabled */ SVC_STOP = 0, /* Disabled */
SVC_START, /* Enabled */ SVC_START, /* Enabled */
@@ -50,16 +48,22 @@ typedef enum {
* of issuing an initctl call. E.g. * of issuing an initctl call. E.g.
* initctl <stop|start|restart> service */ * initctl <stop|start|restart> service */
typedef struct svc { typedef struct svc {
/* Private */
int id; /* Service ID#, set by svc_new() */
pid_t pid; pid_t pid;
int reload;
char cmd[MAX_ARG_LEN]; char cmd[MAX_ARG_LEN];
char args[MAX_NUM_SVC_ARGS][MAX_ARG_LEN]; char args[MAX_NUM_SVC_ARGS][MAX_ARG_LEN];
char descr[MAX_STR_LEN]; char desc[MAX_STR_LEN];
char username[MAX_USER_LEN]; char username[MAX_USER_LEN];
/* Public */
int delayed_reload; /* For external service plugin. */ /* For external plugins. If @cb is set a plugin is loaded.
plugin_svc_t *plugin; * @dynamic: Set by plugins that want dynamic events.
* @dynamic_stop: Set by plugins that allow dyn. events to stop it as well.
* @private: Can be used freely by plugin, e.g., to store "states".
*/
int dynamic;
int dynamic_stop;
int private;
svc_cmd_t (*cb)(struct svc *svc, int event, void *event_arg);
} svc_t; } svc_t;
typedef struct svc_map svc_map_t; typedef struct svc_map svc_map_t;
@@ -79,30 +83,17 @@ static inline svc_t *finit_svc_connect(void)
return (svc_t *)ptr; return (svc_t *)ptr;
} }
static inline int svc_id(svc_t *svc)
{
if (!svc) {
errno = EINVAL;
return -1;
}
return svc->id;
}
svc_t *svc_new (void); svc_t *svc_new (void);
svc_t *svc_find_by_id (int id); svc_t *svc_find (char *name);
svc_t *svc_find_by_name (char *name);
svc_t *svc_iterator (int restart); svc_t *svc_iterator (int restart);
int svc_register (char *line, char *username); int svc_register (char *line, char *username);
int svc_id_by_name (char *name); int svc_id_by_name (char *name);
svc_cmd_t svc_enabled (svc_t *svc, int dynamic); svc_cmd_t svc_enabled (svc_t *svc, int event, void *arg);
int svc_start (svc_t *svc); int svc_start (svc_t *svc);
int svc_start_by_name (char *name); int svc_start_by_name (char *name);
int svc_stop (svc_t *svc); int svc_stop (svc_t *svc);
int svc_reload (svc_t *svc); int svc_reload (svc_t *svc);
void svc_start_all (void);
void svc_monitor (void);
#endif /* FINIT_SVC_H_ */ #endif /* FINIT_SVC_H_ */