mirror of
https://github.com/troglobit/finit.git
synced 2026-10-12 10:12:32 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
65c9e7ebc6 | ||
|
|
c002b5301f | ||
|
|
3f1c2f6211 | ||
|
|
5116cd66ef | ||
|
|
f55f68d032 | ||
|
|
5e99b5e735 | ||
|
|
d26852e07a | ||
|
|
a90a7c04e4 | ||
|
|
14a1fb9cde | ||
|
|
b373e199a8 | ||
|
|
149ed0e81c | ||
|
|
e32ca1fc83 | ||
|
|
9aa90763b0 | ||
|
|
06759d3544 | ||
|
|
ff73dab447 | ||
|
|
0d70fa4cf0 | ||
|
|
103bf33b3c | ||
|
|
2b2fcb740c | ||
|
|
7542f4e199 | ||
|
|
1fece1f9b5 | ||
|
|
814ff1f77e | ||
|
|
fbfffbc9a4 | ||
|
|
e496913f5c | ||
|
|
5bc9ff0e20 | ||
|
|
dd0220fd2c | ||
|
|
bb0a378f1c | ||
|
|
2a025356d4 | ||
|
|
c49d89dfe0 | ||
|
|
75eb5cc043 | ||
|
|
dfa0fe6428 | ||
|
|
0e02429e75 | ||
|
|
5dda9051ac | ||
|
|
239772d667 | ||
|
|
a0fa877520 | ||
|
|
23ef745985 | ||
|
|
077a7e82e0 | ||
|
|
d21dc2b477 | ||
|
|
c0356b5c7a | ||
|
|
855c7d8251 | ||
|
|
2f527215d0 | ||
|
|
5da4f4cfc3 | ||
|
|
b0aec188bc | ||
|
|
4657d9713a | ||
|
|
a654d99b92 | ||
|
|
e2c4a6ceaf | ||
|
|
5816c9cab9 | ||
|
|
f92438d42a | ||
|
|
6afbcbdd6e | ||
|
|
b9583fb354 | ||
|
|
37af9970d4 | ||
|
|
3a7f7cd61a | ||
|
|
b11d6c6d4e | ||
|
|
88ffb9351d | ||
|
|
c70872f19e | ||
|
|
9e0b22ddb6 | ||
|
|
321264f0dc | ||
|
|
65c971925c | ||
|
|
a2de2c1591 | ||
|
|
85fedac866 | ||
|
|
29ab953a87 | ||
|
|
1843a0e66f | ||
|
|
6a8a3fd4ab | ||
|
|
d096efe643 | ||
|
|
e33d385f0c | ||
|
|
7ebc19782f | ||
|
|
4af58f8bb0 | ||
|
|
ed4abc952a | ||
|
|
52feb6f51c | ||
|
|
c7c388e567 | ||
|
|
95a70ed2af | ||
|
|
4554377e4d | ||
|
|
3811275df5 | ||
|
|
7360ef1f08 | ||
|
|
529224153f | ||
|
|
0f8393ef0e | ||
|
|
a1d7e48225 | ||
|
|
938773765c | ||
|
|
367049a11c | ||
|
|
efcdc141c8 | ||
|
|
dfed328d47 | ||
|
|
804aa3c747 | ||
|
|
3ce7638dab | ||
|
|
b0746f5220 | ||
|
|
c324eff01a | ||
|
|
a6f534621c | ||
|
|
b0e3dbc47f | ||
|
|
220b2c9ae3 | ||
|
|
173853ca17 | ||
|
|
9f83bbe788 | ||
|
|
a187b88dd9 | ||
|
|
134d9f3463 | ||
|
|
25e9d84673 | ||
|
|
765bef0991 | ||
|
|
7d10388158 | ||
|
|
a0382dfab8 | ||
|
|
ead2eb7076 | ||
|
|
0f2a14bf4f | ||
|
|
4e8be438e9 | ||
|
|
2f3404165f | ||
|
|
ca9ee99f59 | ||
|
|
0ab62c8871 | ||
|
|
efdac3fc2d | ||
|
|
c127735e2d | ||
|
|
d621b0ba15 | ||
|
|
33469873a5 | ||
|
|
36043c04f9 | ||
|
|
ec10fecd8d | ||
|
|
0fc7654a83 | ||
|
|
ba9c897e83 | ||
|
|
4948844f82 | ||
|
|
9f99f38561 | ||
|
|
f516108ca6 | ||
|
|
04b91da9f9 | ||
|
|
f94504ad96 | ||
|
|
698c5a1852 | ||
|
|
d5037d1352 | ||
|
|
57ad91136b | ||
|
|
9488e65998 | ||
|
|
19540d148e | ||
|
|
df14fd5255 | ||
|
|
821a6853fe | ||
|
|
dbdf8ccc72 | ||
|
|
b2f143e623 | ||
|
|
2ffafc3d03 | ||
|
|
3158733ced | ||
|
|
1aa6358611 | ||
|
|
ce998373e5 | ||
|
|
d0b6457f01 | ||
|
|
349593d41b | ||
|
|
b8daa9c869 | ||
|
|
f21b0a2580 | ||
|
|
4e18bc3724 | ||
|
|
90c8c73470 | ||
|
|
c8e7b34b4c | ||
|
|
6ff7f2e52b | ||
|
|
b6bf00ed06 | ||
|
|
136dfeb41a | ||
|
|
7867db7b23 | ||
|
|
75d755afad | ||
|
|
01509376cc | ||
|
|
c55afaadb3 | ||
|
|
ccd49f2024 | ||
|
|
0fdf97653f | ||
|
|
9d164ac312 | ||
|
|
5acd2cd441 | ||
|
|
1f7eab37a0 | ||
|
|
d87fb47cf3 | ||
|
|
7caf633259 | ||
|
|
ba6470f5a6 | ||
|
|
fa23155593 | ||
|
|
996cb2ec1e | ||
|
|
4e3d6ec976 | ||
|
|
0857a0846f | ||
|
|
a3ad99798e | ||
|
|
c79b823f17 | ||
|
|
71ce4b98e9 | ||
|
|
9908a6e680 | ||
|
|
f94a76ed17 | ||
|
|
6fc2a6b108 | ||
|
|
a52c932085 | ||
|
|
2e7952645a | ||
|
|
494f182b13 | ||
|
|
5ad9ff48c5 | ||
|
|
b5e2af21a6 | ||
|
|
eb5445628f | ||
|
|
89854a579f | ||
|
|
1c88ae1f61 | ||
|
|
f972ff4d30 | ||
|
|
904c12d06a | ||
|
|
a85b0cf481 | ||
|
|
286711237d | ||
|
|
434ec4c533 | ||
|
|
6371f82fea | ||
|
|
b2233a6f4b | ||
|
|
6c807c3a95 | ||
|
|
e4f675fa1a | ||
|
|
880b5f8a92 | ||
|
|
c8f171556b | ||
|
|
2a9bfa7fd7 | ||
|
|
98624a3d21 | ||
|
|
6565cc67ee |
@@ -0,0 +1,6 @@
|
||||
*.o
|
||||
.*.d
|
||||
*.so
|
||||
*.gz
|
||||
*.map
|
||||
finit
|
||||
@@ -0,0 +1,6 @@
|
||||
Current Maintainer(s):
|
||||
* Joachim Nilsson <troglobit@gmail.com>
|
||||
|
||||
Original Author(s):
|
||||
* Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
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,19 +0,0 @@
|
||||
0.3 ()
|
||||
- Change poweroff method to reboot(RB_POWER_OFF) (Metalshark)
|
||||
- Remove duplicate unionctl() reimplementation error
|
||||
- Fix string termination in path creation
|
||||
- Mount /var/lock and /var/run as tmpfs
|
||||
|
||||
0.2 (20080219)
|
||||
- replace system("touch") with touch() in finit-mod (Metalshark)
|
||||
- disable NO_HCTOSYS by default to match stock Eeepc kernel
|
||||
- drop system("rm -f") to clean /tmp, its a fresh mounted tmpfs
|
||||
- write ACPI sleep state to /sys/power/state instead of
|
||||
/proc/acpi/sleep (Metalshark)
|
||||
- use direct calls to set loopback instead of system("ifconfig")
|
||||
- replace system("cat") and system("dd") with C implementation
|
||||
- moved finit-mod and finit-alt helpers to helpers.c
|
||||
- replace system("echo;cat") to draw shutdown splash with C calls
|
||||
|
||||
0.1 (20081214)
|
||||
- initial release
|
||||
@@ -0,0 +1,20 @@
|
||||
Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||
Copyright (c) 2008-2012 Joachim Nilsson <troglobit@gmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
@@ -1,65 +1,168 @@
|
||||
CC = gcc
|
||||
CFLAGS = -Os -Wall -DVERSION=\"$(VERSION)\" -DWHOAMI=\"`whoami`@`hostname`\"
|
||||
LD = gcc
|
||||
LDFLAGS =
|
||||
LIBS =
|
||||
VERSION = 0.3
|
||||
PKG = finit-$(VERSION)
|
||||
DFILES = Makefile README finit.c finit-mod.c finit-alt.c helpers.c helpers.h
|
||||
BINS = finit finit-mod finit-mdv
|
||||
# Finit - Extremely fast /sbin/init replacement w/ I/O, hook & service plugins
|
||||
#
|
||||
# Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||
# Copyright (c) 2008-2012 Joachim Nilsson <troglobit@gmail.com>
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
.PHONY: all install clean distclean dist \
|
||||
install-exec install-data install-dev \
|
||||
uninstall-exec uninstall-data uninstall-dev
|
||||
|
||||
#### Configurable parameters
|
||||
# Top directory for building complete system, fall back to this directory
|
||||
ROOTDIR = $(shell pwd)
|
||||
|
||||
# Add -DDEBUG to build with debug messages, also drops to terminal after X
|
||||
#CFLAGS += -DDEBUG
|
||||
#VERSION ?= $(shell git tag -l | tail -1)
|
||||
VERSION ?= 1.4
|
||||
NAME = finit
|
||||
PKG = $(NAME)-$(VERSION)
|
||||
DEV = $(NAME)-dev
|
||||
ARCHIVE = $(PKG).tar.xz
|
||||
EXEC = finit reboot
|
||||
HEADERS = plugin.h svc.h helpers.h
|
||||
DISTFILES = LICENSE README ChangeLog finit.conf services
|
||||
OBJS = finit.o conf.o helpers.o sig.o svc.o plugin.o
|
||||
OBJS += strlcpy.o
|
||||
SRCS = $(OBJS:.o=.c)
|
||||
DEPS = $(addprefix .,$(SRCS:.c=.d))
|
||||
|
||||
# Parameters added by Metalshark
|
||||
# Installation paths, always prepended with DESTDIR if set
|
||||
prefix ?= /usr
|
||||
sysconfdir ?= /etc
|
||||
sbindir ?= /sbin
|
||||
libdir ?= /lib
|
||||
plugindir ?= $(libdir)/finit/plugins
|
||||
incdir = $(prefix)/include/finit
|
||||
datadir = $(prefix)/share/doc/finit
|
||||
mandir = $(prefix)/share/man/man8
|
||||
|
||||
# Use -march=pentium-m to build for Eeepc
|
||||
CFLAGS += -march=pentium-m
|
||||
# The initctl FIFO, should probably be in /run, not /dev
|
||||
FINIT_FIFO ?= /dev/initctl
|
||||
FINIT_CONF ?= $(sysconfdir)/finit.conf
|
||||
FINIT_RCSD ?= $(sysconfdir)/finit.d
|
||||
|
||||
# Omit the first /sbin/hwclock if CONFIG_RTC_HCTOSYS is enabled in the kernel
|
||||
#CFLAGS += -DNO_HCTOSYS
|
||||
CFLAGS += -W -Wall -Werror -Os
|
||||
# Disable annoying gcc warning for "warn_unused_result", see GIT 37af997
|
||||
CPPFLAGS += -U_FORTIFY_SOURCE
|
||||
CPPFLAGS += -Ilibite -D_XOPEN_SOURCE=600 -D_BSD_SOURCE -D_GNU_SOURCE
|
||||
CPPFLAGS += -DVERSION=\"$(VERSION)\" -DWHOAMI=\"`whoami`@`hostname`\"
|
||||
CPPFLAGS += -DFINIT_FIFO=\"$(FINIT_FIFO)\" -DFINIT_CONF=\"$(FINIT_CONF)\"
|
||||
CPPFLAGS += -DFINIT_RCSD=\"$(FINIT_RCSD)\" -DPLUGIN_PATH=\"$(plugindir)\"
|
||||
LDFLAGS += -rdynamic -L$(ROOTDIR)/libite
|
||||
DEPLIBS = libite/libite.so
|
||||
LDLIBS += -ldl -lite
|
||||
|
||||
# Append –directisa to /sbin/hwclock lines if the user has disabled
|
||||
# CONFIG_GENRTC and enabled CONFIG_RTC but not enabled CONFIG_HPET_TIMER
|
||||
# and CONFIG_HPET_RTC_IRQ.
|
||||
#CFLAGS += -DDIRECTISA
|
||||
include common.mk
|
||||
export libdir plugindir incdir ROOTDIR CPPFLAGS LDFLAGS LDLIBS
|
||||
|
||||
all: $(DEPLIBS) $(EXEC)
|
||||
$(MAKE) -C plugins $@
|
||||
|
||||
$(DEPLIBS): Makefile
|
||||
$(MAKE) -C libite all
|
||||
|
||||
.c.o:
|
||||
$(CC) -c $(CFLAGS) -o $*.o $<
|
||||
$(OBJS): Makefile
|
||||
|
||||
all: $(BINS)
|
||||
finit: $(OBJS) $(DEPLIBS)
|
||||
|
||||
finit: finit.o
|
||||
$(LD) $(LDFLAGS) -o $@ $+ $(LIBS)
|
||||
strip $@
|
||||
reboot: reboot.o $(DEPLIBS)
|
||||
|
||||
finit-mod: finit-mod.o helpers.o
|
||||
$(LD) $(LDFLAGS) -o $@ $+ $(LIBS)
|
||||
strip $@
|
||||
install-exec: all
|
||||
@$(INSTALL) -d $(DESTDIR)$(FINIT_RCSD)
|
||||
@$(INSTALL) -d $(DESTDIR)$(sbindir)
|
||||
@for file in $(EXEC); do \
|
||||
printf " INSTALL $(DESTDIR)$(sbindir)/$$file\n"; \
|
||||
$(STRIPINST) $$file $(DESTDIR)$(sbindir)/$$file; \
|
||||
done
|
||||
$(MAKE) -C libite install-exec
|
||||
$(MAKE) -C plugins install
|
||||
|
||||
finit-mdv: finit-mdv.o helpers.o
|
||||
$(LD) $(LDFLAGS) -o $@ $+ $(LIBS)
|
||||
strip $@
|
||||
install-data:
|
||||
@$(INSTALL) -d $(DESTDIR)$(datadir)
|
||||
@$(INSTALL) -d $(DESTDIR)$(mandir)
|
||||
@for file in $(DISTFILES); do \
|
||||
printf " INSTALL $(DESTDIR)$(datadir)/$$file\n"; \
|
||||
$(INSTALL) -m 0644 $$file $(DESTDIR)$(datadir)/$$file; \
|
||||
done
|
||||
|
||||
finit-mdv.o: finit-alt.c Makefile
|
||||
$(CC) -c $(CFLAGS) -DDIST_MDV -o $@ finit-alt.c
|
||||
install-dev:
|
||||
@$(INSTALL) -d $(DESTDIR)$(incdir)
|
||||
@for file in $(HEADERS); do \
|
||||
printf " INSTALL $(DESTDIR)$(incdir)/$$file\n"; \
|
||||
$(INSTALL) -m 0644 $$file $(DESTDIR)$(incdir)/$$file; \
|
||||
done
|
||||
$(MAKE) -C libite install-dev install-exec
|
||||
|
||||
install: install-exec install-data install-dev
|
||||
|
||||
uninstall-exec:
|
||||
-@for file in $(EXEC); do \
|
||||
printf " REMOVE $(DESTDIR)$(sbindir)/$$file\n"; \
|
||||
rm $(DESTDIR)$(sbindir)/$$file 2>/dev/null; \
|
||||
done
|
||||
-@rmdir $(DESTDIR)$(sbindir) 2>/dev/null
|
||||
-@rmdir $(DESTDIR)$(FINIT_RCSD) 2>/dev/null
|
||||
$(MAKE) -C libite uninstall
|
||||
$(MAKE) -C plugins uninstall
|
||||
|
||||
uninstall-data:
|
||||
@for file in $(DISTFILES); do \
|
||||
printf " REMOVE $(DESTDIR)$(datadir)/$$file\n"; \
|
||||
rm $(DESTDIR)$(datadir)/$$file 2>/dev/null; \
|
||||
done
|
||||
-@rmdir $(DESTDIR)$(mandir)
|
||||
-@rmdir $(DESTDIR)$(datadir)
|
||||
|
||||
uninstall-dev:
|
||||
-@$(RM) -rf $(DESTDIR)$(incdir)
|
||||
|
||||
uninstall: uninstall-exec uninstall-data uninstall-dev
|
||||
|
||||
clean:
|
||||
rm -f *.o core *~ $(BINS)
|
||||
-@$(RM) $(OBJS) $(DEPS) $(EXEC)
|
||||
$(MAKE) -C libite $@
|
||||
$(MAKE) -C plugins $@
|
||||
|
||||
finit.o: finit.c Makefile
|
||||
|
||||
finit-mod.o: finit-mod.c Makefile
|
||||
distclean: clean
|
||||
-@$(RM) $(JUNK) unittest *.o .*.d
|
||||
$(MAKE) -C libite $@
|
||||
$(MAKE) -C plugins $@
|
||||
|
||||
dist:
|
||||
rm -Rf $(PKG)
|
||||
mkdir $(PKG)
|
||||
cp Makefile $(DFILES) $(PKG)
|
||||
tar cf - $(PKG) | gzip -c > $(PKG).tar.gz
|
||||
rm -Rf $(PKG)
|
||||
ls -l $(PKG).tar.gz
|
||||
@echo "Building xz tarball of $(PKG) in parent dir..."
|
||||
git archive --format=tar --prefix=$(PKG)/ $(VERSION) | xz >../$(ARCHIVE)
|
||||
@(cd ..; md5sum $(ARCHIVE) | tee $(ARCHIVE).md5)
|
||||
|
||||
dev: distclean
|
||||
@echo "Building unstable xz $(DEV) in parent dir..."
|
||||
-@$(RM) -f ../$(DEV).tar.xz*
|
||||
@(dir=`mktemp -d`; mkdir $$dir/$(DEV); cp -a . $$dir/$(DEV); \
|
||||
cd $$dir; tar --exclude=.git --exclude=contrib \
|
||||
-c -J -f $(DEV).tar.xz $(DEV); \
|
||||
cd - >/dev/null; mv $$dir/$(DEV).tar.xz ../; cd ..; \
|
||||
rm -rf $$dir; md5sum $(DEV).tar.xz | tee $(DEV).tar.xz.md5)
|
||||
|
||||
# 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)
|
||||
endif
|
||||
endif
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
|
||||
Eeepc "fastinit" reimplementations
|
||||
----------------------------------
|
||||
|
||||
finit.c is a reimplementation of the Asus Eeepc fastinit program based
|
||||
on its library calls. It tries to be an accurate re-creation and keeps
|
||||
the original bugs and lack of optimization.
|
||||
|
||||
finit-mod.c is a fixed/improved version of finit.c.
|
||||
|
||||
finit-alt.c is a fixed/improved version of finit.c for alternative Linux
|
||||
distributions running on the Eeepc (previously ffinit.c). Currently able
|
||||
to boot unmodified Mandriva Linux.
|
||||
|
||||
See Makefile for configurable parameters to better suit your system.
|
||||
|
||||
|
||||
* Eeepc boot process
|
||||
|
||||
The essential steps in the boot process carried out in initramfs are:
|
||||
|
||||
ROOT=`sed 's!.*root=\([^ ]*\).*!\1!' < /proc/cmdline`
|
||||
mount -t proc proc /proc
|
||||
mount -t ext2 -o ro $ROOT /mnt-system
|
||||
mount -t ext3 -o rw /dev/sda2 /mnt-user
|
||||
mount -t unionfs -o dirs=/mnt-user=rw:/mnt-system=ro unionfs /mnt
|
||||
mount --move /mnt-system /mnt/mnt
|
||||
umount -l /mnt-user
|
||||
umount /proc
|
||||
exec switch_root /mnt /sbin/fastinit "$@" </mnt/dev/console >/mnt/dev/console
|
||||
|
||||
If mounting the root filesystem fails, execute a maintenance shell. If
|
||||
mounting the user filesystem fails, fsck and reboot.
|
||||
|
||||
|
||||
* Utilities available in the Eeepc initramfs busybox:
|
||||
|
||||
[ cat cp cut dd
|
||||
dmesg echo env expr false
|
||||
grep insmod ln losetup ls
|
||||
mdev mkdir mknod mount mv
|
||||
pivot_root realpath rm rmmod sed
|
||||
sh sleep switch_root test true
|
||||
umount vi
|
||||
|
||||
|
||||
* Devices in the Eeepc initramfs /dev:
|
||||
|
||||
console fb null ram0 sda1 sda2 sda3 sr0 tty0
|
||||
|
||||
|
||||
|
||||
Using finit with alternative systems
|
||||
------------------------------------
|
||||
|
||||
Currently tested only with Mandriva 2008. Proceed with caution, there are
|
||||
problems related to udev and pam.
|
||||
|
||||
1 - Add init=/sbin/finit-mdv to the kernel boot line
|
||||
|
||||
2 - Provide a suitable /usr/sbin/services.sh, this is the one I use in my
|
||||
test system:
|
||||
|
||||
mkdir /var/lock/subsys
|
||||
chmod 1777 /var/lock/subsys
|
||||
/etc/init.d/network start
|
||||
dhclient eth0
|
||||
/sbin/start_udev&
|
||||
/etc/init.d/portmap start
|
||||
/etc/init.d/nfs-common start
|
||||
|
||||
3 - Provide /etc/hostname if you don't have it already
|
||||
|
||||
4 - Set the pointer device in the X server configuration to /dev/input/mice
|
||||
|
||||
5 - Have a user named "user", or change DEFUSER in the source file
|
||||
|
||||
+195
@@ -0,0 +1,195 @@
|
||||
==============================================================================
|
||||
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
|
||||
@@ -0,0 +1,6 @@
|
||||
* FHS changes, see http://askubuntu.com/questions/57297/why-has-var-run-been-migrated-to-run
|
||||
* Look at Erik Troan's nash linuxrc parser for more inspiration
|
||||
* Look at how to support a standard SysV init runlevel mechanism
|
||||
* Arguments to finit, like to SysV init "init q" to reload finit.conf at runtime, etc.
|
||||
* Implement initctl stop|start|reload <SVC> and service <SVC> stop|start|reload on top
|
||||
* Write man pages for finit and finit.conf, steal from pimd man pages...
|
||||
@@ -0,0 +1,25 @@
|
||||
# Some junk files we always want to be removed when doing a make clean.
|
||||
JUNK = *~ *.bak *.aux *.dvi *.idx *.ind *.log *.ps *.map .*.d DEADJOE semantic.cache *.gdb *.elf core core.*
|
||||
MAKE := @$(MAKE)
|
||||
MAKEFLAGS = --no-print-directory --silent
|
||||
INSTALL := install --backup=off
|
||||
STRIPINST := $(INSTALL) -s --strip-program=$(CROSS)strip -m 0755
|
||||
|
||||
# Smart autodependecy generation via GCC -M.
|
||||
.%.d: %.c
|
||||
@$(SHELL) -ec "$(CC) -MM $(CFLAGS) $(CPPFLAGS) $< \
|
||||
| sed 's,.*: ,$*.o $@ : ,g' > $@; \
|
||||
[ -s $@ ] || rm -f $@"
|
||||
|
||||
# Override default implicit rules
|
||||
%.o: %.c
|
||||
@printf " CC $(subst $(ROOTDIR)/,,$(shell pwd)/$@)\n"
|
||||
@$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
|
||||
|
||||
%: %.o
|
||||
@printf " LINK $(subst $(ROOTDIR)/,,$(shell pwd)/$@)\n"
|
||||
@$(CC) $(CFLAGS) $(LDFLAGS) -Wl,-Map,$@.map -o $@ $^ $(LDLIBS$(LDLIBS-$(@)))
|
||||
|
||||
%.so: %.o
|
||||
@printf " PLUGIN $(subst $(ROOTDIR)/,,$(shell pwd)/$@)\n"
|
||||
@$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS)
|
||||
@@ -0,0 +1,145 @@
|
||||
/* Parser for finit.conf
|
||||
*
|
||||
* Copyright (c) 2012 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "finit.h"
|
||||
#include "svc.h"
|
||||
#include "helpers.h"
|
||||
|
||||
/* Match one command. */
|
||||
#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)
|
||||
{
|
||||
int l;
|
||||
char *c;
|
||||
|
||||
/* Trim leading whitespace */
|
||||
while (*line && (*line == ' ' || *line == '\t'))
|
||||
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;
|
||||
|
||||
_d("cmd = %s", cmd);
|
||||
return cmd;
|
||||
}
|
||||
|
||||
void parse_finit_conf(char *file)
|
||||
{
|
||||
FILE *fp;
|
||||
char line[LINE_SIZE];
|
||||
char cmd[CMD_SIZE];
|
||||
|
||||
/* Default username and hostname */
|
||||
username = strdup(DEFUSER);
|
||||
hostname = strdup(DEFHOST);
|
||||
|
||||
if ((fp = fopen(file, "r")) != NULL) {
|
||||
char *x;
|
||||
|
||||
_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, "startx ", x)) {
|
||||
svc_register(x, username);
|
||||
continue;
|
||||
}
|
||||
if (MATCH_CMD(line, "service ", x)) {
|
||||
svc_register(x, NULL);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* version-control: t
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
-384
@@ -1,384 +0,0 @@
|
||||
/*
|
||||
Improved fast init
|
||||
|
||||
Copyright (c) 2008 Claudio Matsuoka
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/reboot.h>
|
||||
#include <sys/wait.h>
|
||||
#include <linux/fs.h>
|
||||
|
||||
#include "helpers.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
#define debug(x...) do { \
|
||||
printf("finit: %d: ", __LINE__); printf(x); printf("\n"); \
|
||||
} while (0)
|
||||
#else
|
||||
#define debug(x...)
|
||||
#endif
|
||||
|
||||
/* Distribution configuration */
|
||||
|
||||
#ifdef DIST_MDV /* Mandriva */
|
||||
#define RANDOMSEED "/var/lib/random-seed"
|
||||
#define SYSROOT "/sysroot"
|
||||
#define GETTY "/sbin/mingetty tty3"
|
||||
#define RUNPARTS "/usr/bin/run-parts --arg=-i"
|
||||
#define DEFUSER "user"
|
||||
#define HOMEDEV "/dev/sda6"
|
||||
#define AGPDRV "intel-agp"
|
||||
#define REMOUNT_ROOTFS_RW
|
||||
#define MAKE_DEVICES
|
||||
#else /* original Eeepc distribution */
|
||||
#define RANDOMSEED "/var/lib/urandom/random-seed"
|
||||
#define SYSROOT "/mnt"
|
||||
#define GETTY "/sbin/getty 38400 tty3"
|
||||
#define RUNPARTS "/bin/run-parts --arg=-i"
|
||||
#define DEFUSER "user"
|
||||
#define TOUCH_ETC_NETWORK_RUN_IFSTATE
|
||||
#endif
|
||||
|
||||
#ifdef DIRECTISA
|
||||
#define HWCLOCK_DIRECTISA " --directisa"
|
||||
#else
|
||||
#define HWCLOCK_DIRECTISA
|
||||
#endif
|
||||
|
||||
|
||||
/* From sysvinit */
|
||||
/* Set a signal handler. */
|
||||
#define SETSIG(sa, sig, fun, flags) \
|
||||
do { \
|
||||
sa.sa_handler = fun; \
|
||||
sa.sa_flags = flags; \
|
||||
sigemptyset(&sa.sa_mask); \
|
||||
sigaction(sig, &sa, NULL); \
|
||||
} while (0)
|
||||
|
||||
#define touch(x) mknod((x), S_IFREG|0644, 0)
|
||||
#define chardev(x,m,maj,min) mknod((x), S_IFCHR|(m), makedev((maj),(min)))
|
||||
|
||||
|
||||
void shutdown(int);
|
||||
void signal_handler(int);
|
||||
void chld_handler(int);
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
int i;
|
||||
FILE *f;
|
||||
char line[2096];
|
||||
int fd;
|
||||
DIR *dir;
|
||||
struct dirent *d;
|
||||
char filename[1024];
|
||||
struct sigaction sa, act;
|
||||
char hline[1024];
|
||||
char *x;
|
||||
sigset_t nmask, nmask2;
|
||||
|
||||
puts("finit-alt " VERSION " (built " __DATE__ " by " WHOAMI ")");
|
||||
|
||||
chdir("/");
|
||||
umask(022);
|
||||
|
||||
/*
|
||||
* Signal management
|
||||
*/
|
||||
for (i = 1; i < NSIG; i++)
|
||||
SETSIG(sa, i, SIG_IGN, SA_RESTART);
|
||||
|
||||
SETSIG(sa, SIGINT, shutdown, 0);
|
||||
SETSIG(sa, SIGPWR, signal_handler, 0);
|
||||
SETSIG(sa, SIGUSR1, shutdown, 0);
|
||||
SETSIG(sa, SIGUSR2, shutdown, 0);
|
||||
SETSIG(sa, SIGTERM, signal_handler, 0);
|
||||
SETSIG(sa, SIGALRM, signal_handler, 0);
|
||||
SETSIG(sa, SIGHUP, signal_handler, 0);
|
||||
SETSIG(sa, SIGCONT, signal_handler, SA_RESTART);
|
||||
SETSIG(sa, SIGCHLD, chld_handler, SA_RESTART);
|
||||
|
||||
/* Block sigchild while forking */
|
||||
sigemptyset(&nmask);
|
||||
sigaddset(&nmask, SIGCHLD);
|
||||
sigprocmask(SIG_BLOCK, &nmask, NULL);
|
||||
|
||||
reboot(RB_DISABLE_CAD);
|
||||
|
||||
mount("proc", "/proc", "proc", 0, NULL);
|
||||
|
||||
/*
|
||||
* Parse kernel parameters
|
||||
*/
|
||||
if ((f = fopen("/proc/cmdline", "r")) != NULL) {
|
||||
fgets(line, 2095, f);
|
||||
if (strstr(line, "quiet")) {
|
||||
close(0);
|
||||
close(1);
|
||||
close(2);
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
setsid();
|
||||
|
||||
/*
|
||||
* Mount filesystems
|
||||
*/
|
||||
debug("mount filesystems");
|
||||
|
||||
#ifdef REMOUNT_ROOTFS_RW
|
||||
system("/bin/mount -n -o remount,rw /");
|
||||
#endif
|
||||
umask(0);
|
||||
|
||||
mkdir("/dev/shm", 0755);
|
||||
mkdir("/dev/pts", 0755);
|
||||
|
||||
mount("sysfs", "/sys", "sysfs", 0, NULL);
|
||||
mount("devpts", "/dev/pts", "devpts", 0, "gid=5,mode=620");
|
||||
mount("tmpfs", "/dev/shm", "tmpfs", 0, NULL);
|
||||
mount("tmpfs", "/tmp", "tmpfs", 0, "mode=1777,size=128m");
|
||||
mount("tmpfs", "/var/run", "tmpfs", 0, "mode=0755");
|
||||
mount("tmpfs", "/var/lock", "tmpfs", 0, "mode=1777");
|
||||
mount(SYSROOT, "/", NULL, MS_MOVE, NULL);
|
||||
|
||||
unlink("/etc/mtab");
|
||||
system("mount -a");
|
||||
|
||||
#ifdef MAKE_DEVICES
|
||||
debug("make devices");
|
||||
mkdir("/dev/input", 0755);
|
||||
chardev("/dev/urandom", 0666, 1, 9);
|
||||
chardev("/dev/ptmx", 0666, 5, 2);
|
||||
chardev("/dev/null", 0666, 1, 3);
|
||||
chardev("/dev/mem", 0640, 1, 1);
|
||||
chmod("/dev/null", 0667);
|
||||
chmod("/dev/mem", 0640);
|
||||
chardev("/dev/tty", 0666, 5, 0);
|
||||
chardev("/dev/input/mice", 0660, 13, 63);
|
||||
chardev("/dev/input/event0", 0660, 13, 64);
|
||||
chardev("/dev/agpgart", 0660, 10, 175);
|
||||
#endif
|
||||
|
||||
umask(0022);
|
||||
|
||||
/*
|
||||
* Time adjustments
|
||||
*/
|
||||
if ((fd = open("/etc/adjtime", O_CREAT|O_WRONLY|O_TRUNC, 0644)) >= 0) {
|
||||
write(fd, "0.0 0 0.0\n", 10);
|
||||
close(fd);
|
||||
}
|
||||
#ifndef NO_HCTOSYS
|
||||
system("/sbin/hwclock --hctosys --localtime" HWCLOCK_DIRECTISA);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Network stuff
|
||||
*/
|
||||
makepath("/dev/shm/network");
|
||||
makepath("/dev/shm/resolvconf/interface");
|
||||
|
||||
if ((dir = opendir("/etc/resolvconf/run/interface")) != NULL) {
|
||||
while ((d = readdir(dir)) != NULL) {
|
||||
if (isalnum(d->d_name[0]))
|
||||
continue;
|
||||
sprintf(filename, "/etc/resolvconf/run/interface/%s",
|
||||
d->d_name);
|
||||
unlink(filename);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
touch("/var/run/utmp");
|
||||
touch("/etc/resolvconf/run/enable-updates");
|
||||
|
||||
chdir("/etc/resolvconf/run/interface");
|
||||
system(RUNPARTS " /etc/resolvconf/update.d");
|
||||
chdir("/");
|
||||
|
||||
#ifdef TOUCH_ETC_NETWORK_RUN_IFSTATE
|
||||
touch("/etc/network/run/ifstate");
|
||||
#endif
|
||||
|
||||
if ((f = fopen("/etc/hostname", "r")) != NULL) {
|
||||
fgets(hline, 1023, f);
|
||||
if ((x = strchr(hline, 0x0a)) != NULL)
|
||||
*x = 0;
|
||||
|
||||
sethostname(hline, strlen(hline));
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
ifconfig("lo", "127.0.0.1", "255.0.0.0", 1);
|
||||
|
||||
/*
|
||||
* Set random seed
|
||||
*/
|
||||
copyfile(RANDOMSEED, "/dev/urandom", 0);
|
||||
unlink(RANDOMSEED);
|
||||
umask(077);
|
||||
copyfile("/dev/urandom", RANDOMSEED, 4096);
|
||||
umask(0);
|
||||
|
||||
/*
|
||||
* Console setup (for X)
|
||||
*/
|
||||
makepath("/var/run/console");
|
||||
touch("/var/run/console/" DEFUSER);
|
||||
|
||||
/*
|
||||
* Misc setup
|
||||
*/
|
||||
mkdir("/tmp/.X11-unix", 01777);
|
||||
mkdir("/tmp/.ICE-unix", 01777);
|
||||
umask(022);
|
||||
|
||||
debug("forking");
|
||||
|
||||
if (!fork()) {
|
||||
/* child process */
|
||||
|
||||
vhangup();
|
||||
|
||||
close(2);
|
||||
close(1);
|
||||
close(0);
|
||||
|
||||
if (open("/dev/tty1", O_RDWR, 0))
|
||||
exit(1);
|
||||
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_handler = SIG_DFL;
|
||||
|
||||
sigemptyset(&nmask2);
|
||||
sigaddset(&nmask2, SIGCHLD);
|
||||
sigprocmask(SIG_UNBLOCK, &nmask2, NULL);
|
||||
|
||||
for (i = 1; i < NSIG; i++)
|
||||
sigaction(i, &sa, NULL);
|
||||
|
||||
dup2(0, 0);
|
||||
dup2(0, 1);
|
||||
dup2(0, 2);
|
||||
|
||||
touch("/tmp/nologin");
|
||||
|
||||
#ifdef AGPDRV
|
||||
system("/sbin/modprobe agpgart");
|
||||
system("/sbin/modprobe " AGPDRV);
|
||||
#endif
|
||||
|
||||
while (access("/tmp/shutdown", F_OK) < 0) {
|
||||
debug("start X as " DEFUSER);
|
||||
#ifdef DEBUG
|
||||
system("su -c startx -l " DEFUSER);
|
||||
system("/bin/sh");
|
||||
#else
|
||||
system("su -c startx -l " DEFUSER " &> /dev/null");
|
||||
#endif
|
||||
}
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* parent process */
|
||||
|
||||
system(GETTY "&");
|
||||
sleep(1);
|
||||
system("/usr/sbin/services.sh &>/dev/null&");
|
||||
|
||||
while (1) {
|
||||
sigemptyset(&nmask);
|
||||
pselect(0, NULL, NULL, NULL, NULL, &nmask);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Shut down on INT USR1 USR2
|
||||
*/
|
||||
void shutdown(int sig)
|
||||
{
|
||||
debug("shutdown");
|
||||
touch("/tmp/shutdown");
|
||||
|
||||
kill(-1, SIGTERM);
|
||||
|
||||
write(1, "\033[?25l\033[30;40m", 14);
|
||||
copyfile("/boot/shutdown.fb", "/dev/fb/0", 0);
|
||||
sleep(2);
|
||||
|
||||
system("/usr/sbin/alsactl store > /dev/null 2>&1");
|
||||
system("/sbin/hwclock --systohc --localtime" HWCLOCK_DIRECTISA);
|
||||
|
||||
kill(-1, SIGKILL);
|
||||
|
||||
sync();
|
||||
sync();
|
||||
system("/bin/mount -n -o remount,ro /");
|
||||
system("/sbin/unionctl.static / --remove / > /dev/null 2>&1");
|
||||
|
||||
if (sig == SIGINT || sig == SIGUSR1)
|
||||
reboot(RB_AUTOBOOT);
|
||||
|
||||
reboot(RB_POWER_OFF);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* SIGCHLD: one of our children has died
|
||||
*/
|
||||
void chld_handler(int sig)
|
||||
{
|
||||
int status;
|
||||
|
||||
while (waitpid(-1, &status, WNOHANG) != 0) {
|
||||
if (errno == ECHILD)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* We got a signal (PWR TERM ALRM HUP CONT)
|
||||
*/
|
||||
void signal_handler(int sig)
|
||||
{
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
-325
@@ -1,325 +0,0 @@
|
||||
/*
|
||||
Improved fast init
|
||||
|
||||
Copyright (c) 2008 Claudio Matsuoka
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
Changelog from the original Eeepc fastinit:
|
||||
|
||||
- Use mknod() instead of close(open()) call to create empty file
|
||||
- Fix random seed initialization
|
||||
- Don't try to handle signal 0, SIGKILL or SIGSTOP
|
||||
- Implement makepath() to avoid system("mkdir -p")
|
||||
- Omit first hwclock if user has CONFIG_RTC_HCTOSYS in kernel (by Metalshark)
|
||||
- Add –directisa to hwclock if user has disabled CONFIG_GENRTC and enabled
|
||||
CONFIG_RTC but not CONFIG_HPET_TIMER and CONFIG_HPET_RTC_IRQ (by Metalshark)
|
||||
- Drop system() call to clean /tmp, it's a fresh mounted tmpfs
|
||||
- Change /proc/acpi/sleep to /sys/power/state (by Metalshark)
|
||||
- Set loopback interface using direct calls instead of system("ifconfig")
|
||||
- Copy 4096 data block in C instead of system("cat") or system("dd")
|
||||
- Draw shutdown splash screen using C calls instead of system("echo;cat")
|
||||
- Change poweroff method from writing 5 to /sys/power/state to
|
||||
reboot(RB_POWER_OFF) (by Metalshark)
|
||||
- Mount /var/run and /var/lock as tmpfs
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/reboot.h>
|
||||
#include <sys/wait.h>
|
||||
#include <linux/fs.h>
|
||||
|
||||
#include "helpers.h"
|
||||
|
||||
#ifdef DIRECTISA
|
||||
#define HWCLOCK_DIRECTISA " --directisa"
|
||||
#else
|
||||
#define HWCLOCK_DIRECTISA
|
||||
#endif
|
||||
|
||||
|
||||
/* From sysvinit */
|
||||
/* Set a signal handler. */
|
||||
#define SETSIG(sa, sig, fun, flags) \
|
||||
do { \
|
||||
sa.sa_handler = fun; \
|
||||
sa.sa_flags = flags; \
|
||||
sigemptyset(&sa.sa_mask); \
|
||||
sigaction(sig, &sa, NULL); \
|
||||
} while(0)
|
||||
|
||||
#define touch(x) mknod((x), S_IFREG|0644, 0)
|
||||
|
||||
|
||||
void shutdown(int);
|
||||
void signal_handler(int);
|
||||
void chld_handler(int);
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
int i;
|
||||
FILE *f;
|
||||
char line[2096];
|
||||
int fd;
|
||||
DIR *dir;
|
||||
struct dirent *d;
|
||||
char filename[1024];
|
||||
struct sigaction sa, act;
|
||||
char hline[1024];
|
||||
char *x;
|
||||
sigset_t nmask, nmask2;
|
||||
|
||||
puts("finit-mod " VERSION " (built " __DATE__ " by " WHOAMI ")");
|
||||
|
||||
chdir("/");
|
||||
umask(022);
|
||||
|
||||
/*
|
||||
* Signal management
|
||||
*/
|
||||
for (i = 1; i < NSIG; i++)
|
||||
SETSIG(sa, i, SIG_IGN, SA_RESTART);
|
||||
|
||||
SETSIG(sa, SIGINT, shutdown, 0);
|
||||
SETSIG(sa, SIGPWR, signal_handler, 0);
|
||||
SETSIG(sa, SIGUSR1, shutdown, 0);
|
||||
SETSIG(sa, SIGUSR2, shutdown, 0);
|
||||
SETSIG(sa, SIGTERM, signal_handler, 0);
|
||||
SETSIG(sa, SIGALRM, signal_handler, 0);
|
||||
SETSIG(sa, SIGHUP, signal_handler, 0);
|
||||
SETSIG(sa, SIGCONT, signal_handler, SA_RESTART);
|
||||
SETSIG(sa, SIGCHLD, chld_handler, SA_RESTART);
|
||||
|
||||
/* Block sigchild while forking */
|
||||
sigemptyset(&nmask);
|
||||
sigaddset(&nmask, SIGCHLD);
|
||||
sigprocmask(SIG_BLOCK, &nmask, NULL);
|
||||
|
||||
reboot(RB_DISABLE_CAD);
|
||||
|
||||
/*
|
||||
* Parse kernel parameters
|
||||
*/
|
||||
if ((f = fopen("/proc/cmdline", "r")) != NULL) {
|
||||
fgets(line, 2095, f);
|
||||
if (strstr(line, "quiet")) {
|
||||
close(0);
|
||||
close(1);
|
||||
close(2);
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
setsid();
|
||||
|
||||
/*
|
||||
* Mount filesystems
|
||||
*/
|
||||
mount("proc", "/proc", "proc", 0, NULL);
|
||||
mount("sysfs", "/sys", "sysfs", 0, NULL);
|
||||
mount("devpts", "/dev/pts", "devpts", 0, "gid=5,mode=620");
|
||||
mount("tmpfs", "/dev/shm", "tmpfs", 0, NULL);
|
||||
mount("tmpfs", "/tmp", "tmpfs", 0, "mode=1777,size=128m");
|
||||
mount("tmpfs", "/var/run", "tmpfs", 0, "mode=0755");
|
||||
mount("tmpfs", "/var/lock", "tmpfs", 0, "mode=1777");
|
||||
mount("/mnt", "/", NULL, MS_MOVE, NULL);
|
||||
|
||||
/*
|
||||
* Time adjustments
|
||||
*/
|
||||
if ((fd = open("/etc/adjtime", O_CREAT|O_WRONLY|O_TRUNC, 0644)) >= 0) {
|
||||
write(fd, "0.0 0 0.0\n", 10);
|
||||
close(fd);
|
||||
}
|
||||
#ifndef NO_HCTOSYS
|
||||
system("/sbin/hwclock --hctosys --localtime" HWCLOCK_DIRECTISA);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Network stuff
|
||||
*/
|
||||
makepath("/dev/shm/network");
|
||||
makepath("/dev/shm/resolvconf/interface");
|
||||
|
||||
if ((dir = opendir("/etc/resolvconf/run/interface")) != NULL) {
|
||||
while ((d = readdir(dir)) != NULL) {
|
||||
if (isalnum(d->d_name[0]))
|
||||
continue;
|
||||
sprintf(filename, "/etc/resolvconf/run/interface/%s",
|
||||
d->d_name);
|
||||
unlink(filename);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
touch("/var/run/utmp");
|
||||
touch("/etc/resolvconf/run/enable-updates");
|
||||
|
||||
chdir("/etc/resolvconf/run/interface");
|
||||
system("/bin/run-parts --arg=-i /etc/resolvconf/update.d");
|
||||
chdir("/");
|
||||
|
||||
touch("/etc/network/run/ifstate");
|
||||
|
||||
if ((f = fopen("/etc/hostname", "r")) != NULL) {
|
||||
fgets(hline, 1023, f);
|
||||
if ((x = strchr(hline, 0x0a)) != NULL)
|
||||
*x = 0;
|
||||
|
||||
sethostname(hline, strlen(hline));
|
||||
fclose(f);
|
||||
|
||||
}
|
||||
|
||||
ifconfig("lo", "127.0.0.1", "255.0.0.0", 1);
|
||||
|
||||
/*
|
||||
* Set random seed
|
||||
*/
|
||||
copyfile("/var/lib/urandom/random-seed", "/dev/urandom", 0);
|
||||
unlink("/var/lib/urandom/random-seed");
|
||||
umask(077);
|
||||
copyfile("/dev/urandom", "/var/lib/urandom/random-seed", 4096);
|
||||
|
||||
/*
|
||||
* Misc setup
|
||||
*/
|
||||
unlink("/var/run/.clean");
|
||||
unlink("/var/lock/.clean");
|
||||
umask(0);
|
||||
mkdir("/tmp/.X11-unix", 01777);
|
||||
mkdir("/tmp/.ICE-unix", 01777);
|
||||
umask(022);
|
||||
|
||||
if (!fork()) {
|
||||
/* child process */
|
||||
|
||||
vhangup();
|
||||
|
||||
close(2);
|
||||
close(1);
|
||||
close(0);
|
||||
|
||||
if (open("/dev/tty1", O_RDWR, 0))
|
||||
exit(1);
|
||||
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_handler = SIG_DFL;
|
||||
|
||||
sigemptyset(&nmask2);
|
||||
sigaddset(&nmask2, SIGCHLD);
|
||||
sigprocmask(SIG_UNBLOCK, &nmask2, NULL);
|
||||
|
||||
for (i = 1; i < NSIG; i++)
|
||||
sigaction(i, &sa, NULL);
|
||||
|
||||
dup2(0, 0);
|
||||
dup2(0, 1);
|
||||
dup2(0, 2);
|
||||
|
||||
touch("/tmp/nologin");
|
||||
|
||||
while (access("/tmp/shutdown", F_OK) < 0)
|
||||
system("su -c startx -l user &> /dev/null");
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* parent process */
|
||||
|
||||
system("/sbin/getty 38400 tty3&");
|
||||
sleep(1);
|
||||
system("/usr/sbin/services.sh &>/dev/null&");
|
||||
|
||||
while (1) {
|
||||
sigemptyset(&nmask);
|
||||
pselect(0, NULL, NULL, NULL, NULL, &nmask);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Shut down on INT USR1 USR2
|
||||
*/
|
||||
void shutdown(int sig)
|
||||
{
|
||||
touch("/tmp/shutdown");
|
||||
|
||||
kill(-1, SIGTERM);
|
||||
|
||||
write(1, "\033[?25l\033[30;40m", 14);
|
||||
copyfile("/boot/shutdown.fb", "/dev/fb/0", 0);
|
||||
sleep(2);
|
||||
|
||||
system("/usr/sbin/alsactl store > /dev/null 2>&1");
|
||||
system("/sbin/hwclock --systohc --localtime" HWCLOCK_DIRECTISA);
|
||||
|
||||
kill(-1, SIGKILL);
|
||||
|
||||
sync();
|
||||
sync();
|
||||
system("/bin/mount -n -o remount,ro /");
|
||||
system("/sbin/unionctl.static / --remove / > /dev/null 2>&1");
|
||||
|
||||
if (sig == SIGINT || sig == SIGUSR1)
|
||||
reboot(RB_AUTOBOOT);
|
||||
|
||||
reboot(RB_POWER_OFF);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* SIGCHLD: one of our children has died
|
||||
*/
|
||||
void chld_handler(int sig)
|
||||
{
|
||||
int status;
|
||||
|
||||
while (waitpid(-1, &status, WNOHANG) != 0) {
|
||||
if (errno == ECHILD)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* We got a signal (PWR TERM ALRM HUP CONT)
|
||||
*/
|
||||
void signal_handler(int sig)
|
||||
{
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
@@ -1,282 +1,209 @@
|
||||
/* Finit - Extremely fast /sbin/init replacement w/ I/O, hook & service plugins
|
||||
*
|
||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||
* Copyright (c) 2008-2012 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <ctype.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/reboot.h>
|
||||
#include <sys/wait.h>
|
||||
#include <linux/fs.h>
|
||||
#include <sys/stat.h> /* umask(), mkdir() */
|
||||
|
||||
#include "finit.h"
|
||||
#include "helpers.h"
|
||||
#include "private.h"
|
||||
#include "plugin.h"
|
||||
#include "svc.h"
|
||||
#include "sig.h"
|
||||
|
||||
int debug = 0;
|
||||
int verbose = 1;
|
||||
char *sdown = NULL;
|
||||
char *network = NULL;
|
||||
char *username = NULL;
|
||||
char *hostname = NULL;
|
||||
|
||||
|
||||
/* From sysvinit */
|
||||
/* Set a signal handler. */
|
||||
#define SETSIG(sa, sig, fun, flags) \
|
||||
do { \
|
||||
sa.sa_handler = fun; \
|
||||
sa.sa_flags = flags; \
|
||||
sigemptyset(&sa.sa_mask); \
|
||||
sigaction(sig, &sa, NULL); \
|
||||
} while(0)
|
||||
|
||||
#define touch(x) close(open((x), O_CREAT|O_WRONLY|O_TRUNC, 0644))
|
||||
|
||||
|
||||
void shutdown(int);
|
||||
void signal_handler(int);
|
||||
void chld_handler(int);
|
||||
|
||||
|
||||
int main()
|
||||
static void parse_kernel_cmdline(void)
|
||||
{
|
||||
int i;
|
||||
FILE *f;
|
||||
char line[2096];
|
||||
int fd;
|
||||
DIR *dir;
|
||||
struct dirent *d;
|
||||
char filename[1024];
|
||||
struct sigaction sa, act;
|
||||
char hline[1024];
|
||||
char *x;
|
||||
sigset_t nmask, nmask2;
|
||||
FILE *fp;
|
||||
char line[LINE_SIZE];
|
||||
|
||||
chdir("/");
|
||||
umask(022);
|
||||
|
||||
if ((fp = fopen("/proc/cmdline", "r")) != NULL) {
|
||||
fgets(line, sizeof(line), fp);
|
||||
_d("Kernel command line: %s", line);
|
||||
|
||||
if (strstr(line, "finit_debug") || strstr(line, "--debug"))
|
||||
debug = 1;
|
||||
|
||||
if (!debug && strstr(line, "quiet"))
|
||||
verbose = 0;
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
|
||||
static int run_loop(void)
|
||||
{
|
||||
while (1) {
|
||||
svc_monitor();
|
||||
plugin_monitor();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int UNUSED(args), char *argv[])
|
||||
{
|
||||
/*
|
||||
* Signal management
|
||||
* Initial setup of signals, ignore all until we're up.
|
||||
*/
|
||||
for (i = 1; i < NSIG; i++)
|
||||
SETSIG(sa, i, SIG_IGN, SA_RESTART);
|
||||
sig_init();
|
||||
|
||||
SETSIG(sa, SIGINT, shutdown, 0);
|
||||
SETSIG(sa, SIGPWR, signal_handler, 0);
|
||||
SETSIG(sa, SIGUSR1, shutdown, 0);
|
||||
SETSIG(sa, SIGUSR2, shutdown, 0);
|
||||
SETSIG(sa, SIGTERM, signal_handler, 0);
|
||||
SETSIG(sa, SIGKILL, signal_handler, 0);
|
||||
SETSIG(sa, SIGALRM, signal_handler, 0);
|
||||
SETSIG(sa, SIGHUP, signal_handler, 0);
|
||||
SETSIG(sa, SIGSTOP, signal_handler, SA_RESTART);
|
||||
SETSIG(sa, SIGCONT, signal_handler, SA_RESTART);
|
||||
SETSIG(sa, SIGCHLD, chld_handler, SA_RESTART);
|
||||
|
||||
/* Block sigchild while forking */
|
||||
sigemptyset(&nmask);
|
||||
sigaddset(&nmask, SIGCHLD);
|
||||
sigprocmask(SIG_BLOCK, &nmask, NULL);
|
||||
|
||||
reboot(RB_DISABLE_CAD);
|
||||
/*
|
||||
* Mount base file system, kernel is assumed to run devtmpfs for /dev
|
||||
*/
|
||||
chdir("/");
|
||||
umask(0);
|
||||
mount("none", "/proc", "proc", 0, NULL);
|
||||
mount("none", "/proc/bus/usb", "usbfs", 0, NULL);
|
||||
mount("none", "/sys", "sysfs", 0, NULL);
|
||||
mkdir("/dev/pts", 0755);
|
||||
mkdir("/dev/shm", 0755);
|
||||
mount("none", "/dev/pts", "devpts", 0, "gid=5,mode=620");
|
||||
mount("none", "/dev/shm", "tmpfs", 0, NULL);
|
||||
umask(022);
|
||||
|
||||
/*
|
||||
* Parse kernel parameters
|
||||
*/
|
||||
if ((f = fopen("/proc/cmdline", "r")) != NULL) {
|
||||
fgets(line, 2095, f);
|
||||
if (strstr(line, "quiet")) {
|
||||
close(0);
|
||||
close(1);
|
||||
close(2);
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
parse_kernel_cmdline();
|
||||
|
||||
setsid();
|
||||
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
|
||||
|
||||
/*
|
||||
* Parse configuration file
|
||||
*/
|
||||
parse_finit_conf(FINIT_CONF);
|
||||
|
||||
/*
|
||||
* Load plugins. Must run after finit.conf has registered
|
||||
* all services, or service plugins won't have anything to
|
||||
* hook on to.
|
||||
*/
|
||||
print_desc("", "Loading plugins");
|
||||
print_result(plugin_load_all(PLUGIN_PATH));
|
||||
|
||||
/*
|
||||
* Mount filesystems
|
||||
*/
|
||||
mount("proc", "/proc", "proc", 0, NULL);
|
||||
mount("sysfs", "/sys", "sysfs", 0, NULL);
|
||||
mount("devpts", "/dev/pts", "devpts", 0, "gid=5,mode=620");
|
||||
mount("tmpfs", "/dev/shm", "tmpfs", 0, NULL);
|
||||
mount("tmpfs", "/tmp", "tmpfs", 0, "mode=1777,size=128m");
|
||||
mount("/mnt", "/", NULL, MS_MOVE, NULL);
|
||||
_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);
|
||||
|
||||
umask(0);
|
||||
run("/bin/mount -na");
|
||||
run("/sbin/swapon -ea");
|
||||
umask(0022);
|
||||
|
||||
/* Cleanup stale files, if any still linger on. */
|
||||
run_interactive("rm -rf /tmp/* /var/run/* /var/lock/*", "Cleanup temporary directories");
|
||||
|
||||
/*
|
||||
* Time adjustments
|
||||
* Base FS up, enable standard SysV init signals
|
||||
*/
|
||||
if ((fd = open("/etc/adjtime", O_CREAT|O_WRONLY|O_TRUNC, 0644)) >= 0) {
|
||||
write(fd, "0.0 0 0.0\n", 10);
|
||||
close(fd);
|
||||
}
|
||||
system("/sbin/hwclock --hctosys --localtime");
|
||||
sig_setup();
|
||||
|
||||
_d("Base FS up, calling hooks ...");
|
||||
plugin_run_hooks(HOOK_BASEFS_UP);
|
||||
|
||||
/*
|
||||
* Network stuff
|
||||
*/
|
||||
system("mkdir -p /dev/shm/network");
|
||||
system("mkdir -p /dev/shm/resolvconf/interface");
|
||||
|
||||
if ((dir = opendir("/etc/resolvconf/run/interface")) != NULL) {
|
||||
while ((d = readdir(dir)) != NULL) {
|
||||
if (isalnum(d->d_name[0]))
|
||||
continue;
|
||||
sprintf(filename, "/etc/resolvconf/run/interface/%s",
|
||||
d->d_name);
|
||||
unlink(filename);
|
||||
}
|
||||
/* Setup kernel specific settings, e.g. allow broadcast ping, etc. */
|
||||
run("/sbin/sysctl -e -p /etc/sysctl.conf >/dev/null");
|
||||
|
||||
closedir(dir);
|
||||
}
|
||||
/* Set initial hostname. */
|
||||
set_hostname(hostname);
|
||||
|
||||
touch("/var/run/utmp");
|
||||
touch("/etc/resolvconf/run/enable-updates");
|
||||
|
||||
chdir("/etc/resolvconf/run/interface");
|
||||
system("/bin/run-parts --arg=-i /etc/resolvconf/update.d");
|
||||
chdir("/");
|
||||
|
||||
touch("/etc/network/run/ifstate");
|
||||
|
||||
if ((f = fopen("/etc/hostname", "r")) != NULL) {
|
||||
fgets(hline, 1023, f);
|
||||
if ((x = strchr(hline, 0x0a)) != NULL)
|
||||
*x = 0;
|
||||
|
||||
sethostname(hline, strlen(hline));
|
||||
fclose(f);
|
||||
|
||||
}
|
||||
|
||||
system("/sbin/ifconfig lo 127.0.0.1 netmask 255.0.0.0 up > /dev/null");
|
||||
|
||||
/*
|
||||
* Set random seed
|
||||
*/
|
||||
/* Bug: the eeepc never sets its random seed from file */
|
||||
system("/bin/cat /var/lib/urandom/random-seed >/dev/urandom "
|
||||
"> /dev/null 2>&1");
|
||||
unlink("/var/lib/urandom/random-seed");
|
||||
|
||||
umask(077);
|
||||
system("/bin/dd if=/dev/urandom of=/var/lib/urandom/random-seed "
|
||||
"bs=4096 count=1 >/dev/null 2>&1");
|
||||
|
||||
/*
|
||||
* Misc setup
|
||||
*/
|
||||
/* not really needed, /tmp is a fresh mounted tmpfs */
|
||||
system("/bin/rm -rf /tmp/* /tmp/.* 2>/dev/null");
|
||||
|
||||
unlink("/var/run/.clean");
|
||||
unlink("/var/lock/.clean");
|
||||
umask(0);
|
||||
mkdir("/tmp/.X11-unix", 01777);
|
||||
mkdir("/tmp/.ICE-unix", 01777);
|
||||
ifconfig("lo", "127.0.0.1", "255.0.0.0", 1);
|
||||
if (network)
|
||||
run_interactive(network, "Starting networking: %s", network);
|
||||
umask(022);
|
||||
|
||||
if (!fork()) {
|
||||
/* child process */
|
||||
/*
|
||||
* Hooks that rely on loopback, or basic networking being up.
|
||||
*/
|
||||
plugin_run_hooks(HOOK_NETWORK_UP);
|
||||
|
||||
vhangup();
|
||||
/*
|
||||
* Start service monitor framework
|
||||
*/
|
||||
_d("Starting all static services from %s", FINIT_CONF);
|
||||
svc_start_all();
|
||||
|
||||
close(2);
|
||||
close(1);
|
||||
close(0);
|
||||
/*
|
||||
* Run startup scripts in /etc/finit.d/, if any.
|
||||
*/
|
||||
_d("Running startup scripts in /etc/finit.d/ ...");
|
||||
run_parts(FINIT_RCSD);
|
||||
|
||||
if (open("/dev/tty1", O_RDWR, 0))
|
||||
exit(1);
|
||||
/*
|
||||
* Hooks that should run at the very end
|
||||
*/
|
||||
plugin_run_hooks(HOOK_SYSTEM_UP);
|
||||
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_handler = SIG_DFL;
|
||||
/* Start GETTY on console */
|
||||
_d("Starting getty on console ...");
|
||||
run_getty(GETTY, argv);
|
||||
|
||||
sigemptyset(&nmask2);
|
||||
sigaddset(&nmask2, SIGCHLD);
|
||||
sigprocmask(SIG_UNBLOCK, &nmask2, NULL);
|
||||
|
||||
/* Bug: no signal 0 */
|
||||
for (i = 0; i < NSIG; i++)
|
||||
sigaction(i, &sa, NULL);
|
||||
|
||||
dup2(0, 0);
|
||||
dup2(0, 1);
|
||||
dup2(0, 2);
|
||||
|
||||
touch("/tmp/nologin");
|
||||
|
||||
while (access("/tmp/shutdown", F_OK) < 0)
|
||||
system("su -c startx -l user &> /dev/null");
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* parent process */
|
||||
|
||||
system("/sbin/getty 38400 tty3 &");
|
||||
sleep(1);
|
||||
system("/usr/sbin/services.sh &> /dev/null &");
|
||||
|
||||
while (1) {
|
||||
sigemptyset(&nmask);
|
||||
pselect(0, NULL, NULL, NULL, NULL, &nmask);
|
||||
}
|
||||
/*
|
||||
* Enter main loop to monior /dev/initctl and services
|
||||
*/
|
||||
_d("Entering main loop ...");
|
||||
return run_loop();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Shut down on INT USR1 USR2
|
||||
/**
|
||||
* Local Variables:
|
||||
* version-control: t
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
void shutdown(int sig)
|
||||
{
|
||||
int fd;
|
||||
|
||||
system("/usr/bin/touch /tmp/shutdown");
|
||||
|
||||
kill(-1, SIGTERM);
|
||||
|
||||
system("/bin/echo -e \"\033[?25l\033[30;40m\"; "
|
||||
"/bin/cp /boot/shutdown.fb /dev/fb/0");
|
||||
sleep(1);
|
||||
sleep(1);
|
||||
|
||||
system("/usr/sbin/alsactl store > /dev/null 2>&1");
|
||||
system("/sbin/hwclock --systohc --localtime");
|
||||
|
||||
kill(-1, SIGKILL);
|
||||
|
||||
sync();
|
||||
sync();
|
||||
system("/bin/mount -n -o remount,ro /");
|
||||
system("/sbin/unionctl.static / --remove / > /dev/null 2>&1");
|
||||
|
||||
if (sig == SIGINT || sig == SIGUSR1)
|
||||
reboot(RB_AUTOBOOT);
|
||||
|
||||
if ((fd = open("/proc/acpi/sleep", O_WRONLY)) >= 0) {
|
||||
write(fd, "5", 1);
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* SIGCHLD: one of our children has died
|
||||
*/
|
||||
void chld_handler(int sig)
|
||||
{
|
||||
int status;
|
||||
|
||||
while (waitpid(-1, &status, WNOHANG) != 0) {
|
||||
if (errno == ECHILD)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* We got a signal (PWR TERM ALRM HUP STOP CONT)
|
||||
*/
|
||||
void signal_handler(int sig)
|
||||
{
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
# Simple Debian finit.conf
|
||||
check /dev/vda1
|
||||
module evdev
|
||||
module loop
|
||||
module psmouse
|
||||
user admin
|
||||
host testbed
|
||||
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
|
||||
@@ -0,0 +1,81 @@
|
||||
/* Finit - Extremely fast /sbin/init replacement w/ I/O, hook & service plugins
|
||||
*
|
||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||
* Copyright (c) 2008-2012 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef FINIT_H_
|
||||
#define FINIT_H_
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* Distribution configuration */
|
||||
|
||||
#if defined EMBEDDED_SYSTEM
|
||||
# define CONSOLE "/dev/console"
|
||||
# define MDEV "/sbin/mdev"
|
||||
# define GETTY "/sbin/getty -L 115200 ttyS0 vt100"
|
||||
#else /* Debian/Ubuntu based distributions */
|
||||
# define RANDOMSEED "/var/lib/urandom/random-seed"
|
||||
# define CONSOLE "/dev/tty1"
|
||||
# define GETTY "/sbin/getty -8 38400 tty1"
|
||||
# define REMOUNT_ROOTFS_RW
|
||||
# define RUNLEVEL 2
|
||||
# define USE_UDEV
|
||||
# define USE_MESSAGE_BUS
|
||||
#endif
|
||||
|
||||
#ifndef DEFUSER
|
||||
# define DEFUSER "root"
|
||||
#endif
|
||||
#ifndef DEFHOST
|
||||
# define DEFHOST "noname"
|
||||
#endif
|
||||
|
||||
#define CMD_SIZE 256
|
||||
#define LINE_SIZE 1024
|
||||
#define BUF_SIZE 4096
|
||||
#define USERNAME_SIZE 16
|
||||
#define HOSTNAME_SIZE 32
|
||||
|
||||
extern char *sdown;
|
||||
extern char *network;
|
||||
extern char *hostname;
|
||||
extern char *username;
|
||||
|
||||
/* conf.c */
|
||||
void parse_finit_conf(char *file);
|
||||
|
||||
#endif /* FINIT_H_ */
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* version-control: t
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -1,38 +1,86 @@
|
||||
/* Misc. utility functions and C-library extensions for finit and its plugins
|
||||
*
|
||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||
* Copyright (c) 2008-2012 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <ctype.h> /* isdigit() */
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <dirent.h>
|
||||
#include <stdarg.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <grp.h>
|
||||
#include <pwd.h>
|
||||
|
||||
#include "finit.h"
|
||||
#include "helpers.h"
|
||||
#include "private.h"
|
||||
#include "sig.h"
|
||||
#include "lite.h"
|
||||
|
||||
#define NUM_ARGS 16
|
||||
#define NUM_SCRIPTS 128 /* ought to be enough for anyone */
|
||||
|
||||
/*
|
||||
* Helpers to replace system() calls
|
||||
*/
|
||||
|
||||
int makepath(char *p)
|
||||
int makepath(char *path)
|
||||
{
|
||||
char *x, path[PATH_MAX];
|
||||
char buf[PATH_MAX];
|
||||
char *x = buf;
|
||||
int ret;
|
||||
|
||||
x = path;
|
||||
|
||||
if (!path) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
do {
|
||||
do { *x++ = *p++; } while (*p && *p != '/');
|
||||
do {
|
||||
*x++ = *path++;
|
||||
} while (*path && *path != '/');
|
||||
|
||||
*x = 0;
|
||||
ret = mkdir(path, 0777);
|
||||
} while (*p && (*p != '/' || *(p + 1))); /* ignore trailing slash */
|
||||
ret = mkdir(buf, 0777);
|
||||
} while (*path && (*path != '/' || *(path + 1))); /* ignore trailing slash */
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ifconfig(char *name, char *inet, char *mask, int up)
|
||||
void ifconfig(char *ifname, char *addr, char *mask, int up)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
struct sockaddr_in *a = (struct sockaddr_in *)&ifr.ifr_addr;
|
||||
@@ -42,14 +90,18 @@ void ifconfig(char *name, char *inet, char *mask, int up)
|
||||
return;
|
||||
|
||||
memset(&ifr, 0, sizeof (ifr));
|
||||
strncpy(ifr.ifr_name, name, IFNAMSIZ);
|
||||
a->sin_family = AF_INET;
|
||||
strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
|
||||
ifr.ifr_addr.sa_family = AF_INET;
|
||||
|
||||
if (up) {
|
||||
inet_aton(inet, &a->sin_addr);
|
||||
ioctl(sock, SIOCSIFADDR, &ifr);
|
||||
inet_aton(mask, &a->sin_addr);
|
||||
ioctl(sock, SIOCSIFNETMASK, &ifr);
|
||||
if (addr) {
|
||||
inet_aton(addr, &a->sin_addr);
|
||||
ioctl(sock, SIOCSIFADDR, &ifr);
|
||||
}
|
||||
if (mask) {
|
||||
inet_aton(mask, &a->sin_addr);
|
||||
ioctl(sock, SIOCSIFNETMASK, &ifr);
|
||||
}
|
||||
}
|
||||
|
||||
ioctl(sock, SIOCGIFFLAGS, &ifr);
|
||||
@@ -64,29 +116,587 @@ void ifconfig(char *name, char *inet, char *mask, int up)
|
||||
close(sock);
|
||||
}
|
||||
|
||||
#define BUF_SIZE 4096
|
||||
|
||||
void copyfile(char *src, char *dst, int size)
|
||||
/**
|
||||
* pidfile_read - Reads a PID value from a pidfile.
|
||||
* @pidfile: File containing PID, usually in /var/run/<PROC>.pid
|
||||
*
|
||||
* This function takes a @pidfile and returns the PID found therein.
|
||||
*
|
||||
* Returns:
|
||||
* On invalid @pidfile -1 and @errno set to %EINVAL, when @pidfile does not exist -1
|
||||
* and errno set to %ENOENT. When the pidfile is empty or when its contents cannot
|
||||
* be translated this function returns zero (0), on success this function returns
|
||||
* a PID value greater than one. PID 1 is reserved for the system init process.
|
||||
*/
|
||||
pid_t pidfile_read(char *pidfile)
|
||||
{
|
||||
char buffer[BUF_SIZE];
|
||||
int s, d, n;
|
||||
pid_t pid = 0;
|
||||
char buf[16];
|
||||
FILE *fp;
|
||||
|
||||
/* Size == 0 means copy entire file */
|
||||
if (size == 0)
|
||||
size = INT_MAX;
|
||||
if (!pidfile) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((s = open(src, O_RDONLY)) >= 0) {
|
||||
if ((d = open(dst, O_WRONLY | O_CREAT, 0644)) >= 0) {
|
||||
do {
|
||||
int csize = size > BUF_SIZE ? BUF_SIZE : size;
|
||||
|
||||
if ((n = read(s, buffer, csize)) > 0)
|
||||
write(d, buffer, n);
|
||||
size -= csize;
|
||||
} while (size > 0 && n == BUF_SIZE);
|
||||
close(d);
|
||||
}
|
||||
close(s);
|
||||
}
|
||||
if (!fexist(pidfile))
|
||||
return -1;
|
||||
|
||||
fp = fopen(pidfile, "r");
|
||||
if (!fp)
|
||||
return -1;
|
||||
|
||||
if (fgets(buf, sizeof(buf), fp)) {
|
||||
errno = 0;
|
||||
pid = strtoul(buf, NULL, 0);
|
||||
if (errno)
|
||||
pid = 0; /* Failed conversion. */
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
return pid;
|
||||
}
|
||||
|
||||
/**
|
||||
* pidfile_poll - Poll for the existence of a pidfile and return PID
|
||||
* @cmd: Process name, or command, called to expect a pidfile
|
||||
* @path: Path to pidfile to poll for
|
||||
*
|
||||
* This function polls for the pidfile at @path for at most 5 seconds
|
||||
* before timing out. If the file is created within that time span the
|
||||
* file is read and its PID contents returned.
|
||||
*
|
||||
* Returns:
|
||||
* The PID read from @path, or zero on timeout.
|
||||
*/
|
||||
pid_t pidfile_poll(char *cmd, char *path)
|
||||
{
|
||||
pid_t pid = 0;
|
||||
int tries = 0;
|
||||
|
||||
/* Timeout = 100 * 50ms = 5s */
|
||||
while (!fexist(path) && tries++ < 100) {
|
||||
/* Wait 50ms between retries */
|
||||
usleep(50000);
|
||||
}
|
||||
|
||||
if (!fexist(path)) {
|
||||
_e("Timeout! No PID found for %s, pidfile %s does not exist?", cmd, path);
|
||||
pid = 0;
|
||||
} else {
|
||||
pid = pidfile_read(path);
|
||||
}
|
||||
|
||||
return pid;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* pid_alive - Check if a given process ID is running
|
||||
* @pid: Process ID to check for.
|
||||
*
|
||||
* Returns:
|
||||
* %TRUE(1) if pid is alive (/proc/pid exists), otherwise %FALSE(0)
|
||||
*/
|
||||
int pid_alive(pid_t pid)
|
||||
{
|
||||
char name[24]; /* Enough for max pid_t */
|
||||
|
||||
snprintf(name, sizeof(name), "/proc/%d", pid);
|
||||
|
||||
return fexist(name);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* pid_get_name - Find name of a process
|
||||
* @pid: PID of process to find.
|
||||
* @name: Pointer to buffer where to return process name, may be %NULL
|
||||
* @len: Length in bytes of @name buffer.
|
||||
*
|
||||
* If @name is %NULL, or @len is zero the function will return
|
||||
* a static string. This may be useful to one-off calls.
|
||||
*
|
||||
* Returns:
|
||||
* %NULL on error, otherwise a va
|
||||
*/
|
||||
char *pid_get_name(pid_t pid, char *name, size_t len)
|
||||
{
|
||||
int ret = 1;
|
||||
FILE *fp;
|
||||
char path[32];
|
||||
static char line[64];
|
||||
|
||||
if (!name || len == 0)
|
||||
name = line;
|
||||
|
||||
snprintf(path, sizeof(path), "/proc/%d/status", pid);
|
||||
if ((fp = fopen(path, "r")) != NULL) {
|
||||
if (fgets(line, sizeof (line), fp)) {
|
||||
char *pname = line + 6; /* Skip first part of line --> "Name:\t" */
|
||||
|
||||
chomp(pname);
|
||||
strlcpy(name, pname, len);
|
||||
ret = 0; /* Found it! */
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
if (ret)
|
||||
return NULL;
|
||||
|
||||
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.
|
||||
* @signo: Signal to send.
|
||||
*
|
||||
* Send a signal to a running process (group). This function searches
|
||||
* for a given process @name and sends a signal, @signo, to each
|
||||
* process ID matching that @name.
|
||||
*
|
||||
* Returns:
|
||||
* Number of signals sent, i.e. number of processes who have received the signal.
|
||||
*/
|
||||
int procname_kill (char *name, int signo)
|
||||
{
|
||||
int result = 0;
|
||||
char path[32], line[64];
|
||||
FILE *fp;
|
||||
DIR *dir;
|
||||
struct dirent *entry;
|
||||
|
||||
dir = opendir("/proc");
|
||||
if (!dir || !name) {
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
while ((entry = readdir (dir)) != NULL) {
|
||||
/* Skip non-process entries in /proc */
|
||||
if (!isdigit (*entry->d_name))
|
||||
continue;
|
||||
|
||||
snprintf (path, sizeof(path), "/proc/%s/status", entry->d_name);
|
||||
/* Skip non-readable files (protected?) */
|
||||
if ((fp = fopen (path, "r")) == NULL)
|
||||
continue;
|
||||
|
||||
if (fgets (line, sizeof (line), fp)) {
|
||||
char *pname = line + 6; /* Skip first part of line --> "Name:\t" */
|
||||
|
||||
if (strncmp(pname, name, strlen(pname) - 1) == 0) {
|
||||
int error = errno;
|
||||
|
||||
if (kill(atoi(entry->d_name), signo)) {
|
||||
FLOG_ERROR("Failed signalling(%d) %s: %s!", signo, name, strerror(error));
|
||||
} else {
|
||||
result++; /* Track number of processes we deliver the signal to. */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static int print_uptime(void)
|
||||
{
|
||||
#if defined(CONFIG_PRINTK_TIME)
|
||||
FILE * uptimefile;
|
||||
float num1, num2;
|
||||
char uptime_str[30];
|
||||
|
||||
if((uptimefile = fopen("/proc/uptime", "r")) == NULL)
|
||||
return 1;
|
||||
|
||||
fgets(uptime_str, 20, uptimefile);
|
||||
fclose(uptimefile);
|
||||
|
||||
sscanf(uptime_str, "%f %f", &num1, &num2);
|
||||
sprintf(uptime_str, "[ %.6f ]", num1);
|
||||
|
||||
write(STDERR_FILENO, uptime_str, strlen(uptime_str));
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
void print_desc(char *action, char *desc)
|
||||
{
|
||||
const char home[] = "\r\e[K";
|
||||
const char dots[] = " .....................................................................";
|
||||
|
||||
write(STDERR_FILENO, home, strlen(home));
|
||||
|
||||
print_uptime();
|
||||
|
||||
write(STDERR_FILENO, action, strlen(action));
|
||||
write(STDERR_FILENO, desc, strlen(desc));
|
||||
write(STDERR_FILENO, dots, 60 - strlen(desc) - strlen(action)); /* pad with dots. */
|
||||
}
|
||||
|
||||
int print_result(int fail)
|
||||
{
|
||||
if (fail)
|
||||
fprintf(stderr, " \e[7m[FAIL]\e[0m\n");
|
||||
else
|
||||
fprintf(stderr, " \e[1m[ OK ]\e[0m\n");
|
||||
|
||||
return fail;
|
||||
}
|
||||
|
||||
int run(char *cmd)
|
||||
{
|
||||
int status, result, i = 0;
|
||||
FILE *fp;
|
||||
char *args[NUM_ARGS + 1], *arg, *backup;
|
||||
pid_t pid;
|
||||
|
||||
/* We must create a copy that is possible to modify. */
|
||||
backup = arg = strdup(cmd);
|
||||
if (!arg)
|
||||
return 1; /* Failed allocating a string to be modified. */
|
||||
|
||||
/* Split command line into tokens of an argv[] array. */
|
||||
args[i++] = strsep(&arg, "\t ");
|
||||
do {
|
||||
/* Handle run("su -c \"dbus-daemon --system\" messagebus");
|
||||
* => "su", "-c", "\"dbus-daemon --system\"", "messagebus" */
|
||||
if (*arg == '\'' || *arg == '"') {
|
||||
char *p, delim[2] = " ";
|
||||
|
||||
delim[0] = arg[0];
|
||||
args[i++] = arg++;
|
||||
strsep(&arg, delim);
|
||||
p = arg - 1;
|
||||
*p = *delim;
|
||||
*arg++ = 0;
|
||||
} else {
|
||||
args[i++] = strsep(&arg, "\t ");
|
||||
}
|
||||
} while (arg && i < NUM_ARGS);
|
||||
args[i] = NULL;
|
||||
#if 0
|
||||
_e("Splitting: '%s' =>", cmd);
|
||||
for (i = 0; args[i]; i++)
|
||||
_e("\t%s", args[i]);
|
||||
#endif
|
||||
if (i == NUM_ARGS && args[i]) {
|
||||
_e("Command too long: %s", cmd);
|
||||
free(backup);
|
||||
errno = EOVERFLOW;
|
||||
return 1;
|
||||
}
|
||||
|
||||
fp = fopen("/dev/null", "w");
|
||||
pid = fork();
|
||||
if (0 == pid) {
|
||||
int i;
|
||||
struct sigaction sa;
|
||||
|
||||
/* Reset signal handlers that were set by the parent process */
|
||||
for (i = 1; i < NSIG; i++)
|
||||
DFLSIG(sa, i, 0);
|
||||
|
||||
/* Redirect stdio if the caller requested so. */
|
||||
if (fp) {
|
||||
int fd = fileno(fp);
|
||||
|
||||
dup2(fd, STDIN_FILENO);
|
||||
dup2(fd, STDOUT_FILENO);
|
||||
dup2(fd, STDERR_FILENO);
|
||||
}
|
||||
|
||||
execvp(args[0], args);
|
||||
_exit(1); /* Only if execv() fails. */
|
||||
} else if (-1 == pid) {
|
||||
_pe("%s", args[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
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);
|
||||
free(backup);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
result = WEXITSTATUS(status);
|
||||
if (WIFEXITED(status)) {
|
||||
_d("Started %s and ended OK: %d", args[0], result);
|
||||
} else if (WIFSIGNALED(status)) {
|
||||
_d("Process %s terminated by signal %d", args[0], WTERMSIG(status));
|
||||
if (!result)
|
||||
result = 1; /* Must alert callee that the command did complete successfully.
|
||||
* This is necessary since not all programs trap signals and
|
||||
* change their return code accordingly. --Jocke */
|
||||
}
|
||||
|
||||
if (fp) fclose(fp);
|
||||
free(backup);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int run_interactive(char *cmd, char *fmt, ...)
|
||||
{
|
||||
int status, oldout = 1, olderr = 2;
|
||||
char line[LINE_SIZE];
|
||||
va_list ap;
|
||||
FILE *fp = tmpfile();
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(line, sizeof(line), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
print_desc("", line);
|
||||
if (fp && !debug) {
|
||||
oldout = dup(STDOUT_FILENO);
|
||||
olderr = dup(STDERR_FILENO);
|
||||
dup2(fileno(fp), STDOUT_FILENO);
|
||||
dup2(fileno(fp), STDERR_FILENO);
|
||||
}
|
||||
status = run(cmd);
|
||||
if (fp && !debug) {
|
||||
dup2(oldout, STDOUT_FILENO);
|
||||
dup2(olderr, STDERR_FILENO);
|
||||
}
|
||||
print_result(status);
|
||||
if (fp && !debug) {
|
||||
size_t len, written;
|
||||
|
||||
rewind(fp);
|
||||
do {
|
||||
len = fread(line, 1, sizeof(line), fp);
|
||||
written = fwrite(line, len, sizeof(char), stderr);
|
||||
} while (len > 0 && written == len);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
pid_t run_getty(char *cmd, char *argv[])
|
||||
{
|
||||
pid_t pid = fork();
|
||||
|
||||
if (!pid) {
|
||||
int i;
|
||||
char c;
|
||||
sigset_t nmask;
|
||||
struct sigaction sa;
|
||||
|
||||
/* Detach from initial controlling TTY */
|
||||
vhangup();
|
||||
|
||||
close(2);
|
||||
close(1);
|
||||
close(0);
|
||||
|
||||
/* Attach TTY to console */
|
||||
if (open(CONSOLE, O_RDWR) != 0)
|
||||
exit(1);
|
||||
|
||||
sigemptyset(&nmask);
|
||||
sigaddset(&nmask, SIGCHLD);
|
||||
sigprocmask(SIG_UNBLOCK, &nmask, NULL);
|
||||
|
||||
/* Reset signal handlers that were set by the parent process */
|
||||
for (i = 1; i < NSIG; i++)
|
||||
DFLSIG(sa, i, 0);
|
||||
|
||||
dup2(0, STDIN_FILENO);
|
||||
dup2(0, STDOUT_FILENO);
|
||||
dup2(0, STDERR_FILENO);
|
||||
|
||||
procname_set("console", argv);
|
||||
|
||||
while (!fexist(SYNC_SHUTDOWN)) {
|
||||
static const char msg[] = "\nPlease press Enter to activate this console. ";
|
||||
|
||||
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 (fexist(SYNC_STOPPED))
|
||||
continue;
|
||||
|
||||
run(cmd);
|
||||
}
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
return pid;
|
||||
}
|
||||
|
||||
static int cmp(const void *s1, const void *s2)
|
||||
{
|
||||
return strcmp(*(char **)s1, *(char **)s2);
|
||||
}
|
||||
|
||||
int run_parts(char *dir, ...)
|
||||
{
|
||||
DIR *d;
|
||||
struct dirent *e;
|
||||
struct stat st;
|
||||
char *oldpwd = NULL;
|
||||
char *ent[NUM_SCRIPTS];
|
||||
int i, num = 0, argnum = 1;
|
||||
char *args[NUM_ARGS];
|
||||
va_list ap;
|
||||
|
||||
oldpwd = getcwd (NULL, 0);
|
||||
if (chdir(dir)) {
|
||||
if (oldpwd) free(oldpwd);
|
||||
return -1;
|
||||
}
|
||||
if ((d = opendir(dir)) == NULL) {
|
||||
if (oldpwd) free(oldpwd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
va_start(ap, dir);
|
||||
while (argnum < NUM_ARGS && (args[argnum++] = va_arg(ap, char *)));
|
||||
va_end(ap);
|
||||
|
||||
while ((e = readdir(d))) {
|
||||
if (e->d_type == DT_REG && stat(e->d_name, &st) == 0) {
|
||||
_d("Found %s/%s ...", dir, e->d_name);
|
||||
if (st.st_mode & S_IXUSR) {
|
||||
ent[num++] = strdup(e->d_name);
|
||||
if (num >= NUM_SCRIPTS)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
closedir(d);
|
||||
|
||||
if (num == 0) {
|
||||
if (oldpwd) free(oldpwd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
qsort(ent, num, sizeof(char *), cmp);
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
pid_t pid = 0;
|
||||
int status;
|
||||
|
||||
args[0] = ent[i];
|
||||
args[1] = NULL;
|
||||
|
||||
pid = fork();
|
||||
if (!pid) {
|
||||
_d("Calling %s ...", ent[i]);
|
||||
execv(ent[i], args);
|
||||
exit(0);
|
||||
}
|
||||
waitpid(pid, &status, 0);
|
||||
free(ent[i]);
|
||||
}
|
||||
|
||||
chdir(oldpwd);
|
||||
free(oldpwd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int getuser(char *username)
|
||||
{
|
||||
struct passwd *usr;
|
||||
|
||||
if (!username || (usr = getpwnam(username)) == NULL)
|
||||
return -1;
|
||||
|
||||
return usr->pw_uid;
|
||||
}
|
||||
|
||||
int getgroup(char *group)
|
||||
{
|
||||
struct group *grp;
|
||||
|
||||
if ((grp = getgrnam(group)) == NULL)
|
||||
return -1;
|
||||
|
||||
return grp->gr_gid;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
if ((x = strchr((str), 0x0a)) != NULL)
|
||||
*x = 0;
|
||||
}
|
||||
|
||||
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);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
sethostname(hostname, strlen(hostname));
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* version-control: t
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
|
||||
@@ -1,8 +1,102 @@
|
||||
#ifndef __FINIT_HELPERS_H
|
||||
#define __FINIT_HELPERS_H
|
||||
/* Misc. utility functions and C-library extensions for finit and its plugins
|
||||
*
|
||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||
* Copyright (c) 2008-2012 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
int makepath (char *);
|
||||
void ifconfig (char *, char *, char *, int);
|
||||
void copyfile (char *, char *, int);
|
||||
#ifndef FINIT_HELPERS_H_
|
||||
#define FINIT_HELPERS_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <syslog.h>
|
||||
|
||||
#define DO_LOG(level, fmt, args...) \
|
||||
{ \
|
||||
openlog("finit", LOG_CONS | LOG_PID, LOG_DAEMON); \
|
||||
syslog(level, fmt, ##args); \
|
||||
closelog(); \
|
||||
}
|
||||
|
||||
#define FLOG_DEBUG(fmt, args...) DO_LOG(LOG_DEBUG, fmt, ##args)
|
||||
#define FLOG_ERROR(fmt, args...) DO_LOG(LOG_CRIT, fmt, ##args)
|
||||
#define FLOG_PERROR(fmt, args...) DO_LOG(LOG_CRIT, fmt ". Error %d: %s", ##args, errno, strerror(errno))
|
||||
|
||||
|
||||
#ifndef touch
|
||||
# define touch(x) mknod((x), S_IFREG|0644, 0)
|
||||
#endif
|
||||
#ifndef chardev
|
||||
# define chardev(x,m,maj,min) mknod((x), S_IFCHR|(m), makedev((maj),(min)))
|
||||
#endif
|
||||
#ifndef blkdev
|
||||
# define blkdev(x,m,maj,min) mknod((x), S_IFBLK|(m), makedev((maj),(min)))
|
||||
#endif
|
||||
|
||||
#ifndef UNUSED
|
||||
#define UNUSED(x) UNUSED_ ## x __attribute__ ((unused))
|
||||
#endif
|
||||
|
||||
#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)
|
||||
|
||||
extern int debug;
|
||||
extern int verbose;
|
||||
|
||||
int makepath (char *path);
|
||||
void ifconfig (char *ifname, char *addr, char *mask, int up);
|
||||
|
||||
pid_t pidfile_read (char *pidfile);
|
||||
pid_t pidfile_poll (char *cmd, char *path);
|
||||
|
||||
int pid_alive (pid_t pid);
|
||||
char *pid_get_name (pid_t pid, char *name, size_t len);
|
||||
|
||||
void procname_set (char *name, char *args[]);
|
||||
int procname_kill (char *name, int signo);
|
||||
|
||||
void print_desc (char *action, char *desc);
|
||||
int print_result (int fail);
|
||||
int start_process (char *cmd, char *args[], int console);
|
||||
void cls (void);
|
||||
void chomp (char *str);
|
||||
int getuser (char *username);
|
||||
int getgroup (char *group);
|
||||
void set_hostname (char *hostname);
|
||||
|
||||
int run (char *cmd);
|
||||
int run_interactive (char *cmd, char *fmt, ...);
|
||||
pid_t run_getty (char *cmd, char *argv[]);
|
||||
int run_parts (char *dir, ...);
|
||||
|
||||
/* strlcpy.c */
|
||||
size_t strlcpy(char *dst, const char *src, size_t siz);
|
||||
|
||||
#endif /* FINIT_HELPERS_H_ */
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* version-control: t
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -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:
|
||||
*/
|
||||
@@ -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:
|
||||
*/
|
||||
@@ -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:
|
||||
*/
|
||||
@@ -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:
|
||||
*/
|
||||
@@ -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
@@ -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:
|
||||
*/
|
||||
@@ -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)
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
Prevent nash-hotplug to keep running after boot using 100% of cpu
|
||||
|
||||
diff -rud mkinitrd-6.0.34-orig/nash/hotplug.c mkinitrd-6.0.34/nash/hotplug.c
|
||||
--- mkinitrd-6.0.34-orig/nash/hotplug.c 2008-03-06 21:20:34.000000000 -0300
|
||||
+++ mkinitrd-6.0.34/nash/hotplug.c 2008-03-12 18:48:46.000000000 -0300
|
||||
@@ -547,7 +547,7 @@
|
||||
nashLogger(nc, NASH_ERROR, "parent exited without telling us\n");
|
||||
close(nc->hp_childfd);
|
||||
nc->hp_childfd = -1;
|
||||
- break;
|
||||
+ exit(1);
|
||||
}
|
||||
count += rc;
|
||||
}
|
||||
@@ -0,0 +1,228 @@
|
||||
/* Plugin based services architecture for finit
|
||||
*
|
||||
* Copyright (c) 2012 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <dlfcn.h> /* dlopen() et al */
|
||||
#include <dirent.h> /* readdir() et al */
|
||||
#include <poll.h>
|
||||
#include <string.h>
|
||||
#include <sys/queue.h> /* BSD sys/queue.h API */
|
||||
|
||||
#include "finit.h"
|
||||
#include "private.h"
|
||||
#include "helpers.h"
|
||||
#include "plugin.h"
|
||||
|
||||
#define is_io_plugin(p) ((p)->io.cb && (p)->io.fd >= 0)
|
||||
|
||||
static size_t num_fds = 0;
|
||||
static struct pollfd fds[MAX_NUM_FDS];
|
||||
static LIST_HEAD(, plugin) plugins = LIST_HEAD_INITIALIZER();
|
||||
|
||||
int plugin_register(plugin_t *plugin)
|
||||
{
|
||||
int i, inuse = 0;
|
||||
|
||||
if (!plugin) {
|
||||
errno = EINVAL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!plugin->name) {
|
||||
Dl_info info;
|
||||
|
||||
if (!dladdr(plugin, &info) || !info.dli_fname)
|
||||
plugin->name = "unknown";
|
||||
else
|
||||
plugin->name = (char *)info.dli_fname;
|
||||
}
|
||||
|
||||
if (is_io_plugin(plugin)) {
|
||||
if (num_fds + 1 >= MAX_NUM_FDS) {
|
||||
num_fds = MAX_NUM_SVC;
|
||||
errno = ENOMEM;
|
||||
return 1;
|
||||
}
|
||||
num_fds++;
|
||||
inuse++;
|
||||
}
|
||||
|
||||
if (plugin->svc.cb) {
|
||||
svc_t *svc = svc_find(plugin->name);
|
||||
|
||||
if (svc) {
|
||||
inuse++;
|
||||
svc->cb = plugin->svc.cb;
|
||||
svc->dynamic = plugin->svc.dynamic;
|
||||
svc->dynamic_stop = plugin->svc.dynamic_stop;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < HOOK_MAX_NUM; i++) {
|
||||
if (plugin->hook[i].cb)
|
||||
inuse++;
|
||||
}
|
||||
|
||||
if (!inuse) {
|
||||
_d("No service \"%s\" loaded, and no I/O or finit hooks, skipping plugin.", basename(plugin->name));
|
||||
return 1;
|
||||
}
|
||||
|
||||
LIST_INSERT_HEAD(&plugins, plugin, link);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int plugin_unregister(plugin_t *plugin)
|
||||
{
|
||||
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! */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Private daemon API *******************************************************/
|
||||
void plugin_run_hooks(hook_point_t no)
|
||||
{
|
||||
plugin_t *p;
|
||||
|
||||
PLUGIN_ITERATOR(p) {
|
||||
if (p->hook[no].cb) {
|
||||
_d("Calling %s hook n:o %d from runloop...", basename(p->name), no);
|
||||
p->hook[no].cb(p->hook[no].arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Generic libev I/O callback, looks up correct plugin and calls its callback */
|
||||
static void generic_io_cb(int fd, int events)
|
||||
{
|
||||
plugin_t *p;
|
||||
|
||||
/* Find matching plugin, pick first matching fd */
|
||||
PLUGIN_ITERATOR(p) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/* Setup any I/O callbacks for plugins that use them */
|
||||
static void init_plugins(void)
|
||||
{
|
||||
int i = 0;
|
||||
plugin_t *p;
|
||||
|
||||
PLUGIN_ITERATOR(p) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int plugin_load_all(char *path)
|
||||
{
|
||||
int fail = 0;
|
||||
DIR *dp = opendir(path);
|
||||
struct dirent *entry;
|
||||
|
||||
if (!dp) {
|
||||
_e("Failed, cannot open plugin directory %s: %s", path, strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
while ((entry = readdir(dp))) {
|
||||
char *ext = entry->d_name + strlen(entry->d_name) - 3;
|
||||
|
||||
if (!strcmp(ext, ".so")) {
|
||||
int result = 0;
|
||||
void *handle;
|
||||
char plugin[1024];
|
||||
|
||||
snprintf(plugin, sizeof(plugin), "%s/%s", path, entry->d_name);
|
||||
// print_desc(" Loading plugin ", basename(plugin));
|
||||
handle = dlopen(plugin, RTLD_LAZY | RTLD_GLOBAL);
|
||||
if (!handle) {
|
||||
_d("Failed loading plugin %s: %s", plugin, dlerror());
|
||||
result = 1;
|
||||
}
|
||||
if (result)
|
||||
fail++;
|
||||
|
||||
// print_result(result);
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dp);
|
||||
init_plugins();
|
||||
|
||||
return fail;
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* version-control: t
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,118 @@
|
||||
/* Plugin based services architecture for finit
|
||||
*
|
||||
* Copyright (c) 2012 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef FINIT_PLUGIN_H_
|
||||
#define FINIT_PLUGIN_H_
|
||||
|
||||
#include <poll.h>
|
||||
#include <sys/queue.h> /* BSD sys/queue.h API */
|
||||
#include "svc.h"
|
||||
|
||||
#define PLUGIN_IO_READ POLLIN
|
||||
#define PLUGIN_IO_WRITE POLLOUT
|
||||
|
||||
#define PLUGIN_INIT(x) static void __attribute__ ((constructor)) x(void)
|
||||
#define PLUGIN_EXIT(x) static void __attribute__ ((destructor)) x(void)
|
||||
|
||||
#define PLUGIN_ITERATOR(x) LIST_FOREACH(x, &plugins, link)
|
||||
|
||||
/*
|
||||
* Predefined hook points for easier plugin debugging
|
||||
*/
|
||||
typedef enum {
|
||||
HOOK_ROOTFS_UP = 0,
|
||||
HOOK_BASEFS_UP,
|
||||
HOOK_NETWORK_UP,
|
||||
HOOK_SYSTEM_UP,
|
||||
HOOK_SVC_UP,
|
||||
HOOK_SHUTDOWN,
|
||||
HOOK_MAX_NUM
|
||||
} hook_point_t;
|
||||
|
||||
/**
|
||||
* plugin_t - Finit &plugin_t object
|
||||
* @link: BSD sys/queue.h linked list node
|
||||
* @name: Plugin name, or identifier to match against a &svc_t object
|
||||
* @svc: Service callback for a loaded &svc_t object
|
||||
* @hook: Hook callback definitions
|
||||
* @io: I/O hook callback
|
||||
*
|
||||
* To setup an &svc_t object callback for a service monitor the @name
|
||||
* must match the @svc_t @cmd exactly for them to "pair".
|
||||
*
|
||||
* A &plugin_t object may contain a service callback, several hooks
|
||||
* and/or an I/O callback as well. This way all critical extensions
|
||||
* to finit can fit in one single plugin, if needed.
|
||||
*
|
||||
* The "dynamic events" discussed in the svc callback is for external
|
||||
* service plugins to implement. However, it can be anything that
|
||||
* can cause a service to need to SIGHUP at runtime. E.g., acquiring
|
||||
* a DHCP lease, or an interface going UP/DOWN. The event itself can
|
||||
* be passed as an integer @event and any optional argument @event_arg
|
||||
*
|
||||
* It is up to the external service plugin to track these events and
|
||||
* relay them to each @dynamic service plugins' callback. I.e., to
|
||||
* all those with the dynamic flag set.
|
||||
*/
|
||||
typedef struct plugin {
|
||||
/* BSD sys/queue.h linked list node. */
|
||||
LIST_ENTRY(plugin) link;
|
||||
|
||||
/* Plugin name, defaults to plugin path if unset.
|
||||
* NOTE: Must be same as @cmd for service plugins! */
|
||||
char *name;
|
||||
|
||||
/* Service callback to be called once per lap of runloop. */
|
||||
struct {
|
||||
int dynamic; /* Callback wants external events as well. */
|
||||
int dynamic_stop; /* Callback allows dynamic events to stop. */
|
||||
svc_cmd_t (*cb)(svc_t *svc, int event, void *event_arg);
|
||||
} svc;
|
||||
|
||||
/* List of hook callbacks. */
|
||||
struct {
|
||||
void *arg; /* Optional argument to callback func. */
|
||||
void (*cb)(void *arg);
|
||||
} hook[HOOK_MAX_NUM];
|
||||
|
||||
/* I/O Plugin */
|
||||
struct {
|
||||
int fd, flags; /* 1:READ, 2:WRITE */
|
||||
void *arg;
|
||||
void (*cb)(void *arg, int fd, int events);
|
||||
} io;
|
||||
} plugin_t;
|
||||
|
||||
/* Public plugin API */
|
||||
int plugin_register (plugin_t *plugin);
|
||||
int plugin_unregister (plugin_t *plugin);
|
||||
|
||||
#endif /* FINIT_PLUGIN_H_ */
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* version-control: t
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,36 @@
|
||||
# Plugin based services architecture for finit -*-Makefile-*-
|
||||
CFLAGS += -fPIC -Os
|
||||
CPPFLAGS += -I..
|
||||
LDFLAGS := $(filter-out -rdynamic, $(LDFLAGS))
|
||||
LDFLAGS += -shared
|
||||
PLUGINS ?= initctl.so alsa-utils.so bootmisc.so dbus.so hwclock.so \
|
||||
resolvconf.so urandom.so x11-common.so
|
||||
DEPS = $(addprefix .,$(PLUGINS:.so=.d))
|
||||
|
||||
include ../common.mk
|
||||
|
||||
all: $(PLUGINS)
|
||||
|
||||
clean:
|
||||
-@$(RM) $(PLUGINS) *.o
|
||||
|
||||
distclean: clean
|
||||
-@$(RM) $(JUNK) $(DEPS)
|
||||
|
||||
install: all
|
||||
@install -d $(DESTDIR)$(plugindir)
|
||||
@for plugin in $(PLUGINS); do \
|
||||
echo " INSTALL $(DESTDIR)$(plugindir)/$$plugin"; \
|
||||
$(STRIPINST) $$plugin $(DESTDIR)$(plugindir)/$$plugin; \
|
||||
done
|
||||
|
||||
uninstall:
|
||||
-@for plugin in $(PLUGINS); do \
|
||||
echo " RM $(DESTDIR)$(plugindir)/$$plugin"; \
|
||||
rm $(DESTDIR)$(plugindir)/$$plugin 2>/dev/null; \
|
||||
done
|
||||
-@rmdir $(DESTDIR)$(plugindir) 2>/dev/null
|
||||
|
||||
ifneq ($(MAKECMDGOALS),clean)
|
||||
-include $(DEPS)
|
||||
endif
|
||||
@@ -0,0 +1,66 @@
|
||||
/* Save and restore ALSA sound settings using alsactl
|
||||
*
|
||||
* Copyright (c) 2012 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "finit.h"
|
||||
#include "helpers.h"
|
||||
#include "plugin.h"
|
||||
|
||||
static void save(void *UNUSED(arg))
|
||||
{
|
||||
_d("Saving system clock to RTC ...");
|
||||
run_interactive("/usr/sbin/alsactl store > /dev/null 2>&1", "Saving sound settings");
|
||||
}
|
||||
|
||||
static void restore(void *UNUSED(arg))
|
||||
{
|
||||
_d("Restoring system clock from RTC ...");
|
||||
run_interactive("/usr/sbin/alsactl restore > /dev/null 2>&1", "Restoring sound settings");
|
||||
}
|
||||
|
||||
static plugin_t plugin = {
|
||||
.hook[HOOK_BASEFS_UP] = {
|
||||
.cb = restore
|
||||
},
|
||||
.hook[HOOK_SHUTDOWN] = {
|
||||
.cb = save
|
||||
}
|
||||
};
|
||||
|
||||
PLUGIN_INIT(plugin_init)
|
||||
{
|
||||
plugin_register(&plugin);
|
||||
}
|
||||
|
||||
PLUGIN_EXIT(plugin_exit)
|
||||
{
|
||||
plugin_unregister(&plugin);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* version-control: t
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,85 @@
|
||||
/* Setup necessary files for UTMP, tracking logins
|
||||
*
|
||||
* Copyright (c) 2012 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <utmp.h>
|
||||
|
||||
#include "finit.h"
|
||||
#include "helpers.h"
|
||||
#include "plugin.h"
|
||||
|
||||
static void setup(void *UNUSED(arg))
|
||||
{
|
||||
#ifdef RUNLEVEL
|
||||
struct utmp entry;
|
||||
#endif
|
||||
|
||||
_d("Setting up necessary UTMP files ...");
|
||||
touch("/var/run/utmp");
|
||||
chown("/var/run/utmp", 0, getgroup("utmp"));
|
||||
chmod("/var/run/utmp", 0664);
|
||||
|
||||
#ifdef RUNLEVEL
|
||||
memset(&entry, 0, sizeof(struct utmp));
|
||||
entry.ut_type = RUN_LVL;
|
||||
entry.ut_pid = '0' + RUNLEVEL;
|
||||
setutent();
|
||||
pututline(&entry);
|
||||
endutent();
|
||||
#endif
|
||||
|
||||
#ifdef TOUCH_ETC_NETWORK_RUN_IFSTATE
|
||||
touch("/etc/network/run/ifstate");
|
||||
#else
|
||||
remove("/etc/network/run/ifstate");
|
||||
#endif
|
||||
|
||||
_d("Setting up misc files ...");
|
||||
mkdir("/var/run/sshd", 01755); /* OpenSSH */
|
||||
mkfifo("/dev/xconsole", 0640); /* sysklogd */
|
||||
chown("/dev/xconsole", 0, getgroup("tty"));
|
||||
}
|
||||
|
||||
static plugin_t plugin = {
|
||||
.hook[HOOK_BASEFS_UP] = {
|
||||
.cb = setup
|
||||
},
|
||||
};
|
||||
|
||||
PLUGIN_INIT(plugin_init)
|
||||
{
|
||||
plugin_register(&plugin);
|
||||
}
|
||||
|
||||
PLUGIN_EXIT(plugin_exit)
|
||||
{
|
||||
plugin_unregister(&plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* version-control: t
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,62 @@
|
||||
/* Setup and start system message bus, D-Bus
|
||||
*
|
||||
* Copyright (c) 2012 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "finit.h"
|
||||
#include "helpers.h"
|
||||
#include "plugin.h"
|
||||
|
||||
static void setup(void *UNUSED(arg))
|
||||
{
|
||||
#ifdef USE_MESSAGE_BUS
|
||||
_d("Starting D-Bus ...");
|
||||
mkdir("/var/run/dbus", 0755);
|
||||
mkdir("/var/lock/subsys/messagebus", 0755);
|
||||
run("dbus-uuidgen --ensure");
|
||||
remove("/var/run/dbus/pid");
|
||||
run_interactive("dbus-daemon --system", "Starting D-Bus");
|
||||
#endif
|
||||
}
|
||||
|
||||
static plugin_t plugin = {
|
||||
.hook[HOOK_NETWORK_UP] = {
|
||||
.cb = setup
|
||||
},
|
||||
};
|
||||
|
||||
PLUGIN_INIT(plugin_init)
|
||||
{
|
||||
plugin_register(&plugin);
|
||||
}
|
||||
|
||||
PLUGIN_EXIT(plugin_exit)
|
||||
{
|
||||
plugin_unregister(&plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* version-control: t
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,67 @@
|
||||
/* Save and restore RTC using hwclock
|
||||
*
|
||||
* Copyright (c) 2012 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "finit.h"
|
||||
#include "helpers.h"
|
||||
#include "plugin.h"
|
||||
|
||||
static void save(void *UNUSED(arg))
|
||||
{
|
||||
_d("Saving system clock to RTC ...");
|
||||
/* -w,--systohc, -u,--utc */
|
||||
run_interactive("/sbin/hwclock -w -u", "Saving system time (UTC) to RTC");
|
||||
}
|
||||
|
||||
static void restore(void *UNUSED(arg))
|
||||
{
|
||||
_d("Restoring system clock from RTC ...");
|
||||
/* -s,--hctosys, -u,--utc */
|
||||
run_interactive("/sbin/hwclock -s -u", "Restoring system clock (UTC) from RTC");
|
||||
}
|
||||
|
||||
static plugin_t plugin = {
|
||||
.hook[HOOK_BASEFS_UP] = {
|
||||
.cb = restore
|
||||
},
|
||||
.hook[HOOK_SHUTDOWN] = {
|
||||
.cb = save
|
||||
}
|
||||
};
|
||||
|
||||
PLUGIN_INIT(plugin_init)
|
||||
{
|
||||
plugin_register(&plugin);
|
||||
}
|
||||
|
||||
PLUGIN_EXIT(plugin_exit)
|
||||
{
|
||||
plugin_unregister(&plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* version-control: t
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,120 @@
|
||||
/* Optional /dev/initctl FIFO monitor
|
||||
*
|
||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||
* Copyright (c) 2008-2012 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h> /* O_RDONLY et al */
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h> /* read() */
|
||||
|
||||
#include "helpers.h"
|
||||
#include "plugin.h"
|
||||
#include "sig.h"
|
||||
|
||||
#define INIT_MAGIC 0x03091969
|
||||
#define INIT_CMD_RUNLVL 1
|
||||
|
||||
struct init_request {
|
||||
int magic; /* Magic number */
|
||||
int cmd; /* What kind of request */
|
||||
int runlevel; /* Runlevel to change to */
|
||||
int sleeptime; /* Time between TERM and KILL */
|
||||
char data[368];
|
||||
};
|
||||
|
||||
/* 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))
|
||||
{
|
||||
struct init_request request;
|
||||
|
||||
_d("Receiving request on %s...", FINIT_FIFO);
|
||||
while (1) {
|
||||
ssize_t len = read(fd, &request, sizeof(request));
|
||||
|
||||
if (-1 == len) {
|
||||
_d("Error %d", errno);
|
||||
break; /* Probably EAGAIN */
|
||||
}
|
||||
|
||||
if (request.magic != INIT_MAGIC)
|
||||
continue;
|
||||
|
||||
_d("Magic OK...");
|
||||
if (request.cmd == INIT_CMD_RUNLVL) {
|
||||
switch (request.runlevel) {
|
||||
case '0':
|
||||
_d("Halting system (SIGUSR2)");
|
||||
do_shutdown(SIGUSR2);
|
||||
break;
|
||||
|
||||
case '6':
|
||||
_d("Rebooting system (SIGUSR1)");
|
||||
do_shutdown(SIGUSR1);
|
||||
break;
|
||||
|
||||
default:
|
||||
_d("Unsupported runlevel: %d", request.runlevel);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
_d("Unsupported cmd: %d", request.cmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static plugin_t plugin = {
|
||||
.io = {
|
||||
.cb = read_initctl,
|
||||
.flags = PLUGIN_IO_READ,
|
||||
},
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
plugin_register(&plugin);
|
||||
}
|
||||
|
||||
PLUGIN_EXIT(plugin_exit)
|
||||
{
|
||||
plugin_unregister(&plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* version-control: t
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,89 @@
|
||||
/* Setup necessary files for resolvconf
|
||||
*
|
||||
* Copyright (c) 2012 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "finit.h"
|
||||
#include "helpers.h"
|
||||
#include "plugin.h"
|
||||
|
||||
static void setup(void *UNUSED(arg))
|
||||
{
|
||||
#ifdef USE_ETC_RESOLVCONF_RUN
|
||||
DIR *dir;
|
||||
struct dirent *d;
|
||||
#endif
|
||||
|
||||
_d("Setting up the resolver ...");
|
||||
#ifdef USE_ETC_RESOLVCONF_RUN
|
||||
makepath("/dev/shm/network");
|
||||
makepath("/dev/shm/resolvconf/interface");
|
||||
|
||||
if ((dir = opendir("/etc/resolvconf/run/interface")) != NULL) {
|
||||
while ((d = readdir(dir)) != NULL) {
|
||||
if (isalnum(d->d_name[0]))
|
||||
continue;
|
||||
snprintf(line, sizeof(line),
|
||||
"/etc/resolvconf/run/interface/%s", d->d_name);
|
||||
unlink(line);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_VAR_RUN_RESOLVCONF
|
||||
makepath("/var/run/resolvconf/interface");
|
||||
symlink("../../../etc/resolv.conf", "/var/run/resolvconf/resolv.conf");
|
||||
#endif
|
||||
|
||||
#ifdef USE_ETC_RESOLVCONF_RUN
|
||||
touch("/etc/resolvconf/run/enable-updates");
|
||||
|
||||
chdir("/etc/resolvconf/run/interface");
|
||||
run_parts("/etc/resolvconf/update.d", "-i", NULL);
|
||||
chdir("/");
|
||||
#endif /* USE_ETC_RESOLVCONF_RUN */
|
||||
}
|
||||
|
||||
static plugin_t plugin = {
|
||||
.hook[HOOK_BASEFS_UP] = {
|
||||
.cb = setup
|
||||
},
|
||||
};
|
||||
|
||||
PLUGIN_INIT(plugin_init)
|
||||
{
|
||||
plugin_register(&plugin);
|
||||
}
|
||||
|
||||
PLUGIN_EXIT(plugin_exit)
|
||||
{
|
||||
plugin_unregister(&plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* version-control: t
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,65 @@
|
||||
/* Setup random seed
|
||||
*
|
||||
* Copyright (c) 2012 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "finit.h"
|
||||
#include "helpers.h"
|
||||
#include "plugin.h"
|
||||
|
||||
static void setup(void *UNUSED(arg))
|
||||
{
|
||||
#ifdef RANDOMSEED
|
||||
copyfile(RANDOMSEED, "/dev/urandom", 0);
|
||||
unlink(RANDOMSEED);
|
||||
umask(077);
|
||||
copyfile("/dev/urandom", RANDOMSEED, 4096);
|
||||
umask(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
static plugin_t plugin = {
|
||||
.hook[HOOK_BASEFS_UP] = {
|
||||
.cb = setup
|
||||
},
|
||||
};
|
||||
|
||||
PLUGIN_INIT(plugin_init)
|
||||
{
|
||||
plugin_register(&plugin);
|
||||
}
|
||||
|
||||
PLUGIN_EXIT(plugin_exit)
|
||||
{
|
||||
plugin_unregister(&plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* version-control: t
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,77 @@
|
||||
/* Console setup (for X)
|
||||
*
|
||||
* Copyright (c) 2012 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "finit.h"
|
||||
#include "helpers.h"
|
||||
#include "plugin.h"
|
||||
|
||||
static void setup(void *UNUSED(arg))
|
||||
{
|
||||
#ifdef PAM_CONSOLE
|
||||
int fd;
|
||||
#endif
|
||||
char line[LINE_SIZE];
|
||||
|
||||
makepath("/var/run/console");
|
||||
snprintf(line, sizeof(line), "/var/run/console/%s", username);
|
||||
touch(line);
|
||||
|
||||
#ifdef PAM_CONSOLE
|
||||
if ((fd = open("/var/run/console/console.lock", O_CREAT|O_WRONLY|O_TRUNC, 0644)) >= 0) {
|
||||
write(fd, username, strlen(username));
|
||||
close(fd);
|
||||
run("/sbin/pam_console_apply");
|
||||
}
|
||||
#endif
|
||||
|
||||
mkdir("/tmp/.X11-unix", 01777);
|
||||
mkdir("/tmp/.ICE-unix", 01777);
|
||||
}
|
||||
|
||||
static plugin_t plugin = {
|
||||
.hook[HOOK_NETWORK_UP] = {
|
||||
.cb = setup
|
||||
},
|
||||
};
|
||||
|
||||
PLUGIN_INIT(plugin_init)
|
||||
{
|
||||
plugin_register(&plugin);
|
||||
}
|
||||
|
||||
PLUGIN_EXIT(plugin_exit)
|
||||
{
|
||||
plugin_unregister(&plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* version-control: t
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,46 @@
|
||||
/* Private header file for main finit daemon, not for plugins
|
||||
*
|
||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||
* Copyright (c) 2008-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_PRIVATE_H_
|
||||
#define FINIT_PRIVATE_H_
|
||||
|
||||
#include "svc.h"
|
||||
#include "plugin.h"
|
||||
|
||||
void svc_start_all (void);
|
||||
void svc_monitor (void);
|
||||
|
||||
void plugin_run_hooks (hook_point_t no);
|
||||
int plugin_load_all (char *path);
|
||||
void plugin_monitor (void);
|
||||
|
||||
#endif /* FINIT_PRIVATE_H_ */
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* version-control: t
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -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:
|
||||
*/
|
||||
@@ -0,0 +1,15 @@
|
||||
#!/bin/sh
|
||||
# Alternative boot method for other distributions than Debian 6.0
|
||||
# Place this file in a /etc/finit.d/ directory. At boot finit will
|
||||
# run all files, using its built-in run_parts(), in that directory.
|
||||
#
|
||||
# Here we chain load Debian /etc/rcS.d and /etc/rc2.d directories
|
||||
# in sequence using the standard run-parts tool.
|
||||
run-parts /etc/rcS.d --arg=start
|
||||
run-parts /etc/rc2.d --arg=start
|
||||
|
||||
# You can also place other commands in this services file, akin to
|
||||
# the old finit /usr/sbin/services.sh (not supported anymore).
|
||||
#service acpid start
|
||||
#service networking start
|
||||
#service ssh start
|
||||
@@ -0,0 +1,189 @@
|
||||
/* Signal management - Be conservative with what finit responds to!
|
||||
*
|
||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||
* Copyright (c) 2008-2012 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* The standard SysV init only responds to the following signals:
|
||||
* SIGHUP
|
||||
* Has the same effect as telinit q.
|
||||
*
|
||||
* SIGUSR1
|
||||
* On receipt of this signals, init closes and re-opens its control
|
||||
* fifo, /dev/initctl. Useful for bootscripts when /dev is remounted.
|
||||
*
|
||||
* SIGINT
|
||||
* Normally the kernel sends this signal to init when CTRL-ALT-DEL is
|
||||
* pressed. It activates the ctrlaltdel action.
|
||||
*
|
||||
* SIGWINCH
|
||||
* The kernel sends this signal when the KeyboardSignal key is hit.
|
||||
* It activates the kbrequest action.
|
||||
*/
|
||||
|
||||
#include <sys/reboot.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include "finit.h"
|
||||
#include "helpers.h"
|
||||
#include "plugin.h"
|
||||
#include "private.h"
|
||||
#include "sig.h"
|
||||
|
||||
static int stopped = 0;
|
||||
|
||||
|
||||
void do_shutdown (int sig)
|
||||
{
|
||||
touch(SYNC_SHUTDOWN);
|
||||
|
||||
if (sdown)
|
||||
run_interactive(sdown, "Calling shutdown hook: %s", sdown);
|
||||
|
||||
_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);
|
||||
|
||||
_d("Sending SIGKILL to remaining processes.");
|
||||
kill(-1, SIGKILL);
|
||||
|
||||
sync();
|
||||
sync();
|
||||
_d("Unmounting file systems, remounting / read-only.");
|
||||
run("/bin/umount -fa 2>/dev/null");
|
||||
run("/bin/mount -n -o remount,ro / 2>/dev/null");
|
||||
run("/sbin/swapoff -ea");
|
||||
|
||||
_d("%s.", sig == SIGINT || sig == SIGUSR1 ? "Rebooting" : "Halting");
|
||||
if (sig == SIGINT || sig == SIGUSR1)
|
||||
reboot(RB_AUTOBOOT);
|
||||
|
||||
reboot(RB_POWER_OFF);
|
||||
}
|
||||
|
||||
/*
|
||||
* Shut down on INT USR1 USR2
|
||||
*/
|
||||
static void shutdown_handler(int sig, siginfo_t *info, void *UNUSED(ctx))
|
||||
{
|
||||
_d("Rebooting on signal %d from %s (PID %d)",
|
||||
sig, pid_get_name(info->si_pid, NULL, 0), info->si_pid);
|
||||
|
||||
do_shutdown(sig);
|
||||
}
|
||||
|
||||
/*
|
||||
* SIGCHLD: one of our children has died
|
||||
*/
|
||||
static void chld_handler(int UNUSED(sig), siginfo_t *UNUSED(info), void *UNUSED(ctx))
|
||||
{
|
||||
/* Do nothing, the svc_monitor() is the designated child reaper. */
|
||||
}
|
||||
|
||||
/*
|
||||
* SIGSTOP: Paused by user or netflash
|
||||
*/
|
||||
static void sigstop_handler(int sig, siginfo_t *info, void *UNUSED(ctx))
|
||||
{
|
||||
_d("Received SIGSTOP(%d) from %s (PID %d)",
|
||||
sig, pid_get_name(info->si_pid, NULL, 0), info->si_pid);
|
||||
touch(SYNC_STOPPED);
|
||||
stopped ++;
|
||||
}
|
||||
static void sigcont_handler(int sig, siginfo_t *info, void *UNUSED(ctx))
|
||||
{
|
||||
_d("Received SIGCONT(%d) from %s (PID %d)",
|
||||
sig, pid_get_name(info->si_pid, NULL, 0), info->si_pid);
|
||||
stopped = 0;
|
||||
remove(SYNC_STOPPED);
|
||||
}
|
||||
|
||||
/*
|
||||
* Is SIGSTOP asserted?
|
||||
*/
|
||||
int sig_stopped(void)
|
||||
{
|
||||
return stopped;
|
||||
}
|
||||
|
||||
/*
|
||||
* Inital signal setup - ignore everything but SIGCHLD until we're capable of responding
|
||||
*/
|
||||
void sig_init(void)
|
||||
{
|
||||
int i;
|
||||
struct sigaction sa;
|
||||
|
||||
for (i = 1; i < NSIG; i++)
|
||||
IGNSIG(sa, i, SA_RESTART);
|
||||
|
||||
SETSIG(sa, SIGCHLD, chld_handler, SA_RESTART);
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup limited set of SysV compatible signals to respond to
|
||||
*/
|
||||
void sig_setup(void)
|
||||
{
|
||||
struct sigaction sa;
|
||||
|
||||
_d("Setup signals");
|
||||
|
||||
/* Cleanup any stale finit control files */
|
||||
remove(SYNC_SHUTDOWN);
|
||||
remove(SYNC_STOPPED);
|
||||
|
||||
/* Standard SysV init calls ctrl-alt-delete handler */
|
||||
SETSIG(sa, SIGINT, shutdown_handler, 0);
|
||||
SETSIG(sa, SIGPWR, shutdown_handler, 0);
|
||||
|
||||
/* Ignore SIGUSR1/2 for now, only BusyBox init implements them as reboot+halt. */
|
||||
// SETSIG2(sa, SIGUSR1, reopen_initctl, 0);
|
||||
// SETSIG2(sa, SIGUSR2, pwrdwn_handler, 0);
|
||||
|
||||
/* Init must ignore SIGTERM. May otherwise get false SIGTERM in forked children! */
|
||||
IGNSIG(sa, SIGTERM, 0);
|
||||
|
||||
/* Some C APIs may need SIGALRM for implementing timers. */
|
||||
IGNSIG(sa, SIGALRM, 0);
|
||||
|
||||
/* We don't have any /etc/inittab yet, reread finit.conf? */
|
||||
IGNSIG(sa, SIGHUP, 0);
|
||||
|
||||
/* Stopping init is a bit tricky. */
|
||||
SETSIG(sa, SIGSTOP, sigstop_handler, 0);
|
||||
SETSIG(sa, SIGTSTP, sigstop_handler, 0);
|
||||
SETSIG(sa, SIGCONT, sigcont_handler, 0);
|
||||
|
||||
/* Disable CTRL-ALT-DELETE from kernel, we handle shutdown gracefully with SIGINT, above */
|
||||
reboot(RB_DISABLE_CAD);
|
||||
setsid();
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* version-control: t
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,70 @@
|
||||
/* Signal management - Be conservative with what finit responds to!
|
||||
*
|
||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||
* Copyright (c) 2008-2012 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef FINIT_SIG_H_
|
||||
#define FINIT_SIG_H_
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
#define SYNC_SHUTDOWN "/var/lock/finit.shutdown"
|
||||
#define SYNC_STOPPED "/var/lock/finit.stopped"
|
||||
|
||||
#define SETSIG(sa, sig, fun, flags) \
|
||||
do { \
|
||||
sa.sa_sigaction = fun; \
|
||||
sa.sa_flags = SA_SIGINFO | flags; \
|
||||
sigemptyset(&sa.sa_mask); \
|
||||
sigaction(sig, &sa, NULL); \
|
||||
} while (0)
|
||||
|
||||
#define IGNSIG(sa, sig, flags) \
|
||||
do { \
|
||||
sa.sa_handler = SIG_IGN; \
|
||||
sa.sa_flags = flags; \
|
||||
sigemptyset(&sa.sa_mask); \
|
||||
sigaction(sig, &sa, NULL); \
|
||||
} while (0)
|
||||
|
||||
#define DFLSIG(sa, sig, flags) \
|
||||
do { \
|
||||
sa.sa_handler = SIG_DFL; \
|
||||
sa.sa_flags = flags; \
|
||||
sigemptyset(&sa.sa_mask); \
|
||||
sigaction(sig, &sa, NULL); \
|
||||
} while (0)
|
||||
|
||||
void do_shutdown (int sig);
|
||||
int sig_stopped (void);
|
||||
void sig_init (void);
|
||||
void sig_setup (void);
|
||||
|
||||
#endif /* FINIT_SIG_H_ */
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* version-control: t
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,58 @@
|
||||
/* $OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
* Copy src to string dst of size siz. At most siz-1 characters
|
||||
* will be copied. Always NUL terminates (unless siz == 0).
|
||||
* Returns strlen(src); if retval >= siz, truncation occurred.
|
||||
*/
|
||||
size_t
|
||||
strlcpy(char *dst, const char *src, size_t siz)
|
||||
{
|
||||
char *d = dst;
|
||||
const char *s = src;
|
||||
size_t n = siz;
|
||||
|
||||
/* Copy as many bytes as will fit */
|
||||
if (n != 0) {
|
||||
while (--n != 0) {
|
||||
if ((*d++ = *s++) == '\0')
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Not enough room in dst, add NUL and traverse rest of src */
|
||||
if (n == 0) {
|
||||
if (siz != 0)
|
||||
*d = '\0'; /* NUL-terminate dst */
|
||||
while (*s++)
|
||||
;
|
||||
}
|
||||
|
||||
return(s - src - 1); /* count does not include NUL */
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* version-control: t
|
||||
* c-file-style: "bsd"
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,423 @@
|
||||
/* Finit service monitor and heneric API for managing svc_t structures
|
||||
*
|
||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||
* Copyright (c) 2008-2012 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include "finit.h"
|
||||
#include "helpers.h"
|
||||
#include "private.h"
|
||||
#include "sig.h"
|
||||
#include "lite.h"
|
||||
#include "svc.h"
|
||||
|
||||
/* The registered services are kept in shared memory for easy read-only access
|
||||
* by 3rd party APIs. Mostly because of the ability to, from the outside, query
|
||||
* liveness state of all daemons that should run. */
|
||||
static int svc_counter = 0; /* Number of registered services to monitor. */
|
||||
static svc_t *services = NULL; /* List of registered services, in shared memory. */
|
||||
|
||||
|
||||
/* Connect to/create shared memory area of registered servies */
|
||||
static void __connect_shm(void)
|
||||
{
|
||||
if (!services) {
|
||||
services = finit_svc_connect();
|
||||
if (!services) {
|
||||
/* This should never happen, but if it does we're probably
|
||||
* knee-deep in more serious problems already... */
|
||||
_e("Failed allocating shared memory, error %d: %s", errno, strerror (errno));
|
||||
abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* svc_new - Create a new service object
|
||||
*
|
||||
* Returns:
|
||||
* A pointer to an empty &svc_t object, or %NULL if out of empty slots.
|
||||
*/
|
||||
svc_t *svc_new(void)
|
||||
{
|
||||
svc_t *svc = NULL;
|
||||
|
||||
__connect_shm();
|
||||
if (svc_counter < MAX_NUM_SVC) {
|
||||
svc = &services[svc_counter++];
|
||||
memset(svc, 0, sizeof(*svc));
|
||||
} else {
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return svc;
|
||||
}
|
||||
|
||||
/**
|
||||
* svc_find - Find a service object by its full path name
|
||||
* @name: Full path name, e.g., /sbin/syslogd
|
||||
*
|
||||
* Returns:
|
||||
* A pointer to an &svc_t object, or %NULL if not found.
|
||||
*/
|
||||
svc_t *svc_find(char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
__connect_shm();
|
||||
for (i = 0; i < svc_counter; i++) {
|
||||
svc_t *svc = &services[i];
|
||||
|
||||
if (!strncmp(name, svc->cmd, strlen(svc->cmd))) {
|
||||
_d("Found a matching svc for %s", name);
|
||||
return svc;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* svc_iterator - Iterates over all registered services.
|
||||
* @restart: Get first &svc_t object by setting @restart
|
||||
*
|
||||
* Returns:
|
||||
* The first &svc_t when @restart is set, otherwise the next &svc_t until
|
||||
* the end when %NULL is returned.
|
||||
*/
|
||||
svc_t *svc_iterator(int restart)
|
||||
{
|
||||
static int i = 0;
|
||||
|
||||
__connect_shm();
|
||||
if (restart)
|
||||
i = 0;
|
||||
|
||||
if (i >= svc_counter)
|
||||
return NULL;
|
||||
|
||||
return &services[i++];
|
||||
}
|
||||
|
||||
/**
|
||||
* svc_register - Register a non-backgrounding service to be monitored
|
||||
* @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:
|
||||
*
|
||||
* "service [@username] /path/to/daemon -- Description text"
|
||||
*
|
||||
* The [] brackets means the argument is optional. If the username is
|
||||
* left out the daemon is started as root.
|
||||
*
|
||||
* Returns:
|
||||
* POSIX OK(0) on success, or non-zero errno exit status on failure.
|
||||
*/
|
||||
int svc_register(char *line, char *username)
|
||||
{
|
||||
int i = 0;
|
||||
char *cmd, *desc;
|
||||
svc_t *svc;
|
||||
|
||||
if (!line) {
|
||||
_e("Invalid input argument.");
|
||||
return errno = EINVAL;
|
||||
}
|
||||
|
||||
desc = strstr(line, "-- ");
|
||||
if (desc)
|
||||
*desc = 0;
|
||||
|
||||
cmd = strtok(line, " ");
|
||||
if (!cmd) {
|
||||
incomplete:
|
||||
_e("Incomplete service, cannot register.");
|
||||
return errno = ENOENT;
|
||||
}
|
||||
|
||||
if (cmd[0] == '@') { /* @username */
|
||||
username = &cmd[1];
|
||||
|
||||
/* Check if valid command follows... */
|
||||
cmd = strtok(NULL, " ");
|
||||
if (!cmd)
|
||||
goto incomplete;
|
||||
}
|
||||
|
||||
svc = svc_new();
|
||||
if (!svc) {
|
||||
_e("Out of memorym, cannot register service %s", cmd);
|
||||
return errno = ENOMEM;
|
||||
}
|
||||
|
||||
if (desc)
|
||||
strlcpy(svc->desc, desc + 3, sizeof(svc->desc));
|
||||
if (username)
|
||||
strlcpy(svc->username, username, sizeof(svc->username));
|
||||
strlcpy(svc->cmd, cmd, sizeof(svc->cmd));
|
||||
strlcpy(svc->args[i++], cmd, sizeof(svc->args[0]));
|
||||
|
||||
while ((cmd = strtok(NULL, " ")))
|
||||
strlcpy(svc->args[i++], cmd, sizeof(svc->args[0]));
|
||||
svc->args[i][0] = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* svc_enabled - Should the service run?
|
||||
* @svc: Pointer to &svc_t object
|
||||
* @event: Dynamic event, opaque flag passed to callback
|
||||
* @arg: Event argument, used only by external service plugins.
|
||||
*
|
||||
* This method calls an associated service callback, if registered by a
|
||||
* plugin, and returns the &svc_cmd_t status. If no plugin is registered
|
||||
* the service is statically enabled in /etc/finit.conf and the result
|
||||
* will always be %SVC_START.
|
||||
*
|
||||
* Returns:
|
||||
* Either one of %SVC_START, %SVC_STOP, %SVC_RELOAD.
|
||||
*/
|
||||
svc_cmd_t svc_enabled(svc_t *svc, int event, void *arg)
|
||||
{
|
||||
if (!svc) {
|
||||
errno = EINVAL;
|
||||
return SVC_STOP;
|
||||
}
|
||||
|
||||
/* Is there a service plugin registered? */
|
||||
if (svc->cb)
|
||||
return svc->cb(svc, event, arg);
|
||||
|
||||
/* No service plugin, default to start, since listed in finit.conf */
|
||||
return SVC_START;
|
||||
}
|
||||
|
||||
static int is_norespawn(void)
|
||||
{
|
||||
return sig_stopped() ||
|
||||
fexist("/mnt/norespawn") ||
|
||||
fexist("/tmp/norespawn");
|
||||
}
|
||||
|
||||
void svc_monitor(void)
|
||||
{
|
||||
pid_t lost;
|
||||
svc_t *svc;
|
||||
|
||||
lost = waitpid(-1, NULL, WNOHANG);
|
||||
if (lost < 1)
|
||||
return;
|
||||
|
||||
if (fexist(SYNC_SHUTDOWN) || lost <= 1)
|
||||
return;
|
||||
|
||||
/* Power user at the console, don't respawn tasks. */
|
||||
if (is_norespawn())
|
||||
return;
|
||||
|
||||
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 (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);
|
||||
|
||||
/* Restarting lost service. */
|
||||
if (svc_enabled(svc, 0, NULL))
|
||||
svc_start(svc);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Remember: svc_enabled() must be called before calling svc_start() */
|
||||
int svc_start(svc_t *svc)
|
||||
{
|
||||
int respawn = svc->pid != 0;
|
||||
pid_t pid;
|
||||
sigset_t nmask, omask;
|
||||
char *args[MAX_NUM_SVC_ARGS];
|
||||
|
||||
/* Ignore if finit is SIGSTOP'ed */
|
||||
if (is_norespawn())
|
||||
return 0;
|
||||
|
||||
if (!respawn)
|
||||
print_desc("Starting ", svc->desc);
|
||||
|
||||
/* Block sigchild while forking. */
|
||||
sigemptyset(&nmask);
|
||||
sigaddset(&nmask, SIGCHLD);
|
||||
sigprocmask(SIG_BLOCK, &nmask, &omask);
|
||||
|
||||
pid = fork();
|
||||
sigprocmask(SIG_SETMASK, &omask, NULL);
|
||||
if (pid == 0) {
|
||||
int i = 0;
|
||||
int uid = getuser(svc->username);
|
||||
struct sigaction sa;
|
||||
|
||||
sigemptyset(&nmask);
|
||||
sigaddset(&nmask, SIGCHLD);
|
||||
sigprocmask(SIG_UNBLOCK, &nmask, NULL);
|
||||
|
||||
/* Reset signal handlers that were set by the parent process */
|
||||
for (i = 1; i < NSIG; i++)
|
||||
DFLSIG(sa, i, 0);
|
||||
|
||||
/* Set desired user */
|
||||
if (uid >= 0)
|
||||
setuid(uid);
|
||||
|
||||
/* Serve copy of args to process in case it modifies them. */
|
||||
for (i = 0; svc->args[i][0] != 0 && i < MAX_NUM_SVC_ARGS; i++)
|
||||
args[i] = svc->args[i];
|
||||
args[i] = NULL;
|
||||
|
||||
if (debug) {
|
||||
int fd;
|
||||
char buf[256] = "";
|
||||
|
||||
fd = open (CONSOLE, O_WRONLY | O_APPEND);
|
||||
if (-1 != fd) {
|
||||
dup2(STDOUT_FILENO, fd);
|
||||
dup2(STDERR_FILENO, fd);
|
||||
}
|
||||
|
||||
for (i = 0; args[i] && i < MAX_NUM_SVC_ARGS; i++) {
|
||||
char arg[MAX_ARG_LEN];
|
||||
|
||||
snprintf(arg, sizeof(arg), "%s ", args[i]);
|
||||
if ((sizeof(buf) - strlen(buf)) < strlen(arg))
|
||||
strcat(buf, arg);
|
||||
}
|
||||
_e("%starting %s: %s", respawn ? "Res" : "S", svc->cmd, buf);
|
||||
}
|
||||
|
||||
execvp(svc->cmd, args);
|
||||
exit(0);
|
||||
}
|
||||
svc->pid = pid;
|
||||
|
||||
if (!respawn)
|
||||
print_result(svc->pid > 1 ? 0 : 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int svc_start_by_name(char *name)
|
||||
{
|
||||
svc_t *svc = svc_find(name);
|
||||
|
||||
if (svc && svc_enabled(svc, 0, NULL))
|
||||
return svc_start(svc);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int svc_stop(svc_t *svc)
|
||||
{
|
||||
int res = 1;
|
||||
|
||||
if (!svc) {
|
||||
_e("Failed, no svc pointer.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (svc->pid <= 1) {
|
||||
_d("Bad PID %d for %s, SIGTERM", svc->pid, svc->desc);
|
||||
svc->pid = 0;
|
||||
return 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);
|
||||
svc->pid = 0;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int svc_reload(svc_t *svc)
|
||||
{
|
||||
/* Ignore if finit is SIGSTOP'ed */
|
||||
if (is_norespawn())
|
||||
return 0;
|
||||
|
||||
if (!svc) {
|
||||
_e("Failed, no svc pointer.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (svc->pid <= 1) {
|
||||
_d("Bad PID %d for %s, SIGHUP", svc->pid, svc->cmd);
|
||||
svc->pid = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
_d("Sending SIGHUP to PID %d", svc->pid);
|
||||
return kill(svc->pid, SIGHUP);
|
||||
}
|
||||
|
||||
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"
|
||||
* version-control: t
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,106 @@
|
||||
/* Finit service monitor and heneric API for managing svc_t structures
|
||||
*
|
||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||
* Copyright (c) 2008-2012 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef FINIT_SVC_H_
|
||||
#define FINIT_SVC_H_
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h> /* strerror() */
|
||||
#include <sys/shm.h> /* shmat() */
|
||||
#include <sys/types.h> /* pid_t */
|
||||
|
||||
typedef enum {
|
||||
SVC_STOP = 0, /* Disabled */
|
||||
SVC_START, /* Enabled */
|
||||
SVC_RELOAD /* Enabled, needs restart */
|
||||
} svc_cmd_t;
|
||||
|
||||
#define FINIT_SHM_ID 0x494E4954 /* "INIT", see ascii(7) */
|
||||
#define MAX_ARG_LEN 64
|
||||
#define MAX_STR_LEN 64
|
||||
#define MAX_USER_LEN 16
|
||||
#define MAX_NUM_FDS 64 /* Max number of I/O plugins */
|
||||
#define MAX_NUM_SVC 64 /* Enough? */
|
||||
#define MAX_NUM_SVC_ARGS 16
|
||||
|
||||
/* Default enable for all services, can be stopped by means
|
||||
* of issuing an initctl call. E.g.
|
||||
* initctl <stop|start|restart> service */
|
||||
typedef struct svc {
|
||||
pid_t pid;
|
||||
int reload;
|
||||
char cmd[MAX_ARG_LEN];
|
||||
char args[MAX_NUM_SVC_ARGS][MAX_ARG_LEN];
|
||||
char desc[MAX_STR_LEN];
|
||||
char username[MAX_USER_LEN];
|
||||
|
||||
/* For external plugins. If @cb is set a plugin is loaded.
|
||||
* @dynamic: Set by plugins that want dynamic events.
|
||||
* @dynamic_stop: Set by plugins that allow dyn. events to stop it as well.
|
||||
* @private: Can be used freely by plugin, e.g., to store "states".
|
||||
*/
|
||||
int dynamic;
|
||||
int dynamic_stop;
|
||||
int private;
|
||||
svc_cmd_t (*cb)(struct svc *svc, int event, void *event_arg);
|
||||
} svc_t;
|
||||
|
||||
typedef struct svc_map svc_map_t;
|
||||
|
||||
/* Put services array in shm */
|
||||
static inline svc_t *finit_svc_connect(void)
|
||||
{
|
||||
const long ID = FINIT_SHM_ID;
|
||||
static void *ptr = (void *)-1;
|
||||
|
||||
if ((void *)-1 == ptr) {
|
||||
ptr = shmat (shmget (ID, sizeof(svc_t) * MAX_NUM_SVC, 0600 | IPC_CREAT), NULL, 0);
|
||||
if ((void *)-1 == ptr)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (svc_t *)ptr;
|
||||
}
|
||||
|
||||
svc_t *svc_new (void);
|
||||
svc_t *svc_find (char *name);
|
||||
svc_t *svc_iterator (int restart);
|
||||
|
||||
int svc_register (char *line, char *username);
|
||||
int svc_id_by_name (char *name);
|
||||
svc_cmd_t svc_enabled (svc_t *svc, int event, void *arg);
|
||||
int svc_start (svc_t *svc);
|
||||
int svc_start_by_name (char *name);
|
||||
int svc_stop (svc_t *svc);
|
||||
int svc_reload (svc_t *svc);
|
||||
|
||||
#endif /* FINIT_SVC_H_ */
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* version-control: t
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
Reference in New Issue
Block a user