summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--COPYRIGHT1
-rw-r--r--ChangeLog26
-rw-r--r--Makefile108
-rw-r--r--STYLE53
-rw-r--r--conf.d.BSD/Makefile5
-rw-r--r--conf.d.BSD/localmount31
-rw-r--r--conf.d.BSD/net.example309
-rw-r--r--conf.d.BSD/wireless.example190
-rw-r--r--conf.d.Linux/Makefile7
-rw-r--r--conf.d.Linux/clock31
-rw-r--r--conf.d.Linux/consolefont19
-rw-r--r--conf.d.Linux/keymaps26
-rw-r--r--conf.d.Linux/net.example846
-rw-r--r--conf.d.Linux/rc34
-rw-r--r--conf.d.Linux/volumes15
-rw-r--r--conf.d.Linux/wireless.example266
-rw-r--r--conf.d/Makefile6
-rw-r--r--conf.d/bootmisc12
-rw-r--r--conf.d/checkfs8
-rw-r--r--conf.d/clock16
-rw-r--r--conf.d/env_whitelist6
-rw-r--r--conf.d/hostname4
-rw-r--r--conf.d/local.start5
-rw-r--r--conf.d/local.stop8
-rw-r--r--conf.d/net4
-rw-r--r--conf.d/rc87
-rw-r--r--default.mk54
-rw-r--r--etc.BSD/COPYRIGHT2
-rw-r--r--etc.BSD/Makefile5
-rw-r--r--etc.BSD/issue3
-rw-r--r--etc.BSD/issue.logo13
-rw-r--r--etc.BSD/login.conf65
-rw-r--r--etc.BSD/rc14
-rw-r--r--etc.BSD/rc.shutdown17
-rw-r--r--etc.Linux/Makefile7
-rw-r--r--etc.Linux/filesystems14
-rw-r--r--etc.Linux/inputrc67
-rw-r--r--etc.Linux/issue3
-rw-r--r--etc.Linux/issue.logo13
-rw-r--r--etc.Linux/modules.autoload.d/Makefile5
-rw-r--r--etc.Linux/modules.autoload.d/kernel-2.411
-rw-r--r--etc.Linux/modules.autoload.d/kernel-2.610
-rw-r--r--etc.Linux/modules.d/Makefile5
-rw-r--r--etc.Linux/modules.d/aliases42
-rw-r--r--etc.Linux/modules.d/i3864
-rw-r--r--etc.Linux/sysctl.conf54
-rw-r--r--etc/Makefile7
-rw-r--r--etc/env.d/00basic10
-rw-r--r--etc/env.d/Makefile5
-rw-r--r--etc/hosts31
-rw-r--r--etc/networks8
-rw-r--r--etc/profile67
-rw-r--r--etc/protocols147
-rw-r--r--etc/rc.conf37
-rw-r--r--etc/services1178
-rw-r--r--etc/shells10
-rw-r--r--init.d.BSD/Makefile5
-rwxr-xr-xinit.d.BSD/clock41
-rw-r--r--init.d.Linux/Makefile5
-rwxr-xr-xinit.d.Linux/clock131
-rwxr-xr-xinit.d.Linux/consolefont87
-rwxr-xr-xinit.d.Linux/keymaps80
-rwxr-xr-xinit.d.Linux/modules104
-rwxr-xr-xinit.d.Linux/numlock35
-rwxr-xr-xinit.d.Linux/volumes42
-rw-r--r--init.d/Makefile6
-rwxr-xr-xinit.d/bootmisc138
-rwxr-xr-xinit.d/checkfs77
-rwxr-xr-xinit.d/checkroot149
-rwxr-xr-xinit.d/halt.sh94
-rwxr-xr-xinit.d/hostname20
-rwxr-xr-xinit.d/local34
-rwxr-xr-xinit.d/localmount183
-rwxr-xr-xinit.d/netmount85
-rwxr-xr-xinit.d/rmnologin16
-rwxr-xr-xinit.d/urandom34
-rw-r--r--man.Linux/Makefile5
-rw-r--r--man.Linux/modules.autoload.519
-rw-r--r--man/Makefile5
-rw-r--r--man/rc-depend.873
-rw-r--r--man/rc-status.837
-rw-r--r--man/rc-update.843
-rw-r--r--man/start-stop-daemon.8212
-rw-r--r--net.BSD/Makefile5
-rw-r--r--net.BSD/ifconfig.sh125
-rw-r--r--net.BSD/iwconfig.sh562
-rw-r--r--net.Linux/Makefile8
-rw-r--r--net.Linux/adsl.sh71
-rw-r--r--net.Linux/apipa.sh46
-rw-r--r--net.Linux/arping.sh111
-rw-r--r--net.Linux/bonding.sh100
-rw-r--r--net.Linux/br2684ctl.sh50
-rw-r--r--net.Linux/bridge.sh113
-rw-r--r--net.Linux/ccwgroup.sh66
-rw-r--r--net.Linux/clip.sh212
-rw-r--r--net.Linux/ifconfig.sh239
-rw-r--r--net.Linux/ifplugd.sh91
-rw-r--r--net.Linux/ip6to4.sh97
-rw-r--r--net.Linux/ipppd.sh47
-rw-r--r--net.Linux/iproute2.sh185
-rw-r--r--net.Linux/iwconfig.sh710
-rw-r--r--net.Linux/macchanger.sh88
-rw-r--r--net.Linux/netplugd.sh93
-rw-r--r--net.Linux/pppd.sh219
-rw-r--r--net.Linux/pump.sh60
-rw-r--r--net.Linux/tuntap.sh57
-rw-r--r--net.Linux/udhcpc.sh102
-rw-r--r--net.Linux/vlan.sh108
-rw-r--r--net/Makefile6
-rw-r--r--net/dhclient.sh75
-rw-r--r--net/dhcpcd.sh71
-rw-r--r--net/macchanger.sh88
-rw-r--r--net/macnet.sh19
-rw-r--r--net/ssidnet.sh24
-rw-r--r--net/system.sh106
-rw-r--r--net/wpa_supplicant.sh164
-rw-r--r--runlevels.BSD/Makefile12
-rw-r--r--runlevels.Linux/Makefile12
-rw-r--r--runlevels/Makefile12
-rw-r--r--sh.BSD/Makefile5
-rwxr-xr-xsh.BSD/init.sh47
-rw-r--r--sh.Linux/Makefile5
-rwxr-xr-xsh.Linux/init.sh251
-rw-r--r--sh/Makefile7
-rw-r--r--sh/functions.sh157
-rwxr-xr-xsh/gendepends.sh58
-rw-r--r--sh/init-common-post.sh22
-rw-r--r--sh/init-functions.sh62
-rwxr-xr-xsh/net.sh566
-rwxr-xr-xsh/rc-functions.sh60
-rwxr-xr-xsh/rc-help.sh262
-rw-r--r--sh/rc-mount.sh70
-rwxr-xr-xsh/runscript.sh74
-rw-r--r--share.BSD/Makefile6
-rw-r--r--share.BSD/fstab21
-rw-r--r--share.BSD/group16
-rw-r--r--share.BSD/master.passwd15
-rw-r--r--share.Linux/Makefile6
-rw-r--r--share.Linux/fstab27
-rw-r--r--share.Linux/group27
-rw-r--r--share.Linux/issue.devfix21
-rw-r--r--share.Linux/passwd15
-rw-r--r--share.Linux/shadow16
-rw-r--r--share/Makefile4
-rw-r--r--src/Makefile153
-rw-r--r--src/einfo.h83
-rw-r--r--src/env-update.c247
-rw-r--r--src/env_whitelist48
-rw-r--r--src/fstabinfo.c146
-rw-r--r--src/libeinfo.c877
-rw-r--r--src/librc-daemon.c600
-rw-r--r--src/librc-depend.c838
-rw-r--r--src/librc-misc.c750
-rw-r--r--src/librc-strlist.c141
-rw-r--r--src/librc.c773
-rw-r--r--src/mountinfo.c246
-rw-r--r--src/rc-depend.c120
-rw-r--r--src/rc-misc.h34
-rw-r--r--src/rc-plugin.c119
-rw-r--r--src/rc-plugin.h15
-rw-r--r--src/rc-status.c142
-rw-r--r--src/rc-update.c162
-rw-r--r--src/rc.c1174
-rw-r--r--src/rc.h180
-rw-r--r--src/runscript.c1097
-rw-r--r--src/splash.c130
-rw-r--r--src/start-stop-daemon.c1047
-rw-r--r--src/start-stop-daemon.pam6
-rw-r--r--src/strlist.h24
169 files changed, 20917 insertions, 0 deletions
diff --git a/COPYRIGHT b/COPYRIGHT
new file mode 100644
index 00000000..247707dc
--- /dev/null
+++ b/COPYRIGHT
@@ -0,0 +1 @@
+Copyright 1996-2007 Gentoo Foundation
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 00000000..cb0d3fa9
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,26 @@
+# ChangeLog for Gentoo System Intialization ("rc") scripts
+# Copyright 1999-2007 Gentoo Foundation; Distributed under the GPLv2
+
+ 05 Apr 2007; Roy Marples <uberlord@gentoo.org>:
+
+ Rewrite the core parts in C. We now provide librc so other programs can
+ query runlevels, services and state without using bash. We also provide
+ libeinfo so other programs can easily use our informational functions.
+
+ As such, we have dropped the requirement of using bash as the init script
+ shell. We now use /bin/sh and have strived to make the scripts as portable
+ as possible. Shells that work are bash and dash. busybox works provided
+ you disable s-s-d. If you have WIPE_TMP set to yes in conf.d/bootmisc you
+ should disable find too.
+ zsh and ksh do not work at this time.
+
+ Networking support is currently being re-vamped also as it was heavily bash
+ array based. As such, a new config format is available like so
+ config_eth0="1.2.3.4/24 5.6.7.8/16"
+ or like so
+ config_eth0="'1.2.3.4 netmask 255.255.255.0' '5.6.7.8 netmask 255.255.0.0'"
+
+ We will still support the old bash array format provided that /bin/sh IS
+ a link it bash.
+
+ ChangeLog for baselayout-1 can be found in our SVN repo.
diff --git a/Makefile b/Makefile
new file mode 100644
index 00000000..b349b879
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,108 @@
+# baselayout Makefile
+# Copyright 2006-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+#
+# We've moved the installation logic from Gentoo ebuild into a generic
+# Makefile so that the ebuild is much smaller and more simple.
+# It also has the added bonus of being easier to install on systems
+# without an ebuild style package manager.
+
+SUBDIRS = conf.d etc init.d man net sh share src
+
+NAME = baselayout
+#VERSION = 2.0.0_alpha1
+VERSION = 1.13.99
+
+PKG = $(NAME)-$(VERSION)
+
+ARCH = x86
+ifeq ($(OS),)
+OS=$(shell uname -s)
+ifneq ($(OS),Linux)
+OS=BSD
+endif
+endif
+
+BASE_DIRS = /$(LIB)/rcscripts/init.d /$(LIB)/rcscripts/tmp
+KEEP_DIRS = /boot /home /mnt /root \
+ /usr/local/bin /usr/local/sbin /usr/local/share/doc /usr/local/share/man \
+ /var/lock /var/run
+
+ifeq ($(OS),Linux)
+ KEEP_DIRS += /dev /sys
+ NET_LO = net.lo
+endif
+ifneq ($(OS),Linux)
+ NET_LO = net.lo0
+endif
+
+TOPDIR = .
+include $(TOPDIR)/default.mk
+
+install::
+ # These dirs may not exist from prior versions
+ for x in $(BASE_DIRS) ; do \
+ $(INSTALL_DIR) $(DESTDIR)$$x || exit $$? ; \
+ touch $(DESTDIR)$$x/.keep || exit $$? ; \
+ done
+ # Don't install runlevels if they already exist
+ if ! test -d $(DESTDIR)/etc/runlevels ; then \
+ (cd runlevels; $(MAKE) install) ; \
+ test -d runlevels.$(OS) && (cd runlevels.$(OS); $(MAKE) install) ; \
+ $(INSTALL_DIR) $(DESTDIR)/etc/runlevels/single || exit $$? ; \
+ $(INSTALL_DIR) $(DESTDIR)/etc/runlevels/nonetwork || exit $$? ; \
+ fi
+ ln -snf ../../$(LIB)/rcscripts/sh/net.sh $(DESTDIR)/etc/init.d/$(NET_LO) || exit $$?
+ ln -snf ../../$(LIB)/rcscripts/sh/functions.sh $(DESTDIR)/etc/init.d || exit $$?
+ # Handle lib correctly
+ if test $(LIB) != "lib" ; then \
+ sed -i'.bak' -e 's,/lib/,/$(LIB)/,g' $(DESTDIR)/$(LIB)/rcscripts/sh/functions.sh || exit $$? ; \
+ rm -f $(DESTDIR)/$(LIB)/rcscripts/sh/functions.sh.bak ; \
+ fi
+
+.PHONY: all clean install
+
+layout:
+ # Create base filesytem layout
+ for x in $(KEEP_DIRS) ; do \
+ $(INSTALL_DIR) $(DESTDIR)$$x || exit $$? ; \
+ touch $(DESTDIR)$$x/.keep || exit $$? ; \
+ done
+ # Special dirs
+ install -m 0700 -d $(DESTDIR)/root || exit $$?
+ touch $(DESTDIR)/root/.keep || exit $$?
+ install -m 1777 -d $(DESTDIR)/var/tmp || exit $$?
+ touch $(DESTDIR)/var/tmp/.keep || exit $$?
+ install -m 1777 -d $(DESTDIR)/tmp || exit $$?
+ touch $(DESTDIR)/tmp/.keep || exit $$?
+ # FHS compatibility symlinks stuff
+ ln -snf /var/tmp $(DESTDIR)/usr/tmp || exit $$?
+ ln -snf share/man $(DESTDIR)/usr/local/man || exit $$?
+
+distcheck:
+ if test -d .svn ; then \
+ svnfiles=`svn status 2>&1 | egrep -v '^(U|P)'` ; \
+ if test "x$$svnfiles" != "x" ; then \
+ echo "Refusing to package tarball until svn is in sync:" ; \
+ echo "$$svnfiles" ; \
+ echo "make distforce to force packaging" ; \
+ exit 1 ; \
+ fi \
+ fi
+
+distforce:
+ install -d /tmp/$(PKG)
+ cp -PRp . /tmp/$(PKG)
+ `which find` /tmp/$(PKG) -depth -path "*/.svn/*" -delete
+ `which find` /tmp/$(PKG) -depth -path "*/.svn" -delete
+ rm -rf /tmp/$(PKG)/src/core /tmp/$(PKG)/po
+ $(MAKE) -C /tmp/$(PKG) clean
+ sed -i'.bak' -e '/-Wl,-rpath ./ s/^/#/g' /tmp/$(PKG)/src/Makefile
+ rm -f /tmp/$(PKG)/src/Makefile.bak
+ tar -C /tmp -cvjpf /tmp/$(PKG).tar.bz2 $(PKG)
+ rm -Rf /tmp/$(PKG)
+ du /tmp/$(PKG).tar.bz2
+
+dist: distcheck distforce
+
+# vim: set ts=4 :
diff --git a/STYLE b/STYLE
new file mode 100644
index 00000000..0fbd2845
--- /dev/null
+++ b/STYLE
@@ -0,0 +1,53 @@
+This is the rc-scripts style manual. It governs the coding style
+of rc-scripts. Everything here might as well have been spoken by
+God. If you find any issues, please talk to base-system@gentoo.org
+or #gentoo-base on irc.freenode.net.
+
+#############
+# VARIABLES #
+#############
+- User Variables -
+ Variables must always be enclosed by {}
+ e.g. ${foo} ${bar}
+- Internal Shell Variables -
+ Do not use {} with internal variables unless appropriate
+ e.g. case $1 in
+ e.g. foo=$IFS
+ e.g. echo "blah${1}123"
+- Assigning with Quotes -
+ When assigning to a variable from another variable, you should
+ not need quotes. However, you do when assigning from a subshell.
+ e.g. foo=${bar}
+ e.g. foo="$(uname -a)"
+
+#########
+# TESTS #
+#########
+- Brackets -
+ Always use the [ ... ] form instead of [[ ... ]] as the later only really
+ works in bash, and we should support as many shells as we can.
+- Quoting -
+ When dealing with strings, you should quote both sides.
+
+###############
+# CODE BLOCKS #
+###############
+- Structure -
+ Use the more compact form
+ e.g. if ... ; then
+ e.g. while ... ; do
+ Do not use the older form
+ e.g. if ...
+ then
+- Functions -
+ Use the more compact form
+ e.g. foo() {
+ Do not lead with 'function '
+ e.g. function foo() {
+
+############
+# COMMENTS #
+############
+- General -
+ Try to include a comment block before sections
+ of code to explain what you're attempting
diff --git a/conf.d.BSD/Makefile b/conf.d.BSD/Makefile
new file mode 100644
index 00000000..13731e61
--- /dev/null
+++ b/conf.d.BSD/Makefile
@@ -0,0 +1,5 @@
+DIR = /etc/conf.d
+FILES = localmount net.example wireless.example
+
+TOPDIR = ..
+include $(TOPDIR)/default.mk
diff --git a/conf.d.BSD/localmount b/conf.d.BSD/localmount
new file mode 100644
index 00000000..2002beb6
--- /dev/null
+++ b/conf.d.BSD/localmount
@@ -0,0 +1,31 @@
+# /etc/conf.d/localmount
+
+# Kernel core dump options for FreeBSD kernel.
+# Unless you're a FreeBSD kernel developer or driver writer then this won't
+# be of any interest to you at all.
+
+# The following options allow to configure the kernel's core dump
+# facilities. Please read
+# http://www.freebsd.org/doc/en_US.ISO8859-1/books/developers-handbook/kerneldebug.html
+# for more information about Kernel core dumps and kernel debugging.
+
+# KERNEL_DUMP_DEVICE variable is used to specify which device will be
+# used by the kernel to write the dump down. This has to be a swap
+# partition, and has to be at least big enough to contain the whole
+# physical memory (see hw.physmem sysctl(8) variable).
+# When the variable is commented out, no core dump will be enabled for
+# the kernel.
+#KERNEL_DUMP_DEVICE="/dev/ad0s1b"
+
+# KERNEL_DUMP_DIR variable is used to tell savecore(8) utility where
+# to save the kernel core dump once it's restored from the dump
+# device. If unset, /var/crash will be used, as the default of
+# FreeBSD.
+#KERNEL_DUMP_DIR="/var/crash"
+
+# KERNEL_DUMP_COMPRESS variable decide whether to compress with
+# gzip(1) the dump or leave it of its original size (the size of the
+# physical memory present on the system). If set to yes, the -z option
+# will be passed to savecore(8) that will proceed on compressing the
+# dump.
+#KERNEL_DUMP_COMPRESS="no"
diff --git a/conf.d.BSD/net.example b/conf.d.BSD/net.example
new file mode 100644
index 00000000..7108c0f6
--- /dev/null
+++ b/conf.d.BSD/net.example
@@ -0,0 +1,309 @@
+# BSD NOTE: Network functionality support is still being written and
+# many parts here are missing compared to Gentoo/Linux
+# Feel free to write the needed modules and submit them to us :)
+#
+##############################################################################
+# QUICK-START
+#
+# The quickest start is if you want to use DHCP.
+# In that case, everything should work out of the box, no configuration
+# necessary, though the startup script will warn you that you haven't
+# specified anything.
+
+# WARNING :- some examples have a mixture of IPv4 (ie 192.168.0.1) and IPv6
+# (ie 4321:0:1:2:3:4:567:89ab) internet addresses. They only work if you have
+# the relevant kernel option enabled. So if you don't have an IPv6 enabled
+# kernel then remove the IPv6 address from your config.
+
+# If you want to use a static address or use DHCP explicitly, jump
+# down to the section labelled INTERFACE HANDLERS.
+#
+# If you want to do anything more fancy, you should take the time to
+# read through the rest of this file.
+
+##############################################################################
+# MODULES
+#
+# We now support modular networking scripts which means we can easily
+# add support for new interface types and modules while keeping
+# compatability with existing ones.
+#
+# Modules load by default if the package they need is installed. If
+# you specify a module here that doesn't have it's package installed
+# then you get an error stating which package you need to install.
+# Ideally, you only use the modules setting when you have two or more
+# packages installed that supply the same service.
+#
+# In other words, you probably should DO NOTHING HERE...
+
+##############################################################################
+# INTERFACE HANDLERS
+
+# For a static configuration, use something like this
+# (They all do exactly the same thing btw)
+#config_eth0="192.168.0.2/24"
+#config_eth0="'192.168.0.2 netmask 255.255.255.0'"
+
+# We can also specify a broadcast
+#config_eth0="'192.168.0.2/24 brd 192.168.0.255'"
+#config_eth0="'192.168.0.2 netmask 255.255.255.0 broadcast 192.168.0.255'"
+
+# If you need more than one address, you can use something like this
+# NOTE: ifconfig creates an aliased device for each extra IPv4 address
+# (eth0:1, eth0:2, etc)
+# iproute2 does not do this as there is no need to
+#config_eth0="'192.168.0.2/24' '192.168.0.3/24' '192.168.0.4/24'"
+# Or you can use sequence expressions
+#config_eth0="'192.168.0.{2..4}/24'" FIXME - may not work with baselayout2
+# which does the same as above. Be careful though as if you use this and
+# fallbacks, you have to ensure that both end up with the same number of
+# values otherwise your fallback won't work correctly.
+
+# You can also use IPv6 addresses
+# (you should always specify a prefix length with IPv6 here)
+#config_eth0="192.168.0.2/24 \
+#4321:0:1:2:3:4:567:89ab/64 \
+#4321:0:1:2:3:4:567:89ac/64"
+
+# If you wish to keep existing addresses + routing and the interface is up,
+# you can specify a noop (no operation). If the interface is down or there
+# are no addresses assigned, then we move onto the next step (default dhcp)
+# This is useful when configuring your interface with a kernel command line
+# or similar
+#config_eth0="noop 192.168.0.2/24"
+
+# If you don't want ANY address (only useful when calling for advanced stuff)
+#config_eth0="null"
+
+# Here's how to do routing if you need it
+# We add an IPv4 default route, IPv4 subnet route and an IPv6 unicast route
+#routes_eth0=" \
+# 'default via 192.168.0.1' \
+# '10.0.0.0/8 via 192.168.0.1' \
+# '::/0' \
+#"
+
+# If a specified module fails (like dhcp - see below), you can specify a
+# fallback like so
+#fallback_eth0="'192.168.0.2 netmask 255.255.255.0'"
+#fallback_route_eth0="'default via 192.168.0.1'"
+
+# NOTE: fallback entry must match the entry location in config_eth0
+# As such you can only have one fallback route.
+
+# Some users may need to alter the MTU - here's how
+#mtu_eth0="1500"
+
+# Most drivers that report carrier status function correctly, but some do not
+# One of these faulty drivers is for the Intel e1000 network card, but only
+# at boot time. To get around this you may alter the carrier_timeout value for
+# the interface. -1 is disable, 0 is infinite and any other number of seconds
+# is how long we wait for carrier. The current default is 3 seconds
+#carrier_timeout_eth0=-1
+
+##############################################################################
+# OPTIONAL MODULES
+
+#-----------------------------------------------------------------------------
+# WIRELESS (802.11 support)
+# Wireless can be provided by BSDs ifconfig or wpa_supplicant
+
+# ifconfig support is a one shot script - wpa_supplicant is daemon that
+# scans, assoicates and re-configures if assocation is lost.
+# wpa_supplicant is preferred
+# See wireless.example for details about using ifconfig for wireless
+
+# emerge net-wireless/wpa-supplicant
+# Wireless options are held in /etc/wpa_supplicant/wpa_supplicant.conf
+# Console the wpa_supplicant.conf.example that is installed in
+# /usr/share/doc/wpa_supplicant
+
+# By default we don't wait for wpa_suppliant to associate and authenticate.
+# If you would like to, so can specify how long in seconds
+#associate_timeout_eth0=60
+# A value of 0 means wait forever.
+
+# You can also override any settings found here per SSID - which is very
+# handy if you use different networks a lot. See below for using the SSID
+# in our variables
+#config_SSID="dhcp"
+# See the System module below for setting dns/nis/ntp per SSID
+
+# You can also override any settings found here per MAC address of the AP
+# in case you use Access Points with the same SSID but need different
+# networking configs. Below is an example - of course you use the same
+# method with other variables
+#mac_config_001122334455="dhcp"
+#mac_dns_servers_001122334455="192.168.0.1 192.168.0.2"
+
+# When an interface has been associated with an Access Point, a global
+# variable called SSID is set to the Access Point's SSID for use in the
+# pre/post user functions below (although it's not available in preup as you
+# won't have associated then)
+
+# If you're using anything else to configure wireless on your interface AND
+# you have installed wpa_supplicant, you need to disable wpa_supplicant
+#modules="!iwconfig !wpa_supplicant"
+#or
+#modules="!wireless"
+
+##############################################################################
+# WIRELESS SSID IN VARIABLES
+##############################################################################
+# Remember to change SSID to your SSID.
+# Say that your SSID is My NET - the line
+# #key_SSID="s:passkey"
+# becomes
+# #key_My_NET="s:passkey"
+# Notice that the space has changed to an underscore - do the same with all
+# characters not in a-z A-Z (English alphabet) 0-9. This only applies to
+# variables and not values.
+#
+# Any SSID's in values like essid_eth0="My NET" may need to be escaped
+# This means placing the character \ before the character
+# \" need to be escaped for example
+# So if your SSID is
+# My "\ NET
+# it becomes
+# My \"\\ NET
+# for example
+# #essid_eth0="My\"\\NET"
+#
+# So using the above we can use
+# #dns_domain_My____NET="My\"\\NET"
+# which is an invalid dns domain, but shows the how to use the variable
+# structure
+#########################################################
+
+#-----------------------------------------------------------------------------
+# DHCP
+# DHCP can be provided by dhclient.
+#
+# dhcpcd: emerge net-misc/dhcpcd
+# dhclient: emerge net-misc/dhcp
+
+# Regardless of which DHCP client you prefer, you configure them the
+# same way using one of following depending on which interface modules
+# you're using.
+#config_eth0="dhcp"
+
+# For passing custom options to dhcpcd use something like the following. This
+# example reduces the timeout for retrieving an address from 60 seconds (the
+# default) to 10 seconds.
+#dhcpcd_eth0="-t 10"
+
+# GENERIC DHCP OPTIONS
+# Set generic DHCP options like so
+#dhcp_eth0="release nodns nontp nonis nogateway nosendhost"
+
+# This tells the dhcp client to release it's lease when it stops, not to
+# overwrite dns, ntp and nis settings, not to set a default route and not to
+# send the current hostname to the dhcp server and when it starts.
+# You can use any combination of the above options - the default is not to
+# use any of them.
+
+
+#-----------------------------------------------------------------------------
+# System
+# For configuring system specifics such as domain, dns, ntp and nis servers
+# It's rare that you would need todo this, but you can anyway.
+# This is most benefit to wireless users who don't use DHCP so they can change
+# their configs based on SSID. See above for more details
+
+# Setting name/domain server causes /etc/resolv.conf to be overwritten
+# Note that if DHCP is used, and you want this to take precedence then
+# set dhcp_SSID="nodns"
+# To use dns settings such as these, dns_servers_eth0 must be set!
+# If you omit the _eth0 suffix, then it applies to all interfaces unless
+# overridden by the interface suffix.
+#dns_domain_eth0="your.domain"
+#dns_servers_eth0="192.168.0.2 192.168.0.3"
+#dns_search_eth0="this.domain that.domain"
+#dns_options_eth0="'timeout 1' 'rotate'"
+#dns_sortlist_eth0="130.155.160.0/255.255.240.0 130.155.0.0"
+# See the man page for resolv.conf for details about the options and sortlist
+# directives
+
+#ntp_servers_eth0="192.168.0.2 192.168.0.3"
+
+#nis_domain_eth0="domain"
+#nis_servers_eth0="192.168.0.2 192.168.0.3"
+
+# NOTE: Setting any of these will stamp on the files in question. So if you
+# don't specify dns_servers but you do specify dns_domain then no nameservers
+# will be listed in /etc/resolv.conf even if there were any there to start
+# with.
+# If this is an issue for you then maybe you should look into a resolv.conf
+# manager like resolvconf-gentoo to manage this file for you. All packages
+# that baselayout supports use resolvconf-gentoo if installed.
+
+#-----------------------------------------------------------------------------
+# Cable in/out detection
+# Sometimes the cable is in, others it's out. Obviously you don't want to
+# restart net.eth0 every time when you plug it in either.
+# BSD has the Device State Change Daemon - or devd for short
+# To enable this, simple add devd to the boot runlevel
+#rc-update add devd boot
+#rc
+
+##############################################################################
+# ADVANCED CONFIGURATION
+#
+# Four functions can be defined which will be called surrounding the
+# start/stop operations. The functions are called with the interface
+# name first so that one function can control multiple adapters. An extra two
+# functions can be defined when an interface fails to start or stop.
+#
+# The return values for the preup and predown functions should be 0
+# (success) to indicate that configuration or deconfiguration of the
+# interface can continue. If preup returns a non-zero value, then
+# interface configuration will be aborted. If predown returns a
+# non-zero value, then the interface will not be allowed to continue
+# deconfiguration.
+#
+# The return values for the postup, postdown, failup and faildown functions are
+# ignored since there's nothing to do if they indicate failure.
+#
+# ${IFACE} is set to the interface being brought up/down
+# ${IFVAR} is ${IFACE} converted to variable name bash allows
+
+#preup() {
+# # Remember to return 0 on success
+# return 0
+#}
+
+#predown() {
+# # The default in the script is to test for NFS root and disallow
+# # downing interfaces in that case. Note that if you specify a
+# # predown() function you will override that logic. Here it is, in
+# # case you still want it...
+# if is_net_fs /; then
+# eerror "root filesystem is network mounted -- can't stop ${IFACE}"
+# return 1
+# fi
+#
+# # Remember to return 0 on success
+# return 0
+#}
+
+#postup() {
+# # This function could be used, for example, to register with a
+# # dynamic DNS service. Another possibility would be to
+# # send/receive mail once the interface is brought up.
+
+#}
+
+#postdown() {
+# # Return 0 always
+# return 0
+#}
+
+#failup() {
+# # This function is mostly here for completeness... I haven't
+# # thought of anything nifty to do with it yet ;-)
+#}
+
+#faildown() {
+# # This function is mostly here for completeness... I haven't
+# # thought of anything nifty to do with it yet ;-)
+#}
diff --git a/conf.d.BSD/wireless.example b/conf.d.BSD/wireless.example
new file mode 100644
index 00000000..d9dadcbe
--- /dev/null
+++ b/conf.d.BSD/wireless.example
@@ -0,0 +1,190 @@
+# /etc/conf.d/wireless:
+# Global wireless config file for net.* rc-scripts
+
+##############################################################################
+# HINTS
+##############################################################################
+# see net.example for using ESSID in variable names
+#
+# Most users will just need to set the following options
+# key_ESSID1="s:yourkeyhere enc open" # s: means a text key
+# key_ESSID2="aaaa-bbbb-cccc-dd" # no s: means a hex key
+# preferred_aps="'ESSID1' 'ESSID2'"
+#
+# Clear? Good. Now configure your wireless network below
+#############################################################################
+
+##############################################################################
+# SETTINGS
+##############################################################################
+# Hard code an ESSID to an interface - leave this unset if you wish the driver
+# to scan for available Access Points
+# I would only set this as a last resort really - use the preferred_aps
+# setting at the bottom of this file
+#essid_eth0='foo'
+
+# Some drivers/hardware don't scan all that well. We have no control over this
+# but we can say how many scans we want to do to try and get a better sweep of
+# the area. The default is 1.
+#scans_eth0="1"
+
+#Channel can be set (1-14), but defaults to 3 if not set.
+#
+# The below is taken verbatim from the BSD wavelan documentation found at
+# http://www.netbsd.org/Documentation/network/wavelan.html
+# There are 14 channels possible; We are told that channels 1-11 are legal for
+# North America, channels 1-13 for most of Europe, channels 10-13 for France,
+# and only channel 14 for Japan. If in doubt, please refer to the documentation
+# that came with your card or access point. Make sure that the channel you
+# select is the same channel your access point (or the other card in an ad-hoc
+# network) is on. The default for cards sold in North America and most of Europe
+# is 3; the default for cards sold in France is 11, and the default for cards
+# sold in Japan is 14.
+#channel_eth0="3"
+
+# Setup any other config commands. This is basically the ifconfig argument
+# without the ifconfig $iface.
+#ifconfig_eth0=""
+# You can do the same per ESSID too.
+#ifconfig_ESSID=""
+
+# Seconds to wait until associated. The default is to wait 10 seconds.
+# 0 means wait indefinitely. WARNING: this can cause an infinite delay when
+# booting.
+#associate_timeout_eth0="5"
+
+# Define a WEP key per ESSID or MAC address (of the AP, not your card)
+# The encryption type (open or restricted) must match the
+# encryption type on the Access Point.
+# To set a hex key, prefix with 0x
+#key_ESSID="0x12341234123412341234123456"
+# or you can use strings. Passphrase IS NOT supported
+#key_ESSID="foobar"
+#key_ESSID="foobar"
+
+# WEP key for the AP with MAC address 001122334455
+#mac_key_001122334455="foobar"
+
+# You can also override the interface settings found in /etc/conf.d/net
+# per ESSID - which is very handy if you use different networks a lot
+#config_ESSID="dhcp"
+#routes_ESSID=
+#fallback_ESSID=
+
+# Setting name/domain server causes /etc/resolv.conf to be overwritten
+# Note that if DHCP is used, and you want this to take precedence then
+# please put -R in your dhcpcd options
+#dns_servers_ESSID="192.168.0.1 192.168.0.2"
+#dns_domain_ESSID="some.domain"
+#dns_search_path_ESSID="search.this.domain search.that.domain"
+# Please check the man page for resolv.conf for more information
+# as domain and search (searchdomains) are mutually exclusive and
+# searchdomains takes precedence
+
+# You can also set any of the /etc/conf.d/net variables per MAC address
+# incase you use Access Points with the same ESSID but need different
+# networking configs. Below is an example - of course you use the same
+# method with other variables
+#config_001122334455="dhcp"
+#dns_servers_001122334455="192.168.0.1 192.168.0.2"
+
+# Map a MAC address to an ESSID
+# This is used when the Access Point is not broadcasting it's ESSID
+# WARNING: This will override the ESSID being broadcast due to some
+# Access Points sending an ESSID even when they have been configured
+# not to!
+# Change 001122334455 to the MAC address and ESSID to the ESSID
+# it should map to
+#mac_essid_001122334455="ESSID"
+
+# This lists the preferred ESSIDs to connect to in order
+# ESSID's can contain any characters here as they must match the broadcast
+# ESSID exactly.
+# Surround each ESSID with the " character and seperate them with a space
+# If the first ESSID isn't found then it moves onto the next
+# If this isn't defined then it connects to the first one found
+#preferred_aps="'ESSID 1' 'ESSID 2'"
+
+# You can also define a preferred_aps list per interface
+#preferred_aps_eth0="'ESSID 3' 'ESSID 4'"
+
+# You can also say whether we only connect to preferred APs or not
+# Values are "any", "preferredonly", "forcepreferred", "forcepreferredonly"
+# and "forceany"
+# "any" means it will connect to visible APs in the preferred list and then
+# any other available AP
+# "preferredonly" means it will only connect to visible APs in the preferred
+# list
+# "forcepreferred" means it will forceably connect to APs in order if it does
+# not find them in a scan
+# "forcepreferredonly" means it forceably connects to the APs in order and
+# does not bother to scan
+# "forceany" does the same as forcepreferred + connects to any other
+# available AP
+# Default is "any"
+#associate_order="any"
+#associate_order_eth0="any"
+
+# You can define blacklisted Access Points in the same way
+#blacklist_aps="'ESSID 1' 'ESSID 2'"
+#blacklist_aps_eth0="'ESSID 3' 'ESSID 4'"
+
+# If you have more than one wireless card, you can say if you want
+# to allow each card to associate with the same Access Point or not
+# Values are "yes" and "no"
+# Default is "yes"
+#unique_ap="yes"
+#unique_ap_eth0="yes"
+
+# IMPORTANT: preferred_only, blacklisted_aps and unique_ap only work when
+# essid_eth0 is not set and your card is capable of scanning
+
+# NOTE: preferred_aps list ignores blacklisted_aps - so if you have
+# the same ESSID in both, well, you're a bit silly :p
+
+
+##############################################################################
+# ADVANCED CONFIGURATION
+#
+# Two functions can be defined which will be called surrounding the
+# associate function. The functions are called with the interface
+# name first so that one function can control multiple adapters.
+#
+# The return values for the preassociate function should be 0
+# (success) to indicate that configuration or deconfiguration of the
+# interface can continue. If preassociate returns a non-zero value, then
+# interface configuration will be aborted.
+#
+# The return value for the postassociate function is ignored
+# since there's nothing to do if it indicates failure.
+
+#preassociate() {
+# # The below adds two configuration variables leap_user_ESSID
+# # and leap_pass_ESSID. When they are both confiugred for the ESSID
+# # being connected to then we run the CISCO LEAP script
+#
+# local user pass
+# eval user=\"\$\{leap_user_${ESSIDVAR}\}\"
+# eval pass=\"\$\{leap_pass_${ESSIDVAR}\}\"
+#
+# if [ -n "${user}" -a -n "${pass}" ]; then
+# if [ ! -x /opt/cisco/bin/leapscript ]; then
+# eend "For LEAP support, please emerge net-misc/cisco-aironet-client-utils"
+# return 1
+# fi
+# einfo "Waiting for LEAP Authentication on \"${ESSID}\""
+# if /opt/cisco/bin/leapscript ${user} ${pass} | grep -q 'Login incorrect'; then
+# ewarn "Login Failed for ${user}"
+# return 1
+# fi
+# fi
+#
+# return 0
+#}
+
+#postassociate() {
+# # This function is mostly here for completeness... I haven't
+# # thought of anything nifty to do with it yet ;-)
+# # Return 0 always
+# return 0
+#}
diff --git a/conf.d.Linux/Makefile b/conf.d.Linux/Makefile
new file mode 100644
index 00000000..6a87562d
--- /dev/null
+++ b/conf.d.Linux/Makefile
@@ -0,0 +1,7 @@
+DIR = /etc/conf.d
+FILES = net.example wireless.example
+FILES_APPEND = clock rc
+FILES_NOEXIST = consolefont keymaps volumes
+
+TOPDIR = ..
+include $(TOPDIR)/default.mk
diff --git a/conf.d.Linux/clock b/conf.d.Linux/clock
new file mode 100644
index 00000000..0ff87c01
--- /dev/null
+++ b/conf.d.Linux/clock
@@ -0,0 +1,31 @@
+
+# If you wish to pass any other arguments to hwclock during bootup,
+# you may do so here.
+
+CLOCK_OPTS=""
+
+# If you want to set the Hardware Clock to the current System Time
+# during shutdown, then say "yes" here.
+
+CLOCK_SYSTOHC="no"
+
+# Newer FHS specs say this file should live in /var/lib rather than
+# /etc. If you care about such things, feel free to change this value.
+# Note that a blank value means that you do not wish to even use the
+# adjtime facility. This is the default behavior as adjtime can be
+# very fragile. If the clock is updated without updating the adjtime
+# file (which is common when using services such as ntp), then the
+# clock can be screwed up when it gets updated at next boot.
+
+#CLOCK_ADJTIME="/var/lib/adjtime"
+#CLOCK_ADJTIME="/etc/adjtime"
+CLOCK_ADJTIME=""
+
+
+### ALPHA SPECIFIC OPTIONS ###
+
+# If your alpha uses the SRM console, set this to "yes".
+SRM="no"
+
+# If your alpha uses the ARC console, set this to "yes".
+ARC="no"
diff --git a/conf.d.Linux/consolefont b/conf.d.Linux/consolefont
new file mode 100644
index 00000000..d1c29a6d
--- /dev/null
+++ b/conf.d.Linux/consolefont
@@ -0,0 +1,19 @@
+# /etc/conf.d/consolefont
+
+# CONSOLEFONT specifies the default font that you'd like Linux to use on the
+# console. You can find a good selection of fonts in /usr/share/consolefonts;
+# you shouldn't specify the trailing ".psf.gz", just the font name below.
+# To use the default console font, comment out the CONSOLEFONT setting below.
+# This setting is used by the /etc/init.d/consolefont script (NOTE: if you do
+# not want to use it, run "rc-update del consolefont" as root).
+CONSOLEFONT="default8x16"
+
+# CONSOLETRANSLATION is the charset map file to use. Leave commented to use
+# the default one. Have a look in /usr/share/consoletrans for a selection of
+# map files you can use.
+#CONSOLETRANSLATION="8859-1_to_uni"
+
+# UNICODEMAP is the unicode map file to use. Leave commented to use the
+# default one. Have a look in /usr/share/unimaps for a selection of map files
+# you can use.
+#UNICODEMAP="iso01"
diff --git a/conf.d.Linux/keymaps b/conf.d.Linux/keymaps
new file mode 100644
index 00000000..eb68fbe2
--- /dev/null
+++ b/conf.d.Linux/keymaps
@@ -0,0 +1,26 @@
+# /etc/conf.d/keymaps
+
+# Use KEYMAP to specify the default console keymap. There is a complete tree
+# of keymaps in /usr/share/keymaps to choose from.
+
+KEYMAP="us"
+
+
+# Should we first load the 'windowkeys' console keymap? Most x86 users will
+# say "yes" here. Note that non-x86 users should leave it as "no".
+
+SET_WINDOWKEYS="no"
+
+
+# The maps to load for extended keyboards. Most users will leave this as is.
+
+EXTENDED_KEYMAPS=""
+#EXTENDED_KEYMAPS="backspace keypad euro"
+
+
+# Tell dumpkeys(1) to interpret character action codes to be
+# from the specified character set.
+# This only matters if you set UNICODE="yes" in /etc/rc.conf.
+# For a list of valid sets, run `dumpkeys --help`
+
+DUMPKEYS_CHARSET=""
diff --git a/conf.d.Linux/net.example b/conf.d.Linux/net.example
new file mode 100644
index 00000000..ffbece15
--- /dev/null
+++ b/conf.d.Linux/net.example
@@ -0,0 +1,846 @@
+##############################################################################
+# QUICK-START
+#
+# The quickest start is if you want to use DHCP.
+# In that case, everything should work out of the box, no configuration
+# necessary, though the startup script will warn you that you haven't
+# specified anything.
+
+# WARNING :- some examples have a mixture of IPv4 (ie 192.168.0.1) and IPv6
+# (ie 4321:0:1:2:3:4:567:89ab) internet addresses. They only work if you have
+# the relevant kernel option enabled. So if you don't have an IPv6 enabled
+# kernel then remove the IPv6 address from your config.
+
+# If you want to use a static address or use DHCP explicitly, jump
+# down to the section labelled INTERFACE HANDLERS.
+#
+# If you want to do anything more fancy, you should take the time to
+# read through the rest of this file.
+
+
+##############################################################################
+# VARIABLES
+#
+# We've changed from using arrays to evaluated strings.
+# This has the benefit of being slightly more readable but more importantly it
+# works across all shells.
+# OLD
+# config_eth0=( "192.168.0.24 netmask 255.255.255.0" "192.168.0.25/24" )
+# NEW
+# config_eth0="'192.168.0.24 netmask 255.255.255.0' 192.168.0.25/24"
+# INVALID
+# config_eth0='192.168.0.24 netmask 255.255.255.0'
+#
+# As the 1st value has spaces in it, it needs additional quoting. The 2nd
+# value has no spaces, therefore no additional quoting is required.
+# The last statement is invalid because when it is evaluated, it only has one
+# set of quotes.
+
+##############################################################################
+# MODULES
+#
+# We now support modular networking scripts which means we can easily
+# add support for new interface types and modules while keeping
+# compatability with existing ones.
+#
+# Modules load by default if the package they need is installed. If
+# you specify a module here that doesn't have it's package installed
+# then you get an error stating which package you need to install.
+# Ideally, you only use the modules setting when you have two or more
+# packages installed that supply the same service.
+#
+# In other words, you probably should DO NOTHING HERE...
+
+# Prefer ifconfig over iproute2
+#modules="ifconfig"
+
+# You can also specify other modules for an interface
+# In this case we prefer udhcpc over dhcpcd
+#modules_eth0="udhcpc"
+
+# You can also specify which modules not to use - for example you may be
+# using a supplicant or linux-wlan-ng to control wireless configuration but
+# you still want to configure network settings per SSID associated with.
+#modules="!iwconfig !wpa_supplicant"
+# IMPORTANT: If you need the above, please disable modules in that order
+
+
+##############################################################################
+# INTERFACE HANDLERS
+#
+# We provide two interface handlers presently: ifconfig and iproute2.
+# You need one of these to do any kind of network configuration.
+# For ifconfig support, emerge sys-apps/net-tools
+# For iproute2 support, emerge sys-apps/iproute2
+
+# If you don't specify an interface then we prefer iproute2 if it's installed
+# To prefer ifconfig over iproute2
+#modules="ifconfig"
+
+# For a static configuration, use something like this
+# (They all do exactly the same thing btw)
+#config_eth0="192.168.0.2/24"
+#config_eth0="'192.168.0.2 netmask 255.255.255.0'"
+
+# We can also specify a broadcast
+#config_eth0="'192.168.0.2/24 brd 192.168.0.255'"
+#config_eth0="'192.168.0.2 netmask 255.255.255.0 broadcast 192.168.0.255'"
+
+# If you need more than one address, you can use something like this
+# NOTE: ifconfig creates an aliased device for each extra IPv4 address
+# (eth0:1, eth0:2, etc)
+# iproute2 does not do this as there is no need to
+#config_eth0="'192.168.0.2/24' '192.168.0.3/24' '192.168.0.4/24'"
+# Or you can use sequence expressions
+#config_eth0="192.168.0.{2..4}/24" # FIXME - does it work?
+# which does the same as above. Be careful though as if you use this and
+# fallbacks, you have to ensure that both end up with the same number of
+# values otherwise your fallback won't work correctly.
+
+# You can also use IPv6 addresses
+# (you should always specify a prefix length with IPv6 here)
+#config_eth0="192.168.0.2/24 \
+#4321:0:1:2:3:4:567:89ab/64 \
+#4321:0:1:2:3:4:567:89ac/64"
+#)
+
+# If you wish to keep existing addresses + routing and the interface is up,
+# you can specify a noop (no operation). If the interface is down or there
+# are no addresses assigned, then we move onto the next step (default dhcp)
+# This is useful when configuring your interface with a kernel command line
+# or similar
+#config_eth0="noop 192.168.0.2/24"
+
+# If you don't want ANY address (only useful when calling for advanced stuff)
+#config_eth0="null"
+
+# Here's how to do routing if you need it
+# We add an IPv4 default route, IPv4 subnet route and an IPv6 unicast route
+#routes_eth0=" \
+# 'default via 192.168.0.1' \
+# '10.0.0.0/8 via 192.168.0.1' \
+# '::/0' \
+#"
+
+# If a specified module fails (like dhcp - see below), you can specify a
+# fallback like so
+#fallback_eth0="'192.168.0.2 netmask 255.255.255.0'"
+#fallback_route_eth0="'default via 192.168.0.1'"
+
+# NOTE: fallback entry must match the entry location in config_eth0
+# As such you can only have one fallback route.
+
+# Some users may need to alter the MTU - here's how
+#mtu_eth0="1500"
+
+# Each module described below can set a default base metric, lower is
+# preferred over higher. This is so we can prefer a wired route over a
+# wireless route automaticaly. You can override this by setting
+#metric_eth0="100"
+# or on a global basis
+#metric="100"
+# The only downside of the global setting is that you have to ensure that
+# there are no conflicting routes yourself. For users with large routing
+# tables you may have to set a global metric as the due to a simple read of
+# the routing table taking over a minute at a time.
+
+##############################################################################
+# OPTIONAL MODULES
+
+#-----------------------------------------------------------------------------
+# WIRELESS (802.11 support)
+# Wireless can be provided by iwconfig or wpa_supplicant
+
+# iwconfig
+# emerge net-wireless/wireless-tools
+# Wireless options are held in /etc/conf.d/wireless - but could be here too
+# Consult the sample file /etc/conf.d/wireless.example for instructions
+# wpa_supplicant is the default if it is installed
+
+# wpa_supplicant
+# emerge net-wireless/wpa-supplicant
+# Wireless options are held in /etc/wpa_supplicant/wpa_supplicant.conf
+# Console the wpa_supplicant.conf.example that is installed in
+# /usr/share/doc/wpa_supplicant
+# To configure wpa_supplicant
+#wpa_supplicant_ath0="-Dmadwifi" # For Atheros based cards
+# Consult wpa_supplicant for more drivers - the default is -Dwext which should
+# work for most cards.
+
+# By default we don't wait for wpa_suppliant to associate and authenticate.
+# If you need to change this behaviour then you don't know how our scripts work
+# and setting this value could cause strange things to happen.
+# If you would like to, so can specify how long in seconds.
+#associate_timeout_eth0=60
+# A value of 0 means wait forever.
+
+# You can also override any settings found here per SSID - which is very
+# handy if you use different networks a lot. See below for using the SSID
+# in our variables
+#config_SSID="dhcp"
+# See the System module below for setting dns/nis/ntp per SSID
+
+# You can also override any settings found here per MAC address of the AP
+# in case you use Access Points with the same SSID but need different
+# networking configs. Below is an example - of course you use the same
+# method with other variables
+#mac_config_001122334455="dhcp"
+#mac_dns_servers_001122334455="192.168.0.1 192.168.0.2"
+
+# When an interface has been associated with an Access Point, a global
+# variable called SSID is set to the Access Point's SSID for use in the
+# pre/post user functions below (although it's not available in preup as you
+# won't have associated then)
+
+# If you're using anything else to configure wireless on your interface AND
+# you have installed wpa_supplicant, you need to disable wpa_supplicant
+#modules="!iwconfig !wpa_supplicant"
+#or
+#modules="!wireless"
+
+##############################################################################
+# WIRELESS SSID IN VARIABLES
+##############################################################################
+# Remember to change SSID to your SSID.
+# Say that your SSID is My NET - the line
+# #key_SSID="s:passkey"
+# becomes
+# #key_My_NET="s:passkey"
+# Notice that the space has changed to an underscore - do the same with all
+# characters not in a-z A-Z (English alphabet) 0-9. This only applies to
+# variables and not values.
+#
+# Any SSID's in values like essid_eth0="My NET" may need to be escaped
+# This means placing the character \ before the character
+# \" need to be escaped for example
+# So if your SSID is
+# My "\ NET
+# it becomes
+# My \"\\ NET
+# for example
+# #essid_eth0="My\"\\NET"
+#
+# So using the above we can use
+# #dns_domain_My____NET="My\"\\NET"
+# which is an invalid dns domain, but shows the how to use the variable
+# structure
+#########################################################
+
+
+#-----------------------------------------------------------------------------
+# DHCP
+# DHCP can be provided by dhclient, dhcpcd, pump or udhcpc.
+#
+# dhclient: emerge net-misc/dhcp
+# dhcpcd: emerge net-misc/dhcpcd
+# pump: emerge net-misc/pump
+# udhcpc: emerge net-misc/udhcp
+
+# If you have more than one DHCP client installed, you need to specify which
+# one to use - otherwise we default to dhcpcd if available.
+#modules=( "dhclient" ) # to select dhclient over dhcpcd
+#
+# Notes:
+# - All clients send the current hostname to the DHCP server by default
+# - dhcpcd does not daemonize when the lease time is infinite
+# - udhcp-0.9.3-r3 and earlier do not support getting NTP servers
+# - pump does not support getting NIS servers
+# - DHCP tends to erase any existing device information - so add
+# static addresses after dhcp if you need them
+# - dhclient and udhcpc can set other resolv.conf options such as "option"
+# and "sortlist"- see the System module for more details
+
+# Regardless of which DHCP client you prefer, you configure them the
+# same way using one of following depending on which interface modules
+# you're using.
+#config_eth0="dhcp"
+
+# For passing custom options to dhcpcd use something like the following. This
+# example reduces the timeout for retrieving an address from 60 seconds (the
+# default) to 10 seconds.
+#dhcpcd_eth0="-t 10"
+
+# dhclient, udhcpc and pump don't have many runtime options
+# You can pass options to them in a similar manner to dhcpcd though
+#dhclient_eth0="..."
+#udhcpc_eth0="..."
+#pump_eth0="..."
+
+# GENERIC DHCP OPTIONS
+# Set generic DHCP options like so
+#dhcp_eth0="release nodns nontp nonis nogateway nosendhost"
+
+# This tells the dhcp client to release it's lease when it stops, not to
+# overwrite dns, ntp and nis settings, not to set a default route and not to
+# send the current hostname to the dhcp server and when it starts.
+# You can use any combination of the above options - the default is not to
+# use any of them.
+
+#-----------------------------------------------------------------------------
+# For APIPA support, emerge net-misc/iputils or net-analyzer/arping
+
+# APIPA is a module that tries to find a free address in the range
+# 169.254.0.0-169.254.255.255 by arping a random address in that range on the
+# interface. If no reply is found then we assign that address to the interface
+
+# This is only useful for LANs where there is no DHCP server and you don't
+# connect directly to the internet.
+#config_eth0="dhcp"
+#fallback_eth0="apipa"
+
+#-----------------------------------------------------------------------------
+# ARPING Gateway configuration
+# and
+# Automatic Private IP Addressing (APIPA)
+# For arpingnet / apipa support, emerge net-misc/iputils or net-analyzer/arping
+#
+# This is a module that tries to find a gateway IP. If it exists then we use
+# that gateways configuration for our own. For the configuration variables
+# simply ensure that each octet is zero padded and the dots are removed.
+# Below is an example.
+#
+#gateways_eth0="192.168.0.1 10.0.0.1"
+#config_192168000001="192.168.0.2/24"
+#routes_192168000001="'default via 192.168.0.1'"
+#dns_servers_192168000001="192.168.0.1"
+#config_010000000001="10.0.0.254/8"
+#routes_010000000001="default via 10.0.0.1"
+#dns_servers_010000000001="10.0.0.1"
+
+# We can also specify a specific MAC address for each gateway if different
+# networks have the same gateway.
+#gateways_eth0="192.168.0.1,00:11:22:AA:BB:CC 10.0.0.1,33:44:55:DD:EE:FF"
+#config_192168000001_001122AABBCC="192.168.0.2/24"
+#routes_192168000001_001122AABBCC="default via 192.168.0.1"
+#dns_servers_192168000001_001122AABBCC="192.168.0.1"
+#config_010000000001_334455DDEEFF="10.0.0.254/8"
+#routes_010000000001_334455DDEEFF="default via 10.0.0.1"
+#dns_servers_010000000001_334455DDEEFF="10.0.0.1"
+
+# If we don't find any gateways (or there are none configured) then we try and
+# use APIPA to find a free address in the range 169.254.0.0-169.254.255.255
+# by arping a random address in that range on the interface. If no reply is
+# found then we assign that address to the interface.
+
+# This is only useful for LANs where there is no DHCP server.
+#config_eth0="arping"
+
+# or if no DHCP server can be found
+#config_eth0="dhcp"
+#fallback_eth0="arping"
+
+# NOTE: We default to sleeping for 1 second the first time we attempt an
+# arping to give the interface time to settle on the LAN. This appears to
+# be a good default for most instances, but if not you can alter it here.
+#arping_sleep=5
+#arping_sleep_lan=7
+
+# NOTE: We default to waiting 3 seconds to get an arping response. You can
+# change the default wait like so.
+#arping_wait=3
+#arping_wait_lan=2
+
+#-----------------------------------------------------------------------------
+# VLAN (802.1q support)
+# For VLAN support, emerge net-misc/vconfig
+
+# Specify the VLAN numbers for the interface like so
+# Please ensure your VLAN IDs are NOT zero-padded
+#vlans_eth0="1 2"
+
+# You may not want to assign an IP the the physical interface, but we still
+# need it up.
+#config_eth0="null"
+
+# You can also configure the VLAN - see for vconfig man page for more details
+#vconfig_eth0="'set_name_type VLAN_PLUS_VID_NO_PAD'"
+#vconfig_vlan1="'set_flag 1' 'set_egress_map 2 6'"
+#config_vlan1="'172.16.3.1 netmask 255.255.254.0'"
+#config_vlan2="'172.16.2.1 netmask 255.255.254.0'"
+
+# NOTE: Vlans can be configured with a . in their interface names
+# When configuring vlans with this name type, you need to replace . with a _
+#config_eth0.1="dhcp" - does not work
+#config_eth0_1="dhcp" - does work
+
+# NOTE: Vlans are controlled by their physical interface and not per vlan
+# This means you do not need to create init scripts in /etc/init.d for each
+# vlan, you must need to create one for the physical interface.
+# If you wish to control the configuration of each vlan through a separate
+# script, or wish to rename the vlan interface to something that vconfig
+# cannot then you need to do this.
+#vlan_start_eth0="no"
+
+# If you do the above then you may want to depend on eth0 like so
+# RC_NEED_vlan1="net.eth0"
+# NOTE: depend functions only work in /etc/conf.d/net
+# and not in profile configs such as /etc/conf.d/net.foo
+
+#-----------------------------------------------------------------------------
+# Bonding
+# For link bonding/trunking emerge net-misc/ifenslave
+
+# To bond interfaces together
+#slaves_bond0="eth0 eth1 eth2"
+#config_bond0="null" # You may not want to assign an IP the the bond
+
+# If any of the slaves require extra configuration - for example wireless or
+# ppp devices - we need to depend function on the bonded interfaces
+#RC_NEED_bond0="net.eth0 net.eth1"
+
+
+#-----------------------------------------------------------------------------
+# Classical IP over ATM
+# For CLIP support emerge net-dialup/linux-atm
+
+# Ensure that you have /etc/atmsigd.conf setup correctly
+# Now setup each clip interface like so
+#clip_atm0=( "peer_ip [if.]vpi.vci [opts]" ... )
+# where "peer_ip" is the IP address of a PVC peer (in case of an ATM connection
+# with your ISP, your only peer is usually the ISP gateway closest to you),
+# "if" is the number of the ATM interface which will carry the PVC, "vpi.vci"
+# is the ATM VC address, and "opts" may optionally specify VC parameters like
+# qos, pcr, and the like (see "atmarp -s" for further reference). Please also
+# note quoting: it is meant to distinguish the VCs you want to create. You may,
+# in example, create an atm0 interface to more peers, like this:
+#clip_atm0="'1.1.1.254 0.8.35' 1.1.1.253 1.8.35'"
+
+# By default, the PVC will use the LLC/SNAP encapsulation. If you rather need a
+# null encapsulation (aka "VC mode"), please add the keyword "null" to opts.
+
+
+#-----------------------------------------------------------------------------
+# PPP
+# For PPP support, emerge net-dialup/ppp
+# PPP is used for most dialup connections, including ADSL.
+# The older ADSL module is documented below, but you are encouraged to try
+# this module first.
+#
+# You need to create the PPP net script yourself. Make it like so
+#ln -s net.lo /etc/init.d/net.ppp0
+#
+# We have to instruct ppp0 to actually use ppp
+#config_ppp0="ppp"
+#
+# Each PPP interface requires an interface to use as a "Link"
+#link_ppp0="/dev/ttyS0" # Most PPP links will use a serial port
+#link_ppp0="eth0" # PPPoE requires an ethernet interface
+#link_ppp0="[itf.]vpi.vci" # PPPoA requires the ATM VC's address
+#link_ppp0="/dev/null" # ISDN links should have this
+#link_ppp0="pty 'your_link_command'" # PPP links over ssh, rsh, etc
+#
+# Here you should specify what pppd plugins you want to use
+# Available plugins are: pppoe, pppoa, capi, dhcpc, minconn, radius,
+# radattr, radrealms and winbind
+#plugins_ppp0="pppoe" # Required plugin for PPPoE
+#plugins_ppp0="pppoa vc-encaps" # Required plugin for PPPoA with an option
+#plugins_ppp0="capi" # Required plugin for ISDN
+#
+# PPP requires at least a username. You can optionally set a password here too
+# If you don't, then it will use the password specified in /etc/ppp/*-secrets
+# against the specified username
+#username_ppp0='user'
+#password_ppp0='password'
+# NOTE: You can set a blank password like so
+#password_ppp0=
+#
+# The PPP daemon has many options you can specify - although there are many
+# and may seem daunting, it is recommended that you read the pppd man page
+# before enabling any of them
+#pppd_ppp0=(
+# "maxfail 0" # WARNING: It's not recommended you use this
+# # if you don't specify maxfail then we assume 0
+# "updetach" # If not set, "/etc/init.d/net.ppp0 start" will return
+# # immediately, without waiting the link to come up
+# # for the first time.
+# # Do not use it for dial-on-demand links!
+# "debug" # Enables syslog debugging
+# "noauth" # Do not require the peer to authenticate itself
+# "defaultroute" # Make this PPP interface the default route
+# "usepeerdns" # Use the DNS settings provided by PPP
+#
+# On demand options
+# "demand" # Enable dial on demand
+# "idle 30" # Link goes down after 30 seconds of inactivity
+# "10.112.112.112:10.112.112.113" # Phony IP addresses
+# "ipcp-accept-remote" # Accept the peers idea of remote address
+# "ipcp-accept-local" # Accept the peers idea of local address
+# "holdoff 3" # Wait 3 seconds after link dies before re-starting
+#
+# Dead peer detection
+# "lcp-echo-interval 15" # Send a LCP echo every 15 seconds
+# "lcp-echo-failure 3" # Make peer dead after 3 consective
+# # echo-requests
+#
+# Compression options - use these to completely disable compression
+# noaccomp noccp nobsdcomp nodeflate nopcomp novj novjccomp
+#
+# Dial-up settings
+# "lock" # Lock serial port
+# "115200" # Set the serial port baud rate
+# "modem crtscts" # Enable hardware flow control
+# "192.168.0.1:192.168.0.2" # Local and remote IP addresses
+#)
+#
+# Dial-up PPP users need to specify at least one telephone number
+#phone_number_ppp0=( "12345689" ) # Maximum 2 phone numbers are supported
+# They will also need a chat script - here's a good one
+#chat_ppp0=(
+# 'ABORT' 'BUSY'
+# 'ABORT' 'ERROR'
+# 'ABORT' 'NO ANSWER'
+# 'ABORT' 'NO CARRIER'
+# 'ABORT' 'NO DIALTONE'
+# 'ABORT' 'Invalid Login'
+# 'ABORT' 'Login incorrect'
+# 'TIMEOUT' '5'
+# '' 'ATZ'
+# 'OK' 'AT' # Put your modem initialization string here
+# 'OK' 'ATDT\T'
+# 'TIMEOUT' '60'
+# 'CONNECT' ''
+# 'TIMEOUT' '5'
+# '~--' ''
+#)
+
+# If the link require extra configuration - for example wireless or
+# RFC 268 bridge - we need to depend on the bridge so they get
+# configured correctly.
+#RC_NEED_ppp0="net.nas0"
+
+#WARNING: if MTU of the PPP interface is less than 1500 and you use this
+#machine as a router, you should add the following rule to your firewall
+#
+#iptables -I FORWARD 1 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
+
+#-----------------------------------------------------------------------------
+# ADSL
+# For ADSL support, emerge net-dialup/rp-pppoe
+# WARNING: This ADSL module is being deprecated in favour of the PPP module
+# above.
+# You should make the following settings and also put your
+# username/password information in /etc/ppp/pap-secrets
+
+# Configure the interface to use ADSL
+#config_eth0="adsl"
+
+# You probably won't need to edit /etc/ppp/pppoe.conf if you set this
+#adsl_user_eth0="my-adsl-username"
+
+#-----------------------------------------------------------------------------
+# ISDN
+# For ISDN support, emerge net-dialup/isdn4k-utils
+# You should make the following settings and also put your
+# username/password information in /etc/ppp/pap-secrets
+
+# Configure the interface to use ISDN
+#config_ippp0="dhcp"
+# It's important to specify dhcp if you need it!
+#config_ippp0="192.168.0.1/24"
+# Otherwise, you can use a static IP
+
+# NOTE: The interface name must be either ippp or isdn followed by a number
+
+# You may need this option to set the default route
+#ipppd_eth0="defaultroute"
+
+#-----------------------------------------------------------------------------
+# MAC changer
+# To set a specific MAC address
+#mac_eth0="00:11:22:33:44:55"
+
+# For changing MAC addresses using the below, emerge net-analyzer/macchanger
+# - to randomize the last 3 bytes only
+#mac_eth0="random-ending"
+# - to randomize between the same physical type of connection (e.g. fibre,
+# copper, wireless) , all vendors
+#mac_eth0="random-samekind"
+# - to randomize between any physical type of connection (e.g. fibre, copper,
+# wireless) , all vendors
+#mac_eth0="random-anykind"
+# - full randomization - WARNING: some MAC addresses generated by this may NOT
+# act as expected
+#mac_eth0="random-full"
+# custom - passes all parameters directly to net-analyzer/macchanger
+#mac_eth0="some custom set of parameters"
+
+# You can also set other options based on the MAC address of your network card
+# Handy if you use different docking stations with laptops
+#config_001122334455="dhcp"
+
+#-----------------------------------------------------------------------------
+# TUN/TAP
+# For TUN/TAP support emerge net-misc/openvpn or sys-apps/usermode-utilities
+#
+# You must specify if we're a tun or tap device. Then you can give it any
+# name you like - such as vpn
+#tuntap_vpn="tun"
+#config_vpn="192.168.0.1/24"
+
+# Or stick wit the generic names - like tap0
+#tuntap_tap0="tap"
+#config_tap0="192.168.0.1/24"
+
+# For passing custom options to tunctl use something like the following. This
+# example sets the owner to adm
+#tunctl_tun1="-u adm"
+# When using openvpn, there are no options
+
+#-----------------------------------------------------------------------------
+# Bridging (802.1d)
+# For bridging support emerge net-misc/bridge-utils
+
+# To add ports to bridge br0
+#bridge_br0="eth0 eth1"
+# or dynamically add them when the interface comes up
+#bridge_add_eth0="br0"
+#bridge_add_eth1="br0"
+
+# You need to configure the ports to null values so dhcp does not get started
+#config_eth0="null"
+#config_eth1="null"
+
+# Finally give the bridge an address - dhcp or a static IP
+#config_br0="dhcp" # may not work when adding ports dynamically
+#config_br0="192.168.0.1/24"
+
+# If any of the ports require extra configuration - for example wireless or
+# ppp devices - we need to depend on them like so.
+#RC_NEED_br0="net.eth0 net.eth1"
+
+# Below is an example of configuring the bridge
+# Consult "man brctl" for more details
+#brctl_br0="'setfd 0' 'sethello 0' 'stp off'"
+
+#-----------------------------------------------------------------------------
+# RFC 2684 Bridge Support
+# For RFC 2684 bridge support emerge net-misc/br2684ctl
+
+# Interface names have to be of the form nas0, nas1, nas2, etc.
+# You have to specify a VPI and VCI for the interface like so
+#br2684ctl_nas0="-a 0.38" # UK VPI and VCI
+
+# You may want to configure the encapsulation method as well by adding the -e
+# option to the command above (may need to be before the -a command)
+# -e 0 # LLC (default)
+# -e 1 # VC mux
+
+# Then you can configure the interface as normal
+#config_nas0="'192.168.0.1/24'"
+
+#-----------------------------------------------------------------------------
+# Tunnelling
+# WARNING: For tunnelling it is highly recommended that you
+# emerge sys-apps/iproute2
+#
+# For GRE tunnels
+#iptunnel_vpn0="mode gre remote 207.170.82.1 key 0xffffffff ttl 255"
+
+# For IPIP tunnels
+#iptunnel_vpn0="mode ipip remote 207.170.82.2 ttl 255"
+
+# To configure the interface
+#config_vpn0="'192.168.0.2 pointopoint 192.168.1.2'" # ifconfig style
+#config_vpn0="'192.168.0.2 peer 192.168.1.1'" # iproute2 style
+
+# 6to4 Tunnels allow IPv6 to work over IPv4 addresses, provided you
+# have a non-private address configured on an interface.
+# link_6to4="eth0" # Interface to base it's addresses on
+# config_6to4="ip6to4"
+# You may want to depend on eth0 like so
+#RC_NEED_6to4="net.eth0"
+# To ensure that eth0 is configured before 6to4. Of course, the tunnel could be
+# any name and this also works for any configured interface.
+# NOTE: If you're not using iproute2 then your 6to4 tunnel has to be called
+# sit0 - otherwise use a different name like 6to4 in the example above.
+
+# You can also specify a relay and suffix if you like.
+# The default relay is 192.88.99.1 and the defualt suffix is :1
+#relay_6to4="192.168.3.2"
+#suffix_6to4=":ff"
+
+
+#-----------------------------------------------------------------------------
+# System
+# For configuring system specifics such as domain, dns, ntp and nis servers
+# It's rare that you would need todo this, but you can anyway.
+# This is most benefit to wireless users who don't use DHCP so they can change
+# their configs based on SSID. See wireless.example for more details
+
+# To use dns settings such as these, dns_servers_eth0 must be set!
+# If you omit the _eth0 suffix, then it applies to all interfaces unless
+# overridden by the interface suffix.
+#dns_domain_eth0="your.domain"
+#dns_servers_eth0="192.168.0.2 192.168.0.3"
+#dns_search_eth0="this.domain that.domain"
+#dns_options_eth0="'timeout 1' rotate"
+#dns_sortlist_eth0="130.155.160.0/255.255.240.0 130.155.0.0"
+# See the man page for resolv.conf for details about the options and sortlist
+# directives
+
+#ntp_servers_eth0="192.168.0.2 192.168.0.3"
+
+#nis_domain_eth0="domain"
+#nis_servers_eth0="192.168.0.2 192.168.0.3"
+
+# NOTE: Setting any of these will stamp on the files in question. So if you
+# don't specify dns_servers but you do specify dns_domain then no nameservers
+# will be listed in /etc/resolv.conf even if there were any there to start
+# with.
+# If this is an issue for you then maybe you should look into a resolv.conf
+# manager like resolvconf-gentoo to manage this file for you. All packages
+# that baselayout supports use resolvconf-gentoo if installed.
+
+#-----------------------------------------------------------------------------
+# Cable in/out detection
+# Sometimes the cable is in, others it's out. Obviously you don't want to
+# restart net.eth0 every time when you plug it in either.
+#
+# netplug is a package that detects this and requires no extra configuration
+# on your part.
+# emerge sys-apps/netplug
+# or
+# emerge sys-apps/ifplugd
+# and you're done :)
+
+# By default we don't wait for netplug/ifplugd to configure the interface.
+# If you would like it to wait so that other services now that network is up
+# then you can specify a timeout here.
+#plug_timeout="10"
+# A value of 0 means wait forever.
+
+# If you don't want to use netplug on a specific interface but you have it
+# installed, you can disable it for that interface via the modules statement
+#modules_eth0="!netplugd"
+# You can do the same for ifplugd
+#
+# You can disable them both with the generic plug
+#modules_eth0="!plug"
+
+# To use specific ifplugd options, fex specifying wireless mode
+#ifplugd_eth0="--api-mode=wlan"
+# man ifplugd for more options
+
+##############################################################################
+# ADVANCED CONFIGURATION
+#
+# Four functions can be defined which will be called surrounding the
+# start/stop operations. The functions are called with the interface
+# name first so that one function can control multiple adapters. An extra two
+# functions can be defined when an interface fails to start or stop.
+#
+# The return values for the preup and predown functions should be 0
+# (success) to indicate that configuration or deconfiguration of the
+# interface can continue. If preup returns a non-zero value, then
+# interface configuration will be aborted. If predown returns a
+# non-zero value, then the interface will not be allowed to continue
+# deconfiguration.
+#
+# The return values for the postup, postdown, failup and faildown functions are
+# ignored since there's nothing to do if they indicate failure.
+#
+# ${IFACE} is set to the interface being brought up/down
+# ${IFVAR} is ${IFACE} converted to variable name bash allows
+
+#preup() {
+# # Test for link on the interface prior to bringing it up. This
+# # only works on some network adapters and requires the mii-diag
+# # package to be installed.
+# if mii-tool "${IFACE}" 2> /dev/null | grep -q 'no link'; then
+# ewarn "No link on ${IFACE}, aborting configuration"
+# return 1
+# fi
+#
+# # Test for link on the interface prior to bringing it up. This
+# # only works on some network adapters and requires the ethtool
+# # package to be installed.
+# if ethtool "${IFACE}" | grep -q 'Link detected: no'; then
+# ewarn "No link on ${IFACE}, aborting configuration"
+# return 1
+# fi
+#
+#
+# # Remember to return 0 on success
+# return 0
+#}
+
+#predown() {
+# # The default in the script is to test for NFS root and disallow
+# # downing interfaces in that case. Note that if you specify a
+# # predown() function you will override that logic. Here it is, in
+# # case you still want it...
+# if is_net_fs /; then
+# eerror "root filesystem is network mounted -- can't stop ${IFACE}"
+# return 1
+# fi
+#
+# # Remember to return 0 on success
+# return 0
+#}
+
+#postup() {
+# # This function could be used, for example, to register with a
+# # dynamic DNS service. Another possibility would be to
+# # send/receive mail once the interface is brought up.
+
+# # Here is an example that allows the use of iproute rules
+# # which have been configured using the rules_eth0 variable.
+# #rules_eth0=" \
+# # 'from 24.80.102.112/32 to 192.168.1.0/24 table localnet priority 100' \
+# # 'from 216.113.223.51/32 to 192.168.1.0/24 table localnet priority 100' \
+# #"
+# eval set -- $\rules_${IFVAR}
+# if [ -n "$@" ] ; then
+# einfo "Adding IP policy routing rules"
+# eindent
+# # Ensure that the kernel supports policy routing
+# if ! ip rule list | grep -q "^" ; then
+# eerror "You need to enable IP Policy Routing (CONFIG_IP_MULTIPLE_TABLES)"
+# eerror "in your kernel to use ip rules"
+# else
+# for x in "$@" ; do
+# ebegin "${x}"
+# ip rule add ${x} dev "${IFACE}"
+# eend $?
+# done
+# fi
+# eoutdent
+# # Flush the cache
+# ip route flush cache dev "${IFACE}"
+# fi
+
+#}
+
+#postdown() {
+# # Enable Wake-On-LAN for every interface except for lo
+# # Probably a good idea to set RC_DOWN_INTERFACE="no" in /etc/conf.d/rc
+# # as well ;)
+# [[ ${IFACE} != "lo" ]] && ethtool -s "${IFACE}" wol g
+
+# Automatically erase any ip rules created in the example postup above
+# if interface_exists "${IFACE}" ; then
+# # Remove any rules for this interface
+# local rule
+# ip rule list | grep " iif ${IFACE}[ ]*" | {
+# while read rule ; do
+# rule="${rule#*:}"
+# ip rule del ${rule}
+# done
+# }
+# # Flush the route cache
+# ip route flush cache dev "${IFACE}"
+# fi
+
+# # Return 0 always
+# return 0
+#}
+
+#failup() {
+# # This function is mostly here for completeness... I haven't
+# # thought of anything nifty to do with it yet ;-)
+#}
+
+#faildown() {
+# # This function is mostly here for completeness... I haven't
+# # thought of anything nifty to do with it yet ;-)
+#}
diff --git a/conf.d.Linux/rc b/conf.d.Linux/rc
new file mode 100644
index 00000000..bd41acf7
--- /dev/null
+++ b/conf.d.Linux/rc
@@ -0,0 +1,34 @@
+
+##############################################################################
+# LINUX SPECIFIC OPTIONS
+
+# This is the number of tty's used in most of the rc-scripts (like
+# consolefont, numlock, etc ...)
+RC_TTY_NUMBER=11
+
+# RC_DOWN_INTERFACE allows you to specify if RC will bring the interface
+# completely down when it stops. The default is yes, but there are some
+# instances where you may not want this to happen such as using Wake On LAN.
+RC_DOWN_INTERFACE="yes"
+
+# RC_DOWN_HARDDISK allows you to specify if RC will put harddisks to
+# standby mode when it stops.
+RC_DOWN_HARDDISK="yes"
+
+# Use this variable to control the /dev management behavior.
+# auto - let the scripts figure out what's best at boot
+# devfs - use devfs (requires sys-fs/devfsd)
+# udev - use udev (requires sys-fs/udev)
+# static - let the user manage /dev (YOU need to create ALL device nodes)
+RC_DEVICES="auto"
+
+# UDEV OPTION:
+# Set to "yes" if you want to save /dev to a tarball on shutdown
+# and restore it on startup. This is useful if you have a lot of
+# custom device nodes that udev does not handle/know about.
+RC_DEVICE_TARBALL="no"
+
+# RC_DMESG_LEVEL sets the level at which logging of messages is done to the
+# console. See dmesg(8) for more info.
+RC_DMESG_LEVEL="1"
+
diff --git a/conf.d.Linux/volumes b/conf.d.Linux/volumes
new file mode 100644
index 00000000..da70e9f6
--- /dev/null
+++ b/conf.d.Linux/volumes
@@ -0,0 +1,15 @@
+# IMPORTANT
+# volumes dependancy order is specified here so users can move it before
+# checkroot so that it can create the needed nodes in /dev.
+# By default it comes after modules in case the volume required modules
+# are not compiled into the kernel.
+
+#RC_BEFORE="checkroot"
+RC_NEED="checkroot"
+RC_USE="modules"
+
+# VOLUME_ORDER allows you to specify, or even remove the volume setup
+# for various volume managers (MD, EVMS2, LVM, DM, etc). Note that they are
+# stopped in reverse order.
+
+#VOLUME_ORDER="raid evms lvm dm"
diff --git a/conf.d.Linux/wireless.example b/conf.d.Linux/wireless.example
new file mode 100644
index 00000000..7b0edd68
--- /dev/null
+++ b/conf.d.Linux/wireless.example
@@ -0,0 +1,266 @@
+# /etc/conf.d/wireless:
+# Global wireless config file for net.* rc-scripts
+
+##############################################################################
+# IMPORTANT
+# linux-wlan-ng is not supported as they have their own configuration program
+# ensure that /etc/conf.d/net has the entry "!iwconfig" in it's modules line
+# Try and use an alternative driver if you need to use this - hostap-driver
+# supports non-usb linux-wlan-ng driven devices
+##############################################################################
+
+##############################################################################
+# HINTS
+##############################################################################
+# see net.example for using SSID in variable names
+#
+# Most users will just need to set the following options
+# key_SSID1="s:yourkeyhere enc open" # s: means a text key
+# key_SSID2="aaaa-bbbb-cccc-dd" # no s: means a hex key
+# preferred_aps="'SSID 1' 'SSID 2'"
+#
+# Clear? Good. Now configure your wireless network below
+#############################################################################
+
+##############################################################################
+# SETTINGS
+##############################################################################
+# Hard code an SSID to an interface - leave this unset if you wish the driver
+# to scan for available Access Points
+# Set to "any" to connect to any SSID - the driver picks an Access Point
+# This needs to be done when the driver doesn't support scanning
+# This may work for drivers that don't support scanning but you need automatic
+# AP association
+# I would only set this as a last resort really - use the preferred_aps
+# setting at the bottom of this file
+
+# However, using ad-hoc (without scanning for APs) and master mode
+# do require the SSID to be set - do this here
+#essid_eth0="any"
+
+# Set the mode of the interface (managed, ad-hoc, master or auto)
+# The default is auto
+# If it's ad-hoc or master you also may need to specify the channel below
+#mode_eth0="auto"
+
+# If managed mode fails, drop to ad-hoc mode with the below SSID?
+#adhoc_essid_eth0="WLAN"
+
+# Some drivers/hardware don't scan all that well. We have no control over this
+# but we can say how many scans we want to do to try and get a better sweep of
+# the area. The default is 1.
+#scans_eth0="1"
+
+#Channel can be set (1-14), but defaults to 3 if not set.
+#
+# The below is taken verbatim from the BSD wavelan documentation found at
+# http://www.netbsd.org/Documentation/network/wavelan.html
+# There are 14 channels possible; We are told that channels 1-11 are legal for
+# North America, channels 1-13 for most of Europe, channels 10-13 for France,
+# and only channel 14 for Japan. If in doubt, please refer to the documentation
+# that came with your card or access point. Make sure that the channel you
+# select is the same channel your access point (or the other card in an ad-hoc
+# network) is on. The default for cards sold in North America and most of Europe
+# is 3; the default for cards sold in France is 11, and the default for cards
+# sold in Japan is 14.
+#channel_eth0="3"
+
+# Setup any other config commands. This is basically the iwconfig argument
+# without the iwconfig $iface.
+#iwconfig_eth0=""
+
+# Set private driver ioctls. This is basically the iwpriv argument without
+# the iwpriv $iface. If you use the rt2500 driver (not the rt2x00 one) then
+# you can set WPA here, below is an example.
+#iwpriv_eth0=""
+#iwpriv_SSID=" \
+# 'set AuthMode=WPAPSK' \
+# 'set EncrypType=TKIP' \
+# 'set WPAPSK=yourpasskey' \
+#"
+#NOTE: Even though you can use WPA like so, you may have to set a WEP key
+#if your driver claims the AP is encrypted. The WEP key itself will not be
+#used though.
+
+# Seconds to wait before scanning
+# Some drivers need to wait until they have finished "loading"
+# before they can scan - otherwise they error and claim that they cannot scan
+# or resource is unavailable. The default is to wait zero seconds
+#sleep_scan_eth0="1"
+
+# Seconds to wait until associated. The default is to wait 10 seconds.
+# 0 means wait indefinitely. WARNING: this can cause an infinite delay when
+# booting.
+#associate_timeout_eth0="5"
+
+# By default a successful association in Managed mode sets the MAC
+# address of the AP connected to. However, some drivers (namely
+# the ipw2100) don't set an invalid MAC address when association
+# fails - so we need to check on link quality which some drivers
+# don't report properly either.
+# So if you have connection problems try flipping this setting
+# Valid options are MAC, quality and all - defaults to MAC
+#associate_test_eth0="MAC"
+
+# Some driver/card combinations need to scan in Ad-Hoc mode
+# After scanning, the mode is reset to the one defined above
+#scan_mode_eth0="Ad-Hoc"
+
+# Below you can define private ioctls to run before and after scanning
+# Format is the same as the iwpriv_eth0 above
+# This is needed for the HostAP drivers
+#iwpriv_scan_pre_eth0="'host_roaming 2'"
+#iwpriv_scan_post_eth0="'host_roaming 0'"
+
+# Define a WEP key per SSID or MAC address (of the AP, not your card)
+# The encryption type (open or restricted) must match the
+# encryption type on the Access Point
+# You can't use "any" for an SSID here
+#key_SSID="1234-1234-1234-1234-1234-1234-56"
+# or you can use strings. Passphrase IS NOT supported
+# To use a string, prefix it with s:
+# Note - this example also sets the encryption method to open
+# which is regarded as more secure than restricted
+#key_SSID="s:foobar enc open"
+#key_SSID="s:foobar enc restricted"
+
+# If you have whitespace in your key, here's how to set it and use other
+# commands like using open encryption.
+#key_SSID="s:'foo bar' enc open"
+
+# WEP key for the AP with MAC address 001122334455
+#mac_key_001122334455="s:foobar"
+
+# Here are some more examples of keys as some users find others work
+# and some don't where they should all do the same thing
+#key_SSID="open s:foobar"
+#key_SSID="open 1234-5678-9012"
+#key_SSID="s:foobar enc open"
+#key_SSID="1234-5678-9012 enc open"
+
+# You may want to set muliple keys - here's an example
+# It sets 4 keys on the card and instructs to use key 2 by default
+#key_SSID="[1] s:passkey1 key [2] s:passkey2 key [3] s:passkey3 key [4] s:passkey4 key [2]"
+
+# You can also override the interface settings found in /etc/conf.d/net
+# per SSID - which is very handy if you use different networks a lot
+#config_SSID="dhcp"
+#dhcpcd_SSID="-t 5"
+#routes_SSID=
+#fallback_SSID=
+
+# Setting name/domain server causes /etc/resolv.conf to be overwritten
+# Note that if DHCP is used, and you want this to take precedence then
+# please put -R in your dhcpcd options
+#dns_servers_SSID="192.168.0.1 192.168.0.2"
+#dns_domain_SSID="some.domain"
+#dns_search_path_SSID="search.this.domain search.that.domain"
+# Please check the man page for resolv.conf for more information
+# as domain and search (searchdomains) are mutually exclusive and
+# searchdomains takes precedence
+
+# You can also set any of the /etc/conf.d/net variables per MAC address
+# incase you use Access Points with the same SSID but need different
+# networking configs. Below is an example - of course you use the same
+# method with other variables
+#config_001122334455="dhcp"
+#dhcpcd_001122334455="-t 10"
+#dns_servers_001122334455="192.168.0.1 192.168.0.2"
+
+# Map a MAC address to an SSID
+# This is used when the Access Point is not broadcasting it's SSID
+# WARNING: This will override the SSID being broadcast due to some
+# Access Points sending an SSID even when they have been configured
+# not to!
+# Change 001122334455 to the MAC address and SSID to the SSID
+# it should map to
+#mac_essid_001122334455="SSID"
+
+# This lists the preferred SSIDs to connect to in order
+# SSID's can contain any characters here as they must match the broadcast
+# SSID exactly.
+# Surround each SSID with the " character and seperate them with a space
+# If the first SSID isn't found then it moves onto the next
+# If this isn't defined then it connects to the first one found
+#preferred_aps="'SSID 1' 'SSID 2'"
+
+# You can also define a preferred_aps list per interface
+#preferred_aps_eth0="'SSID 3' 'SSID 4'"
+
+# You can also say whether we only connect to preferred APs or not
+# Values are "any", "preferredonly", "forcepreferred", "forcepreferredonly" and "forceany"
+# "any" means it will connect to visible APs in the preferred list and then any
+# other available AP
+# "preferredonly" means it will only connect to visible APs in the preferred list
+# "forcepreferred" means it will forceably connect to APs in order if it does not find
+# them in a scan
+# "forcepreferredonly" means it forceably connects to the APs in order and does not bother
+# to scan
+# "forceany" does the same as forcepreferred + connects to any other available AP
+# Default is "any"
+#associate_order="any"
+#associate_order_eth0="any"
+
+# You can define blacklisted Access Points in the same way
+#blacklist_aps="'SSID 1' 'SSID 2'"
+#blacklist_aps_eth0="'SSID 3' 'SSID 4'"
+
+# If you have more than one wireless card, you can say if you want
+# to allow each card to associate with the same Access Point or not
+# Values are "yes" and "no"
+# Default is "yes"
+#unique_ap="yes"
+#unique_ap_eth0="yes"
+
+# IMPORTANT: preferred_only, blacklisted_aps and unique_ap only work when
+# essid_eth0 is not set and your card is capable of scanning
+
+# NOTE: preferred_aps list ignores blacklisted_aps - so if you have
+# the same SSID in both, well, you're a bit silly :p
+
+
+##############################################################################
+# ADVANCED CONFIGURATION
+#
+# Two functions can be defined which will be called surrounding the
+# associate function. The functions are called with the interface
+# name first so that one function can control multiple adapters.
+#
+# The return values for the preassociate function should be 0
+# (success) to indicate that configuration or deconfiguration of the
+# interface can continue. If preassociate returns a non-zero value, then
+# interface configuration will be aborted.
+#
+# The return value for the postassociate function is ignored
+# since there's nothing to do if it indicates failure.
+
+#preassociate() {
+# # The below adds two configuration variables leap_user_SSID
+# # and leap_pass_SSID. When they are both confiugred for the SSID
+# # being connected to then we run the CISCO LEAP script
+#
+# local user pass
+# eval user=\"\$\{leap_user_${SSIDVAR}\}\"
+# eval pass=\"\$\{leap_pass_${SSIDVAR}\}\"
+#
+# if [ -n "${user}" -a -n "${pass}" ]; then
+# if [ ! -x /opt/cisco/bin/leapscript ]; then
+# eend "For LEAP support, please emerge net-misc/cisco-aironet-client-utils"
+# return 1
+# fi
+# einfo "Waiting for LEAP Authentication on \"${SSID//\\\\//}\""
+# if /opt/cisco/bin/leapscript ${user} ${pass} | grep -q 'Login incorrect'; then
+# ewarn "Login Failed for ${user}"
+# return 1
+# fi
+# fi
+#
+# return 0
+#}
+
+#postassociate() {
+# # This function is mostly here for completeness... I haven't
+# # thought of anything nifty to do with it yet ;-)
+# # Return 0 always
+# return 0
+#}
diff --git a/conf.d/Makefile b/conf.d/Makefile
new file mode 100644
index 00000000..5f9f1411
--- /dev/null
+++ b/conf.d/Makefile
@@ -0,0 +1,6 @@
+DIR = /etc/conf.d
+FILES_NOEXIST = bootmisc checkfs clock env_whitelist hostname \
+ local.start local.stop net rc
+
+TOPDIR = ..
+include $(TOPDIR)/default.mk
diff --git a/conf.d/bootmisc b/conf.d/bootmisc
new file mode 100644
index 00000000..e33c03b3
--- /dev/null
+++ b/conf.d/bootmisc
@@ -0,0 +1,12 @@
+# /etc/conf.d/bootmisc
+
+# Put a nologin file in /etc to prevent people from logging in before
+# system startup is complete
+
+DELAYLOGIN="no"
+
+
+# Should we completely wipe out /tmp or just selectively remove known
+# locks / files / etc... ?
+
+WIPE_TMP="yes"
diff --git a/conf.d/checkfs b/conf.d/checkfs
new file mode 100644
index 00000000..868dfaba
--- /dev/null
+++ b/conf.d/checkfs
@@ -0,0 +1,8 @@
+# FSCK_SHUTDOWN causes checkfs to trigger during shutdown as well as startup.
+# The end result of this is that if any periodic non-root filesystem checks are
+# scheduled, under normal circumstances the actual check will happen during
+# shutdown rather than at next boot.
+# This is useful when periodic filesystem checks are causing undesirable
+# delays at startup, but such delays at shutdown are acceptable.
+
+FSCK_SHUTDOWN="no"
diff --git a/conf.d/clock b/conf.d/clock
new file mode 100644
index 00000000..f11df3fa
--- /dev/null
+++ b/conf.d/clock
@@ -0,0 +1,16 @@
+# /etc/conf.d/clock
+
+# Set CLOCK to "UTC" if your system clock is set to UTC (also known as
+# Greenwich Mean Time). If your clock is set to the local time, then
+# set CLOCK to "local". Note that if you dual boot with Windows, then
+# you should set it to "local".
+
+CLOCK="UTC"
+
+# Select the proper timezone. For valid values, peek inside of the
+# /usr/share/zoneinfo/ directory. For example, some common values are
+# "America/New_York" or "EST5EDT" or "Europe/Berlin". If you want to
+# manage /etc/localtime yourself, set this to "".
+
+#TIMEZONE="Factory"
+
diff --git a/conf.d/env_whitelist b/conf.d/env_whitelist
new file mode 100644
index 00000000..30a3695a
--- /dev/null
+++ b/conf.d/env_whitelist
@@ -0,0 +1,6 @@
+# /etc/conf.d/env_whitelist: Environment whitelist for rc-system
+
+# Specify which variables are allowed to be passed from the environment to the
+# rc-system. If it is not set by the environment, then the variable will be
+# taken from /etc/profile.env - meaning, if you need to set LANG or such,
+# do it in a /etc/env.d/99myownstuff file for example, and run env-update.
diff --git a/conf.d/hostname b/conf.d/hostname
new file mode 100644
index 00000000..619abcd3
--- /dev/null
+++ b/conf.d/hostname
@@ -0,0 +1,4 @@
+# /etc/conf.d/hostname
+
+# Set to the hostname of this machine
+HOSTNAME="localhost"
diff --git a/conf.d/local.start b/conf.d/local.start
new file mode 100644
index 00000000..7a20c142
--- /dev/null
+++ b/conf.d/local.start
@@ -0,0 +1,5 @@
+# /etc/conf.d/local.start
+
+# This is a good place to load any misc programs
+# on startup (use &>/dev/null to hide output)
+
diff --git a/conf.d/local.stop b/conf.d/local.stop
new file mode 100644
index 00000000..7dc89f63
--- /dev/null
+++ b/conf.d/local.stop
@@ -0,0 +1,8 @@
+# /etc/conf.d/local.stop
+
+# This is a good place to unload any misc.
+# programs you started above.
+# For example, if you are using OSS and have
+# "/usr/local/bin/soundon" above, put
+# "/usr/local/bin/soundoff" here.
+
diff --git a/conf.d/net b/conf.d/net
new file mode 100644
index 00000000..54337cf0
--- /dev/null
+++ b/conf.d/net
@@ -0,0 +1,4 @@
+# This blank configuration will automatically use DHCP for any net.*
+# scripts in /etc/init.d. To create a more complete configuration,
+# please review /etc/conf.d/net.example and save your configuration
+# in /etc/conf.d/net (this file :]!).
diff --git a/conf.d/rc b/conf.d/rc
new file mode 100644
index 00000000..25203f3e
--- /dev/null
+++ b/conf.d/rc
@@ -0,0 +1,87 @@
+# /etc/conf.d/rc: Global config file for the Gentoo RC System
+
+# Set to "yes" if you want the rc system to try and start services
+# in parallel for a slight speed improvement. NOTE: When enabled
+# init script output is buffered and displayed in one go when finished.
+RC_PARALLEL_STARTUP="no"
+
+# Set RC_INTERACTIVE to "yes" and you'll be able to press the I key during
+# boot so you can choose to start specific services. Set to "no" to disable
+# this feature.
+RC_INTERACTIVE="yes"
+
+# RC_VERBOSE will make init scripts more verbose and adds
+# "Service FOO starting/started/stopping/stopped" messages around each
+# init script.
+RC_VERBOSE="no"
+
+# RC_QUIET on the other hand will make init scripts quiet and produce no
+# output.
+RC_QUIET="no"
+
+
+# Do we allow any started service in the runlevel to satisfy the depedency
+# or do we want all of them regardless of state? For example, if net.eth0
+# and net.eth0 are in the default runlevel then with RC_STRICT_DEPEND="no"
+# both will be started, but services that depend on 'net' will work if either
+# one comes up. With RC_STRICT_DEPEND="yes" we would require them both to
+# come up.
+RC_STRICT_DEPEND="no"
+
+# Do we allow services to be hotplugged? If not, set to RC_HOTPLUG="no"
+# NOTE: This does not affect anything hotplug/udev/devd related, just the
+# starting/stopping of the init.d service triggered by it.
+RC_HOTPLUG="yes"
+
+# Dynamic /dev managers can trigger coldplug events which cause services to
+# start before we are ready for them. If this happens, we can defer these
+# services to start in the boot runlevel. Set RC_COLDPLUG="no" if you don't
+# want this.
+# NOTE: This also affects module coldplugging in udev-096 and higher
+# If you want module coldplugging but not coldplugging of services then you
+# can set RC_COLDPLUG="yes" and RC_PLUG_SERVICES="!*"
+RC_COLDPLUG="yes"
+
+# Some people want a finer grain over hotplug/coldplug. RC_PLUG_SERVICES is a
+# list of services that are matched in order, either allowing or not. By
+# default we allow services through as RC_COLDPLUG/RC_HOTPLUG has to be yes
+# anyway.
+# Example - RC_PLUG_SERVICES="net.wlan !net.*"
+# This allows net.wlan and any service not matching net.* to be plugged.
+RC_PLUG_SERVICES=""
+
+# Define network fstypes. Below is the default.
+#RC_NET_FS_LIST="afs cifs coda davfs fuse gfs ncpfs nfs nfs4 ocfs2 shfs smbfs"
+
+# RC_FORCE_AUTO tries its best to prevent user interaction during the boot and
+# shutdown process. For example, fsck will automatically be run or volumes
+# remounted to create proper directory trees. This feature can be dangerous
+# and is meant ONLY for headless machines where getting a physical console
+# hooked up is a huge pita.
+RC_FORCE_AUTO="no"
+
+
+##############################################################################
+# SERVICE CONFIGURATION VARIABLES
+# These variables are documented here, but should be configured in
+# /etc/conf.d/foo for service foo and NOT enabled here unless you
+# really want them to work on a global basis.
+
+# Some daemons are started and stopped via start-stop-daemon.
+# We can launch them through other daemons here, for example valgrind.
+# This is only useful for serious debugging of the daemon
+# WARNING: If the script's "stop" function does not supply a PID file then
+# all processes using the same daemon will be killed.
+#RC_DAEMON="/usr/bin/valgrind --tool=memcheck --log-file=/tmp/valgrind.syslog-ng"
+
+# strace needs to be prefixed with --background as it does not detach when
+# it's following
+#RC_DAEMON="--background /usr/sbin/strace -f -o /tmp/strace.syslog-ng"
+
+# Pass ulimit parameters
+#RC_ULIMIT="-u 30"
+
+# It's possible to define extra dependencies for services like so
+#RC_NEED="openvpn"
+#RC_USE="net.eth0"
+
diff --git a/default.mk b/default.mk
new file mode 100644
index 00000000..e65bad87
--- /dev/null
+++ b/default.mk
@@ -0,0 +1,54 @@
+# Common makefile settings
+# Copyright 2006-2007 Gentoo Foundation
+
+DESTDIR = /
+ROOT = /
+LIB = lib
+
+#
+# Recursive rules
+#
+
+SUBDIRS_ALL = $(patsubst %,%_all,$(SUBDIRS))
+SUBDIRS_CLEAN = $(patsubst %,%_clean,$(SUBDIRS))
+SUBDIRS_INSTALL = $(patsubst %,%_install,$(SUBDIRS))
+
+all:: $(SUBDIRS_ALL)
+clean:: $(SUBDIRS_CLEAN)
+install:: $(SUBDIRS_INSTALL)
+
+# Hmm ... possible to combine these three and not be ugly ?
+%_all:
+ $(MAKE) -C $(patsubst %_all,%,$@) all
+ if test -d $(patsubst %_all,%,$@).$(OS) ; then $(MAKE) -C $(patsubst %_all,%,$@).$(OS) all ; fi
+%_clean:
+ $(MAKE) -C $(patsubst %_clean,%,$@) clean
+ if test -d $(patsubst %_clean,%,$@).$(OS) ; then $(MAKE) -C $(patsubst %_clean,%,$@).$(OS) clean ; fi
+%_install:
+ $(MAKE) -C $(patsubst %_install,%,$@) install
+ if test -d $(patsubst %_install,%,$@).$(OS) ; then $(MAKE) -C $(patsubst %_install,%,$@).$(OS) install ; fi
+
+
+#
+# Install rules
+#
+
+INSTALL_DIR = install -m 0755 -d
+INSTALL_EXE = install -m 0755
+INSTALL_FILE = install -m 0644
+INSTALL_SECURE = install -m 0600
+
+install:: $(EXES) $(FILES) $(FILES_NOEXIST) $(MANS)
+ test -n $(DIR) && $(INSTALL_DIR) $(DESTDIR)$(DIR)
+ for x in $(EXES) ; do $(INSTALL_EXE) $$x $(DESTDIR)$(DIR) || exit $$? ; done
+ for x in $(FILES) ; do $(INSTALL_FILE) $$x $(DESTDIR)$(DIR) || exit $$? ; done
+ for x in $(FILES_APPEND) ; do if test -e $(DESTDIR)$(DIR)/$$x ; then cat $$x >> $(DESTDIR)$(DIR)/$$x || exit $$? ; else $(INSTALL_FILE) $$x $(DESTDIR)$(DIR) || exit $$? ; fi ; done
+ for x in $(FILES_NOEXIST) ; do if ! test -e $(DESTDIR)$(DIR)/$$x ; then $(INSTALL_FILE) $$x $(DESTDIR)$(DIR) || exit $$? ; fi ; done
+ for x in $(FILES_SECURE) ; do $(INSTALL_SECURE) $$x $(DESTDIR)$(DIR) || exit $$? ; done
+ for x in $(MANS) ; do \
+ ext=`echo $$x | sed -e 's/^.*\\.//'` ; \
+ $(INSTALL_DIR) $(DESTDIR)$(DIR)/man$$ext || exit $$? ; \
+ $(INSTALL_FILE) $$x $(DESTDIR)$(DIR)/man$$ext || exit $$? ; \
+ done
+
+.PHONY: all clean install
diff --git a/etc.BSD/COPYRIGHT b/etc.BSD/COPYRIGHT
new file mode 100644
index 00000000..378f62fc
--- /dev/null
+++ b/etc.BSD/COPYRIGHT
@@ -0,0 +1,2 @@
+Copyright 1996-2007 Gentoo Foundation
+Copyright 1992-2007 The FreeBSD Project
diff --git a/etc.BSD/Makefile b/etc.BSD/Makefile
new file mode 100644
index 00000000..b78ea8b4
--- /dev/null
+++ b/etc.BSD/Makefile
@@ -0,0 +1,5 @@
+DIR = /etc
+FILES = COPYRIGHT issue issue.logo login.conf rc rc.shutdown
+
+TOPDIR = ..
+include $(TOPDIR)/default.mk
diff --git a/etc.BSD/issue b/etc.BSD/issue
new file mode 100644
index 00000000..7a303dfb
--- /dev/null
+++ b/etc.BSD/issue
@@ -0,0 +1,3 @@
+
+This is %h (%s %m %r) %d
+
diff --git a/etc.BSD/issue.logo b/etc.BSD/issue.logo
new file mode 100644
index 00000000..81946e24
--- /dev/null
+++ b/etc.BSD/issue.logo
@@ -0,0 +1,13 @@
+ .
+ .vir. d$b
+ .d$$$$$$b. .cd$$b. .d$$b. d$$$$$$$$$$$b .d$$b. .d$$b.
+ $$$$( )$$$b d$$$()$$$. d$$$$$$$b Q$$$$$$$P$$$P.$$$$$$$b. .$$$$$$$b.
+ Q$$$$$$$$$$B$$$$$$$$P" d$$$PQ$$$$b. $$$$. .$$$P' `$$$ .$$$P' `$$$
+ "$$$$$$$P Q$$$$$$$b d$$$P Q$$$$b $$$$b $$$$b..d$$$ $$$$b..d$$$
+ d$$$$$$P" "$$$$$$$$ Q$$$ Q$$$$ $$$$$ `Q$$$$$$$P `Q$$$$$$$P
+ $$$$$$$P `""""" "" "" Q$$$P "Q$$$P" "Q$$$P"
+ `Q$$P" """
+
+
+This is %h (%s %m %r) %d
+
diff --git a/etc.BSD/login.conf b/etc.BSD/login.conf
new file mode 100644
index 00000000..e38f1703
--- /dev/null
+++ b/etc.BSD/login.conf
@@ -0,0 +1,65 @@
+# login.conf - login class capabilities database.
+#
+# Remember to rebuild the database after each change to this file:
+#
+# cap_mkdb /etc/login.conf
+#
+# This file controls resource limits, accounting limits and
+# default user environment settings.
+
+# defaults
+# These settings are used by login(1) by default for classless users
+# Note that entries like "cputime" set both "cputime-cur" and "cputime-max"
+
+default:\
+ :passwd_format=md5:\
+ :copyright=/etc/COPYRIGHT:\
+ :welcome=/etc/motd:\
+ :setenv=FTP_PASSIVE_MODE=YES:\
+ :path=/sbin /bin /usr/sbin /usr/bin /usr/local/sbin /usr/local/bin ~/bin:\
+ :nologin=/etc/nologin:\
+ :cputime=unlimited:\
+ :datasize=unlimited:\
+ :stacksize=unlimited:\
+ :memorylocked=unlimited:\
+ :memoryuse=unlimited:\
+ :filesize=unlimited:\
+ :coredumpsize=unlimited:\
+ :openfiles=unlimited:\
+ :maxproc=unlimited:\
+ :sbsize=unlimited:\
+ :vmemoryuse=unlimited:\
+ :priority=0:\
+ :ignoretime@:\
+ :umask=022:
+
+#
+# Root can always login
+#
+# N.B. login_getpwclass(3) will use this entry for the root account,
+# in preference to 'default'.
+root:\
+ :ignorenologin:\
+ :tc=default:
+
+#
+# A collection of common class names - forward them all to 'default'
+# (login would normally do this anyway, but having a class name
+# here suppresses the diagnostic)
+#
+standard:\
+ :tc=default:
+xuser:\
+ :tc=default:
+daemon:\
+ :tc=default:
+news:\
+ :tc=default:
+
+#
+# Russian Users Accounts. Setup proper environment variables.
+#
+#russian|Russian Users Accounts:\
+# :charset=KOI8-R:\
+# :lang=ru_RU.KOI8-R:\
+# :tc=default:
diff --git a/etc.BSD/rc b/etc.BSD/rc
new file mode 100644
index 00000000..64fb4df9
--- /dev/null
+++ b/etc.BSD/rc
@@ -0,0 +1,14 @@
+#!/bin/sh
+# Copyright 2006-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+# Ensure we are called by init
+[ "$PPID" = "1" ] || exit 0
+
+# BSD's init works somewhat differently to sysvinit.
+# This block should 'translate' from the way init calls it to the way it would
+# be called by sysvinit on linux.
+
+RUNLEVEL="1" /sbin/rc sysinit || exit 1
+RUNLEVEL="1" /sbin/rc boot || exit 1
+/sbin/rc default || exit 1
diff --git a/etc.BSD/rc.shutdown b/etc.BSD/rc.shutdown
new file mode 100644
index 00000000..737002d4
--- /dev/null
+++ b/etc.BSD/rc.shutdown
@@ -0,0 +1,17 @@
+#!/bin/sh
+# Copyright 2006-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+# Ensure we are called by init
+[ "$PPID" = "1" ] || exit 0
+
+# Try and use stuff in /lib over anywhere else so we can shutdown
+# local mounts correctly.
+LD_LIBRARY_PATH="/lib${LD_LIBRARY_PATH:+:}${LDLIBRARY_PATH}"
+export LD_LIBRARY_PATH
+
+# BSD's init works somewhat differently to sysvinit.
+# This block should 'translate' from the way init calls it to the way it would
+# be called by sysvinit on linux.
+export RUNLEVEL=S
+exec /sbin/rc "$1"
diff --git a/etc.Linux/Makefile b/etc.Linux/Makefile
new file mode 100644
index 00000000..8a14505b
--- /dev/null
+++ b/etc.Linux/Makefile
@@ -0,0 +1,7 @@
+SUBDIRS = modules.d modules.autoload.d
+DIR = /etc
+FILES = filesystems inputrc issue issue.logo
+FILES_NOEXIST = sysctl.conf
+
+TOPDIR = ..
+include $(TOPDIR)/default.mk
diff --git a/etc.Linux/filesystems b/etc.Linux/filesystems
new file mode 100644
index 00000000..0bb9c3c5
--- /dev/null
+++ b/etc.Linux/filesystems
@@ -0,0 +1,14 @@
+# /etc/filesystems
+#
+# This file defines the filesystems search order used by a
+# 'mount -t auto' command.
+#
+
+# Uncomment the following line if your modular kernel has vfat
+# support and you want mount to try vfat.
+#vfat
+
+# Keep the last '*' intact as it directs mount to use the
+# filesystems list available at /proc/filesystems also.
+# Don't remove it unless you REALLY know what you are doing!
+*
diff --git a/etc.Linux/inputrc b/etc.Linux/inputrc
new file mode 100644
index 00000000..8fe3ae15
--- /dev/null
+++ b/etc.Linux/inputrc
@@ -0,0 +1,67 @@
+# /etc/inputrc: initialization file for readline
+#
+# For more information on how this file works, please see the
+# INITIALIZATION FILE section of the readline(3) man page
+#
+# Quick dirty little note:
+# To get the key sequence for binding, you can abuse bash.
+# While running bash, hit CTRL+V, and then type the key sequence.
+# So, typing 'ALT + left arrow' in Konsole gets you back:
+# ^[[1;3D
+# The readline entry to make this skip back a word will then be:
+# "\e[1;3D" backward-word
+#
+
+# do not bell on tab-completion
+#set bell-style none
+
+set meta-flag on
+set input-meta on
+set convert-meta off
+set output-meta on
+
+# Completed names which are symbolic links to
+# directories have a slash appended.
+set mark-symlinked-directories on
+
+$if mode=emacs
+
+# for linux console and RH/Debian xterm
+"\e[1~": beginning-of-line
+"\e[4~": end-of-line
+#"\e[5~": beginning-of-history
+#"\e[6~": end-of-history
+"\e[5~": history-search-backward
+"\e[6~": history-search-forward
+"\e[3~": delete-char
+"\e[2~": quoted-insert
+
+# gnome-terminal (escape + arrow key)
+"\e[5C": forward-word
+"\e[5D": backward-word
+# konsole / xterm / rxvt (escape + arrow key)
+"\e\e[C": forward-word
+"\e\e[D": backward-word
+# konsole (alt + arrow key)
+"\e[1;3C": forward-word
+"\e[1;3D": backward-word
+# aterm / eterm (control + arrow key)
+"\eOc": forward-word
+"\eOd": backward-word
+
+$if term=rxvt
+"\e[8~": end-of-line
+$endif
+
+# for non RH/Debian xterm, can't hurt for RH/Debian xterm
+"\eOH": beginning-of-line
+"\eOF": end-of-line
+
+# for freebsd console
+"\e[H": beginning-of-line
+"\e[F": end-of-line
+$endif
+
+# fix Home and End for German users
+"\e[7~": beginning-of-line
+"\e[8~": end-of-line
diff --git a/etc.Linux/issue b/etc.Linux/issue
new file mode 100644
index 00000000..015e46d5
--- /dev/null
+++ b/etc.Linux/issue
@@ -0,0 +1,3 @@
+
+This is \n.\O (\s \m \r) \t
+
diff --git a/etc.Linux/issue.logo b/etc.Linux/issue.logo
new file mode 100644
index 00000000..d8e20efd
--- /dev/null
+++ b/etc.Linux/issue.logo
@@ -0,0 +1,13 @@
+ .
+ .vir. d$b
+ .d$$$$$$b. .cd$$b. .d$$b. d$$$$$$$$$$$b .d$$b. .d$$b.
+ $$$$( )$$$b d$$$()$$$. d$$$$$$$b Q$$$$$$$P$$$P.$$$$$$$b. .$$$$$$$b.
+ Q$$$$$$$$$$B$$$$$$$$P" d$$$PQ$$$$b. $$$$. .$$$P' `$$$ .$$$P' `$$$
+ "$$$$$$$P Q$$$$$$$b d$$$P Q$$$$b $$$$b $$$$b..d$$$ $$$$b..d$$$
+ d$$$$$$P" "$$$$$$$$ Q$$$ Q$$$$ $$$$$ `Q$$$$$$$P `Q$$$$$$$P
+ $$$$$$$P `""""" "" "" Q$$$P "Q$$$P" "Q$$$P"
+ `Q$$P" """
+
+
+This is \n.\O (\s \m \r) \t
+
diff --git a/etc.Linux/modules.autoload.d/Makefile b/etc.Linux/modules.autoload.d/Makefile
new file mode 100644
index 00000000..b940e73b
--- /dev/null
+++ b/etc.Linux/modules.autoload.d/Makefile
@@ -0,0 +1,5 @@
+DIR = /etc/modules.autoload.d
+FILES_NOEXIST = kernel-2.4 kernel-2.6
+
+TOPDIR = ../..
+include $(TOPDIR)/default.mk
diff --git a/etc.Linux/modules.autoload.d/kernel-2.4 b/etc.Linux/modules.autoload.d/kernel-2.4
new file mode 100644
index 00000000..56bd841b
--- /dev/null
+++ b/etc.Linux/modules.autoload.d/kernel-2.4
@@ -0,0 +1,11 @@
+# /etc/modules.autoload.d/kernel-2.4: kernel modules to load when system boots.
+#
+# Note that this file is for 2.4 kernels. If you need different modules
+# for a 2.6 kernel, you can create /etc/modules.autoload.d/kernel-2.6
+#
+# Add the names of modules that you'd like to load when the system
+# starts into this file, one per line. Comments begin with # and
+# are ignored. Read man modules.autoload for additional details.
+
+# For example:
+# aic7xxx
diff --git a/etc.Linux/modules.autoload.d/kernel-2.6 b/etc.Linux/modules.autoload.d/kernel-2.6
new file mode 100644
index 00000000..89edd3b9
--- /dev/null
+++ b/etc.Linux/modules.autoload.d/kernel-2.6
@@ -0,0 +1,10 @@
+# /etc/modules.autoload.d/kernel-2.6: kernel modules to load when system boots.
+#
+# Note that this file is for 2.6 kernels.
+#
+# Add the names of modules that you'd like to load when the system
+# starts into this file, one per line. Comments begin with # and
+# are ignored. Read man modules.autoload for additional details.
+
+# For example:
+# aic7xxx
diff --git a/etc.Linux/modules.d/Makefile b/etc.Linux/modules.d/Makefile
new file mode 100644
index 00000000..26c24963
--- /dev/null
+++ b/etc.Linux/modules.d/Makefile
@@ -0,0 +1,5 @@
+DIR = /etc/modules.d
+FILES_NOEXIST = aliases i386
+
+TOPDIR = ../..
+include $(TOPDIR)/default.mk
diff --git a/etc.Linux/modules.d/aliases b/etc.Linux/modules.d/aliases
new file mode 100644
index 00000000..52f30c9b
--- /dev/null
+++ b/etc.Linux/modules.d/aliases
@@ -0,0 +1,42 @@
+# Aliases to tell insmod/modprobe which modules to use
+
+# Uncomment the network protocols you don't want loaded:
+# alias net-pf-1 off # Unix
+# alias net-pf-2 off # IPv4
+# alias net-pf-3 off # Amateur Radio AX.25
+# alias net-pf-4 off # IPX
+# alias net-pf-5 off # DDP / appletalk
+# alias net-pf-6 off # Amateur Radio NET/ROM
+# alias net-pf-9 off # X.25
+# alias net-pf-10 off # IPv6
+# alias net-pf-11 off # ROSE / Amateur Radio X.25 PLP
+# alias net-pf-19 off # Acorn Econet
+
+alias char-major-10-175 agpgart
+alias char-major-10-200 tun
+alias char-major-81 bttv
+alias char-major-108 ppp_generic
+alias /dev/ppp ppp_generic
+alias tty-ldisc-3 ppp_async
+alias tty-ldisc-14 ppp_synctty
+alias ppp-compress-21 bsd_comp
+alias ppp-compress-24 ppp_deflate
+alias ppp-compress-26 ppp_deflate
+
+# Crypto modules (see http://www.kerneli.org/)
+alias loop-xfer-gen-0 loop_gen
+alias loop-xfer-3 loop_fish2
+alias loop-xfer-gen-10 loop_gen
+alias cipher-2 des
+alias cipher-3 fish2
+alias cipher-4 blowfish
+alias cipher-6 idea
+alias cipher-7 serp6f
+alias cipher-8 mars6
+alias cipher-11 rc62
+alias cipher-15 dfc2
+alias cipher-16 rijndael
+alias cipher-17 rc5
+
+# Support for i2c and lm_sensors
+alias char-major-89 i2c-dev
diff --git a/etc.Linux/modules.d/i386 b/etc.Linux/modules.d/i386
new file mode 100644
index 00000000..b89459f1
--- /dev/null
+++ b/etc.Linux/modules.d/i386
@@ -0,0 +1,4 @@
+alias parport_lowlevel parport_pc
+alias char-major-10-144 nvram
+alias binfmt-0064 binfmt_aout
+alias char-major-10-135 rtc
diff --git a/etc.Linux/sysctl.conf b/etc.Linux/sysctl.conf
new file mode 100644
index 00000000..b3a209e8
--- /dev/null
+++ b/etc.Linux/sysctl.conf
@@ -0,0 +1,54 @@
+# /etc/sysctl.conf
+#
+# For more information on how this file works, please see
+# the manpages sysctl(8) and sysctl.conf(5).
+#
+# In order for this file to work properly, you must first
+# enable 'Sysctl support' in the kernel.
+#
+# Look in /proc/sys/ for all the things you can setup.
+#
+
+# Disables packet forwarding
+#net.ipv4.ip_forward = 0
+# Disables IP dynaddr
+#net.ipv4.ip_dynaddr = 0
+# Disable ECN
+#net.ipv4.tcp_ecn = 0
+# Enables source route verification
+net.ipv4.conf.default.rp_filter = 1
+# Enable reverse path
+net.ipv4.conf.all.rp_filter = 1
+
+# Enable SYN cookies (yum!)
+# http://cr.yp.to/syncookies.html
+#net.ipv4.tcp_syncookies = 1
+
+# Disable source route
+#net.ipv4.conf.all.accept_source_route = 0
+#net.ipv4.conf.default.accept_source_route = 0
+
+# Disable redirects
+#net.ipv4.conf.all.accept_redirects = 0
+#net.ipv4.conf.default.accept_redirects = 0
+
+# Disable secure redirects
+#net.ipv4.conf.all.secure_redirects = 0
+#net.ipv4.conf.default.secure_redirects = 0
+
+# Ignore ICMP broadcasts
+#net.ipv4.icmp_echo_ignore_broadcasts = 1
+
+# Disables the magic-sysrq key
+#kernel.sysrq = 0
+# When the kernel panics, automatically reboot in 3 seconds
+#kernel.panic = 3
+# Allow for more PIDs (cool factor!); may break some programs
+#kernel.pid_max = 999999
+
+# You should compile nfsd into the kernel or add it
+# to modules.autoload for this to work properly
+# TCP Port for lock manager
+#fs.nfs.nlm_tcpport = 0
+# UDP Port for lock manager
+#fs.nfs.nlm_udpport = 0
diff --git a/etc/Makefile b/etc/Makefile
new file mode 100644
index 00000000..190239ec
--- /dev/null
+++ b/etc/Makefile
@@ -0,0 +1,7 @@
+SUBDIRS = env.d
+
+DIR = /etc
+FILES = hosts networks profile protocols rc.conf services shells
+
+TOPDIR = ..
+include $(TOPDIR)/default.mk
diff --git a/etc/env.d/00basic b/etc/env.d/00basic
new file mode 100644
index 00000000..d19d5401
--- /dev/null
+++ b/etc/env.d/00basic
@@ -0,0 +1,10 @@
+# /etc/env.d/00basic
+
+PATH="/opt/bin"
+ROOTPATH="/opt/bin"
+LDPATH="/usr/local/lib"
+MANPATH="/usr/local/share/man:/usr/share/man"
+INFOPATH="/usr/share/info"
+CVS_RSH="ssh"
+PAGER="/usr/bin/less"
+LESSOPEN="|lesspipe.sh %s"
diff --git a/etc/env.d/Makefile b/etc/env.d/Makefile
new file mode 100644
index 00000000..69a3150c
--- /dev/null
+++ b/etc/env.d/Makefile
@@ -0,0 +1,5 @@
+DIR = /etc/env.d
+FILES = 00basic
+
+TOPDIR = ../..
+include $(TOPDIR)/default.mk
diff --git a/etc/hosts b/etc/hosts
new file mode 100644
index 00000000..8a37ca53
--- /dev/null
+++ b/etc/hosts
@@ -0,0 +1,31 @@
+# /etc/hosts: Local Host Database
+#
+# This file describes a number of aliases-to-address mappings for the for
+# local hosts that share this file.
+#
+# In the presence of the domain name service or NIS, this file may not be
+# consulted at all; see /etc/host.conf for the resolution order.
+#
+
+# IPv4 and IPv6 localhost aliases
+127.0.0.1 localhost
+::1 localhost
+
+#
+# Imaginary network.
+#10.0.0.2 myname
+#10.0.0.3 myfriend
+#
+# According to RFC 1918, you can use the following IP networks for private
+# nets which will never be connected to the Internet:
+#
+# 10.0.0.0 - 10.255.255.255
+# 172.16.0.0 - 172.31.255.255
+# 192.168.0.0 - 192.168.255.255
+#
+# In case you want to be able to connect directly to the Internet (i.e. not
+# behind a NAT, ADSL router, etc...), you need real official assigned
+# numbers. Do not try to invent your own network numbers but instead get one
+# from your network provider (if any) or from your regional registry (ARIN,
+# APNIC, LACNIC, RIPE NCC, or AfriNIC.)
+#
diff --git a/etc/networks b/etc/networks
new file mode 100644
index 00000000..48327f00
--- /dev/null
+++ b/etc/networks
@@ -0,0 +1,8 @@
+# /etc/networks
+#
+# This file describes a number of netname-to-adress
+# mappings for the TCP/IP subsytem. It is mostly
+# used at boot time, when no name servers are running.
+#
+
+loopback 127.0.0.0
diff --git a/etc/profile b/etc/profile
new file mode 100644
index 00000000..27d6b4d1
--- /dev/null
+++ b/etc/profile
@@ -0,0 +1,67 @@
+# /etc/profile: login shell setup
+#
+# That this file is used by any Bourne-shell derivative to setup the
+# environment for login shells.
+#
+
+# Load environment settings from profile.env, which is created by
+# env-update from the files in /etc/env.d
+if [ -e /etc/profile.env ] ; then
+ . /etc/profile.env
+fi
+
+# 077 would be more secure, but 022 is generally quite realistic
+umask 022
+
+# Set up PATH depending on whether we're root or a normal user.
+# There's no real reason to exclude sbin paths from the normal user,
+# but it can make tab-completion easier when they aren't in the
+# user's PATH to pollute the executable namespace.
+#
+# It is intentional in the following line to use || instead of -o.
+# This way the evaluation can be short-circuited and calling whoami is
+# avoided.
+if [ "$EUID" = "0" ] || [ "$USER" = "root" ] ; then
+ PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:${ROOTPATH}"
+else
+ PATH="/usr/local/bin:/usr/bin:/bin:${PATH}"
+fi
+export PATH
+unset ROOTPATH
+
+# Extract the value of EDITOR
+[ -z "$EDITOR" ] && EDITOR="`. /etc/rc.conf 2>/dev/null; echo $EDITOR`"
+[ -z "$EDITOR" ] && EDITOR="/bin/nano"
+export EDITOR
+
+if [ -n "${BASH_VERSION}" ] ; then
+ # Newer bash ebuilds include /etc/bash/bashrc which will setup PS1
+ # including color. We leave out color here because not all
+ # terminals support it.
+ if [ -f /etc/bash/bashrc ] ; then
+ # Bash login shells run only /etc/profile
+ # Bash non-login shells run only /etc/bash/bashrc
+ # Since we want to run /etc/bash/bashrc regardless, we source it
+ # from here. It is unfortunate that there is no way to do
+ # this *after* the user's .bash_profile runs (without putting
+ # it in the user's dot-files), but it shouldn't make any
+ # difference.
+ . /etc/bash/bashrc
+ else
+ PS1='\u@\h \w \$ '
+ fi
+else
+ # Setup a bland default prompt. Since this prompt should be useable
+ # on color and non-color terminals, as well as shells that don't
+ # understand sequences such as \h, don't put anything special in it.
+ if type whoami >/dev/null 2>/dev/null && \
+ type cut >/dev/null 2>/dev/null && \
+ type uname >/dev/null 2>/dev/null ; then
+ PS1="`whoami`@`uname -n | cut -f1 -d.` \$ "
+ fi
+fi
+
+for sh in /etc/profile.d/*.sh ; do
+ [ -r "$sh" ] && . "$sh"
+done
+unset sh
diff --git a/etc/protocols b/etc/protocols
new file mode 100644
index 00000000..798a5c8e
--- /dev/null
+++ b/etc/protocols
@@ -0,0 +1,147 @@
+#
+# Internet protocols
+#
+# $FreeBSD: src/etc/protocols,v 1.20 2005/02/22 13:04:02 glebius Exp $
+# from: @(#)protocols 5.1 (Berkeley) 4/17/89
+#
+# See also http://www.iana.org/assignments/protocol-numbers
+#
+ip 0 IP # internet protocol, pseudo protocol number
+#hopopt 0 HOPOPT # hop-by-hop options for ipv6
+icmp 1 ICMP # internet control message protocol
+igmp 2 IGMP # internet group management protocol
+ggp 3 GGP # gateway-gateway protocol
+ipencap 4 IP-ENCAP # IP encapsulated in IP (officially ``IP'')
+st2 5 ST2 # ST2 datagram mode (RFC 1819)
+tcp 6 TCP # transmission control protocol
+cbt 7 CBT # CBT, Tony Ballardie <A.Ballardie@cs.ucl.ac.uk>
+egp 8 EGP # exterior gateway protocol
+igp 9 IGP # any private interior gateway (Cisco: for IGRP)
+bbn-rcc 10 BBN-RCC-MON # BBN RCC Monitoring
+nvp 11 NVP-II # Network Voice Protocol
+pup 12 PUP # PARC universal packet protocol
+argus 13 ARGUS # ARGUS
+emcon 14 EMCON # EMCON
+xnet 15 XNET # Cross Net Debugger
+chaos 16 CHAOS # Chaos
+udp 17 UDP # user datagram protocol
+mux 18 MUX # Multiplexing protocol
+dcn 19 DCN-MEAS # DCN Measurement Subsystems
+hmp 20 HMP # host monitoring protocol
+prm 21 PRM # packet radio measurement protocol
+xns-idp 22 XNS-IDP # Xerox NS IDP
+trunk-1 23 TRUNK-1 # Trunk-1
+trunk-2 24 TRUNK-2 # Trunk-2
+leaf-1 25 LEAF-1 # Leaf-1
+leaf-2 26 LEAF-2 # Leaf-2
+rdp 27 RDP # "reliable datagram" protocol
+irtp 28 IRTP # Internet Reliable Transaction Protocol
+iso-tp4 29 ISO-TP4 # ISO Transport Protocol Class 4
+netblt 30 NETBLT # Bulk Data Transfer Protocol
+mfe-nsp 31 MFE-NSP # MFE Network Services Protocol
+merit-inp 32 MERIT-INP # MERIT Internodal Protocol
+sep 33 SEP # Sequential Exchange Protocol
+3pc 34 3PC # Third Party Connect Protocol
+idpr 35 IDPR # Inter-Domain Policy Routing Protocol
+xtp 36 XTP # Xpress Tranfer Protocol
+ddp 37 DDP # Datagram Delivery Protocol
+idpr-cmtp 38 IDPR-CMTP # IDPR Control Message Transport Proto
+tp++ 39 TP++ # TP++ Transport Protocol
+il 40 IL # IL Transport Protocol
+ipv6 41 IPV6 # ipv6
+sdrp 42 SDRP # Source Demand Routing Protocol
+ipv6-route 43 IPV6-ROUTE # routing header for ipv6
+ipv6-frag 44 IPV6-FRAG # fragment header for ipv6
+idrp 45 IDRP # Inter-Domain Routing Protocol
+rsvp 46 RSVP # Resource ReSerVation Protocol
+gre 47 GRE # Generic Routing Encapsulation
+mhrp 48 MHRP # Mobile Host Routing Protocol
+bna 49 BNA # BNA
+esp 50 ESP # encapsulating security payload
+ah 51 AH # authentication header
+i-nlsp 52 I-NLSP # Integrated Net Layer Security TUBA
+swipe 53 SWIPE # IP with Encryption
+narp 54 NARP # NBMA Address Resolution Protocol
+mobile 55 MOBILE # IP Mobility
+tlsp 56 TLSP # Transport Layer Security Protocol
+skip 57 SKIP # SKIP
+ipv6-icmp 58 IPV6-ICMP icmp6 # ICMP for IPv6
+ipv6-nonxt 59 IPV6-NONXT # no next header for ipv6
+ipv6-opts 60 IPV6-OPTS # destination options for ipv6
+# 61 # any host internal protocol
+cftp 62 CFTP # CFTP
+# 63 # any local network
+sat-expak 64 SAT-EXPAK # SATNET and Backroom EXPAK
+kryptolan 65 KRYPTOLAN # Kryptolan
+rvd 66 RVD # MIT Remote Virtual Disk Protocol
+ippc 67 IPPC # Internet Pluribus Packet Core
+# 68 # any distributed filesystem
+sat-mon 69 SAT-MON # SATNET Monitoring
+visa 70 VISA # VISA Protocol
+ipcv 71 IPCV # Internet Packet Core Utility
+cpnx 72 CPNX # Computer Protocol Network Executive
+cphb 73 CPHB # Computer Protocol Heart Beat
+wsn 74 WSN # Wang Span Network
+pvp 75 PVP # Packet Video Protocol
+br-sat-mon 76 BR-SAT-MON # Backroom SATNET Monitoring
+sun-nd 77 SUN-ND # SUN ND PROTOCOL-Temporary
+wb-mon 78 WB-MON # WIDEBAND Monitoring
+wb-expak 79 WB-EXPAK # WIDEBAND EXPAK
+iso-ip 80 ISO-IP # ISO Internet Protocol
+vmtp 81 VMTP # Versatile Message Transport
+secure-vmtp 82 SECURE-VMTP # SECURE-VMTP
+vines 83 VINES # VINES
+ttp 84 TTP # TTP
+nsfnet-igp 85 NSFNET-IGP # NSFNET-IGP
+dgp 86 DGP # Dissimilar Gateway Protocol
+tcf 87 TCF # TCF
+eigrp 88 EIGRP # Enhanced Interior Routing Protocol (Cisco)
+ospf 89 OSPFIGP # Open Shortest Path First IGP
+sprite-rpc 90 Sprite-RPC # Sprite RPC Protocol
+larp 91 LARP # Locus Address Resolution Protocol
+mtp 92 MTP # Multicast Transport Protocol
+ax.25 93 AX.25 # AX.25 Frames
+ipip 94 IPIP # Yet Another IP encapsulation
+micp 95 MICP # Mobile Internetworking Control Pro.
+scc-sp 96 SCC-SP # Semaphore Communications Sec. Pro.
+etherip 97 ETHERIP # Ethernet-within-IP Encapsulation
+encap 98 ENCAP # Yet Another IP encapsulation
+# 99 # any private encryption scheme
+gmtp 100 GMTP # GMTP
+ifmp 101 IFMP # Ipsilon Flow Management Protocol
+pnni 102 PNNI # PNNI over IP
+pim 103 PIM # Protocol Independent Multicast
+aris 104 ARIS # ARIS
+scps 105 SCPS # SCPS
+qnx 106 QNX # QNX
+a/n 107 A/N # Active Networks
+ipcomp 108 IPComp # IP Payload Compression Protocol
+snp 109 SNP # Sitara Networks Protocol
+compaq-peer 110 Compaq-Peer # Compaq Peer Protocol
+ipx-in-ip 111 IPX-in-IP # IPX in IP
+carp 112 CARP vrrp # Common Address Redundancy Protocol
+pgm 113 PGM # PGM Reliable Transport Protocol
+# 114 # any 0-hop protocol
+l2tp 115 L2TP # Layer Two Tunneling Protocol
+ddx 116 DDX # D-II Data Exchange
+iatp 117 IATP # Interactive Agent Transfer Protocol
+st 118 ST # Schedule Transfer
+srp 119 SRP # SpectraLink Radio Protocol
+uti 120 UTI # UTI
+smp 121 SMP # Simple Message Protocol
+sm 122 SM # SM
+ptp 123 PTP # Performance Transparency Protocol
+isis 124 ISIS # ISIS over IPv4
+fire 125 FIRE
+crtp 126 CRTP # Combat Radio Transport Protocol
+crudp 127 CRUDP # Combat Radio User Datagram
+sscopmce 128 SSCOPMCE
+iplt 129 IPLT
+sps 130 SPS # Secure Packet Shield
+pipe 131 PIPE # Private IP Encapsulation within IP
+sctp 132 SCTP # Stream Control Transmission Protocol
+fc 133 FC # Fibre Channel
+# 134-254 # Unassigned
+pfsync 240 PFSYNC # PF Synchronization
+# 255 # Reserved
+divert 258 DIVERT # Divert pseudo-protocol [non IANA]
diff --git a/etc/rc.conf b/etc/rc.conf
new file mode 100644
index 00000000..482acddc
--- /dev/null
+++ b/etc/rc.conf
@@ -0,0 +1,37 @@
+# /etc/rc.conf: Global startup script configuration settings
+
+# UNICODE specifies whether you want to have UNICODE support in the console.
+# If you set to yes, please make sure to set a UNICODE aware CONSOLEFONT and
+# KEYMAP in the /etc/conf.d/consolefont and /etc/conf.d/keymaps config files.
+
+UNICODE="no"
+
+# Set EDITOR to your preferred editor.
+# You may use something other than what is listed here.
+
+EDITOR="/bin/nano"
+#EDITOR="/usr/bin/vim"
+#EDITOR="/usr/bin/emacs"
+
+# XSESSION is a new variable to control what window manager to start
+# default with X if run with xdm, startx or xinit. The default behavior
+# is to look in /etc/X11/Sessions/ and run the script in matching the
+# value that XSESSION is set to. The support scripts are smart enough to
+# look in all bin directories if it cant find a match in /etc/X11/Sessions/,
+# so setting it to "enlightenment" can also work. This is basically used
+# as a way for the system admin to configure a default system wide WM,
+# allthough it will work if the user export XSESSION in his .bash_profile, etc.
+#
+# NOTE: 1) this behaviour is overridden when a ~/.xinitrc exists, and startx
+# is called.
+# 2) even if ~/.xsession exists, if XSESSION can be resolved, it will
+# be executed rather than ~/.xsession, else KDM breaks ...
+#
+# Defaults depending on what you install currently include:
+#
+# Gnome - will start gnome-session
+# kde-<version> - will start startkde (look in /etc/X11/Sessions/)
+# Xsession - will start a terminal and a few other nice apps
+# Xfce4 - will start a XFCE4 session
+
+#XSESSION="Gnome"
diff --git a/etc/services b/etc/services
new file mode 100644
index 00000000..9552f589
--- /dev/null
+++ b/etc/services
@@ -0,0 +1,1178 @@
+# /etc/services
+#
+# Network services, Internet style
+#
+# Note that it is presently the policy of IANA to assign a single well-known
+# port number for both TCP and UDP; hence, most entries here have two entries
+# even if the protocol doesn't support UDP operations.
+#
+# Some References:
+# http://www.iana.org/assignments/port-numbers
+# http://www.freebsd.org/cgi/cvsweb.cgi/src/etc/services
+#
+# Each line describes one service, and is of the form:
+# service-name port/protocol [aliases ...] [# comment]
+#
+# See services(5) for more info.
+#
+
+#
+# IANA Assignments [Well Known Ports]
+# The Well Known Ports are assigned by the IANA and on most systems can
+# only be used by system (or root) processes or by programs executed by
+# privileged users.
+# The range for assigned ports managed by the IANA is 0-1023.
+#
+tcpmux 1/tcp # TCP port service multiplexer
+tcpmux 1/udp
+compressnet 2/tcp # Management Utility
+compressnet 2/udp
+compressnet 3/tcp # Compression Process
+compressnet 3/udp
+rje 5/tcp # Remote Job Entry
+rje 5/udp
+echo 7/tcp # Echo
+echo 7/udp
+discard 9/tcp sink null # Discard
+discard 9/udp sink null
+systat 11/tcp users # Active Users
+systat 11/udp users
+daytime 13/tcp # Daytime (RFC 867)
+daytime 13/udp
+#netstat 15/tcp # (was once asssigned, no more)
+qotd 17/tcp quote # Quote of the Day
+qotd 17/udp quote
+msp 18/tcp # Message Send Protocol
+msp 18/udp
+chargen 19/tcp ttytst source # Character Generator
+chargen 19/udp ttytst source
+ftp-data 20/tcp # File Transfer [Default Data]
+ftp-data 20/udp
+ftp 21/tcp # File Transfer [Control]
+ftp 21/udp fsp fspd
+ssh 22/tcp # SSH Remote Login Protocol
+ssh 22/udp
+telnet 23/tcp # Telnet
+telnet 23/udp
+# private 24/tcp # any private mail system
+# private 24/udp
+smtp 25/tcp mail # Simple Mail Transfer
+smtp 25/udp
+nsw-fe 27/tcp # NSW User System FE
+nsw-fe 27/udp
+msg-icp 29/tcp # MSG ICP
+msg-icp 29/udp
+msg-auth 31/tcp # MSG Authentication
+msg-auth 31/udp
+dsp 33/tcp # Display Support Protocol
+dsp 33/udp
+# private 35/tcp # any private printer server
+# private 35/udp
+time 37/tcp timserver
+time 37/udp timserver
+rap 38/tcp # Route Access Protocol
+rap 38/udp
+rlp 39/tcp resource # Resource Location Protocol
+rlp 39/udp resource
+graphics 41/tcp # Graphics
+graphics 41/udp
+nameserver 42/tcp name # Host Name Server
+nameserver 42/udp name
+nicname 43/tcp whois # Who Is
+nicname 43/udp whois
+mpm-flags 44/tcp # MPM FLAGS Protocol
+mpm-flags 44/udp
+mpm 45/tcp # Message Processing Module [recv]
+mpm 45/udp
+mpm-snd 46/tcp # MPM [default send]
+mpm-snd 46/udp
+ni-ftp 47/tcp # NI FTP
+ni-ftp 47/udp
+auditd 48/tcp # Digital Audit Daemon
+auditd 48/udp
+tacacs 49/tcp # Login Host Protocol (TACACS)
+tacacs 49/udp
+re-mail-ck 50/tcp # Remote Mail Checking Protocol
+re-mail-ck 50/udp
+domain 53/tcp # Domain Name Server
+domain 53/udp
+xns-ch 54/tcp # XNS Clearinghouse
+xns-ch 54/udp
+isi-gl 55/tcp # ISI Graphics Language
+isi-gl 55/udp
+xns-auth 56/tcp # XNS Authentication
+xns-auth 56/udp
+# private 57/tcp # any private terminal access
+# private 57/udp
+xns-mail 58/tcp # XNS Mail
+xns-mail 58/udp
+# private 59/tcp # any private file service
+# private 59/udp
+ni-mail 61/tcp # NI MAIL
+ni-mail 61/udp
+acas 62/tcp # ACA Services
+acas 62/udp
+whois++ 63/tcp # whois++
+whois++ 63/udp
+covia 64/tcp # Communications Integrator (CI)
+covia 64/udp
+tacacs-ds 65/tcp # TACACS-Database Service
+tacacs-ds 65/udp
+sql*net 66/tcp # Oracle SQL*NET
+sql*net 66/udp
+bootps 67/tcp # Bootstrap Protocol Server (BOOTP)
+bootps 67/udp
+bootpc 68/tcp # Bootstrap Protocol Client (BOOTP)
+bootpc 68/udp
+tftp 69/tcp # Trivial File Transfer
+tftp 69/udp
+gopher 70/tcp # Gopher
+gopher 70/udp
+netrjs-1 71/tcp # Remote Job Service
+netrjs-1 71/udp
+netrjs-2 72/tcp
+netrjs-2 72/udp
+netrjs-3 73/tcp
+netrjs-3 73/udp
+netrjs-4 74/tcp
+netrjs-4 74/udp
+# private 75/tcp # any private dial out service
+# private 75/udp
+deos 76/tcp # Distributed External Object Store
+deos 76/udp
+# private 77/tcp # any private RJE service
+# private 77/udp
+vettcp 78/tcp # vettcp
+vettcp 78/udp
+finger 79/tcp # Finger
+finger 79/udp
+http 80/tcp www www-http # World Wide Web HTTP
+http 80/udp www www-http
+hosts2-ns 81/tcp # HOSTS2 Name Server
+hosts2-ns 81/udp
+xfer 82/tcp # XFER Utility
+xfer 82/udp
+mit-ml-dev 83/tcp # MIT ML Device
+mit-ml-dev 83/udp
+ctf 84/tcp # Common Trace Facility
+ctf 84/udp
+mit-ml-dev 85/tcp # MIT ML Device
+mit-ml-dev 85/udp
+mfcobol 86/tcp # Micro Focus Cobol
+mfcobol 86/udp
+# private 87/tcp # any private terminal link
+# private 87/udp
+kerberos 88/tcp kerberos5 krb5 # Kerberos
+kerberos 88/udp kerberos5 krb5
+su-mit-tg 89/tcp # SU/MIT Telnet Gateway
+su-mit-tg 89/udp
+dnsix 90/tcp # DNSIX Securit Attribute Token Map
+dnsix 90/udp
+mit-dov 91/tcp # MIT Dover Spooler
+mit-dov 91/udp
+npp 92/tcp # Network Printing Protocol
+npp 92/udp
+dcp 93/tcp # Device Control Protocol
+dcp 93/udp
+objcall 94/tcp # Tivoli Object Dispatcher
+objcall 94/udp
+supdup 95/tcp # SUPDUP
+supdup 95/udp
+dixie 96/tcp # DIXIE Protocol Specification
+dixie 96/udp
+swift-rvf 97/tcp # Swift Remote Virtural File Protocol
+swift-rvf 97/udp
+tacnews 98/tcp linuxconf # TAC News
+tacnews 98/udp
+metagram 99/tcp # Metagram Relay
+metagram 99/udp
+#newacct 100/tcp # [unauthorized use]
+hostname 101/tcp hostnames # NIC Host Name Server
+hostname 101/udp hostnames
+iso-tsap 102/tcp tsap # ISO-TSAP Class 0
+iso-tsap 102/udp tsap
+gppitnp 103/tcp # Genesis Point-to-Point Trans Net
+gppitnp 103/udp
+acr-nema 104/tcp # ACR-NEMA Digital Imag. & Comm. 300
+acr-nema 104/udp
+cso 105/tcp csnet-ns cso-ns # CCSO name server protocol
+cso 105/udp csnet-ns cso-ns
+3com-tsmux 106/tcp poppassd # 3COM-TSMUX
+3com-tsmux 106/udp poppassd # Eudora: Unauthorized use by insecure poppassd protocol
+rtelnet 107/tcp # Remote Telnet Service
+rtelnet 107/udp
+snagas 108/tcp # SNA Gateway Access Server
+snagas 108/udp
+pop2 109/tcp pop-2 postoffice# Post Office Protocol - Version 2
+pop2 109/udp pop-2
+pop3 110/tcp pop-3 # Post Office Protocol - Version 3
+pop3 110/udp pop-3
+sunrpc 111/tcp portmapper rpcbind # SUN Remote Procedure Call
+sunrpc 111/udp portmapper rpcbind
+mcidas 112/tcp # McIDAS Data Transmission Protocol
+mcidas 112/udp
+auth 113/tcp authentication tap ident # Authentication Service
+auth 113/udp
+sftp 115/tcp # Simple File Transfer Protocol
+sftp 115/udp
+ansanotify 116/tcp # ANSA REX Notify
+ansanotify 116/udp
+uucp-path 117/tcp # UUCP Path Service
+uucp-path 117/udp
+sqlserv 118/tcp # SQL Services
+sqlserv 118/udp
+nntp 119/tcp readnews untp # Network News Transfer Protocol
+nntp 119/udp readnews untp
+cfdptkt 120/tcp # CFDPTKT
+cfdptkt 120/udp
+erpc 121/tcp # Encore Expedited Remote Pro.Call
+erpc 121/udp
+smakynet 122/tcp # SMAKYNET
+smakynet 122/udp
+ntp 123/tcp # Network Time Protocol
+ntp 123/udp
+ansatrader 124/tcp # ANSA REX Trader
+ansatrader 124/udp
+locus-map 125/tcp # Locus PC-Interface Net Map Ser
+locus-map 125/udp
+nxedit 126/tcp unitary # NXEdit
+nxedit 126/udp unitary # Unisys Unitary Login
+locus-con 127/tcp # Locus PC-Interface Conn Server
+locus-con 127/udp
+gss-xlicen 128/tcp # GSS X License Verification
+gss-xlicen 128/udp
+pwdgen 129/tcp # Password Generator Protocol
+pwdgen 129/udp
+cisco-fna 130/tcp # cisco FNATIVE
+cisco-fna 130/udp
+cisco-tna 131/tcp # cisco TNATIVE
+cisco-tna 131/udp
+cisco-sys 132/tcp # cisco SYSMAINT
+cisco-sys 132/udp
+statsrv 133/tcp # Statistics Service
+statsrv 133/udp
+ingres-net 134/tcp # INGRES-NET Service
+ingres-net 134/udp
+epmap 135/tcp loc-srv # DCE endpoint resolution
+epmap 135/udp loc-srv
+profile 136/tcp # PROFILE Naming System
+profile 136/udp
+netbios-ns 137/tcp # NETBIOS Name Service
+netbios-ns 137/udp
+netbios-dgm 138/tcp # NETBIOS Datagram Service
+netbios-dgm 138/udp
+netbios-ssn 139/tcp # NETBIOS Session Service
+netbios-ssn 139/udp
+emfis-data 140/tcp # EMFIS Data Service
+emfis-data 140/udp
+emfis-cntl 141/tcp # EMFIS Control Service
+emfis-cntl 141/udp
+imap 143/tcp imap2 # Internet Message Access Protocol
+imap 143/udp imap2
+uma 144/tcp # Universal Management Architecture
+uma 144/udp
+uaac 145/tcp # UAAC Protocol
+uaac 145/udp
+iso-tp0 146/tcp # ISO-TP0
+iso-tp0 146/udp
+iso-ip 147/tcp # ISO-IP
+iso-ip 147/udp
+jargon 148/tcp # Jargon
+jargon 148/udp
+aed-512 149/tcp # AED 512 Emulation Service
+aed-512 149/udp
+sql-net 150/tcp # SQL-NET
+sql-net 150/udp
+hems 151/tcp # HEMS
+hems 151/udp
+bftp 152/tcp # Background File Transfer Program
+bftp 152/udp
+sgmp 153/tcp # SGMP
+sgmp 153/udp
+netsc-prod 154/tcp # NETSC
+netsc-prod 154/udp
+netsc-dev 155/tcp
+netsc-dev 155/udp
+sqlsrv 156/tcp # SQL Service
+sqlsrv 156/udp
+knet-cmp 157/tcp # KNET/VM Command/Message Protocol
+knet-cmp 157/udp
+pcmail-srv 158/tcp # PCMail Server
+pcmail-srv 158/udp
+nss-routing 159/tcp # NSS-Routing
+nss-routing 159/udp
+sgmp-traps 160/tcp # SGMP-TRAPS
+sgmp-traps 160/udp
+snmp 161/tcp # Simple Net Mgmt Proto
+snmp 161/udp
+snmptrap 162/tcp snmp-trap # Traps for SNMP
+snmptrap 162/udp snmp-trap
+cmip-man 163/tcp # CMIP/TCP Manager
+cmip-man 163/udp
+cmip-agent 164/tcp # CMIP/TCP Agent
+cmip-agent 164/udp
+xns-courier 165/tcp # Xerox
+xns-courier 165/udp
+s-net 166/tcp # Sirius Systems
+s-net 166/udp
+namp 167/tcp # NAMP
+namp 167/udp
+rsvd 168/tcp # RSVD
+rsvd 168/udp
+send 169/tcp # SEND
+send 169/udp
+print-srv 170/tcp # Network PostScript
+print-srv 170/udp
+multiplex 171/tcp # Network Innovations Multiplex
+multiplex 171/udp
+cl/1 172/tcp # Network Innovations CL/1
+cl/1 172/udp
+xyplex-mux 173/tcp # Xyplex
+xyplex-mux 173/udp
+mailq 174/tcp # Mailer transport queue for Zmailer
+mailq 174/udp
+vmnet 175/tcp # VMNET
+vmnet 175/udp
+genrad-mux 176/tcp # GENRAD-MUX
+genrad-mux 176/udp
+xdmcp 177/tcp # X Display Manager Control Protocol
+xdmcp 177/udp
+nextstep 178/tcp NeXTStep NextStep# NextStep Window Server
+nextstep 178/udp NeXTStep NextStep
+bgp 179/tcp # Border Gateway Protocol
+bgp 179/udp
+ris 180/tcp # Intergraph
+ris 180/udp
+unify 181/tcp # Unify
+unify 181/udp
+audit 182/tcp # Unisys Audit SITP
+audit 182/udp
+ocbinder 183/tcp # OCBinder
+ocbinder 183/udp
+ocserver 184/tcp # OCServer
+ocserver 184/udp
+remote-kis 185/tcp # Remote-KIS
+remote-kis 185/udp
+kis 186/tcp # KIS Protocol
+kis 186/udp
+aci 187/tcp # Application Communication Interface
+aci 187/udp
+mumps 188/tcp # Plus Five's MUMPS
+mumps 188/udp
+qft 189/tcp # Queued File Transport
+qft 189/udp
+gacp 190/tcp # Gateway Access Control Protocol
+gacp 190/udp
+prospero 191/tcp # Prospero Directory Service
+prospero 191/udp
+osu-nms 192/tcp # OSU Network Monitoring System
+osu-nms 192/udp
+srmp 193/tcp # Spider Remote Monitoring Protocol
+srmp 193/udp
+irc 194/tcp # Internet Relay Chat Protocol
+irc 194/udp
+dn6-nlm-aud 195/tcp # DNSIX Network Level Module Audit
+dn6-nlm-aud 195/udp
+dn6-smm-red 196/tcp # DNSIX Session Mgt Module Audit Redir
+dn6-smm-red 196/udp
+dls 197/tcp # Directory Location Service
+dls 197/udp
+dls-mon 198/tcp # Directory Location Service Monitor
+dls-mon 198/udp
+smux 199/tcp # SNMP Unix Multiplexer
+smux 199/udp
+src 200/tcp # IBM System Resource Controller
+src 200/udp
+at-rtmp 201/tcp # AppleTalk Routing Maintenance
+at-rtmp 201/udp
+at-nbp 202/tcp # AppleTalk Name Binding
+at-nbp 202/udp
+at-echo 204/tcp # AppleTalk Echo
+at-echo 204/udp
+at-zis 206/tcp # AppleTalk Zone Information
+at-zis 206/udp
+qmtp 209/tcp # The Quick Mail Transfer Protocol
+qmtp 209/udp
+z39.50 210/tcp wais z3950 # ANSI Z39.50
+z39.50 210/udp wais z3950
+914c/g 211/tcp # Texas Instruments 914C/G Terminal
+914c/g 211/udp
+anet 212/tcp # ATEXSSTR
+anet 212/udp
+ipx 213/tcp # IPX
+ipx 213/udp
+imap3 220/tcp # Interactive Mail Access
+imap3 220/udp
+link 245/tcp # ttylink
+link 245/udp
+pawserv 345/tcp # Perf Analysis Workbench
+pawserv 345/udp
+zserv 346/tcp # Zebra server
+zserv 346/udp
+fatserv 347/tcp # Fatmen Server
+fatserv 347/udp
+scoi2odialog 360/tcp # scoi2odialog
+scoi2odialog 360/udp
+semantix 361/tcp # Semantix
+semantix 361/udp
+srssend 362/tcp # SRS Send
+srssend 362/udp
+rsvp_tunnel 363/tcp # RSVP Tunnel
+rsvp_tunnel 363/udp
+aurora-cmgr 364/tcp # Aurora CMGR
+aurora-cmgr 364/udp
+dtk 365/tcp # Deception Tool Kit
+dtk 365/udp
+odmr 366/tcp # ODMR
+odmr 366/udp
+rpc2portmap 369/tcp # Coda portmapper
+rpc2portmap 369/udp
+codaauth2 370/tcp # Coda authentication server
+codaauth2 370/udp
+clearcase 371/tcp # Clearcase
+clearcase 371/udp
+ulistproc 372/tcp ulistserv # UNIX Listserv
+ulistproc 372/udp ulistserv
+ldap 389/tcp # Lightweight Directory Access Protocol
+ldap 389/udp
+imsp 406/tcp # Interactive Mail Support Protocol
+imsp 406/udp
+svrloc 427/tcp # Server Location
+svrloc 427/udp
+mobileip-agent 434/tcp # MobileIP-Agent
+mobileip-agent 434/udp
+mobilip-mn 435/tcp # MobilIP-MN
+mobilip-mn 435/udp
+https 443/tcp # MCom
+https 443/udp
+snpp 444/tcp # Simple Network Paging Protocol
+snpp 444/udp
+microsoft-ds 445/tcp Microsoft-DS
+microsoft-ds 445/udp Microsoft-DS
+kpasswd 464/tcp kpwd # Kerberos "passwd"
+kpasswd 464/udp kpwd
+urd 465/tcp smtps ssmtp # URL Rendesvous Directory for SSM / smtp protocol over TLS/SSL
+igmpv3lite 465/udp smtps ssmtp # IGMP over UDP for SSM
+photuris 468/tcp
+photuris 468/udp
+rcp 469/tcp # Radio Control Protocol
+rcp 469/udp
+saft 487/tcp # Simple Asynchronous File Transfer
+saft 487/udp
+gss-http 488/tcp
+gss-http 488/udp
+pim-rp-disc 496/tcp
+pim-rp-disc 496/udp
+isakmp 500/tcp # IPsec - Internet Security Association and Key Management Protocol
+isakmp 500/udp
+exec 512/tcp # remote process execution
+comsat 512/udp biff # notify users of new mail received
+login 513/tcp # remote login a la telnet
+who 513/udp whod # who's logged in to machines
+shell 514/tcp cmd # no passwords used
+syslog 514/udp
+printer 515/tcp spooler # line printer spooler
+printer 515/udp spooler
+videotex 516/tcp
+videotex 516/udp
+talk 517/tcp # like tenex link
+talk 517/udp
+ntalk 518/tcp
+ntalk 518/udp
+utime 519/tcp unixtime
+utime 519/udp unixtime
+efs 520/tcp # extended file name server
+router 520/udp route routed # local routing process
+ripng 521/tcp
+ripng 521/udp
+ulp 522/tcp
+ulp 522/udp
+ibm-db2 523/tcp
+ibm-db2 523/udp
+ncp 524/tcp
+ncp 524/udp
+timed 525/tcp timeserver
+timed 525/udp timeserver
+tempo 526/tcp newdate
+tempo 526/udp newdate
+courier 530/tcp rpc
+courier 530/udp rpc
+conference 531/tcp chat
+conference 531/udp chat
+netnews 532/tcp readnews
+netnews 532/udp readnews
+netwall 533/tcp # -for emergency broadcasts
+netwall 533/udp
+mm-admin 534/tcp # MegaMedia Admin
+mm-admin 534/udp
+iiop 535/tcp
+iiop 535/udp
+opalis-rdv 536/tcp
+opalis-rdv 536/udp
+nmsp 537/tcp # Networked Media Streaming Protocol
+nmsp 537/udp
+gdomap 538/tcp # GNUstep distributed objects
+gdomap 538/udp
+uucp 540/tcp uucpd # uucp daemon
+uucp 540/udp uucpd
+klogin 543/tcp # Kerberized `rlogin' (v5)
+klogin 543/udp
+kshell 544/tcp krcmd # Kerberized `rsh' (v5)
+kshell 544/udp krcmd
+appleqtcsrvr 545/tcp
+appleqtcsrvr 545/udp
+dhcpv6-client 546/tcp # DHCPv6 Client
+dhcpv6-client 546/udp
+dhcpv6-server 547/tcp # DHCPv6 Server
+dhcpv6-server 547/udp
+afpovertcp 548/tcp # AFP over TCP
+afpovertcp 548/udp
+rtsp 554/tcp # Real Time Stream Control Protocol
+rtsp 554/udp
+dsf 555/tcp
+dsf 555/udp
+remotefs 556/tcp rfs_server rfs # Brunhoff remote filesystem
+remotefs 556/udp rfs_server rfs
+nntps 563/tcp snntp # NNTP over SSL
+nntps 563/udp snntp
+9pfs 564/tcp # plan 9 file service
+9pfs 564/udp
+whoami 565/tcp
+whoami 565/udp
+submission 587/tcp # mail message submission
+submission 587/udp
+http-alt 591/tcp # FileMaker, Inc. - HTTP Alternate
+http-alt 591/udp
+nqs 607/tcp # Network Queuing system
+nqs 607/udp
+npmp-local 610/tcp dqs313_qmaster # npmp-local / DQS
+npmp-local 610/udp dqs313_qmaster
+npmp-gui 611/tcp dqs313_execd # npmp-gui / DQS
+npmp-gui 611/udp dqs313_execd
+hmmp-ind 612/tcp dqs313_intercell# HMMP Indication / DQS
+hmmp-ind 612/udp dqs313_intercell
+cryptoadmin 624/tcp # Crypto Admin
+cryptoadmin 624/udp
+dec_dlm 625/tcp # DEC DLM
+dec_dlm 625/udp
+asia 626/tcp
+asia 626/udp
+passgo-tivoli 627/tcp # PassGo Tivoli
+passgo-tivoli 627/udp
+qmqp 628/tcp # Qmail QMQP
+qmqp 628/udp
+3com-amp3 629/tcp
+3com-amp3 629/udp
+rda 630/tcp
+rda 630/udp
+ipp 631/tcp # Internet Printing Protocol
+ipp 631/udp
+ldaps 636/tcp # LDAP over SSL
+ldaps 636/udp
+tinc 655/tcp # TINC control port
+tinc 655/udp
+acap 674/tcp # Application Configuration Access Protocol
+acap 674/udp
+asipregistry 687/tcp
+asipregistry 687/udp
+realm-rusd 688/tcp # ApplianceWare managment protocol
+realm-rusd 688/udp
+nmap 689/tcp # Opensource Network Mapper
+nmap 689/udp
+ha-cluster 694/tcp # Heartbeat HA-cluster
+ha-cluster 694/udp
+epp 700/tcp # Extensible Provisioning Protocol
+epp 700/udp
+iris-beep 702/tcp # IRIS over BEEP
+iris-beep 702/udp
+silc 706/tcp # SILC
+silc 706/udp
+kerberos-adm 749/tcp # Kerberos `kadmin' (v5)
+kerberos-adm 749/udp
+kerberos-iv 750/tcp kerberos4 kdc # Kerberos (server)
+kerberos-iv 750/udp kerberos4 kdc
+pump 751/tcp kerberos_master
+pump 751/udp kerberos_master # Kerberos authentication
+qrh 752/tcp passwd_server
+qrh 752/udp passwd_server # Kerberos passwd server
+rrh 753/tcp
+rrh 753/udp
+tell 754/tcp send krb_prop krb5_prop # Kerberos slave propagation
+tell 754/udp send
+nlogin 758/tcp
+nlogin 758/udp
+con 759/tcp
+con 759/udp
+ns 760/tcp krbupdate kreg # Kerberos registration
+ns 760/udp
+webster 765/tcp # Network dictionary
+webster 765/udp
+phonebook 767/tcp # Network phonebook
+phonebook 767/udp
+rsync 873/tcp # rsync
+rsync 873/udp
+ftps-data 989/tcp # ftp protocol, data, over TLS/SSL
+ftps-data 989/udp
+ftps 990/tcp # ftp protocol, control, over TLS/SSL
+ftps 990/udp
+nas 991/tcp # Netnews Administration System
+nas 991/udp
+telnets 992/tcp # telnet protocol over TLS/SSL
+telnets 992/udp
+imaps 993/tcp # imap4 protocol over TLS/SSL
+imaps 993/udp
+ircs 994/tcp # irc protocol over TLS/SSL
+ircs 994/udp
+pop3s 995/tcp # pop3 protocol over TLS/SSL
+pop3s 995/udp
+
+#
+# IANA Assignments [Registered Ports]
+#
+# The Registered Ports are listed by the IANA and on most systems can be
+# used by ordinary user processes or programs executed by ordinary
+# users.
+# Ports are used in the TCP [RFC793] to name the ends of logical
+# connections which carry long term conversations. For the purpose of
+# providing services to unknown callers, a service contact port is
+# defined. This list specifies the port used by the server process as
+# its contact port.
+# The IANA registers uses of these ports as a convenience to the
+# community.
+# To the extent possible, these same port assignments are used with the
+# UDP [RFC768].
+# The Registered Ports are in the range 1024-49151.
+#
+imgames 1077/tcp
+imgames 1077/udp
+socks 1080/tcp # socks proxy server
+socks 1080/udp
+rmiregistry 1099/tcp # Java RMI Registry
+rmiregistry 1099/udp
+bnetgame 1119/tcp # Battle.net Chat/Game Protocol
+bnetgame 1119/udp
+bnetfile 1120/tcp # Battle.net File Transfer Protocol
+bnetfile 1120/udp
+hpvmmcontrol 1124/tcp # HP VMM Control
+hpvmmcontrol 1124/udp
+hpvmmagent 1125/tcp # HP VMM Agent
+hpvmmagent 1125/udp
+hpvmmdata 1126/tcp # HP VMM Agent
+hpvmmdata 1126/udp
+resacommunity 1154/tcp # Community Service
+resacommunity 1154/udp
+3comnetman 1181/tcp # 3Com Net Management
+3comnetman 1181/udp
+mysql-cluster 1186/tcp # MySQL Cluster Manager
+mysql-cluster 1186/udp
+alias 1187/tcp # Alias Service
+alias 1187/udp
+openvpn 1194/tcp # OpenVPN
+openvpn 1194/udp
+kazaa 1214/tcp # KAZAA
+kazaa 1214/udp
+bvcontrol 1236/tcp rmtcfg # Gracilis Packeten remote config server
+bvcontrol 1236/udp rmtcfg
+nessus 1241/tcp # Nessus vulnerability assessment scanner
+nessus 1241/udp
+h323hostcallsc 1300/tcp # H323 Host Call Secure
+h323hostcallsc 1300/udp
+lotusnote 1352/tcp # Lotus Note
+lotusnote 1352/udp
+ms-sql-s 1433/tcp # Microsoft-SQL-Server
+ms-sql-s 1433/udp
+ms-sql-m 1434/tcp # Microsoft-SQL-Monitor
+ms-sql-m 1434/udp
+ica 1494/tcp # Citrix ICA Client
+ica 1494/udp
+wins 1512/tcp # Microsoft's Windows Internet Name Service
+wins 1512/udp
+ingreslock 1524/tcp
+ingreslock 1524/udp
+prospero-np 1525/tcp # Prospero non-privileged
+prospero-np 1525/udp
+datametrics 1645/tcp old-radius # datametrics / old radius entry
+datametrics 1645/udp old-radius
+sa-msg-port 1646/tcp old-radacct # sa-msg-port / old radacct entry
+sa-msg-port 1646/udp old-radacct
+rsap 1647/tcp
+rsap 1647/udp
+concurrent-lm 1648/tcp
+concurrent-lm 1648/udp
+kermit 1649/tcp
+kermit 1649/udp
+l2tp 1701/tcp
+l2tp 1701/udp
+h323gatedisc 1718/tcp
+h323gatedisc 1718/udp
+h323gatestat 1719/tcp
+h323gatestat 1719/udp
+h323hostcall 1720/tcp
+h323hostcall 1720/udp
+iberiagames 1726/tcp
+iberiagames 1726/udp
+gamegen1 1738/tcp
+gamegen1 1738/udp
+tftp-mcast 1758/tcp
+tftp-mcast 1758/udp
+hello 1789/tcp
+hello 1789/udp
+radius 1812/tcp # Radius
+radius 1812/udp
+radius-acct 1813/tcp radacct # Radius Accounting
+radius-acct 1813/udp radacct
+mtp 1911/tcp # Starlight Networks Multimedia Transport Protocol
+mtp 1911/udp
+egs 1926/tcp # Evolution Game Server
+egs 1926/udp
+unix-status 1957/tcp # remstats unix-status server
+unix-status 1957/udp
+hsrp 1985/tcp # Hot Standby Router Protocol
+hsrp 1985/udp
+licensedaemon 1986/tcp # cisco license management
+licensedaemon 1986/udp
+tr-rsrb-p1 1987/tcp # cisco RSRB Priority 1 port
+tr-rsrb-p1 1987/udp
+tr-rsrb-p2 1988/tcp # cisco RSRB Priority 2 port
+tr-rsrb-p2 1988/udp
+tr-rsrb-p3 1989/tcp # cisco RSRB Priority 3 port
+tr-rsrb-p3 1989/udp
+stun-p1 1990/tcp # cisco STUN Priority 1 port
+stun-p1 1990/udp
+stun-p2 1991/tcp # cisco STUN Priority 2 port
+stun-p2 1991/udp
+stun-p3 1992/tcp # cisco STUN Priority 3 port
+stun-p3 1992/udp
+snmp-tcp-port 1994/tcp # cisco SNMP TCP port
+snmp-tcp-port 1994/udp
+stun-port 1995/tcp # cisco serial tunnel port
+stun-port 1995/udp
+perf-port 1996/tcp # cisco Remote SRB port
+perf-port 1996/udp
+gdp-port 1997/tcp # cisco Gateway Discovery Protocol
+gdp-port 1997/udp
+x25-svc-port 1998/tcp # cisco X.25 service (XOT)
+x25-svc-port 1998/udp
+tcp-id-port 1999/tcp # cisco identification port
+tcp-id-port 1999/udp
+cisco-sccp 2000/tcp sieve # Cisco SCCP
+cisco-sccp 2000/udp sieve
+nfs 2049/tcp # Network File System
+nfs 2049/udp
+radsec 2083/tcp # Secure Radius Service
+radsec 2083/udp
+gnunet 2086/tcp # GNUnet
+gnunet 2086/udp
+rtcm-sc104 2101/tcp # RTCM SC-104
+rtcm-sc104 2101/udp
+zephyr-srv 2102/tcp # Zephyr server
+zephyr-srv 2102/udp
+zephyr-clt 2103/tcp # Zephyr serv-hm connection
+zephyr-clt 2103/udp
+zephyr-hm 2104/tcp # Zephyr hostmanager
+zephyr-hm 2104/udp
+eyetv 2170/tcp # EyeTV Server Port
+eyetv 2170/udp
+msfw-storage 2171/tcp # MS Firewall Storage
+msfw-storage 2171/udp
+msfw-s-storage 2172/tcp # MS Firewall SecureStorage
+msfw-s-storage 2172/udp
+msfw-replica 2173/tcp # MS Firewall Replication
+msfw-replica 2173/udp
+msfw-array 2174/tcp # MS Firewall Intra Array
+msfw-array 2174/udp
+airsync 2175/tcp # Microsoft Desktop AirSync Protocol
+airsync 2175/udp
+rapi 2176/tcp # Microsoft ActiveSync Remote API
+rapi 2176/udp
+qwave 2177/tcp # qWAVE Bandwidth Estimate
+qwave 2177/udp
+tivoconnect 2190/tcp # TiVoConnect Beacon
+tivoconnect 2190/udp
+tvbus 2191/tcp # TvBus Messaging
+tvbus 2191/udp
+mysql-im 2273/tcp # MySQL Instance Manager
+mysql-im 2273/udp
+dict-lookup 2289/tcp # Lookup dict server
+dict-lookup 2289/udp
+redstorm_join 2346/tcp # Game Connection Port
+redstorm_join 2346/udp
+redstorm_find 2347/tcp # Game Announcement and Location
+redstorm_find 2347/udp
+redstorm_info 2348/tcp # Information to query for game status
+redstorm_info 2348/udp
+cvspserver 2401/tcp # CVS client/server operations
+cvspserver 2401/udp
+venus 2430/tcp # codacon port
+venus 2430/udp
+venus-se 2431/tcp # tcp side effects
+venus-se 2431/udp
+codasrv 2432/tcp # not used
+codasrv 2432/udp
+codasrv-se 2433/tcp # tcp side effects
+codasrv-se 2433/udp
+netadmin 2450/tcp
+netadmin 2450/udp
+netchat 2451/tcp
+netchat 2451/udp
+snifferclient 2452/tcp
+snifferclient 2452/udp
+ppcontrol 2505/tcp # PowerPlay Control
+ppcontrol 2505/udp
+lstp 2559/tcp #
+lstp 2559/udp
+mon 2583/tcp
+mon 2583/udp
+hpstgmgr 2600/tcp zebrasrv
+hpstgmgr 2600/udp zebrasrv
+discp-client 2601/tcp zebra # discp client
+discp-client 2601/udp zebra
+discp-server 2602/tcp ripd # discp server
+discp-server 2602/udp ripd
+servicemeter 2603/tcp ripngd # Service Meter
+servicemeter 2603/udp ripngd
+nsc-ccs 2604/tcp ospfd # NSC CCS
+nsc-ccs 2604/udp ospfd
+nsc-posa 2605/tcp bgpd # NSC POSA
+nsc-posa 2605/udp bgpd
+netmon 2606/tcp ospf6d # Dell Netmon
+netmon 2606/udp ospf6d
+connection 2607/tcp # Dell Connection
+connection 2607/udp
+wag-service 2608/tcp # Wag Service
+wag-service 2608/udp
+dict 2628/tcp # Dictionary server
+dict 2628/udp
+exce 2769/tcp # eXcE
+exce 2769/udp
+dvr-esm 2804/tcp # March Networks Digital Video Recorders and Enterprise Service Manager products
+dvr-esm 2804/udp
+corbaloc 2809/tcp # CORBA LOC
+corbaloc 2809/udp
+ndtp 2882/tcp # Network Dictionary Transfer Protocol
+ndtp 2882/udp
+gamelobby 2914/tcp # Game Lobby
+gamelobby 2914/udp
+gds_db 3050/tcp # InterBase server
+gds_db 3050/udp
+xbox 3074/tcp # Xbox game port
+xbox 3074/udp
+icpv2 3130/tcp icp # Internet Cache Protocol (Squid)
+icpv2 3130/udp icp
+nm-game-admin 3148/tcp # NetMike Game Administrator
+nm-game-admin 3148/udp
+nm-game-server 3149/tcp # NetMike Game Server
+nm-game-server 3149/udp
+mysql 3306/tcp # MySQL
+mysql 3306/udp
+sftu 3326/tcp
+sftu 3326/udp
+trnsprntproxy 3346/tcp # Transparent Proxy
+trnsprntproxy 3346/udp
+ms-wbt-server 3389/tcp rdp # MS WBT Server
+ms-wbt-server 3389/udp rdp # Microsoft Remote Desktop Protocol
+prsvp 3455/tcp # RSVP Port
+prsvp 3455/udp
+nut 3493/tcp # Network UPS Tools
+nut 3493/udp
+ironstorm 3504/tcp # IronStorm game server
+ironstorm 3504/udp
+cctv-port 3559/tcp # CCTV control port
+cctv-port 3559/udp
+iw-mmogame 3596/tcp # Illusion Wireless MMOG
+iw-mmogame 3596/udp
+distcc 3632/tcp # Distributed Compiler
+distcc 3632/udp
+daap 3689/tcp # Digital Audio Access Protocol
+daap 3689/udp
+svn 3690/tcp # Subversion
+svn 3690/udp
+blizwow 3724/tcp # World of Warcraft
+blizwow 3724/udp
+netboot-pxe 3928/tcp pxe # PXE NetBoot Manager
+netboot-pxe 3928/udp pxe
+smauth-port 3929/tcp # AMS Port
+smauth-port 3929/udp
+treehopper 3959/tcp # Tree Hopper Networking
+treehopper 3959/udp
+cobraclient 3970/tcp # Cobra Client
+cobraclient 3970/udp
+cobraserver 3971/tcp # Cobra Server
+cobraserver 3971/udp
+pxc-spvr-ft 4002/tcp pxc-spvr-ft
+pxc-spvr-ft 4002/udp pxc-spvr-ft
+pxc-splr-ft 4003/tcp pxc-splr-ft rquotad
+pxc-splr-ft 4003/udp pxc-splr-ft rquotad
+pxc-roid 4004/tcp pxc-roid
+pxc-roid 4004/udp pxc-roid
+pxc-pin 4005/tcp pxc-pin
+pxc-pin 4005/udp pxc-pin
+pxc-spvr 4006/tcp pxc-spvr
+pxc-spvr 4006/udp pxc-spvr
+pxc-splr 4007/tcp pxc-splr
+pxc-splr 4007/udp pxc-splr
+xgrid 4111/tcp # Mac OS X Server Xgrid
+xgrid 4111/udp
+rwhois 4321/tcp # Remote Who Is
+rwhois 4321/udp
+epmd 4369/tcp # Erlang Port Mapper Daemon
+epmd 4369/udp
+krb524 4444/tcp
+krb524 4444/udp
+ipsec-nat-t 4500/tcp # IPsec NAT-Traversal
+ipsec-nat-t 4500/udp
+hylafax 4559/tcp # HylaFAX client-server protocol (new)
+hylafax 4559/udp
+piranha1 4600/tcp
+piranha1 4600/udp
+playsta2-app 4658/tcp # PlayStation2 App Port
+playsta2-app 4658/udp
+playsta2-lob 4659/tcp # PlayStation2 Lobby Port
+playsta2-lob 4659/udp
+snap 4752/tcp # Simple Network Audio Protocol
+snap 4752/udp
+radmin-port 4899/tcp # RAdmin Port
+radmin-port 4899/udp
+rfe 5002/tcp # Radio Free Ethernet
+rfe 5002/udp
+ita-agent 5051/tcp # ITA Agent
+ita-agent 5051/udp
+sdl-ets 5081/tcp # SDL - Ent Trans Server
+sdl-ets 5081/udp
+bzflag 5154/tcp # BZFlag game server
+bzflag 5154/udp
+aol 5190/tcp # America-Online
+aol 5190/udp
+xmpp-client 5222/tcp # XMPP Client Connection
+xmpp-client 5222/udp
+caevms 5251/tcp # CA eTrust VM Service
+caevms 5251/udp
+xmpp-server 5269/tcp # XMPP Server Connection
+xmpp-server 5269/udp
+cfengine 5308/tcp # CFengine
+cfengine 5308/udp
+nat-pmp 5351/tcp # NAT Port Mapping Protocol
+nat-pmp 5351/udp
+dns-llq 5352/tcp # DNS Long-Lived Queries
+dns-llq 5352/udp
+mdns 5353/tcp # Multicast DNS
+mdns 5353/udp
+mdnsresponder 5354/tcp noclog # Multicast DNS Responder IPC
+mdnsresponder 5354/udp noclog # noclogd with TCP (nocol)
+llmnr 5355/tcp hostmon # Link-Local Multicast Name Resolution
+llmnr 5355/udp hostmon # hostmon uses TCP (nocol)
+dj-ice 5419/tcp
+dj-ice 5419/udp
+beyond-remote 5424/tcp # Beyond Remote
+beyond-remote 5424/udp
+br-channel 5425/tcp # Beyond Remote Command Channel
+br-channel 5425/udp
+postgresql 5432/tcp # POSTGRES
+postgresql 5432/udp
+sgi-eventmond 5553/tcp # SGI Eventmond Port
+sgi-eventmond 5553/udp
+sgi-esphttp 5554/tcp # SGI ESP HTTP
+sgi-esphttp 5554/udp
+cvsup 5999/tcp # CVSup
+cvsup 5999/udp
+x11 6000/tcp # X Window System
+x11 6000/udp
+kftp-data 6620/tcp # Kerberos V5 FTP Data
+kftp-data 6620/udp
+kftp 6621/tcp # Kerberos V5 FTP Control
+kftp 6621/udp
+ktelnet 6623/tcp # Kerberos V5 Telnet
+ktelnet 6623/udp
+gnutella-svc 6346/tcp
+gnutella-svc 6346/udp
+gnutella-rtr 6347/tcp
+gnutella-rtr 6347/udp
+sane-port 6566/tcp # SANE Network Scanner Control Port
+sane-port 6566/udp
+parsec-game 6582/tcp # Parsec Gameserver
+parsec-game 6582/udp
+afs3-fileserver 7000/tcp bbs # file server itself
+afs3-fileserver 7000/udp bbs
+afs3-callback 7001/tcp # callbacks to cache managers
+afs3-callback 7001/udp
+afs3-prserver 7002/tcp # users & groups database
+afs3-prserver 7002/udp
+afs3-vlserver 7003/tcp # volume location database
+afs3-vlserver 7003/udp
+afs3-kaserver 7004/tcp # AFS/Kerberos authentication
+afs3-kaserver 7004/udp
+afs3-volser 7005/tcp # volume managment server
+afs3-volser 7005/udp
+afs3-errors 7006/tcp # error interpretation service
+afs3-errors 7006/udp
+afs3-bos 7007/tcp # basic overseer process
+afs3-bos 7007/udp
+afs3-update 7008/tcp # server-to-server updater
+afs3-update 7008/udp
+afs3-rmtsys 7009/tcp # remote cache manager service
+afs3-rmtsys 7009/udp
+font-service 7100/tcp xfs # X Font Service
+font-service 7100/udp xfs
+sncp 7560/tcp # Sniffer Command Protocol
+sncp 7560/udp
+soap-http 7627/tcp # SOAP Service Port
+soap-http 7627/udp
+http-alt 8008/tcp # HTTP Alternate
+http-alt 8008/udp
+http-alt 8080/tcp webcache # HTTP Alternate
+http-alt 8080/udp webcache # WWW caching service
+sunproxyadmin 8081/tcp tproxy # Sun Proxy Admin Service
+sunproxyadmin 8081/udp tproxy # Transparent Proxy
+pichat 9009/tcp # Pichat Server
+pichat 9009/udp
+bacula-dir 9101/tcp # Bacula Director
+bacula-dir 9101/udp
+bacula-fd 9102/tcp # Bacula File Daemon
+bacula-fd 9102/udp
+bacula-sd 9103/tcp # Bacula Storage Daemon
+bacula-sd 9103/udp
+dddp 9131/tcp # Dynamic Device Discovery
+dddp 9131/udp
+wap-wsp 9200/tcp # WAP connectionless session service
+wap-wsp 9200/udp
+wap-wsp-wtp 9201/tcp # WAP session service
+wap-wsp-wtp 9201/udp
+wap-wsp-s 9202/tcp # WAP secure connectionless session service
+wap-wsp-s 9202/udp
+wap-wsp-wtp-s 9203/tcp # WAP secure session service
+wap-wsp-wtp-s 9203/udp
+wap-vcard 9204/tcp # WAP vCard
+wap-vcard 9204/udp
+wap-vcal 9205/tcp # WAP vCal
+wap-vcal 9205/udp
+wap-vcard-s 9206/tcp # WAP vCard Secure
+wap-vcard-s 9206/udp
+wap-vcal-s 9207/tcp # WAP vCal Secure
+wap-vcal-s 9207/udp
+git 9418/tcp # git pack transfer service
+git 9418/udp
+cba8 9593/tcp # LANDesk Management Agent
+cba8 9593/udp
+davsrc 9800/tcp # WebDav Source Port
+davsrc 9800/udp
+sd 9876/tcp # Session Director
+sd 9876/udp
+cyborg-systems 9888/tcp # CYBORG Systems
+cyborg-systems 9888/udp
+monkeycom 9898/tcp # MonkeyCom
+monkeycom 9898/udp
+sctp-tunneling 9899/tcp # SCTP TUNNELING
+sctp-tunneling 9899/udp
+domaintime 9909/tcp # domaintime
+domaintime 9909/udp
+amanda 10080/tcp # amanda backup services
+amanda 10080/udp
+vce 11111/tcp # Viral Computing Environment (VCE)
+vce 11111/udp
+smsqp 11201/tcp # Alamin SMS gateway
+smsqp 11201/udp
+hkp 11371/tcp # OpenPGP HTTP Keyserver
+hkp 11371/udp
+h323callsigalt 11720/tcp # h323 Call Signal Alternate
+h323callsigalt 11720/udp
+rets-ssl 12109/tcp # RETS over SSL
+rets-ssl 12109/udp
+cawas 12168/tcp # CA Web Access Service
+cawas 12168/udp
+bprd 13720/tcp # BPRD Protocol (VERITAS NetBackup)
+bprd 13720/udp
+bpdbm 13721/tcp # BPDBM Protocol (VERITAS NetBackup)
+bpdbm 13721/udp
+bpjava-msvc 13722/tcp # BP Java MSVC Protocol
+bpjava-msvc 13722/udp
+vnetd 13724/tcp # Veritas Network Utility
+vnetd 13724/udp
+bpcd 13782/tcp # VERITAS NetBackup
+bpcd 13782/udp
+vopied 13783/tcp # VOPIED Protocol
+vopied 13783/udp
+xpilot 15345/tcp # XPilot Contact Port
+xpilot 15345/udp
+wnn6 22273/tcp # wnn6
+wnn6 22273/udp
+binkp 24554/tcp # Bink fidonet protocol
+binkp 24554/udp
+quake 26000/tcp # Quake @!#
+quake 26000/udp
+wnn6-ds 26208/tcp
+wnn6-ds 26208/udp
+tetrinet 31457/tcp # TetriNET Protocol
+tetrinet 31457/udp
+gamesmith-port 31765/tcp # GameSmith Port
+gamesmith-port 31765/udp
+traceroute 33434/tcp # traceroute use
+traceroute 33434/udp
+candp 42508/tcp # Computer Associates network discovery protocol
+candp 42508/udp
+candrp 42509/tcp # CA discovery response
+candrp 42509/udp
+caerpc 42510/tcp # CA eTrust RPC
+caerpc 42510/udp
+
+#=========================================================================
+# The remaining port numbers are not as allocated by IANA.
+
+# Kerberos (Project Athena/MIT) services
+# Note that these are for Kerberos v4, and are unofficial
+kpop 1109/tcp # Pop with Kerberos
+knetd 2053/tcp # Kerberos de-multiplexor
+eklogin 2105/tcp # Kerberos encrypted rlogin
+
+# CVSup support http://www.cvsup.org/
+supfilesrv 871/tcp # SUP server
+supfiledbg 1127/tcp # SUP debugging
+
+# Datagram Delivery Protocol services
+rtmp 1/ddp # Routing Table Maintenance Protocol
+nbp 2/ddp # Name Binding Protocol
+echo 4/ddp # AppleTalk Echo Protocol
+zip 6/ddp # Zone Information Protocol
+
+# Many services now accepted as 'standard'
+swat 901/tcp # Samba configuration tool
+rndc 953/tcp # rndc control sockets (BIND 9)
+rndc 953/udp
+skkserv 1178/tcp # SKK Japanese input method
+xtel 1313/tcp # french minitel
+support 1529/tcp # GNATS
+cfinger 2003/tcp lmtp # GNU Finger
+ninstall 2150/tcp # ninstall service
+ninstall 2150/udp
+afbackup 2988/tcp # Afbackup system
+afbackup 2988/udp
+fax 4557/tcp # FAX transmission service (old)
+rplay 5555/tcp # RPlay audio service
+rplay 5555/udp
+canna 5680/tcp # Canna (Japanese Input)
+x11-ssh 6010/tcp x11-ssh-offset
+x11-ssh 6010/udp x11-ssh-offset
+ircd 6667/tcp # Internet Relay Chat
+ircd 6667/udp
+jetdirect 9100/tcp # HP JetDirect card
+jetdirect 9100/udp
+mandelspawn 9359/udp mandelbrot # network mandelbrot
+kamanda 10081/tcp # amanda backup services (Kerberos)
+kamanda 10081/udp
+amandaidx 10082/tcp # amanda backup services
+amidxtape 10083/tcp # amanda backup services
+isdnlog 20011/tcp # isdn logging system
+isdnlog 20011/udp
+vboxd 20012/tcp # voice box system
+vboxd 20012/udp
+wnn4_Cn 22289/tcp wnn6_Cn # Wnn (Chinese input)
+wnn4_Kr 22305/tcp wnn6_Kr # Wnn (Korean input)
+wnn4_Tw 22321/tcp wnn6_Tw # Wnn (Taiwanse input)
+asp 27374/tcp # Address Search Protocol
+asp 27374/udp
+tfido 60177/tcp # Ifmail
+tfido 60177/udp
+fido 60179/tcp # Ifmail
+fido 60179/udp
+
+# Local services
+
diff --git a/etc/shells b/etc/shells
new file mode 100644
index 00000000..4f60dfa6
--- /dev/null
+++ b/etc/shells
@@ -0,0 +1,10 @@
+# /etc/shells: valid login shells
+/bin/bash
+/bin/csh
+/bin/esh
+/bin/fish
+/bin/ksh
+/bin/sash
+/bin/sh
+/bin/tcsh
+/bin/zsh
diff --git a/init.d.BSD/Makefile b/init.d.BSD/Makefile
new file mode 100644
index 00000000..0808c286
--- /dev/null
+++ b/init.d.BSD/Makefile
@@ -0,0 +1,5 @@
+DIR = /etc/init.d
+EXES = clock
+
+TOPDIR = ..
+include $(TOPDIR)/default.mk
diff --git a/init.d.BSD/clock b/init.d.BSD/clock
new file mode 100755
index 00000000..71d170ee
--- /dev/null
+++ b/init.d.BSD/clock
@@ -0,0 +1,41 @@
+#!/sbin/runscript
+# Copyright 1999-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+depend() {
+ # BSD adjkerntz needs to be able to write to /etc
+ if [ "${CLOCK}" = "UTC" -a -e /etc/wall_cmos_clock ] ||
+ [ "${CLOCK}" != "UTC" -a ! -e /etc/wall_cmos_clock ] ; then
+ need checkroot
+ fi
+}
+
+start() {
+ if [ "${TIMEZONE-Factory}" = "Factory" ] ; then
+ ewarn "Your TIMEZONE in /etc/conf.d/clock is still set to Factory!"
+ fi
+
+ local TBLURB="Local Time"
+ [ "${CLOCK}" = "UTC" ] && TBLURB="UTC"
+ ebegin "Starting the System Clock Adjuster [${TBLURB}]"
+ if [ "${CLOCK}" != "UTC" ] ; then
+ touch /etc/wall_cmos_clock
+ start-stop-daemon --start --exec /sbin/adjkerntz -- -i
+ else
+ rm -f /etc/wall_cmos_clock
+ /sbin/adjkerntz -i
+ fi
+ eend $?
+}
+
+stop() {
+ ebegin "Stopping the System Clock Adjuster"
+ if start-stop-daemon --test --quiet --stop --exec /sbin/adjkerntz ; then
+ start-stop-daemon --stop --exec /sbin/adjkerntz
+ eend $?
+ else
+ eend 0
+ fi
+}
+
+# vim: set ts=4 :
diff --git a/init.d.Linux/Makefile b/init.d.Linux/Makefile
new file mode 100644
index 00000000..286266d5
--- /dev/null
+++ b/init.d.Linux/Makefile
@@ -0,0 +1,5 @@
+DIR = /etc/init.d
+EXES = clock consolefont keymaps modules numlock volumes
+
+TOPDIR = ..
+include $(TOPDIR)/default.mk
diff --git a/init.d.Linux/clock b/init.d.Linux/clock
new file mode 100755
index 00000000..596b18d2
--- /dev/null
+++ b/init.d.Linux/clock
@@ -0,0 +1,131 @@
+#!/sbin/runscript
+# Copyright 1999-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+opts="save"
+
+depend() {
+ case "${CLOCK_ADJTIME}" in
+ "") before *;;
+ /etc/*) need checkroot;;
+ *) need localmount;;
+ esac
+}
+
+setupopts() {
+ case "${RC_SYS}" in
+ UML|VPS|XEN)
+ TBLURB="${RC_SYS}"
+ fakeit=1
+ ;;
+ *)
+ case "$(uname -m)" in
+ s390*)
+ TBLURB="s390"
+ fakeit=1
+ ;;
+ *)
+ if [ -e /proc/devices ] && grep -q " cobd$" /proc/devices ; then
+ TBLURB="coLinux"
+ fakeit=1
+ elif [ "${CLOCK}" = "UTC" ] ; then
+ myopts="--utc"
+ TBLURB="UTC"
+ else
+ myopts="--localtime"
+ TBLURB="Local Time"
+ fi
+ ;;
+ esac
+ ;;
+ esac
+ [ ${fakeit} -eq 1 ] && return 0
+
+ if [ -z "${CLOCK_ADJTIME}" -o ! -w /etc ] ; then
+ myadj="--noadjfile"
+ else
+ myadj="--adjust"
+ fi
+
+ [ "${SRM}" = "yes" ] && myopts="${myopts} --srm"
+ [ "${ARC}" = "arc" ] && myopts="${myopts} --arc"
+ myopts="${myopts} ${CLOCK_OPTS}"
+
+ # Make sure user isn't using rc.conf anymore.
+ if grep -q "^CLOCK=" /etc/rc.conf ; then
+ ewarn $"CLOCK should not be set in /etc/rc.conf but in /etc/conf.d/clock"
+ fi
+
+ # Make sure people set their timezone ... we do it here
+ # even though we don't actually use the variable so that
+ # people see the warning on boot.
+ if [ "${TIMEZONE-Factory}" = "Factory" ] ; then
+ ewarn "Your TIMEZONE in /etc/conf.d/clock is still set to Factory!"
+ fi
+}
+
+start() {
+ local myopts= myadj= TBLURB= fakeit=0 errstr="" retval=0
+
+ if [ -x /sbin/hwclock ] ; then
+ [ -w "${CLOCK_ADJTIME}" ] && echo "0.0 0 0.0" > "${CLOCK_ADJTIME}"
+ fi
+
+ setupopts
+
+ if [ ${fakeit} -ne 1 -a -e /proc/modules -a ! -e /dev/rtc ] ; then
+ modprobe rtc 2>/dev/null || modprobe genrtc 2>/dev/null
+ fi
+
+ ebegin "Setting system clock using the hardware clock" "[${TBLURB}]"
+ if [ ${fakeit} -eq 1 ] ; then
+ ret=0
+ elif [ -x /sbin/hwclock ] ; then
+ # Since hwclock always exit's with a 0, need to check its output.
+ errstr="$(/sbin/hwclock ${myadj} ${myopts} 2>&1 >/dev/null)"
+ errstr="${errstr}$(/sbin/hwclock --hctosys ${myopts} 2>&1 >/dev/null)"
+
+ if [ -n "${errstr}" ] ; then
+ ewarn "${errstr}"
+ ret=1
+ else
+ ret=0
+ fi
+ errstr="Failed to set clock"
+ else
+ ret=1
+ errstr="/sbin/hwclock not found"
+ fi
+ eend ${ret} "${errstr}" "You will need to set the clock yourself"
+
+ return 0
+}
+
+stop() {
+ # Don't tweak the hardware clock on LiveCD halt.
+ [ -n "${CDBOOT}" -o "${CLOCK_SYSTOHC}" != "yes" ] && return 0
+
+ local myopts= myadj= TBLURB= fakeit=0 errstr="" retval=0
+
+ setupopts
+
+ ebegin "Setting hardware clock using the system clock" "[${TBLURB}]"
+ if [ ${fakeit} -eq 1 ] ; then
+ ret=0
+ elif [ -x /sbin/hwclock ] ; then
+ [ -z "$(/sbin/hwclock --systohc ${myopts} 2>&1 >/dev/null)" ]
+ ret=$?
+ errstr="Failed to sync clocks"
+ else
+ ret=1
+ errstr="/sbin/hwclock not found"
+ fi
+ eend ${ret} "${errstr}"
+}
+
+save() {
+ CLOCK_SYSTOHC="yes"
+ stop
+}
+
+# vim: set ts=4 :
diff --git a/init.d.Linux/consolefont b/init.d.Linux/consolefont
new file mode 100755
index 00000000..5401a7b3
--- /dev/null
+++ b/init.d.Linux/consolefont
@@ -0,0 +1,87 @@
+#!/sbin/runscript
+# Copyright 1999-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+depend() {
+ need localmount
+ need keymaps # sets up terminal encoding scheme
+ after hotplug
+}
+
+start() {
+ # Forget about any font until we are successful
+ rm -rf "${RC_LIBDIR}"/console
+
+ case "${RC_SYS}" in
+ UML|VPS|XEN) return 0 ;;
+ esac
+
+ if [ -z "${CONSOLEFONT}" ] ; then
+ ebegin $"Using the default console font"
+ eend 0
+ return 0
+ fi
+
+ local x= param= sf_param= retval=1
+
+ # Get additional parameters
+ if [ -n "${CONSOLETRANSLATION}" ] ; then
+ param="${param} -m ${CONSOLETRANSLATION}"
+ fi
+ if [ -n "${UNICODEMAP}" ] ; then
+ param="${param} -u ${UNICODEMAP}"
+ fi
+
+ # Set the console font
+ local errmsg=
+ ebegin "Setting user font"
+ if [ -x /bin/setfont ] ; then
+ # We patched setfont to have --tty support ...
+ if [ -n "$(setfont --help 2>&1 | grep -e '--tty')" ] || \
+ [ -n "$(setfont --help 2>&1 | grep -e '-C')" ]
+ then
+ if [ -n "$(setfont --help 2>&1 | grep -e '--tty')" ] ; then
+ sf_param="--tty="
+ else
+ sf_param="-C "
+ fi
+ local ttydev=
+ [ -d /dev/vc ] \
+ && ttydev=/dev/vc/ \
+ || ttydev=/dev/tty
+
+ x=1
+ while [ ${x} -le "${RC_TTY_NUMBER}" ] ; do
+ /bin/setfont ${CONSOLEFONT} ${param} \
+ ${sf_param}/${ttydev}${x} > /dev/null
+ retval=$?
+ x=$((${x} + 1))
+ done
+ else
+ /bin/setfont ${CONSOLEFONT} ${param} > /dev/null
+ retval=$?
+ fi
+ errmsg="Failed to set user font"
+ else
+ retval=1
+ errmsg="/bin/setfont not found"
+ fi
+ eend ${retval} "${errmsg}"
+
+ # Store the last font so we can use it ASAP on boot
+ if [ ${retval} -eq 0 -a -w "${RC_LIBDIR}" ] ; then
+ mkdir -p "${RC_LIBDIR}"/console
+
+ # Pipe errors to null as maps may not be in use
+ /bin/setfont -o "${RC_LIBDIR}"/console/font 2>/dev/null \
+ || rm -f "${RC_LIBDIR}"/console/font
+ /bin/setfont -om "${RC_LIBDIR}"/console/map 2>/dev/null \
+ || rm -f "${RC_LIBDIR}"/console/map
+ /bin/setfont -ou "${RC_LIBDIR}"/console/unimap 2>/dev/null \
+ || rm -f "${RC_LIBDIR}"/console/unimap
+ fi
+
+ return ${retval}
+}
+
+# vim: set ts=4 :
diff --git a/init.d.Linux/keymaps b/init.d.Linux/keymaps
new file mode 100755
index 00000000..2118ffc9
--- /dev/null
+++ b/init.d.Linux/keymaps
@@ -0,0 +1,80 @@
+#!/sbin/runscript
+# Copyright 1999-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+depend() {
+ need localmount
+}
+
+checkconfig() {
+ if [ -z "${KEYMAP}" ] ; then
+ eerror "You need to setup KEYMAP in /etc/conf.d/keymaps first"
+ return 1
+ fi
+
+ # Make sure user isn't using rc.conf anymore
+ if grep -q "^KEYMAP=" /etc/rc.conf ; then
+ ewarn "KEYMAP should not be set in /etc/rc.conf but in /etc/conf.d/keymaps"
+ fi
+}
+
+start() {
+ case "${RC_SYS}" in
+ UML|VPS|XEN)
+ ebegin "Loading key mappings"
+ eend 0
+ return 0
+ ;;
+ esac
+
+ local WINDOWKEYS_KEYMAP=
+
+ checkconfig || return 1
+
+ # Force linux keycodes for PPC.
+ if [ -f /proc/sys/dev/mac_hid/keyboard_sends_linux_keycodes ] ; then
+ echo 1 > /proc/sys/dev/mac_hid/keyboard_sends_linux_keycodes
+ fi
+
+ # Turn on unicode if user wants it
+ [ "${UNICODE}" = "yes" ] && kbd_mode -u
+
+ ebegin "Loading key mappings"
+ if [ -x /bin/loadkeys ] ; then
+ [ "${SET_WINDOWKEYS}" = "yes" ] && WINDOWKEYS_KEYMAP="windowkeys"
+ loadkeys -q ${WINDOWKEYS_KEYMAP} ${KEYMAP} \
+ ${EXTENDED_KEYMAPS} > /dev/null
+ eend $? "Error loading key mappings"
+ else
+ eend 1 "/bin/loadkeys not found"
+ return 1
+ fi
+
+ # Set terminal encoding to either ASCII or UNICODE.
+ # See utf-8(7) for more information.
+ local termencoding= termmsg=
+ if [ "${UNICODE}" = "yes" ] ; then
+ local dumpkey_opts=
+ [ -n "${DUMPKEYS_CHARSET}" ] && dumpkey_opts="-c ${DUMPKEYS_CHARSET}"
+
+ dumpkeys ${dumpkey_opts} | loadkeys --unicode
+ termencoding="\033%%G"
+ termmsg="UTF-8"
+ else
+ termencoding="\033(K"
+ termmsg="ASCII"
+ fi
+ local n=1 ttydev=
+ [ -d /dev/vc ] \
+ && ttydev=/dev/vc/ \
+ || ttydev=/dev/tty
+ ebegin "Setting terminal encoding to" ${termmsg}
+ while [ ${n} -le "${RC_TTY_NUMBER}" ] ; do
+ printf "${termencoding}" >"${ttydev}${n}"
+ n=$((${n} + 1))
+ done
+ eend 0
+}
+
+
+# vim:ts=4
diff --git a/init.d.Linux/modules b/init.d.Linux/modules
new file mode 100755
index 00000000..ff6faf6a
--- /dev/null
+++ b/init.d.Linux/modules
@@ -0,0 +1,104 @@
+#!/sbin/runscript
+# Copyright 1999-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+depend() {
+ need checkroot
+ use isapnp
+}
+
+load_modules() {
+ local modules=""
+ local config="$1"
+
+ [ -z "${config}" -o ! -r "${config}" ] && return 0
+
+ modules=$(sed -e 's:#.*::' -e '/^[[:space:]]*$/d' "${config}")
+ [ -z "${modules}" ] && return 0
+
+ einfo "Using ${config} as config:"
+ eindent
+
+ local x= cnt=0 OIFS=${IFS} SIFS=${IFS-y}
+ IFS=\n
+ for x in ${modules} ; do
+ set -- ${x}
+ ebegin "Loading module $1"
+ modprobe -q "$@" >& /dev/null
+ eend $? "Failed to load $1" && cnt=$((${cnt} + 1))
+ done
+ if [ "${SIFS}" = "y" ] ; then
+ IFS=${save_IFS}
+ else
+ unset IFS
+ fi
+
+ einfo "Autoloaded ${cnt} module(s)"
+
+ return 0
+}
+
+start() {
+ # Should not fail if kernel do not have module
+ # support compiled in ...
+ [ ! -f /proc/modules -o "${RC_SYS}" = "VPS" ] && return 0
+
+ local KV=$(uname -r)
+ local KV_MAJOR=${KV%%.*}
+ local x=${KV#*.}
+ local KV_MINOR=${x%%.*}
+ x=${KV#*.*.}
+ local KV_MICRO=${x%%-*}
+
+ # Make sure depmod from modutils do not whine, but do not bother if
+ # we are on a 2.6 kernel without modprobe.old
+ if [ -z "${CDBOOT}" -a ! -e /etc/modules.conf ] && \
+ [ $(KV_to_int "${KV}") -lt $(KV_to_int '2.5.48') -o -x /sbin/modprobe.old ]
+ then
+ echo '### This file is automatically generated by modules-update' \
+ > /etc/modules.conf 2>/dev/null
+ [ ! -f /etc/modules.conf ] && \
+ ewarn "Cannot update /etc/modules.conf!"
+ fi
+
+ # Only do this if we have modules.conf or a 2.6 kernel
+ if [ -z "${CDBOOT}" ] && \
+ [ -f /etc/modules.conf -o $(KV_to_int "${KV}") -ge $(KV_to_int '2.5.48') ]
+ then
+ /sbin/modules-update
+ fi
+
+ local auto=""
+ if [ -f /etc/modules.autoload -a ! -L /etc/modules.autoload ]; then
+ auto=/etc/modules.autoload
+ else
+ local x= f="/etc/modules.autoload.d/kernel"
+ for x in "${KV}" ${KV_MAJOR}.${KV_MINOR}.${KV_MICRO} ${KV_MAJOR}.${KV_MINOR} ; do
+ if [ -f "${f}-${x}.${RC_SOFTLEVEL}" ] ; then
+ auto="${f}-${x}.${RC_SOFTLEVEL}"
+ break
+ fi
+ if [ "${RC_SOFTLEVEL}" = "${RC_BOOTLEVEL}" -a -f "${f}-${x}.${RC_DEFAULTLEVEL}" ] ; then
+ auto="${f}-${x}.${RC_DEFAULTLEVEL}"
+ break
+ fi
+ if [ -f "${f}-${x}" ] ; then
+ auto="${f}-${x}"
+ break
+ fi
+ done
+ fi
+ [ -n "${auto}" ] && load_modules "${auto}"
+
+ #
+ # Just in case a sysadmin prefers generic symbolic links in
+ # /lib/modules/boot for boot time modules we will load these modules
+ #
+ [ -n "$(modprobe -l -t boot)" ] && modprobe -a -t boot \* 2>/dev/null
+
+ # Above test clobbers the return
+ return 0
+}
+
+
+# vim:ts=4
diff --git a/init.d.Linux/numlock b/init.d.Linux/numlock
new file mode 100755
index 00000000..9597475a
--- /dev/null
+++ b/init.d.Linux/numlock
@@ -0,0 +1,35 @@
+#!/sbin/runscript
+# Copyright 1999-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+depend() {
+ need localmount
+}
+
+_setleds() {
+ [ -z "$1" ] && return 1
+
+ local dev=/dev/tty t= i=1 retval=0
+ [ -d /dev/vc ] && dev=/dev/vc/
+
+ while [ ${i} -le ${RC_TTY_NUMBER:-11} ] ; do
+ setleds -D "$1"num < ${dev}${i} || retval=1
+ i=$((${i} + 1))
+ done
+
+ return ${retval}
+}
+
+start() {
+ ebegin "Enabling numlock on ttys"
+ _setleds +
+ eend $? "Failed to enable numlock"
+}
+
+stop() {
+ ebegin "Disabling numlock on ttys"
+ _setleds -
+ eend $? "Failed to disable numlock"
+}
+
+# vim: set ts=4 :
diff --git a/init.d.Linux/volumes b/init.d.Linux/volumes
new file mode 100755
index 00000000..4f2a7f5e
--- /dev/null
+++ b/init.d.Linux/volumes
@@ -0,0 +1,42 @@
+#!/sbin/runscript
+# Copyright 1999-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+VOLUME_ORDER=${VOLUME_ORDER:-${RC_VOLUME_ORDER:-raid evms lvm dm}}
+
+# Dependancy information is in /etc/conf.d/volumes
+
+start() {
+ local x=
+
+ # Start our volumes, RAID, LVM, etc
+ for x in ${VOLUME_ORDER} ; do
+ start_addon "${x}"
+ done
+
+ # Setup dm-crypt mappings if any
+ start_addon dm-crypt
+
+ return 0
+}
+
+stop() {
+ local x= rev=
+
+ # Stop dm-crypt mappings if any
+ stop_addon dm-crypt
+ stop_addon truecrypt
+
+ # Stop our volumes, RAID, LVM, etc
+ for x in ${VOLUME_ORDER} ; do
+ rev="${x} ${rev}"
+ done
+
+ for x in ${rev} ; do
+ stop_addon "${x}"
+ done
+
+ return 0
+}
+
+# vim: set ts=4 :
diff --git a/init.d/Makefile b/init.d/Makefile
new file mode 100644
index 00000000..c86468ac
--- /dev/null
+++ b/init.d/Makefile
@@ -0,0 +1,6 @@
+DIR = /etc/init.d
+EXES = bootmisc checkfs checkroot hostname local localmount \
+ netmount rmnologin urandom halt.sh
+
+TOPDIR = ..
+include $(TOPDIR)/default.mk
diff --git a/init.d/bootmisc b/init.d/bootmisc
new file mode 100755
index 00000000..1428e874
--- /dev/null
+++ b/init.d/bootmisc
@@ -0,0 +1,138 @@
+#!/sbin/runscript
+# Copyright 1999-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+depend() {
+ use hostname
+ need localmount
+ before logger
+ after clock sysctl
+}
+
+start() {
+ # Put a nologin file in /etc to prevent people from logging
+ # in before system startup is complete.
+ if [ "${DELAYLOGIN}" = "yes" ] ; then
+ echo "System bootup in progress - please wait" \
+ > /etc/nologin
+ cp /etc/nologin /etc/nologin.boot
+ fi
+
+ if ! touch -c /var/run 2> /dev/null ; then
+ ewarn "Skipping /var and /tmp initialization (ro root?)"
+ return 0
+ fi
+
+ if [ "${RC_UNAME}" = "Linux" ] ; then
+ # Setup login records
+ > /var/run/utmp
+ touch /var/log/wtmp
+ chgrp utmp /var/run/utmp /var/log/wtmp
+ chmod 0664 /var/run/utmp /var/log/wtmp
+ fi
+
+ ebegin "Updating environment"
+ /sbin/env-update
+ eend $?
+
+ # Take care of random stuff [ /var/lock | /var/run | pam ]
+ ebegin "Cleaning" /var/lock, /var/run
+ rm -rf /var/run/console.lock /var/run/console/*
+
+ # Clean up any stale locks.
+ find /var/lock -type f -print0 | xargs -0 rm -f --
+
+ # Clean up /var/run and create /var/run/utmp so we can login.
+ for x in $(find /var/run ! -type d ! -name utmp ! -name innd.pid ! -name random-seed ! -name ld-elf.so.hints); do
+ [ ! -f "${x}" ] && continue
+ # Do not remove pidfiles of already running daemons
+ case "${x}" in
+ *.pid)
+ start-stop-daemon --test --quiet --stop --pidfile "${x}"
+ [ $? -eq 0 ] && continue
+ ;;
+ esac
+ rm -f "${x}"
+ done
+
+ # Reset pam_console permissions if we are actually using it
+ if [ -x /sbin/pam_console_apply -a ! -c /dev/.devfsd ] ; then
+ if [ -n $(grep -v -e '^[[:space:]]*#' /etc/pam.d/* | grep 'pam_console') ] ; then
+ /sbin/pam_console_apply -r
+ fi
+ fi
+
+ # Create the .keep to stop portage from removing /var/lock
+ > /var/lock/.keep
+ eend 0
+
+ # Clean up /tmp directory
+ if [ -d /tmp ] ; then
+ cd /tmp
+ if [ "${WIPE_TMP}" = "yes" ] ; then
+ ebegin "Wiping /tmp directory"
+ local startopts="-x . -depth"
+ [ "${RC_UNAME}" = "Linux" ] && startopts=". -xdev -depth"
+
+ # Faster than find
+ rm -rf [b-ikm-pr-zA-Z]*
+
+ find ${startopts} ! -name . \
+ ! -path ./lost+found \
+ ! -path "./lost+found/*" \
+ ! -path ./quota.user \
+ ! -path "./quota.user/*" \
+ ! -path ./aquota.user \
+ ! -path "./aquota.user/*" \
+ ! -path ./quota.group \
+ ! -path "./quota.group/*" \
+ ! -path ./aquota.group \
+ ! -path "./aquota.group/*" \
+ ! -path ./journal \
+ ! -path "./journal/*" \
+ -delete
+ eend 0
+ else
+ ebegin "Cleaning /tmp directory"
+ rm -rf /tmp/.X*-lock /tmp/esrv* /tmp/kio* /tmp/jpsock.* \
+ /tmp/.fam* /tmp/.esd* /tmp/orbit-* /tmp/ssh-* \
+ /tmp/ksocket-* /tmp/.*-unix
+ eend 0
+ fi
+
+ # Make sure our X11 stuff have the correct permissions
+ # Omit the chown as bootmisc is run before network is up
+ # and users may be using lame LDAP auth #139411
+ rm -rf /tmp/.ICE-unix /tmp/.X11-unix
+ mkdir -p /tmp/.ICE-unix /tmp/.X11-unix
+ chmod 1777 /tmp/.ICE-unix /tmp/.X11-unix
+ [ -x /sbin/restorecon ] && restorecon /tmp/.ICE-unix /tmp/.X11-unix
+ fi
+
+ # Create an 'after-boot' dmesg log
+ touch /var/log/dmesg
+ chmod 640 /var/log/dmesg
+ dmesg > /var/log/dmesg
+
+ # Check for /etc/resolv.conf, and create if missing
+ [ -f /etc/resolv.conf ] || touch /etc/resolv.conf 2>/dev/null
+}
+
+stop() {
+ # Reset pam_console permissions if we are actually using it
+ if [ -x /sbin/pam_console_apply -a ! -c /dev/.devfsd ] && \
+ [ -n $(grep -v -e '^[[:space:]]*#' /etc/pam.d/* | grep 'pam_console') ] ; then
+ /sbin/pam_console_apply -r
+ fi
+
+ # Write a halt record if we're shutting down
+ case "${SOFTLEVEL}" in
+ reboot|shutdown)
+ [ "${RC_UNAME}" = "Linux" ] && halt -w
+ ;;
+ esac
+
+ return 0
+}
+
+# vim: set ts=4 :
diff --git a/init.d/checkfs b/init.d/checkfs
new file mode 100755
index 00000000..2f9ead02
--- /dev/null
+++ b/init.d/checkfs
@@ -0,0 +1,77 @@
+#!/sbin/runscript
+# Copyright 1999-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+depend() {
+ need checkroot
+ use volumes
+ after modules
+}
+
+do_checkfs() {
+ local retval=0
+
+ ebegin "Checking all filesystems"
+ if [ "${RC_UNAME}" = "Linux" ] ; then
+ if get_bootparam "forcefsck" ; then
+ ewarn "A full fsck has been forced"
+ fsck -C0 -T -R -A -a -f
+ else
+ fsck -C0 -T -R -A -a
+ fi
+ retval=$?
+ else
+ local parts="$(fstabinfo --passno ">1")"
+ if [ -n "${parts}" ] ; then
+ fsck -p ${parts}
+ retval=$?
+ fi
+ fi
+ if [ ${retval} -eq 0 ] ; then
+ eend 0
+ elif [ ${retval} -eq 1 ] ; then
+ ewend 1 "Filesystem errors corrected."
+ retval=0
+ elif [ ${retval} -eq 2 ] ; then
+ ewend 1 "System should be rebooted"
+ elif [ ${retval} -eq 8 ] ; then
+ ewend 1 "Operational error, continuing"
+ retval=0
+ else
+ if [ "${RC_FORCE_AUTO}" = "yes" ] ; then
+ eend 2 "Fsck could not correct all errors, rerunning"
+ if [ "${RC_UNAME}" = "Linux" ] ; then
+ fsck -C0 -T -R -A -y
+ else
+ fsck -y
+ fi
+ retval=$?
+ eend $?
+ fi
+
+ if [ ${retval} -gt 3 ] ; then
+ eend 2 "Fsck could not correct all errors, manual repair needed"
+ if [ "${RC_SYS}" = "VPS" ] ; then
+ halt -f
+ elif [ -x /sbin/sulogin ] ; then
+ sulogin "${CONSOLE}"
+ else
+ return 1
+ fi
+ fi
+ fi
+
+ return ${retval}
+}
+
+start() {
+ do_checkfs
+}
+
+stop() {
+ # fsck on shutdown if we need to
+ [ "${FSCK_SHUTDOWN}" = "yes" -a ! -f /forcefsck ] && do_checkfs
+ return 0
+}
+
+# vim: set ts=4 :
diff --git a/init.d/checkroot b/init.d/checkroot
new file mode 100755
index 00000000..c7fb66d3
--- /dev/null
+++ b/init.d/checkroot
@@ -0,0 +1,149 @@
+#!/sbin/runscript
+# Copyright 1999-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+do_mtab() {
+ # Don't create mtab if /etc is readonly
+ if ! touch /etc/mtab 2> /dev/null ; then
+ ewarn "Skipping /etc/mtab initialization" "(ro root?)"
+ return 0
+ fi
+
+ # Clear the existing mtab
+ > /etc/mtab
+
+ # Add the entry for / to mtab
+ mount -f /
+
+ # Don't list root more than once
+ grep -v "^[^ ]* / " /proc/mounts >> /etc/mtab
+
+ # Now make sure /etc/mtab have additional info (gid, etc) in there
+ local mnt= mnts="$(mountinfo | sed -e "s/^/'/g" -e "s/$/'/g")"
+ eval set -- ${mnts}
+ for mnt in "$@" ; do
+ if fstabinfo --mount-cmd "${mnt}" >/dev/null ; then
+ mount -f -o remount "${mnt}"
+ fi
+ done
+
+ # Remove stale backups
+ rm -f /etc/mtab~ /etc/mtab~~
+}
+
+start() {
+ local retval=0
+
+ # Don't bother doing a fsck on these
+ if [ -n "${CDBOOT}" ] || is_net_fs / || is_union_fs / ; then
+ return 0
+ fi
+
+ if touch /.test.$$ 2> /dev/null ; then
+ einfo "root filesystem is mounted read-write - skipping"
+ rm -f /.test.$$
+ return 0
+ fi
+
+ if get_bootparam "forcefsck" ; then
+ ebegin "Checking root filesystem (full fsck forced)"
+ if [ "${RC_UNAME}" = "Linux" ] ; then
+ fsck -C -a -f /
+ else
+ fsck -F /
+ fi
+ # /forcefsck isn't deleted because checkfs needs it.
+ # it'll be deleted in that script.
+ retval=$?
+ else
+ # Obey the fs_passno setting for / (see fstab(5))
+ # - find the / entry
+ # - make sure we have 6 fields
+ # - see if fs_passno is something other than 0
+ local pass=$(fstabinfo --passno /)
+ if [ ${pass:-0} != "0" ] ; then
+ ebegin "Checking root filesystem"
+ if [ "${RC_UNAME}" = "Linux" ] ; then
+ fsck -C -T -a /
+ else
+ fsck -p -F /
+ fi
+ retval=$?
+ else
+ ebegin "Skipping root filesystem check" "(fstab's passno == 0)"
+ retval=0
+ fi
+ fi
+
+ if [ ${retval} -eq 0 ] ; then
+ eend 0
+ elif [ ${retval} -eq 1 ] ; then
+ ewend 1 "Filesystem repaired"
+ retval=0
+ elif [ ${retval} -eq 8 ] ; then
+ ewend 1 $"Operational error, continuing"
+ retval=0
+ elif [ ${retval} -eq 2 -o ${retval} -eq 3 ] ; then
+ ewend 1 "Filesystem repaired, but reboot needed!"
+ if [ "${RC_FORCE_AUTO}" != "yes" ] ; then
+ printf "\a"; sleep 1; printf "\a"; sleep 1
+ printf "\a"; sleep 1; printf "\a"; sleep 1
+ ewarn "Rebooting in 10 seconds ..."
+ sleep 10
+ fi
+ einfo "Rebooting"
+ /sbin/reboot -f
+ else
+ if [ "${RC_FORCE_AUTO}" = "yes" ] ; then
+ eend 2 "Rerunning fsck in force mode"
+ if [ "${RC_UNAME}" = "Linux" ] ; then
+ fsck -y -C -T /
+ else
+ fsck -y /
+ fi
+ retval=$?
+ else
+ eend 2 "Filesystem couldn't be fixed :("
+ [ "${RC_UNAME}" = "Linux" ] || return 1
+ sulogin "${CONSOLE}"
+ fi
+ if [ ${retval} != "0" ] ; then
+ einfo "Unmounting filesystems"
+ if [ "${RC_UNAME}" = "Linux" ] ; then
+ mount -a -o remount,ro /
+ else
+ mount -u -o ro /
+ fi
+ einfo "Rebooting"
+ reboot -f
+ fi
+ fi
+
+ ebegin "Remounting root filesystem read/write"
+ if [ "${RC_UNAME}" = "Linux" ] ; then
+ mount -n -o remount,rw /
+ else
+ mount -u -o rw /
+ fi
+ eend $? "Root filesystem could not be mounted read/write :(" || return 1
+
+ # Only Linux has mtab
+ [ "${RC_UNAME}" = "Linux" ] && do_mtab
+
+ # If the user's /dev/null or /dev/console are missing, we
+ # should help them out and explain how to rectify the situation
+ if [ ! -c /dev/null -o ! -c /dev/console ] ; then
+ if [ -e /usr/share/baselayout/issue.devfix ] ; then
+ # Backup current /etc/issue
+ if [ -e /etc/issue -a ! -e /etc/issue.devfix ] ; then
+ mv -f /etc/issue /etc/issue.devfix
+ fi
+ cp -f /usr/share/baselayout/issue.devfix /etc/issue
+ fi
+ fi
+
+ # We got here, so return 0
+ return 0
+}
+
+# vim: set ts=4 :
diff --git a/init.d/halt.sh b/init.d/halt.sh
new file mode 100755
index 00000000..eabc8980
--- /dev/null
+++ b/init.d/halt.sh
@@ -0,0 +1,94 @@
+#!/bin/sh
+# Copyright 1999-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+. /etc/init.d/functions.sh
+. "${RC_LIBDIR}"/sh/rc-functions.sh
+
+# Support LiveCD foo
+if [ -r /sbin/livecd-functions.sh ] ; then
+ . /sbin/livecd-functions.sh
+ livecd_read_commandline
+fi
+
+stop_addon devfs
+stop_addon udev
+
+# Flush all pending disk writes now
+sync ; sync
+
+# If we are in a VPS, we don't need anything below here, because
+# 1) we don't need (and by default can't) umount anything (VServer) or
+# 2) the host utils take care of all umounting stuff (OpenVZ)
+if [ "${RC_SYS}" = "VPS" ] ; then
+ if [ -e /etc/init.d/"$1".sh ] ; then
+ . /etc/init.d/"$1".sh
+ else
+ exit 0
+ fi
+fi
+
+# If $svcdir is still mounted, preserve it if we can
+if mountinfo "${RC_SVCDIR}" >/dev/null && [ -w "${RC_LIBDIR}" ] ; then
+ f_opts="-m -c"
+ [ "${RC_UNAME}" = "Linux" ] && f_opts="-c"
+ if [ -n "$(fuser ${f_opts} "${svcdir}" 2>/dev/null)" ] ; then
+ fuser -k ${f_opts} "${svcdir}" 1>/dev/null 2>/dev/null
+ sleep 2
+ fi
+ cp -p "${RC_SVCDIR}"/deptree "${RC_SVCDIR}"/softlevel \
+ "${RC_SVCDIR}"/nettree "${RC_LIBDIR}" 2>/dev/null
+ umount "${RC_SVCDIR}"
+ rm -rf "${RC_SVCDIR}"/*
+ # Pipe errors to /dev/null as we may have future timestamps
+ cp -p "${RC_LIBDIR}"/deptree "${RC_LIBDIR}"/softlevel \
+ "${RC_LIBDIR}"/nettree "${RC_SVCDIR}" 2>/dev/null
+ rm -f "${RC_LIBDIR}"/deptree "${RC_LIBDIR}"/softlevel \
+ "${RC_LIBDIR}"/nettree
+ # Release the memory disk if we used it
+ case "${mnt}" in
+ "/dev/md"[0-9]*) mdconfig -d -u "${mnt#/dev/md*}" ;;
+ esac
+fi
+
+unmounted=0
+# Remount the remaining filesystems read-only
+if [ "${RC_UNAME}" != "FreeBSD" ] ; then
+ ebegin "Remounting remaining filesystems read-only"
+ # We need the do_unmount function
+ . "${RC_LIBDIR}"/sh/rc-mount.sh
+ eindent
+ do_unmount "mount -n -o remount,ro" "^(/dev|/dev/pts|/dev/shm|/proc|/proc/.*|/sys)$"
+ eoutdent
+ eend $?
+ unmounted=$?
+fi
+
+# This UPS code should be moved to out of here and to an addon
+if [ -f /etc/killpower ] ; then
+ UPS_CTL=/sbin/upsdrvctl
+ UPS_POWERDOWN="${UPS_CTL} shutdown"
+elif [ -f /etc/apcupsd/powerfail ] ; then
+ UPS_CTL=/etc/apcupsd/apccontrol
+ UPS_POWERDOWN="${UPS_CTL} killpower"
+fi
+if [ -x "${UPS_CTL}" ] ; then
+ ewarn "Signalling ups driver(s) to kill the load!"
+ ${UPS_POWERDOWN}
+ ewarn "Halt system and wait for the UPS to kill our power"
+ halt -id
+ sleep 60
+fi
+
+if [ ${unmounted} -ne 0 ] ; then
+ [ -x /sbin/sulogin ] && sulogin -t 10 /dev/console
+ exit 1
+fi
+
+# Load the final script - not needed on BSD so they should not exist
+[ -e /etc/init.d/"$1".sh ] && . /etc/init.d/"$1".sh
+
+# Always exit 0 here
+exit 0
+
+# vim: set ts=4 :
diff --git a/init.d/hostname b/init.d/hostname
new file mode 100755
index 00000000..86eb989a
--- /dev/null
+++ b/init.d/hostname
@@ -0,0 +1,20 @@
+#!/sbin/runscript
+# Copyright 1999-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+depend() {
+ need checkroot
+}
+
+start() {
+ if [ -f /etc/hostname ] ; then
+ ewarn "You should stop using /etc/hostname and use /etc/conf.d/hostname"
+ HOSTNAME=$(cat /etc/hostname)
+ fi
+
+ ebegin "Setting hostname to ${HOSTNAME}"
+ hostname "${HOSTNAME}"
+ eend $? "Failed to set the hostname"
+}
+
+# vim: ts=4 :
diff --git a/init.d/local b/init.d/local
new file mode 100755
index 00000000..4e4c265c
--- /dev/null
+++ b/init.d/local
@@ -0,0 +1,34 @@
+#!/sbin/runscript
+# Copyright 1999-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+depend() {
+ after *
+}
+
+start() {
+ ebegin "Starting local"
+
+ # Add any misc programs that should be started
+ # to /etc/conf.d/local.start
+ if [ -e /etc/conf.d/local.start ] ; then
+ . /etc/conf.d/local.start
+ fi
+
+ eend $? "Failed to start local"
+}
+
+stop() {
+ ebegin "Stopping local"
+
+ # Add any misc programs that should be stopped
+ # to /etc/conf.d/local.stop
+ if [ -e /etc/conf.d/local.stop ] ; then
+ . /etc/conf.d/local.stop
+ fi
+
+ eend $? $"Failed to stop local"
+}
+
+
+# vim:ts=4
diff --git a/init.d/localmount b/init.d/localmount
new file mode 100755
index 00000000..303f5a2c
--- /dev/null
+++ b/init.d/localmount
@@ -0,0 +1,183 @@
+#!/sbin/runscript
+# Copyright 1999-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+depend() {
+ need checkfs
+}
+
+start() {
+ # Mount local filesystems in /etc/fstab.
+ local types="noproc" x=
+ for x in ${RC_NET_FS_LIST} ; do
+ types="${types},${x}"
+ done
+
+ ebegin "Mounting local filesystems"
+ mount -at "${types}"
+ eend $? "Some local filesystem failed to mount"
+
+ # Change the mount options of already mounted paritions
+ # This is needed when /usr is separate and coming back from single user
+ if [ "${RC_UNAME}" != "Linux" ] ; then
+ mount -uao fstab -t "${types},linprocfs"
+ fi
+
+ if [ -x /sbin/savecore ] ; then
+ local dumpdir=${KERNEL_DUMP_DIR:-/var/crash}
+ if ! [ -d "${dumpdir}" ]; then
+ mkdir -p "${dumpdir}"
+ chmod 700 "${dumpdir}"
+ fi
+
+ # Don't quote ${KERNEL_DUMP_DEVICE}, so that if it's unset, savecore
+ # will check on the partitions listed in fstab without errors in the
+ # output
+ if savecore -C "${dumpdir}" ${KERNEL_DUMP_DEVICE} >/dev/null ; then
+ local savecoreopts="${dumpdir} ${KERNEL_DUMP_DEVICE}"
+ [ "${KERNEL_DUMP_COMPRESS}" = "yes" ] \
+ && savecoreopts="-z ${savecoreopts}"
+ ebegin "Saving kernel core dump in" "${dumpdir}"
+ savecore ${savecoreopts} >/dev/null
+ eend $?
+ fi
+ fi
+
+ # Sync bootlog now as /var should be mounted
+ if type bootlog >/dev/null 2>/dev/null ; then
+ bootlog sync 2>/dev/null
+ fi
+
+ # Make sure we insert usbcore if its a module
+ if [ -f /proc/modules -a ! -d /proc/bus/usb ] ; then
+ # >/dev/null to hide errors from non-USB users
+ modprobe usbcore &> /dev/null
+ fi
+
+ if [ -e /proc/filessystems ] ; then
+ # Check what USB fs the kernel support. Currently
+ # 2.5+ kernels, and later 2.4 kernels have 'usbfs',
+ # while older kernels have 'usbdevfs'.
+ if [ -d /proc/bus/usb -a ! -e /proc/bus/usb/devices ] ; then
+ local usbfs=$(grep -Fow usbfs /proc/filesystems ||
+ grep -Fow usbdevfs /proc/filesystems)
+
+ if [ -n "${usbfs}" ] ; then
+ ebegin $"Mounting USB device filesystem" "(${usbfs})"
+ local usbgid="$(getent group usb | \
+ sed -e 's/.*:.*:\(.*\):.*/\1/')"
+ mount -t ${usbfs} \
+ -o ${usbgid:+devmode=0664,devgid=${usbgid},}noexec,nosuid \
+ usbfs /proc/bus/usb
+ eend $?
+ fi
+ fi
+
+ # Setup Kernel Support for miscellaneous Binary Formats
+ if [ -d /proc/sys/fs/binfmt_misc ] ; then
+ if [ -n "$(grep -Fow binfmt_misc /proc/filesystems)" ] ; then
+ ebegin "Mounting misc binary format filesystem"
+ mount -t binfmt_misc -o nodev,noexec,nosuid \
+ binfmt_misc /proc/sys/fs/binfmt_misc
+ eend $?
+ fi
+ fi
+ if [ -d /sys/kernel/security ] ; then
+ if [ -n "$(grep -Fow securityfs /proc/filesystems)" ] ; then
+ ebegin "Mounting security filesystem"
+ mount -t securityfs securityfs /sys/kernel/security \
+ -o nodev,noexec,nosuid
+ eend $?
+ fi
+ fi
+ fi
+
+ # We do our swapping here instead of rc so we can get urandom started
+ # before us for people that like an encrypted swap.
+ ebegin "Activating (possible) swap"
+ swapon -a >/dev/null
+ eend 0 # If swapon has nothing todo it errors, so always return 0
+
+ # Start dm-crypt mappings, if any
+ start_addon dm-crypt
+
+ # Setup any user requested dump device
+ if [ -x /sbin/dumpon -a -n "${KERNEL_DUMP_DEVICE}" ] ; then
+ ebegin "Activating kernel core dump device" "(${KERNEL_DUMP_DEVICE})"
+ dumpon "${KERNEL_DUMP_DEVICE}"
+ eend $?
+ fi
+
+ # Always return 0 - some local mounts may not be critical for boot
+ return 0
+}
+
+stop() {
+ # Don't unmount anything for VPS systems
+ [ "${RC_SYS}" = "VPS" ] && return 0
+
+ # We never unmount / or /dev or $RC_LIBDIR
+ local x= no_umounts="/|/dev|${RC_SVCDIR}"
+
+ # NO_UMOUNTS is taken from /etc/conf.d/localmount
+ # RC_NO_UMOUNTS is taken from /etc/conf.d/rc and can also be
+ # set by plugins
+ local OIFS=$IFS SIFS=${IFS-y}
+ IFS=$IFS:
+ for x in ${NO_UMOUNTS} ${RC_NO_UMOUNTS} ; do
+ no_umounts="${no_umounts}|${x}"
+ done
+ if [ "${SIFS}" = "y" ] ; then
+ IFS=$OIFS
+ else
+ unset IFS
+ fi
+
+ if [ "${RC_UNAME}" = "Linux" ] ; then
+ no_umounts="${no_umounts}|/dev/pts|/dev/shm|/proc|/proc/.*|/sys"
+ fi
+ no_umounts="^(${no_umounts})$"
+
+ # Flush all pending disk writes now
+ sync ; sync
+
+ # Try to unmount all tmpfs filesystems not in use, else a deadlock may
+ # occure, bug #13599.
+ # As $RC_SVCDIR may also be tmpfs we cd to it to lock it
+ cd "${RC_SVCDIR}"
+ umount -a -t tmpfs 2>/dev/null
+
+ # As we're turning off swap below, we need to disable kernel dumps
+ [ -x /sbin/dumpon ] && dumpon off
+
+ local swap_list=
+ # Turn off swap
+ if [ -r /proc/swaps ] ;then
+ swap_list=$(sed -e '1d' /proc/swaps)
+ else
+ swap_list=$(swapctl -l 2>/dev/null | sed -e '1d')
+ fi
+ if [ -n "${swap_list}" ] ; then
+ ebegin "Deactivating swap"
+ swapoff -a >/dev/null
+ eend $?
+ fi
+
+ . "${RC_LIBDIR}"/sh/rc-mount.sh
+
+ # Umount loopback devices
+ einfo "Unmounting loopback devices"
+ eindent
+ do_unmount "umount -d" "${no_umounts}" "^/dev/loop"
+ eoutdent
+
+ # Now everything else
+ einfo "Unmounting filesystems"
+ eindent
+ do_unmount "umount" "${no_umounts}"
+ eoutdent
+
+ return 0
+}
+
+# vim: set ts=4 :
diff --git a/init.d/netmount b/init.d/netmount
new file mode 100755
index 00000000..28c65489
--- /dev/null
+++ b/init.d/netmount
@@ -0,0 +1,85 @@
+#!/sbin/runscript
+# Copyright 1999-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+have_nfs() {
+ local IFS=\n x=
+ set -- $(fstabinfo --fstype nfs,nfs4)
+ for x in "$@" ; do
+ ! fstabinfo --opts "${x}" | grep -q noauto && return 0
+ done
+ return 1
+}
+
+depend() {
+ local myneed= myuse= pmap="portmap" nfsmounts= x
+ [ -x /etc/init.d/rpcbind ] && pmap="rpcbind"
+
+ # Only have Portmap as a dependency if there is a nfs mount in fstab that
+ # is set to mount at boot
+ if have_nfs ; then
+ myneed="${myneed} ${pmap}"
+ else
+ myuse="${myuse} ${pmap}"
+ fi
+
+ need net ${myneed}
+ use afc-client amd autofs dns nfs nfsmount ${myuse}
+}
+
+start() {
+ local myneed= myuse= pmap="portmap" nfsmounts=
+ [ -x /etc/init.d/rpcbind ] && pmap="rpcbind"
+
+ local x= fs=
+ for x in ${RC_NET_FS_LIST} ; do
+ case "${x}" in
+ nfs|nfs4)
+ # If the nfsmount script took care of the nfs filesystems,
+ # then there's no point in trying them twice
+ service_started nfsmount && continue
+
+ # Only try to mount NFS filesystems if portmap was started.
+ # This is to fix "hang" problems for new users who do not
+ # add portmap to the default runlevel.
+ if have_nfs && ! service_started "${pmap}" ; then
+ continue
+ fi
+ ;;
+ esac
+ fs="${fs}${fs:+,}${x}"
+ done
+
+ ebegin "Mounting network filesystems"
+ mount -at ${fs}
+ ewend $? "Could not mount all network filesystems!"
+ return 0
+}
+
+stop() {
+ local x= fs=
+ for x in ${RC_NET_FS_LIST} ; do
+ fs="${fs}${fs:+,}${x}"
+ done
+
+ ebegin "Unmounting network filesystems"
+ umount -at ${fs}
+ local retval=$?
+ eend ${retval} "Failed to simply unmount filesystems"
+
+ if [ ${retval} -ne 0 ] ; then
+ . "${RC_SVCLIB}/sh/rc-mount.sh"
+ eindent
+ fs=
+ for x in ${RC_NET_FS_LIST} ; do
+ fs="${fs:+|}${x}"
+ done
+ do_unmount "umount" "" "" "^(${fs})$"
+ retval=$?
+ eoutent
+ fi
+
+ return ${retval}
+}
+
+# vim: set ts=4 :
diff --git a/init.d/rmnologin b/init.d/rmnologin
new file mode 100755
index 00000000..56b20ea1
--- /dev/null
+++ b/init.d/rmnologin
@@ -0,0 +1,16 @@
+#!/sbin/runscript
+# Copyright 1999-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+depend() {
+ need localmount
+}
+
+start() {
+ if [ -f /etc/nologin.boot ] ; then
+ rm -f /etc/nologin /etc/nologin.boot
+ fi
+}
+
+
+# vim:ts=4
diff --git a/init.d/urandom b/init.d/urandom
new file mode 100755
index 00000000..a09153a5
--- /dev/null
+++ b/init.d/urandom
@@ -0,0 +1,34 @@
+#!/sbin/runscript
+# Copyright 1999-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+depend() {
+ need localmount
+}
+
+start() {
+ [ -c /dev/urandom ] || return
+ if [ -f /var/run/random-seed ] ; then
+ cat /var/run/random-seed > /dev/urandom
+ fi
+ if ! rm -f /var/run/random-seed ; then
+ ewarn "Skipping /var/run/random-seed initialization (ro root?)"
+ return 0
+ fi
+ ebegin "Initializing random number generator"
+ umask 077
+ dd if=/dev/urandom of=/var/run/random-seed count=1 2>/dev/null
+ eend $? "Error initializing random number generator"
+ umask 022
+}
+
+stop() {
+ ebegin "Saving random seed"
+ # Carry a random seed from shut-down to start-up;
+ # see documentation in linux/drivers/char/random.c
+ umask 077
+ dd if=/dev/urandom of=/var/run/random-seed count=1 2>/dev/null
+ eend $? "Failed to save random seed"
+}
+
+# vim:ts=4
diff --git a/man.Linux/Makefile b/man.Linux/Makefile
new file mode 100644
index 00000000..6cb341d7
--- /dev/null
+++ b/man.Linux/Makefile
@@ -0,0 +1,5 @@
+DIR = /usr/share/man
+MANS = modules.autoload.5
+
+TOPDIR = ..
+include $(TOPDIR)/default.mk
diff --git a/man.Linux/modules.autoload.5 b/man.Linux/modules.autoload.5
new file mode 100644
index 00000000..1a0c3e35
--- /dev/null
+++ b/man.Linux/modules.autoload.5
@@ -0,0 +1,19 @@
+.TH MODULES.AUTOLOAD 5 "Gentoo Linux" "Nov 2001"
+.SH NAME
+\fI/etc/modules.autoload\fR - kernel modules to load at boot time
+.SH DESCRIPTION
+.PP
+The \fI/etc/modules.autoload\fR
+file contains the names of kernel modules that are to be loaded at boot
+time, one per line. Arguments can be given on the same line as the module
+name. Comments begin with a `#', and everything on the line after it is
+ignored. This file is read by the \fI/etc/init.d/modules\fR initscript,
+which is usually linked in the \fI/etc/runlevels/boot\fR directory.
+.SH "SEE ALSO"
+.BR modules-update (8),
+.BR modprobe (8),
+.BR modules.conf (5)
+.TP
+The \fI/sbin/modules-update\fR script.
+.TP
+The files in \fI/etc/modules.d\fR.
diff --git a/man/Makefile b/man/Makefile
new file mode 100644
index 00000000..8c6b3cf8
--- /dev/null
+++ b/man/Makefile
@@ -0,0 +1,5 @@
+DIR = /usr/share/man
+MANS = rc-depend.8 rc-status.8 rc-update.8 start-stop-daemon.8
+
+TOPDIR = ..
+include $(TOPDIR)/default.mk
diff --git a/man/rc-depend.8 b/man/rc-depend.8
new file mode 100644
index 00000000..62aa9592
--- /dev/null
+++ b/man/rc-depend.8
@@ -0,0 +1,73 @@
+.TH "BASELAYOUT" "8" "March 2007" "baselayout" "baselayout"
+.SH NAME
+rc-depend \ - resolve init script dependencies
+.SH SYNOPSIS
+\fBrc-depend\fR \fI-ineed\fR \fI-iuse\fR \fIservice\fR ...
+.br
+\fBrc-depend\fR \fI--notrace\fR \fI-iprovide\fR \fIservice\fR ...
+.br
+\fBrc-depend\fR \fI-needsme\fR \fIservice\fR ...
+.br
+\fBrc-depend\fR \fI--update\fR
+.SH DESCRIPTION
+Gentoos init system uses service dependencies to depend on other services.
+Rather than just starting in a set order, we start and stop in the order
+defined by the services themselves.
+For example, most services require local disks to be mounted and as such can
+depend on the localmount service. Others depend on and net and dns and will
+only start when those dependencies have been satisfied.
+
+One issue of note is that a service can provide another service, which is more
+generic. A good example of this is that net.lo and any service linked to it
+provide "net", which a few services depend on. You can of course have a few
+network interfaces: modern laptops have 3 being loopback, wired and wireless.
+What makes this more interesting is that it could be setup so that both wired
+and wireless are optional. So we work out provided services like so :-
+
+1) Always use any services in the runlevel.
+.br
+2) If no services are defined in the runlevel then use any running services
+that satisfy the provide.
+.br
+3) Append any services in the boot runlevel.
+
+\fBrc-order\fR is primarily used internally by Gentoo and is not meant as an
+end-user or admin tool. This man page is purely to describe its function.
+.SH OPTIONS
+.TP
+\fB--deptree \fIdeptree\fR
+Use this \fIdeptree\fR instead of the default one,
+\fI/lib/rcscripts/init.d/deptree\fR.
+.TP
+\fB--notrace\fR
+Just show the dependencies for the specified services without working out
+anything extra.
+.TP
+\fB--strict\fR
+For provided services, depend on all of them in the runlevel instead of just
+ones that are started.
+.TP
+\fB--update\fR
+Force an update of the dependency tree. Normally this is not needed as we
+automatically update the dependency tree if any files in /etc/init.d or
+/etc/conf.d are newer than the tree.
+.TP
+\fB-dependency_type\fR
+Work with the specified dependency type, such as \fIineed\fR, \fIiafter\fR,
+\fIneedsme\fR.
+If none are supplied we default to \fIineed\fR and \fIiuse\fR.
+.SH NOTES
+When needsme depends on a provided service, like net, we don't do any
+mapping to an actual service unless it's the last one up. So if net.lo and
+net.eth0 are started then neither are returned. If net.eth0 then stops then
+every service that needs net then has net.lo in its needsme list so that
+we net.lo stops it brings down all services that depend on net.
+.SH BUGS
+Provided services are calculated at runtime. The current downside of this
+approach means that if you do "after net; before net.lo" and net.lo provides
+net then you can get into an sticky loop where services hang.
+.SH "REPORTING BUGS"
+Please report bugs via http://bugs.gentoo.org/
+.SH "SEE ALSO"
+.BR rc-update (8),
+.BR rc-status (8)
diff --git a/man/rc-status.8 b/man/rc-status.8
new file mode 100644
index 00000000..d78e4469
--- /dev/null
+++ b/man/rc-status.8
@@ -0,0 +1,37 @@
+.TH "BASELAYOUT" "8" "May 2004" "baselayout" "baselayout"
+.SH NAME
+rc-status \- show status info about runlevels
+.SH SYNOPSIS
+\fBrc-status\fR \fI[command [runlevel]]\fR
+.SH DESCRIPTION
+\fBrc-status\fR gathers and displays information about the status of init
+scripts in different runlevels. The default behavior is to show information
+about the current runlevel, but any runlevel can be quickly examined.
+directory. They must also conform to the Gentoo runscript standard.
+.SH OPTIONS
+.TP
+\fB\-\-all (\-a)\fR
+Show all runlevels and their services
+.TP
+\fB\-\-list (\-l)\fR
+List all defined runlevels
+.TP
+\fB\-\-nocolor (\-nc)\fR
+Disable color output
+.TP
+\fB\-\-servicelist (\-s)\fR
+Show all services
+.TP
+\fB\-\-unused (\-u)\fR
+Show services not assigned to any runlevel
+.TP
+\fB[runlevel]\fR
+Show information only for the named \fBrunlevel\fR
+.SH "REPORTING BUGS"
+Please report bugs via http://bugs.gentoo.org/
+.SH "SEE ALSO"
+.BR rc-update (8)
+
+http://www.gentoo.org/doc/en/handbook/handbook-x86.xml?part=2&chap=4
+.SH AUTHORS
+Mike Frysinger <vapier@gentoo.org>
diff --git a/man/rc-update.8 b/man/rc-update.8
new file mode 100644
index 00000000..03e79c84
--- /dev/null
+++ b/man/rc-update.8
@@ -0,0 +1,43 @@
+.TH "BASELAYOUT" "8" "May 2004" "baselayout" "baselayout"
+.SH NAME
+rc-update \- add and remove init scripts to a runlevel
+.SH SYNOPSIS
+\fBrc-update\fR \fIadd\fR \fIscript\fR \fI<runlevels>\fR
+.br
+\fBrc-update\fR \fIdel\fR \fIscript\fR \fI[runlevels]\fR
+.br
+\fBrc-update\fR \fIshow\fR \fI[\-\-verbose]\fR \fI[runlevels]\fR
+.SH DESCRIPTION
+Gentoo's init system uses named runlevels. Rather than editing some obscure
+file or managing a directory of symlinks, \fBrc-update\fR exists to quickly
+add or delete init scripts from different runlevels.
+
+All scripts specified with this utility must reside in the \fI/etc/init.d\fR
+directory. They must also conform to the Gentoo runscript standard.
+.SH OPTIONS
+.TP
+\fBadd (\-a)\fR \fIscript\fR \fI<runlevels>\fR
+Add the specified \fIinit script\fR to the specified \fIrunlevels\fR. You
+must specify at least one runlevel.
+
+Example: rc-update add net.eth0 default
+.TP
+\fBdel (\-d)\fR \fIscript\fR \fI[runlevels]\fR
+Delete the specified \fIinit script\fR from the specified \fIrunlevels\fR.
+If you do not specify the \fIrunlevels\fR from which to delete, the script
+will be removed from all exists runlevels.
+
+Example: rc-update del sysklogd
+.TP
+\fBshow (\-s)\fR \fI[\-v|\-\-verbose]\fR \fI[runlevels]\fR
+Show all enabled scripts and the runlevels they belong to. If you specify
+\fIrunlevels\fR to show, then only those will be included in the output. To
+view all init scripts, run with the \fI\-\-verbose\fR option.
+
+Example: rc-update show
+.SH "REPORTING BUGS"
+Please report bugs via http://bugs.gentoo.org/
+.SH "SEE ALSO"
+.BR rc-status (8)
+
+http://www.gentoo.org/doc/en/handbook/handbook-x86.xml?part=2&chap=4
diff --git a/man/start-stop-daemon.8 b/man/start-stop-daemon.8
new file mode 100644
index 00000000..5ec29f2e
--- /dev/null
+++ b/man/start-stop-daemon.8
@@ -0,0 +1,212 @@
+.TH "BASELAYOUT" "8" "March 2007" "baselayout" "baselayout"
+.SH NAME
+start\-stop\-daemon \- start and stop system daemon programs
+.SH SYNOPSIS
+.B start-stop-daemon
+.BR -S | --start
+.IR options
+.RB [ \-\- ]
+.IR arguments
+.HP
+.B start-stop-daemon
+.BR -K | --stop
+.IR options
+.HP
+.B start-stop-daemon
+.BR -H | --help
+.HP
+.B start-stop-daemon
+.BR -V | --version
+.SH DESCRIPTION
+.B start\-stop\-daemon
+is used to control the creation and termination of system-level processes.
+Using the
+.BR --exec ", " --pidfile ", " --user ", and " --name " options,"
+.B start\-stop\-daemon
+can be configured to find existing instances of a running process.
+
+With
+.BR --start ,
+.B start\-stop\-daemon
+checks for the existence of a specified process.
+If such a process exists,
+.B start\-stop\-daemon
+does nothing, and exits with error status 1.
+If such a process does not exist, it starts an
+instance, using the executable specified by
+.BR --exec .
+Any arguments given after
+.BR --
+on the command line are passed unmodified to the program being
+started.
+.B start\-stop\-daemon
+pauses for a little bit then checks the daemon is still running as badly
+written ones like to fork early and then bail on a error in their config.
+As such it may be necessary to use the --name parameter if the daemon in
+question is not a C program, ie a script. Once started, we store how we
+are called in \fBrc\fR if called from an init script.
+
+With
+.BR --stop ,
+.B start\-stop\-daemon
+also checks for the existence of a specified process.
+If such a process exists,
+.B start\-stop\-daemon
+sends it the signal specified by
+.BR --signal ,
+and exits with error status 0.
+If such a process does not exist, or there was an error stopping it
+.B start\-stop\-daemon
+exits with error status 1. If
+.BR --test
+is specified then we just send the signal and not the schedule. If
+.BR --oknodo
+is specified then we don't remove the daemon information from
+.BR rc.
+
+.SH OPTIONS
+
+.TP
+\fB-x\fP|\fB--exec\fP \fIexecutable\fP
+Check for processes that are instances of this executable.
+.TP
+\fB-p\fP|\fB--pidfile\fP \fIpid-file\fP
+Check for processes whose process-id is specified in
+.I pid-file.
+.TP
+\fB-u\fP|\fB--user\fP \fIusername\fP|\fIuid\fP
+Check for processes owned by the user specified by
+.I username
+or
+.I uid.
+.TP
+\fB-n\fP|\fB--name\fP \fIprocess-name\fP
+Check for processes with the name
+.I process-name
+.TP
+\fB-s\fP|\fB--signal\fP \fIsignal\fP
+With
+.BR --stop
+, specifies the signal to send to processes being stopped (default SIGTERM).
+.TP
+\fB-R\fP|\fB--retry\fP \fItimeout\fP|\fIschedule\fP
+With
+.BR --stop ,
+specifies that
+.B start-stop-daemon
+is to check whether the process(es)
+do finish. It will check repeatedly whether any matching processes
+are running, until none are. If the processes do not exit it will
+then take further action as determined by the schedule.
+
+If
+.I timeout
+is specified instead of
+.I schedule
+then the schedule
+.IB signal / timeout
+is used, where
+.I signal
+is the signal specified with
+.BR --signal .
+
+.I schedule
+is a list of at least two items separated by slashes
+.RB ( / );
+each item may be
+.BI - signal-number
+or [\fB\-\fP]\fIsignal-name\fP,
+which means to send that signal,
+or
+.IR timeout ,
+which means to wait that many seconds for processes to
+exit,
+or
+.BR forever ,
+which means to repeat the rest of the schedule forever if
+necessary.
+
+If the end of the schedule is reached and
+.BR forever
+is not specified, then
+.B start-stop-daemon
+exits with error status 2.
+If a schedule is specified, then any signal specified
+with
+.B --signal
+is ignored.
+.TP
+.BR -t | --test
+Print actions that would be taken and set appropriate return value,
+but take no action.
+.TP
+.BR -o | --oknodo
+Used for sending signals to a running daemon but not expecting it to stop.
+.TP
+.BR -q | --quiet
+Do not print informational messages; only display error messages.
+.TP
+\fB-c\fP|\fB--chuid\fP \fIusername\fR|\fIuid\fP
+Change to this username/uid before starting the process. You can also
+specify a group by appending a
+.BR : ,
+then the group or gid in the same way
+as you would for the `chown' command (\fIuser\fP\fB:\fP\fIgroup\fP).
+When using this option
+you must realize that the primary and supplemental groups are set as well,
+even if the
+.B --group
+option is not specified. The
+.B --group
+option is only for
+groups that the user isn't normally a member of (like adding per/process
+group membership for generic users like
+.BR nobody ).
+.TP
+\fB-r\fP|\fB--chroot\fP \fIroot\fP
+Chdir and chroot to
+.I root
+before starting the process. Please note that the pidfile is also written
+after the chroot.
+.TP
+.BR -b | --background
+Typically used with programs that don't detach on their own. This option
+will force
+.B start-stop-daemon
+to fork before starting the process, and force it into the background.
+.TP
+\fB-1\fP|\fB--stdout\fP \fIlogfile\fP
+Redirect the standard output of the process to \fIlogfile\fP when started with \fB--background\fP.
+Must be an absolute pathname, but relative to the \fIpath\fP optionally given with
+\fB--chroot\fP.
+Hint: The \fIlogfile\fP can also be a named pipe.
+.TP
+\fB-2\fP|\fB--stderr\fP \fIlogfile\fP
+The same thing as \fB--stdout\fP but with the standard error output.
+.TP
+.BR -N | --nicelevel
+This alters the prority of the process before starting it.
+.TP
+.BR -m | --make-pidfile
+Used when starting a program that does not create its own pid file. This
+option will make
+.B start-stop-daemon
+create the file referenced with
+.B --pidfile
+and place the pid into it just before executing the process. Note, it will
+not be removed when stopping the program.
+.B NOTE:
+This feature may not work in all cases. Most notably when the program
+being executed forks from its main process. Because of this it is usually
+only useful when combined with the
+.B --background
+option.
+.TP
+.BR -v | --verbose
+Print verbose informational messages.
+.TP
+.BR -H | --help
+Print help information; then exit.
+.TP
+.BR -V | --version
+Print version information; then exit.
diff --git a/net.BSD/Makefile b/net.BSD/Makefile
new file mode 100644
index 00000000..11bd20a4
--- /dev/null
+++ b/net.BSD/Makefile
@@ -0,0 +1,5 @@
+DIR = /$(LIB)/rcscripts/net
+FILES = ifconfig.sh iwconfig.sh
+
+TOPDIR = ..
+include $(TOPDIR)/default.mk
diff --git a/net.BSD/ifconfig.sh b/net.BSD/ifconfig.sh
new file mode 100644
index 00000000..2e88bc20
--- /dev/null
+++ b/net.BSD/ifconfig.sh
@@ -0,0 +1,125 @@
+# Copyright 2004-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+ifconfig_depend() {
+ program /sbin/ifconfig
+ provide interface
+}
+
+_exists() {
+ [ -e /dev/net/"${IFACE}" ]
+}
+
+_get_mac_address() {
+ local mac=$(LC_ALL=C ifconfig "${IFACE}" | \
+ sed -n -e 's/^[[:space:]]*ether \(..:..:..:..:..:..\).*/\1/p')
+
+ case "${mac}" in
+ 00:00:00:00:00:00) ;;
+ 44:44:44:44:44:44) ;;
+ FF:FF:FF:FF:FF:FF) ;;
+ *) echo "${mac}"; return 0 ;;
+ esac
+
+ return 1
+}
+
+_up () {
+ ifconfig "${IFACE}" up
+}
+
+_down () {
+ ifconfig "${IFACE}" down
+}
+
+_ifindex() {
+ local x=
+ for x in /dev/net[0-9]* ; do
+ if [ "${x}" -ef /dev/net/"${IFACE}" ] ; then
+ echo "${x#/dev/net}"
+ return 0
+ fi
+ done
+ return 1
+}
+
+_is_wireless() {
+ LC_ALL=C ifconfig "${IFACE}" 2>/dev/null | \
+ grep -q "^[[:space:]]*media: IEEE 802.11 Wireless"
+}
+
+_get_inet_address() {
+ set -- $(LC_ALL=C ifconfig "${IFACE}" |
+ sed -n -e 's/^[[:space:]]*inet \([^ ]*\) netmask 0x\(..\)\(..\)\(..\)\(..\).*/\1 0x\2.0x\3.0x\4/p')
+ echo -n "$1"
+ shift
+
+ echo "/$(_netmask2cidr "$1")"
+}
+
+_add_address() {
+ if [ "${metric:-0}" != "0" ] ; then
+ set -- "$@" metric ${metric}
+ fi
+
+ ifconfig "${IFACE}" add "$@"
+}
+
+_add_route() {
+ if [ $# -gt 3 ] ; then
+ if [ "$3" = "gw" -o "$3" = "via" ] ; then
+ local one=$1 two=$2
+ shift ; shift; shift
+ set -- "${one}" "${two}" "$@"
+ fi
+ fi
+
+ route add "$@"
+}
+
+_delete_addresses() {
+ # We don't remove addresses from aliases
+ case "${IFACE}" in
+ *:*) return 0 ;;
+ esac
+
+ einfo "Removing addresses"
+ eindent
+ local addr=
+ for addr in $(LC_ALL=C ifconfig "${IFACE}" |
+ sed -n -e 's/^[[:space:]]*inet \([^ ]*\).*/\1/p') ; do
+ if [ "${addr}" = "127.0.0.1" ] ; then
+ # Don't delete the loopback address
+ [ "$1" = "lo" -o "$1" = "lo0" ] && continue
+ fi
+ einfo "${addr}"
+ /sbin/ifconfig "$1" delete "${addr}"
+ eend $?
+ done
+
+ # Remove IPv6 addresses
+ for addr in $(LC_ALL=C ifconfig "${IFACE}" | \
+ sed -n -e 's/^[[:space:]]*inet6 \([^ ]*\).*/\1/p') ; do
+ case "${addr}" in
+ *"%${IFACE}") continue ;;
+ ::1) continue ;;
+ esac
+ einfo "${addr}"
+ /sbin/ifconfig "${IFACE}" inet6 delete "${addr}"
+ eend $?
+ done
+
+ return 0
+}
+
+_show_address() {
+ einfo "received address $(_get_inet_address "${IFACE}")"
+}
+
+_has_carrier() {
+ local s=$(LC_ALL=C ifconfig "${IFACE}" | \
+ sed -n -e 's/^[[:space:]]status: \(.*\)$/\1/p')
+ [ -z "${s}" -o "${s}" = "active" -o "${s}" = "associated" ]
+}
+
+# vim: set ts=4 :
diff --git a/net.BSD/iwconfig.sh b/net.BSD/iwconfig.sh
new file mode 100644
index 00000000..912e0792
--- /dev/null
+++ b/net.BSD/iwconfig.sh
@@ -0,0 +1,562 @@
+# Copyright 2004-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+_config_vars="$_config_vars essid mode associate_timeout preferred_aps blacklist_aps"
+
+iwconfig_depend() {
+ program /sbin/ifconfig
+ after plug
+ before interface
+ provide wireless
+}
+
+iwconfig_get_wep_status() {
+ local status="disabled"
+ local mode=$(LC_ALL=C ifconfig "${IFACE}" \
+ | sed -n -e 's/^[[:space:]]*authmode \([^ ]*\) privacy ON .*/\1/p')
+ if [ -n "${mode}" ] ; then
+ status="enabled - ${mode}"
+ fi
+
+ echo "(WEP ${status})"
+}
+
+_iwconfig_get() {
+ LC_ALL=C ifconfig "${IFACE}" | \
+ sed -n -e 's/^[[:space:]]*ssid \(.*\) channel \([0-9]*\) bssid \(..:..:..:..:..:..\)$/\'"$1"'/p'
+}
+
+_get_ssid() {
+ _iwconfig_get 1
+}
+
+_get_ap_mac_address() {
+ _iwconfig_get 3
+}
+
+_get_channel() {
+ _iwconfig_get 2
+}
+
+iwconfig_report() {
+ local m="connected to"
+ local ssid=$(_get_ssid)
+ local mac=$(_get_ap_mac_address "${iface}")
+ [ -n "${mac}" ] && mac=" at ${mac}"
+ local wep_status="$(iwconfig_get_wep_status "${iface}")"
+ local channel=$(_get_channel)
+ [ -n "${channel}" ] && channel="on channel ${channel} "
+
+ eindent
+ einfo "${IFACE} ${m} \"${ssid}\"${mac}"
+ einfo "${channel}${wep_status}"
+ eoutdent
+}
+
+iwconfig_get_wep_key() {
+ local mac="$1" key=
+ [ -n "${mac}" ] && mac="$(echo "${mac}" | sed -e 's/://g')"
+ eval key=\$mac_key_${mac}
+ [ -z "${key}" ] && eval key=\$key_${SSIDVAR}
+ echo "${key:--}"
+}
+
+iwconfig_user_config() {
+ local conf=
+ eval set -- \$ifconfig_${SSIDVAR}
+ for conf in "$@" ; do
+ ifconfig "${IFACE}" ${conf}
+ done
+}
+
+iwconfig_set_mode() {
+ local x= opt= unopt="hostap adhoc"
+ case "${mode}" in
+ master|hostap) unopt="adhoc" opt="hostap" ;;
+ ad-hoc|adhoc) unopt="hostap" opt="adhoc" ;;
+ esac
+ for x in ${unopt} ; do
+ ifconfig "${IFACE}" -mediaopt ${x}
+ done
+ for x in ${opt} ; do
+ ifconfig "${IFACE}" mediaopt ${x}
+ done
+}
+
+iwconfig_setup_specific() {
+ local mode="${1:-master}" channel=
+ if [ -z "${SSID}" ]; then
+ eerror "${IFACE} requires an SSID to be set to operate in ${mode} mode"
+ eerror "adjust the ssid_${IFVAR} setting in /etc/conf.d/net"
+ return 1
+ fi
+
+ iwconfig_set_mode "${mode}" || return 1
+
+ SSIDVAR=$(_shell_var "${SSID}")
+ local key=$(iwconfig_get_wep_key)
+
+ # Now set the key
+ ifconfig "${IFACE}" wepkey ${key}
+
+ ifconfig "${IFACE}" ssid "${ESSID}" || return 1
+
+ eval channel=\$channel_${IFVAR}
+ # We default the channel to 3
+ ifconfig "${IFACE}" channel "${channel:-3}" || return 1
+
+ iwconfig_user_config
+ iwconfig_report "${iface}"
+ return 0
+}
+
+iwconfig_associate() {
+ local mac="$1" channel="$2" caps="$3"
+ local mode= w="(WEP Disabled)" key=
+
+ SSIDVAR=$(_shell_var "${SSID}")
+ key=$(iwconfig_get_wep_key "${mac}")
+ case "${caps}" in
+ [EI]P*)
+ if [ "${key}" = "-" ] ; then
+ ewarn "WEP key is not set for \"${SSID}\"; not connecting"
+ return 1
+ fi
+ ;;
+ "") ;;
+ *)
+ if [ "${key}" != "-" ] ; then
+ key="-"
+ ewarn "\"${ESSID}\" is not WEP enabled; ignoring setting"
+ fi
+ ;;
+ esac
+
+ # Set mode accordingly
+ case "${caps}" in
+ *E*) mode="managed"; ifconfig "${IFACE}" -mediaopt adhoc ;;
+ *I*) mode="adhoc"; ifconfig "${IFACE}" mediaopt adhoc ;;
+ *)
+ if LC_ALL=C ifconfig "${IFACE}" | grep -q "^[[:space:]]*media: .*adhoc" ; then
+ mode="adhoc"
+ else
+ mode="managed"
+ fi
+ ;;
+ esac
+
+ if [ "${key}" = "-" ] ; then
+ ifconfig "${IFACE}" wepmode off
+ else
+ ifconfig "${IFACE}" wepmode on
+ ifconfig "${IFACE}" deftxkey 1
+ w=$(iwconfig_get_wep_status)
+ fi
+
+ ebegin "Connecting to \"${SSID}\" in ${mode} mode ${w}"
+
+ if ! ifconfig "${IFACE}" wepkey ${key} ; then
+ eerror "Invalid WEP key ${key}"
+ return 1
+ fi
+
+ ifconfig "${IFACE}" ssid "${SSID}" || return 1
+ iwconfig_user_config
+
+ if [ "${SSID}" != "any" ] && type preassociate >/dev/null 2>/dev/null ; then
+ veinfo "Running preassociate function"
+ veindent
+ ( preassociate )
+ local e=$?
+ veoutdent
+ if [ ${e} -eq 0 ] ; then
+ veend 1 "preassociate \"${SSID}\" on ${IFACE} failed"
+ return 1
+ fi
+ fi
+
+ local timeout= i=0
+ eval timeout=\$associate_timeout_${IFVAR}
+ timeout=${timeout:-10}
+
+ [ ${timeout} -eq 0 ] \
+ && vewarn "WARNING: infinite timeout set for association on ${IFACE}"
+
+ while true; do
+ _has_carrier && break
+ sleep 1
+ [ ${timeout} -eq 0 ] && continue
+ i=$((${i} + 1))
+ [ ${i} -ge ${timeout} ] && return 1
+ done
+
+ if ! _has_carrier ; then
+ eend 1
+ return 1
+ fi
+ eend 0
+
+ if [ "${SSID}" = "any" ]; then
+ SSID="$(_get_ssid)"
+ iwconfig_associate
+ return $?
+ fi
+
+ iwconfig_report
+
+ if type postassociate >/dev/null 2>/dev/null ; then
+ veinfo "Running postassociate function"
+ veindent
+ ( postassociate )
+ veoutdent
+ fi
+
+ return 0
+}
+
+iwconfig_scan() {
+ local x= i=0 scan= quality=
+ einfo "Scanning for access points"
+ eindent
+
+ scan="$(LC_ALL=C ifconfig -v "${IFACE}" list scan 2>/dev/null | sed -e "1 d" -e "s/$/'/g" -e "s/^/'/g")"
+ while [ ${i} -lt 3 -o -z "${scan}" ] ; do
+ scan="${scan}${scan:+ }$(LC_ALL=C ifconfig -v "${IFACE}" scan 2>/dev/null | sed -e "1 d" -e "s/$/'/g" -e "s/^/'/g")"
+ i=$((${i} + 1))
+ done
+
+ local OIFS=$IFS
+ APS=-1
+ eval set -- ${scan}
+ for line in "$@" ; do
+ APS=$((${APS} + 1))
+ set -- ${line}
+ while true ; do
+ case "$1" in
+ *:*:*:*:*:*) break ;;
+ esac
+ eval SSID_${APS}="\"\${SSID_${APS}}\${SSID_${APS}:+ }$1\""
+ shift
+ done
+ eval MAC_${APS}="$(echo "$1" | tr '[:lower:]' '[:upper:]')"
+ eval CHAN_${APS}=$2
+ quality=${4%:*}
+ shift ; shift ; shift ; shift ; shift
+ eval CAPS_${APS}=$*
+
+ # Add 1000 for managed nodes as we prefer them to adhoc
+ set -- $*
+ case "$1" in
+ *E*) eval QUAL_${APS}=$((${quality} + 1000)) ;;
+ *) eval QUAL_${APS}=\$quality ;;
+ esac
+ done
+
+ if [ -z "${MAC_0}" ]; then
+ ewarn "no access points found"
+ eoutdent
+ return 1
+ fi
+
+ # Sort based on quality
+ local i=0 k=1 a= b= x= t=
+ while [ ${i} -lt ${APS} ] ; do
+ k=$((${i} + 1))
+ while [ ${k} -le ${APS} ] ; do
+ eval a=\$QUALITY_${i}
+ [ -z "${a}" ] && break
+ eval b=\$QUALITY_${k}
+ if [ -n "${b}" -a "${a}" -lt "${b}" ] ; then
+ for x in MAC SSID CHAN QUALITY CAPS ; do
+ eval t=\$${x}_${i}
+ eval ${x}_${i}=\$${x}_${k}
+ eval ${x}_${k}=\$t
+ done
+ fi
+ k=$((${k} + 1))
+ done
+ i=$((${i} + 1))
+ done
+
+ # Strip any duplicates
+ local i=0 k=1 a= b=
+ while [ ${i} -lt ${APS} ] ; do
+ k=$((${i} + 1))
+ while [ ${k} -le ${APS} ] ; do
+ eval a=\$MAC_${i}
+ eval b=\$MAC_${k}
+ if [ "${a}" = "${b}" ] ; then
+ eval a=\$QUALITY_${i}
+ eval b=\$QUALITY_${k}
+ if [ -n "${a}" -a -n "${b}" ] ; then
+ if [ ${a} -ge ${b} ] ; then
+ unset MAC_${k} SSID_${k} CHAN_${k} QUALITY_${k} CAPS_${k}
+ else
+ unset MAC_${i} SSID_${i} CHAN_${i} QUALITY_${i} CAPS_${i}
+ fi
+ else
+ unset MAC_${k} SSID_${k} CHAN_${k} QUALITY_${k} CAPS_${k}
+ fi
+ fi
+ k=$((${k} + 1))
+ done
+ i=$((${i} + 1))
+ done
+
+ local i=0 e= m= black= s=
+ eval "$(_get_array "blacklist_aps")"
+ black="$@"
+
+ while [ ${i} -le ${APS} ] ; do
+ eval x=\$MAC_${i}
+ if [ -z "${x}" ] ; then
+ i=$((${i} + 1))
+ continue
+ fi
+
+ eval m=\$MODE_${i}
+ [ -n "${m}" ] && m=", ${m}"
+ eval s=\$SSID_${i}
+ eval q=\$QUALITY_${i}
+ eval e=\$CAPS_${i}
+ case "${e}" in
+ [EI]P*) e=", encrypted" ;;
+ *) e="" ;;
+ esac
+ if [ -z "${s}" ] ; then
+ einfo "Found ${x}${m}${e}"
+ else
+ einfo "Found \"${s}\" at ${x}${m}${e}"
+ fi
+
+ x="$(echo "${x}" | sed -e 's/://g')"
+ eval x=\$mac_ssid_${x}
+ if [ -n "${x}" ] ; then
+ eval SSID_${i}=\$x
+ s=${x}
+ eindent
+ einfo "mapping to \"${x}\""
+ eoutdent
+ fi
+
+ eval "$(_get_array "blacklist_aps")"
+ for x in "$@" ; do
+ if [ "${x}" = "${s}" ] ; then
+ ewarn "${s} has been blacklisted - not connecting"
+ unset SSID_${i} MAC_${i} CHAN_${i} QUALITY_${i} CAPS_${i}
+ fi
+ done
+ i=$((${i} + 1))
+ done
+ eoutdent
+ return 0
+}
+
+iwconfig_force_preferred() {
+ [ -z "${preferred_aps}" ] && return 1
+
+ ewarn "Trying to force preferred in case they are hidden"
+ eval "(_get_array "preferred_aps")"
+ local ssid=
+ for ssid in "$@"; do
+ local found_AP=false i=0 e=
+ while [ ${i} -le ${APS} ] ; do
+ eval e=\$SSID_${i}
+ if [ "${e}" = "${ssid}" ] ; then
+ found_AP=true
+ break
+ fi
+ i=$((${i} + 1))
+ done
+ if ! ${found_AP} ; then
+ SSID=${e}
+ iwconfig_associate && return 0
+ fi
+ done
+
+ ewarn "Failed to associate with any preferred access points on ${IFACE}"
+ return 1
+}
+
+iwconfig_connect_preferred() {
+ local essid= i=0 mode= mac= caps= freq= chan=
+
+ eval "$(_get_array preferred_aps)"
+ for essid in "$@"; do
+ while [ ${i} -le ${APS} ] ; do
+ eval e=\$SSID_${i}
+ if [ "${e}" = "${essid}" ] ; then
+ SSID=${e}
+ eval mac=\$MAC_${i}
+ eval caps=\$CAPS_${i}
+ eval freq=\$FREQ_${i}
+ eval chan=\$CHAN_${i}
+ iwconfig_associate "${mac}" \
+ "${chan}" "${caps}" && return 0
+ fi
+ i=$((${i} + 1))
+ done
+ done
+
+ return 1
+}
+
+iwconfig_connect_not_preferred() {
+ local essid= i=0 mode= mac= caps= freq= chan= pref=
+
+ while [ ${i} -le ${APS} ] ; do
+ eval e=\$SSID_${i}
+ if [ -z "${e}" ] ; then
+ i=$((${i} + 1))
+ continue
+ fi
+
+ eval "$(_get_array preferred_aps)"
+ pref=false
+ for essid in "$@" ; do
+ if [ "${e}" = "${essid}" ] ; then
+ pref=true
+ break
+ fi
+ done
+
+ if ! ${pref} ; then
+ SSID=${e}
+ eval mac=\$MAC_${i}
+ eval caps=\$CAPS_${i}
+ eval freq=\$FREQ_${i}
+ eval chan=\$CHAN_${i}
+ iwconfig_associate "${mac}" \
+ "${chan}" "${caps}" && return 0
+ fi
+ i=$((${i} + 1))
+ done
+
+ return 1
+}
+
+iwconfig_defaults() {
+ # Set some defaults
+ #ifconfig "${iface}" txpower 100 2>/dev/null
+ ifconfig "${IFACE}" bssid -
+ ifconfig "${IFACE}" ssid -
+ ifconfig "${IFACE}" authmode open
+ ifconfig "${IFACE}" -mediaopt adhoc
+ ifconfig "${IFACE}" -mediaopt hostap
+}
+
+iwconfig_configure() {
+ local x APS
+ eval SSID=\$ssid_${IFVAR}
+
+ # Setup ad-hoc mode?
+ eval x=\$mode_${IFVAR}
+ x=${x:-managed}
+ case "${x}" in
+ ad-hoc|adhoc|hostap|master) iwconfig_setup_specific "${x}" ;;
+ esac
+
+ if [ "${x}" != "managed" -a "${x}" != "auto" ] ; then
+ eerror "Only managed, ad-hoc, master and auto modes are supported"
+ return 1
+ fi
+
+ # Has an ESSID been forced?
+ if [ -n "${SSID}" ]; then
+ iwconfig_set_mode "${x}"
+ iwconfig_associate && return 0
+ [ "${SSID}" = "any" ] && iwconfig_force_preferred && return 0
+
+ eval SSID=\$adhoc_ssid_${IFVAR}
+ if [ -n "${SSID}" ]; then
+ iwconfig_setup_specific adhoc
+ return $?
+ fi
+ return 1
+ fi
+
+ # Do we have a preferred Access Point list specific to the interface?
+# x="preferred_aps_${ifvar}[@]"
+# [[ -n ${!x} ]] && preferred_aps=( "${!x}" )
+
+# # Do we have a blacklist Access Point list specific to the interface?
+# x="blacklist_aps_${ifvar}[@]"
+# [[ -n ${!x} ]] && blacklist_aps=( "${!x}" )
+
+ # Are we forcing preferred only?
+ eval x=\$associate_order_${IFVAR}
+ [ -n "${x}" ] && associate_order=${x}
+ associate_order=${associate_order:-any}
+ if [ "${associate_order}" = "forcepreferredonly" ]; then
+ iwconfig_force_preferred && return 0
+ else
+ iwconfig_scan || return 1
+ iwconfig_connect_preferred && return 0
+ [ "${associate_order}" = "forcepreferred" ] || \
+ [ "${associate_order}" = "forceany" ] && \
+ iwconfig_force_preferred && return 0
+ [ "${associate_order}" = "any" ] || \
+ [ "${associate_order}" = "forceany" ] && \
+ iwconfig_connect_not_preferred && return 0
+ fi
+
+ e="associate with"
+ [ -z "${MAC_0}" ] && e="find"
+ [ "${preferred_aps}" = "force" ] || \
+ [ "${preferred_aps}" = "forceonly" ] && \
+ e="force"
+ e="Couldn't ${e} any access points on ${IFACE}"
+
+ eval SSID=\$adhoc_ssid_${IFVAR}
+ if [ -n "${SSID}" ]; then
+ ewarn "${e}"
+ iwconfig_setup_specific adhoc
+ return $?
+ fi
+
+ eerror "${e}"
+ return 1
+}
+
+iwconfig_pre_start() {
+ # We don't configure wireless if we're being called from
+ # the background
+ ${IN_BACKGROUND} && return 0
+
+ save_options "SSID" ""
+ _exists || return 0
+
+ if ! _is_wireless ; then
+ veinfo "${IFACE} is not wireless"
+ return 0
+ fi
+
+ iwconfig_defaults
+ iwconfig_user_config
+
+ # Set the base metric to be 2000
+ metric=2000
+
+ einfo "Configuring wireless network for ${IFACE}"
+
+ if iwconfig_configure ; then
+ save_options "ESSID" "${ESSID}"
+ return 0
+ fi
+
+ eerror "Failed to configure wireless for ${IFACE}"
+ iwconfig_defaults
+ #iwconfig "${IFACE}" txpower 0 2>/dev/null
+ unset SSID SSIDVAR
+ _down
+ return 1
+}
+
+iwconfig_post_stop() {
+ ${IN_BACKGROUND} && return 0
+ _is_wireless || return 0
+ iwconfig_defaults
+ #iwconfig "${IFACE}" txpower 0 2>/dev/null
+}
+
+# vim: set ts=4
diff --git a/net.Linux/Makefile b/net.Linux/Makefile
new file mode 100644
index 00000000..3059f1e4
--- /dev/null
+++ b/net.Linux/Makefile
@@ -0,0 +1,8 @@
+DIR = /$(LIB)/rcscripts/net
+FILES = adsl.sh apipa.sh arping.sh bonding.sh br2684ctl.sh bridge.sh \
+ ccwgroup.sh clip.sh ifconfig.sh ifplugd.sh ip6to4.sh ipppd.sh \
+ iproute2.sh iwconfig.sh netplugd.sh pppd.sh pump.sh tuntap.sh \
+ udhcpc.sh vlan.sh
+
+TOPDIR = ..
+include $(TOPDIR)/default.mk
diff --git a/net.Linux/adsl.sh b/net.Linux/adsl.sh
new file mode 100644
index 00000000..a6e74c9d
--- /dev/null
+++ b/net.Linux/adsl.sh
@@ -0,0 +1,71 @@
+# Copyright 2004-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+adsl_depend() {
+ program /usr/sbin/adsl-start /usr/sbin/pppoe-start
+ before dhcp
+}
+
+adsl_setup_vars() {
+ local startstop="$2" cfgexe=
+
+ if [ -x /usr/sbin/pppoe-start ]; then
+ exe="/usr/sbin/pppoe-${startstop}"
+ cfgexe=pppoe-setup
+ else
+ exe="/usr/sbin/adsl-${startstop}"
+ cfgexe=adsl-setup
+ fi
+
+ # Decide which configuration to use. Hopefully there is an
+ # interface-specific one
+ cfgfile="/etc/ppp/pppoe-${IFACE}.conf"
+ [ -f "${cfgfile}" ] || cfgfile="/etc/ppp/pppoe.conf"
+
+ if [ ! -f "${cfgfile}" ]; then
+ eerror "no pppoe.conf file found!"
+ eerror "Please run ${cfgexe} to create one"
+ return 1
+ fi
+
+ return 0
+}
+
+adsl_start() {
+ local exe= cfgfile= user=
+
+ adsl_setup_vars start || return 1
+
+ # Might or might not be set in conf.d/net
+ eval user=\$adsl_user_${IFVAR}
+
+ # Start ADSL with the cfgfile, but override ETH and PIDFILE
+ einfo "Starting ADSL for ${IFACE}"
+ (
+ cat "${cfgfile}";
+ echo "ETH=${IFACE}";
+ echo "PIDFILE=/var/run/rp-pppoe-${IFACE}.pid";
+ [ -n "${user}" ] && echo "USER=${user}";
+ ) | ${exe} >/dev/null
+ eend $?
+}
+
+adsl_stop() {
+ local exe= cfgfile=
+
+ [ ! -f /var/run/rp-pppoe-"${IFACE}".pid ] && return 0
+
+ adsl_setup_vars stop || return 1
+
+ einfo "Stopping ADSL for ${IFACE}"
+ (
+ cat "${cfgfile}";
+ echo "ETH=${IFACE}";
+ echo "PIDFILE=/var/run/rp-pppoe-${IFACE}.pid";
+ ) | ${exe} >/dev/null
+ eend $?
+
+ return 0
+}
+
+# vim: set ts=4 :
diff --git a/net.Linux/apipa.sh b/net.Linux/apipa.sh
new file mode 100644
index 00000000..2a71b608
--- /dev/null
+++ b/net.Linux/apipa.sh
@@ -0,0 +1,46 @@
+# Copyright 2004-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+apipa_depend() {
+ program /sbin/arping
+}
+
+_random() {
+ if [ -n "${BASH}" ] ; then
+ echo "${RANDOM}"
+ else
+ uuidgen | sed -n -e 's/[^[:digit:]]//g' -e 's/\(^.\{1,7\}\).*/\1/p'
+ fi
+}
+
+apipa_start() {
+ local iface="$1" i1= i2= addr= i=0
+
+ _exists true || return 1
+
+ einfo "Searching for free addresses in 169.254.0.0/16"
+ eindent
+
+ while [ ${i} -lt 64516 ]; do
+ i1=$((($(_random) % 255) + 1))
+ i2=$((($(_random) % 255) + 1))
+
+ addr="169.254.${i1}.${i2}"
+ vebegin "${addr}/16"
+ if ! arping_address "${addr}" ; then
+ eval config_${config_index}="\"${addr}/16 broadcast 169.254.255.255\""
+ config_index=$((${config_index} - 1))
+ veend 0
+ eoutdent
+ return 0
+ fi
+
+ i=$((${i} + 1))
+ done
+
+ eerror "No free address found!"
+ eoutdent
+ return 1
+}
+
+# vim: set ts=4 :
diff --git a/net.Linux/arping.sh b/net.Linux/arping.sh
new file mode 100644
index 00000000..763cb4ce
--- /dev/null
+++ b/net.Linux/arping.sh
@@ -0,0 +1,111 @@
+# Copyright 2004-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+arping_depend() {
+ program /sbin/arping
+ before interface
+}
+
+arping_address() {
+ local ip=${1%%/*} mac="$2" foundmac= i= w= opts=
+
+ # We only handle IPv4 addresses
+ case "${ip}" in
+ 0.0.0.0|0) return 1 ;;
+ *.*.*.*) ;;
+ *) return 1 ;;
+ esac
+
+ # We need to bring the interface up to test
+ _exists "${iface}" || return 1
+ _up "${iface}"
+
+ eval w=\$arping_wait_${IFVAR}
+ [ -z "${w}" ] && w=${arping_wait:-5}
+
+ [ -z "$(_get_inet_address)" ] && opts="${opts} -D"
+
+ foundmac="$(arping -w "${w}" ${opts} -f -I "${IFACE}" "${ip}" 2>/dev/null | \
+ sed -n -e 'y/abcdef/ABCDEF/' -e 's/.*\[\([^]]*\)\].*/\1/p')"
+ [ -z "${foundmac}" ] && return 1
+
+ if [ -n "${mac}" ] ; then
+ if [ "${mac}" != "${foundmac}" ] ; then
+ vewarn "Found ${ip} but MAC ${foundmac} does not match"
+ return 1
+ fi
+ fi
+
+ return 0
+}
+
+arping_start() {
+ local gateways= x= conf= i=
+ einfo "Pinging gateways on ${IFACE} for configuration"
+
+ eval $(_get_array "gateways_${IFVAR}")
+ if [ -z "$@" ] ; then
+ eerror "No gateways have been defined (gateways_${IFVAR}=\"...\")"
+ return 1
+ fi
+
+ eindent
+
+ for x in "$@"; do
+ eval set -- "${x}"
+ local ip=$1 mac=$2 extra=
+
+ if [ -n "${mac}" ] ; then
+ mac="$(echo "${mac}" | tr '[:lower:]' '[:upper:]')"
+ extra="(MAC ${mac})"
+ fi
+
+ vebegin "${ip} ${extra}"
+ if arping_address "${ip}" "${mac}" ; then
+ local OIFS=$IFS SIFS=${IFS-y}
+ IFS=.
+ for i in ${ip} ; do
+ if [ "${#i}" = "2" ] ; then
+ conf="${conf}0${i}"
+ elif [ "${#i}" = "1" ] ; then
+ conf="${conf}00${i}"
+ else
+ conf="${conf}${i}"
+ fi
+ done
+ if [ "${SIFS}" = "y" ] ; then
+ IFS=$OFIS
+ else
+ unset IFS
+ fi
+ [ -n "${mac}" ] && conf="${conf}_$(echo "${mac}" | sed -e 's/://g')"
+
+ veend 0
+ eoutdent
+ veinfo "Configuring ${IFACE} for ${ip} ${extra}"
+ _configure_variables "${conf}"
+
+ # Call the system module as we've aleady passed it by ....
+ # And it *has* to be pre_start for other things to work correctly
+ system_pre_start
+
+ # Ensure that we have a valid config - ie arping is no longer there
+ eval $(_get_array "config_${IFVAR}")
+ for i in "$@" ; do
+ if [ "${i}" = "arping" ] ; then
+ veend 1 "No config found for ${ip} (config_${conf}=\"...\")"
+ continue 2
+ fi
+ done
+
+ _load_config
+ return 0
+ fi
+ veend 1
+ done
+
+ eoutdent
+ return 1
+}
+
+# vim: set ts=4 :
diff --git a/net.Linux/bonding.sh b/net.Linux/bonding.sh
new file mode 100644
index 00000000..36be943f
--- /dev/null
+++ b/net.Linux/bonding.sh
@@ -0,0 +1,100 @@
+# Copyright 2004-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+bonding_depend() {
+ before interface macchanger
+ program /sbin/ifenslave
+}
+
+_config_vars="$_config_vars slaves"
+
+_is_bond() {
+ [ -f "/proc/net/bonding/${IFACE}" ]
+}
+
+bonding_pre_start() {
+ local s= slaves=
+
+ eval $(_get_array "slaves_${IFACE}")
+ [ $# = "0" ] && return 0
+
+ # Load the kernel module if required
+ if [ ! -d /proc/net/bonding ] ; then
+ if ! modprobe bonding ; then
+ eerror "Cannot load the bonding module"
+ return 1
+ fi
+ fi
+
+ # We can create the interface name we like now, but this
+ # requires sysfs
+ if ! _exists && [ -d /sys/class/net ] ; then
+ echo "+${IFACE}" > /sys/class/net/bonding_masters
+ fi
+ _exists true || return 1
+
+ if ! _is_bond ; then
+ eerror "${IFACE} is not capable of bonding"
+ return 1
+ fi
+
+ ebegin "Adding slaves to ${IFACE}"
+ eindent
+ einfo "$@"
+
+ # Check that our slaves exist
+ (
+ for IFACE in "$@" ; do
+ _exists true || return 1
+ done
+
+ # Must force the slaves to a particular state before adding them
+ for IFACE in "$@" ; do
+ _delete_addresses
+ _up
+ done
+ )
+
+ # now force the master to up
+ _up
+
+ # finally add in slaves
+ eoutdent
+ /sbin/ifenslave "${IFACE}" $@ >/dev/null
+ eend $?
+
+ return 0 #important
+}
+
+bonding_stop() {
+ _is_bond || return 0
+
+ local slaves= s=
+ slaves=$( \
+ sed -n -e 's/^Slave Interface: //p' "/proc/net/bonding/${IFACE}" \
+ | tr '\n' ' ' \
+ )
+ [ -z "${slaves}" ] && return 0
+
+ # remove all slaves
+ ebegin "Removing slaves from ${IFACE}"
+ eindent
+ einfo "${slaves}"
+ eoutdent
+ /sbin/ifenslave -d "${IFACE}" ${slaves}
+
+ # reset all slaves
+ (
+ for IFACE in ${slaves}; do
+ if _exists ; then
+ _delete_addresses
+ _down
+ fi
+ done
+ )
+
+ eend 0
+ return 0
+}
+
+# vim: set ts=4 :
diff --git a/net.Linux/br2684ctl.sh b/net.Linux/br2684ctl.sh
new file mode 100644
index 00000000..928473b3
--- /dev/null
+++ b/net.Linux/br2684ctl.sh
@@ -0,0 +1,50 @@
+# Copyright 2004-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+br2684ctl_depend() {
+ before ppp
+ program start /sbin/br2684ctl
+}
+
+_config_vars="$_config_vars bridge bridge_add brctl"
+
+br2684ctl_pre_start() {
+ local opts=
+ eval opts=\$br2684ctl_${IFVAR}
+ [ -z "${opts}" ] && return 0
+
+ if [ "${IFACE#nas[0-9]*}" = "${IFACE}" ] ; then
+ eerror "Interface must be called nas[0-9] for RFC 2684 Bridging"
+ return 1
+ fi
+
+ case " ${opts} " in
+ *" -b "*|*" -c "*)
+ eerror "The -b and -c options are not allowed for br2684ctl_${IVAR}"
+ return 1
+ ;;
+ *" -a "*) ;;
+ *)
+ eerror "-a option (VPI and VCI) is required in br2684ctl_${IFVAR}"
+ return 1
+ ;;
+ esac
+
+ einfo "Starting RFC 2684 Bridge control on ${IFACE}"
+ start-stop-daemon --start --exec /sbin/br2684ctl --background \
+ --make-pidfile --pidfile "/var/run/br2684ctl-${IFACE}.pid" \
+ -- -c "${IFACE#nas*}" ${opts}
+ eend $?
+}
+
+br2684ctl_post_stop() {
+ local pidfile="/var/run/br2684ctl-${IFACE}.pid"
+ [ -e "${pidfile}" ] || return 0
+
+ einfo "Stopping RFC 2684 Bridge control on ${IFACE}"
+ start-stop-daemon --stop --quiet \
+ --exec /sbin/br2684ctl --pidfile "${pidfile}"
+ eend $?
+}
+
+# vim: set ts=4 :
diff --git a/net.Linux/bridge.sh b/net.Linux/bridge.sh
new file mode 100644
index 00000000..89d5687e
--- /dev/null
+++ b/net.Linux/bridge.sh
@@ -0,0 +1,113 @@
+# Copyright 2004-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+bridge_depend() {
+ before interface macnet
+ program /sbin/brctl
+}
+
+_config_vars="$_config_vars bridge bridge_add brctl"
+
+_is_bridge() {
+ brctl show 2>/dev/null | grep -q "^${IFACE}[[:space:]]"
+}
+
+bridge_pre_start() {
+ local ports= brif= opts= iface="${IFACE}" e= x=
+ eval $(_get_array "bridge_${IFVAR}")
+ ports="$@"
+ eval brif=\$bridge_add_${IFVAR}
+ eval $(_get_array "brctl_${IFVAR}")
+ opts="$@"
+ [ -z "${ports}" -a -z "${brif}" -a -z "${opts}" ] && return 0
+
+ [ -n "${ports}" ] && bridge_post_stop
+
+ (
+ if [ -z "${ports}" -a -n "${brif}" ] ; then
+ ports="${IFACE}"
+ IFACE="${brif}"
+ else
+ ports="${ports}"
+ metric=1000
+ fi
+
+ if ! _is_bridge ; then
+ ebegin "Creating bridge ${IFACE}"
+ if ! brctl addbr "${IFACE}" ; then
+ eend 1
+ return 1
+ fi
+
+ eval set -- ${opts}
+ for x in "$@" ; do
+ case " ${x} " in
+ *" ${IFACE} "*) ;;
+ *) x="${x} ${IFACE}" ;;
+ esac
+ brctl ${x}
+ done
+ fi
+
+ if [ -n "${ports}" ] ; then
+ einfo "Adding ports to ${IFACE}"
+ eindent
+
+ eval set -- ${ports}
+ for x in "$@" ; do
+ ebegin "${x}"
+ if ! ifconfig "${x}" promisc up && brctl addif "${IFACE}" "${x}" ; then
+ ifconfig "${x}" -promisc 2>/dev/null
+ eend 1
+ return 1
+ fi
+ eend 0
+ done
+ eoutdent
+ fi
+ )
+}
+
+bridge_post_stop() {
+ local port= ports= delete=false extra=
+
+ if _is_bridge ; then
+ ebegin "Destroying bridge ${IFACE}"
+ _down
+ ports="$( brctl show 2>/dev/null | \
+ sed -n -e '/^'"${IFACE}"'[[:space:]]/,/^\S/ { /^\('"${IFACE}"'[[:space:]]\|\t\)/s/^.*\t//p }')"
+ delete=true
+ iface=${IFACE}
+ eindent
+ else
+ # Work out if we're added to a bridge for removal or not
+ eval set -- $(brctl show 2>/dev/null | sed -e "s/'/'\\\\''/g" -e "s/$/'/g" -e "s/^/'/g")
+ local line=
+ for line in "$@" ; do
+ set -- ${line}
+ if [ "$3" = "${IFACE}" ] ; then
+ iface=$1
+ break
+ fi
+ done
+ [ -z "${iface}" ] && return 0
+ extra=" from ${iface}"
+ fi
+
+ for port in ${ports} ; do
+ ebegin "Removing port ${port}${extra}"
+ ifconfig "${port}" -promisc
+ brctl delif "${iface}" "${port}"
+ eend $?
+ done
+
+ if ${delete} ; then
+ eoutdent
+ brctl delbr "${iface}"
+ eend $?
+ fi
+
+ return 0
+}
+
+# vim: set ts=4 :
diff --git a/net.Linux/ccwgroup.sh b/net.Linux/ccwgroup.sh
new file mode 100644
index 00000000..1cba04cb
--- /dev/null
+++ b/net.Linux/ccwgroup.sh
@@ -0,0 +1,66 @@
+# Copyright 2006-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# Contributed by Roy Marples (uberlord@gentoo.org)
+
+_config_vars="$_config_vars ccwgroup"
+
+ccwgroup_depend() {
+ before interface
+}
+
+ccwgroup_pre_start() {
+ eval $(_get_array "ccwgroup_${IFVAR}")
+ [ $# = "0" ] && return 0
+
+ if [ ! -d /sys/bus/ccwgroup ] ; then
+ modprobe qeth
+ if [ ! -d /sys/bus/ccwgroup ] ; then
+ eerror "ccwgroup support missing in kernel"
+ return 1
+ fi
+ fi
+
+ einfo "Enabling ccwgroup on ${IFACE}"
+ local x= ccw= first= layer2=
+ for x in "$@" ; do
+ [ -z "${first}" ] && first=${x}
+ ccw="${ccw}${ccw:+,}${x}"
+ done
+ if [ -e /sys/devices/qeth/"${first}" ] ; then
+ echo "0" > /sys/devices/qeth/"${first}"/online
+ else
+ echo "${ccw}" > /sys/bus/ccwgroup/drivers/qeth/group
+ fi
+ eval layer2=\$qeth_layer2_${IFVAR}
+ echo "${layer2:-0}" > /sys/devices/qeth/"${first}"/layer2
+ echo "1" > /sys/devices/qeth/"${first}"/online
+ eend $?
+}
+
+ccwgroup_pre_stop() {
+ # Erase any existing ccwgroup to be safe
+ save_options ccwgroup_device ""
+
+ [ ! -L /sys/class/net/"${FACE}"/driver ] && return 0
+ local driver="$(readlink /sys/class/net/"${IFACE}"/driver)"
+ case "${diver}" in
+ */bus/ccwgroup/*) ;;
+ *) return 0 ;;
+ esac
+
+ local device="$(readlink /sys/class/net/"${IFACE}"/device)"
+ device=${device##*/}
+ save_options ccwgroup_device "${device}"
+}
+
+ccwgroup_post_stop() {
+ local device="$(get_options ccwgroup_device)"
+ [ -z "${device}" ] && return 0
+
+ einfo "Disabling ccwgroup on ${iface}"
+ echo "0" > /sys/devices/qeth/"${device}"/online
+ echo "1" > /sys/devices/qeth/"${device}"/ungroup
+ eend $?
+}
+
+# vim: set ts=4 :
diff --git a/net.Linux/clip.sh b/net.Linux/clip.sh
new file mode 100644
index 00000000..d3ec4fd8
--- /dev/null
+++ b/net.Linux/clip.sh
@@ -0,0 +1,212 @@
+# Copyright 2005-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+clip_depend() {
+ program /usr/sbin/atmsigd
+ before interface
+}
+
+_config_vars="$_config_vars clip"
+
+# This starts a service. Albeit atmsigd, ilmid and atmarpd do allow for back-
+# grounding through the -b option, its usage causes them to be sensible to
+# SIGHUP, which is sent to all daemons when console detaches right after
+# startup. This is probably due to the fact that these programs don't detach
+# themself from the controlling terminal when backgrounding... The only way I
+# see to overcame this is to use the --background option in start-stop-daemon,
+# which is reported as a "last resort" method, but it acts correctly about this.
+atmclip_svc_start() {
+ ebegin "Starting $2 Daemon ($1)"
+ start-stop-daemon --start \
+ --background \
+ --make-pidfile --pidfile "/var/run/$1.pid" \
+ --exec "/usr/sbin/$1" -- -l syslog
+ eend $?
+}
+
+atmclip_svcs_start() {
+ einfo "First CLIP instance: starting ATM CLIP daemons"
+ eindent
+
+ if [ "${clip_full:-yes}" = "yes" ]; then
+ atmclip_svc_start atmsigd "Signaling" && \
+ atmclip_svc_start ilmid "Integrated Local Management Interface" && \
+ atmclip_svc_start atmarpd "Address Resolution Protocol"
+ else
+ atmclip_svc_start atmarpd "Address Resolution Protocol"
+ fi
+
+ local r=$?
+
+ eoutdent
+ return ${r}
+}
+
+atmclip_svc_stop() {
+ ebegin "Stopping $2 Daemon ($1)"
+ start-stop-daemon --stop --quiet \
+ --pidfile "/var/run/$1.pid" \
+ --exec "/usr/sbin/$1"
+ eend $?
+}
+
+atmclip_svcs_stop() {
+ einfo "Last CLIP instance: stopping ATM CLIP daemons"
+ eindent
+
+ # Heartake operation!
+ sync
+
+ atmclip_svc_stop atmarpd "Address Resolution Protocol"
+ if [ "${clip_full:-yes}" = "yes" ]; then
+ atmclip_svc_stop ilmid "Integrated Local Management Interface"
+ atmclip_svc_stop atmsigd "Signaling"
+ fi
+
+ eoutdent
+}
+
+are_atmclip_svcs_running() {
+ is_daemon_running atmarpd || return 1
+ if [[ ${clip_full:-yes} == "yes" ]]; then
+ is_daemon_running ilmid || return 1
+ is_daemon_running atmsigd || return 1
+ fi
+
+ return 0
+}
+
+atmarp() {
+ /usr/sbin/atmarp "$@"
+}
+
+clip_pre_start() {
+ eval $(_get_array "clip_${IFVAR}")
+ [ -z "$@" ] && return 0
+
+ if [ ! -r /proc/net/atm/arp ] ; then
+ modprobe clip && sleep 2
+ if [ ! -r /proc/net/atm/arp ] ; then
+ eerror "You need first to enable kernel support for ATM CLIP"
+ return 1
+ fi
+ fi
+
+ local started_here=
+ if ! are_atmclip_svcs_running ; then
+ atmclip_svcs_start || return 1
+ started_here=1
+ fi
+
+ if ! _exists ; then
+ ebegin "Creating CLIP interface ${IFACE}"
+ atmarp -c "${IFACE}"
+ if ! eend $? ; then
+ [ -z "${started_here}" ] && atmclip_svcs_stop
+ return 1
+ fi
+ fi
+
+ return 0
+}
+
+clip_post_start() {
+ eval $(_get_array "clip_${IFVAR}")
+ [ -z "$@" ] && return 0
+
+ are_atmclip_svcs_running || return 1
+
+ # The atm tools (atmarpd?) are silly enough that they would not work with
+ # iproute2 interface setup as opposed to the ifconfig one.
+ # The workaround is to temporarily toggle the interface state from up
+ # to down and then up again, without touching its address. This (should)
+ # work with both iproute2 and ifconfig.
+ _down
+ _up
+
+ # Now the real thing: create a PVC with our peer(s).
+ # There are cases in which the ATM interface is not yet
+ # ready to establish new VCCs. In that cases, atmarp would
+ # fail. Here we allow 10 retries to happen every 2 seconds before
+ # reporting problems. Also, when no defined VC can be established,
+ # we stop the ATM daemons.
+ local has_failures= i=
+ for i in "$@" ; do
+ set -- ${i}
+ local peerip="$1"; shift
+ local ifvpivci="$1"; shift
+ ebegin "Creating PVC ${ifvpivci} for peer ${peerip}"
+
+ local nleftretries=10 emsg= ecode=
+ while [ ${nleftretries} -gt 0 ] ; do
+ nleftretries=$((${nleftretries} - 1))
+ emsg="$(atmarp -s "${peerip}" "${ifvpivci}" "$@" 2>&1)"
+ ecode=$? && break
+ sleep 2
+ done
+
+ if ! eend ${ecode} ; then
+ eerror "Creation failed for PVC ${ifvpivci}: ${emsg}"
+ has_failures=1
+ fi
+ done
+
+ if [ -n "${has_failures}" ]; then
+ clip_pre_stop "${iface}"
+ clip_post_stop "${iface}"
+ return 1
+ else
+ return 0
+ fi
+}
+
+clip_pre_stop() {
+ are_atmclip_svcs_running || return 0
+
+ # We remove all the PVCs which may have been created by
+ # clip_post_start for this interface. This shouldn't be
+ # needed by the ATM stack, but sometimes I got a panic
+ # killing CLIP daemons without previously vacuuming
+ # every active CLIP PVCs.
+ # The linux 2.6's ATM stack is really a mess...
+ local itf= t= encp= idle= ipaddr= left=
+ einfo "Removing PVCs on this interface"
+ eindent
+ {
+ read left && \
+ while read itf t encp idle ipaddr left ; do
+ if [ "${itf}" = "${IFACE}" ]]; then
+ ebegin "Removing PVC to ${ipaddr}"
+ atmarp -d "${ipaddr}"
+ eend $?
+ fi
+ done
+ } < /proc/net/atm/arp
+ eoutdent
+}
+
+# Here we should teorically delete the interface previously created in the
+# clip_pre_start function, but there is no way to "undo" an interface creation.
+# We can just leave the interface down. "ifconfig -a" will still list it...
+# Also, here we can stop the ATM CLIP daemons if there is no other CLIP PVC
+# outstanding. We check this condition by inspecting the /proc/net/atm/arp file.
+clip_post_stop() {
+ are_atmclip_svcs_running || return 0
+
+ local itf= left= hasothers=
+ {
+ read left && \
+ while read itf left ; do
+ if [ "${itf}" != "${IFACE}" ] ; then
+ hasothers=1
+ break
+ fi
+ done
+ } < /proc/net/atm/arp
+
+ if [ -z "${hasothers}" ] ; then
+ atmclip_svcs_stop || return 1
+ fi
+}
+
+# vim: set ts=4 :
diff --git a/net.Linux/ifconfig.sh b/net.Linux/ifconfig.sh
new file mode 100644
index 00000000..637c42f5
--- /dev/null
+++ b/net.Linux/ifconfig.sh
@@ -0,0 +1,239 @@
+# Copyright 2004-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+ifconfig_depend() {
+ program /sbin/ifconfig
+ provide interface
+}
+
+_get_mac_address() {
+ local mac=$(LC_ALL=C ifconfig "${IFACE}" | \
+ sed -n -e 's/.* HWaddr \(..:..:..:..:..:..\).*/\1/p')
+
+
+ case "${mac}" in
+ 00:00:00:00:00:00) ;;
+ 44:44:44:44:44:44) ;;
+ FF:FF:FF:FF:FF:FF) ;;
+ "") ;;
+ *) echo "${mac}"; return 0 ;;
+ esac
+
+ return 1
+}
+
+_up() {
+ ifconfig "${IFACE}" up
+}
+
+_down() {
+ ifconfig "${IFACE}" down
+}
+
+_exists() {
+ grep -Eq "^[[:space:]]*${IFACE}:[[:space:]]*" /proc/net/dev
+}
+
+_ifindex() {
+ local line= i=-2
+ while read line ; do
+ i=$((${i} + 1))
+ [ ${i} -lt 1 ] && continue
+ case "${line}" in
+ "${IFACE}: "*) echo "${i}"; return 0;;
+ esac
+ done < /proc/net/dev
+ return 1
+}
+
+_is_wireless() {
+ # Support new sysfs layout
+ [ -d /sys/class/net/"${IFACE}"/wireless ] && return 0
+
+ [ ! -e /proc/net/wireless ] && return 1
+ grep -Eq "^[[:space:]]*${IFACE}:[[:space:]]+" /proc/net/wireless
+}
+
+_get_inet_address() {
+ set -- $(LC_ALL=C ifconfig "${IFACE}" |
+ sed -n -e 's/.*inet addr:\([^ ]*\).*Mask:\([^ ]*\).*/\1 \2/p')
+ echo -n "$1"
+ shift
+ echo "/$(_netmask2cidr "$1")"
+}
+
+_get_inet_addresses() {
+ local iface=${IFACE} i=0
+ local addrs="$(_get_inet_address)"
+
+ while true ; do
+ local IFACE="${iface}:${i}"
+ _exists || break
+ local addr="$(_get_inet_address)"
+ [ -n "${addr}" ] && addrs="${addrs}${addrs:+ }${addr}"
+ i=$((${i} + 1))
+ done
+ echo "${addrs}"
+}
+
+_cidr2netmask() {
+ local cidr="$1" netmask="" done=0 i=0 sum=0 cur=128
+ local octets= frac=
+
+ local octets=$((${cidr} / 8))
+ local frac=$((${cidr} % 8))
+ while [ ${octets} -gt 0 ] ; do
+ netmask="${netmask}.255"
+ octets=$((${octets} - 1))
+ done=$((${done} + 1))
+ done
+
+ if [ ${done} -lt 4 ] ; then
+ while [ ${i} -lt ${frac} ] ; do
+ sum=$((${sum} + ${cur}))
+ cur=$((${cur} / 2))
+ i=$((i + 1))
+ done
+ netmask="${netmask}.${sum}"
+ done=$((${done} + 1))
+
+ while [ ${done} -lt 4 ] ; do
+ netmask="${netmask}.0"
+ done=$((${done} + 1))
+ done
+ fi
+
+ echo "${netmask#.*}"
+}
+
+_add_address() {
+ if [ "$1" = "127.0.0.1/8" -a "${IFACE}" = "lo" ] ; then
+ ifconfig "${IFACE}" "$@" 2>/dev/null
+ return 0
+ fi
+
+ case "$1" in
+ *:*) ifconfig "${IFACE}" inet6 add "$@"; return $?;;
+ esac
+
+ # IPv4 is tricky - ifconfig requires an aliased device
+ # for multiple addresses
+ local iface="${IFACE}"
+ if LC_ALL=C ifconfig "${iface}" | grep -Eq "\<inet addr:.*" ; then
+ # Get the last alias made for the interface and add 1 to it
+ i=$(ifconfig | sed '1!G;h;$!d' | grep -m 1 -o "^${iface}:[0-9]*" \
+ | sed -n -e 's/'"${iface}"'://p')
+ i=$((${i:-0} + 1))
+ iface="${iface}:${i}"
+ fi
+
+ # ifconfig doesn't like CIDR addresses
+ local ip="${1%%/*}" cidr="${1##*/}" netmask=
+ if [ -n "${cidr}" -a "${cidr}" != "${ip}" ]; then
+ netmask="$(_cidr2netmask "${cidr}")"
+ shift
+ set -- "${ip}" netmask "${netmask}" "$@"
+ fi
+
+# # Support iproute2 style config where possible
+# r="${config[@]}"
+# config=( ${r//brd +/} )
+# config=( "${config[@]//brd/broadcast}" )
+# config=( "${config[@]//peer/pointopoint}" )
+# fi
+
+ ifconfig "${iface}" "$@"
+}
+
+_add_route() {
+ if [ $# -eq 3 ] ; then
+ set -- "$1" "$2" gw "$3"
+ elif [ "$3" = "via" ] ; then
+ local one=$1 two=$2
+ shift ; shift; shift
+ set -- "${one}" "${two}" gw "$@"
+ fi
+
+ if [ -n "${metric}" ] ; then
+ set -- "$@" metric ${metric}
+ fi
+
+ route add "$@"
+}
+
+_delete_addresses() {
+ # We don't remove addresses from aliases
+ case "${IFACE}" in
+ *:*) return 0 ;;
+ esac
+
+ einfo "Removing addresses"
+ eindent
+ # iproute2 can add many addresses to an iface unlike ifconfig ...
+ # iproute2 added addresses cause problems for ifconfig
+ # as we delete an address, a new one appears, so we have to
+ # keep polling
+ while true ; do
+ local addr=$(LC_ALL=C ifconfig "${IFACE}" |
+ sed -n -e 's/.*inet addr:\([^ ]*\).*/\1/p')
+
+ [ -z "${addr}" ] && break
+
+ if [ "${addr}" = "127.0.0.1/8" ] ; then
+ # Don't delete the loopback address
+ [ "${IFACE}" = "lo" -o "${IFACE}" = "lo0" ] && break
+ fi
+ ifconfig "${IFACE}" 0.0.0.0 || break
+ done
+
+ # Remove IPv6 addresses
+ local addr=
+ for addr in $(LC_ALL=C ifconfig "${IFACE}" | \
+ sed -n -e 's/^.*inet6 addr: \([^ ]*\) Scope:[^L].*/\1/p') ; do
+ [ "${addr}" = "::1/128" -a "${IFACE}" = "lo" ] && continue
+ einfo "${addr}"
+ ifconfig "${IFACE}" inet6 del "${addr}"
+ done
+
+ return 0
+}
+
+_has_carrier() {
+ return 0
+}
+
+_tunnel() {
+ iptunnel "$@"
+}
+
+ifconfig_pre_start() {
+ # MTU support
+ local mtu=
+ eval mtu=\$mtu_${IFVAR}
+ [ -n "${mtu}" ] && ifconfig "${IFACE}" mtu "${mtu}"
+
+ local tunnel=
+
+ eval tunnel=\$iptunnel_${IFVAR}
+ [ -z "${tunnel}" ] && return 0
+
+ # Set our base metric to 1000
+ metric=1000
+
+ ebegin "Creating tunnel ${IFVAR}"
+ iptunnel add "${tunnel}"
+ eend $?
+}
+
+ifconfig_post_stop() {
+ # Don't delete sit0 as it's a special tunnel
+ [ "${IFACE}" = "sit0" ] && return 0
+
+ [ -z "$(iptunnel show "${IFACE}" 2>/dev/null)" ] && return 0
+
+ ebegin "Destroying tunnel ${IFACE}"
+ iptunnel del "${IFACE}"
+ eend $?
+}
+
+# vim: set ts=4 :
diff --git a/net.Linux/ifplugd.sh b/net.Linux/ifplugd.sh
new file mode 100644
index 00000000..23dc48cc
--- /dev/null
+++ b/net.Linux/ifplugd.sh
@@ -0,0 +1,91 @@
+# Copyright 2005-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+_config_vars="$_config_vars plug_timeout"
+
+ifplugd_depend() {
+ program start /usr/sbin/ifplugd
+ after macnet rename
+ before interface
+ provide plug
+}
+
+ifplugd_pre_start() {
+ local pidfile="/var/run/ifplugd.${IFACE}.pid" timeout= args=
+
+ # We don't start netplug if we're being called from the background
+ ${IN_BACKGROUND} && return 0
+
+ _exists || return 0
+
+ # We need a valid MAC address
+ # It's a basic test to ensure it's not a virtual interface
+ if ! _get_mac_address >/dev/null 2>/dev/null ; then
+ vewarn "netplug only works on interfaces with a valid MAC address"
+ return 0
+ fi
+
+ # We don't work on bonded, bridges, tun/tap, vlan or wireless
+ for f in bond bridge tuntap vlan wireless ; do
+ if type "_is_${f}" >/dev/null 2>/dev/null ; then
+ if _is_${f} ; then
+ veinfo "netplug does not work with" "${f}"
+ return 0
+ fi
+ fi
+ done
+
+ ebegin "Starting ifplugd on" "${IFACE}"
+
+ eval args=\$ifplugd_${IFVAR}
+
+ # Mark the us as inactive so netplug can restart us
+ mark_service_inactive "${SVCNAME}"
+
+ # Start ifplugd
+ eval start-stop-daemon --start --exec /usr/sbin/ifplugd \
+ --pidfile "${pidfile}" -- "${args}" --iface="${IFACE}"
+ eend "$?" || return 1
+
+ eindent
+
+ eval timeout=\$plug_timeout_${IFVAR}
+ [ -z "${timeout}" ] && timeout=-1
+ if [ ${timeout} -eq 0 ] ; then
+ ewarn "WARNING: infinite timeout set for" "${IFACE}" "to come up"
+ elif [ ${timeout} -lt 0 ] ; then
+ einfo "Backgrounding ..."
+ exit 1
+ fi
+
+ veinfo "Waiting for" "${IFACE}" "to be marked as started"
+
+ local i=0
+ while true ; do
+ if service_started "${SVCNAME}" ; then
+ _show_address
+ exit 0
+ fi
+ sleep 1
+ [ ${timeout} -eq 0 ]] && continue
+ i=$((${i} + 1))
+ [ ${i} -ge ${timeout} ] && break
+ done
+
+ eend 1 "Failed to configure" "${IFACE}" "in the background"
+ exit 1
+}
+
+ifplugd_stop() {
+ ${IN_BACKGROUND} && return 0
+
+ local pidfile="/var/run/ifplugd.${IFACE}.pid"
+ [ ! -e "${pidfile}" ] && return 0
+
+ ebegin "Stopping ifplugd on" "${IFACE}"
+ start-stop-daemon --stop --quiet --exec /usr/sbin/ifplugd \
+ --pidfile "${pidfile}" --signal QUIT
+ eend $?
+}
+
+# vim: set ts=4 :
diff --git a/net.Linux/ip6to4.sh b/net.Linux/ip6to4.sh
new file mode 100644
index 00000000..03d4fac3
--- /dev/null
+++ b/net.Linux/ip6to4.sh
@@ -0,0 +1,97 @@
+# Copyright 2004-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+_config_vars="$_config_vars link suffix relay"
+
+ip6to4_depend() {
+ after interface
+}
+
+ip6to4_start() {
+ case " ${MODULES} " in
+ *" ifconfig "*)
+ if [ "${IFACE}" != "sit0" ] ; then
+ eerror "ip6to4 can only work on the sit0 interface using ifconfig"
+ eerror "emerge sys-apps/iproute2 to use other interfaces"
+ return 1
+ fi
+ esac
+
+ local host= suffix= relay= addr= iface=${IFACE} new=
+ eval host=\$link_${IFVAR}
+ if [ -z "${host}" ] ; then
+ eerror "link_${IFVAR} not set"
+ return 1
+ fi
+
+ eval suffix=\${suffix_${IFVAR}:-1}
+ eval relay=\${relay_${IFVAR}:-192.88.99.1}
+
+ IFACE=${host}
+ addrs=$(_get_inet_addresses)
+ IFACE=${iface}
+ if [ -z "${addrs}" ] ; then
+ eerror "${host} is not configured with an IPv4 address"
+ return 1
+ fi
+
+ for addr in ${addrs} ; do
+ # Strip the subnet
+ local ip="${addr%/*}" subnet="${addr#*/}"
+ # We don't work on private IPv4 addresses
+ case "${ip}" in
+ 127.*) continue ;;
+ 10.*) continue ;;
+ 192.168.*) continue ;;
+ 172.*)
+ local i=16
+ while [ ${i} -lt 32 ] ; do
+ case "${ip}" in
+ 172.${i}.*) break ;;
+ esac
+ i=$((${i} + 1))
+ done
+ [ ${i} -lt 32 ] && continue
+ ;;
+ esac
+
+ veinfo "IPv4 address on ${host}: ${ip}/${subnet}"
+ local OIFS=$IFS SIFS=${IFS-y} ipa= ip6=
+ IFS="${IFS}."
+ for i in ${ip} ; do
+ ipa="${ipa} ${i}"
+ done
+ if [ "${SIFS}" = "y" ] ; then
+ IFS=$OIFS
+ else
+ unset IFS
+ fi
+ eval ip6="$(printf "2002:%02x%02x:%02x%02x::%s" ${ipa} ${suffix})"
+ veinfo "Derived IPv6 address: ${ip6}"
+
+ # Now apply our IPv6 address to our config
+ new="${new}${new:+ }${ip6}/16"
+ done
+
+ if [ -z "${new}" ] ; then
+ eerror "No global IPv4 addresses found on interface ${host}"
+ return 1
+ fi
+
+ if [ "${IFACE}" != "sit0" ] ; then
+ ebegin "Creating 6to4 tunnel on ${IFACE}"
+ _tunnel add "${IFACE}" mode sit ttl 255 remote any local "${ip}"
+ eend $? || return 1
+ _up
+ fi
+
+ # Now apply our config
+ eval config_${config_index}=\'"${new}"\'
+ config_index=$((${config_index} - 1))
+
+ # Add a route for us, ensuring we don't delete anything else
+ eval $(_get_array "routes_${IFVAR}")
+ eval routes_${IFVAR}="\"$@ '2003::/3 via ::${relay} metric 2147483647'\""
+}
+
+# vim: set ts=4 :
diff --git a/net.Linux/ipppd.sh b/net.Linux/ipppd.sh
new file mode 100644
index 00000000..faf0cda0
--- /dev/null
+++ b/net.Linux/ipppd.sh
@@ -0,0 +1,47 @@
+# Copyright 2004-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+ipppd_depend() {
+ program start /usr/sbin/ipppd
+ after macnet
+ before interface
+ provide isdn
+}
+
+_config_vars="$_config_vars ipppd"
+
+ipppd_pre_start() {
+ local opts= pidfile="/var/run/ipppd-${IFACE}.pid"
+
+ # Check that we are a valid ippp interface
+ case "${IFACE}" in
+ ippp[0-9]*) ;;
+ *) return 0 ;;
+ esac
+
+ # Check that the interface exists
+ _exists || return 1
+
+ # Might or might not be set in conf.d/net
+ eval opts=\$ipppd_${IFVAR}
+
+ einfo "Starting ipppd for ${IFACE}"
+ start-stop-daemon --start --exec /usr/sbin/ipppd \
+ --pidfile "${pidfile}" \
+ -- ${opts} pidfile "${pidfile}" \
+ file "/etc/ppp/options.${IFACE}" >/dev/null
+ eend $?
+}
+
+ipppd_post_stop() {
+ local pidfile="/var/run/ipppd-${IFACE}.pid"
+
+ [ ! -f "${pidfile}" ] && return 0
+
+ einfo "Stopping ipppd for ${IFACE}"
+ start-stop-daemon --stop --quiet --exec /usr/sbin/ipppd \
+ --pidfile "${pidfile}"
+ eend $?
+}
+
+# vim: set ts=4 :
diff --git a/net.Linux/iproute2.sh b/net.Linux/iproute2.sh
new file mode 100644
index 00000000..1b1b70fa
--- /dev/null
+++ b/net.Linux/iproute2.sh
@@ -0,0 +1,185 @@
+# Copyright 2004-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+iproute2_depend() {
+ program /sbin/ip
+ provide interface
+ after ifconfig
+}
+
+_get_mac_address() {
+ local mac=$(LC_ALL=C ip link show "${IFACE}" | sed -n \
+ -e 'y/abcdef/ABCDEF/' \
+ -e '/link\// s/^.*\<\(..:..:..:..:..:..\)\>.*/\1/p')
+
+ case "${mac}" in
+ 00:00:00:00:00:00) ;;
+ 44:44:44:44:44:44) ;;
+ FF:FF:FF:FF:FF:FF) ;;
+ "") ;;
+ *) echo "${mac}"; return 0 ;;
+ esac
+
+ return 1
+}
+
+_up() {
+ ip link set up dev "${IFACE}"
+}
+
+_down() {
+ ip link set down dev "${IFACE}"
+}
+
+_exists() {
+ grep -Eq "^[[:space:]]*${IFACE}:[[:space:]]*" /proc/net/dev
+}
+
+_ifindex() {
+ local line= i=-2
+ while read line ; do
+ i=$((${i} + 1))
+ [ ${i} -lt 1 ] && continue
+ case "${line}" in
+ "${IFACE}: "*) echo "${i}"; return 0;;
+ esac
+ done < /proc/net/dev
+ return 1
+}
+
+_is_wireless() {
+ # Support new sysfs layout
+ [ -d /sys/class/net/"${IFACE}"/wireless ] && return 0
+
+ [ ! -e /proc/net/wireless ] && return 1
+ grep -Eq "^[[:space:]]*${IFACE}:[[:space:]]+" /proc/net/wireless
+}
+
+_get_inet_addresses() {
+ LC_ALL=C ip -family inet addr show "${IFACE}" | \
+ sed -n -e 's/.*inet \([^ ]*\).*/\1/p'
+}
+
+_get_inet_address() {
+ set -- $(_get_inet_addresses)
+ [ $# = "0" ] && return 1
+ echo "$1"
+}
+
+_add_address() {
+ if [ "$1" = "127.0.0.1/8" -a "${IFACE}" = "lo" ] ; then
+ ip addr add "$@" dev "${IFACE}" 2>/dev/null
+ return 0
+ fi
+
+ # Convert an ifconfig line to iproute2
+ if [ "$2" = "netmask" ] ; then
+ local one="$1" three="$3"
+ shift ; shift ; shift
+ set -- "${one}/$(_netmask2cidr "${three}")" "$@"
+ fi
+
+ #config=( "${config[@]//pointopoint/peer}" )
+
+ # Always scope lo addresses as host unless specified otherwise
+ if [ "${IFACE}" = "lo" ] ; then
+ set -- "$@" "scope" "host"
+ fi
+
+ # IPv4 specifics
+ case "$1" in
+ *.*.*.*)
+ case "$@" in
+ *" brd "*) ;;
+ *" broadcast "*) ;;
+ *) set -- "$@" brd + ;;
+ esac
+ ;;
+ esac
+
+ ip addr add dev "${IFACE}" "$@"
+}
+
+_add_route() {
+ if [ $# -eq 3 ] ; then
+ set -- "$1" "$2" via "$3"
+ elif [ "$3" = "gw" ] ; then
+ local one=$1 two=$2
+ shift ; shift; shift
+ set -- "${one}" "${two}" gw "$@"
+ fi
+
+ local cmd= have_metric=false
+ while [ -n "$1" ] ; do
+ case "$1" in
+ metric) cmd="${cmd} $1"; have_metric=true ;;
+ netmask) cmd="${cmd}/$(_netmask2cidr "$2")"; shift ;;
+ -net) ;;
+ -A) [ "$2" = "inet6" ] && shift ;;
+ -host) cmd="${cmd} scope host" ;;
+ *) cmd="${cmd} $1" ;;
+ esac
+ shift
+ done
+
+ if ! ${have_metric} && [ -n "${metric}" ] ; then
+ cmd="${cmd} metric ${metric}"
+ fi
+
+ ip route append ${cmd} dev "${IFACE}"
+ eend $?
+}
+
+_delete_addresses() {
+ ip addr flush dev "${IFACE}" scope global 2>/dev/null
+ ip addr flush dev "${IFACE}" scope site 2>/dev/null
+ if [ "${IFACE}" != "lo" ] ; then
+ ip addr flush dev "${IFACE}" scope host 2>/dev/null
+ fi
+ return 0
+}
+
+_has_carrier() {
+ return 0
+}
+
+_tunnel() {
+ ip tunnel "$@"
+}
+
+iproute2_pre_start() {
+ # MTU support
+ local mtu=
+ eval mtu=\$mtu_${IFVAR}
+ [ -n "${mtu}" ] && ip link set mtu "${mtu}" dev "${IFACE}"
+
+ local tunnel=
+ eval tunnel=\$iptunnel_${IFVAR}
+ if [ -n "${tunnel}" ] ; then
+ # Set our base metric to 1000
+ metric=1000
+
+ ebegin "Creating tunnel ${IFVAR}"
+ ip tunnel add "${tunnel}"
+ eend $? || return 1
+ fi
+
+ return 0
+}
+
+iproute2_post_start() {
+ ip route flush cache dev "${IFACE}"
+}
+
+iproute2_post_stop() {
+ # Don't delete sit0 as it's a special tunnel
+ if [ "${IFACE}" != "sit0" ] ; then
+ if [ -n "$(ip tunnel show "${IFACE}" 2>/dev/null)" ] ; then
+ ebegin "Destroying tunnel ${IFACE}"
+ ip tunnel del "${IFACE}"
+ eend $?
+ fi
+ fi
+}
+
+# vim: set ts=4 :
diff --git a/net.Linux/iwconfig.sh b/net.Linux/iwconfig.sh
new file mode 100644
index 00000000..bed13a54
--- /dev/null
+++ b/net.Linux/iwconfig.sh
@@ -0,0 +1,710 @@
+# Copyright 2004-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# Many thanks to all the people in the Gentoo forums for their ideas and
+# motivation for me to make this and keep on improving it
+
+_config_vars="$_config_vars essid mode associate_timeout sleep_scan preferred_aps blacklist_aps"
+
+iwconfig_depend() {
+ program /sbin/iwconfig
+ after plug
+ before interface
+ provide wireless
+}
+
+iwconfig_get_wep_status() {
+ local mode= status="disabled"
+
+ # No easy way of doing this grep in bash regex :/
+ if LC_ALL=C iwconfig "${IFACE}" | grep -qE "^ +Encryption key:[*0-9,A-F]" ; then
+ status="enabled"
+ mode=$(LC_ALL=C iwconfig "${IFACE}" | sed -n -e 's/^.*Security mode:\(.*[^ ]\).*/\1/p')
+ [ -n "${mode}" ] && mode=" - ${mode}"
+ fi
+
+ echo "(WEP ${status}${mode})"
+}
+
+_get_ssid() {
+ local i=5 ssid=
+
+ while [ ${i} -gt 0 ] ; do
+ ssid=$(iwgetid --raw "${IFACE}")
+ if [ -n "${ssid}" ] ; then
+ echo "${ssid}"
+ return 0
+ fi
+ sleep 1
+ i=$((${i} + 1))
+ done
+
+ return 1
+}
+
+_get_ap_mac_address() {
+ local mac="$(iwgetid --raw --ap "${IFACE}")"
+ case "${mac}" in
+ "00:00:00:00:00:00") return 1 ;;
+ "44:44:44:44:44:44") return 1 ;;
+ "FF:00:00:00:00:00") return 1 ;;
+ "FF:FF:FF:FF:FF:FF") return 1 ;;
+ *) echo "${mac}" ;;
+ esac
+}
+
+iwconfig_get_mode() {
+ LC_ALL=C iwgetid --mode "${IFACE}" | \
+ sed -n -e 's/^.*Mode:\(.*\)/\1/p' | \
+ tr '[:upper:]' '[:lower:]'
+}
+
+iwconfig_set_mode() {
+ local mode="$1"
+ [ "${mode}" = "$(iwconfig_get_mode)" ] && return 0
+
+ # Devicescape stack requires the interface to be down
+ _down
+ iwconfig "${IFACE}" mode "${mode}" || return 1
+ _up
+}
+
+iwconfig_get_type() {
+ LC_ALL=C iwconfig "${IFACE}" | sed -n -e 's/^'"$1"' *\([^ ]* [^ ]*\).*/\1/p'
+}
+
+iwconfig_report() {
+ local mac= m="connected to"
+ local ssid="$(_get_ssid)"
+ local wep_status="$(iwconfig_get_wep_status)"
+ local channel="$(iwgetid --raw --channel "${iface}")"
+ [ -n "${channel}" ] && channel="on channel ${channel} "
+ local mode="$(iwconfig_get_mode)"
+ if [ "${mode}" = "master" ]; then
+ m="configured as"
+ else
+ mac="$(_get_ap_mac_address)"
+ [ -n "${mac}" ] && mac=" at ${mac}"
+ fi
+
+ eindent
+ einfo "${IFACE} ${m} SSID \"${SSID}\"${mac}"
+ einfo "in ${mode} mode ${channel}${wep_status}"
+ eoutdent
+}
+
+iwconfig_get_wep_key() {
+ local mac="$1" key=
+ [ -n "${mac}" ] && mac="$(echo "${mac}" | sed -e 's/://g')"
+ eval key=\$mac_key_${mac}
+ [ -z "${key}" ] && eval key=\$key_${SSIDVAR}
+ if [ -z "${key}" ] ; then
+ echo "off"
+ else
+ set -- ${key}
+ local x= e=false
+ for x in "$@" ; do
+ if [ "${x}" = "enc" ] ; then
+ e=true
+ break
+ fi
+ done
+ ${e} || key="${key} enc open"
+ echo "${key}"
+ fi
+}
+
+iwconfig_user_config() {
+ local conf= var=${SSIDVAR}
+ [ -z "${var}" ] && var=${IFVAR}
+
+ eval "$(_get_array "iwconfig_${var}")"
+ for conf in "$@" ; do
+ if ! eval iwconfig "${IFACE}" "${conf}" ; then
+ ewarn "${IFACE} does not support the following configuration commands"
+ ewarn " ${conf}"
+ fi
+ done
+
+ eval "$(_get_array "iwpriv_${var}")"
+ for conf in "$@" ; do
+ if ! eval iwpriv "${IFACE}" "${conf}" ; then
+ ewarn "${IFACE} does not support the following private ioctls"
+ ewarn " ${conf}"
+ fi
+ done
+}
+
+iwconfig_setup_specific() {
+ local mode="$1" channel=
+ if [ -z "${SSID}" ]; then
+ eerror "${IFACE} requires an SSID to be set to operate in ${mode} mode"
+ eerror "adjust the ssid_${IFVAR} setting in /etc/conf.d/net"
+ return 1
+ fi
+ SSIDVAR=$(_shell_var "${SSID}")
+ local key=$(iwconfig_get_wep_key)
+
+ iwconfig_set_mode "${mode}"
+
+ # Now set the key
+ if ! eval iwconfig "${IFACE}" key "${key}" ; then
+ if [ "${key}" != "off" ]; then
+ ewarn "${IFACE} does not support setting keys"
+ ewarn "or the parameter \"mac_key_${SSIDVAR}\" or \"key_${SSIDVAR}\" is incorrect"
+ fi
+ fi
+
+ # Then set the SSID
+ if ! eval iwconfig "${IFACE}" essid "${SSID}" ; then
+ eerror "${IFACE} does not support setting SSID to \"${ESSID}\""
+ return 1
+ fi
+
+ eval channel=\$channel_${SSIDVAR}
+ [ -z "${channel}" ] && eval channel=\$channel_${IFVAR}
+ # We default the channel to 3
+ if ! iwconfig "${IFACE}" channel "${channel:-3}" ; then
+ ewarn "${IFACE} does not support setting the channel to \"${channel:-3}\""
+ return 1
+ fi
+
+ # Finally apply the user Config
+ iwconfig_user_config
+
+ iwconfig_report
+ return 0
+}
+
+iwconfig_wait_for_association() {
+ local timeout= i=0
+ eval timeout=\$associate_timeout_${IFVAR}
+ timeout=${timeout:-10}
+
+ [ ${timeout} -eq 0 ] \
+ && vewarn "WARNING: infinite timeout set for association on ${IFACE}"
+
+ while true; do
+ # Use sysfs if we can
+ if [ -e /sys/class/net/"${IFACE}"/carrier ] ; then
+ if [ "$(cat /sys/class/net/"${IFACE}"/carrier)" = "1" ] ; then
+ # Double check we have an essid. This is mainly for buggy
+ # prism54 drivers that always set their carrier on :/
+ [ -n "$(iwgetid --raw "${IFACE}")" ] && return 0
+ fi
+ else
+ local atest=
+ eval atest=\$associate_test_${IFVAR}
+ atest=${atest:-mac}
+ if [ "${atest}" = "mac" -o "${atest}" = "all" ] ; then
+ [ -n "$(_get_ap_mac_address)" ] && return 0
+ fi
+ if [ "${atest}" = "quality" -o "${atest}" = "all" ] ; then
+ [ "$(sed -n -e 's/^.*'"${IFACE}"': *[0-9]* *\([0-9]*\).*/\1/p' \
+ /proc/net/wireless)" != "0" ] && return 0
+ fi
+ fi
+
+ sleep 1
+ [ ${timeout} -eq 0 ] && continue
+ i=$((${i} + 1))
+ [ ${i} -ge ${timeout} ] && return 1
+ done
+ return 1
+}
+
+iwconfig_associate() {
+ local mode="${1:-managed}" mac="$2" wep_required="$3" freq="$4" chan="$5"
+ local w="(WEP Disabled)" key=
+
+ iwconfig_set_mode "${mode}"
+
+ if [ "${SSID}" = "any" ]; then
+ iwconfig "${IFACE}" ap any 2>/dev/null
+ unset ESSIDVAR
+ else
+ SSIDVAR=$(_shell_var "${SSID}")
+ key="$(iwconfig_get_wep_key "${mac}")"
+ if [ "${wep_required}" = "on" -a "${key}" = "off" ] ; then
+ ewarn "WEP key is not set for \"${SSID}\" - not connecting"
+ return 1
+ fi
+ if [ "${wep_required}" = "off" -a "${key}" != "off" ] ; then
+ key="off"
+ ewarn "\"${SSID}\" is not WEP enabled - ignoring setting"
+ fi
+
+ if ! eval iwconfig "${IFACE}" key "${key}" ; then
+ if [ "${key}" != "off" ] ; then
+ ewarn "${IFACE} does not support setting keys"
+ ewarn "or the parameter \"mac_key_${SSIDVAR}\" or \"key_${SSIDVAR}\" is incorrect"
+ return 1
+ fi
+ fi
+ [ "${key}" != "off" ] && w="$(iwconfig_get_wep_status "${iface}")"
+ fi
+
+ if ! eval iwconfig "${IFACE}" essid "${SSID}" ; then
+ if [ "${SSID}" != "any" ] ; then
+ ewarn "${IFACE} does not support setting ESSID to \"${SSID}\""
+ fi
+ fi
+
+ # Only use channel or frequency
+ if [ -n "${chan}" ] ; then
+ iwconfig "${IFACE}" channel "${chan}"
+ elif [ -n "${freq}" ] ; then
+ iwconfig "${IFACE}" freq "${freq}"
+ fi
+ [ -n "${mac}" ] && iwconfig "${IFACE}" ap "${mac}"
+
+ # Finally apply the user Config
+ iwconfig_user_config
+
+ ebegin "Connecting to \"${SSID}\" in ${mode} mode ${w}"
+
+ if [ "${SSID}" != "any" ] && type preassociate >/dev/null 2>/dev/null ; then
+ veinfo "Running preassociate function"
+ veindent
+ ( preassociate )
+ local e=$?
+ veoutdent
+ if [ ${e} -eq 0 ] ; then
+ veend 1 "preassociate \"${SSID}\" on ${IFACE} failed"
+ return 1
+ fi
+ fi
+
+ if ! iwconfig_wait_for_association ; then
+ eend 1
+ return 1
+ fi
+ eend 0
+
+ if [ "${SSID}" = "any" ]; then
+ SSID="$(_get_ssid)"
+ iwconfig_associate
+ return $?
+ fi
+
+ iwconfig_report
+
+ if type postassociate >/dev/null 2>/dev/null ; then
+ veinfo "Running postassociate function"
+ veindent
+ ( postassociate )
+ veoutdent
+ fi
+
+ return 0
+}
+
+iwconfig_scan() {
+ local x= i=0 scan=
+ einfo "Scanning for access points"
+ eindent
+
+ # Sleep if required
+ eval x=\$sleep_scan_${IFVAR}
+ [ -n "${x}" ] && sleep "${x}"
+
+ while [ ${i} -lt 3 ] ; do
+ scan="${scan} $(iwlist "${IFACE}" scan 2>/dev/null | sed -e "s/'/'\\\\''/g" -e "s/$/'/g" -e "s/^/'/g")"
+ i=$((${i} + 1))
+ done
+
+ if [ -z "${scan}" ] ; then
+ ewarn "${iface} does not support scanning"
+ eoutdent
+ eval x=\$adhoc_essid_${IFVAR}
+ [ -n "${x}" ] && return 0
+ if [ -n "${preferred_aps}" ] ; then
+ [ "${associate_order}" = "forcepreferred" ] || \
+ [ "${associate_order}" = "forcepreferredonly" ] && return 0
+ fi
+ eerror "You either need to set a preferred_aps list in /etc/conf.d/wireless"
+ eerror " preferred_aps=\"SSID1 SSID2\""
+ eerror " and set associate_order_${IFVAR}=\"forcepreferred\""
+ eerror " or set associate_order_${IFVAR}=\"forcepreferredonly\""
+ eerror "or hardcode the SSID to \"any\" and let the driver find an Access Point"
+ eerror " ssid_${IFVAR}=\"any\""
+ eerror "or configure defaulting to Ad-Hoc when Managed fails"
+ eerror " adhoc_essid_${IFVAR}=\"WLAN\""
+ eerror "or hardcode the ESSID against the interface (not recommended)"
+ eerror " essid_${IFVAR}=\"ESSID\""
+ return 1
+ fi
+
+ local OIFS=$IFS
+ APS=-1
+ eval set -- ${scan}
+ for line in "$@" ; do
+ case "${line}" in
+ *Address:*)
+ APS=$((${APS} + 1))
+ eval MAC_${APS}=\""$(echo "${line#*: }" | tr '[:lower:]' '[:upper:]')"\"
+ eval QUALITY_${APS}=0
+ ;;
+ *ESSID:*)
+ x=${line#*\"}
+ x=${x%*\"}
+ eval SSID_${APS}=\$x
+ ;;
+ *Mode:*)
+ x="$(echo "${line#*:}" | tr '[:upper:]' '[:lower:]')"
+ if [ "${x}" = "master" ] ; then
+ eval MODE_${APS}=\"managed\"
+ else
+ eval MODE_${APS}=\$x
+ fi
+ ;;
+ *'Encryption key:'*)
+ x=${line#*:}
+ eval ENC_${APS}=\$x
+ ;;
+ #*Frequency:*)
+ # freq[i]="${line#*:}"
+ # x="${freq[i]#* }"
+ # freq[i]="${freq[i]%% *}${x:0:1}"
+ # ;;
+ *Channel:*)
+ x=${line#*:}
+ x=${x%% *}
+ eval CHAN_${APS}=\$x
+ ;;
+ *Quality*)
+ x=${line#*:}
+ x=${x%/*}
+ x="$(echo "${x}" | sed -e 's/[^[:digit:]]//g')"
+ x=${x:-0}
+ eval QUALITY_${APS}=\$x
+ ;;
+ esac
+ done
+
+ if [ -z "${MAC_0}" ]; then
+ ewarn "no access points found"
+ eoutdent
+ return 1
+ fi
+
+ # Sort based on quality
+ local i=0 k=1 a= b= x= t=
+ while [ ${i} -lt ${APS} ] ; do
+ k=$((${i} + 1))
+ while [ ${k} -le ${APS} ] ; do
+ eval a=\$QUALITY_${i}
+ [ -z "${a}" ] && break
+ eval b=\$QUALITY_${k}
+ if [ -n "${b}" -a "${a}" -lt "${b}" ] ; then
+ for x in MAC SSID CHAN QUALITY ENC ; do
+ eval t=\$${x}_${i}
+ eval ${x}_${i}=\$${x}_${k}
+ eval ${x}_${k}=\$t
+ done
+ fi
+ k=$((${k} + 1))
+ done
+ i=$((${i} + 1))
+ done
+
+ # Strip any duplicates
+ local i=0 k=1 a= b=
+ while [ ${i} -lt ${APS} ] ; do
+ k=$((${i} + 1))
+ while [ ${k} -le ${APS} ] ; do
+ eval a=\$MAC_${i}
+ eval b=\$MAC_${k}
+ if [ "${a}" = "${b}" ] ; then
+ eval a=\$QUALITY_${i}
+ eval b=\$QUALITY_${k}
+ if [ -n "${a}" -a -n "${b}" ] ; then
+ if [ ${a} -ge ${b} ] ; then
+ unset MAC_${k} SSID_${k} CHAN_${k} QUALITY_${k} ENC_${k}
+ else
+ unset MAC_${i} SSID_${i} CHAN_${i} QUALITY_${i} ENC_${i}
+ fi
+ else
+ unset MAC_${k} SSID_${k} CHAN_${k} QUALITY_${k} ENC_${k}
+ fi
+ fi
+ k=$((${k} + 1))
+ done
+ i=$((${i} + 1))
+ done
+
+ local i=0 e= m= black= s=
+ eval "$(_get_array "blacklist_aps")"
+ black="$@"
+
+ while [ ${i} -le ${APS} ] ; do
+ eval x=\$MAC_${i}
+ if [ -z "${x}" ] ; then
+ i=$((${i} + 1))
+ continue
+ fi
+
+ eval m=\$MODE_${i}
+ eval s=\$SSID_${i}
+ eval q=\$QUALITY_${i}
+ eval e=\$ENC_${i}
+ if [ -n "${e}" -a "${e}" != "off" ] ; then
+ e=", encrypted"
+ else
+ e=""
+ fi
+ if [ -z "${s}" ] ; then
+ einfo "Found ${x}, ${m}${e}"
+ else
+ einfo "Found \"${s}\" at ${x}, ${m}${e}"
+ fi
+
+ x="$(echo "${x}" | sed -e 's/://g')"
+ eval x=\$mac_ssid_${x}
+ if [ -n "${x}" ] ; then
+ eval SSID_${i}=\$x
+ s=${x}
+ eindent
+ einfo "mapping to \"${x}\""
+ eoutdent
+ fi
+
+ eval "$(_get_array "blacklist_aps")"
+ for x in "$@" ; do
+ if [ "${x}" = "${s}" ] ; then
+ ewarn "${s} has been blacklisted - not connecting"
+ unset SSID_${i} MAC_${i} CHAN_${i} QUALITY_${i} ENC_${i}
+ fi
+ done
+ i=$((${i} + 1))
+ done
+ eoutdent
+}
+
+iwconfig_force_preferred() {
+ [ -z "${preferred_aps}" ] && return 1
+
+ ewarn "Trying to force preferred in case they are hidden"
+ eval "(_get_array "preferred_aps")"
+ local ssid=
+ for ssid in "$@"; do
+ local found_AP=false i=0 e=
+ while [ ${i} -le ${APS} ] ; do
+ eval e=\$SSID_${i}
+ if [ "${e}" = "${ssid}" ] ; then
+ found_AP=true
+ break
+ fi
+ i=$((${i} + 1))
+ done
+ if ! ${found_AP} ; then
+ SSID=${e}
+ iwconfig_associate && return 0
+ fi
+ done
+
+ ewarn "Failed to associate with any preferred access points on ${IFACE}"
+ return 1
+}
+
+iwconfig_connect_preferred() {
+ local essid= i=0 mode= mac= enc= freq= chan=
+
+ eval "$(_get_array preferred_aps)"
+ for essid in "$@"; do
+ while [ ${i} -le ${APS} ] ; do
+ eval e=\$SSID_${i}
+ if [ "${e}" = "${essid}" ] ; then
+ SSID=${e}
+ eval mode=\$MODE_${i}
+ eval mac=\$MAC_${i}
+ eval enc=\$ENC_${i}
+ eval freq=\$FREQ_${i}
+ eval chan=\$CHAN_${i}
+ iwconfig_associate "${mode}" "${mac}" "${enc}" "${freq}" \
+ "${chan}" && return 0
+ fi
+ i=$((${i} + 1))
+ done
+ done
+
+ return 1
+}
+
+iwconfig_connect_not_preferred() {
+ local essid= i=0 mode= mac= enc= freq= chan= pref=false
+
+ while [ ${i} -le ${APS} ] ; do
+ eval e=\$SSID_${i}
+ eval "$(_get_array preferred_aps)"
+ for essid in "$@" ; do
+ if [ "${e}" = "${essid}" ] ; then
+ pref=true
+ break
+ fi
+ done
+
+ if ! ${pref} ; then
+ SSID=${e}
+ eval mode=\$MODE_${i}
+ eval mac=\$MAC_${i}
+ eval enc=\$ENC_${i}
+ eval freq=\$FREQ_${i}
+ eval chan=\$CHAN_${i}
+ iwconfig_associate "${mode}" "${mac}" "${enc}" "${freq}" \
+ "${chan}" && return 0
+ fi
+ i=$((${i} + 1))
+ done
+
+ return 1
+}
+
+iwconfig_defaults() {
+ local x=
+ for x in txpower rate rts frag ; do
+ iwconfig "${IFACE}" "${x}" auto 2>/dev/null
+ done
+
+ # Release the AP forced
+ # Must do ap and then essid otherwise scanning borks
+ iwconfig "${IFACE}" ap off 2>/dev/null
+ iwconfig "${IFACE}" essid off 2>/dev/null
+}
+
+iwconfig_configure() {
+ local x APS
+ eval ESSID=\$ssid_${IFVAR}
+
+ # Setup ad-hoc mode?
+ eval x=\$mode_${IFVAR}
+ x=${x:-managed}
+ if [ "${x}" = "ad-hoc" -o "${x}" = "master" ] ; then
+ iwconfig_setup_specific "${x}"
+ return $?
+ fi
+
+ if [ "${x}" != "managed" -a "${x}" != "auto" ] ; then
+ eerror "Only managed, ad-hoc, master and auto modes are supported"
+ return 1
+ fi
+
+ # Has an ESSID been forced?
+ if [ -n "${ESSID}" ]; then
+ iwconfig_set_mode "${x}"
+ iwconfig_associate && return 0
+ [ "${ESSID}" = "any" ] && iwconfig_force_preferred && return 0
+
+ eval ESSID=\$adhoc_essid_${IFVAR}
+ if [ -n "${ESSID}" ]; then
+ iwconfig_setup_specific ad-hoc
+ return $?
+ fi
+ return 1
+ fi
+
+ # Do we have a preferred Access Point list specific to the interface?
+# x="preferred_aps_${ifvar}[@]"
+# [[ -n ${!x} ]] && preferred_aps=( "${!x}" )
+
+# # Do we have a blacklist Access Point list specific to the interface?
+# x="blacklist_aps_${ifvar}[@]"
+# [[ -n ${!x} ]] && blacklist_aps=( "${!x}" )
+
+ # Are we forcing preferred only?
+ eval x=\$associate_order_${IFVAR}
+ [ -n "${x}" ] && associate_order=${x}
+ associate_order=${associate_order:-any}
+ if [ "${associate_order}" = "forcepreferredonly" ]; then
+ iwconfig_force_preferred && return 0
+ else
+ iwconfig_scan || return 1
+ iwconfig_connect_preferred && return 0
+ [ "${associate_order}" = "forcepreferred" ] || \
+ [ "${associate_order}" = "forceany" ] && \
+ iwconfig_force_preferred && return 0
+ [ "${associate_order}" = "any" ] || \
+ [ "${associate_order}" = "forceany" ] && \
+ iwconfig_connect_not_preferred && return 0
+ fi
+
+ e="associate with"
+ [ -z "${MAC_0}" ] && e="find"
+ [ "${preferred_aps}" = "force" ] || \
+ [ "${preferred_aps}" = "forceonly" ] && \
+ e="force"
+ e="Couldn't ${e} any access points on ${IFACE}"
+
+ eval SSID=\$adhoc_ssid_${IFVAR}
+ if [ -n "${SSID}" ]; then
+ ewarn "${e}"
+ iwconfig_setup_specific ad-hoc
+ return $?
+ fi
+
+ eerror "${e}"
+ return 1
+}
+
+iwconfig_pre_start() {
+ # We don't configure wireless if we're being called from
+ # the background
+ ${IN_BACKGROUND} && return 0
+
+ save_options "SSID" ""
+ _exists || return 0
+
+ if ! _is_wireless ; then
+ veinfo "Wireless extensions not found for ${IFACE}"
+ return 0
+ fi
+
+ iwconfig_defaults
+ iwconfig_user_config
+
+ # Set the base metric to be 2000
+ metric=2000
+
+ # Check for rf_kill - only ipw supports this at present, but other
+ # cards may in the future.
+ if [ -e /sys/class/net/"${IFACE}"/device/rf_kill ] ; then
+ if [ $(cat /sys/class/net/"${IFACE}"/device/rf_kill) != "0" ] ; then
+ eerror "Wireless radio has been killed for interface ${IFACE}"
+ return 1
+ fi
+ fi
+
+ einfo "Configuring wireless network for ${IFACE}"
+
+ # Are we a proper IEEE device?
+ # Most devices reutrn IEEE 802.11b/g - but intel cards return IEEE
+ # in lower case and RA cards return RAPCI or similar
+ # which really sucks :(
+ # For the time being, we will test prism54 not loading firmware
+ # which reports NOT READY!
+ x="$(iwconfig_get_type)"
+ if [ "${x}" = "NOT READY!" ]; then
+ eerror "Looks like there was a probem loading the firmware for ${IFACE}"
+ return 1
+ fi
+
+ if iwconfig_configure ; then
+ save_options "ESSID" "${ESSID}"
+ return 0
+ fi
+
+ eerror "Failed to configure wireless for ${IFACE}"
+ iwconfig_defaults
+ iwconfig "${IFACE}" txpower off 2>/dev/null
+ unset ESSID ESSIDVAR
+ _down
+ return 1
+}
+
+iwconfig_post_stop() {
+ ${IN_BACKGROUND} && return 0
+ _exists || return 0
+ iwconfig_defaults
+ iwconfig "${IFACE}" txpower off 2>/dev/null
+}
+
+# vim: set ts=4
diff --git a/net.Linux/macchanger.sh b/net.Linux/macchanger.sh
new file mode 100644
index 00000000..9d71513f
--- /dev/null
+++ b/net.Linux/macchanger.sh
@@ -0,0 +1,88 @@
+# Copyright 2004-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+macchanger_depend() {
+ before macnet
+}
+
+_config_vars="$_config_vars mac"
+
+macchanger_pre_start() {
+ # We don't change MAC addresses from background
+ ${IN_BACKGROUND} && return 0
+
+ local mac= opts=
+
+ eval mac=\$mac_${IFVAR}
+ [ -z "${mac}" ] && return 0
+
+ _exists true || return 1
+
+ ebegin "Changing MAC address of ${IFACE}"
+
+ # The interface needs to be up for macchanger to work most of the time
+ _down
+
+ mac=$(echo "${mac}" | sed -e 'y/ABCDEF/abcdef')
+ case "${mac}" in
+ # specific mac-addr, i wish there were a shorter way to specify this
+ [0-9a-f][0-9a-f]:[0-9a-f][0-9a-f]:[0-9a-f][0-9a-f]:[0-9a-f][0-9a-f]:[0-9a-f][0-9a-f]:[0-9a-f][0-9a-f])
+ # We don't need macchanger to change to a specific mac address
+ _set_mac_address "${mac}"
+ if eend "$?" ; then
+ mac=$(_get_mac_address)
+ eindent
+ einfo "changed to ${mac}"
+ eoutdent
+ return 0
+ fi
+ ;;
+
+ # increment MAC address, default macchanger behavior
+ increment) opts="${opts}" ;;
+
+ # randomize just the ending bytes
+ random-ending) opts="${opts} -e" ;;
+
+ # keep the same kind of physical layer (eg fibre, copper)
+ random-samekind) opts="${opts} -a" ;;
+
+ # randomize to any known vendor of any physical layer type
+ random-anykind) opts="${opts} -A" ;;
+
+ # fully random bytes
+ random-full|random) opts="${opts} -r" ;;
+
+ # default case is just to pass on all the options
+ *) opts="${opts} ${mac}" ;;
+ esac
+
+ if [ ! -x /sbin/macchanger ] ; then
+ eerror "For changing MAC addresses, emerge net-analyzer/macchanger"
+ return 1
+ fi
+
+ mac=$(LC_ALL=C macchanger ${opts} "${IFACE}" \
+ | sed -n -e 's/^Faked MAC:.*\<\(..:..:..:..:..:..\)\>.*/\1/p' )
+ _up
+
+ # Sometimes the interface needs to be up ....
+ if [ -z "${mac}" ] ; then
+ mac=$(LC_ALL=C macchanger ${opts} "${IFACE}" \
+ | sed -n -e 's/^Faked MAC:.*\<\(..:..:..:..:..:..\)\>.*/\1/p' )
+ fi
+
+ if [ -z "${mac}" ] ; then
+ eend 1 "Failed to set MAC address"
+ return 1
+ fi
+
+ eend 0
+ eindent
+ einfo "changed to" "${mac}"
+ eoutdent
+
+ return 0
+}
+
+# vim: set ts=4 :
diff --git a/net.Linux/netplugd.sh b/net.Linux/netplugd.sh
new file mode 100644
index 00000000..170e3a8d
--- /dev/null
+++ b/net.Linux/netplugd.sh
@@ -0,0 +1,93 @@
+# Copyright 2005-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+_config_vars="$_config_vars plug_timeout"
+
+netplugd_depend() {
+ program start /sbin/netplugd
+ after macnet rename
+ before interface
+ provide plug
+
+ # Prefer us to ifplugd
+ after ifplugd
+}
+
+netplugd_pre_start() {
+ local pidfile="/var/run/netplugd-${IFACE}.pid" timeout=
+
+ # We don't start netplug if we're being called from the background
+ ${IN_BACKGROUND} && return 0
+
+ _exists || return 0
+
+ # We need a valid MAC address
+ # It's a basic test to ensure it's not a virtual interface
+ if ! _get_mac_address >/dev/null 2>/dev/null ; then
+ vewarn "netplug only works on interfaces with a valid MAC address"
+ return 0
+ fi
+
+ # We don't work on bonded, bridges, tun/tap, vlan or wireless
+ for f in bond bridge tuntap vlan wireless ; do
+ if type "_is_${f}" >/dev/null 2>/dev/null ; then
+ if _is_${f} ; then
+ veinfo "netplug does not work with" "${f}"
+ return 0
+ fi
+ fi
+ done
+
+ ebegin "Starting netplug on" "${IFACE}"
+
+ # Mark the us as inactive so netplug can restart us
+ mark_service_inactive "${SVCNAME}"
+
+ # Start netplug
+ start-stop-daemon --start --exec /sbin/netplugd \
+ --pidfile "${pidfile}" \
+ -- -i "${IFACE}" -P -p "${pidfile}" -c /dev/null
+ eend "$?" || return 1
+
+ eindent
+
+ eval timeout=\$plug_timeout_${IFVAR}
+ [ -z "${timeout}" ] && timeout=-1
+ if [ ${timeout} -eq 0 ] ; then
+ ewarn "WARNING: infinite timeout set for" "${IFACE}" "to come up"
+ elif [ ${timeout} -lt 0 ] ; then
+ einfo "Backgrounding ..."
+ exit 1
+ fi
+
+ veinfo "Waiting for" "${IFACE}" "to be marked as started"
+
+ local i=0
+ while true ; do
+ if service_started "${SVCNAME}" ; then
+ _show_address
+ exit 0
+ fi
+ sleep 1
+ [ ${timeout} -eq 0 ]] && continue
+ i=$((${i} + 1))
+ [ ${i} -ge ${timeout} ] && break
+ done
+
+ eend 1 "Failed to configure" "${IFACE}" "in the background"
+ exit 1
+}
+
+netplugd_stop() {
+ ${IN_BACKGROUND} && return 0
+
+ local pidfile="/var/run/netplugd-${IFACE}.pid"
+ [ ! -e "${pidfile}" ] && return 0
+
+ ebegin "Stopping netplug on" "${IFACE}"
+ start-stop-daemon --stop --quiet --exec /sbin/netplugd \
+ --pidfile "${pidfile}"
+ eend $?
+}
+
+# vim: set ts=4 :
diff --git a/net.Linux/pppd.sh b/net.Linux/pppd.sh
new file mode 100644
index 00000000..72a8e7d4
--- /dev/null
+++ b/net.Linux/pppd.sh
@@ -0,0 +1,219 @@
+# Copyright 2005-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+pppd_depend() {
+ program /usr/sbin/pppd
+ after interface
+ before dhcp
+ provide ppp
+}
+
+is_ppp() {
+ [ -e /var/run/ppp-"${IFACE}".pid ]
+}
+
+requote() {
+ printf "'%s' " "$@"
+}
+
+pppd_start() {
+ ${IN_BACKGROUND} && return 0
+
+ if [ "${iface%%[0-9]*}" != "ppp" ] ; then
+ eerror "PPP can only be invoked from net.ppp[0-9]"
+ return 1
+ fi
+
+ local link= i= opts= unit="${IFACE#ppp}" mtu=
+ if [ -z "${unit}" ] ; then
+ eerror $"PPP requires a unit - use net.ppp[0-9] instead of net.ppp"
+ return 1
+ fi
+
+ # PPP requires a link to communicate over - normally a serial port
+ # PPPoE communicates over Ethernet
+ # PPPoA communicates over ATM
+ # In all cases, the link needs to be available before we start PPP
+ eval link=\$link_${IFVAR}
+ if [ -z "${link}" ] ; then
+ eerror "link_${IFVAR} has not been set in /etc/conf.d/net"
+ return 1
+ fi
+
+ case "${link}" in
+ /*)
+ if [ ! -e "${link}" ] ; then
+ eerror "${link} does not exist"
+ eerror "Please verify hardware or kernel module (driver)"
+ return 1
+ fi
+ ;;
+ esac
+
+ eval $(_get_array "pppd_${IFVAR}")
+ opts="$@"
+
+ # We don't work with these options set by the user
+ for i in "$@" ; do
+ set -- ${i}
+ case "$1" in
+ unit|nodetach|linkname)
+ eerror "The option \"$1\" is not allowed in pppd_${IFVAR}"
+ return 1
+ ;;
+ esac
+ done
+
+ # Might be set in conf.d/net
+ local username= password= passwordset=
+ eval username=\$username_${IFVAR}
+ eval password=\$password_${IFVAR}
+ eval passwordset=\${password_${IFVAR}-x}
+ if [ -n "${username}" ] \
+ && [ -n "${password}" -o -z "${passwordset}" ] ; then
+ opts="${opts} plugin passwordfd.so passwordfd 0"
+ fi
+
+ # Check for mtu/mru
+ local mtu= hasmtu=false hasmru=false hasmaxfail=false haspersits=false
+ loal hasupdetach=false
+ eval mtu=\$mtu_${IFVAR}
+ for i in ${opts} ; do
+ case "${i}" in
+ mtu" "*) hasmtu=true ;;
+ mru" "*) hasmru=true ;;
+ maxfail" "*) hasmaxfail=true ;;
+ persist) haspersist=true ;;
+ updetach) hasupdetach=true;
+ esac
+ done
+ ! ${hasmtu} && opts="${opts} mtu ${mtu}"
+ ! ${hasmru} && opts="${opts} mru ${mtu}"
+ ! ${hasmailfail} && opts="${opts} maxfail 0"
+ ! ${haspersist} && opts="${opts} persist"
+
+ # Set linkname because we need /var/run/ppp-${linkname}.pid
+ # This pidfile has the advantage of being there, even if ${iface} interface was never started
+ opts="linkname ${IFACE} ${opts}"
+
+ # Setup auth info
+ if [ -n "${username}" ] ; then
+ opts="user '"${username}"' remotename ${IFACE} ${opts}"
+ fi
+
+ # Load a custom interface configuration file if it exists
+ [ -f "/etc/ppp/options.${IFACE}" ] \
+ && opts="${opts} file /etc/ppp/options.${IFACE}"
+
+ # Set unit
+ opts="unit ${unit} ${opts}"
+
+ # Setup connect script
+ local chatopts="/usr/sbin/chat -e -E -v"
+ eval $(_get_array "phone_number_${IFVAR}")
+ [ -n "$1" ] && chatopts="${chatopts} -T '$1'"
+ [ -n "$2" ] && chatopts="${chatopts} -U '$2'"
+ eval $(_get_array "chat_${IFVAR}")
+ if [ -n "$@" ] ; then
+ opts="${opts} connect $(printf "'%s' " "${chatopts} $(printf "'%s' " "$@")")"
+ fi
+
+ # Add plugins
+ local haspppoa=false haspppoe=false
+ eval $(_get_array "plugins_${IFVAR}")
+ for i in "$@" ; do
+ set -- ${i}
+ case "${i}" in
+ passwordfd) continue;;
+ pppoa) shift; set -- "rp-pppoe" "$@" ;;
+ pppoe) shift; set -- "pppoatm" "$@" ;;
+ capi) shift; set -- "capiplugin" "$@" ;;
+ esac
+ case "${i}" in
+ rp-pppoe) haspppoe=true ;;
+ pppoatm) haspppoa=true ;;
+ esac
+ if [ "$1" = "rp-pppoe" ] || [ "$1" = "pppoatm" -a "${link}" != "/dev/null" ] ; then
+ opts="${opts} connect true"
+ set -- "$@" "${link}"
+ fi
+ opts="${opts} plugin $1.so"
+ shift
+ opts="${opts} $@"
+ done
+
+ #Specialized stuff. Insert here actions particular to connection type (pppoe,pppoa,capi)
+ local insert_link_in_opts=1
+ if ${haspppoe} ; then
+ if [ ! -e /proc/net/pppoe ] ; then
+ # Load the PPPoE kernel module
+ if ! modprobe pppoe ; then
+ eerror "kernel does not support PPPoE"
+ return 1
+ fi
+ fi
+
+ # Ensure that the link exists and is up
+ ( IFACE="${link}" ; _exists true && _up ) || return 1
+ insert_link_in_opts=0
+ fi
+
+ if ${haspppoa} ; then
+ if [ ! -d /proc/net/atm ] ; then
+ # Load the PPPoA kernel module
+ if ! modprobe pppoatm ; then
+ eerror "kernel does not support PPPoATM"
+ return 1
+ fi
+ fi
+
+ if [ "${link}" != "/dev/null" ] ; then
+ insert_link_in_opts=0
+ else
+ ewarn "WARNING: An [itf.]vpi.vci ATM address was expected in link_${IFVAR}"
+ fi
+
+ fi
+ [ "${insert_link_in_opts}" == "0" ] || opts="${link} ${opts}"
+
+ ebegin "Starting pppd in ${IFACE}"
+ mark_service_inactive "${SVCNAME}"
+ if [ -n "${username}" ] \
+ && [ -n "${password}" -o -z "${passwordset}" ] ; then
+ echo "${password}" | sed -e 's/\\/\\\\/g' -e 's/"/\\"/g' | \
+ eval start-stop-daemon --start --exec /usr/sbin/pppd \
+ --pidfile "/var/run/ppp-${IFACE}.pid" -- "${opts}" >/dev/null
+ else
+ eval start-stop-daemon --start --exec /usr/sbin/pppd \
+ --pidfile "/var/run/ppp-${IFACE}.pid" -- "${opts}" >/dev/null
+ fi
+
+ if ! eend $? $"Failed to start PPP" ; then
+ mark_service_starting "net.${iface}"
+ return 1
+ fi
+
+ if ${hasupdetach} ; then
+ _show_address
+ else
+ einfo "Backgrounding ..."
+ fi
+
+ # pppd will re-call us when we bring the interface up
+ exit 0
+}
+
+pppd_stop() {
+ ${IN_BACKGROUND} && return 0
+ local pidfile="/var/run/ppp-${IFACE}.pid"
+
+ [ ! -s "${pidfile}" ] && return 0
+
+ # Give pppd at least 30 seconds do die, #147490
+ einfo "Stopping pppd on ${IFACE}"
+ start-stop-daemon --stop --quiet --exec /usr/sbin/pppd \
+ --pidfile "${pidfile}" --retry 30
+ eend $?
+}
+
+# vim: set ts=4 :
diff --git a/net.Linux/pump.sh b/net.Linux/pump.sh
new file mode 100644
index 00000000..fd57fcda
--- /dev/null
+++ b/net.Linux/pump.sh
@@ -0,0 +1,60 @@
+# Copyright 2004-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+pump_depend() {
+ program /sbin/pump
+ after interface
+ provide dhcp
+}
+
+_config_vars="$_config_vars dhcp pump"
+
+pump_start() {
+ local args= opt= opts=
+
+ _wait_for_carrier || return 1
+
+ # Get our options
+ eval opts=\$dhcp_${IFVAR}
+ [ -z "${opts}" ] && opts=${dhcp}
+
+ # Map some generic options to dhcpcd
+ for opt in ${opts} ; do
+ case "${opt}" in
+ nodns) args="${args} --no-dns" ;;
+ nontp) args="${args} --no-ntp" ;;
+ nogateway) args="${args} --no-gateway" ;;
+ esac
+ done
+
+ # Add our route metric
+ [ "${metric:-0}" != "0" ] && args="${args} --route-metric ${metric}"
+
+ args="${args} --win-client-ident"
+ args="${args} --keep-up --interface ${IFACE}"
+
+ ebegin "Running pump"
+ eval pump "${args}"
+ eend $? || return 1
+
+ _show_address
+ return 0
+}
+
+pump_stop() {
+ # We check for a pump process first as querying for status
+ # causes pump to spawn a process
+ start-stop-daemon --quiet --test --stop --exec /sbin/pump || return 0
+
+ # Check that pump is running on the interface
+ if ! pump --status --interface "${IFACE}" >/dev/null 2>/dev/null ; then
+ return 0
+ fi
+
+ # Pump always releases the lease
+ ebegin "Stopping pump on ${IFACE}"
+ pump --release --interface "${IFACE}"
+ eend $? "Failed to stop pump"
+}
+
+# vim: set ts=4 :
diff --git a/net.Linux/tuntap.sh b/net.Linux/tuntap.sh
new file mode 100644
index 00000000..829bf138
--- /dev/null
+++ b/net.Linux/tuntap.sh
@@ -0,0 +1,57 @@
+# Copyright 2004-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+tuntap_depend() {
+ before bridge interface macchanger
+}
+
+_config_vars="$_config_vars tunctl"
+
+_is_tuntap() {
+ [ -n "$(get_options tuntap "${SVCNAME}")" ]
+}
+
+tuntap_pre_start() {
+ local tuntap=
+ eval tuntap=\$tuntap_${IFVAR}
+
+ [ -z "${tuntap}" ] && return 0
+
+ if [ ! -a /dev/net/tun ] ; then
+ modprobe tun && sleep 1
+ if [ ! -a /dev/net/tun ] ; then
+ eerror "TUN/TAP support is not present in this kernel"
+ return 1
+ fi
+ fi
+
+ ebegin "Creating Tun/Tap interface ${IFACE}"
+
+ # Set the base metric to 1000
+ metric=1000
+
+ if [ -x /usr/sbin/openvpn ] ; then
+ openvpn --mktun --dev-type "${tuntap}" --dev "${IFACE}" > /dev/null
+ else
+ local opts=
+ eval opts=\$tunctl_${IFVAR}
+ tunctl ${opts} -t "${IFACE}" >/dev/null
+ fi
+ eend $? && save_options tuntap "${tuntap}"
+}
+
+tuntap_post_stop() {
+ _is_tuntap || return 0
+
+ ebegin "Destroying Tun/Tap interface ${IFACE}"
+ if [ -x /usr/sbin/openvpn ] ; then
+ openvpn --rmtun \
+ --dev-type "$(get_options tuntap)" \
+ --dev "${IFACE}" > /dev/null
+ else
+ tunctl -d "${IFACE}" >/dev/null
+ fi
+ eend $?
+}
+
+# vim: set ts=4 :
diff --git a/net.Linux/udhcpc.sh b/net.Linux/udhcpc.sh
new file mode 100644
index 00000000..e59d0049
--- /dev/null
+++ b/net.Linux/udhcpc.sh
@@ -0,0 +1,102 @@
+# Copyright 2004-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+udhcpc_depend() {
+ program start /sbin/udhcpc
+ after interface
+ provide dhcp
+}
+
+_config_vars="$_config_vars dhcp udhcpc"
+
+udhcpc_start() {
+ local args= opt= opts= pidfile="/var/run/udhcpc-${IFACE}.pid"
+ local sendhost=true cachefile="/var/cache/udhcpc-${IFACE}.lease"
+
+ _wait_for_carrier || return 1
+
+ eval args=\$udhcpc_${IFVAR}
+
+ # Get our options
+ eval opts=\$dhcp_${IFVAR}
+ [ -z "${opts}" ] && opts=${dhcp}
+
+ # Map some generic options to dhcpcd
+ for opt in ${opts} ; do
+ case "${opt}" in
+ nodns) args="${args} --env PEER_DNS=no" ;;
+ nontp) args="${args} --env PEER_NTP=no" ;;
+ nogateway) args="${args} --env PEER_ROUTERS=no" ;;
+ nosendhost) sendhost=false;
+ esac
+ done
+
+ [ "${metric:-0}" != "0" ] && args="${args} --env IF_METRIC=${metric}"
+
+ ebegin "Running udhcpc"
+
+ # Try and load the cache if it exists
+ if [ -f "${cachefile}" ]; then
+ case "$ {args} " in
+ *" --request="*|*" -r "*) ;;
+ *)
+ local x=$(cat "${cachefile}")
+ # Check for a valid ip
+ case "${x}" in
+ *.*.*.*) args="${args} --request=${x}" ;;
+ esac
+ ;;
+ esac
+ fi
+
+ case " ${args} " in
+ *" --quit "*|*" -q "*) x="/sbin/udhcpc" ;;
+ *) x="start-stop-daemon --start --exec /sbin/udhcpc \
+ --pidfile \"${pidfile}\" --" ;;
+ esac
+
+ case " ${args} " in
+ *" --hosname="*|*" -h "*|*" -H "*) ;;
+ *)
+ if ${sendhost} ; then
+ local hname="$(hostname)"
+ if [ "${hname}" != "(none)" ] && [ "${hname}" != "localhost" ]; then
+ args="${args} --hostname='${hname}'"
+ fi
+ fi
+ ;;
+ esac
+
+ eval "${x}" "${args}" --interface="${IFACE}" --now \
+ --script="${RC_LIBDIR}"/sh/udhcpc.sh \
+ --pidfile="${pidfile}" >/dev/null
+ eend $? || return 1
+
+ _show_address
+ return 0
+}
+
+udhcpc_stop() {
+ local pidfile="/var/run/udhcpc-${IFACE}.pid" opts= sig="TERM"
+ [ ! -f "${pidfile}" ] && return 0
+
+ # Get our options
+ eval opts=\$dhcp_${IFVAR}
+ [ -z "${opts}" ] && opts=${dhcp}
+
+ ebegin "Stopping udhcpc on ${IFACE}"
+ case " ${opts} " in
+ *" release "*)
+ sig="USR2"
+ if [ -f /var/cache/udhcpc-"${IFACE}".lease ] ; then
+ rm -f /var/cache/udhcpc-"${IFACE}".lease
+ fi
+ ;;
+ esac
+
+ start-stop-daemon --stop --quiet --signal "${sig}" \
+ --exec /sbin/udhcpc --pidfile "${pidfile}"
+ eend $?
+}
+
+# vim: set ts=4 :
diff --git a/net.Linux/vlan.sh b/net.Linux/vlan.sh
new file mode 100644
index 00000000..fef4f2c5
--- /dev/null
+++ b/net.Linux/vlan.sh
@@ -0,0 +1,108 @@
+# Copyright 2004-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+vlan_depend() {
+ program /sbin/vconfig
+ after interface
+ before dhcp
+}
+
+_config_vars="$_config_vars vlans"
+
+_is_vlan() {
+ [ ! -d /proc/net/vlan ] && return 1
+ grep -q "^${IFACE}[[:space:]]+" /proc/net/vlan/config
+}
+
+_get_vlans() {
+ [ -e /proc/net/vlan/config ] || return 1
+ sed -n -e 's/^\(.*[0-9]\) \(.* \) .*'"${IFACE}"'$/\1/p' /proc/net/vlan/config
+}
+
+_check_vlan() {
+ if [ ! -d /proc/net/vlan ] ; then
+ modprobe 8021q
+ if [ ! -d /proc/net/vlan ] ; then
+ eerror "VLAN (802.1q) support is not present in this kernel"
+ return 1
+ fi
+ fi
+}
+
+vlan_pre_start() {
+ eval $(_get_array "vconfig_${IFVAR}")
+ [ $# = "0" ] && return 0
+
+ _check_vlan || return 1
+ _exists || return 1
+
+ local v= x= e=
+ for v in "$@" ; do
+ case "${v}" in
+ set_name_type" "*) x=${v} ;;
+ *) x="$(echo "${v}" | sed -e "s/ / ${IFACE} /g")"
+ [ "${x}" = "${v}" ] && x="${x} ${IFACE}"
+ ;;
+ esac
+
+ set -x
+ e="$(vconfig ${x} 2>&1 1>/dev/null)"
+ set +x
+ [ -z "${e}" ] && continue
+ eerror "${e}"
+ return 1
+ done
+}
+
+vlan_post_start() {
+ eval $(_get_array "vlans_${IFVAR}")
+ [ $# = "0" ] && return 0
+
+ _check_vlan || return 1
+ _exists || return 1
+
+ local vlan= e= s=
+ for vlan in "$@" ; do
+ einfo "Adding VLAN ${vlan} to ${IFACE}"
+ e="$(vconfig add "${IFACE}" "${vlan}" 2>&1 1>/dev/null)"
+ if [ -n "${e}" ] ; then
+ eend 1 "${e}"
+ continue
+ fi
+
+ # We may not want to start the vlan ourselves
+ eval s=\$vlan_start_${IFVAR}
+ [ "${s:-yes}" != "yes" ] && continue
+
+ # We need to work out the interface name of our new vlan id
+ local ifname="$( \
+ sed -n -e 's/^\([^ \t]*\) *| '"${vlan}"' *| .*'"${iface}"'$/\1/p' \
+ /proc/net/vlan/config )"
+ mark_service_started "net.${ifname}"
+ (
+ export SVCNAME="net.${ifname}"
+ start
+ ) || mark_service_stopped "net.${ifname}"
+ done
+
+ return 0
+}
+
+vlan_post_stop() {
+ local vlan=
+
+ for vlan in $(_get_vlans) ; do
+ einfo "Removing VLAN ${vlan##*.} from ${IFACE}"
+ (
+ export SVCNAME="net.${vlan}"
+ stop
+ ) && {
+ mark_service_stopped "net.${vlan}"
+ vconfig rem "${vlan}" >/dev/null
+ }
+ done
+
+ return 0
+}
+
+# vim: set ts=4 :
diff --git a/net/Makefile b/net/Makefile
new file mode 100644
index 00000000..5ed3d8b9
--- /dev/null
+++ b/net/Makefile
@@ -0,0 +1,6 @@
+DIR = /$(LIB)/rcscripts/net
+FILES = dhclient.sh dhcpcd.sh macchanger.sh macnet.sh ssidnet.sh system.sh \
+ wpa_supplicant.sh
+
+TOPDIR = ..
+include $(TOPDIR)/default.mk
diff --git a/net/dhclient.sh b/net/dhclient.sh
new file mode 100644
index 00000000..14838d00
--- /dev/null
+++ b/net/dhclient.sh
@@ -0,0 +1,75 @@
+# Copyright 2004-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+dhclient_depend() {
+ after interface
+ program start /sbin/dhclient
+ provide dhcp
+}
+
+_config_vars="$_config_vars dhcp dhcpcd"
+
+dhclient_start() {
+ local args= opt= opts= pidfile="/var/run/dhclient-${IFACE}.pid"
+ local sendhost=true dconf=
+
+ _wait_for_carrier || return 1
+
+ # Get our options
+ eval opts=\$dhcp_${IFVAR}
+ [ -z "${opts}" ] && opts=${dhcp}
+
+ # Map some generic options to dhcpcd
+ for opt in ${opts} ; do
+ case "${opt}" in
+ nodns) args="${args} -e PEER_DNS=no" ;;
+ nontp) args="${args} -e PEER_NTP=no" ;;
+ nogateway) args="${args} -e PEER_ROUTERS=no" ;;
+ nosendhost) sendhost=false ;;
+ esac
+ done
+
+ # Add our route metric
+ [ "${metric:-0}" != "0" ] && args="${args} -e IF_METRIC=${metric}"
+
+ if ${sendhost} ; then
+ local hname="$(hostname)"
+ if [ "${hname}" != "(none)" -a "${hname}" != "localhost" ]; then
+ dhconf="${dhconf} interface \"${iface}\" {"
+ dhconf="${dhconf} send host-name \"${hname}\";"
+ dhconf="${dhconf}}"
+ fi
+ fi
+
+ # Bring up DHCP for this interface
+ ebegin "Running dhclient"
+ echo "${dhconf}" | start-stop-daemon --start --exec /sbin/dhclient \
+ --pidfile "${pidfile}" -- ${opts} -q -1 -pf "${pidfile}" "${IFACE}"
+ eend $? || return 1
+
+ _show_address
+ return 0
+}
+
+dhclient_stop() {
+ local pidfile="/var/run/dhclient-${IFACE}.pid" opts=
+ [ ! -f "${pidfile}" ] && return 0
+
+ # Get our options
+ if [ -x /sbin/dhclient ] ; then
+ eval opts=\$dhcp_${IFVAR}
+ [ -z "${opts}" ] && opts=${dhcp}
+ fi
+
+ ebegin "Stopping dhclient on ${IFACE}"
+ case " ${opts} " in
+ *" release "*) dhclient -q -r -pf "${pidfile}" "${IFACE}" ;;
+ *)
+ start-stop-daemon --stop --quiet \
+ --exec /sbin/dhclient --pidfile "${pidfile}"
+ ;;
+ esac
+ eend $?
+}
+
+# vim: set ts=4 :
diff --git a/net/dhcpcd.sh b/net/dhcpcd.sh
new file mode 100644
index 00000000..f90f3336
--- /dev/null
+++ b/net/dhcpcd.sh
@@ -0,0 +1,71 @@
+# Copyright 2004-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+dhcpcd_depend() {
+ after interface
+ program start /sbin/dhcpcd
+ provide dhcp
+
+ # We prefer dhcpcd over the others
+ after dhclient pump udhcpc
+}
+
+_config_vars="$_config_vars dhcp dhcpcd"
+
+dhcpcd_start() {
+ local args= opt= opts= pidfile="/var/run/dhcpcd-${IFACE}.pid"
+
+ _wait_for_carrier || return 1
+
+ eval args=\$dhcpcd_${IFVAR}
+
+ # Get our options
+ eval opts=\$dhcp_${IFVAR}
+ [ -z "${opts}" ] && opts=${dhcp}
+
+ # Map some generic options to dhcpcd
+ for opt in ${opts} ; do
+ case "${opt}" in
+ nodns) args="${args} -R" ;;
+ nontp) args="${args} -N" ;;
+ nonis) args="${args} -Y" ;;
+ nogateway) args="${args} -G" ;;
+ nosendhost) args="${args} -h ''";
+ esac
+ done
+
+ # Add our route metric
+ [ "${metric:-0}" != "0" ] && args="${args} -m ${metric}"
+
+ # Bring up DHCP for this interface
+ ebegin "Running dhcpcd"
+
+ eval /sbin/dhcpcd "${args}" "${IFACE}"
+ eend $? || return 1
+
+ _show_address
+ return 0
+}
+
+dhcpcd_stop() {
+ local pidfile="/var/run/dhcpcd-${IFACE}.pid" opts=
+ [ ! -f "${pidfile}" ] && return 0
+
+ # Get our options
+ if [ -x /sbin/dhcpcd ] ; then
+ eval opts=\$dhcp_${IFVAR}
+ [ -z "${opts}" ] && opts=${dhcp}
+ fi
+
+ ebegin "Stopping dhcpcd on ${IFACE}"
+ case " ${opts} " in
+ *" release "*) dhcpcd -k "${IFACE}" ;;
+ *)
+ start-stop-daemon --stop --quiet \
+ --exec /sbin/dhcpcd --pidfile "${pidfile}"
+ ;;
+ esac
+ eend $?
+}
+
+# vim: set ts=4 :
diff --git a/net/macchanger.sh b/net/macchanger.sh
new file mode 100644
index 00000000..dce481c8
--- /dev/null
+++ b/net/macchanger.sh
@@ -0,0 +1,88 @@
+# Copyright 2004-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+macchanger_depend() {
+ before macnet
+}
+
+_config_vars="$_config_vars mac"
+
+macchanger_pre_start() {
+ # We don't change MAC addresses from background
+ ${IN_BACKGROUND} && return 0
+
+ local mac= opts=
+
+ eval mac=\$mac_${IFVAR}
+ [ -z "${mac}" ] && return 0
+
+ _exists true || return 1
+
+ ebegin "Changing MAC address of ${IFACE}"
+
+ # The interface needs to be up for macchanger to work most of the time
+ _down
+
+ mac=$(echo "${mac}" | tr '[:upper:]' '[:lower:]')
+ case "${mac}" in
+ # specific mac-addr, i wish there were a shorter way to specify this
+ [0-9a-f][0-9a-f]:[0-9a-f][0-9a-f]:[0-9a-f][0-9a-f]:[0-9a-f][0-9a-f]:[0-9a-f][0-9a-f]:[0-9a-f][0-9a-f])
+ # We don't need macchanger to change to a specific mac address
+ _set_mac_address "${mac}"
+ if eend "$?" ; then
+ mac=$(_get_mac_address)
+ eindent
+ einfo "changed to ${mac}"
+ eoutdent
+ return 0
+ fi
+ ;;
+
+ # increment MAC address, default macchanger behavior
+ increment) opts="${opts}" ;;
+
+ # randomize just the ending bytes
+ random-ending) opts="${opts} -e" ;;
+
+ # keep the same kind of physical layer (eg fibre, copper)
+ random-samekind) opts="${opts} -a" ;;
+
+ # randomize to any known vendor of any physical layer type
+ random-anykind) opts="${opts} -A" ;;
+
+ # fully random bytes
+ random-full|random) opts="${opts} -r" ;;
+
+ # default case is just to pass on all the options
+ *) opts="${opts} ${mac}" ;;
+ esac
+
+ if [ ! -x /sbin/macchanger ] ; then
+ eerror "For changing MAC addresses, emerge net-analyzer/macchanger"
+ return 1
+ fi
+
+ mac=$(/sbin/macchanger ${opts} "${IFACE}" \
+ | sed -n -e 's/^Faked MAC:.*\<\(..:..:..:..:..:..\)\>.*/\U\1/p' )
+ _up
+
+ # Sometimes the interface needs to be up ....
+ if [ -z "${mac}" ] ; then
+ mac=$(/sbin/macchanger ${opts} "${IFACE}" \
+ | sed -n -e 's/^Faked MAC:.*\<\(..:..:..:..:..:..\)\>.*/\U\1/p' )
+ fi
+
+ if [ -z "${mac}" ] ; then
+ eend 1 "Failed to set MAC address"
+ return 1
+ fi
+
+ eend 0
+ eindent
+ einfo "changed to" "${mac}"
+ eoutdent
+
+ return 0
+}
+
+# vim: set ts=4 :
diff --git a/net/macnet.sh b/net/macnet.sh
new file mode 100644
index 00000000..d8db406a
--- /dev/null
+++ b/net/macnet.sh
@@ -0,0 +1,19 @@
+# Copyright 2005-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+macnet_depend() {
+ before rename interface wireless
+ after macchanger
+}
+
+macnet_pre_start() {
+ local mac=$(_get_mac_address 2>/dev/null)
+ [ -z "${mac}" ] && return 0
+
+ vebegin "Configuring ${IFACE} for MAC address ${mac}"
+ mac=$(echo "${mac}" | sed -e 's/://g')
+ _configure_variables "${mac}"
+ veend 0
+}
+
+# vim: set ts=4 :
diff --git a/net/ssidnet.sh b/net/ssidnet.sh
new file mode 100644
index 00000000..379e4d38
--- /dev/null
+++ b/net/ssidnet.sh
@@ -0,0 +1,24 @@
+# Copyright 2004-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+ssidnet_depend() {
+ before interface system
+ after wireless
+}
+
+ssidnet_pre_start() {
+ [ -z "${SSID}" -a -z "${SSIDVAR}" ] && return 0
+
+ local mac=$(_get_ap_mac_address | sed -e 's/://g') x=
+
+ vebegin "Configuring ${IFACE} for SSID ${SSID}"
+ _configure_variables "${mac}" "${SSIDVAR}"
+
+ # Backwards compat for old gateway var
+ eval x=\$gateway_${SSIDVAR}
+ [ -n "${x}" ] && gateway=${x}
+
+ veend 0
+}
+
+# vim: set ts=4 :
diff --git a/net/system.sh b/net/system.sh
new file mode 100644
index 00000000..68abc7fe
--- /dev/null
+++ b/net/system.sh
@@ -0,0 +1,106 @@
+# Copyright 2005-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+_config_vars="$_config_vars dns_servers dns_domain dns_search"
+_config_vars="$_config_vars ntp_servers nis_servers nis_domain"
+
+system_depend() {
+ after interface
+ before dhcp
+}
+
+_system_dns() {
+ local servers= domain= search= x=
+
+ eval servers=\$dns_servers_${IFVAR}
+ [ -z "${servers}" ] && servers=${dns_servers}
+
+ eval domain=\$dns_domain_${IFVAR}
+ [ -z "${domain}" ] && domain=${dns_domain}
+
+ eval search=\$dns_search_${IFVAR}
+ [ -z "${search}" ] && search=${dns_search}
+
+ [ -z "${servers}" -a -z "${domain}" -a -z "${search}" ] && return 0
+
+ local buffer="# Generated by net-scripts for interface ${IFACE}\n"
+ [ -n "${domain}" ] && buffer="${buffer}domain ${domain}\n"
+ [ -n "${search}" ] && buffer="${buffer}search ${search}\n"
+
+ for x in ${servers} ; do
+ buffer="${buffer}nameserver ${x}\n"
+ done
+
+ # Support resolvconf if we have it.
+ if [ -x /sbin/resolvconf ] ; then
+ printf "${buffer}" | resolvconf -a "${IFACE}"
+ else
+ printf "${buffer}" > /etc/resolv.conf
+ chmod 644 /etc/resolv.conf
+ fi
+}
+
+_system_ntp() {
+ local servers= buffer= x=
+
+ eval servers=\$ntp_servers_${IFVAR}
+ [ -z ${servers} ] && servers=${ntp_servers}
+ [ -z ${servers} ] && return 0
+
+ buffer="# Generated by net-scripts for interface ${IFACE}\n"
+ buffer="${buffer}restrict default noquery notrust nomodify\n"
+ buffer="${buffer}restrict 127.0.0.1\n"
+
+ for x in ${servers} ; do
+ buffer="${buffer}restrict ${x} nomodify notrap noquery\n"
+ buffer="${buffer}server ${x}\n"
+ done
+
+ buffer="${buffer}driftfile /var/lib/ntp/ntp.drift\n"
+ buffer="${buffer}logfile /var/log/ntp.log\n"
+
+ printf "${buffer}" > /etc/ntp.conf
+ chmod 644 /etc/ntp.conf
+}
+
+_system_nis() {
+ local servers= domain= x= buffer=
+
+ eval servers=\$nis_servers_${IFVAR}
+ [ -z "${servers}" ] && servers=${nis_servers}
+
+ eval domain=\$nis_domain_${IFVAR}
+ [ -z "${domain}" ] && domain=${nis_domain}
+
+ [ -z "${servers}" -a -z "${domain}" ] && return 0
+
+ buffer="# Generated by net-scripts for interface ${iface}\n"
+
+ if [ -n "${domain}" ] ; then
+ hostname -y "${domain}"
+ if [ -n "${servers}" ] ; then
+ for x in ${servers} ; do
+ buffer="${buffer}domain ${domain} server ${x}\n"
+ done
+ else
+ buffer="${buffer}domain ${domain} broadcast\n"
+ fi
+ else
+ for x in ${servers} ; do
+ buffer="${buffer}ypserver ${x}\n"
+ done
+ fi
+
+ printf "${buffer}" > /etc/yp.conf
+ chmod 644 /etc/yp.conf
+}
+
+system_pre_start() {
+ _system_dns
+ _system_ntp
+ _system_nis
+
+ return 0
+}
+
+# vim: set ts=4 :
diff --git a/net/wpa_supplicant.sh b/net/wpa_supplicant.sh
new file mode 100644
index 00000000..7ba5bb4f
--- /dev/null
+++ b/net/wpa_supplicant.sh
@@ -0,0 +1,164 @@
+# Copyright 2004-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+wpa_supplicant_depend() {
+ program start /sbin/wpa_supplicant
+ after macnet plug
+ before interface
+ provide wireless
+
+ # Prefer us over iwconfig
+ after iwconfig
+}
+
+# Only set these functions if not set already
+# IE, prefer to use iwconfig
+if ! type _get_ssid >/dev/null 2>/dev/null ; then
+_get_ssid() {
+ local timeout=5 ssid=
+
+ while [ ${timeout} -gt 0 ] ;do
+ ssid=$(wpa_cli -i"${IFACE}" status | sed -n -e 's/^ssid=//p')
+ if [ -n "${ssid}" ] ; then
+ echo "${ssid}"
+ return 0
+ fi
+ sleep 1
+ timeout=$((timeout - 1))
+ done
+
+ return 1
+}
+
+_get_ap_mac_address() {
+ wpa_cli -i"${IFACE}" status | sed -n -e 's/^bssid=\(.*\)$/\1/p' \
+ | tr '[:lower:]' '[:upper:]'
+}
+fi
+
+wpa_supplicant_pre_start() {
+ local opts= cfgfile= ctrl_dir=
+
+ _is_wireless || return 0
+
+ # We don't configure wireless if we're being called from
+ # the background unless we're not currently running
+ if [ "${IN_BACKGROUND}" = "true" ] ; then
+ if service_started_daemon "${SVCNAME}" /sbin/wpa_supplicant ; then
+ SSID=$(_get_ssid "${IFACE}")
+ SSIDVAR=$(_shell_var "${SSID}")
+ save_options "SSID" "${SSID}"
+ metric=2000
+ fi
+ return 0
+ fi
+
+ save_options "SSID" ""
+ eval opts=\$wpa_supplicant_${IFVAR}
+ ebegin "Starting wpa_supplicant on" "${IFVAR}"
+
+
+ if [ -x /sbin/iwconfig ] ; then
+ local x=
+ for x in txpower rate rts frag ; do
+ iwconfig "${IFACE}" "${x}" auto 2>/dev/null
+ done
+ fi
+
+ cfgfile=${opts##* -c}
+ if [ -n "${cfgfile}" -a "${cfgfile}" != "${opts}" ] ; then
+ case "${cfgfile}" in
+ " "*) cfgfile=${cfgfile# *} ;;
+ esac
+ cfgfile=${cfgfile%% *}
+ else
+ # Support new and old style locations
+ cfgfile="/etc/wpa_supplicant/wpa_supplicant-${IFACE}.conf"
+ [ ! -e "${cfgfile}" ] \
+ && cfgfile="/etc/wpa_supplicant/wpa_supplicant.conf"
+ [ ! -e ${cfgfile} ] \
+ && cfgfile="/etc/wpa_supplicant.conf"
+ opts="${opts} -c ${cfgfile}"
+ fi
+
+ if [ ! -f ${cfgfile} ] ; then
+ eend 1 "/etc/wpa_supplicant/wpa_supplicant.conf not found"
+ return 1
+ fi
+
+ # Work out where the ctrl_interface dir is if it's not specified
+ local ctrl_dir=$(sed -n -e 's/[ \t]*#.*//g;s/[ \t]*$//g;s/^ctrl_interface=//p' "${cfgfile}")
+ if [ -z "${ctrl_dir}" ] ; then
+ ctrl_dir=${opts##* -C}
+ if [ -n "${ctrl_dir}" -a "${ctrl_dir}" != "${opts}" ] ; then
+ case "${ctrl_dir}" in
+ " "*) ctrl_dir=${ctrl_dir# *} ;;
+ esac
+ ctrl_dir=${ctrl_dir%% *}
+ else
+ ctrl_dir="/var/run/wpa_supplicant"
+ opts="${opts} -C ${ctrl_dir}"
+ fi
+ fi
+ save_options ctrl_dir "${ctrl_dir}"
+
+ actfile="/etc/wpa_supplicant/wpa_cli.sh"
+
+ start-stop-daemon --start --exec /sbin/wpa_supplicant \
+ --pidfile "/var/run/wpa_supplicant-${IFACE}.pid" \
+ -- ${opts} -W -B -i "${IFACE}" \
+ -P "/var/run/wpa_supplicant-${IFACE}.pid"
+ eend $? || return 1
+
+ # Starting wpa_supplication-0.4.0, we can get wpa_cli to
+ # start/stop our scripts from wpa_supplicant messages
+ local inact=false
+ service_inactive "${SVCNAME}" && inact=true
+ mark_service_inactive "${SVCNAME}"
+
+ ebegin "Starting wpa_cli on" "${IFACE}"
+ start-stop-daemon --start --exec /bin/wpa_cli \
+ --pidfile "/var/run/wpa_cli-${IFACE}.pid" \
+ -- -a /etc/wpa_supplicant/wpa_cli.sh -p "${ctrl_dir}" -i "${IFACE}" \
+ -P "/var/run/wpa_cli-${IFACE}.pid" -B
+ if eend $? ; then
+ ebegin "Backgrounding ..."
+ exit 1
+ fi
+
+ # wpa_cli failed to start? OK, error here
+ start-stop-daemon --quiet --stop --exec /sbin/wpa_supplicant \
+ --pidfile "/var/run/wpa_supplicant-${IFACE}.pid"
+ ${inact} || mark_service_stopped "${SVCNAME}"
+ return 1
+}
+
+wpa_supplicant_post_stop() {
+ if [ "${IN_BACKGROUND}" = "true" ] ; then
+ # Only stop wpa_supplicant if it's not the controlling daemon
+ ! service_started_daemon "${SVCNAME}" /sbin/wpa_supplicant 1
+ fi
+ [ $? != 0 ] && return 0
+
+ local pidfile="/var/run/wpa_cli-${IFACE}.pid"
+ if [ -f ${pidfile} ] ; then
+ ebegin "Stopping wpa_cli on ${IFACE}"
+ start-stop-daemon --stop --exec /bin/wpa_cli \
+ --pidfile "${pidfile}"
+ eend $?
+ fi
+
+ pidfile="/var/run/wpa_supplicant-${IFACE}.pid"
+ if [ -f ${pidfile} ] ; then
+ ebegin "Stopping wpa_supplicant on ${IFACE}"
+ start-stop-daemon --stop --exec /sbin/wpa_supplicant \
+ --pidfile "${pidfile}"
+ eend $?
+ fi
+
+ # If wpa_supplicant exits uncleanly, we need to remove the stale dir
+ [ -S "/var/run/wpa_supplicant/${IFACE}" ] \
+ && rm -f "/var/run/wpa_supplicant/${IFACE}"
+}
+
+# vim: set ts=4 :
diff --git a/runlevels.BSD/Makefile b/runlevels.BSD/Makefile
new file mode 100644
index 00000000..a130621f
--- /dev/null
+++ b/runlevels.BSD/Makefile
@@ -0,0 +1,12 @@
+BOOTLEVEL = net.lo0 sysctl syscons
+DEFAULT =
+
+install:
+ install -d -m 0755 $(DESTDIR)/etc/runlevels/boot || exit $$?
+ for x in $(BOOT) ; do ln -snf ../../init.d/"$$x" $(DESTDIR)/etc/runlevels/boot/"$$x" || exit $$? ; done
+ install -d -m 0755 $(DESTDIR)/etc/runlevels/default || exit $$?
+ for x in $(DEFAULT) ; do ln -snf ../../init.d/"$$x" $(DESTDIR)/etc/runlevels/default/"$$x" || exit $$? ; done
+
+.PHONY: all clean
+
+# vim: set ts=4 :
diff --git a/runlevels.Linux/Makefile b/runlevels.Linux/Makefile
new file mode 100644
index 00000000..aa84c1c0
--- /dev/null
+++ b/runlevels.Linux/Makefile
@@ -0,0 +1,12 @@
+BOOT = consolefont keymaps modules net.lo volumes
+DEFAULT = hdparm
+
+install:
+ install -d -m 0755 $(DESTDIR)/etc/runlevels/boot || exit $$? ; \
+ for x in $(BOOT) ; do ln -snf ../../init.d/"$$x" $(DESTDIR)/etc/runlevels/boot/"$$x" || exit $$? ; done ; \
+ install -d -m 0755 $(DESTDIR)/etc/runlevels/default || exit $$? ; \
+ for x in $(DEFAULT) ; do ln -snf ../../init.d/"$$x" $(DESTDIR)/etc/runlevels/default/"$$x" || exit $$? ; done ; \
+
+.PHONY: all clean
+
+# vim: set ts=4 :
diff --git a/runlevels/Makefile b/runlevels/Makefile
new file mode 100644
index 00000000..0cc60ed3
--- /dev/null
+++ b/runlevels/Makefile
@@ -0,0 +1,12 @@
+BOOT = bootmisc checkroot checkfs clock hostname localmount rmnologin urandom
+DEFAULT = local netmount
+
+install:
+ install -d -m 0755 $(DESTDIR)/etc/runlevels/boot || exit $$? ; \
+ for x in $(BOOT) ; do ln -snf ../../init.d/"$$x" $(DESTDIR)/etc/runlevels/boot/"$$x" || exit $$? ; done ; \
+ install -d -m 0755 $(DESTDIR)/etc/runlevels/default || exit $$? ; \
+ for x in $(DEFAULT) ; do ln -snf ../../init.d/"$$x" $(DESTDIR)/etc/runlevels/default/"$$x" || exit $$? ; done ; \
+
+.PHONY: all clean
+
+# vim: set ts=4 :
diff --git a/sh.BSD/Makefile b/sh.BSD/Makefile
new file mode 100644
index 00000000..9c08bbd6
--- /dev/null
+++ b/sh.BSD/Makefile
@@ -0,0 +1,5 @@
+DIR = /$(LIB)/rcscripts/sh
+EXES = init.sh
+
+TOPDIR = ..
+include $(TOPDIR)/default.mk
diff --git a/sh.BSD/init.sh b/sh.BSD/init.sh
new file mode 100755
index 00000000..63f26927
--- /dev/null
+++ b/sh.BSD/init.sh
@@ -0,0 +1,47 @@
+#!/bin/sh
+# Copyright 1999-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+# void single_user()
+#
+# Drop to a shell, remount / ro, and then reboot
+#
+single_user() {
+ exit 1
+}
+
+# This basically mounts $svcdir as a ramdisk, but preserving its content
+# which allows us to run depscan.sh
+# FreeBSD has a nice ramdisk - we don't set a size as we should always
+# be fairly small and we unmount them after the boot level is done anyway
+# NOTE we don't set a size for Linux either
+mount_svcdir() {
+ local dotmp=false
+ if [ -e "${RC_SVCDIR}"/deptree ] ; then
+ dotmp=true
+ try mdconfig -a -t malloc -s 1m -u 1
+ try newfs /dev/md1
+ try mount /dev/md1 "${RC_LIBDIR}"/tmp
+ cp -p "${RC_SVCDIR}"/deptree "${RC_SVCDIR}"/nettree \
+ "${RC_LIBDIR}"/tmp 2>/dev/null
+ fi
+ try mdconfig -a -t malloc -s "${RC_SVCSIZE:-1024}"k -u 0
+ try newfs -b 4096 -i 1024 -n /dev/md0
+ try mount -o rw,noexec,nosuid /dev/md0 "${RC_SVCDIR}"
+ if ${dotmp} ; then
+ cp -p "${RC_LIBDIR}"/tmp/deptree "${RC_LIBDIR}"/tmp/nettree \
+ "${RC_SVCDIR}" 2>/dev/null
+ try umount "${RC_LIBDIR}"/tmp
+ try mdconfig -d -u 1
+ fi
+}
+
+. "${RC_LIBDIR}"/sh/init-functions.sh
+. "${RC_LIBDIR}"/sh/functions.sh
+
+# Disable devd until we need it
+sysctl hw.bus.devctl_disable=1 >/dev/null
+
+. "${RC_LIBDIR}"/sh/init-common-post.sh
+
+# vim: set ts=4 :
diff --git a/sh.Linux/Makefile b/sh.Linux/Makefile
new file mode 100644
index 00000000..cd286002
--- /dev/null
+++ b/sh.Linux/Makefile
@@ -0,0 +1,5 @@
+DIR = /$(LIB)/rcscripts/sh
+EXES = init.sh
+
+TOPDIR = ..
+include $(TOPDIR)/default.mk
diff --git a/sh.Linux/init.sh b/sh.Linux/init.sh
new file mode 100755
index 00000000..fc19bddb
--- /dev/null
+++ b/sh.Linux/init.sh
@@ -0,0 +1,251 @@
+#!/bin/sh
+# Copyright 1999-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+# void single_user()
+#
+# Drop to a shell, remount / ro, and then reboot
+#
+single_user() {
+ if [ "${RC_SYS}" = "VPS" ] ; then
+ einfo "Halting"
+ halt -f
+ return
+ fi
+
+ sulogin ${CONSOLE}
+ einfo "Unmounting filesystems"
+ if [ -c /dev/null ] ; then
+ mount -a -o remount,ro 2>/dev/null
+ else
+ mount -a -o remount,ro
+ fi
+ einfo "Rebooting"
+ reboot -f
+}
+
+# This basically mounts $svcdir as a ramdisk, but preserving its content
+# which allows us to run depscan.sh
+# The tricky part is finding something our kernel supports
+# tmpfs and ramfs are easy, so force one or the other
+mount_svcdir() {
+ local fs= fsopts="-o rw,noexec,nodev,nosuid" devdir="none" devtmp="none" x=
+ local svcsize=${svcsize:-1024}
+ local mntcmd=$(fstabinfo --mount-cmd "${RC_LIBDIR}")
+
+ if grep -Eq "[[:space:]]+tmpfs$" /proc/filesystems ; then
+ fs="tmpfs"
+ fsopts="${fsopts},mode=0755,size=${svcsize}k"
+ elif grep -Eq "[[:space:]]+ramfs$" /proc/filesystems ; then
+ fs="ramfs"
+ fsopts="${fsopts},mode=0755,size=${svcsize}k"
+ elif [ -e /dev/ram0 -a -e /dev/ram1 ] \
+ && grep -Eq "[[:space:]]+ext2$" /proc/filesystems ; then
+ devdir="/dev/ram0"
+ devtmp="/dev/ram1"
+ fs="ext2"
+ for x in ${devdir} ${devtmp} ; do
+ try dd if=/dev/zero of="${x}" bs=1k count="${svcsize}"
+ try mkfs -t "${fs}" -i 1024 -vm0 "${x}" "${svcsize}"
+ done
+ else
+ echo
+ eerror "Gentoo Linux requires tmpfs, ramfs or 2 ramdisks + ext2"
+ eerror "compiled into the kernel"
+ echo
+ single_user
+ fi
+
+ # If we have no entry in fstab for $svcdir, provide our own
+ if [ -z "${mntcmd}" ] ; then
+ mntcmd="-t ${fs} ${fsopts} ${devdir} ${RC_SVCDIR}"
+ fi
+
+ local dotmp=false
+ if [ -e "${RC_SVCDIR}"/deptree ] ; then
+ dotmp=true
+ try mount -n -t "${fs}" -o rw "${devtmp}" "${RC_LIBDIR}"/tmp
+ cp -p "${RC_SVCDIR}"/deptree "${RC_SVCDIR}"/nettree \
+ "${RC_LIBDIR}"/tmp 2>/dev/null
+ fi
+ try mount -n ${mntcmd}
+ if ${dotmp} ; then
+ cp -p "${RC_LIBDIR}"/tmp/deptree "${RC_LIBDIR}"/tmp/nettree \
+ "${RC_SVCDIR}" 2>/dev/null
+ try umount -n "${RC_LIBDIR}"/tmp
+ fi
+}
+
+_RC_GET_KV_CACHE=""
+get_KV() {
+ [ -z "${_RC_GET_KV_CACHE}" ] \
+ && _RC_GET_KV_CACHE="$(uname -r)"
+
+ echo "$(KV_to_int "${_RC_GET_KV_CACHE}")"
+
+ return $?
+}
+
+# Try and set a font as early as we can
+ttydev=${CONSOLE:-/dev/tty1}
+if [ -c "${ttydev}" ] ; then
+ ttydev="-C ${ttydev}"
+else
+ [ -c /dev/vc/1 ] && ttydev="-C /dev/vc/1" || ttydev=
+fi
+[ -r "${RC_LIBDIR}"/console/font ] \
+ && /bin/setfont ${ttydev} "${RC_LIBDIR}"/console/font
+[ -r "${RC_LIBDIR}"/console/map ] \
+ && /bin/setfont ${ttydev} -m "${RC_LIBDIR}"/console/map
+[ -r "${RC_LIBDIR}"/console/unimap ] \
+ && /bin/setfont ${ttydev} -u "${RC_LIBDIR}"/console/unimap
+unset ttydev
+
+. /etc/init.d/functions.sh
+. "${RC_LIBDIR}"/sh/init-functions.sh
+. "${RC_LIBDIR}"/sh/rc-functions.sh
+
+# Set the console loglevel to 1 for a cleaner boot
+# the logger should anyhow dump the ring-0 buffer at start to the
+# logs, and that with dmesg can be used to check for problems
+${RC_DMESG_LEVEL+/bin/dmesg -n ${RC_DMESG_LEVEL}}
+
+check_statedir /proc
+
+# By default VServer already has /proc mounted, but OpenVZ does not!
+if [ ! -e /proc/self/stat ] ; then
+ procfs="proc"
+ [ "${RC_UNAME}" = "GNU/kFreeBSD" ] && proc="linprocfs"
+ ebegin "Mounting ${procfs} at /proc"
+ mntcmd="$(fstabinfo --mount-cmd /proc)"
+ try mount -n ${mntcmd:--t ${procfs} -o noexec,nosuid,nodev proc /proc}
+ eend $?
+fi
+
+# Read off the kernel commandline to see if there's any special settings
+# especially check to see if we need to set the CDBOOT environment variable
+# Note: /proc MUST be mounted
+if [ -r /sbin/livecd-functions.sh ] ; then
+ . /sbin/livecd-functions.sh
+ livecd_read_commandline
+fi
+
+[ "$(KV_to_int "$(uname -r)")" -ge "$(KV_to_int "2.6.0")" ]
+K26=$?
+
+if [ "${RC_UNAME}" != "GNU/kFreeBSD" -a "${RC_NAME}" != "VPS" -a "${K26}" = "0" ] ; then
+ if [ -d /sys ] ; then
+ ebegin "Mounting sysfs at /sys"
+ mntcmd="$(fstabinfo --mount-cmd /sys)"
+ try mount -n ${mntcmd:--t sysfs -o noexec,nosuid,nodev sysfs /sys}
+ eend $?
+ else
+ ewarn "No /sys to mount sysfs needed in 2.6 and later kernels!"
+ fi
+fi
+
+check_statedir /dev
+
+devfs_mounted=
+if [ -e /dev/.devfsd ] ; then
+ # make sure devfs is actually mounted and it isnt a bogus file
+ devfs_mounted=$(mountinfo --fstype-regex devfs)
+fi
+
+# Try to figure out how the user wants /dev handled
+# - check $RC_DEVICES from /etc/conf.d/rc
+# - check boot parameters
+# - make sure the required binaries exist
+# - make sure the kernel has support
+if [ "${RC_DEVICES}" = "static" -o "${RC_SYS}" = "VPS" ] ; then
+ ebegin "Using existing device nodes in /dev"
+ eend 0
+elif [ "${RC_UNAME}" = "GNU/kFreeBSD" ] ; then
+ ebegin "Using kFreeBSD devfs in /dev"
+ eend 0
+else
+ fellback_to_devfs="no"
+ case "${RC_DEVICES}" in
+ devfs) devfs="yes"
+ udev="no"
+ ;;
+ udev) devfs="yes"
+ udev="yes"
+ fellback_to_devfs="yes"
+ ;;
+ auto|*) devfs="yes"
+ udev="yes"
+ ;;
+ esac
+
+ # Check udev prerequisites and kernel params
+ if [ "${udev}" = "yes" ] ; then
+ if get_bootparam "noudev" || ! has_addon udev-start || \
+ [ -n "${devfs_mounted}" -o "${K26}" != 0 ] ; then
+ udev="no"
+ fi
+ fi
+
+ # Check devfs prerequisites and kernel params
+ if [ "${devfs}" = "yes" ] ; then
+ if get_bootparam "nodevfs" || ! has_addon devfs-start ||
+ [ "${udev}" = "yes" -o ! -r /proc/filesystems ] ; then
+ devfs="no"
+ elif ! grep -Eq "[[:space:]]+devfs$" /proc/filesystems ; then
+ devfs="no"
+ fi
+ fi
+
+ # Actually start setting up /dev now
+ if [ "${udev}" = "yes" ] ; then
+ start_addon udev
+
+ # With devfs, /dev can be mounted by the kernel ...
+ elif [ "${devfs}" = "yes" ] ; then
+ start_addon devfs
+
+ # Did the user want udev in the config file but for
+ # some reason, udev support didnt work out ?
+ if [ "${fellback_to_devfs}" = "yes" ] ; then
+ ewarn "You wanted udev but support for it was not available!"
+ ewarn "Please review your system after it's booted!"
+ fi
+ fi
+
+ # OK, if we got here, things are probably not right :)
+ if [ "${devfs}" = "no" -a "${udev}" = "no" ] ; then
+ :
+ fi
+fi
+
+# From linux-2.6 we need to mount /dev/pts again ...
+if [ "${RC_UNAME}" != "GNU/kFreeBSD" -a "${K26}" = "0" ] ; then
+ if grep -Eq "[[:space:]]+devpts$" /proc/filesystems && \
+ ! mountinfo /dev/pts > /dev/null ; then
+ if [ ! -d /dev/pts ] && \
+ [ "${devfs}" = "yes" -o "${udev}" = "yes" ] ; then
+ # Make sure we have /dev/pts
+ mkdir -p /dev/pts >/dev/null 2>/dev/null || \
+ ewarn "Could not create /dev/pts!"
+ fi
+
+ if [ -d /dev/pts ] ; then
+ ebegin "Mounting devpts at /dev/pts"
+ mntcmd="$(fstabinfo --mount-cmd /dev/pts)"
+ try mount -n ${mntcmd:--t devpts -o gid=5,mode=0620,noexec,nosuid devpts /dev/pts}
+ eend $?
+ fi
+ fi
+fi
+
+# If booting off CD, we want to update inittab before setting the runlevel
+if [ -f /sbin/livecd-functions.sh -a -n "${CDBOOT}" ] ; then
+ ebegin "Updating inittab"
+ livecd_fix_inittab
+ eend $?
+ /sbin/telinit q &>/dev/null
+fi
+
+. "${RC_LIBDIR}"/sh/init-common-post.sh
+
+# vim: set ts=4 :
diff --git a/sh/Makefile b/sh/Makefile
new file mode 100644
index 00000000..ac50fa90
--- /dev/null
+++ b/sh/Makefile
@@ -0,0 +1,7 @@
+DIR = /$(LIB)/rcscripts/sh
+FILES = functions.sh init-functions.sh init-common-post.sh \
+ rc-functions.sh rc-mount.sh
+EXES = gendepends.sh net.sh rc-mount.sh rc-help.sh runscript.sh
+
+TOPDIR = ..
+include $(TOPDIR)/default.mk
diff --git a/sh/functions.sh b/sh/functions.sh
new file mode 100644
index 00000000..d1327ad5
--- /dev/null
+++ b/sh/functions.sh
@@ -0,0 +1,157 @@
+# Copyright 1999-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+# Please keep this useable by every shell in portage
+
+RC_GOT_FUNCTIONS="yes"
+
+eindent() {
+ if [ -n "${RC_EBUFFER}" ] ; then
+ "${RC_LIBDIR}"/bin/eindent
+ else
+ RC_EINDENT=$((${RC_EINDENT:-0} + 2))
+ [ "${RC_EINDENT}" -gt 40 ] && RC_EINDENT=40
+ export RC_EINDENT
+ fi
+}
+
+eoutdent() {
+ if [ -n "${RC_EBUFFER}" ] ; then
+ "${RC_LIBDIR}"/bin/eoutdent
+ else
+ RC_EINDENT=$((${RC_EINDENT:-0} - 2))
+ [ "${RC_EINDENT}" -lt 0 ] && RC_EINDENT=0
+ fi
+ return 0
+}
+
+# void esyslog(char* priority, char* tag, char* message)
+#
+# use the system logger to log a message
+#
+esyslog() {
+ local pri= tag=
+
+ if [ -x /usr/bin/logger ] ; then
+ pri="$1"
+ tag="$2"
+
+ shift 2
+ [ -z "$*" ] && return 0
+
+ /usr/bin/logger -p "${pri}" -t "${tag}" -- "$*"
+ fi
+
+ return 0
+}
+
+# Safer way to list the contents of a directory,
+# as it do not have the "empty dir bug".
+#
+# char *dolisting(param)
+#
+# print a list of the directory contents
+#
+# NOTE: quote the params if they contain globs.
+# also, error checking is not that extensive ...
+#
+dolisting() {
+ local x= y= mylist= mypath="$*"
+
+ # Here we use file globbing instead of ls to save on forking
+ for x in ${mypath} ; do
+ [ ! -e "${x}" ] && continue
+
+ if [ -L "${x}" -o -f "${x}" ] ; then
+ mylist="${mylist} "${x}
+ elif [ -d "${x}" ] ; then
+ [ "${x%/}" != "${x}" ] && x=${x%/}
+
+ for y in "${x}"/* ; do
+ [ -e "${y}" ] && mylist="${mylist} ${y}"
+ done
+ fi
+ done
+
+ echo "${mylist# *}"
+}
+
+# bool is_older_than(reference, files/dirs to check)
+#
+# return 0 if any of the files/dirs are newer than
+# the reference file
+#
+# EXAMPLE: if is_older_than a.out *.o ; then ...
+is_older_than() {
+ local x= ref="$1"
+ shift
+
+ for x in "$@" ; do
+ [ -e "${x}" ] || continue
+ # We need to check the mtime if it's a directory too as the
+ # contents may have changed.
+ [ "${x}" -nt "${ref}" ] && return 0
+ [ -d "${x}" ] && is_older_than "${ref}" "${x}"/* && return 0
+ done
+
+ return 1
+}
+
+uniqify() {
+ local result=
+ while [ -n "$1" ] ; do
+ case " ${result} " in
+ *" $1 "*) ;;
+ *) result="${result} $1" ;;
+ esac
+ shift
+ done
+ echo "${result# *}"
+}
+
+KV_to_int() {
+ [ -z $1 ] && return 1
+
+ local KV_MAJOR=${1%%.*}
+ local x=${1#*.}
+ local KV_MINOR=${x%%.*}
+ x=${1#*.*.}
+ local KV_MICRO=${x%%-*}
+ local KV_int=$((${KV_MAJOR} * 65536 + ${KV_MINOR} * 256 + ${KV_MICRO} ))
+
+ # We make version 2.2.0 the minimum version we will handle as
+ # a sanity check ... if its less, we fail ...
+ [ "${KV_int}" -lt 131584 ] && return 1
+
+ echo "${KV_int}"
+}
+
+# Setup a basic $PATH. Just add system default to existing.
+# This should solve both /sbin and /usr/sbin not present when
+# doing 'su -c foo', or for something like: PATH= rcscript start
+case "${PATH}" in
+ /lib/rcscripts/bin:/bin:/sbin:/usr/bin:/usr/sbin) ;;
+ /lib/rcscripts/bin:/bin:/sbin:/usr/bin:/usr/sbin:*) ;;
+ *) export PATH="/lib/rcscripts/bin:/bin:/sbin:/usr/bin:/usr/sbin:${PATH}" ;;
+esac
+
+for arg in "$@" ; do
+ case "${arg}" in
+ --nocolor|--nocolour)
+ export RC_NOCOLOR="yes"
+ ;;
+ esac
+done
+
+if [ "${RC_NOCOLOR}" != "yes" -a -z "${GOOD}" ] ; then
+ if color_terminal ; then
+ GOOD=$'\e[32;01m'
+ WARN=$'\e[33;01m'
+ BAD=$'\e[31;01m'
+ HILITE=$'\e[36;01m'
+ BRACKET=$'\e[34;01m'
+ NORMAL=$'\e[0m'
+ fi
+fi
+
+# vim: set ts=4 :
diff --git a/sh/gendepends.sh b/sh/gendepends.sh
new file mode 100755
index 00000000..aa494f03
--- /dev/null
+++ b/sh/gendepends.sh
@@ -0,0 +1,58 @@
+#!/bin/sh
+# Shell wrapper to list our dependencies
+# Copyright 2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+. /etc/init.d/functions.sh
+
+need() {
+ [ -n "$*" ] && echo "${SVCNAME} ineed $*"
+}
+use() {
+ [ -n "$*" ] && echo "${SVCNAME} iuse $*"
+}
+before() {
+ [ -n "$*" ] && echo "${SVCNAME} ibefore $*"
+}
+after() {
+ [ -n "$*" ] && echo "${SVCNAME} iafter $*"
+}
+provide() {
+ [ -n "$*" ] && echo "${SVCNAME} iprovide $*"
+}
+depend() {
+ :
+}
+
+cd /etc/init.d
+for SVCNAME in * ; do
+ [ -x "${SVCNAME}" ] || continue
+ case "${SVCNAME}" in
+ *.sh) continue ;;
+ esac
+
+ SVCNAME=${SVCNAME##*/}
+ (
+ if . /etc/init.d/"${SVCNAME}" ; then
+ rc_c=${SVCNAME%%.*}
+ if [ -n "${rc_c}" -a "${rc_c}" != "${SVCNAME}" ] ; then
+ [ -e /etc/conf.d/"${rc_c}" ] && . /etc/conf.d/"${rc_c}"
+ fi
+ unset rc_c
+
+ [ -e /etc/conf.d/"${SVCNAME}" ] && . /etc/conf.d/"${SVCNAME}"
+
+ echo "${SVCNAME}"
+ depend
+
+ # Add any user defined depends
+ need ${RC_NEED}
+ use ${RC_USE}
+ before ${RC_BEFORE}
+ after ${RC_AFTER}
+ provide ${RC_PROVIDE}
+ fi
+ )
+done
+
+# vim: set ts=4 :
diff --git a/sh/init-common-post.sh b/sh/init-common-post.sh
new file mode 100644
index 00000000..ec535eb6
--- /dev/null
+++ b/sh/init-common-post.sh
@@ -0,0 +1,22 @@
+# Copyright 1999-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+# mount $svcdir as something we can write to if it's not rw
+# On vservers, / is always rw at this point, so we need to clean out
+# the old service state data
+if touch "${RC_SVCDIR}/.test" 2>/dev/null ; then
+ rm -rf "${RC_SVCDIR}/.test" \
+ $(ls -d1 "${RC_SVCDIR:-/lib/rcscripts/init.d}"/* 2>/dev/null | \
+ grep -Ev "/(deptree|ksoftlevel)$")
+else
+ mount_svcdir
+fi
+
+echo "sysinit" > "${RC_SVCDIR}/softlevel"
+
+# sysinit is now done, so allow init scripts to run normally
+[ -e /dev/.rcsysinit ] && rm -f /dev/.rcsysinit
+
+exit 0
+
+# vim: set ts=4 :
diff --git a/sh/init-functions.sh b/sh/init-functions.sh
new file mode 100644
index 00000000..59f0eb6b
--- /dev/null
+++ b/sh/init-functions.sh
@@ -0,0 +1,62 @@
+# Copyright 1999-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+# void try(command)
+#
+# Try to execute 'command', if it fails, drop to a shell.
+#
+try() {
+ local errstr
+ local retval=0
+
+ if [ -c /dev/null ] ; then
+ errstr=$(eval $* 2>&1 >/dev/null)
+ else
+ errstr=$(eval $* 2>&1)
+ fi
+ retval=$?
+ if [ ${retval} -ne 0 ] ; then
+ #splash "critical" &
+ eend 1
+ eerror "The \"$*\" command failed with error:"
+ eerror " ${errstr#*: }"
+ echo
+ eerror "Since this is a critical task, startup cannot continue."
+ echo
+ single_user
+ fi
+
+ return ${retval}
+}
+
+# bool check_statedir(dir)
+#
+# Check that 'dir' exists, if not, drop to a shell.
+#
+check_statedir() {
+ [ -z "$1" ] && return 0
+
+ if [ ! -d "$1" ] ; then
+ if ! mkdir -p "$1" &>/dev/null ; then
+ #splash "critical" &
+ echo
+ eerror "For Gentoo to function properly, \"$1\" needs to exist."
+ if [ "${RC_FORCE_AUTO}" = "yes" ] ; then
+ eerror "Attempting to create \"$1\" for you ..."
+ mount -o remount,rw /
+ mkdir -p "$1"
+ fi
+ if [ ! -d "$1" ] ; then
+ eerror "Please mount your root partition read/write, and execute:"
+ echo
+ eerror " # mkdir -p $1"
+ echo; echo
+ single_user
+ fi
+ fi
+ fi
+
+ return 0
+}
+
+# vim: set ts=4 :
diff --git a/sh/net.sh b/sh/net.sh
new file mode 100755
index 00000000..c839dd4c
--- /dev/null
+++ b/sh/net.sh
@@ -0,0 +1,566 @@
+#!/sbin/runscript
+# Copyright 1999-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+MODULESDIR="${RC_LIBDIR}/net"
+MODULESLIST="${RC_SVCDIR}/nettree"
+_config_vars="config"
+
+[ -z "${IN_BACKGROUND}" ] && IN_BACKGROUND=false
+
+depend() {
+ local IFACE=${SVCNAME#*.}
+ local IFVAR=$(echo -n "${IFACE}" | sed -e 's/[^[:alnum:]]/_/g')
+
+ need localmount
+ after bootmisc
+ provide net
+ case "${IFACE}" in
+ lo|lo0) ;;
+ *)
+ after net.lo net.lo0
+ local prov=
+ eval prov=\$RC_NEED_${IFVAR}
+ [ -n "${prov}" ] && need ${prov}
+ eval prov=\$RC_USE_${IFVAR}
+ [ -n "${prov}" ] && use ${prov}
+ eval prov=\$RC_BEFORE_${IFVAR}
+ [ -n "${prov}" ] && before ${prov}
+ eval prov=\$RC_AFTER_${IFVAR}
+ [ -n "${prov}" ] && after ${prov}
+ eval prov=\$RC_PROVIDE_${IFVAR}
+ [ -n "${prov}" ] && provide ${prov}
+ ;;
+ esac
+}
+
+_shell_var() {
+ echo -n "$1" | sed -e 's/[^[:alnum:]]/_/g'
+}
+
+# Credit to David Leverton for this function which handily maps a bash array
+# structure to positional parameters so existing configs work :)
+# We'll deprecate arrays at some point though.
+_get_array() {
+ if [ -n "${BASH}" ] ; then
+ case "$(declare -p "$1" 2>/dev/null)" in
+ "declare -a "*)
+ echo "set -- \"\${$1[@]}\""
+ return
+ ;;
+ esac
+ fi
+
+ echo "eval set -- \"\$$1\""
+}
+
+_wait_for_carrier() {
+ local timeout= efunc=einfon
+
+ _has_carrier && return 0
+
+ eval timeout=\$carrier_timeout_${IF_VAR}
+ timeout=${timeout:-5}
+
+ [ -n "${RC_EBUFFER}" ] && efunc=einfo
+ ${efunc} "Waiting for carrier (${timeout} seconds) "
+ while [ ${timeout} -gt 0 ] ; do
+ sleep 1
+ if _has_carrier ; then
+ [ -z "${RC_EBUFFER}" ] && echo
+ return 0
+ fi
+ timeout=$((${timeout} - 1))
+ [ -z "${RC_EBUFFER}" ] && echo -n "."
+ done
+
+ echo
+ return 1
+}
+
+_netmask2cidr() {
+ local i= len=0
+
+ local IFS=.
+ for i in $1; do
+ while [ ${i} != "0" ] ; do
+ len=$((${len} + 1))
+ i=$((${i} >> 1))
+ done
+ done
+
+ echo "${len}"
+}
+
+_configure_variables() {
+ local var= v= t=
+
+ for var in ${_config_vars} ; do
+ local v=
+ for t in "$@" ; do
+ eval v=\$${var}_${t}
+ if [ -n "${v}" ] ; then
+ eval ${var}_${IFVAR}=\$${var}_${t}
+ continue 2
+ fi
+ done
+ done
+}
+
+_show_address() {
+ einfo "received address $(_get_inet_address "${IFACE}")"
+}
+
+# Basically sorts our modules into order and saves the list
+_gen_module_list() {
+ local x= f=
+ if [ -s "${MODULESLIST}" -a "${MODULESLIST}" -nt "${MODULESDIR}" ] ; then
+ local update=false
+ for x in "${MODULESDIR}"/* ; do
+ [ -e "${x}" ] || continue
+ if [ "${x}" -nt "${MODULESLIST}" ] ; then
+ update=true
+ break
+ fi
+ done
+ ${update} || return 0
+ fi
+
+ einfo "Caching network module dependencies"
+ # Run in a subshell to protect the main script
+ (
+ after() {
+ eval ${MODULE}_after="\"\${${MODULE}_after}\${${MODULE}_after:+ }$*\""
+ }
+
+ before() {
+ local mod=${MODULE}
+ local MODULE=
+ for MODULE in "$@" ; do
+ after "${mod}"
+ done
+ }
+
+ program() {
+ if [ "$1" = "start" -o "$1" = "stop" ] ; then
+ local s="$1"
+ shift
+ eval ${MODULE}_program_${s}="\"\${${MODULE}_program_${s}}\${${MODULE}_program_${s}:+ }$*\""
+ else
+ eval ${MODULE}_program="\"\${${MODULE}_program}\${${MODULE}_program:+ }$*\""
+ fi
+ }
+
+ provide() {
+ eval ${MODULE}_provide="\"\${${MODULE}_provide}\${${MODULE}_provide:+ }$*\""
+ local x
+ for x in $* ; do
+ eval ${x}_providedby="\"\${${MODULE}_providedby}\${${MODULE}_providedby:+ }${MODULE}\""
+ done
+ }
+
+ for MODULE in "${MODULESDIR}"/* ; do
+ sh -n "${MODULE}" || continue
+ . "${MODULE}" || continue
+ MODULE=${MODULE#${MODULESDIR}/}
+ MODULE=${MODULE%.sh}
+ eval ${MODULE}_depend
+ MODULES="${MODULES} ${MODULE}"
+ done
+
+ VISITED=
+ SORTED=
+ visit() {
+ case " ${VISITED} " in
+ *" $1 "*) return ;;
+ esac
+ VISITED="${VISITED} $1"
+
+ eval AFTER=\$${1}_after
+ for MODULE in ${AFTER} ; do
+ eval PROVIDEDBY=\$${MODULE}_providedby
+ if [ -n "${PROVIDEDBY}" ] ; then
+ for MODULE in ${PROVIDEDBY} ; do
+ visit "${MODULE}"
+ done
+ else
+ visit "${MODULE}"
+ fi
+ done
+
+ eval PROVIDE=\$${1}_provide
+ for MODULE in ${PROVIDE} ; do
+ visit "${MODULE}"
+ done
+
+ eval PROVIDEDBY=\$${1}_providedby
+ [ -z "${PROVIDEDBY}" ] && SORTED="${SORTED} $1"
+ }
+
+ for MODULE in ${MODULES} ; do
+ visit "${MODULE}"
+ done
+
+ > "${MODULESLIST}"
+ i=0
+ for MODULE in ${SORTED} ; do
+ eval PROGRAM=\$${MODULE}_program
+ eval PROGRAM_START=\$${MODULE}_program_start
+ eval PROGRAM_STOP=\$${MODULE}_program_stop
+ #for x in ${PROGRAM} ; do
+ # [ -x "${x}" ] || continue 2
+ #done
+ eval PROVIDE=\$${MODULE}_provide
+ echo "module_${i}='${MODULE}'" >> "${MODULESLIST}"
+ echo "module_${i}_program='${PROGRAM}'" >> "${MODULESLIST}"
+ echo "module_${i}_program_start='${PROGRAM_START}'" >> "${MODULESLIST}"
+ echo "module_${i}_program_stop='${PROGRAM_STOP}'" >> "${MODULESLIST}"
+ echo "module_${i}_provide='${PROVIDE}'" >> "${MODULESLIST}"
+ i=$((${i} + 1))
+ done
+ echo "module_${i}=" >> "${MODULESLIST}"
+ )
+
+ return 0
+}
+
+_load_modules() {
+ # Ensure our list is up to date
+ _gen_module_list
+
+ local starting=$1 mymods=
+
+ MODULES=
+ if [ "${IFACE}" != "lo" -a "${IFACE}" != "lo0" ] ; then
+ eval mymods=\$modules_${IFVAR}
+ [ -z "${mymods}" ] && mymods=${modules}
+ fi
+
+ . "${MODULESLIST}"
+ local i=-1 x= mod= f= provides=
+ while true ; do
+ i=$((${i} + 1))
+ eval mod=\$module_${i}
+ [ -z "${mod}" ] && break
+ [ -e "${MODULESDIR}/${mod}.sh" ] || continue
+
+ eval set -- \$module_${i}_program
+ if [ -n "$1" ] ; then
+ x=
+ for x in "$@" ; do
+ [ -x "${x}" ] && break
+ done
+ [ -x "${x}" ] || continue
+ fi
+ if ${starting} ; then
+ eval set -- \$module_${i}_program_start
+ else
+ eval set -- \$module_${i}_program_stop
+ fi
+ if [ -n "$1" ] ; then
+ x=
+ for x in "$@" ; do
+ [ -x "${x}" ] && break
+ done
+ [ -x "${x}" ] || continue
+ fi
+
+ eval provides=\$module_${i}_provide
+ if ${starting} ; then
+ case " ${mymods} " in
+ *" !${mod} "*) continue ;;
+ *" !${provides} "*) [ -n "${provides}" ] && continue ;;
+ esac
+ fi
+ MODULES="${MODULES}${MODULES:+ }${mod}"
+
+ # Now load and wrap our functions
+ if ! . "${MODULESDIR}/${mod}.sh" ; then
+ eend 1 "${SVCNAME}: error loading module \`${mod}'"
+ exit 1
+ fi
+
+ [ -z "${provides}" ] && continue
+
+ # Wrap our provides
+ local f=
+ for f in pre_start start post_start ; do
+ eval "${provides}_${f}() { type ${mod}_${f} >/dev/null 2>/dev/null || return 0; ${mod}_${f} \"\$@\"; }"
+ done
+
+ eval module_${mod}_provides="${provides}"
+ eval module_${provides}_providedby="${mod}"
+ done
+
+ # Wrap our preferred modules
+ for mod in ${mymods} ; do
+ case " ${MODULES} " in
+ *" ${mod} "*)
+ eval x=\$module_${mod}_provides
+ [ -z "${x}" ] && continue
+ for f in pre_start start post_start ; do
+ eval "${x}_${f}() { type ${mod}_${f} >/dev/null 2>/dev/null || return 0; ${mod}_${f} \"\$@\"; }"
+ done
+ eval module_${x}_providedby="${mod}"
+ ;;
+ esac
+ done
+
+ # Finally remove any duplicated provides from our list if we're starting
+ # Otherwise reverse the list
+ local LIST="${MODULES}" p=
+ MODULES=
+ if ${starting} ; then
+ for mod in ${LIST} ; do
+ eval x=\$module_${mod}_provides
+ if [ -n "${x}" ] ; then
+ eval p=\$module_${x}_providedby
+ [ "${mod}" != "${p}" ] && continue
+ fi
+ MODULES="${MODULES}${MODULES:+ }${mod}"
+ done
+ else
+ for mod in ${LIST} ; do
+ MODULES="${mod}${MODULES:+ }${MODULES}"
+ done
+ fi
+
+ veinfo "Loaded modules: ${MODULES}"
+}
+
+_load_config() {
+ eval "$(_get_array "config_${IFVAR}")"
+ if [ "${IFACE}" = "lo" -o "${IFACE}" = "lo0" ] ; then
+ set -- "127.0.0.1/8" "$@"
+ else
+ if [ $# -eq 0 ] ; then
+ ewarn "No configuration specified; defaulting to DHCP"
+ set -- "dhcp"
+ fi
+ fi
+
+ # We store our config in an array like vars
+ # so modules can influence it
+ config_index=0
+ for cmd in "$@" ; do
+ eval config_${config_index}="'${cmd}'"
+ config_index=$((${config_index} + 1))
+ done
+ # Terminate the list
+ eval config_${config_index}=
+
+ config_index=0
+ eval $(_get_array fallback_${IFVAR})
+ for cmd in "$@" ; do
+ eval fallback_${config_index}="'${cmd}'"
+ config_index=$((${config_index} + 1))
+ done
+ # Terminate the list
+ eval fallback_${config_index}=
+
+ # Don't set to zero, so any net modules don't have to do anything extra
+ config_index=-1
+}
+
+start() {
+ local IFACE=${SVCNAME#*.} oneworked=false module=
+ local IFVAR=$(_shell_var "${IFACE}") cmd= metric=0 our_metric=$metric
+
+ einfo "Bringing up interface ${IFACE}"
+ eindent
+
+ if [ -z "${MODULES}" ] ; then
+ local MODULES=
+ _load_modules true
+ fi
+
+ _up 2>/dev/null
+
+ if type preup >/dev/null 2>/dev/null ; then
+ ebegin "Running preup"
+ eindent
+ preup || return 1
+ eoutdent
+ fi
+
+ for module in ${MODULES} ; do
+ if type "${module}_pre_start" >/dev/null 2>/dev/null ; then
+ if ! ${module}_pre_start ; then
+ eend 1
+ exit 1
+ fi
+ fi
+ done
+
+ local config= config_index=
+ _load_config
+ config_index=0
+
+ if [ -n "${our_metric}" ] ; then
+ metric=${our_metric}
+ elif [ "${IFACE}" != "lo" -a "${IFACE}" != "lo0" ] ; then
+ metric=$((${metric} + $(_ifindex)))
+ fi
+
+ while true ; do
+ eval config=\$config_${config_index}
+ [ -z "${config}" ] && break
+
+ set -- "${config}"
+ ebegin "$1"
+ eindent
+ case "$1" in
+ noop)
+ if [ -n "$(_get_inet_address)" ] ; then
+ oneworked=true
+ break
+ fi
+ ;;
+ null) : ;;
+ [0-9]*|*:*) _add_address ${config} ;;
+ *)
+ if type "${config}_start" >/dev/null 2>/dev/null ; then
+ "${config}"_start
+ else
+ eerror "nothing provides \`${config}'"
+ fi
+ ;;
+ esac
+ if eend $? ; then
+ oneworked=true
+ else
+ eval config=\$fallback_${IFVAR}
+ if [ -n "${config}" ] ; then
+ einfo "Trying fallback configuration"
+ eval config_${config_index}=\$fallback_${IFVAR}
+ eval fallback_${config_index}=
+ config_index=$((${config_index} - 1))
+ fi
+ fi
+ eoutdent
+ config_index=$((${config_index} + 1))
+ done
+
+ if ! ${oneworked} ; then
+ if type failup >/dev/null 2>/dev/null ; then
+ ebegin "Running failup"
+ eindent
+ failup
+ eoutdent
+ fi
+ return 1
+ fi
+
+ local hidefirstroute=false first=true routes=
+ eval "$(_get_array "routes_${IFVAR}")"
+ if [ "${IFACE}" = "lo" -o "${IFACE}" = "lo0" ] ; then
+ set -- "127.0.0.0/8 via 127.0.0.1" "$@"
+ hidefirstroute=true
+ fi
+ for cmd in "$@" ; do
+ if ${first} ; then
+ first=false
+ einfo "Adding routes"
+ fi
+ eindent
+ ebegin "${cmd}"
+ # Work out if we're a host or a net if not told
+ case "${cmd}" in
+ *" -net "*|*" -host "*) ;;
+ *" netmask "*) cmd="-net ${cmd}" ;;
+ *)
+ case "${cmd%% *}" in
+ *.*.*.*/32) cmd="-host ${cmd}" ;;
+ *.*.*.*/*|0.0.0.0|default) cmd="-net ${cmd}" ;;
+ *) cmd="-host ${cmd}" ;;
+ esac
+ ;;
+ esac
+ if ${hidefirstroute} ; then
+ _add_route ${cmd} >/dev/null 2>/dev/null
+ hidefirstroute=false
+ else
+ _add_route ${cmd} >/dev/null
+ fi
+ eend $?
+ eoutdent
+ done
+
+ for module in ${MODULES} ; do
+ if type "${module}_post_start" >/dev/null 2>/dev/null ; then
+ if ! ${module}_post_start ; then
+ eend 1
+ exit 1
+ fi
+ fi
+ done
+
+ if type postup >/dev/null 2>/dev/null ; then
+ ebegin "Running postup"
+ eindent
+ postup
+ eoutdent
+ fi
+
+ return 0
+}
+
+stop() {
+ local IFACE=${SVCNAME#*.} module=
+ local IFVAR=$(_shell_var "${IFACE}") opts=
+
+ einfo "Bringing down interface ${IFACE}"
+ eindent
+
+ if [ -z "${MODULES}" ] ; then
+ local MODULES=
+ _load_modules false
+ fi
+
+ if type predown >/dev/null 2>/dev/null ; then
+ ebegin "Running predown"
+ eindent
+ predown || return 1
+ eoutdent
+ fi
+
+ for module in ${MODULES} ; do
+ if type "${module}_pre_stop" >/dev/null 2>/dev/null ; then
+ if ! ${module}_pre_stop ; then
+ eend 1
+ exit 1
+ fi
+ fi
+ done
+
+ for module in ${MODULES} ; do
+ if type "${module}_stop" >/dev/null 2>/dev/null ; then
+ ${module}_stop
+ fi
+ done
+
+ _delete_addresses "${IFACE}"
+
+ for module in ${MODULES} ; do
+ if type "${module}_post_stop" >/dev/null 2>/dev/null ; then
+ ${module}_post_stop
+ fi
+ done
+
+ [ "${IN_BACKGROUND}" != "true" ] && \
+ [ "${IFACE}" != "lo" -a "${IFACE}" != "lo0" ] && \
+ _down 2>/dev/null
+
+ [ -x /sbin/resolvconf ] && resolvconf -d "${IFACE}"
+
+ if type predown >/dev/null 2>/dev/null ; then
+ ebegin "Running postdown"
+ eindent
+ postdown
+ eoutdent
+ fi
+
+ return 0
+}
+
+# vim: set ts=4 :
diff --git a/sh/rc-functions.sh b/sh/rc-functions.sh
new file mode 100755
index 00000000..586471dd
--- /dev/null
+++ b/sh/rc-functions.sh
@@ -0,0 +1,60 @@
+# Copyright 2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+has_addon() {
+ [ -e "${RC_LIBDIR}/addons/$1.sh" ]
+}
+
+import_addon() {
+ if has_addon "$1" ; then
+ . "${RC_LIBDIR}/addons/$1.sh"
+ return 0
+ fi
+ return 1
+}
+
+start_addon() {
+ ( import_addon "$1-start" )
+}
+
+stop_addon() {
+ ( import_addon "$1-stop" )
+}
+
+is_net_fs() {
+ [ -z "$1" ] && return 1
+
+ local t=$(mountinfo --fstype "$1" )
+ for x in ${RC_NET_FS_LIST} ; do
+ [ "${x}" = "${t}" ] && return 0
+ done
+ return 1
+}
+
+is_union_fs() {
+ [ ! -x /sbin/unionctl ] && return 1
+ unionctl "$1" --list >/dev/null 2>/dev/null
+}
+
+get_bootparam() {
+ local match="$1"
+ [ -z "${match}" -o ! -r /proc/cmdline ] && return 1
+
+ set -- $(cat /proc/cmdline)
+ while [ -n "$1" ] ; do
+ case "$1" in
+ gentoo=*)
+ local params="${1##*=}"
+ local IFS=, x=
+ for x in ${params} ; do
+ [ "${x}" = "${match}" ] && return 0
+ done
+ ;;
+ esac
+ shift
+ done
+
+ return 1
+}
+
+# vim: set ts=4 :
diff --git a/sh/rc-help.sh b/sh/rc-help.sh
new file mode 100755
index 00000000..97ca53f4
--- /dev/null
+++ b/sh/rc-help.sh
@@ -0,0 +1,262 @@
+#!/bin/sh
+# Copyright 1999-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+if [ "${RC_NOCOLOR}" = "yes" ] ; then
+ unset BLUE GREEN OFF CYAN
+else
+ BLUE="\033[34;01m"
+ GREEN="\033[32;01m"
+ OFF="\033[0m"
+ CYAN="\033[36;01m"
+fi
+
+myscript=$1
+if [ -z "${myscript}" ] ; then
+ echo "Please execute an init.d script"
+ exit 1
+fi
+
+if [ -L "${myscript}" ] ; then
+ SERVICE=$(readlink "${myscript}")
+else
+ SERVICE=${myscript}
+fi
+SERVICE=${SERVICE##*/}
+
+if [ "$2" = "help" ] ; then
+ BE_VERBOSE="yes"
+ NL="\n"
+else
+ BE_VERBOSE="no"
+ NL=
+fi
+
+default_opts="start stop restart pause zap"
+extra_opts="$(. "${myscript}" 2>/dev/null ; echo "${opts}")"
+
+if [ "${BE_VERBOSE}" = "yes" ] ; then
+printf "
+${GREEN}Gentoo RC-Scripts; ${BLUE}http://www.gentoo.org/${OFF}
+ Copyright 1999-2007 Gentoo Foundation; Distributed under the GPL
+"
+fi
+
+printf "Usage: ${CYAN}${SERVICE}${OFF} [ ${GREEN}flags${OFF} ] < ${GREEN}options${OFF} >
+
+${CYAN}Normal Options:${OFF}"
+
+if [ "${BE_VERBOSE}" = "yes" ] ; then
+printf "
+ ${GREEN}start${OFF}
+ Start service, as well as the services it depends on (if not already
+ started).
+
+ ${GREEN}stop${OFF}
+ Stop service, as well as the services that depend on it (if not already
+ stopped).
+
+ ${GREEN}restart${OFF}
+ Restart service, as well as the services that depend on it.
+
+ Note to developers: If this function is replaced with a custom one,
+ 'svc_start' and 'svc_stop' should be used instead of 'start' and
+ 'stop' to restart the service. This is so that the dependencies
+ can be handled correctly. Refer to the portmap rc-script for an
+ example.
+
+ ${GREEN}conditionalrestart|condrestart${OFF}
+ Same as 'restart', but only if the service has already been started.
+
+ ${GREEN}pause${OFF}
+ Same as 'stop', but the services that depends on it, will not be
+ stopped. This is useful for stopping a network interface without
+ stopping all the network services that depend on 'net'.
+
+ ${GREEN}zap${OFF}
+ Reset a service that is currently stopped, but still marked as started,
+ to the stopped state. Basically for killing zombie services.
+
+ ${GREEN}status${OFF}
+ Prints \"status: started\" if the service is running, else it
+ prints \"status: stopped\".
+
+ Note that if the '--quiet' flag is given, it will return true if the
+ service is running, else false.
+
+ ${GREEN}ineed|iuse${OFF}
+ List the services this one depends on. Consult the section about
+ dependencies for more info on the different types of dependencies.
+
+ ${GREEN}needsme|usesme${OFF}
+ List the services that depend on this one. Consult the section about
+ dependencies for more info on the different types of dependencies.
+
+ ${GREEN}broken${OFF}
+ List the missing or broken dependencies of type 'need' this service
+ depends on.
+"
+
+else
+
+printf " ${GREEN}${default_opts}${OFF}
+ Default init.d options.
+"
+
+fi
+
+if [ -n "${extra_opts}" ] ; then
+printf "
+${CYAN}Additional Options:${OFF}${NL}
+ ${GREEN}${extra_opts}${OFF}
+ Extra options supported by this init.d script.
+"
+fi
+
+printf "
+${CYAN}Flags:${OFF}${NL}
+ ${GREEN}--ifstarted${OFF} Only do actions if service started
+ ${GREEN}--nodeps${OFF} Don't stop or start any dependencies
+ ${GREEN}--quiet${OFF}
+ Suppress output to stdout, except if:${NL}
+ 1) It is a warning, then output to stdout
+ 2) It is an error, then output to stderr${NL}
+ ${GREEN}--verbose${OFF} Output extra information
+ ${GREEN}--debug${OFF} Output debug information
+ ${GREEN}--nocolor${OFF} Suppress the use of colors
+"
+
+if [ "${BE_VERBOSE}" = "yes" ] ; then
+printf "
+${CYAN}Dependencies:${OFF}
+
+ This is the heart of the Gentoo RC-Scripts, as it determines the order
+ in which services gets started, and also to some extend what services
+ get started in the first place.
+
+ The following example demonstrates how to use dependencies in
+ rc-scripts:
+
+ depend() {
+ need foo bar
+ use ray
+ }
+
+ Here we have foo and bar as dependencies of type 'need', and ray of
+ type 'use'. You can have as many dependencies of each type as needed, as
+ long as there is only one entry for each type, listing all its dependencies
+ on one line only.
+
+ ${GREEN}need${OFF}
+ These are all the services needed for this service to start. If any
+ service in the 'need' line is not started, it will be started even if it
+ is not in the current, or 'boot' runlevel, and then this service will be
+ started. If any services in the 'need' line fails to start or is
+ missing, this service will never be started.
+
+ ${GREEN}use${OFF}
+ This can be seen as representing optional services this service depends on
+ that are not critical for it to start. For any service in the 'use' line,
+ it must be added to the 'boot' or current runlevel to be considered a
+ valid 'use' dependency. It can also be used to determine startup order.
+
+ ${GREEN}before${OFF}
+ This, together with the 'after' dependency type, can be used to control
+ startup order. In core, 'before' and 'after' do not denote a dependency,
+ but should be used for order changes that will only be honoured during
+ a change of runlevel. All services listed will get started *after* the
+ current service. In other words, this service will get started *before*
+ all listed services.
+
+ ${GREEN}after${OFF}
+ All services listed will be started *before* the current service. Have a
+ look at 'before' for more info.
+
+ ${GREEN}provide${OFF}
+ This is not really a dependency type, rather it will enable you to create
+ virtual services. This is useful if there is more than one version of
+ a specific service type, system loggers or crons for instance. Just
+ have each system logger provide 'logger', and make all services in need
+ of a system logger depend on 'logger'. This should make things much more
+ generic.
+
+ Note that the 'need', 'use', 'before', and 'after' dependency types accept
+ an '*' as an argument. Having:
+
+ depend() {
+ before *
+ }
+
+ will make the service start first in the current runlevel, and:
+
+ depend() {
+ after *
+ }
+
+ will make the service the last to start.
+
+ You should however be careful how you use this, as I really will not
+ recommend using it with the 'need' or 'use' dependency type ... you have
+ been warned!
+
+${CYAN}'net' Dependency and 'net.*' Services:${OFF}
+
+ Example:
+
+ depend() {
+ need net
+ }
+
+ This is a special dependency of type 'need'. It represents a state where
+ a network interface or interfaces besides lo is up and active. Any service
+ starting with 'net.' will be treated as a part of the 'net' dependency,
+ if:
+
+ 1. It is part of the 'boot' runlevel
+ 2. It is part of the current runlevel
+
+ A few examples are the /etc/init.d/net.eth0 and /etc/init.d/net.lo services.
+"
+fi
+
+printf "
+${CYAN}Configuration files:${OFF}
+"
+
+if [ "${BE_VERBOSE}" = "yes" ] ; then
+printf "
+ There are two files which will be sourced for possible configuration by
+ the rc-scripts. They are (sourced from top to bottom):
+"
+fi
+
+printf " /etc/conf.d/${SERVICE}${NL} /etc/rc.conf"
+
+if [ "${BE_VERBOSE}" = "yes" ] ; then
+printf "
+ You can add extra dependencies to ${SERVICE} by adding some variables to
+ /etc/conf.d/${SERVICE}
+ RC_NEED=\"openvpn ntpd\"
+ RC_USE=\"dns\"
+
+ This makes ${SERVICE} need openvpn and ntpd, while it just uses dns.
+
+ A good example of this is nfsmount needing openvpn if the nfs mounts in
+ /etc/fstab are over the vpn link.
+"
+fi
+
+if [ "${BE_VERBOSE}" = "yes" ] ; then
+printf "\n
+${CYAN}Management:${OFF}
+
+ Services are added and removed via the 'rc-update' tool. Running it without
+ arguments should give sufficient help.
+"
+else
+printf "\n
+For more info, please run '${myscript} help'.
+"
+fi
+
+exit 0
diff --git a/sh/rc-mount.sh b/sh/rc-mount.sh
new file mode 100644
index 00000000..67ea203f
--- /dev/null
+++ b/sh/rc-mount.sh
@@ -0,0 +1,70 @@
+# Copyright 2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+# bool do_unmount(char *cmd, char *no_unmounts, char *nodes, char *fslist)
+# Handy function to handle all our unmounting needs
+# find-mount is a C program to actually find our mounts on our supported OS's
+do_unmount() {
+ local cmd="$1" retval=0 retry=
+ local f_opts="-m -c" f_kill="-s " mnt=
+ if [ "${RC_UNAME}" = "Linux" ] ; then
+ f_opts="-c"
+ f_kill="-"
+ fi
+
+ local mnts="$(mountinfo ${2:+--skip-regex} $2 ${3:+--node-regex} $3 ${4:+--fstype-regex} $4 --reverse \
+ | sed -e "s/'/'\\\\''/g" -e "s/^/'/g" -e "s/$/'/g")"
+ eval set -- ${mnts}
+ for mnt in "$@" ; do
+ case "${cmd}" in
+ umount*)
+ # If we're using the mount (probably /usr) then don't unmount us
+ local pids="$(fuser ${f_opts} "${mnt}" 2>/dev/null)"
+ case " ${pids} " in
+ *" $$ "*)
+ ewarn "We are using ${mnt}, not unmounting"
+ continue
+ ;;
+ esac
+ ebegin "Unmounting ${mnt}"
+ ;;
+ *)
+ ebegin "Remounting ${mnt}"
+ ;;
+ esac
+
+ retry=3
+ while ! ${cmd} "${mnt}" 2>/dev/null ; do
+ # Don't kill if it's us (/ and possibly /usr)
+ local pids="$(fuser ${f_opts} "${mnt}" 2>/dev/null)"
+ case " ${pids} " in
+ *" $$ "*) retry=0 ;;
+ " ") eend 1 "in use but fuser finds nothing"; retry=0 ;;
+ *)
+ local sig="KILL"
+ [ ${retry} -gt 0 ] && sig="TERM"
+ fuser ${f_kill}${sig} -k ${f_opts} "${mnt}" \
+ >/dev/null 2>/dev/null
+ sleep 1
+ retry=$((${retry} - 1))
+ ;;
+ esac
+
+ # OK, try forcing things
+ if [ ${retry} -le 0 ] ; then
+ ${cmd} -f "${mnt}" || retry=-999
+ retry=-999
+ break
+ fi
+ done
+ if [ ${retry} -eq -999 ] ; then
+ eend 1
+ retval=1
+ else
+ eend 0
+ fi
+ done
+ return ${retval}
+}
+
+# vim: set ts=4 :
diff --git a/sh/runscript.sh b/sh/runscript.sh
new file mode 100755
index 00000000..6b679c21
--- /dev/null
+++ b/sh/runscript.sh
@@ -0,0 +1,74 @@
+#!/bin/sh
+# Shell wrapper for runscript
+# Copyright 1999-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+. /etc/init.d/functions.sh
+. "${RC_LIBDIR}"/sh/rc-functions.sh
+
+# Support LiveCD foo
+if [ -r /sbin/livecd-functions.sh ] ; then
+ . /sbin/livecd-functions.sh
+ livecd_read_commandline
+fi
+
+if [ -z "$1" -o -z "$2" ] ; then
+ eerror "${SVCNAME}: not enough arguments"
+ exit 1
+fi
+
+[ "${RC_DEBUG}" = "yes" ] && set -x
+
+# If we're net.eth0 or openvpn.work then load net or openvpn config
+rc_c=${SVCNAME%%.*}
+if [ -n "${rc_c}" -a "${rc_c}" != "${SVCNAME}" ] ; then
+ if [ -e "/etc/conf.d/${rc_c}.${RC_SOFTLEVEL}" ] ; then
+ . "/etc/conf.d/${rc_c}.${RC_SOFTLEVEL}"
+ elif [ -e "/etc/conf.d/${rc_c}" ] ; then
+ . "/etc/conf.d/${rc_c}"
+ fi
+fi
+unset rc_c
+
+# Overlay with our specific config
+if [ -e "/etc/conf.d/${SVCNAME}.${RC_SOFTLEVEL}" ] ; then
+ . "/etc/conf.d/${SVCNAME}.${RC_SOFTLEVEL}"
+elif [ -e "/etc/conf.d/${SVCNAME}" ] ; then
+ . "/etc/conf.d/${SVCNAME}"
+fi
+
+# Load any system overrides
+[ -e /etc/rc.conf ] && . /etc/rc.conf
+
+# Apply any ulimit defined
+[ -n "${RC_ULIMIT}" ] && ulimit ${RC_ULIMIT}
+
+# Load our script
+. $1
+
+shift
+
+while [ -n "$1" ] ; do
+ # See if we have the required function and run it
+ for rc_x in start stop ${opts} ; do
+ if [ "${rc_x}" = "$1" ] ; then
+ if type "$1" >/dev/null 2>/dev/null ; then
+ unset rc_x
+ "$1" || exit $?
+ shift
+ continue 2
+ else
+ if [ "${rc_x}" = "start" -o "${rc_x}" = "stop" ] ; then
+ exit 0
+ else
+ eerror "${SVCNAME}: function \`$1' defined but does not exist"
+ exit 1
+ fi
+ fi
+ fi
+ done
+ eerror "${SVCNAME}: unknown function \`$1'"
+ exit 1
+done
+
+# vim: set ts=4 :
diff --git a/share.BSD/Makefile b/share.BSD/Makefile
new file mode 100644
index 00000000..73872aab
--- /dev/null
+++ b/share.BSD/Makefile
@@ -0,0 +1,6 @@
+DIR = /usr/share/baselayout
+FILES = fstab group
+FILES_SECURE = master.passwd
+
+TOPDIR = ..
+include $(TOPDIR)/default.mk
diff --git a/share.BSD/fstab b/share.BSD/fstab
new file mode 100644
index 00000000..b28c3fc9
--- /dev/null
+++ b/share.BSD/fstab
@@ -0,0 +1,21 @@
+# /etc/fstab: static file system information.
+#
+# noatime turns off atimes for increased performance (atimes normally aren't
+# needed.
+#
+# The root filesystem should have a pass number of either 0 or 1.
+# All other filesystems should have a pass number of 0 or greater than 1.
+#
+# See the manpage fstab(5) for more information.
+#
+
+# <fs> <mountpoint> <type> <opts> <dump/pass>
+
+/dev/ad0s1a / ufs rw,noatime 1 1
+/dev/ad0s1b none swap sw 0 0
+
+/dev/acd0 /mnt/cdrom cd9660 ro,noauto 0 0
+
+# Enable this line to mount /proc automatically.
+# Required for Linux emulation.
+#none /proc linprocfs rw,noexec,nosuid 0 0
diff --git a/share.BSD/group b/share.BSD/group
new file mode 100644
index 00000000..3cd3c2a1
--- /dev/null
+++ b/share.BSD/group
@@ -0,0 +1,16 @@
+wheel:*:0:root
+daemon:*:1:
+kmem:*:2:
+sys:*:3:
+tty:*:4:
+operator:*:5:root
+mail:*:6:
+bin:*:7:
+news:*:8:
+guest:*:31:
+uucp:*:66:
+dialer:*:68:
+network:*:69:
+portage:*:250:
+nogroup:*:65533:
+nobody:*:65534:
diff --git a/share.BSD/master.passwd b/share.BSD/master.passwd
new file mode 100644
index 00000000..cc546e19
--- /dev/null
+++ b/share.BSD/master.passwd
@@ -0,0 +1,15 @@
+root:*:0:0::0:0:GOD:/root:/bin/bash
+toor:*:0:0::0:0:Bourne-again Superuser:/root:
+daemon:*:1:1::0:0:Owner of many system processes:/root:/usr/sbin/nologin
+operator:*:2:5::0:0:System Operator:/:/usr/sbin/nologin
+bin:*:3:7::0:0:Binaries Commands and Source:/:/usr/sbin/nologin
+tty:*:4:65533::0:0:Tty Sandbox:/:/usr/sbin/nologin
+kmem:*:5:65533::0:0:KMem Sandbox:/:/usr/sbin/nologin
+mail:*:6:6::0:0:Mail programs:/var/spool/mail:/usr/sbin/nologin
+games:*:7:13::0:0:Games pseudo-user:/usr/games:/usr/sbin/nologin
+news:*:8:8::0:0:News Subsystem:/:/usr/sbin/nologin
+man:*:9:9::0:0:Mister Man Pages:/usr/share/man:/usr/sbin/nologin
+smmsp:*:25:25::0:0:Sendmail Submission User:/var/spool/clientmqueue:/usr/sbin/nologin
+uucp:*:66:66::0:0:UUCP pseudo-user:/var/spool/uucppublic:/usr/local/libexec/uucp/uucico
+portage:*:250:250::0:0:Portage user:/var/tmp/portage/homedir:/bin/sh
+nobody:*:65534:65534::0:0:Unprivileged user:/nonexistent:/usr/sbin/nologin
diff --git a/share.Linux/Makefile b/share.Linux/Makefile
new file mode 100644
index 00000000..9f04fea2
--- /dev/null
+++ b/share.Linux/Makefile
@@ -0,0 +1,6 @@
+DIR = /usr/share/baselayout
+FILES = fstab issue.devfix group passwd
+FILES_SECURE = shadow
+
+TOPDIR = ..
+include $(TOPDIR)/default.mk
diff --git a/share.Linux/fstab b/share.Linux/fstab
new file mode 100644
index 00000000..2ba830fc
--- /dev/null
+++ b/share.Linux/fstab
@@ -0,0 +1,27 @@
+# /etc/fstab: static file system information.
+#
+# noatime turns off atimes for increased performance (atimes normally aren't
+# needed; notail increases performance of ReiserFS (at the expense of storage
+# efficiency). It's safe to drop the noatime options if you want and to
+# switch between notail / tail freely.
+#
+# The root filesystem should have a pass number of either 0 or 1.
+# All other filesystems should have a pass number of 0 or greater than 1.
+#
+# See the manpage fstab(5) for more information.
+#
+
+# <fs> <mountpoint> <type> <opts> <dump/pass>
+
+# NOTE: If your BOOT partition is ReiserFS, add the notail option to opts.
+/dev/BOOT /boot ext2 noauto,noatime 1 2
+/dev/ROOT / ext3 noatime 0 1
+/dev/SWAP none swap sw 0 0
+/dev/cdrom /mnt/cdrom audo noauto,ro 0 0
+#/dev/fd0 /mnt/floppy auto noauto 0 0
+
+# glibc 2.2 and above expects tmpfs to be mounted at /dev/shm for
+# POSIX shared memory (shm_open, shm_unlink).
+# (tmpfs is a dynamically expandable/shrinkable ramdisk, and will
+# use almost no memory if not populated with files)
+shm /dev/shm tmpfs nodev,nosuid,noexec 0 0
diff --git a/share.Linux/group b/share.Linux/group
new file mode 100644
index 00000000..d8e2be15
--- /dev/null
+++ b/share.Linux/group
@@ -0,0 +1,27 @@
+root::0:root
+bin::1:root,bin,daemon
+daemon::2:root,bin,daemon
+sys::3:root,bin,adm
+adm::4:root,adm,daemon
+tty::5:
+disk::6:root,adm
+lp::7:lp
+mem::8:
+kmem::9:
+wheel::10:root
+floppy::11:root
+mail::12:mail
+news::13:news
+uucp::14:uucp
+console::17:
+audio::18:
+cdrom::19:
+tape::26:root
+video::27:root
+cdrw::80:
+usb::85:
+users::100:games
+portage::250:portage
+utmp:x:406:
+nogroup::65533:
+nobody::65534:
diff --git a/share.Linux/issue.devfix b/share.Linux/issue.devfix
new file mode 100644
index 00000000..163e50f4
--- /dev/null
+++ b/share.Linux/issue.devfix
@@ -0,0 +1,21 @@
+-----------------------------------------------------
+Your system seems to be missing critical device files
+in /dev ! Although you may be running udev or devfs,
+the root partition is missing these required files !
+
+To rectify this situation, please do the following:
+mkdir /mnt/fixit
+mount --bind / /mnt/fixit
+cp -a /dev/* /mnt/fixit/dev/
+umount /mnt/fixit
+rmdir /mnt/fixit
+
+You may refer to these instructions at /etc/issue.
+If you previously had an issue file, it has been
+backed up at /etc/issue.devfix. Once you've fixed
+your system, you will have to restore your old issue
+file in order to get rid of this warning.
+
+Thanks for using Gentoo ! :)
+http://bugs.gentoo.org/show_bug.cgi?id=40987
+-----------------------------------------------------
diff --git a/share.Linux/passwd b/share.Linux/passwd
new file mode 100644
index 00000000..dfab6776
--- /dev/null
+++ b/share.Linux/passwd
@@ -0,0 +1,15 @@
+root:x:0:0:root:/root:/bin/bash
+bin:x:1:1:bin:/bin:/bin/false
+daemon:x:2:2:daemon:/sbin:/bin/false
+adm:x:3:4:adm:/var/adm:/bin/false
+lp:x:4:7:lp:/var/spool/lpd:/bin/false
+sync:x:5:0:sync:/sbin:/bin/sync
+shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
+halt:x:7:0:halt:/sbin:/sbin/halt
+mail:x:8:12:mail:/var/spool/mail:/bin/false
+news:x:9:13:news:/usr/lib/news:/bin/false
+uucp:x:10:14:uucp:/var/spool/uucppublic:/bin/false
+operator:x:11:0:operator:/root:/bin/bash
+postmaster:x:14:12:postmaster:/var/spool/mail:/bin/false
+portage:x:250:250:portage:/var/tmp/portage:/bin/false
+nobody:x:65534:65534:nobody:/:/bin/false
diff --git a/share.Linux/shadow b/share.Linux/shadow
new file mode 100644
index 00000000..99d5ecce
--- /dev/null
+++ b/share.Linux/shadow
@@ -0,0 +1,16 @@
+root:*:10770:0:::::
+halt:*:9797:0:::::
+operator:*:9797:0:::::
+shutdown:*:9797:0:::::
+sync:*:9797:0:::::
+bin:*:9797:0:::::
+daemon:*:9797:0:::::
+adm:*:9797:0:::::
+lp:*:9797:0:::::
+mail:*:9797:0:::::
+postmaster:*:9797:0:::::
+news:*:9797:0:::::
+uucp:*:9797:0:::::
+games:*:9797:0:::::
+guest:*:9797:0:::::
+nobody:*:9797:0:::::
diff --git a/share/Makefile b/share/Makefile
new file mode 100644
index 00000000..4bd705fe
--- /dev/null
+++ b/share/Makefile
@@ -0,0 +1,4 @@
+# Empty Makefile as share is currently OS specific
+
+TOPDIR = ..
+include $(TOPDIR)/default.mk
diff --git a/src/Makefile b/src/Makefile
new file mode 100644
index 00000000..131b4d5c
--- /dev/null
+++ b/src/Makefile
@@ -0,0 +1,153 @@
+# Copyright 1999-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+CC ?= gcc
+
+CFLAGS ?= -Wall -O2 -pipe
+CFLAGS += -pedantic -std=c99 \
+ -Wall -Wextra -Wunused -Wimplicit -Wshadow -Wformat=2 \
+ -Wmissing-declarations -Wno-missing-prototypes -Wwrite-strings \
+ -Wbad-function-cast -Wnested-externs -Wcomment -Winline \
+ -Wchar-subscripts -Wcast-align -Wno-format-nonliteral
+
+# Early GCC versions don't support these flags, so you may need to comment
+# this line out
+CFLAGS += -Wsequence-point -Wextra -Wdeclaration-after-statement
+
+# For debugging. -Werror is pointless due to ISO C issues with dlsym
+#CFLAGS += -ggdb
+
+DESTDIR =
+LIB = lib
+
+LIBEINFOSOVER = 0
+LIBEINFOSO = libeinfo.so.$(LIBRCSOVER)
+LIBEINFOOBJS= libeinfo.o
+
+LIBRCSOVER = 0
+LIBRCSO = librc.so.$(LIBRCSOVER)
+LIBRCOBJS= librc.o librc-depend.o librc-daemon.o librc-misc.o librc-strlist.o
+
+LIB_TARGETS = $(LIBEINFOSO) $(LIBRCSO)
+BIN_TARGETS = rc-status
+SBIN_TARGETS = env-update fstabinfo mountinfo \
+ rc rc-depend rc-update runscript start-stop-daemon
+SYS_WHITELIST = env_whitelist
+
+TARGET = $(LIB_TARGETS) $(BIN_TARGETS) $(SBIN_TARGETS)
+
+RCLINKS = einfon einfo ewarnn ewarn eerrorn eerror ebegin eend ewend \
+ eindent eoutdent eflush color_terminal \
+ veinfo vewarn vebegin veend vewend veindent veoutdent \
+ service_starting service_inactive service_started \
+ service_stopping service_stopped \
+ service_inactive service_wasinactive \
+ service_coldplugged \
+ mark_service_starting mark_service_inactive mark_service_started \
+ mark_service_stopping mark_service_stopped \
+ mark_service_inactive mark_service_wasinactive \
+ mark_service_coldplugged \
+ get_options save_options \
+ is_runlevel_start is_runlevel_stop service_started_daemon
+
+# Quick hack to make my life easier on BSD and Linux
+ifeq ($(OS),)
+OS=$(shell uname -s)
+ifneq ($(OS),Linux)
+OS=BSD
+endif
+endif
+
+ifeq ($(OS),Linux)
+LDLIBS_RC = -ldl
+LDLIBS_RS = -ldl
+# Shouldn't need this, but it's the easiest workaround for silly
+# Linux headers that don't work with -std=c99
+override CFLAGS += -D_GNU_SOURCE
+endif
+ifeq ($(OS),BSD)
+override LDLIBS += -lkvm
+endif
+
+HAVE_PAM =
+ifdef HAVE_PAM
+CFLAGS_SSD = -DHAVE_PAM
+LDLIBS_SSD = -lpam
+endif
+
+# We also define _BSD_SOURCE so both Linux and the BSDs get a few
+# handy functions which makes our lives a lot easier
+override CFLAGS += -DLIBDIR=\"$(LIB)\"
+
+# IMPORTANT!!!
+# Remove this when releasing as it's a security risk
+# However, this does save us using libtool when we're testing
+# NOTE: The toplevel Makefile for baselayout will automatically
+# disable then when doing `make dist`
+##override LDFLAGS += -Wl,-rpath .
+
+all: $(TARGET)
+
+$(LIBEINFOOBJS): CFLAGS += -fPIC
+$(LIBEINFOSO): LDLIBS =
+$(LIBEINFOSO): $(LIBEINFOOBJS)
+ $(CC) -fPIC -shared -Wl,-soname,$(LIBEINFOSO) -o $(LIBEINFOSO) $(LIBEINFOOBJS)
+ ln -sf $(LIBEINFOSO) libeinfo.so
+
+$(LIBRCOBJS): CFLAGS += -fPIC
+$(LIBRCSO): $(LIBRCOBJS)
+ $(CC) -fPIC -shared -Wl,-soname,$(LIBRCSO) -o $(LIBRCSO) $(LIBRCOBJS)
+ ln -sf $(LIBRCSO) librc.so
+
+splash: CFLAGS += -fPIC
+splash: splash.o
+ $(CC) -fPIC -shared -Wl,-soname,splash.so -o splash.so splash.o
+
+env-update: $(LIBEINFOSO) $(LIBRCSO) env-update.o
+
+fstabinfo: $(LIBEINFOSO) fstabinfo.o
+
+mountinfo: $(LIBEINFOSO) $(LIBRCSO) mountinfo.o
+
+rc-depend: $(LIBEINFOSO) $(LIBRCSO) rc-depend.o
+
+rc-status: $(LIBEINFOSO) $(LIBRCSO) rc-status.o
+
+rc-update: $(LIBEINFOSO) $(LIBRCSO) rc-update.o
+
+rc: LDLIBS += $(LDLIBS_RC)
+rc: $(LIBEINFOSO) $(LIBRCSO) rc-plugin.o rc.o
+
+runscript: LDLIBS += $(LDLIBS_RS)
+runscript: $(LIBEINFOSO) $(LIBRCSO) rc-plugin.o runscript.o
+
+start-stop-daemon: CFLAGS += $(CFLAGS_SSD)
+start-stop-daemon: LDLIBS += $(LDLIBS_SSD)
+start-stop-daemon: $(LIBEINFOSO) $(LIBRCSO) start-stop-daemon.o
+
+links: rc
+ for x in $(RCLINKS) $(RCPRIVLINKS); do ln -sf rc $$x; done
+
+install: $(TARGET)
+ install -m 0755 -d $(DESTDIR)/$(LIB)
+ install -m 0755 $(LIB_TARGETS) $(DESTDIR)/$(LIB)
+ ln -sf $(LIBEINFOSO) $(DESTDIR)/$(LIB)/libeinfo.so
+ ln -sf $(LIBRCSO) $(DESTDIR)/$(LIB)/librc.so
+ install -m 0755 -d $(DESTDIR)/usr/include
+ install -m 0644 einfo.h rc.h $(DESTDIR)/usr/include
+ install -m 0755 -d $(DESTDIR)/bin
+ install -m 0755 $(BIN_TARGETS) $(DESTDIR)/bin
+ install -m 0755 -d $(DESTDIR)/sbin
+ install -m 0755 $(SBIN_TARGETS) $(DESTDIR)/sbin
+ install -m 0755 -d $(DESTDIR)/$(LIB)/rcscripts/conf.d
+ install -m 0644 $(SYS_WHITELIST) $(DESTDIR)/$(LIB)/rcscripts/conf.d
+ install -m 0755 -d $(DESTDIR)/$(LIB)/rcscripts/bin
+ for x in $(RCLINKS); do ln -sf $(DESTDIR)/sbin/rc $(DESTDIR)/$(LIB)/rcscripts/bin/$$x; done
+ if test "$(HAVE_PAM)" != "" ; then \
+ install -m 0755 -d $(DESTDIR)/etc/pam.d ; \
+ install -m 0644 start-stop-daemon.pam $(DESTDIR)/etc/pam.d/start-stop-daemon ; \
+ fi
+
+clean:
+ rm -f $(TARGET) $(RCLINKS) $(RCPRIVLINKS)
+ rm -f *.o *~ *.core *.so
diff --git a/src/einfo.h b/src/einfo.h
new file mode 100644
index 00000000..7ab52afd
--- /dev/null
+++ b/src/einfo.h
@@ -0,0 +1,83 @@
+/*
+ rc.h
+ Header file for external applications to get RC information.
+ Copyright 2007 Gentoo Foundation
+ Released under the GPLv2
+ */
+
+#ifndef __EINFO_H__
+#define __EINFO_H__
+
+#ifdef __GNUC__
+# define EINFO_PRINTF(_one, _two) __attribute__ ((__format__ (__printf__, _one, _two)))
+# define EINFO_XPRINTF(_one, _two) __attribute__ ((__noreturn__, __format__ (__printf__, _one, _two)))
+#endif
+
+#include <sys/types.h>
+#include <stdbool.h>
+
+typedef enum
+{
+ einfo_good,
+ einfo_warn,
+ einfo_bad,
+ einfo_hilite,
+ einfo_bracket,
+ einfo_normal
+} einfo_color_t;
+
+/* Colour codes used by the below functions. */
+#define EINFO_GOOD "\033[32;01m"
+#define EINFO_WARN "\033[33;01m"
+#define EINFO_BAD "\033[31;01m"
+#define EINFO_HILITE "\033[36;01m"
+#define EINFO_BRACKET "\033[34;01m"
+#define EINFO_NORMAL "\033[0m"
+
+/* Handy macros to easily use the above in a custom manner */
+#define PEINFO_GOOD if (colour_terminal ()) printf (EINFO_GOOD)
+#define PEINFO_WARN if (colour_terminal ()) printf (EINFO_WARN)
+#define PEINFO_BAD if (colour_terminal ()) printf (EINFO_BAD)
+#define PEINFO_HILITE if (colour_terminal ()) printf (EINFO_HILITE)
+#define PEINFO_BRACKET if (colour_terminal ()) printf (EINFO_BRACKET)
+#define PEINFO_NORMAL if (colour_terminal ()) printf (EINFO_NORMAL)
+
+/* We work out if the terminal supports colour or not through the use
+ of the TERM env var. We cache the reslt in a static bool, so
+ subsequent calls are very fast. */
+/* The n suffix means that a newline is NOT appended to the string
+ The v prefix means that we only print it when RC_VERBOSE=yes */
+bool colour_terminal (void);
+int einfon (const char *fmt, ...) EINFO_PRINTF (1, 2);
+int ewarnn (const char *fmt, ...) EINFO_PRINTF (1, 2);
+int eerrorn (const char *fmt, ...) EINFO_PRINTF (1, 2);
+int einfo (const char *fmt, ...) EINFO_PRINTF(1, 2);
+int ewarn (const char *fmt, ...) EINFO_PRINTF (1, 2);
+void ewarnx (const char *fmt, ...) EINFO_XPRINTF (1,2);
+int eerror (const char *fmt, ...) EINFO_PRINTF (1,2);
+void eerrorx (const char *fmt, ...) EINFO_XPRINTF (1,2);
+int ebegin (const char *fmt, ...) EINFO_PRINTF (1, 2);
+int eend (int retval, const char *fmt, ...) EINFO_PRINTF (2, 3);
+int ewend (int retval, const char *fmt, ...) EINFO_PRINTF (2, 3);
+void ebracket (int col, einfo_color_t color, const char *msg);
+void eindent (void);
+void eoutdent (void);
+
+int veinfon (const char *fmt, ...) EINFO_PRINTF (1, 2);
+int vewarnn (const char *fmt, ...) EINFO_PRINTF (1, 2);
+int vebeginn (const char *fmt, ...) EINFO_PRINTF (1, 2);
+int veendn (int retval, const char *fmt, ...) EINFO_PRINTF (2, 3);
+int vewendn (int retval, const char *fmt, ...) EINFO_PRINTF (2, 3);
+int veinfo (const char *fmt, ...) EINFO_PRINTF (1, 2);
+int vewarn (const char *fmt, ...) EINFO_PRINTF (1, 2);
+int vebegin (const char *fmt, ...) EINFO_PRINTF (1, 2);
+int veend (int retval, const char *fmt, ...) EINFO_PRINTF (2, 3);
+int vewend (int retval, const char *fmt, ...) EINFO_PRINTF (2, 3);
+void veindent (void);
+void veoutdent (void);
+
+/* If RC_EBUFFER is set, then we buffer all the above commands.
+ As such, we need to flush the buffer when done. */
+void eflush(void);
+
+#endif
diff --git a/src/env-update.c b/src/env-update.c
new file mode 100644
index 00000000..c04974b1
--- /dev/null
+++ b/src/env-update.c
@@ -0,0 +1,247 @@
+/*
+ env-update
+ Create /etc/profile.env (sh), /etc/csh.env from /etc/env.d
+ Run ldconfig as required
+
+ Copyright 2007 Gentoo Foundation
+ Released under the GPLv2
+ */
+
+#include <errno.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "einfo.h"
+#include "rc.h"
+#include "rc-misc.h"
+#include "strlist.h"
+
+#define ENVDIR "/etc/env.d"
+#define PROFILE_ENV "/etc/profile.env"
+#define CSH_ENV "/etc/csh.env"
+#define LDSOCONF "/etc/ld.so.conf"
+
+#define NOTICE "# THIS FILE IS AUTOMATICALLY GENERATED BY env-update.\n" \
+ "# DO NOT EDIT THIS FILE. CHANGES TO STARTUP PROFILES\n" \
+ "# GO INTO %s NOT %s\n\n"
+
+#define LDNOTICE "# ld.so.conf autogenerated by env-update; make all\n" \
+ "# changes to contents of /etc/env.d directory\n"
+
+static const char *specials[] =
+{
+ "ADA_INCLUDE_PATH",
+ "ADA_OBJECTS_PATH",
+ "CLASSPATH",
+ "INFOPATH",
+ "KDEDIRS",
+ "LDPATH",
+ "MANPATH",
+ "PATH",
+ "PKG_CONFIG_PATH",
+ "PRELINK_PATH",
+ "PRELINK_PATH_MASK",
+ "PYTHONPATH",
+ "ROOTPATH",
+ NULL
+};
+
+static const char *special_spaces[] =
+{
+ "CONFIG_PROTECT",
+ "CONFIG_PROTECT_MASK",
+ NULL,
+};
+
+static char *applet = NULL;
+
+int main (int argc, char **argv)
+{
+ char **files = rc_ls_dir (NULL, ENVDIR, 0);
+ char *file;
+ char **envs = NULL;
+ char *env;
+ int i = 0;
+ FILE *fp;
+ bool ld = true;
+ char *ldent;
+ char **ldents = NULL;
+ int nents = 0;
+
+ applet = argv[0];
+
+ if (! files)
+ eerrorx ("%s: no files in " ENVDIR " to process", applet);
+
+ STRLIST_FOREACH (files, file, i)
+ {
+ char *path = rc_strcatpaths (ENVDIR, file, NULL);
+ char **entries = NULL;
+ char *entry;
+ int j;
+
+ if (! rc_is_dir (path))
+ entries = rc_get_config (NULL, path);
+ free (path);
+
+ STRLIST_FOREACH (entries, entry, j)
+ {
+ char *tmpent = rc_xstrdup (entry);
+ char *value = tmpent;
+ char *var = strsep (&value, "=");
+ int k;
+ bool isspecial = false;
+ bool isspecial_spaced = false;
+ bool replaced = false;
+
+ for (k = 0; special_spaces[k]; k++)
+ if (strcmp (special_spaces[k], var) == 0)
+ {
+ isspecial = true;
+ isspecial_spaced = true;
+ break;
+ }
+
+ if (! isspecial)
+ {
+ for (k = 0; specials[k]; k++)
+ if (strcmp (specials[k], var) == 0)
+ {
+ isspecial = true;
+ break;
+ }
+ }
+
+ /* Skip blank vars */
+ if (isspecial &&
+ (! value || strlen (value)) == 0)
+ {
+ free (tmpent);
+ continue;
+ }
+
+ STRLIST_FOREACH (envs, env, k)
+ {
+ char *tmpenv = rc_xstrdup (env);
+ char *tmpvalue = tmpenv;
+ char *tmpentry = strsep (&tmpvalue, "=");
+
+ if (strcmp (tmpentry, var) == 0)
+ {
+ if (isspecial)
+ {
+ envs[k - 1] = rc_xrealloc (envs[k - 1],
+ strlen (envs[k - 1]) +
+ strlen (entry) + 1);
+ sprintf (envs[k - 1] + strlen (envs[k - 1]),
+ "%s%s", isspecial_spaced ? " " : ":", value);
+ }
+ else
+ {
+ free (envs[k - 1]);
+ envs[k - 1] = strdup (entry);
+ }
+ replaced = true;
+ }
+ free (tmpenv);
+
+ if (replaced)
+ break;
+ }
+
+ if (! replaced)
+ envs = rc_strlist_addsort (envs, entry);
+
+ free (tmpent);
+ }
+ }
+
+ if ((fp = fopen (PROFILE_ENV, "w")) == NULL)
+ eerrorx ("%s: fopen `%s': %s", applet, PROFILE_ENV, strerror (errno));
+ fprintf (fp, NOTICE, "/etc/profile", PROFILE_ENV);
+ STRLIST_FOREACH (envs, env, i)
+ {
+ char *tmpent = rc_xstrdup (env);
+ char *value = tmpent;
+ char *var = strsep (&value, "=");
+ if (strcmp (var, "LDPATH") != 0)
+ fprintf (fp, "export %s='%s'\n", var, value);
+ free (tmpent);
+ }
+ fclose (fp);
+
+ if ((fp = fopen (CSH_ENV, "w")) == NULL)
+ eerrorx ("%s: fopen `%s': %s", applet, PROFILE_ENV, strerror (errno));
+ fprintf (fp, NOTICE, "/etc/csh.cshrc", PROFILE_ENV);
+ STRLIST_FOREACH (envs, env, i)
+ {
+ char *tmpent = rc_xstrdup (env);
+ char *value = tmpent;
+ char *var = strsep (&value, "=");
+ if (strcmp (var, "LDPATH") != 0)
+ fprintf (fp, "setenv %s '%s'\n", var, value);
+ free (tmpent);
+ }
+ fclose (fp);
+
+ ldent = rc_get_config_entry (envs, "LDPATH");
+
+ if (! ldent ||
+ (argc > 1 && argv[1] && strcmp (argv[1], "--no-ldconfig") == 0))
+ {
+ free (envs);
+ return (EXIT_SUCCESS);
+ }
+
+ while ((file = strsep (&ldent, ":")))
+ {
+ if (strlen (file) == 0)
+ continue;
+
+ ldents = rc_strlist_add (ldents, file);
+ nents++;
+ }
+
+ /* Update ld.so.conf only if different */
+ if (rc_exists (LDSOCONF))
+ {
+ char **lines = rc_get_list (NULL, LDSOCONF);
+ char *line;
+ ld = false;
+ STRLIST_FOREACH (lines, line, i)
+ if (i > nents || strcmp (line, ldents[i - 1]) != 0)
+ {
+ ld = true;
+ break;
+ }
+ if (i - 1 != nents)
+ ld = true;
+ }
+
+ if (ld)
+ {
+ int retval = 0;
+
+ if ((fp = fopen (LDSOCONF, "w")) == NULL)
+ eerrorx ("%s: fopen `%s': %s", applet, LDSOCONF, strerror (errno));
+ fprintf (fp, LDNOTICE);
+ STRLIST_FOREACH (ldents, ldent, i)
+ fprintf (fp, "%s\n", ldent);
+ fclose (fp);
+
+#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
+ ebegin ("Regenerating /var/run/ld-elf.so.hints");
+ retval = system ("/sbin/ldconfig -elf -i '" LDSOCONF "'");
+#else
+ ebegin ("Regenerating /etc/ld.so.cache");
+ retval = system ("/sbin/ldconfig");
+#endif
+ eend (retval, NULL);
+ }
+
+ return(EXIT_SUCCESS);
+}
diff --git a/src/env_whitelist b/src/env_whitelist
new file mode 100644
index 00000000..ca21935b
--- /dev/null
+++ b/src/env_whitelist
@@ -0,0 +1,48 @@
+# System environment whitelist for rc-system
+# See /etc/conf.d/env_whitelist for details.
+
+#
+# Internal variables needed for operation of rc-system
+# NB: Do not modify below this line if you do not know what you are doing!!
+#
+
+# Hotplug
+IN_HOTPLUG
+
+# RC network script support
+IN_BACKGROUND
+RC_INTERFACE_KEEP_CONFIG
+
+# Default shell stuff
+PATH
+SHELL
+USER
+HOME
+TERM
+
+# Language variables
+LANG
+LC_CTYPE
+LC_NUMERIC
+LC_TIME
+LC_COLLATE
+LC_MONETARY
+LC_MESSAGES
+LC_PAPER
+LC_NAME
+LC_ADDRESS
+LC_TELEPHONE
+LC_MEASUREMENT
+LC_IDENTIFICATION
+LC_ALL
+
+# From /sbin/init
+INIT_HALT
+INIT_VERSION
+RUNLEVEL
+PREVLEVEL
+CONSOLE
+
+# Allow this through too so we can prefer stuff in /lib when shutting down
+# or going to single mode.
+LD_LIBRARY_PATH
diff --git a/src/fstabinfo.c b/src/fstabinfo.c
new file mode 100644
index 00000000..6f45cc70
--- /dev/null
+++ b/src/fstabinfo.c
@@ -0,0 +1,146 @@
+/*
+ fstabinfo.c
+ Gets information about /etc/fstab.
+
+ Copyright 2007 Gentoo Foundation
+ */
+
+#include <errno.h>
+#include <libgen.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Yay for linux and it's non liking of POSIX functions.
+ Okay, we could use getfsent but the man page says use getmntent instead
+ AND we don't have getfsent on uclibc or dietlibc for some odd reason. */
+#ifdef __linux__
+#define HAVE_GETMNTENT
+#include <mntent.h>
+#define GET_ENT getmntent (fp)
+#define GET_ENT_FILE(_name) getmntfile (fp, _name)
+#define END_ENT endmntent (fp)
+#define ENT_DEVICE(_ent) ent->mnt_fsname
+#define ENT_FILE(_ent) ent->mnt_dir
+#define ENT_TYPE(_ent) ent->mnt_type
+#define ENT_OPTS(_ent) ent->mnt_opts
+#define ENT_PASS(_ent) ent->mnt_passno
+#else
+#define HAVE_GETFSENT
+#include <fstab.h>
+#define GET_ENT getfsent ()
+#define GET_ENT_FILE(_name) getfsfile (_name)
+#define END_ENT endfsent ()
+#define ENT_DEVICE(_ent) ent->fs_spec
+#define ENT_TYPE(_ent) ent->fs_vfstype
+#define ENT_FILE(_ent) ent->fs_file
+#define ENT_OPTS(_ent) ent->fs_mntops
+#define ENT_PASS(_ent) ent->fs_passno
+#endif
+
+#include "einfo.h"
+
+#ifdef HAVE_GETMNTENT
+static struct mntent *getmntfile (FILE *fp, const char *file)
+{
+ struct mntent *ent;
+
+ while ((ent = getmntent (fp)))
+ if (strcmp (file, ent->mnt_dir) == 0)
+ return (ent);
+
+ return (NULL);
+}
+#endif
+
+int main (int argc, char **argv)
+{
+ int i;
+#ifdef HAVE_GETMNTENT
+ FILE *fp;
+ struct mntent *ent;
+#else
+ struct fstab *ent;
+#endif
+ int result = EXIT_FAILURE;
+ char *p;
+ char *token;
+ int n = 0;
+
+ for (i = 1; i < argc; i++)
+ {
+#ifdef HAVE_GETMNTENT
+ fp = setmntent ("/etc/fstab", "r");
+#endif
+
+ if (strcmp (argv[i], "--fstype") == 0 && i + 1 < argc)
+ {
+ i++;
+ p = argv[i];
+ while ((token = strsep (&p, ",")))
+ while ((ent = GET_ENT))
+ if (strcmp (token, ENT_TYPE (ent)) == 0)
+ printf ("%s\n", ENT_FILE (ent));
+ result = EXIT_SUCCESS;
+ }
+
+ if (strcmp (argv[i], "--mount-cmd") == 0 && i + 1 < argc)
+ {
+ i++;
+ if ((ent = GET_ENT_FILE (argv[i])) == NULL)
+ continue;
+ printf ("-o %s -t %s %s %s\n", ENT_OPTS (ent), ENT_TYPE (ent),
+ ENT_DEVICE (ent), ENT_FILE (ent));
+ result = EXIT_SUCCESS;
+ }
+
+ if (strcmp (argv[i], "--opts") == 0 && i + 1 < argc)
+ {
+ i++;
+ if ((ent = GET_ENT_FILE (argv[i])) == NULL)
+ continue;
+ printf ("%s\n", ENT_OPTS (ent));
+ result = EXIT_SUCCESS;
+ }
+
+ if (strcmp (argv[i], "--passno") == 0 && i + 1 < argc)
+ {
+ i++;
+ switch (argv[i][0])
+ {
+ case '=':
+ case '<':
+ case '>':
+ if (sscanf (argv[i] + 1, "%d", &n) != 1)
+ eerrorx ("%s: invalid passno %s", argv[0], argv[i] + 1);
+
+ while ((ent = GET_ENT))
+ {
+ if (((argv[i][0] == '=' && n == ENT_PASS (ent)) ||
+ (argv[i][0] == '<' && n > ENT_PASS (ent)) ||
+ (argv[i][0] == '>' && n < ENT_PASS (ent))) &&
+ strcmp (ENT_FILE (ent), "none") != 0)
+ printf ("%s\n", ENT_FILE (ent));
+ }
+
+ default:
+ if ((ent = GET_ENT_FILE (argv[i])) == NULL)
+ continue;
+ printf ("%d\n", ENT_PASS (ent));
+ result = EXIT_SUCCESS;
+ }
+ }
+
+ END_ENT;
+
+ if (result != EXIT_SUCCESS)
+ {
+ eerror ("%s: unknown option `%s'", basename (argv[0]), argv[i]);
+ break;
+ }
+
+ }
+
+ exit (result);
+}
+
diff --git a/src/libeinfo.c b/src/libeinfo.c
new file mode 100644
index 00000000..e0faf988
--- /dev/null
+++ b/src/libeinfo.c
@@ -0,0 +1,877 @@
+/*
+ einfo.c
+ Gentoo informational functions
+ Copyright 2007 Gentoo Foundation
+ */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include "einfo.h"
+#include "rc.h"
+#include "rc-misc.h"
+
+/* Incase we cannot work out how many columns from ioctl, supply a default */
+#define DEFAULT_COLS 80
+
+#define OK "ok"
+#define NOT_OK "!!"
+
+#define CHECK_VERBOSE if (! is_env ("RC_VERBOSE", "yes")) return 0
+
+/* Number of spaces for an indent */
+#define INDENT_WIDTH 2
+
+/* How wide can the indent go? */
+#define INDENT_MAX 40
+
+#define EBUFFER_LOCK RC_SVCDIR "ebuffer/.lock"
+
+/* A cheat sheet of colour capable terminals
+ This is taken from DIR_COLORS from GNU coreutils
+ We embed it here as we shouldn't depend on coreutils */
+static const char *colour_terms[] =
+{
+ "Eterm",
+ "ansi",
+ "color-xterm",
+ "con132x25",
+ "con132x30",
+ "con132x43",
+ "con132x60",
+ "con80x25",
+ "con80x28",
+ "con80x30",
+ "con80x43",
+ "con80x50",
+ "con80x60",
+ "cons25",
+ "console",
+ "cygwin",
+ "dtterm",
+ "gnome",
+ "konsole",
+ "kterm",
+ "linux",
+ "linux-c",
+ "mach-color",
+ "mlterm",
+ "putty",
+ "rxvt",
+ "rxvt-cygwin",
+ "rxvt-cygwin-native",
+ "rxvt-unicode",
+ "screen",
+ "screen-bce",
+ "screen-w",
+ "screen.linux",
+ "vt100",
+ "xterm",
+ "xterm-256color",
+ "xterm-color",
+ "xterm-debian",
+ NULL
+};
+
+static bool is_env (const char *var, const char *val)
+{
+ char *v;
+
+ if (! var)
+ return (false);
+
+ v = getenv (var);
+ if (! v)
+ return (val == NULL ? true : false);
+
+ return (strcasecmp (v, val) == 0 ? true : false);
+}
+
+bool colour_terminal (void)
+{
+ static int in_colour = -1;
+ int i = 0;
+ char *term;
+
+ if (in_colour == 0)
+ return (false);
+ if (in_colour == 1)
+ return (true);
+
+ term = getenv ("TERM");
+ /* If $TERM isn't set then the chances are we're in single user mode */
+ if (! term)
+ return (true);
+
+ while (colour_terms[i])
+ {
+ if (strcmp (colour_terms[i], term) == 0)
+ {
+ in_colour = 1;
+ return (true);
+ }
+ i++;
+ }
+
+ in_colour = 0;
+ return (false);
+}
+
+static int get_term_columns (void)
+{
+#ifdef TIOCGSIZE /* BSD */
+ struct ttysize ts;
+
+ if (ioctl(0, TIOCGSIZE, &ts) == 0)
+ return (ts.ts_cols);
+#elif TIOCGWINSZ /* Linux */
+ struct winsize ws;
+
+ if (ioctl(0, TIOCGWINSZ, &ws) == 0)
+ return (ws.ws_col);
+#endif
+
+ return (DEFAULT_COLS);
+}
+
+static int ebuffer (const char *cmd, int retval, const char *fmt, va_list ap)
+{
+ char *file = getenv ("RC_EBUFFER");
+ FILE *fp;
+ char buffer[RC_LINEBUFFER];
+ int l = 1;
+
+ if (! file || ! cmd || strlen (cmd) < 4)
+ return (0);
+
+ if (! (fp = fopen (file, "a")))
+ {
+ fprintf (stderr, "fopen `%s': %s\n", file, strerror (errno));
+ return (0);
+ }
+
+ fprintf (fp, "%s %d ", cmd, retval);
+
+ if (fmt)
+ {
+ l = vsnprintf (buffer, sizeof (buffer), fmt, ap);
+ fprintf (fp, "%d %s\n", l, buffer);
+ }
+ else
+ fprintf (fp, "0\n");
+
+ fclose (fp);
+ return (l);
+}
+
+typedef struct func
+{
+ const char *name;
+ int (*efunc) (const char *fmt, ...);
+ int (*eefunc) (int retval, const char *fmt, ...);
+ void (*eind) (void);
+} func_t;
+
+static const func_t funcmap[] = {
+ { "einfon", &einfon, NULL, NULL },
+ { "ewarnn", &ewarnn, NULL, NULL},
+ { "eerrorn", &eerrorn, NULL, NULL},
+ { "einfo", &einfo, NULL, NULL },
+ { "ewarn", &ewarn, NULL, NULL },
+ { "eerror", &eerror, NULL, NULL },
+ { "ebegin", &ebegin, NULL, NULL },
+ { "eend", NULL, &eend, NULL },
+ { "ewend", NULL, &ewend, NULL },
+ { "eindent", NULL, NULL, &eindent },
+ { "eoutdent", NULL, NULL, &eoutdent },
+ { "veinfon", &veinfon, NULL, NULL },
+ { "vewarnn", &vewarnn, NULL, NULL },
+ { "veinfo", &veinfo, NULL, NULL },
+ { "vewarn", &vewarn, NULL, NULL },
+ { "vebegin", &vebegin, NULL, NULL },
+ { "veend", NULL, &veend, NULL },
+ { "vewend", NULL, &vewend, NULL },
+ { "veindent" ,NULL, NULL, &veindent },
+ { "veoutdent", NULL, NULL, &veoutdent },
+ { NULL, NULL, NULL, NULL },
+};
+
+void eflush (void)
+{
+ FILE *fp;
+ char *file = getenv ("RC_EBUFFER");
+ char buffer[RC_LINEBUFFER];
+ char *cmd;
+ int retval = 0;
+ int length = 0;
+ char *token;
+ char *p;
+ struct stat buf;
+ pid_t pid;
+ char newfile[PATH_MAX];
+ int i = 1;
+
+ if (! file|| (stat (file, &buf) != 0))
+ {
+ errno = 0;
+ return;
+ }
+
+ /* Find a unique name for our file */
+ while (true)
+ {
+ snprintf (newfile, sizeof (newfile), "%s.%d", file, i);
+ if (stat (newfile, &buf) != 0)
+ {
+ if (rename (file, newfile))
+ fprintf (stderr, "rename `%s' `%s': %s\n", file, newfile,
+ strerror (errno));
+ break;
+ }
+ i++;
+ }
+
+ /* We fork a child process here so we don't hold anything up */
+ if ((pid = fork ()) == -1)
+ {
+ fprintf (stderr, "fork: %s", strerror (errno));
+ return;
+ }
+
+ if (pid != 0)
+ return;
+
+ /* Spin until we can lock the ebuffer */
+ while (true)
+ {
+ struct timeval tv;
+ tv.tv_sec = 0;
+ tv.tv_usec = 20000;
+ select (0, NULL, NULL, NULL, &tv);
+ errno = 0;
+ if (link (newfile, EBUFFER_LOCK) == 0)
+ break;
+ if (errno != EEXIST)
+ fprintf (stderr, "link `%s' `%s': %s\n", newfile, EBUFFER_LOCK,
+ strerror (errno));
+ }
+
+ if (! (fp = fopen (newfile, "r")))
+ {
+ fprintf (stderr, "fopen `%s': %s\n", newfile, strerror (errno));
+ return;
+ }
+
+ unsetenv ("RC_EBUFFER");
+
+ memset (buffer, 0, RC_LINEBUFFER);
+ while (fgets (buffer, RC_LINEBUFFER, fp))
+ {
+ i = strlen (buffer) - 1;
+ if (i < 1)
+ continue;
+
+ if (buffer[i] == '\n')
+ buffer[i] = 0;
+
+ p = buffer;
+ cmd = strsep (&p, " ");
+ token = strsep (&p, " ");
+ if (sscanf (token, "%d", &retval) != 1)
+ {
+ fprintf (stderr, "eflush `%s': not a number", token);
+ continue;
+ }
+ token = strsep (&p, " ");
+ if (sscanf (token, "%d", &length) != 1)
+ {
+ fprintf (stderr, "eflush `%s': not a number", token);
+ continue;
+ }
+
+ i = 0;
+ while (funcmap[i].name)
+ {
+ if (strcmp (funcmap[i].name, cmd) == 0)
+ {
+ if (funcmap[i].efunc)
+ {
+ if (p)
+ funcmap[i].efunc ("%s", p);
+ else
+ funcmap[i].efunc (NULL, NULL);
+ }
+ else if (funcmap[i].eefunc)
+ {
+ if (p)
+ funcmap[i].eefunc (retval, "%s", p);
+ else
+ funcmap[i].eefunc (retval, NULL, NULL);
+ }
+ else if (funcmap[i].eind)
+ funcmap[i].eind ();
+ else
+ fprintf (stderr, "eflush `%s': no function defined\n", cmd);
+ break;
+ }
+ i++;
+ }
+
+ if (! funcmap[i].name)
+ fprintf (stderr, "eflush `%s': invalid function\n", cmd);
+ }
+ fclose (fp);
+
+ if (unlink (EBUFFER_LOCK))
+ fprintf (stderr, "unlink `%s': %s", EBUFFER_LOCK, strerror (errno));
+
+ if (unlink (newfile))
+ fprintf (stderr, "unlink `%s': %s", newfile, strerror (errno));
+
+ _exit (EXIT_SUCCESS);
+}
+
+#define EBUFFER(_cmd, _retval, _fmt, _ap) \
+{ \
+ int _i = ebuffer (_cmd, _retval, _fmt, _ap); \
+ if (_i) \
+ return (_i); \
+}
+
+static void elog (int level, const char *fmt, va_list ap)
+{
+ char *e = getenv ("RC_ELOG");
+
+ if (e)
+ {
+ closelog ();
+ openlog (e, LOG_PID, LOG_DAEMON);
+ vsyslog (level, fmt, ap);
+ }
+}
+static int _eindent (FILE *stream)
+{
+ char *env = getenv ("RC_EINDENT");
+ int amount = 0;
+ char indent[INDENT_MAX];
+
+ if (env)
+ {
+ errno = 0;
+ amount = strtol (env, NULL, 0);
+ if (errno != 0 || amount < 0)
+ amount = 0;
+ else if (amount > INDENT_MAX)
+ amount = INDENT_MAX;
+
+ if (amount > 0)
+ memset (indent, ' ', amount);
+ }
+
+ /* Terminate it */
+ memset (indent + amount, 0, 1);
+
+ return (fprintf (stream, "%s", indent));
+}
+
+#define VEINFON(_file, _colour) \
+ if (colour_terminal ()) \
+ fprintf (_file, " " _colour "*" EINFO_NORMAL " "); \
+ else \
+ fprintf (_file, " * "); \
+ retval += _eindent (_file); \
+ retval += vfprintf (_file, fmt, ap) + 3; \
+ if (colour_terminal ()) \
+ fprintf (_file, "\033[K");
+
+static int _veinfon (const char *fmt, va_list ap)
+{
+ int retval = 0;
+
+ VEINFON (stdout, EINFO_GOOD);
+ return (retval);
+}
+
+static int _vewarnn (const char *fmt, va_list ap)
+{
+ int retval = 0;
+
+ VEINFON (stdout, EINFO_WARN);
+ return (retval);
+}
+
+static int _veerrorn (const char *fmt, va_list ap)
+{
+ int retval = 0;
+
+ VEINFON (stderr, EINFO_BAD);
+ return (retval);
+}
+
+int einfon (const char *fmt, ...)
+{
+ int retval;
+ va_list ap;
+
+ if (! fmt || is_env ("RC_QUIET", "yes"))
+ return (0);
+
+ va_start (ap, fmt);
+ if (! (retval = ebuffer ("einfon", 0, fmt, ap)))
+ retval = _veinfon (fmt, ap);
+ va_end (ap);
+
+ return (retval);
+}
+
+int ewarnn (const char *fmt, ...)
+{
+ int retval;
+ va_list ap;
+
+ if (! fmt || is_env ("RC_QUIET", "yes"))
+ return (0);
+
+ va_start (ap, fmt);
+ if (! (retval = ebuffer ("ewarnn", 0, fmt, ap)))
+ retval = _vewarnn (fmt, ap);
+ va_end (ap);
+
+ return (retval);
+}
+
+int eerrorn (const char *fmt, ...)
+{
+ int retval;
+ va_list ap;
+
+ va_start (ap, fmt);
+ if (! (retval = ebuffer ("eerrorn", 0, fmt, ap)))
+ retval = _veerrorn (fmt, ap);
+ va_end (ap);
+
+ return (retval);
+}
+
+int einfo (const char *fmt, ...)
+{
+ int retval;
+ va_list ap;
+
+ if (! fmt || is_env ("RC_QUIET", "yes"))
+ return (0);
+
+ va_start (ap, fmt);
+ if (! (retval = ebuffer ("einfo", 0, fmt, ap)))
+ {
+ retval = _veinfon (fmt, ap);
+ retval += printf ("\n");
+ }
+ va_end (ap);
+
+ return (retval);
+}
+
+int ewarn (const char *fmt, ...)
+{
+ int retval;
+ va_list ap;
+
+ if (! fmt || is_env ("RC_QUIET", "yes"))
+ return (0);
+
+ va_start (ap, fmt);
+ elog (LOG_WARNING, fmt, ap);
+ if (! (retval = ebuffer ("ewarn", 0, fmt, ap)))
+ {
+ retval = _vewarnn (fmt, ap);
+ retval += printf ("\n");
+ }
+ va_end (ap);
+
+ return (retval);
+}
+
+void ewarnx (const char *fmt, ...)
+{
+ int retval;
+ va_list ap;
+
+ if (fmt && ! is_env ("RC_QUIET", "yes"))
+ {
+ va_start (ap, fmt);
+ elog (LOG_WARNING, fmt, ap);
+ retval = _vewarnn (fmt, ap);
+ va_end (ap);
+ retval += printf ("\n");
+ }
+ exit (EXIT_FAILURE);
+}
+
+int eerror (const char *fmt, ...)
+{
+ int retval;
+ va_list ap;
+
+ if (! fmt)
+ return (0);
+
+ va_start (ap, fmt);
+ elog (LOG_ERR, fmt, ap);
+ retval = _veerrorn (fmt, ap);
+ va_end (ap);
+ retval += fprintf (stderr, "\n");
+
+ return (retval);
+}
+
+void eerrorx (const char *fmt, ...)
+{
+ va_list ap;
+
+ if (fmt)
+ {
+ va_start (ap, fmt);
+ elog (LOG_ERR, fmt, ap);
+ _veerrorn (fmt, ap);
+ va_end (ap);
+ printf ("\n");
+ }
+ exit (EXIT_FAILURE);
+}
+
+int ebegin (const char *fmt, ...)
+{
+ int retval;
+ va_list ap;
+
+ if (! fmt || is_env ("RC_QUIET", "yes"))
+ return (0);
+
+ va_start (ap, fmt);
+ if ((retval = ebuffer ("ebegin", 0, fmt, ap)))
+ {
+ va_end (ap);
+ return (retval);
+ }
+
+ retval = _veinfon (fmt, ap);
+ va_end (ap);
+ retval += printf (" ...");
+ if (colour_terminal ())
+ retval += printf ("\n");
+
+ return (retval);
+}
+
+static void _eend (int col, einfo_color_t color, const char *msg)
+{
+ FILE *fp = stdout;
+ int i;
+ int cols;
+
+ if (! msg)
+ return;
+
+ if (color == einfo_bad)
+ fp = stderr;
+
+ cols = get_term_columns () - (strlen (msg) + 6);
+
+ if (cols > 0 && colour_terminal ())
+ {
+ fprintf (fp, "\033[A\033[%dC %s[ ", cols, EINFO_BRACKET);
+ switch (color)
+ {
+ case einfo_good:
+ fprintf (fp, EINFO_GOOD);
+ break;
+ case einfo_warn:
+ fprintf (fp, EINFO_WARN);
+ break;
+ case einfo_bad:
+ fprintf (fp, EINFO_BAD);
+ break;
+ case einfo_hilite:
+ fprintf (fp, EINFO_HILITE);
+ break;
+ case einfo_bracket:
+ fprintf (fp, EINFO_BRACKET);
+ break;
+ case einfo_normal:
+ fprintf (fp, EINFO_NORMAL);
+ break;
+ }
+ fprintf (fp, "%s%s ]%s\n", msg, EINFO_BRACKET, EINFO_NORMAL);
+ }
+ else
+ {
+ for (i = -1; i < cols - col; i++)
+ fprintf (fp, " ");
+ fprintf (fp, "[ %s ]\n", msg);
+ }
+}
+
+static int _do_eend (const char *cmd, int retval, const char *fmt, va_list ap)
+{
+ int col = 0;
+ FILE *fp;
+
+ if (ebuffer (cmd, retval, fmt, ap))
+ return (retval);
+
+ if (fmt && retval != 0)
+ {
+ if (strcmp (cmd, "ewend") == 0)
+ {
+ col = _vewarnn (fmt, ap);
+ fp = stdout;
+ }
+ else
+ {
+ col = _veerrorn (fmt, ap);
+ fp = stderr;
+ }
+ if (colour_terminal ())
+ fprintf (fp, "\n");
+ }
+
+ _eend (col, retval == 0 ? einfo_good : einfo_bad, retval == 0 ? OK : NOT_OK);
+ return (retval);
+}
+
+int eend (int retval, const char *fmt, ...)
+{
+ va_list ap;
+
+ if (is_env ("RC_QUIET", "yes"))
+ return (retval);
+
+ va_start (ap, fmt);
+ _do_eend ("eend", retval, fmt, ap);
+ va_end (ap);
+
+ return (retval);
+}
+
+int ewend (int retval, const char *fmt, ...)
+{
+ va_list ap;
+
+ if (is_env ("RC_QUIET", "yes"))
+ return (retval);
+
+ va_start (ap, fmt);
+ _do_eend ("ewend", retval, fmt, ap);
+ va_end (ap);
+
+ return (retval);
+}
+
+void ebracket (int col, einfo_color_t color, const char *msg)
+{
+ _eend (col, color, msg);
+}
+
+void eindent (void)
+{
+ char *env = getenv ("RC_EINDENT");
+ int amount = 0;
+ char num[10];
+
+ if (ebuffer ("eindent", 0, NULL, NULL))
+ return;
+
+ if (env)
+ {
+ errno = 0;
+ amount = strtol (env, NULL, 0);
+ if (errno != 0)
+ amount = 0;
+ }
+
+ amount += INDENT_WIDTH;
+ if (amount > INDENT_MAX)
+ amount = INDENT_MAX;
+
+ snprintf (num, 10, "%08d", amount);
+ setenv ("RC_EINDENT", num, 1);
+}
+
+void eoutdent (void)
+{
+ char *env = getenv ("RC_EINDENT");
+ int amount = 0;
+ char num[10];
+
+ if (ebuffer ("eoutdent", 0, NULL, NULL))
+ return;
+
+ if (! env)
+ return;
+
+ errno = 0;
+ amount = strtol (env, NULL, 0);
+ if (errno != 0)
+ amount = 0;
+ else
+ amount -= INDENT_WIDTH;
+
+ if (amount <= 0)
+ unsetenv ("RC_EINDENT");
+ else
+ {
+ snprintf (num, 10, "%08d", amount);
+ setenv ("RC_EINDENT", num, 1);
+ }
+}
+
+int veinfon (const char *fmt, ...)
+{
+ int retval;
+ va_list ap;
+
+ CHECK_VERBOSE;
+
+ if (! fmt)
+ return (0);
+
+ va_start (ap, fmt);
+ if (! (retval = ebuffer ("veinfon", 0, fmt, ap)))
+ retval = _veinfon (fmt, ap);
+ va_end (ap);
+
+ return (retval);
+}
+
+int vewarnn (const char *fmt, ...)
+{
+ int retval;
+ va_list ap;
+
+ CHECK_VERBOSE;
+
+ if (! fmt)
+ return (0);
+
+ va_start (ap, fmt);
+ if (! (retval = ebuffer ("vewarnn", 0, fmt, ap)))
+ retval = _vewarnn (fmt, ap);
+ va_end (ap);
+
+ return (retval);
+}
+
+int veinfo (const char *fmt, ...)
+{
+ int retval;
+ va_list ap;
+
+ CHECK_VERBOSE;
+
+ if (! fmt)
+ return (0);
+
+ va_start (ap, fmt);
+ if (! (retval = ebuffer ("veinfo", 0, fmt, ap)))
+ {
+ retval = _veinfon (fmt, ap);
+ retval += printf ("\n");
+ }
+ va_end (ap);
+
+ return (retval);
+}
+
+int vewarn (const char *fmt, ...)
+{
+ int retval;
+ va_list ap;
+
+ CHECK_VERBOSE;
+
+ if (! fmt)
+ return (0);
+
+ va_start (ap, fmt);
+ if (! (retval = ebuffer ("vewarn", 0, fmt, ap)))
+ {
+ retval = _vewarnn (fmt, ap);
+ retval += printf ("\n");
+ }
+ va_end (ap);
+ retval += printf ("\n");
+
+ return (retval);
+}
+
+int vebegin (const char *fmt, ...)
+{
+ int retval;
+ va_list ap;
+
+ CHECK_VERBOSE;
+
+ if (! fmt)
+ return (0);
+
+ va_start (ap, fmt);
+ if (! (retval = ebuffer ("vewarn", 0, fmt, ap)))
+ {
+ retval = _veinfon (fmt, ap);
+ retval += printf (" ...");
+ if (colour_terminal ())
+ retval += printf ("\n");
+ }
+ va_end (ap);
+
+ return (retval);
+}
+
+int veend (int retval, const char *fmt, ...)
+{
+ va_list ap;
+
+ CHECK_VERBOSE;
+
+ va_start (ap, fmt);
+ _do_eend ("veend", retval, fmt, ap);
+ va_end (ap);
+
+ return (retval);
+}
+
+int vewend (int retval, const char *fmt, ...)
+{
+ va_list ap;
+
+ CHECK_VERBOSE;
+
+ va_start (ap, fmt);
+ _do_eend ("vewend", retval, fmt, ap);
+ va_end (ap);
+
+ return (retval);
+}
+
+void veindent (void)
+{
+ if (is_env ("RC_VERBOSE", "yes"))
+ eindent ();
+}
+
+void veoutdent (void)
+{
+ if (is_env ("RC_VERBOSE", "yes"))
+ eoutdent ();
+}
diff --git a/src/librc-daemon.c b/src/librc-daemon.c
new file mode 100644
index 00000000..02d0d937
--- /dev/null
+++ b/src/librc-daemon.c
@@ -0,0 +1,600 @@
+/*
+ librc-daemon
+ Finds PID for given daemon criteria
+ Copyright 2007 Gentoo Foundation
+ Released under the GPLv2
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#if defined(__FreeBSD__) || defined(__NetBSD__) || defined (__OpenBSD__)
+#include <sys/param.h>
+#include <sys/user.h>
+#include <sys/sysctl.h>
+#include <kvm.h>
+#include <limits.h>
+#endif
+
+#ifndef __linux__
+#include <libgen.h>
+#endif
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "einfo.h"
+#include "rc.h"
+#include "rc-misc.h"
+#include "strlist.h"
+
+#if defined(__linux__)
+static bool pid_is_cmd (pid_t pid, const char *cmd)
+{
+ char buffer[32];
+ FILE *fp;
+ int c;
+
+ snprintf(buffer, sizeof (buffer), "/proc/%d/stat", pid);
+ if ((fp = fopen (buffer, "r")) == NULL)
+ return (false);
+
+ while ((c = getc (fp)) != EOF && c != '(')
+ ;
+
+ if (c != '(')
+ {
+ fclose(fp);
+ return (false);
+ }
+
+ while ((c = getc (fp)) != EOF && c == *cmd)
+ cmd++;
+
+ fclose (fp);
+
+ return ((c == ')' && *cmd == '\0') ? true : false);
+}
+
+static bool pid_is_exec (pid_t pid, const char *exec)
+{
+ char cmdline[32];
+ char buffer[PATH_MAX];
+ char *p;
+ int fd = -1;
+ int r;
+
+ snprintf (cmdline, sizeof (cmdline), "/proc/%u/exe", pid);
+ memset (buffer, 0, sizeof (buffer));
+ if (readlink (cmdline, buffer, sizeof (buffer)) != -1)
+ {
+ if (strcmp (exec, buffer) == 0)
+ return (true);
+
+ /* We should cater for deleted binaries too */
+ if (strlen (buffer) > 10)
+ {
+ p = buffer + (strlen (buffer) - 10);
+ if (strcmp (p, " (deleted)") == 0)
+ {
+ *p = 0;
+ if (strcmp (buffer, exec) == 0)
+ return (true);
+ }
+ }
+ }
+
+ snprintf (cmdline, sizeof (cmdline), "/proc/%u/cmdline", pid);
+ if ((fd = open (cmdline, O_RDONLY)) < 0)
+ return (false);
+
+ r = read(fd, buffer, sizeof (buffer));
+ close (fd);
+
+ if (r == -1)
+ return 0;
+
+ buffer[r] = 0;
+ return (strcmp (exec, buffer) == 0 ? true : false);
+}
+
+pid_t *rc_find_pids (const char *exec, const char *cmd,
+ uid_t uid, pid_t pid)
+{
+ DIR *procdir;
+ struct dirent *entry;
+ int npids = 0;
+ int foundany = false;
+ pid_t p;
+ pid_t *pids = NULL;
+ char buffer[PATH_MAX];
+ struct stat sb;
+ pid_t runscript_pid = 0;
+ char *pp;
+
+ if ((procdir = opendir ("/proc")) == NULL)
+ eerrorx ("opendir `/proc': %s", strerror (errno));
+
+ /*
+ We never match RC_RUNSCRIPT_PID if present so we avoid the below
+ scenario
+
+ /etc/init.d/ntpd stop does
+ start-stop-daemon --stop --name ntpd
+ catching /etc/init.d/ntpd stop
+
+ nasty
+ */
+
+ if ((pp = getenv ("RC_RUNSCRIPT_PID")))
+ {
+ if (sscanf (pp, "%d", &runscript_pid) != 1)
+ runscript_pid = 0;
+ }
+
+ while ((entry = readdir (procdir)) != NULL)
+ {
+ if (sscanf (entry->d_name, "%d", &p) != 1)
+ continue;
+ foundany = true;
+
+ if (runscript_pid != 0 && runscript_pid == p)
+ continue;
+
+ if (pid != 0 && pid != p)
+ continue;
+
+ if (uid)
+ {
+ snprintf (buffer, sizeof (buffer), "/proc/%d", pid);
+ if (stat (buffer, &sb) != 0 || sb.st_uid != uid)
+ continue;
+ }
+
+ if (cmd && ! pid_is_cmd (p, cmd))
+ continue;
+
+ if (exec && ! cmd && ! pid_is_exec (p, exec))
+ continue;
+
+ pids = realloc (pids, sizeof (pid_t) * (npids + 2));
+ if (! pids)
+ eerrorx ("memory exhausted");
+
+ pids[npids] = p;
+ pids[npids + 1] = 0;
+ npids++;
+ }
+ closedir (procdir);
+
+ if (! foundany)
+ eerrorx ("nothing in /proc");
+
+ return (pids);
+}
+
+#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
+
+# if defined(__FreeBSD__)
+# define _KINFO_PROC kinfo_proc
+# define _KVM_GETPROCS kvm_getprocs
+# define _KVM_GETARGV kvm_getargv
+# define _GET_KINFO_UID(kp) (kp.ki_ruid)
+# define _GET_KINFO_COMM(kp) (kp.ki_comm)
+# define _GET_KINFO_PID(kp) (kp.ki_pid)
+# else
+# define _KINFO_PROC kinfo_proc2
+# define _KVM_GETPROCS kvm_getprocs2
+# define _KVM_GETARGV kvm_getargv2
+# define _GET_KINFO_UID(kp) (kp.p_ruid)
+# define _GET_KINFO_COMM(kp) (kp.p_comm)
+# define _GET_KINFO_PID(kp) (kp.p_pid)
+# endif
+
+pid_t *rc_find_pids (const char *exec, const char *cmd,
+ uid_t uid, pid_t pid)
+{
+ static kvm_t *kd = NULL;
+ char errbuf[_POSIX2_LINE_MAX];
+ struct _KINFO_PROC *kp;
+ int i;
+ int processes = 0;
+ int argc = 0;
+ char **argv;
+ pid_t *pids = NULL;
+ int npids = 0;
+
+ if ((kd = kvm_openfiles (NULL, NULL, NULL, O_RDONLY, errbuf)) == NULL)
+ eerrorx ("kvm_open: %s", errbuf);
+
+ kp = _KVM_GETPROCS (kd, KERN_PROC_PROC, 0, &processes);
+ for (i = 0; i < processes; i++)
+ {
+ pid_t p = _GET_KINFO_PID (kp[i]);
+ if (pid != 0 && pid != p)
+ continue;
+
+ if (uid != 0 && uid != _GET_KINFO_UID (kp[i]))
+ continue;
+
+ if (cmd)
+ {
+ if (! _GET_KINFO_COMM (kp[i]) ||
+ strcmp (cmd, _GET_KINFO_COMM (kp[i])) != 0)
+ continue;
+ }
+
+ if (exec && ! cmd)
+ {
+ if ((argv = _KVM_GETARGV (kd, &kp[i], argc)) == NULL || ! *argv)
+ continue;
+
+ if (strcmp (*argv, exec) != 0)
+ continue;
+ }
+
+ pids = realloc (pids, sizeof (pid_t) * (npids + 2));
+ if (! pids)
+ eerrorx ("memory exhausted");
+
+ pids[npids] = p;
+ pids[npids + 1] = 0;
+ npids++;
+ }
+ kvm_close(kd);
+
+ return (pids);
+}
+
+#else
+# error "Platform not supported!"
+#endif
+
+static bool _match_daemon (const char *path, const char *file,
+ const char *mexec, const char *mname,
+ const char *mpidfile)
+{
+ char buffer[RC_LINEBUFFER];
+ char *ffile = rc_strcatpaths (path, file, NULL);
+ FILE *fp;
+ int lc = 0;
+ int m = 0;
+
+ if (! rc_exists (ffile))
+ {
+ free (ffile);
+ return (false);
+ }
+
+ if ((fp = fopen (ffile, "r")) == NULL)
+ {
+ eerror ("fopen `%s': %s", ffile, strerror (errno));
+ free (ffile);
+ return (false);
+ }
+
+ if (! mname)
+ m += 10;
+ if (! mpidfile)
+ m += 100;
+
+ memset (buffer, 0, sizeof (buffer));
+ while ((fgets (buffer, RC_LINEBUFFER, fp)))
+ {
+ int lb = strlen (buffer) - 1;
+ if (buffer[lb] == '\n')
+ buffer[lb] = 0;
+
+ if (strcmp (buffer, mexec) == 0)
+ m += 1;
+ else if (mname && strcmp (buffer, mname) == 0)
+ m += 10;
+ else if (mpidfile && strcmp (buffer, mpidfile) == 0)
+ m += 100;
+
+ if (m == 111)
+ break;
+
+ lc++;
+ if (lc > 5)
+ break;
+ }
+ fclose (fp);
+ free (ffile);
+
+ return (m == 111 ? true : false);
+}
+
+void rc_set_service_daemon (const char *service, const char *exec,
+ const char *name, const char *pidfile,
+ bool started)
+{
+ char *dirpath = rc_strcatpaths (RC_SVCDIR, "daemons", basename (service), NULL);
+ char **files = NULL;
+ char *file;
+ char *ffile = NULL;
+ int i;
+ char *mexec;
+ char *mname;
+ char *mpidfile;
+ int nfiles = 0;
+
+ if (! exec && ! name && ! pidfile)
+ return;
+
+ if (exec)
+ {
+ i = strlen (exec) + 6;
+ mexec = rc_xmalloc (sizeof (char *) * i);
+ snprintf (mexec, i, "exec=%s", exec);
+ }
+ else
+ mexec = strdup ("exec=");
+
+ if (name)
+ {
+ i = strlen (name) + 6;
+ mname = rc_xmalloc (sizeof (char *) * i);
+ snprintf (mname, i, "name=%s", name);
+ }
+ else
+ mname = strdup ("name=");
+
+ if (pidfile)
+ {
+ i = strlen (pidfile) + 9;
+ mpidfile = rc_xmalloc (sizeof (char *) * i);
+ snprintf (mpidfile, i, "pidfile=%s", pidfile);
+ }
+ else
+ mpidfile = strdup ("pidfile=");
+
+ /* Regardless, erase any existing daemon info */
+ if (rc_is_dir (dirpath))
+ {
+ char *oldfile = NULL;
+ files = rc_ls_dir (NULL, dirpath, 0);
+ STRLIST_FOREACH (files, file, i)
+ {
+ ffile = rc_strcatpaths (dirpath, file, NULL);
+ nfiles++;
+
+ if (! oldfile)
+ {
+ if (_match_daemon (dirpath, file, mexec, mname, mpidfile))
+ {
+ unlink (ffile);
+ oldfile = ffile;
+ nfiles--;
+ }
+ }
+ else
+ {
+ rename (ffile, oldfile);
+ free (oldfile);
+ oldfile = ffile;
+ }
+ }
+ if (ffile)
+ free (ffile);
+ free (files);
+ }
+
+ /* Now store our daemon info */
+ if (started)
+ {
+ char buffer[10];
+ FILE *fp;
+
+ if (! rc_is_dir (dirpath))
+ if (mkdir (dirpath, 0755) != 0)
+ eerror ("mkdir `%s': %s", dirpath, strerror (errno));
+
+ snprintf (buffer, sizeof (buffer), "%03d", nfiles + 1);
+ file = rc_strcatpaths (dirpath, buffer, NULL);
+ if ((fp = fopen (file, "w")) == NULL)
+ eerror ("fopen `%s': %s", file, strerror (errno));
+ else
+ {
+ fprintf (fp, "%s\n%s\n%s\n", mexec, mname, mpidfile);
+ fclose (fp);
+ }
+ free (file);
+ }
+
+ free (mexec);
+ free (mname);
+ free (mpidfile);
+ free (dirpath);
+}
+
+bool rc_service_started_daemon (const char *service, const char *exec,
+ int indx)
+{
+ char *dirpath;
+ char *file;
+ int i;
+ char *mexec;
+ bool retval = false;
+
+ if (! service || ! exec)
+ return (false);
+
+ dirpath = rc_strcatpaths (RC_SVCDIR, "daemons", basename (service), NULL);
+ if (! rc_is_dir (dirpath))
+ {
+ free (dirpath);
+ return (false);
+ }
+
+ i = strlen (exec) + 6;
+ mexec = rc_xmalloc (sizeof (char *) * i);
+ snprintf (mexec, i, "exec=%s", exec);
+
+ if (indx > 0)
+ {
+ file = rc_xmalloc (sizeof (char *) * 10);
+ snprintf (file, sizeof (file), "%03d", indx);
+ retval = _match_daemon (dirpath, file, mexec, NULL, NULL);
+ free (file);
+ }
+ else
+ {
+ char **files = rc_ls_dir (NULL, dirpath, 0);
+ STRLIST_FOREACH (files, file, i)
+ {
+ retval = _match_daemon (dirpath, file, mexec, NULL, NULL);
+ if (retval)
+ break;
+ }
+ free (files);
+ }
+
+ free (mexec);
+ return (retval);
+}
+
+bool rc_service_daemons_crashed (const char *service)
+{
+ char *dirpath;
+ char **files;
+ char *file;
+ char *path;
+ int i;
+ FILE *fp;
+ char buffer[RC_LINEBUFFER];
+ char *exec = NULL;
+ char *name = NULL;
+ char *pidfile = NULL;
+ pid_t pid = 0;
+ pid_t *pids = NULL;
+ char *p;
+ char *token;
+ bool retval = false;
+
+ if (! service)
+ return (false);
+
+ dirpath = rc_strcatpaths (RC_SVCDIR, "daemons", basename (service), NULL);
+ if (! rc_is_dir (dirpath))
+ {
+ free (dirpath);
+ return (false);
+ }
+
+ memset (buffer, 0, sizeof (buffer));
+ files = rc_ls_dir (NULL, dirpath, 0);
+ STRLIST_FOREACH (files, file, i)
+ {
+ path = rc_strcatpaths (dirpath, file, NULL);
+ fp = fopen (path, "r");
+ free (path);
+ if (! fp)
+ {
+ eerror ("fopen `%s': %s", file, strerror (errno));
+ continue;
+ }
+
+ while ((fgets (buffer, RC_LINEBUFFER, fp)))
+ {
+ int lb = strlen (buffer) - 1;
+ if (buffer[lb] == '\n')
+ buffer[lb] = 0;
+
+ p = buffer;
+ if ((token = strsep (&p, "=")) == NULL || ! p)
+ continue;
+
+ if (strlen (p) == 0)
+ continue;
+
+ if (strcmp (token, "exec") == 0)
+ {
+ if (exec)
+ free (exec);
+ exec = strdup (p);
+ }
+ else if (strcmp (token, "name") == 0)
+ {
+ if (name)
+ free (name);
+ name = strdup (p);
+ }
+ else if (strcmp (token, "pidfile") == 0)
+ {
+ if (pidfile)
+ free (pidfile);
+ pidfile = strdup (p);
+ }
+ }
+ fclose (fp);
+
+ pid = 0;
+ if (pidfile)
+ {
+ if (! rc_exists (pidfile))
+ {
+ retval = true;
+ break;
+ }
+
+ if ((fp = fopen (pidfile, "r")) == NULL)
+ {
+ eerror ("fopen `%s': %s", pidfile, strerror (errno));
+ retval = true;
+ break;
+ }
+
+ if (fscanf (fp, "%d", &pid) != 1)
+ {
+ eerror ("no pid found in `%s'", pidfile);
+ fclose (fp);
+ retval = true;
+ break;
+ }
+
+ fclose (fp);
+ free (pidfile);
+ pidfile = NULL;
+ }
+
+ if ((pids = rc_find_pids (exec, name, 0, pid)) == NULL)
+ {
+ retval = true;
+ break;
+ }
+ free (pids);
+
+ if (exec)
+ {
+ free (exec);
+ exec = NULL;
+ }
+ if (name)
+ {
+ free (name);
+ name = NULL;
+ }
+ }
+
+ if (exec)
+ {
+ free (exec);
+ exec = NULL;
+ }
+ if (name)
+ {
+ free (name);
+ name = NULL;
+ }
+
+ free (dirpath);
+ rc_strlist_free (files);
+
+ return (retval);
+}
diff --git a/src/librc-depend.c b/src/librc-depend.c
new file mode 100644
index 00000000..0da93aa5
--- /dev/null
+++ b/src/librc-depend.c
@@ -0,0 +1,838 @@
+/*
+ librc-depend
+ rc service dependency and ordering
+ Copyright 2006-2007 Gentoo Foundation
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "einfo.h"
+#include "rc.h"
+#include "rc-misc.h"
+#include "strlist.h"
+
+#define GENDEP RC_LIBDIR "/sh/gendepends.sh"
+
+/* We use this so we can pass our char array through many functions */
+struct lhead
+{
+ char **list;
+};
+
+static char *get_shell_value (char *string)
+{
+ char *p = string;
+ char *e;
+
+ if (! string)
+ return (NULL);
+
+ if (*p == '\'')
+ p++;
+
+ e = p + strlen (p) - 1;
+ if (*e == '\n')
+ *e-- = 0;
+ if (*e == '\'')
+ *e-- = 0;
+
+ if (*p != 0)
+ return p;
+
+ return (NULL);
+}
+
+void rc_free_deptree (rc_depinfo_t *deptree)
+{
+ rc_depinfo_t *di = deptree;
+ while (di)
+ {
+ rc_depinfo_t *dip = di->next;
+ rc_deptype_t *dt = di->depends;
+ free (di->service);
+ while (dt)
+ {
+ rc_deptype_t *dtp = dt->next;
+ free (dt->type);
+ rc_strlist_free (dt->services);
+ free (dt);
+ dt = dtp;
+ }
+ free (di);
+ di = dip;
+ }
+}
+
+rc_depinfo_t *rc_load_deptree (void)
+{
+ FILE *fp;
+ rc_depinfo_t *deptree = NULL;
+ rc_depinfo_t *depinfo = NULL;
+ rc_deptype_t *deptype = NULL;
+ char buffer [RC_LINEBUFFER];
+ char *type;
+ char *p;
+ char *e;
+ int i;
+
+ /* Update our deptree, but only if we need too */
+ rc_update_deptree (false);
+
+ if (! (fp = fopen (RC_DEPTREE, "r")))
+ return (NULL);
+
+ while (fgets (buffer, RC_LINEBUFFER, fp))
+ {
+ p = buffer;
+ e = strsep (&p, "_");
+ if (! e || strcmp (e, "depinfo") != 0)
+ continue;
+
+ e = strsep (&p, "_");
+ if (! e || sscanf (e, "%d", &i) != 1)
+ continue;
+
+ if (! (type = strsep (&p, "_=")))
+ continue;
+
+ if (strcmp (type, "service") == 0)
+ {
+ /* Sanity */
+ e = get_shell_value (p);
+ if (! e || strlen (e) == 0)
+ continue;
+
+ if (! deptree)
+ {
+ deptree = rc_xmalloc (sizeof (rc_depinfo_t));
+ depinfo = deptree;
+ }
+ else
+ {
+ depinfo->next = rc_xmalloc (sizeof (rc_depinfo_t));
+ depinfo = depinfo->next;
+ }
+ memset (depinfo, 0, sizeof (rc_depinfo_t));
+ depinfo->service = strdup (e);
+ deptype = NULL;
+ continue;
+ }
+
+ e = strsep (&p, "=");
+ if (! e || sscanf (e, "%d", &i) != 1)
+ continue;
+
+ /* Sanity */
+ e = get_shell_value (p);
+ if (! e || strlen (e) == 0)
+ continue;
+
+ if (! deptype)
+ {
+ depinfo->depends = rc_xmalloc (sizeof (rc_deptype_t));
+ deptype = depinfo->depends;
+ memset (deptype, 0, sizeof (rc_deptype_t));
+ }
+ else
+ if (strcmp (deptype->type, type) != 0)
+ {
+ deptype->next = rc_xmalloc (sizeof (rc_deptype_t));
+ deptype = deptype->next;
+ memset (deptype, 0, sizeof (rc_deptype_t));
+ }
+
+ if (! deptype->type)
+ deptype->type = strdup (type);
+
+ deptype->services = rc_strlist_addsort (deptype->services, e);
+ }
+ fclose (fp);
+
+ return (deptree);
+}
+
+rc_depinfo_t *rc_get_depinfo (rc_depinfo_t *deptree, const char *service)
+{
+ rc_depinfo_t *di;
+
+ if (! deptree || ! service)
+ return (NULL);
+
+ for (di = deptree; di; di = di->next)
+ if (strcmp (di->service, service) == 0)
+ return (di);
+
+ return (NULL);
+}
+
+rc_deptype_t *rc_get_deptype (rc_depinfo_t *depinfo, const char *type)
+{
+ rc_deptype_t *dt;
+
+ if (! depinfo || !type)
+ return (NULL);
+
+ for (dt = depinfo->depends; dt; dt = dt->next)
+ if (strcmp (dt->type, type) == 0)
+ return (dt);
+
+ return (NULL);
+}
+
+static bool valid_service (const char *runlevel, const char *service)
+{
+ return ((strcmp (runlevel, RC_LEVEL_BOOT) != 0 &&
+ rc_service_in_runlevel (service, RC_LEVEL_BOOT)) ||
+ rc_service_in_runlevel (service, runlevel) ||
+ rc_service_state (service, rc_service_coldplugged) ||
+ rc_service_state (service, rc_service_started));
+}
+
+static bool get_provided1 (const char *runlevel, struct lhead *providers,
+ rc_deptype_t *deptype,
+ const char *level, bool coldplugged,
+ bool started, bool inactive)
+{
+ char *service;
+ int i;
+ bool retval = false;
+
+ STRLIST_FOREACH (deptype->services, service, i)
+ {
+ bool ok = true;
+ if (level)
+ ok = rc_service_in_runlevel (service, level);
+ else if (coldplugged)
+ ok = (rc_service_state (service, rc_service_coldplugged) &&
+ ! rc_service_in_runlevel (service, runlevel) &&
+ ! rc_service_in_runlevel (service, RC_LEVEL_BOOT));
+
+ if (! ok)
+ continue;
+
+ if (started)
+ ok = (rc_service_state (service, rc_service_starting) ||
+ rc_service_state (service, rc_service_started) ||
+ rc_service_state (service, rc_service_stopping));
+ else if (inactive)
+ ok = rc_service_state (service, rc_service_inactive);
+
+ if (! ok)
+ continue;
+
+ retval = true;
+ providers->list = rc_strlist_add (providers->list, service);
+ }
+
+ return (retval);
+}
+
+/* Work out if a service is provided by another service.
+ For example metalog provides logger.
+ We need to be able to handle syslogd providing logger too.
+ We do this by checking whats running, then what's starting/stopping,
+ then what's run in the runlevels and finally alphabetical order.
+
+ If there are any bugs in rc-depend, they will probably be here as
+ provided dependancy can change depending on runlevel state.
+ */
+static char **get_provided (rc_depinfo_t *deptree, rc_depinfo_t *depinfo,
+ const char *runlevel, int options)
+{
+ rc_deptype_t *dt;
+ struct lhead providers;
+ char *service;
+ int i;
+
+ if (! deptree || ! depinfo)
+ return (NULL);
+ if (rc_service_exists (depinfo->service))
+ return (NULL);
+
+ dt = rc_get_deptype (depinfo, "providedby");
+ if (! dt)
+ return (NULL);
+
+ memset (&providers, 0, sizeof (struct lhead));
+ /* If we are stopping then all depends are true, regardless of state.
+ This is especially true for net services as they could force a restart
+ of the local dns resolver which may depend on net. */
+ if (options & RC_DEP_STOP)
+ {
+ STRLIST_FOREACH (dt->services, service, i)
+ providers.list = rc_strlist_add (providers.list, service);
+
+ return (providers.list);
+ }
+
+ /* If we're strict, then only use what we have in our runlevel */
+ if (options & RC_DEP_STRICT)
+ {
+ STRLIST_FOREACH (dt->services, service, i)
+ if (rc_service_in_runlevel (service, runlevel))
+ providers.list = rc_strlist_add (providers.list, service);
+
+ if (providers.list)
+ return (providers.list);
+ }
+
+ /* OK, we're not strict or there were no services in our runlevel.
+ This is now where the logic gets a little fuzzy :)
+ If there is >1 running service then we return NULL.
+ We do this so we don't hang around waiting for inactive services and
+ our need has already been satisfied as it's not strict.
+ We apply this to our runlevel, coldplugged services, then bootlevel
+ and finally any running.*/
+#define DO \
+ if (providers.list && providers.list[0] && providers.list[1]) \
+ { \
+ rc_strlist_free (providers.list); \
+ return (NULL); \
+ } \
+ else if (providers.list) \
+ return providers.list; \
+
+ /* Anything in the runlevel has to come first */
+ if (get_provided1 (runlevel, &providers, dt, runlevel, false, true, false))
+ { DO }
+ if (get_provided1 (runlevel, &providers, dt, runlevel, false, false, true))
+ { DO }
+ if (get_provided1 (runlevel, &providers, dt, runlevel, false, false, false))
+ return (providers.list);
+
+ /* Check coldplugged started services */
+ if (get_provided1 (runlevel, &providers, dt, NULL, true, true, false))
+ { DO }
+
+ /* Check bootlevel if we're not in it */
+ if (strcmp (runlevel, RC_LEVEL_BOOT) != 0)
+ {
+ if (get_provided1 (runlevel, &providers, dt, RC_LEVEL_BOOT, false, true, false))
+ { DO }
+ if (get_provided1 (runlevel, &providers, dt, RC_LEVEL_BOOT, false, false, true))
+ { DO }
+ }
+
+ /* Check coldplugged inactive services */
+ if (get_provided1 (runlevel, &providers, dt, NULL, true, false, true))
+ { DO }
+
+ /* Check manually started */
+ if (get_provided1 (runlevel, &providers, dt, NULL, false, true, false))
+ { DO }
+ if (get_provided1 (runlevel, &providers, dt, NULL, false, false, true))
+ { DO }
+
+ /* Nothing started then. OK, lets get the stopped services */
+ if (get_provided1 (runlevel, &providers, dt, NULL, true, false, false))
+ return (providers.list);
+ if ((strcmp (runlevel, RC_LEVEL_BOOT) != 0)
+ && (get_provided1 (runlevel, &providers, dt, RC_LEVEL_BOOT, false, false, false)))
+ return (providers.list);
+
+ /* Still nothing? OK, list all services */
+ STRLIST_FOREACH (dt->services, service, i)
+ providers.list = rc_strlist_add (providers.list, service);
+
+ return (providers.list);
+}
+
+static void visit_service (rc_depinfo_t *deptree, char **types,
+ struct lhead *sorted, struct lhead *visited,
+ rc_depinfo_t *depinfo,
+ const char *runlevel, int options)
+{
+ int i, j, k;
+ char *lp, *item;
+ char *service;
+ rc_depinfo_t *di;
+ rc_deptype_t *dt;
+ char **provides;
+ char *svcname;
+
+ if (! deptree || !sorted || !visited || !depinfo)
+ return;
+
+ /* Check if we have already visited this service or not */
+ STRLIST_FOREACH (visited->list, item, i)
+ if (strcmp (item, depinfo->service) == 0)
+ return;
+
+ /* Add ourselves as a visited service */
+ visited->list = rc_strlist_add (visited->list, depinfo->service);
+
+ STRLIST_FOREACH (types, item, i)
+ {
+ if ((dt = rc_get_deptype (depinfo, item)))
+ {
+ STRLIST_FOREACH (dt->services, service, j)
+ {
+ if (! options & RC_DEP_TRACE || strcmp (item, "iprovide") == 0)
+ {
+ sorted->list = rc_strlist_add (sorted->list, service);
+ continue;
+ }
+
+ di = rc_get_depinfo (deptree, service);
+ if ((provides = get_provided (deptree, di, runlevel, options)))
+ {
+ STRLIST_FOREACH (provides, lp, k)
+ {
+ di = rc_get_depinfo (deptree, lp);
+ if (di && (strcmp (item, "ineed") == 0 ||
+ valid_service (runlevel, di->service)))
+ visit_service (deptree, types, sorted, visited, di,
+ runlevel, options | RC_DEP_TRACE);
+ }
+ rc_strlist_free (provides);
+ }
+ else
+ if (di && (strcmp (item, "ineed") == 0 ||
+ valid_service (runlevel, service)))
+ visit_service (deptree, types, sorted, visited, di,
+ runlevel, options | RC_DEP_TRACE);
+ }
+ }
+ }
+
+ /* Now visit the stuff we provide for */
+ if (options & RC_DEP_TRACE && (dt = rc_get_deptype (depinfo, "iprovide")))
+ {
+ STRLIST_FOREACH (dt->services, service, i)
+ {
+ if ((di = rc_get_depinfo (deptree, service)))
+ if ((provides = get_provided (deptree, di, runlevel, options)))
+ {
+ STRLIST_FOREACH (provides, lp, j)
+ if (strcmp (lp, depinfo->service) == 0)
+ {
+ visit_service (deptree, types, sorted, visited, di,
+ runlevel, options | RC_DEP_TRACE);
+ break;
+ }
+ rc_strlist_free (provides);
+ }
+ }
+ }
+
+ /* We've visited everything we need, so add ourselves unless we
+ are also the service calling us or we are provided by something */
+ svcname = getenv("SVCNAME");
+ if (! svcname || strcmp (svcname, depinfo->service) != 0)
+ if (! rc_get_deptype (depinfo, "providedby"))
+ sorted->list = rc_strlist_add (sorted->list, depinfo->service);
+}
+
+char **rc_get_depends (rc_depinfo_t *deptree,
+ char **types, char **services,
+ const char *runlevel, int options)
+{
+ struct lhead sorted;
+ struct lhead visited;
+ rc_depinfo_t *di;
+ char *service;
+ int i;
+
+ if (! deptree || ! types || ! services)
+ return (NULL);
+
+ memset (&sorted, 0, sizeof (struct lhead));
+ memset (&visited, 0, sizeof (struct lhead));
+
+ STRLIST_FOREACH (services, service, i)
+ {
+ di = rc_get_depinfo (deptree, service);
+ visit_service (deptree, types, &sorted, &visited, di, runlevel, options);
+ }
+
+ rc_strlist_free (visited.list);
+ return (sorted.list);
+}
+
+char **rc_order_services (rc_depinfo_t *deptree, const char *runlevel,
+ int options)
+{
+ char **list = NULL;
+ char **types = NULL;
+ char **services = NULL;
+ bool reverse = false;
+
+ if (! runlevel)
+ return (NULL);
+
+ /* When shutting down, list all running services */
+ if (strcmp (runlevel, RC_LEVEL_SINGLE) == 0 ||
+ strcmp (runlevel, RC_LEVEL_SHUTDOWN) == 0 ||
+ strcmp (runlevel, RC_LEVEL_REBOOT) == 0)
+ {
+ list = rc_ls_dir (list, RC_SVCDIR_STARTING, RC_LS_INITD);
+ list = rc_ls_dir (list, RC_SVCDIR_INACTIVE, RC_LS_INITD);
+ list = rc_ls_dir (list, RC_SVCDIR_STARTED, RC_LS_INITD);
+ reverse = true;
+ }
+ else
+ {
+ list = rc_services_in_runlevel (runlevel);
+
+ /* Add coldplugged services */
+ list = rc_ls_dir (list, RC_SVCDIR_COLDPLUGGED, RC_LS_INITD);
+
+ /* If we're not the boot runlevel then add that too */
+ if (strcmp (runlevel, RC_LEVEL_BOOT) != 0)
+ {
+ char *path = rc_strcatpaths (RC_RUNLEVELDIR, RC_LEVEL_BOOT, NULL);
+ list = rc_ls_dir (list, path, RC_LS_INITD);
+ free (path);
+ }
+ }
+
+ /* Now we have our lists, we need to pull in any dependencies
+ and order them */
+ types = rc_strlist_add (NULL, "ineed");
+ types = rc_strlist_add (types, "iuse");
+ types = rc_strlist_add (types, "iafter");
+ services = rc_get_depends (deptree, types, list, runlevel,
+ RC_DEP_STRICT | RC_DEP_TRACE | options);
+ rc_strlist_free (list);
+ rc_strlist_free (types);
+
+ if (reverse)
+ rc_strlist_reverse (services);
+
+ return (services);
+}
+
+static bool is_newer_than (const char *file, const char *target)
+{
+ struct stat buf;
+ int mtime;
+
+ if (stat (file, &buf) != 0 || buf.st_size == 0)
+ return (false);
+ mtime = buf.st_mtime;
+
+ if (stat (target, &buf) != 0)
+ return (false);
+
+ if (mtime < buf.st_mtime)
+ return (false);
+
+ if (rc_is_dir (target))
+ {
+ char **targets = rc_ls_dir (NULL, target, 0);
+ char *t;
+ int i;
+ bool newer = true;
+ STRLIST_FOREACH (targets, t, i)
+ {
+ char *path = rc_strcatpaths (target, t, NULL);
+ newer = is_newer_than (file, path);
+ free (path);
+ if (! newer)
+ break;
+ }
+ rc_strlist_free (targets);
+ return (newer);
+ }
+
+ return (true);
+}
+
+typedef struct deppair
+{
+ const char *depend;
+ const char *addto;
+} deppair_t;
+
+static const deppair_t deppairs[] = {
+ { "ineed", "needsme" },
+ { "iuse", "usesme" },
+ { "iafter", "ibefore" },
+ { "ibefore", "iafter" },
+ { "iprovide", "providedby" },
+ { NULL, NULL }
+};
+
+static const char *depdirs[] =
+{
+ RC_SVCDIR "starting",
+ RC_SVCDIR "started",
+ RC_SVCDIR "stopping",
+ RC_SVCDIR "inactive",
+ RC_SVCDIR "wasinactive",
+ RC_SVCDIR "failed",
+ RC_SVCDIR "coldplugged",
+ RC_SVCDIR "daemons",
+ RC_SVCDIR "options",
+ RC_SVCDIR "exclusive",
+ RC_SVCDIR "scheduled",
+ RC_SVCDIR "ebuffer",
+ NULL
+};
+
+/* This is a 5 phase operation
+ Phase 1 is a shell script which loads each init script and config in turn
+ and echos their dependency info to stdout
+ Phase 2 takes that and populates a depinfo object with that data
+ Phase 3 adds any provided services to the depinfo object
+ Phase 4 scans that depinfo object and puts in backlinks
+ Phase 5 saves the depinfo object to disk
+ */
+int rc_update_deptree (bool force)
+{
+ char *depends;
+ char *service;
+ char *type;
+ char *depend;
+ int retval = 0;
+ FILE *fp;
+ rc_depinfo_t *deptree;
+ rc_depinfo_t *depinfo;
+ rc_depinfo_t *di;
+ rc_depinfo_t *last_depinfo = NULL;
+ rc_deptype_t *deptype;
+ rc_deptype_t *dt;
+ rc_deptype_t *last_deptype = NULL;
+ char buffer[RC_LINEBUFFER];
+ int len;
+ int i;
+ int j;
+ int k;
+ bool already_added;
+
+ /* Create base directories if needed */
+ for (i = 0; depdirs[i]; i++)
+ if (! rc_is_dir (depdirs[i]))
+ if (mkdir (depdirs[i], 0755) != 0)
+ eerrorx ("mkdir `%s': %s", depdirs[i], strerror (errno));
+
+ if (! force)
+ if (is_newer_than (RC_DEPTREE, RC_INITDIR) &&
+ is_newer_than (RC_DEPTREE, RC_CONFDIR) &&
+ is_newer_than (RC_DEPTREE, "/etc/rc.conf"))
+ return 0;
+
+ ebegin ("Caching service dependencies");
+
+ /* Some init scripts need RC_LIBDIR to source stuff
+ Ideally we should be setting our full env instead */
+ if (! getenv ("RC_LIBDIR"))
+ setenv ("RC_LIBDIR", RC_LIBDIR, 0);
+
+ /* Phase 1 */
+ if ((fp = popen (GENDEP, "r")) == NULL)
+ eerrorx ("popen: %s", strerror (errno));
+
+ deptree = rc_xmalloc (sizeof (rc_depinfo_t));
+ memset (deptree, 0, sizeof (rc_depinfo_t));
+ memset (buffer, 0, RC_LINEBUFFER);
+
+ /* Phase 2 */
+ while (fgets (buffer, RC_LINEBUFFER, fp))
+ {
+ /* Trim the newline */
+ if (buffer[strlen (buffer) - 1] == '\n')
+ buffer[strlen(buffer) -1] = 0;
+
+ depends = buffer;
+ service = strsep (&depends, " ");
+ if (! service)
+ continue;
+ type = strsep (&depends, " ");
+
+ for (depinfo = deptree; depinfo; depinfo = depinfo->next)
+ {
+ last_depinfo = depinfo;
+ if (depinfo->service && strcmp (depinfo->service, service) == 0)
+ break;
+ }
+
+ if (! depinfo)
+ {
+ if (! last_depinfo->service)
+ depinfo = last_depinfo;
+ else
+ {
+ last_depinfo->next = rc_xmalloc (sizeof (rc_depinfo_t));
+ depinfo = last_depinfo->next;
+ }
+ memset (depinfo, 0, sizeof (rc_depinfo_t));
+ depinfo->service = strdup (service);
+ }
+
+ /* We may not have any depends */
+ if (! type || ! depends)
+ continue;
+
+ last_deptype = NULL;
+ for (deptype = depinfo->depends; deptype; deptype = deptype->next)
+ {
+ last_deptype = deptype;
+ if (strcmp (deptype->type, type) == 0)
+ break;
+ }
+
+ if (! deptype)
+ {
+ if (! last_deptype)
+ {
+ depinfo->depends = rc_xmalloc (sizeof (rc_deptype_t));
+ deptype = depinfo->depends;
+ }
+ else
+ {
+ last_deptype->next = rc_xmalloc (sizeof (rc_deptype_t));
+ deptype = last_deptype->next;
+ }
+ memset (deptype, 0, sizeof (rc_deptype_t));
+ deptype->type = strdup (type);
+ }
+
+ /* Now add each depend to our type.
+ We do this individually so we handle multiple spaces gracefully */
+ while ((depend = strsep (&depends, " ")))
+ {
+ if (depend[0] == 0)
+ continue;
+
+ /* .sh files are not init scripts */
+ len = strlen (depend);
+ if (len > 2 &&
+ depend[len - 3] == '.' &&
+ depend[len - 2] == 's' &&
+ depend[len - 1] == 'h')
+ continue;
+
+ deptype->services = rc_strlist_addsort (deptype->services, depend);
+ }
+
+ }
+ pclose (fp);
+
+ /* Phase 3 - add our providors to the tree */
+ for (depinfo = deptree; depinfo; depinfo = depinfo->next)
+ {
+ if ((deptype = rc_get_deptype (depinfo, "iprovide")))
+ STRLIST_FOREACH (deptype->services, service, i)
+ {
+ for (di = deptree; di; di = di->next)
+ {
+ last_depinfo = di;
+ if (strcmp (di->service, service) == 0)
+ break;
+ }
+ if (! di)
+ {
+ last_depinfo->next = rc_xmalloc (sizeof (rc_depinfo_t));
+ di = last_depinfo->next;
+ memset (di, 0, sizeof (rc_depinfo_t));
+ di->service = strdup (service);
+ }
+ }
+ }
+
+ /* Phase 4 - backreference our depends */
+ for (depinfo = deptree; depinfo; depinfo = depinfo->next)
+ {
+ for (i = 0; deppairs[i].depend; i++)
+ {
+ deptype = rc_get_deptype (depinfo, deppairs[i].depend);
+ if (! deptype)
+ continue;
+
+ STRLIST_FOREACH (deptype->services, service, j)
+ {
+ di = rc_get_depinfo (deptree, service);
+ if (! di)
+ {
+ if (strcmp (deptype->type, "ineed") == 0)
+ {
+ eerror ("Service `%s' needs non existant service `%s'",
+ depinfo->service, service);
+ retval = -1;
+ }
+ continue;
+ }
+
+ /* Add our deptype now */
+ last_deptype = NULL;
+ for (dt = di->depends; dt; dt = dt->next)
+ {
+ last_deptype = dt;
+ if (strcmp (dt->type, deppairs[i].addto) == 0)
+ break;
+ }
+ if (! dt)
+ {
+ if (! last_deptype)
+ {
+ di->depends = rc_xmalloc (sizeof (rc_deptype_t));
+ dt = di->depends;
+ }
+ else
+ {
+ last_deptype->next = rc_xmalloc (sizeof (rc_deptype_t));
+ dt = last_deptype->next;
+ }
+ memset (dt, 0, sizeof (rc_deptype_t));
+ dt->type = strdup (deppairs[i].addto);
+ }
+
+ already_added = false;
+ STRLIST_FOREACH (dt->services, service, k)
+ if (strcmp (service, depinfo->service) == 0)
+ {
+ already_added = true;
+ break;
+ }
+
+ if (! already_added)
+ dt->services = rc_strlist_addsort (dt->services,
+ depinfo->service);
+ }
+ }
+ }
+
+ /* Phase 5 - save to disk
+ Now that we're purely in C, do we need to keep a shell parseable file?
+ I think yes as then it stays human readable
+ This works and should be entirely shell parseable provided that depend
+ names don't have any non shell variable characters in
+ */
+ if ((fp = fopen (RC_DEPTREE, "w")) == NULL)
+ eerror ("fopen `%s': %s", RC_DEPTREE, strerror (errno));
+ else
+ {
+ i = 0;
+ for (depinfo = deptree; depinfo; depinfo = depinfo->next)
+ {
+ fprintf (fp, "depinfo_%d_service='%s'\n", i, depinfo->service);
+ for (deptype = depinfo->depends; deptype; deptype = deptype->next)
+ {
+ k = 0;
+ STRLIST_FOREACH (deptype->services, service, j)
+ {
+ fprintf (fp, "depinfo_%d_%s_%d='%s'\n", i, deptype->type,
+ k, service);
+ k++;
+ }
+ }
+ i++;
+ }
+ fclose (fp);
+ }
+
+ rc_free_deptree (deptree);
+
+ eend (retval, "Failed to update the service dependency tree");
+ return (retval);
+}
diff --git a/src/librc-misc.c b/src/librc-misc.c
new file mode 100644
index 00000000..604c5518
--- /dev/null
+++ b/src/librc-misc.c
@@ -0,0 +1,750 @@
+/*
+ rc-misc.c
+ rc misc functions
+ Copyright 2007 Gentoo Foundation
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/utsname.h>
+
+#include <dirent.h>
+#include <errno.h>
+#include <limits.h>
+#include <regex.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "einfo.h"
+#include "rc-misc.h"
+#include "rc.h"
+#include "strlist.h"
+
+#define ERRX eerrorx("out of memory");
+
+#define PROFILE_ENV "/etc/profile.env"
+#define SYS_WHITELIST RC_LIBDIR "conf.d/env_whitelist"
+#define USR_WHITELIST "/etc/conf.d/env_whitelist"
+#define RC_CONFIG "/etc/conf.d/rc"
+
+#define PATH_PREFIX RC_LIBDIR "bin:/bin:/sbin:/usr/bin:/usr/sbin"
+
+#ifndef S_IXUGO
+# define S_IXUGO (S_IXUSR | S_IXGRP | S_IXOTH)
+#endif
+
+void *rc_xcalloc (size_t n, size_t size)
+{
+ void *value = calloc (n, size);
+
+ if (value)
+ return value;
+
+ ERRX
+}
+
+void *rc_xmalloc (size_t size)
+{
+ void *value = malloc (size);
+
+ if (value)
+ return (value);
+
+ ERRX
+}
+
+void *rc_xrealloc (void *ptr, size_t size)
+{
+ void *value = realloc (ptr, size);
+
+ if (value)
+ return (value);
+
+ ERRX
+}
+
+
+char *rc_xstrdup (const char *str)
+{
+ char *value;
+
+ if (! str)
+ return (NULL);
+
+ value = strdup (str);
+
+ if (value)
+ return (value);
+
+ ERRX
+}
+
+bool rc_is_env (const char *var, const char *val)
+{
+ char *v;
+
+ if (! var)
+ return (false);
+
+ v = getenv (var);
+ if (! v)
+ return (val == NULL ? true : false);
+
+ return (strcasecmp (v, val) == 0 ? true : false);
+}
+
+char *rc_strcatpaths (const char *path1, const char *paths, ...)
+{
+ va_list ap;
+ int length;
+ int i;
+ char *p;
+ char *path;
+ char *pathp;
+
+ if (! path1 || ! paths)
+ return (NULL);
+
+ length = strlen (path1) + strlen (paths) + 3;
+ i = 0;
+ va_start (ap, paths);
+ while ((p = va_arg (ap, char *)) != NULL)
+ length += strlen (p) + 1;
+ va_end (ap);
+
+ path = rc_xmalloc (length);
+ memset (path, 0, length);
+ memcpy (path, path1, strlen (path1));
+ pathp = path + strlen (path1) - 1;
+ if (*pathp != '/')
+ {
+ pathp++;
+ *pathp++ = '/';
+ }
+ else
+ pathp++;
+ memcpy (pathp, paths, strlen (paths));
+ pathp += strlen (paths);
+
+ va_start (ap, paths);
+ while ((p = va_arg (ap, char *)) != NULL)
+ {
+ if (*pathp != '/')
+ *pathp++ = '/';
+ i = strlen (p);
+ memcpy (pathp, p, i);
+ pathp += i;
+ }
+ va_end (ap);
+
+ *pathp++ = 0;
+
+ return (path);
+}
+
+bool rc_exists (const char *pathname)
+{
+ struct stat buf;
+
+ if (! pathname)
+ return (false);
+
+ if (stat (pathname, &buf) == 0)
+ return (true);
+
+ errno = 0;
+ return (false);
+}
+
+bool rc_is_file (const char *pathname)
+{
+ struct stat buf;
+
+ if (! pathname)
+ return (false);
+
+ if (stat (pathname, &buf) == 0)
+ return (S_ISREG (buf.st_mode));
+
+ errno = 0;
+ return (false);
+}
+
+bool rc_is_dir (const char *pathname)
+{
+ struct stat buf;
+
+ if (! pathname)
+ return (false);
+
+ if (stat (pathname, &buf) == 0)
+ return (S_ISDIR (buf.st_mode));
+
+ errno = 0;
+ return (false);
+}
+
+bool rc_is_link (const char *pathname)
+{
+ struct stat buf;
+
+ if (! pathname)
+ return (false);
+
+ if (lstat (pathname, &buf) == 0)
+ return (S_ISLNK (buf.st_mode));
+
+ errno = 0;
+ return (false);
+}
+
+bool rc_is_exec (const char *pathname)
+{
+ struct stat buf;
+
+ if (! pathname)
+ return (false);
+
+ if (lstat (pathname, &buf) == 0)
+ return (buf.st_mode & S_IXUGO);
+
+ errno = 0;
+ return (false);
+}
+
+char **rc_ls_dir (char **list, const char *dir, int options)
+{
+ DIR *dp;
+ struct dirent *d;
+
+ if (! dir)
+ return (list);
+
+ if ((dp = opendir (dir)) == NULL)
+ {
+ eerror ("failed to opendir `%s': %s", dir, strerror (errno));
+ return (list);
+ }
+
+ errno = 0;
+ while (((d = readdir (dp)) != NULL) && errno == 0)
+ {
+ if (d->d_name[0] != '.')
+ {
+ if (options & RC_LS_INITD)
+ {
+ int l = strlen (d->d_name);
+ char *init = rc_strcatpaths (RC_INITDIR, d->d_name, NULL);
+ bool ok = rc_exists (init);
+ free (init);
+ if (! ok)
+ continue;
+
+ /* .sh files are not init scripts */
+ if (l > 2 && d->d_name[l - 3] == '.' &&
+ d->d_name[l - 2] == 's' &&
+ d->d_name[l - 1] == 'h')
+ continue;
+ }
+ list = rc_strlist_addsort (list, d->d_name);
+ }
+ }
+ closedir (dp);
+
+ if (errno != 0)
+ {
+ eerror ("failed to readdir `%s': %s", dir, strerror (errno));
+ rc_strlist_free (list);
+ return (NULL);
+ }
+
+ return (list);
+}
+
+bool rc_rm_dir (const char *pathname, bool top)
+{
+ DIR *dp;
+ struct dirent *d;
+
+ if (! pathname)
+ return (false);
+
+ if ((dp = opendir (pathname)) == NULL)
+ {
+ eerror ("failed to opendir `%s': %s", pathname, strerror (errno));
+ return (false);
+ }
+
+ errno = 0;
+ while (((d = readdir (dp)) != NULL) && errno == 0)
+ {
+ if (strcmp (d->d_name, ".") != 0 && strcmp (d->d_name, "..") != 0)
+ {
+ char *tmp = rc_strcatpaths (pathname, d->d_name, NULL);
+ if (d->d_type == DT_DIR)
+ {
+ if (! rc_rm_dir (tmp, true))
+ {
+ free (tmp);
+ closedir (dp);
+ return (false);
+ }
+ }
+ else
+ {
+ if (unlink (tmp))
+ {
+ eerror ("failed to unlink `%s': %s", tmp, strerror (errno));
+ free (tmp);
+ closedir (dp);
+ return (false);
+ }
+ }
+ free (tmp);
+ }
+ }
+ if (errno != 0)
+ eerror ("failed to readdir `%s': %s", pathname, strerror (errno));
+ closedir (dp);
+
+ if (top && rmdir (pathname) != 0)
+ {
+ eerror ("failed to rmdir `%s': %s", pathname, strerror (errno));
+ return false;
+ }
+
+ return (true);
+}
+
+char **rc_get_config (char **list, const char *file)
+{
+ FILE *fp;
+ char buffer[RC_LINEBUFFER];
+ char *p;
+ char *token;
+ char *line;
+ char *linep;
+ char *linetok;
+ int i = 0;
+ bool replaced;
+ char *entry;
+ char *newline;
+
+ if (! (fp = fopen (file, "r")))
+ {
+ ewarn ("load_config_file `%s': %s", file, strerror (errno));
+ return (list);
+ }
+
+ while (fgets (buffer, RC_LINEBUFFER, fp))
+ {
+ p = buffer;
+
+ /* Strip leading spaces/tabs */
+ while ((*p == ' ') || (*p == '\t'))
+ p++;
+
+ if (! p || strlen (p) < 3 || p[0] == '#')
+ continue;
+
+ /* Get entry */
+ token = strsep (&p, "=");
+ if (! token)
+ continue;
+
+ entry = rc_xstrdup (token);
+
+ do
+ {
+ /* Bash variables are usually quoted */
+ token = strsep (&p, "\"\'");
+ }
+ while ((token) && (strlen (token) == 0));
+
+ /* Drop a newline if that's all we have */
+ i = strlen (token) - 1;
+ if (token[i] == 10)
+ token[i] = 0;
+
+ i = strlen (entry) + strlen (token) + 2;
+ newline = rc_xmalloc (i);
+ snprintf (newline, i, "%s=%s", entry, token);
+
+ replaced = false;
+ /* In shells the last item takes precedence, so we need to remove
+ any prior values we may already have */
+ STRLIST_FOREACH (list, line, i)
+ {
+ char *tmp = rc_xstrdup (line);
+ linep = tmp;
+ linetok = strsep (&linep, "=");
+ if (strcmp (linetok, entry) == 0)
+ {
+ /* We have a match now - to save time we directly replace it */
+ free (list[i - 1]);
+ list[i - 1] = newline;
+ replaced = true;
+ free (tmp);
+ break;
+ }
+ free (tmp);
+ }
+
+ if (! replaced)
+ {
+ list = rc_strlist_addsort (list, newline);
+ free (newline);
+ }
+ free (entry);
+ }
+ fclose (fp);
+
+ return (list);
+}
+
+char *rc_get_config_entry (char **list, const char *entry)
+{
+ char *line;
+ int i;
+ char *p;
+
+ STRLIST_FOREACH (list, line, i)
+ {
+ p = strchr (line, '=');
+ if (p && strncmp (entry, line, p - line) == 0)
+ return (p += 1);
+ }
+
+ return (NULL);
+}
+
+char **rc_get_list (char **list, const char *file)
+{
+ FILE *fp;
+ char buffer[RC_LINEBUFFER];
+ char *p;
+ char *token;
+
+ if (! (fp = fopen (file, "r")))
+ {
+ ewarn ("rc_get_list `%s': %s", file, strerror (errno));
+ return (list);
+ }
+
+ while (fgets (buffer, RC_LINEBUFFER, fp))
+ {
+ p = buffer;
+
+ /* Strip leading spaces/tabs */
+ while ((*p == ' ') || (*p == '\t'))
+ p++;
+
+ /* Get entry - we do not want comments */
+ token = strsep (&p, "#");
+ if (token && (strlen (token) > 1))
+ {
+ token[strlen (token) - 1] = 0;
+ list = rc_strlist_add (list, token);
+ }
+ }
+ fclose (fp);
+
+ return (list);
+}
+
+char **rc_filter_env (void)
+{
+ char **env = NULL;
+ char **whitelist = NULL;
+ char *env_name = NULL;
+ char **profile = NULL;
+ int count = 0;
+ bool got_path = false;
+ char *env_var;
+ int env_len;
+ char *p;
+ char *token;
+ char *sep;
+ char *e;
+ int pplen = strlen (PATH_PREFIX);
+
+ whitelist = rc_get_list (whitelist, SYS_WHITELIST);
+ if (! whitelist)
+ ewarn ("system environment whitelist (" SYS_WHITELIST ") missing");
+
+ whitelist = rc_get_list (whitelist, USR_WHITELIST);
+
+ if (! whitelist)
+ return (NULL);
+
+ if (rc_is_file (PROFILE_ENV))
+ profile = rc_get_config (profile, PROFILE_ENV);
+
+ STRLIST_FOREACH (whitelist, env_name, count)
+ {
+ char *space = strchr (env_name, ' ');
+ if (space)
+ *space = 0;
+
+ env_var = getenv (env_name);
+
+ if (! env_var && profile)
+ {
+ env_len = strlen (env_name) + strlen ("export ") + 1;
+ p = rc_xmalloc (sizeof (char *) * env_len);
+ snprintf (p, env_len, "export %s", env_name);
+ env_var = rc_get_config_entry (profile, p);
+ free (p);
+ }
+
+ if (! env_var)
+ continue;
+
+ /* Ensure our PATH is prefixed with the system locations first
+ for a little extra security */
+ if (strcmp (env_name, "PATH") == 0 &&
+ strncmp (PATH_PREFIX, env_var, pplen) != 0)
+ {
+ got_path = true;
+ env_len = strlen (env_name) + strlen (env_var) + pplen + 2;
+ e = p = rc_xmalloc (sizeof (char *) * env_len);
+ p += sprintf (e, "%s=%s", env_name, PATH_PREFIX);
+
+ /* Now go through the env var and only add bits not in our PREFIX */
+ sep = env_var;
+ while ((token = strsep (&sep, ":")))
+ {
+ char *np = strdup (PATH_PREFIX);
+ char *npp = np;
+ char *tok = NULL;
+ while ((tok = strsep (&npp, ":")))
+ if (strcmp (tok, token) == 0)
+ break;
+ if (! tok)
+ p += sprintf (p, ":%s", token);
+ free (np);
+ }
+ *p++ = 0;
+ }
+ else
+ {
+ env_len = strlen (env_name) + strlen (env_var) + 2;
+ e = rc_xmalloc (sizeof (char *) * env_len);
+ snprintf (e, env_len, "%s=%s", env_name, env_var);
+ }
+
+ env = rc_strlist_add (env, e);
+ free (e);
+ }
+
+ /* We filtered the env but didn't get a PATH? Very odd.
+ However, we do need a path, so use a default. */
+ if (! got_path)
+ {
+ env_len = strlen ("PATH=") + strlen (PATH_PREFIX) + 2;
+ p = rc_xmalloc (sizeof (char *) * env_len);
+ snprintf (p, env_len, "PATH=%s", PATH_PREFIX);
+ env = rc_strlist_add (env, p);
+ free (p);
+ }
+
+ rc_strlist_free (whitelist);
+ rc_strlist_free (profile);
+
+ return (env);
+}
+
+/* Other systems may need this at some point, but for now it's Linux only */
+#ifdef __linux__
+static bool file_regex (const char *file, const char *regex)
+{
+ FILE *fp;
+ char buffer[RC_LINEBUFFER];
+ regex_t re;
+ bool retval = false;
+ int result;
+
+ if (! rc_exists (file))
+ return (false);
+
+ if (! (fp = fopen (file, "r")))
+ {
+ ewarn ("file_regex `%s': %s", file, strerror (errno));
+ return (false);
+ }
+
+ if ((result = regcomp (&re, regex, REG_EXTENDED | REG_NOSUB)) != 0)
+ {
+ fclose (fp);
+ regerror (result, &re, buffer, sizeof (buffer));
+ eerror ("file_regex: %s", buffer);
+ return (false);
+ }
+
+ while (fgets (buffer, RC_LINEBUFFER, fp))
+ {
+ if (regexec (&re, buffer, 0, NULL, 0) == 0)
+ {
+ retval = true;
+ break;
+ }
+ }
+ fclose (fp);
+ regfree (&re);
+
+ return (retval);
+}
+#endif
+
+char **rc_config_env (char **env)
+{
+ char *line;
+ int i;
+ char *p;
+ char **config = rc_get_config (NULL, RC_CONFIG);
+ char *e;
+ char sys[6];
+ struct utsname uts;
+ bool has_net_fs_list = false;
+ FILE *fp;
+ char buffer[PATH_MAX];
+
+ STRLIST_FOREACH (config, line, i)
+ {
+ p = strchr (line, '=');
+ if (! p)
+ continue;
+
+ *p = 0;
+ e = getenv (line);
+ if (! e)
+ {
+ *p = '=';
+ env = rc_strlist_add (env, line);
+ }
+ else
+ {
+ int len = strlen (line) + strlen (e) + 2;
+ char *new = rc_xmalloc (sizeof (char *) * len);
+ snprintf (new, len, "%s=%s", line, e);
+ env = rc_strlist_add (env, new);
+ free (new);
+ }
+ }
+ rc_strlist_free (config);
+
+ i = strlen ("RC_LIBDIR=//rcscripts") + strlen (LIBDIR) + 2;
+ line = rc_xmalloc (sizeof (char *) * i);
+ snprintf (line, i, "RC_LIBDIR=/" LIBDIR "/rcscripts");
+ env = rc_strlist_add (env, line);
+ free (line);
+
+ i += strlen ("/init.d");
+ line = rc_xmalloc (sizeof (char *) * i);
+ snprintf (line, i, "RC_SVCDIR=/" LIBDIR "/rcscripts/init.d");
+ env = rc_strlist_add (env, line);
+ free (line);
+
+ env = rc_strlist_add (env, "RC_BOOTLEVEL=" RC_LEVEL_BOOT);
+
+ p = rc_get_runlevel ();
+ i = strlen ("RC_SOFTLEVEL=") + strlen (p) + 1;
+ line = rc_xmalloc (sizeof (char *) * i);
+ snprintf (line, i, "RC_SOFTLEVEL=%s", p);
+ env = rc_strlist_add (env, line);
+ free (line);
+
+ if (rc_exists (RC_SVCDIR "ksoftlevel"))
+ {
+ if (! (fp = fopen (RC_SVCDIR "ksoftlevel", "r")))
+ eerror ("fopen `%s': %s", RC_SVCDIR "ksoftlevel",
+ strerror (errno));
+ else
+ {
+ memset (buffer, 0, sizeof (buffer));
+ if (fgets (buffer, sizeof (buffer), fp))
+ {
+ i = strlen (buffer) - 1;
+ if (buffer[i] == '\n')
+ buffer[i] = 0;
+ i += strlen ("RC_DEFAULTLEVEL=") + 2;
+ line = rc_xmalloc (sizeof (char *) * i);
+ snprintf (line, i, "RC_DEFAULTLEVEL=%s", buffer);
+ env = rc_strlist_add (env, line);
+ free (line);
+ }
+ fclose (fp);
+ }
+ }
+ else
+ env = rc_strlist_add (env, "RC_DEFAULTLEVEL=" RC_LEVEL_DEFAULT);
+
+ memset (sys, 0, sizeof (sys));
+
+/* Linux can run some funky stuff like Xen, VServer, UML, etc
+ We store this special system in RC_SYS so our scripts run fast */
+#ifdef __linux__
+ if (rc_is_dir ("/proc/xen"))
+ {
+ fp = fopen ("/proc/xen/capabilities", "r");
+ if (fp)
+ {
+ fclose (fp);
+ if (file_regex ("/proc/xen/capabilities", "control_d"))
+ sprintf (sys, "XENU");
+ }
+ if (! sys)
+ sprintf (sys, "XEN0");
+ }
+ else if (file_regex ("/proc/cpuinfo", "UML"))
+ sprintf (sys, "UML");
+ else if (file_regex ("/proc/self/status",
+ "(s_context|VxID|envID):[[:space:]]*[1-9]"))
+ sprintf(sys, "VPS");
+#endif
+
+ /* Only add a NET_FS list if not defined */
+ STRLIST_FOREACH (env, line, i)
+ if (strncmp (line, "RC_NET_FS_LIST=", strlen ("RC_NET_FS_LIST=")) == 0)
+ {
+ has_net_fs_list = true;
+ break;
+ }
+ if (! has_net_fs_list)
+ {
+ i = strlen ("RC_NET_FS_LIST=") + strlen (RC_NET_FS_LIST_DEFAULT) + 1;
+ line = rc_xmalloc (sizeof (char *) * i);
+ snprintf (line, i, "RC_NET_FS_LIST=%s", RC_NET_FS_LIST_DEFAULT);
+ env = rc_strlist_add (env, line);
+ free (line);
+ }
+
+ if (sys[0])
+ {
+ i = strlen ("RC_SYS=") + strlen (sys) + 2;
+ line = rc_xmalloc (sizeof (char *) * i);
+ snprintf (line, i, "RC_SYS=%s", sys);
+ env = rc_strlist_add (env, line);
+ free (line);
+ }
+
+ /* Some scripts may need to take a different code path if Linux/FreeBSD, etc
+ To save on calling uname, we store it in an environment variable */
+ if (uname (&uts) == 0)
+ {
+ i = strlen ("RC_UNAME=") + strlen (uts.sysname) + 2;
+ line = rc_xmalloc (sizeof (char *) * i);
+ snprintf (line, i, "RC_UNAME=%s", uts.sysname);
+ env = rc_strlist_add (env, line);
+ free (line);
+ }
+
+ /* Set this var to ensure that things are POSIX, which makes scripts work
+ on non GNU systems with less effort. */
+ env = rc_strlist_add (env, "POSIXLY_CORRECT=1");
+
+ return (env);
+}
diff --git a/src/librc-strlist.c b/src/librc-strlist.c
new file mode 100644
index 00000000..981f654b
--- /dev/null
+++ b/src/librc-strlist.c
@@ -0,0 +1,141 @@
+/*
+ librc-strlist.h
+ String list functions for using char ** arrays
+
+ Copyright 2007 Gentoo Foundation
+ Based on a previous implementation by Martin Schlemmer
+ Released under the GPLv2
+ */
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "rc.h"
+#include "rc-misc.h"
+
+char **rc_strlist_add (char **list, const char *item)
+{
+ char **newlist;
+ int i = 0;
+
+ if (! item)
+ return (list);
+
+ while (list && list[i])
+ i++;
+
+ newlist = rc_xrealloc (list, sizeof (char *) * (i + 2));
+ newlist[i] = rc_xstrdup (item);
+ newlist[i + 1] = NULL;
+
+ return (newlist);
+}
+
+static char **_rc_strlist_addsort (char **list, const char *item,
+ int (*sortfunc) (const char *s1,
+ const char *s2))
+{
+ char **newlist;
+ int i = 0;
+ char *tmp1;
+ char *tmp2;
+
+ if (! item)
+ return (list);
+
+ while (list && list[i])
+ i++;
+
+ newlist = rc_xrealloc (list, sizeof (char *) * (i + 2));
+
+ if (i == 0)
+ newlist[i] = NULL;
+ newlist[i + 1] = NULL;
+
+ i = 0;
+ while (newlist[i] && sortfunc (newlist[i], item) < 0)
+ i++;
+
+ tmp1 = newlist[i];
+ newlist[i] = rc_xstrdup (item);
+ do
+ {
+ i++;
+ tmp2 = newlist[i];
+ newlist[i] = tmp1;
+ tmp1 = tmp2;
+ } while (tmp1);
+
+ return (newlist);
+}
+
+char **rc_strlist_addsort (char **list, const char *item)
+{
+ return (_rc_strlist_addsort (list, item, strcoll));
+}
+
+char **rc_strlist_addsortc (char **list, const char *item)
+{
+ return (_rc_strlist_addsort (list, item, strcmp));
+}
+
+char **rc_strlist_delete (char **list, const char *item)
+{
+ int i = 0;
+
+ if (!list || ! item)
+ return (list);
+
+ while (list[i])
+ if (strcmp (list[i], item) == 0)
+ {
+ free (list[i]);
+ do
+ {
+ list[i] = list[i + 1];
+ i++;
+ } while (list[i]);
+ }
+
+ return (list);
+}
+
+void rc_strlist_reverse (char **list)
+{
+ char *item;
+ int i = 0;
+ int j = 0;
+
+ if (! list)
+ return;
+
+ while (list[j])
+ j++;
+ j--;
+
+ while (i < j && list[i] && list[j])
+ {
+ item = list[i];
+ list[i] = list[j];
+ list[j] = item;
+ i++;
+ j--;
+ }
+}
+
+void rc_strlist_free (char **list)
+{
+ int i = 0;
+
+ if (! list)
+ return;
+
+ while (list[i])
+ {
+ free (list[i]);
+ list[i++] = NULL;
+ }
+
+ free (list);
+}
diff --git a/src/librc.c b/src/librc.c
new file mode 100644
index 00000000..d9c4a539
--- /dev/null
+++ b/src/librc.c
@@ -0,0 +1,773 @@
+/*
+ librc
+ core RC functions
+ Copyright 2007 Gentoo Foundation
+ Released under the GPLv2
+ */
+
+#include <sys/types.h>
+#include <sys/select.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <errno.h>
+#ifndef __linux__
+/* Although linux should work fine, gcc likes to bitch with our default
+ CFLAGS so we just don't include the file and use the GNU one defined
+ in string.h */
+#include <libgen.h>
+#endif
+#include <limits.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "einfo.h"
+#include "rc.h"
+#include "rc-misc.h"
+#include "strlist.h"
+
+/* usecs to wait while we poll the fifo */
+#define WAIT_INTERVAL 20000
+
+/* max secs to wait until a service comes up */
+#define WAIT_MAX 60
+
+#define SOFTLEVEL RC_SVCDIR "softlevel"
+
+static const char *rc_service_state_names[] = {
+ "started",
+ "stopped",
+ "starting",
+ "stopping",
+ "inactive",
+ "wasinactive",
+ "coldplugged",
+ "failed",
+ NULL
+};
+
+bool rc_runlevel_starting (void)
+{
+ return (rc_is_dir (RC_SVCDIR "softscripts.old"));
+}
+
+bool rc_runlevel_stopping (void)
+{
+ return (rc_is_dir (RC_SVCDIR "softscripts.new"));
+}
+
+char **rc_get_runlevels (void)
+{
+ char **dirs = rc_ls_dir (NULL, RC_RUNLEVELDIR, 0);
+ char **runlevels = NULL;
+ int i;
+ char *dir;
+
+ STRLIST_FOREACH (dirs, dir, i)
+ {
+ char *path = rc_strcatpaths (RC_RUNLEVELDIR, dir, NULL);
+ if (rc_is_dir (path))
+ runlevels = rc_strlist_addsort (runlevels, dir);
+ free (path);
+ }
+ rc_strlist_free (dirs);
+
+ return (runlevels);
+}
+
+char *rc_get_runlevel (void)
+{
+ FILE *fp;
+ static char buffer [PATH_MAX];
+
+ if (! (fp = fopen (SOFTLEVEL, "r")))
+ {
+ strcpy (buffer, "sysinit");
+ return (buffer);
+ }
+
+ if (fgets (buffer, PATH_MAX, fp))
+ {
+ int i = strlen (buffer) - 1;
+ if (buffer[i] == '\n')
+ buffer[i] = 0;
+ fclose (fp);
+ return (buffer);
+ }
+
+ fclose (fp);
+ strcpy (buffer, "sysinit");
+ return (buffer);
+}
+
+void rc_set_runlevel (const char *runlevel)
+{
+ FILE *fp = fopen (SOFTLEVEL, "w");
+ if (! fp)
+ eerrorx ("failed to open `" SOFTLEVEL "': %s", strerror (errno));
+ fprintf (fp, "%s", runlevel);
+ fclose (fp);
+}
+
+bool rc_runlevel_exists (const char *runlevel)
+{
+ char *path;
+ bool retval;
+
+ if (! runlevel)
+ return (false);
+
+ path = rc_strcatpaths (RC_RUNLEVELDIR, runlevel, NULL);
+ retval = rc_is_dir (path);
+ free (path);
+ return (retval);
+}
+
+/* Resolve a service name to it's full path */
+char *rc_resolve_service (const char *service)
+{
+ char buffer[PATH_MAX];
+ char *file;
+ int r = 0;
+
+ if (! service)
+ return (NULL);
+
+ if (service[0] == '/')
+ return (strdup (service));
+
+ file = rc_strcatpaths (RC_SVCDIR, "started", service, NULL);
+ if (! rc_is_link (file))
+ {
+ free (file);
+ file = rc_strcatpaths (RC_SVCDIR, "inactive", service, NULL);
+ if (! rc_is_link (file))
+ {
+ free (file);
+ file = NULL;
+ }
+ }
+
+ memset (buffer, 0, sizeof (buffer));
+ if (file)
+ {
+ r = readlink (file, buffer, sizeof (buffer));
+ free (file);
+ if (r > 0)
+ return strdup (buffer);
+ }
+
+ snprintf (buffer, sizeof (buffer), RC_INITDIR "%s", service);
+ return (strdup (buffer));
+}
+
+bool rc_service_exists (const char *service)
+{
+ char *file;
+ bool retval = false;
+ int len;
+
+ if (! service)
+ return (false);
+
+ len = strlen (service);
+
+ /* .sh files are not init scripts */
+ if (len > 2 && service[len - 3] == '.' &&
+ service[len - 2] == 's' &&
+ service[len - 1] == 'h')
+ return (false);
+
+ file = rc_resolve_service (service);
+ if (rc_exists (file))
+ retval = rc_is_exec (file);
+ free (file);
+ return (retval);
+}
+
+bool rc_service_in_runlevel (const char *service, const char *runlevel)
+{
+ char *file;
+ bool retval;
+
+ if (! runlevel || ! service)
+ return (false);
+
+ if (! rc_service_exists (service))
+ return (false);
+
+ file = rc_strcatpaths (RC_RUNLEVELDIR, runlevel, basename (service), NULL);
+ retval = rc_exists (file);
+ free (file);
+
+ return (retval);
+}
+
+bool rc_mark_service (const char *service, const rc_service_state_t state)
+{
+ char *file;
+ int i = 0;
+ int skip_state = -1;
+ char *base;
+ char *init = rc_resolve_service (service);
+ bool skip_wasinactive = false;
+
+ if (! service)
+ return (false);
+
+ base = basename (service);
+
+ if (state != rc_service_stopped)
+ {
+ if (! rc_is_file(init))
+ {
+ free (init);
+ return (false);
+ }
+
+ file = rc_strcatpaths (RC_SVCDIR, rc_service_state_names[state], base, NULL);
+ if (rc_exists (file))
+ unlink (file);
+ i = symlink (init, file);
+ if (i != 0)
+ {
+ free (file);
+ free (init);
+ einfo ("%d %s %s", state, rc_service_state_names[state], base);
+ eerror ("symlink `%s' to `%s': %s", init, file, strerror (errno));
+ return (false);
+ }
+
+ free (file);
+ skip_state = state;
+ }
+
+ if (state == rc_service_coldplugged)
+ {
+ free (init);
+ return (true);
+ }
+
+ /* Remove any old states now */
+ i = 0;
+ while (rc_service_state_names[i])
+ {
+ if ((i != skip_state &&
+ i != rc_service_stopped &&
+ i != rc_service_coldplugged &&
+ i != rc_service_crashed) &&
+ (! skip_wasinactive || i != rc_service_wasinactive))
+ {
+ file = rc_strcatpaths (RC_SVCDIR, rc_service_state_names[i], base, NULL);
+ if (rc_exists (file))
+ {
+ if ((state == rc_service_starting ||
+ state == rc_service_stopping) &&
+ i == rc_service_inactive)
+ {
+ char *wasfile = rc_strcatpaths (RC_SVCDIR,
+ rc_service_state_names[rc_service_wasinactive],
+ base, NULL);
+
+ if (symlink (init, wasfile) != 0)
+ eerror ("symlink `%s' to `%s': %s", init, wasfile,
+ strerror (errno));
+
+ skip_wasinactive = true;
+ free (wasfile);
+ }
+
+ errno = 0;
+ if (unlink (file) != 0 && errno != ENOENT)
+ eerror ("failed to delete `%s': %s", file,
+ strerror (errno));
+ }
+ free (file);
+ }
+ i++;
+ }
+
+ /* Remove the exclusive state if we're inactive */
+ if (state == rc_service_started ||
+ state == rc_service_stopped ||
+ state == rc_service_inactive)
+ {
+ file = rc_strcatpaths (RC_SVCDIR, "exclusive", base, NULL);
+ if (rc_exists (file))
+ if (unlink (file) != 0)
+ eerror ("unlink `%s': %s", file, strerror (errno));
+ free (file);
+ }
+
+ /* Remove any options and daemons the service may have stored */
+ if (state == rc_service_stopped)
+ {
+ char *dir = rc_strcatpaths (RC_SVCDIR, "options", base, NULL);
+
+ if (rc_is_dir (dir))
+ rc_rm_dir (dir, true);
+ free (dir);
+
+ dir = rc_strcatpaths (RC_SVCDIR, "daemons", base, NULL);
+ if (rc_is_dir (dir))
+ rc_rm_dir (dir, true);
+ free (dir);
+
+ rc_schedule_clear (service);
+ }
+
+ /* These are final states, so remove us from scheduled */
+ if (state == rc_service_started || state == rc_service_stopped)
+ {
+ char *sdir = rc_strcatpaths (RC_SVCDIR, "scheduled", NULL);
+ char **dirs = rc_ls_dir (NULL, sdir, 0);
+ char *dir;
+ int serrno;
+
+ STRLIST_FOREACH (dirs, dir, i)
+ {
+ char *bdir = rc_strcatpaths (sdir, dir, NULL);
+ file = rc_strcatpaths (bdir, base, NULL);
+ if (rc_exists (file))
+ if (unlink (file) != 0)
+ eerror ("unlink `%s': %s", file, strerror (errno));
+ free (file);
+
+ /* Try and remove the dir - we don't care about errors */
+ serrno = errno;
+ rmdir (bdir);
+ errno = serrno;
+ free (bdir);
+ }
+ rc_strlist_free (dirs);
+ free (sdir);
+ }
+
+ free (init);
+ return (true);
+}
+
+bool rc_service_state (const char *service, const rc_service_state_t state)
+{
+ char *file;
+ bool retval;
+
+ /* If the init script does not exist then we are stopped */
+ if (! rc_service_exists (service))
+ return (state == rc_service_stopped ? true : false);
+
+ /* We check stopped state by not being in any of the others */
+ if (state == rc_service_stopped)
+ return ( ! (rc_service_state (service, rc_service_started) ||
+ rc_service_state (service, rc_service_starting) ||
+ rc_service_state (service, rc_service_stopping) ||
+ rc_service_state (service, rc_service_inactive)));
+
+ /* The crashed state and scheduled states are virtual */
+ if (state == rc_service_crashed)
+ return (rc_service_daemons_crashed (service));
+ else if (state == rc_service_scheduled)
+ {
+ char **services = rc_services_scheduled_by (service);
+ retval = (services);
+ if (services)
+ free (services);
+ return (retval);
+ }
+
+ /* Now we just check if a file by the service name rc_exists
+ in the state dir */
+ file = rc_strcatpaths (RC_SVCDIR, rc_service_state_names[state],
+ basename (service), NULL);
+ retval = rc_exists (file);
+ free (file);
+ return (retval);
+}
+
+bool rc_get_service_option (const char *service, const char *option,
+ char *value)
+{
+ FILE *fp;
+ char buffer[1024];
+ char *file = rc_strcatpaths (RC_SVCDIR, "options", service, option, NULL);
+ bool retval = false;
+
+ if (rc_exists (file))
+ {
+ if ((fp = fopen (file, "r")) == NULL)
+ eerror ("fopen `%s': %s", file, strerror (errno));
+ else
+ {
+ memset (buffer, 0, sizeof (buffer));
+ while (fgets (buffer, RC_LINEBUFFER, fp))
+ {
+ memcpy (value, buffer, strlen (buffer));
+ value += strlen (buffer);
+ }
+ fclose (fp);
+ retval = true;
+ }
+ }
+
+ free (file);
+ return (retval);
+}
+
+bool rc_set_service_option (const char *service, const char *option,
+ const char *value)
+{
+ FILE *fp;
+ char *path = rc_strcatpaths (RC_SVCDIR, "options", service, NULL);
+ char *file = rc_strcatpaths (path, option, NULL);
+ bool retval = false;
+
+ if (! rc_is_dir (path))
+ {
+ if (mkdir (path, 0755) != 0)
+ {
+ eerror ("mkdir `%s': %s", path, strerror (errno));
+ free (path);
+ free (file);
+ return (false);
+ }
+ }
+
+ if ((fp = fopen (file, "w")) == NULL)
+ eerror ("fopen `%s': %s", file, strerror (errno));
+ else
+ {
+ if (value)
+ fprintf (fp, "%s", value);
+ fclose (fp);
+ retval = true;
+ }
+
+ free (path);
+ free (file);
+ return (retval);
+}
+
+static pid_t _exec_service (const char *service, const char *arg)
+{
+ char *file;
+ char *fifo;
+ pid_t pid = -1;
+ pid_t savedpid;
+ int status;
+
+ file = rc_resolve_service (service);
+ if (! rc_is_file (file))
+ {
+ rc_mark_service (service, rc_service_stopped);
+ free (file);
+ return (0);
+ }
+
+ /* We create a fifo so that other services can wait until we complete */
+ fifo = rc_strcatpaths (RC_SVCDIR, "exclusive", basename (service), NULL);
+
+ if (mkfifo (fifo, 0600) != 0 && errno != EEXIST)
+ {
+ eerror ("unable to create fifo `%s': %s", fifo, strerror (errno));
+ free (fifo);
+ free (file);
+ return (-1);
+ }
+
+ if ((pid = fork ()) == 0)
+ {
+ char *myarg = strdup (arg);
+ int e = 0;
+ execl (file, file, myarg, NULL);
+ e = errno;
+ free (myarg);
+ unlink (fifo);
+ free (fifo);
+ eerrorx ("unable to exec `%s': %s", file, strerror (errno));
+ }
+
+ free (fifo);
+ free (file);
+
+ if (pid == -1)
+ {
+ eerror ("unable to fork: %s", strerror (errno));
+ return (pid);
+ }
+
+ if (rc_is_env ("RC_PARALLEL_STARTUP", "yes"))
+ return (pid);
+
+ savedpid = pid;
+ errno = 0;
+ do
+ {
+ pid = waitpid (savedpid, &status, 0);
+ if (pid < 0)
+ {
+ if (errno != ECHILD)
+ eerror ("waitpid %d: %s", savedpid, strerror (errno));
+ return (-1);
+ }
+ } while (! WIFEXITED (status) && ! WIFSIGNALED (status));
+
+ return (0);
+}
+
+pid_t rc_stop_service (const char *service)
+{
+ if (rc_service_state (service, rc_service_stopped))
+ return (0);
+
+ return (_exec_service (service, "stop"));
+}
+
+
+pid_t rc_start_service (const char *service)
+{
+ if (! rc_service_state (service, rc_service_stopped))
+ return (0);
+
+ return (_exec_service (service, "start"));
+}
+
+void rc_schedule_start_service (const char *service,
+ const char *service_to_start)
+{
+ char *dir;
+ char *init;
+ char *file;
+
+ if (! rc_service_exists (service) || ! rc_service_exists (service_to_start))
+ return;
+
+ dir = rc_strcatpaths (RC_SVCDIR, "scheduled", basename (service), NULL);
+ if (! rc_is_dir (dir))
+ if (mkdir (dir, 0755) != 0)
+ {
+ eerror ("mkdir `%s': %s", dir, strerror (errno));
+ free (dir);
+ return;
+ }
+
+ init = rc_resolve_service (service_to_start);
+ file = rc_strcatpaths (dir, basename (service_to_start), NULL);
+ if (! rc_exists (file) && symlink (init, file) != 0)
+ eerror ("symlink `%s' to `%s': %s", init, file, strerror (errno));
+
+ free (init);
+ free (file);
+ free (dir);
+}
+
+void rc_schedule_clear (const char *service)
+{
+ char *dir = rc_strcatpaths (RC_SVCDIR, "scheduled", basename (service), NULL);
+
+ if (rc_is_dir (dir))
+ rc_rm_dir (dir, true);
+ free (dir);
+}
+
+bool rc_wait_service (const char *service)
+{
+ char *fifo = rc_strcatpaths (RC_SVCDIR, "exclusive", basename (service), NULL);
+ struct timeval tv;
+ struct timeval stopat;
+ struct timeval now;
+ bool retval = false;
+
+ if (gettimeofday (&stopat, NULL) != 0)
+ {
+ eerror ("gettimeofday: %s", strerror (errno));
+ return (false);
+ }
+ stopat.tv_sec += WAIT_MAX;
+
+ while (true)
+ {
+ if (! rc_exists (fifo))
+ {
+ retval = true;
+ break;
+ }
+
+ tv.tv_sec = 0;
+ tv.tv_usec = WAIT_INTERVAL;
+ if (select (0, 0, 0, 0, &tv) < 0)
+ {
+ if (errno != EINTR)
+ eerror ("select: %s",strerror (errno));
+ break;
+ }
+
+ /* Don't hang around forever */
+ if (gettimeofday (&now, NULL) != 0)
+ {
+ eerror ("gettimeofday: %s", strerror (errno));
+ break;
+ }
+ if (timercmp (&now, &stopat, >))
+ break;
+ }
+
+ free (fifo);
+ return (retval);
+}
+
+char **rc_services_in_runlevel (const char *runlevel)
+{
+ char *dir;
+ char **list = NULL;
+
+ if (! runlevel)
+ return (rc_ls_dir (NULL, RC_INITDIR, RC_LS_INITD));
+
+ /* These special levels never contain any services */
+ if (strcmp (runlevel, RC_LEVEL_SYSINIT) == 0 ||
+ strcmp (runlevel, RC_LEVEL_SINGLE) == 0)
+ return (NULL);
+
+ dir = rc_strcatpaths (RC_RUNLEVELDIR, runlevel, NULL);
+ if (! rc_is_dir (dir))
+ eerror ("runlevel `%s' does not exist", runlevel);
+ else
+ list = rc_ls_dir (list, dir, RC_LS_INITD);
+
+ free (dir);
+ return (list);
+}
+
+char **rc_services_in_state (rc_service_state_t state)
+{
+ char *dir = rc_strcatpaths (RC_SVCDIR, rc_service_state_names[state], NULL);
+ char **list = NULL;
+
+ if (rc_is_dir (dir))
+ list = rc_ls_dir (list, dir, RC_LS_INITD);
+
+ free (dir);
+ return (list);
+}
+
+bool rc_service_add (const char *runlevel, const char *service)
+{
+ bool retval;
+ char *init;
+ char *file;
+
+ if (! rc_runlevel_exists (runlevel))
+ {
+ errno = ENOENT;
+ return (false);
+ }
+
+ if (rc_service_in_runlevel (service, runlevel))
+ {
+ errno = EEXIST;
+ return (false);
+ }
+
+ init = rc_resolve_service (service);
+ file = rc_strcatpaths (RC_RUNLEVELDIR, runlevel, basename (service), NULL);
+ retval = (symlink (init, file) == 0);
+ free (init);
+ free (file);
+ return (retval);
+}
+
+bool rc_service_delete (const char *runlevel, const char *service)
+{
+ char *file;
+ bool retval = false;
+
+ if (! runlevel || ! service)
+ return (false);
+
+ file = rc_strcatpaths (RC_RUNLEVELDIR, runlevel, basename (service), NULL);
+ if (unlink (file) == 0)
+ retval = true;
+
+ free (file);
+ return (retval);
+}
+
+char **rc_services_scheduled_by (const char *service)
+{
+ char **dirs = rc_ls_dir (NULL, RC_SVCDIR "scheduled", 0);
+ char **list = NULL;
+ char *dir;
+ int i;
+
+ STRLIST_FOREACH (dirs, dir, i)
+ {
+ char *file = rc_strcatpaths (RC_SVCDIR "scheduled", dir, service, NULL);
+ if (rc_exists (file))
+ list = rc_strlist_add (list, file);
+ free (file);
+ }
+ rc_strlist_free (dirs);
+
+ return (list);
+}
+
+char **rc_services_scheduled (const char *service)
+{
+ char *dir = rc_strcatpaths (RC_SVCDIR, "scheduled", basename (service), NULL);
+ char **list = NULL;
+
+ if (rc_is_dir (dir))
+ list = rc_ls_dir (list, dir, RC_LS_INITD);
+
+ free (dir);
+ return (list);
+}
+
+bool rc_allow_plug (char *service)
+{
+ char *list;
+ char *p;
+ char *star;
+ char *token;
+ bool allow = true;
+ char *match = getenv ("RC_PLUG_SERVICES");
+ if (! match)
+ return true;
+
+ list = strdup (match);
+ p = list;
+ while ((token = strsep (&p, " ")))
+ {
+ bool truefalse = true;
+ if (token[0] == '!')
+ {
+ truefalse = false;
+ token++;
+ }
+
+ star = strchr (token, '*');
+ if (star)
+ {
+ if (strncmp (service, token, star - token) == 0)
+ {
+ allow = truefalse;
+ break;
+ }
+ }
+ else
+ {
+ if (strcmp (service, token) == 0)
+ {
+ allow = truefalse;
+ break;
+ }
+ }
+ }
+
+ free (list);
+ return (allow);
+}
diff --git a/src/mountinfo.c b/src/mountinfo.c
new file mode 100644
index 00000000..1fc84420
--- /dev/null
+++ b/src/mountinfo.c
@@ -0,0 +1,246 @@
+/*
+ mountinfo.c
+ Obtains information about mounted filesystems.
+
+ Copyright 2007 Gentoo Foundation
+ */
+
+#include <sys/types.h>
+#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
+#include <sys/param.h>
+#include <sys/ucred.h>
+#include <sys/mount.h>
+#elif defined(__linux__)
+#include <limits.h>
+#endif
+
+#include <errno.h>
+#include <limits.h>
+#include <regex.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "einfo.h"
+#include "rc.h"
+#include "rc-misc.h"
+#include "strlist.h"
+
+#if defined(__FreeBSD__) || defined(__NetBSD__) || defined (__OpenBSD__)
+static char **find_mounts (regex_t *node_regex, regex_t *fstype_regex,
+ char **mounts, bool list_nodes, bool list_fstype)
+{
+ struct statfs *mnts;
+ int nmnts;
+ int i;
+ char **list = NULL;
+
+ if ((nmnts = getmntinfo (&mnts, MNT_NOWAIT)) == 0)
+ eerrorx ("getmntinfo: %s", strerror (errno));
+
+ for (i = 0; i < nmnts; i++)
+ {
+ if (node_regex &&
+ regexec (node_regex, mnts[i].f_mntfromname, 0, NULL, 0) != 0)
+ continue;
+ if (fstype_regex &&
+ regexec (fstype_regex, mnts[i].f_fstypename, 0, NULL, 0) != 0)
+ continue;
+
+ if (mounts)
+ {
+ bool found = false;
+ int j;
+ char *mnt;
+ STRLIST_FOREACH (mounts, mnt, j)
+ if (strcmp (mnt, mnts[i].f_mntonname) == 0)
+ {
+ found = true;
+ break;
+ }
+ if (! found)
+ continue;
+ }
+
+ list = rc_strlist_addsortc (list, list_nodes ?
+ mnts[i].f_mntfromname :
+ list_fstype ? mnts[i].f_fstypename :
+ mnts[i].f_mntonname);
+ }
+
+ return (list);
+}
+
+#elif defined (__linux__)
+static char **find_mounts (regex_t *node_regex, regex_t *fstype_regex,
+ char **mounts, bool list_nodes, bool list_fstype)
+{
+ FILE *fp;
+ char buffer[PATH_MAX * 3];
+ char *p;
+ char *from;
+ char *to;
+ char *fstype;
+ char **list = NULL;
+
+ if ((fp = fopen ("/proc/mounts", "r")) == NULL)
+ eerrorx ("getmntinfo: %s", strerror (errno));
+
+ while (fgets (buffer, sizeof (buffer), fp))
+ {
+ p = buffer;
+ from = strsep (&p, " ");
+ if (node_regex &&
+ regexec (node_regex, from, 0, NULL, 0) != 0)
+ continue;
+
+ to = strsep (&p, " ");
+ fstype = strsep (&p, " ");
+ /* Skip the really silly rootfs */
+ if (strcmp (fstype, "rootfs") == 0)
+ continue;
+ if (fstype_regex &&
+ regexec (fstype_regex, fstype, 0, NULL, 0) != 0)
+ continue;
+
+ if (mounts)
+ {
+ bool found = false;
+ int j;
+ char *mnt;
+ STRLIST_FOREACH (mounts, mnt, j)
+ if (strcmp (mnt, to) == 0)
+ {
+ found = true;
+ break;
+ }
+ if (! found)
+ continue;
+ }
+
+ list = rc_strlist_addsortc (list,
+ list_nodes ?
+ list_fstype ? fstype :
+ from : to);
+ }
+ fclose (fp);
+
+ return (list);
+}
+
+#else
+# error "Operating system not supported!"
+#endif
+
+int main (int argc, char **argv)
+{
+ int i;
+ regex_t *fstype_regex = NULL;
+ regex_t *node_regex = NULL;
+ regex_t *skip_regex = NULL;
+ char **nodes = NULL;
+ char *node;
+ int result;
+ char buffer[256];
+ bool list_nodes = false;
+ bool list_fstype = false;
+ bool reverse = false;
+ char **mounts = NULL;
+
+ for (i = 1; i < argc; i++)
+ {
+ if (strcmp (argv[i], "--fstype-regex") == 0 && (i + 1 < argc))
+ {
+ i++;
+ if (fstype_regex)
+ free (fstype_regex);
+ fstype_regex = rc_xmalloc (sizeof (regex_t));
+ if ((result = regcomp (fstype_regex, argv[i],
+ REG_EXTENDED | REG_NOSUB)) != 0)
+ {
+ regerror (result, fstype_regex, buffer, sizeof (buffer));
+ eerrorx ("%s: invalid regex `%s'", argv[0], buffer);
+ }
+ continue;
+ }
+
+ if (strcmp (argv[i], "--node-regex") == 0 && (i + 1 < argc))
+ {
+ i++;
+ if (node_regex)
+ free (node_regex);
+ node_regex = rc_xmalloc (sizeof (regex_t));
+ if ((result = regcomp (node_regex, argv[i],
+ REG_EXTENDED | REG_NOSUB)) != 0)
+ {
+ regerror (result, node_regex, buffer, sizeof (buffer));
+ eerrorx ("%s: invalid regex `%s'", argv[0], buffer);
+ }
+ continue;
+ }
+
+ if (strcmp (argv[i], "--skip-regex") == 0 && (i + 1 < argc))
+ {
+ i++;
+ if (skip_regex)
+ free (skip_regex);
+ skip_regex = rc_xmalloc (sizeof (regex_t));
+ if ((result = regcomp (skip_regex, argv[i],
+ REG_EXTENDED | REG_NOSUB)) != 0)
+ {
+ regerror (result, skip_regex, buffer, sizeof (buffer));
+ eerrorx ("%s: invalid regex `%s'", argv[0], buffer);
+ }
+ continue;
+ }
+
+ if (strcmp (argv[i], "--fstype") == 0)
+ {
+ list_fstype = true;
+ continue;
+ }
+
+ if (strcmp (argv[i], "--node") == 0)
+ {
+ list_nodes = true;
+ continue;
+ }
+ if (strcmp (argv[i], "--reverse") == 0)
+ {
+ reverse = true;
+ continue;
+ }
+
+ if (argv[i][0] != '/')
+ eerrorx ("%s: `%s' is not a mount point", argv[0], argv[i]);
+
+ mounts = rc_strlist_add (mounts, argv[i]);
+ }
+
+ nodes = find_mounts (node_regex, fstype_regex, mounts,
+ list_nodes, list_fstype);
+
+ if (node_regex)
+ regfree (node_regex);
+ if (fstype_regex)
+ regfree (fstype_regex);
+
+ if (reverse)
+ rc_strlist_reverse (nodes);
+
+ result = EXIT_FAILURE;
+ STRLIST_FOREACH (nodes, node, i)
+ {
+ if (skip_regex && regexec (skip_regex, node, 0, NULL, 0) == 0)
+ continue;
+ printf ("%s\n", node);
+ result = EXIT_SUCCESS;
+ }
+ rc_strlist_free (nodes);
+
+ if (skip_regex)
+ free (skip_regex);
+
+ exit (result);
+}
+
diff --git a/src/rc-depend.c b/src/rc-depend.c
new file mode 100644
index 00000000..9d0b3af8
--- /dev/null
+++ b/src/rc-depend.c
@@ -0,0 +1,120 @@
+/*
+ rc-depend
+ rc service dependency and ordering
+ Copyright 2006-2007 Gentoo Foundation
+ Released under the GPLv2
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "einfo.h"
+#include "rc.h"
+#include "rc-misc.h"
+#include "strlist.h"
+
+int main (int argc, char **argv)
+{
+ char **types = NULL;
+ char **services = NULL;
+ char **depends = NULL;
+ rc_depinfo_t *deptree = NULL;
+ rc_depinfo_t *di;
+ char *service;
+ int options = RC_DEP_TRACE;
+ bool first = true;
+ int i;
+ bool update = false;
+ char *runlevel = getenv ("RC_SOFTLEVEL");
+
+ if (! runlevel)
+ runlevel = rc_get_runlevel ();
+
+ for (i = 1; i < argc; i++)
+ {
+ if (strcmp (argv[i], "--update") == 0)
+ {
+ if (! update)
+ {
+ rc_update_deptree (true);
+ update = true;
+ }
+ continue;
+ }
+
+ if (strcmp (argv[i], "--strict") == 0)
+ {
+ options |= RC_DEP_STRICT;
+ continue;
+ }
+
+ if (strcmp (argv[i], "--notrace") == 0)
+ {
+ options &= RC_DEP_TRACE;
+ continue;
+ }
+
+ if (argv[i][0] == '-')
+ {
+ argv[i]++;
+ types = rc_strlist_add (types, argv[i]);
+ }
+ else
+ {
+ if ((deptree = rc_load_deptree ()) == NULL)
+ eerrorx ("failed to load deptree");
+
+ di = rc_get_depinfo (deptree, argv[i]);
+ if (! di)
+ eerror ("no dependency info for service `%s'", argv[i]);
+ else
+ services = rc_strlist_add (services, argv[i]);
+ }
+ }
+
+ if (! services)
+ {
+ rc_strlist_free (types);
+ rc_free_deptree (deptree);
+ if (update)
+ return (EXIT_SUCCESS);
+ eerrorx ("no services specified");
+ }
+
+ /* If we don't have any types, then supply some defaults */
+ if (! types)
+ {
+ types = rc_strlist_add (NULL, "ineed");
+ rc_strlist_add (types, "iuse");
+ }
+
+ depends = rc_get_depends (deptree, types, services, runlevel, options);
+
+ if (depends)
+ {
+ STRLIST_FOREACH (depends, service, i)
+ {
+ if (first)
+ first = false;
+ else
+ printf (" ");
+
+ if (service)
+ printf ("%s", service);
+
+ }
+ printf ("\n");
+ }
+
+ rc_strlist_free (types);
+ rc_strlist_free (services);
+ rc_strlist_free (depends);
+ rc_free_deptree (deptree);
+
+ return (EXIT_SUCCESS);
+}
diff --git a/src/rc-misc.h b/src/rc-misc.h
new file mode 100644
index 00000000..5a4aa55f
--- /dev/null
+++ b/src/rc-misc.h
@@ -0,0 +1,34 @@
+/*
+ rc-misc.h
+ This is private to us and not for user consumption
+ Copyright 2007 Gentoo Foundation
+ */
+
+#ifndef __RC_MISC_H__
+#define __RC_MISC_H__
+
+#ifndef LIBDIR
+# define LIBDIR "lib"
+#endif
+
+#define RC_LIBDIR "/" LIBDIR "/rcscripts/"
+#define RC_SVCDIR RC_LIBDIR "init.d/"
+#define RC_DEPTREE RC_SVCDIR "deptree"
+#define RC_RUNLEVELDIR "/etc/runlevels/"
+#define RC_INITDIR "/etc/init.d/"
+#define RC_CONFDIR "/etc/conf.d/"
+
+#define RC_SVCDIR_STARTING RC_SVCDIR "starting/"
+#define RC_SVCDIR_INACTIVE RC_SVCDIR "inactive/"
+#define RC_SVCDIR_STARTED RC_SVCDIR "started/"
+#define RC_SVCDIR_COLDPLUGGED RC_SVCDIR "coldplugged/"
+
+#define RC_PLUGINDIR RC_LIBDIR "plugins/"
+
+/* Max buffer to read a line from a file */
+#define RC_LINEBUFFER 4096
+
+/* Good defaults just incase user has none set */
+#define RC_NET_FS_LIST_DEFAULT "afs cifs coda davfs fuse gfs ncpfs nfs nfs4 ocfs2 shfs smbfs"
+
+#endif
diff --git a/src/rc-plugin.c b/src/rc-plugin.c
new file mode 100644
index 00000000..c02b6a81
--- /dev/null
+++ b/src/rc-plugin.c
@@ -0,0 +1,119 @@
+/*
+ librc-plugin.c
+ Simple plugin handler
+ Copyright 2007 Gentoo Foundation
+ Released under the GPLv2
+ */
+
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "einfo.h"
+#include "rc.h"
+#include "rc-misc.h"
+#include "rc-plugin.h"
+#include "strlist.h"
+
+typedef struct plugin
+{
+ char *name;
+ void *handle;
+ int (*hook) (rc_hook_t hook, const char *name);
+ struct plugin *next;
+} plugin_t;
+
+static plugin_t *plugins = NULL;
+
+void rc_plugin_load (void)
+{
+ char **files;
+ char *file;
+ int i;
+ plugin_t *plugin = plugins;
+
+ /* Ensure some sanity here */
+ rc_plugin_unload ();
+
+ if (! rc_exists (RC_PLUGINDIR))
+ return;
+
+ files = rc_ls_dir (NULL, RC_PLUGINDIR, 0);
+ STRLIST_FOREACH (files, file, i)
+ {
+ char *p = rc_strcatpaths (RC_PLUGINDIR, file, NULL);
+ void *h = dlopen (p, RTLD_LAZY);
+ char *func;
+ void *f;
+
+ if (! h)
+ {
+ eerror ("dlopen `%s': %s", p, dlerror ());
+ free (p);
+ continue;
+ }
+
+ func = file;
+ file = strsep (&func, ".");
+ func = rc_xmalloc (strlen (file) + strlen ("__hook") + 1);
+ sprintf (func, "_%s_hook", file);
+
+ f = dlsym (h, func);
+ if (! f)
+ {
+ eerror ("`%s' does not expose the symbol `%s'", p, func);
+ dlclose (h);
+ }
+ else
+ {
+ if (plugin)
+ {
+ plugin->next = rc_xmalloc (sizeof (plugin_t));
+ plugin = plugin->next;
+ }
+ else
+ plugin = plugins = rc_xmalloc (sizeof (plugin_t));
+
+ memset (plugin, 0, sizeof (plugin_t));
+ plugin->name = strdup (file);
+ plugin->handle = h;
+ plugin->hook = f;
+ }
+
+ free (func);
+ free (p);
+ }
+
+ rc_strlist_free (files);
+}
+
+void rc_plugin_run (rc_hook_t hook, const char *value)
+{
+ plugin_t *plugin = plugins;
+
+ while (plugin)
+ {
+ if (plugin->hook)
+ plugin->hook (hook, value);
+
+ plugin = plugin->next;
+ }
+}
+
+void rc_plugin_unload (void)
+{
+ plugin_t *plugin = plugins;
+ plugin_t *next;
+
+ while (plugin)
+ {
+ next = plugin->next;
+ dlclose (plugin->handle);
+ free (plugin->name);
+ free (plugin);
+ plugin = next;
+ }
+ plugins = NULL;
+}
diff --git a/src/rc-plugin.h b/src/rc-plugin.h
new file mode 100644
index 00000000..b4391ad0
--- /dev/null
+++ b/src/rc-plugin.h
@@ -0,0 +1,15 @@
+/*
+ librc-plugin.h
+ Private instructions to use plugins
+ Copyright 2007 Gentoo Foundation
+ Released under the GPLv2
+ */
+
+#ifndef __LIBRC_PLUGIN_H__
+#define __LIBRC_PLUGIN_H__
+
+void rc_plugin_load ();
+void rc_plugin_unload ();
+void rc_plugin_run (rc_hook_t, const char *value);
+
+#endif
diff --git a/src/rc-status.c b/src/rc-status.c
new file mode 100644
index 00000000..5f2f9b1d
--- /dev/null
+++ b/src/rc-status.c
@@ -0,0 +1,142 @@
+/*
+ rc-status
+ Display the status of the services in runlevels
+ Copyright 2007 Gentoo Foundation
+ Released under the GPLv2
+ */
+
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "einfo.h"
+#include "rc.h"
+#include "rc-misc.h"
+#include "strlist.h"
+
+static void print_level (char *level)
+{
+ printf ("Runlevel: ");
+ PEINFO_HILITE;
+ printf ("%s\n", level);
+ PEINFO_NORMAL;
+}
+
+static void print_service (char *service)
+{
+ char status[10];
+ int cols = printf (" %s\n", service);
+ einfo_color_t color = einfo_bad;
+
+ if (rc_service_state (service, rc_service_stopping))
+ snprintf (status, sizeof (status), "stopping ");
+ else if (rc_service_state (service, rc_service_starting))
+ {
+ snprintf (status, sizeof (status), "starting ");
+ color = einfo_warn;
+ }
+ else if (rc_service_state (service, rc_service_inactive))
+ {
+ snprintf (status, sizeof (status), "inactive ");
+ color = einfo_warn;
+ }
+ else if (geteuid () == 0 && rc_service_state (service, rc_service_crashed))
+ snprintf (status, sizeof (status), " crashed ");
+ else if (rc_service_state (service, rc_service_started))
+ {
+ snprintf (status, sizeof (status), " started ");
+ color = einfo_good;
+ }
+ else if (rc_service_state (service, rc_service_scheduled))
+ {
+ snprintf (status, sizeof (status), "scheduled");
+ color = einfo_warn;
+ }
+ else
+ snprintf (status, sizeof (status), " stopped ");
+ ebracket (cols, color, status);
+}
+
+int main (int argc, char **argv)
+{
+ char **levels = NULL;
+ char **services = NULL;
+ char *level;
+ char *service;
+ char c;
+ int option_index = 0;
+ int i;
+ int j;
+
+ const struct option longopts[] =
+ {
+ {"all", no_argument, NULL, 'a'},
+ {"list", no_argument, NULL, 'l'},
+ {"servicelist", no_argument, NULL, 's'},
+ {"unused", no_argument, NULL, 'u'},
+ {NULL, 0, NULL, 0}
+ };
+
+ while ((c = getopt_long(argc, argv, "alsu", longopts, &option_index)) != -1)
+ switch (c)
+ {
+ case 'a':
+ levels = rc_get_runlevels ();
+ break;
+ case 'l':
+ levels = rc_get_runlevels ();
+ STRLIST_FOREACH (levels, level, i)
+ printf ("%s\n", level);
+ rc_strlist_free (levels);
+ exit (EXIT_SUCCESS);
+ case 's':
+ services = rc_services_in_runlevel (NULL);
+ STRLIST_FOREACH (services, service, i)
+ print_service (service);
+ rc_strlist_free (services);
+ exit (EXIT_SUCCESS);
+ case 'u':
+ services = rc_services_in_runlevel (NULL);
+ levels = rc_get_runlevels ();
+ STRLIST_FOREACH (services, service, i)
+ {
+ bool found = false;
+ STRLIST_FOREACH (levels, level, j)
+ if (rc_service_in_runlevel (service, level))
+ {
+ found = true;
+ break;
+ }
+ if (! found)
+ print_service (service);
+ }
+ rc_strlist_free (levels);
+ rc_strlist_free (services);
+ exit (EXIT_SUCCESS);
+ case '?':
+ exit (EXIT_FAILURE);
+ default:
+ exit (EXIT_FAILURE);
+ }
+
+ while (optind < argc)
+ levels = rc_strlist_add (levels, argv[optind++]);
+
+ if (! levels)
+ levels = rc_strlist_add (NULL, rc_get_runlevel ());
+
+ STRLIST_FOREACH (levels, level, i)
+ {
+ print_level (level);
+ services = rc_services_in_runlevel (level);
+ STRLIST_FOREACH (services, service, j)
+ print_service (service);
+ rc_strlist_free (services);
+ }
+
+ rc_strlist_free (levels);
+
+ return (EXIT_SUCCESS);
+}
diff --git a/src/rc-update.c b/src/rc-update.c
new file mode 100644
index 00000000..8d50a4af
--- /dev/null
+++ b/src/rc-update.c
@@ -0,0 +1,162 @@
+/*
+ rc-update
+ Manage init scripts and runlevels
+ Copyright 2007 Gentoo Foundation
+ Released under the GPLv2
+ */
+
+#include <errno.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "einfo.h"
+#include "rc.h"
+#include "rc-misc.h"
+#include "strlist.h"
+
+static char *applet = NULL;
+
+static bool add (const char *runlevel, const char *service)
+{
+ bool retval = true;
+
+ if (! rc_runlevel_exists (runlevel))
+ {
+ ewarn ("runlevel `%s' does not exist", runlevel);
+ return (false);
+ }
+ if (rc_service_in_runlevel (service, runlevel))
+ {
+ ewarn ("%s already installed in runlevel `%s'; skipping",
+ service, runlevel);
+ return (false);
+ }
+
+ if (rc_service_add (runlevel, service))
+ einfo ("%s added to runlevel %s", service, runlevel);
+ else
+ {
+ eerror ("%s: failed to add service `%s' to runlevel `%s': %s",
+ applet, service, runlevel, strerror (errno));
+ retval = false;
+ }
+
+ return (retval);
+}
+
+int main (int argc, char **argv)
+{
+ int i;
+ int j;
+ char *service;
+ char **runlevels = NULL;
+ char *runlevel;
+
+ applet = argv[0];
+ if (argc < 2 ||
+ strcmp (argv[1], "show") == 0 ||
+ strcmp (argv[1], "-s") == 0)
+ {
+ bool verbose = false;
+ char **services = rc_services_in_runlevel (NULL);
+
+ for (i = 2; i < argc; i++)
+ {
+ if (strcmp (argv[i], "--verbose") == 0 ||
+ strcmp (argv[i], "-v") == 0)
+ verbose = true;
+ else
+ runlevels = rc_strlist_add (runlevels, argv[i]);
+ }
+
+ if (! runlevels)
+ runlevels = rc_get_runlevels ();
+
+ STRLIST_FOREACH (services, service, i)
+ {
+ char **in = NULL;
+ bool inone = false;
+
+ STRLIST_FOREACH (runlevels, runlevel, j)
+ {
+ if (rc_service_in_runlevel (service, runlevel))
+ {
+ in = rc_strlist_add (in, runlevel);
+ inone = true;
+ }
+ else
+ {
+ char buffer[PATH_MAX];
+ memset (buffer, ' ', strlen (runlevel));
+ buffer[strlen (runlevel)] = 0;
+ in = rc_strlist_add (in, buffer);
+ }
+ }
+
+ if (! inone && ! verbose)
+ continue;
+
+ printf (" %20s |", service);
+ STRLIST_FOREACH (in, runlevel, j)
+ printf (" %s", runlevel);
+ printf ("\n");
+ }
+
+ return (EXIT_SUCCESS);
+ }
+
+ if (geteuid () != 0)
+ eerrorx ("%s: must be root to add or delete services from runlevels",
+ applet);
+
+ if (! (service = argv[2]))
+ eerrorx ("%s: no service specified", applet);
+
+ if (strcmp (argv[1], "add") == 0 ||
+ strcmp (argv[1], "-a") == 0)
+ {
+ if (! service)
+ eerrorx ("%s: no service specified", applet);
+ if (! rc_service_exists (service))
+ eerrorx ("%s: service `%s' does not exist", applet, service);
+
+ if (argc < 4)
+ add (rc_get_runlevel (), service);
+
+ for (i = 3; i < argc; i++)
+ add (argv[i], service);
+
+ return (EXIT_SUCCESS);
+ }
+
+ if (strcmp (argv[1], "delete") == 0 ||
+ strcmp (argv[1], "del") == 0 ||
+ strcmp (argv[1], "-d") == 0)
+ {
+ for (i = 3; i < argc; i++)
+ runlevels = rc_strlist_add (runlevels, argv[i]);
+
+ if (! runlevels)
+ runlevels = rc_strlist_add (runlevels, rc_get_runlevel ());
+
+ STRLIST_FOREACH (runlevels, runlevel, i)
+ {
+ if (rc_service_in_runlevel (service, runlevel))
+ {
+ if (rc_service_delete (runlevel, service))
+ einfo ("%s removed from runlevel %s", service, runlevel);
+ else
+ eerror ("%s: failed to remove service `%s' from runlevel `%s': %s",
+ applet, service, runlevel, strerror (errno));
+ }
+ }
+
+ return (EXIT_SUCCESS);
+ }
+
+ eerrorx ("%s: unknown command `%s'", applet, argv[1]);
+}
diff --git a/src/rc.c b/src/rc.c
new file mode 100644
index 00000000..b9b4c82e
--- /dev/null
+++ b/src/rc.c
@@ -0,0 +1,1174 @@
+/*
+ rc.c
+ rc - manager for init scripts which control the startup, shutdown
+ and the running of daemons on a Gentoo system.
+
+ Also a multicall binary for various commands that can be used in shell
+ scripts to query service state, mark service state and provide the
+ Gentoo einfo family of informational functions.
+
+ Copyright 2007 Gentoo Foundation
+ Released under the GPLv2
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/utsname.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <ctype.h>
+#include <libgen.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include "einfo.h"
+#include "rc.h"
+#include "rc-misc.h"
+#include "rc-plugin.h"
+#include "strlist.h"
+
+#define INITSH RC_LIBDIR "sh/init.sh"
+#define HALTSH RC_INITDIR "halt.sh"
+
+#define RC_SVCDIR_STARTING RC_SVCDIR "starting/"
+#define RC_SVCDIR_INACTIVE RC_SVCDIR "inactive/"
+#define RC_SVCDIR_STARTED RC_SVCDIR "started/"
+#define RC_SVCDIR_COLDPLUGGED RC_SVCDIR "coldplugged/"
+
+#define INTERACTIVE RC_SVCDIR "interactive"
+
+#define DEVBOOT "/dev/.rcboot"
+
+/* Cleanup anything in main */
+#define CHAR_FREE(_item) \
+ if (_item) \
+{ \
+ free (_item); \
+ _item = NULL; \
+}
+
+extern char **environ;
+
+static char **env = NULL;
+static char **newenv = NULL;
+static char **coldplugged_services;
+static char **stop_services = NULL;
+static char **start_services = NULL;
+static rc_depinfo_t *deptree = NULL;
+static char **types = NULL;
+static char *mycmd = NULL;
+static char *myarg = NULL;
+static char *tmp = NULL;
+static char *applet = NULL;
+
+struct termios *termios_orig;
+
+static void cleanup (void)
+{
+ rc_plugin_unload ();
+
+ if (termios_orig)
+ {
+ tcsetattr (STDIN_FILENO, TCSANOW, termios_orig);
+ free (termios_orig);
+ }
+
+ if (env)
+ rc_strlist_free (env);
+ if (newenv)
+ rc_strlist_free (newenv);
+ if (coldplugged_services)
+ rc_strlist_free (coldplugged_services);
+ if (stop_services)
+ rc_strlist_free (stop_services);
+ if (start_services)
+ rc_strlist_free (start_services);
+ if (deptree)
+ rc_free_deptree (deptree);
+ if (types)
+ rc_strlist_free (types);
+ if (mycmd)
+ free (mycmd);
+ if (myarg)
+ free (myarg);
+
+ /* Clean runlevel start, stop markers */
+ if (rc_is_dir (RC_SVCDIR "softscripts.new"))
+ rc_rm_dir (RC_SVCDIR "softscripts.new", true);
+ if (rc_is_dir (RC_SVCDIR "softscripts.old"))
+ rc_rm_dir (RC_SVCDIR "softscripts.old", true);
+}
+
+static int do_e (int argc, char **argv)
+{
+ int retval = EXIT_SUCCESS;
+ int i;
+ int l = 0;
+ char *message = NULL;
+ char *p;
+ char *fmt = NULL;
+
+ if (strcmp (applet, "eend") == 0 ||
+ strcmp (applet, "ewend") == 0 ||
+ strcmp (applet, "veend") == 0 ||
+ strcmp (applet, "vweend") == 0)
+ {
+ if (argc > 0)
+ {
+ errno = 0;
+ retval = strtol (argv[0], NULL, 0);
+ if (errno != 0)
+ retval = EXIT_FAILURE;
+ else
+ {
+ argc--;
+ argv++;
+ }
+ }
+ else
+ retval = EXIT_FAILURE;
+ }
+
+ if (argc > 0)
+ {
+ for (i = 0; i < argc; i++)
+ l += strlen (argv[i]) + 1;
+
+ message = rc_xmalloc (l);
+ p = message;
+
+ for (i = 0; i < argc; i++)
+ {
+ if (i > 0)
+ *p++ = ' ';
+ memcpy (p, argv[i], strlen (argv[i]));
+ p += strlen (argv[i]);
+ }
+ *p = 0;
+ }
+
+ if (message)
+ fmt = strdup ("%s");
+
+ if (strcmp (applet, "einfo") == 0)
+ einfo (fmt, message);
+ else if (strcmp (applet, "einfon") == 0)
+ einfon (fmt, message);
+ else if (strcmp (applet, "ewarn") == 0)
+ ewarn (fmt, message);
+ else if (strcmp (applet, "ewarnn") == 0)
+ ewarnn (fmt, message);
+ else if (strcmp (applet, "eerror") == 0)
+ {
+ eerror (fmt, message);
+ retval = 1;
+ }
+ else if (strcmp (applet, "eerrorn") == 0)
+ {
+ eerrorn (fmt, message);
+ retval = 1;
+ }
+ else if (strcmp (applet, "ebegin") == 0)
+ ebegin (fmt, message);
+ else if (strcmp (applet, "eend") == 0)
+ eend (retval, fmt, message);
+ else if (strcmp (applet, "ewend") == 0)
+ ewend (retval, fmt, message);
+ else if (strcmp (applet, "veinfo") == 0)
+ veinfo (fmt, message);
+ else if (strcmp (applet, "veinfon") == 0)
+ veinfon (fmt, message);
+ else if (strcmp (applet, "vewarn") == 0)
+ vewarn (fmt, message);
+ else if (strcmp (applet, "vewarnn") == 0)
+ vewarnn (fmt, message);
+ else if (strcmp (applet, "vebegin") == 0)
+ vebegin (fmt, message);
+ else if (strcmp (applet, "veend") == 0)
+ veend (retval, fmt, message);
+ else if (strcmp (applet, "vewend") == 0)
+ vewend (retval, fmt, message);
+ else if (strcmp (applet, "eindent") == 0)
+ eindent ();
+ else if (strcmp (applet, "eoutdent") == 0)
+ eoutdent ();
+ else if (strcmp (applet, "veindent") == 0)
+ veindent ();
+ else if (strcmp (applet, "veoutdent") == 0)
+ veoutdent ();
+ else if (strcmp (applet, "eflush") == 0)
+ eflush ();
+ else
+ {
+ eerror ("%s: unknown applet", applet);
+ retval = EXIT_FAILURE;
+ }
+
+ if (fmt)
+ free (fmt);
+ if (message)
+ free (message);
+ return (retval);
+}
+
+static int do_service (int argc, char **argv)
+{
+ bool ok = false;
+
+ if (argc < 1 || ! argv[0] || strlen (argv[0]) == 0)
+ eerrorx ("%s: no service specified", applet);
+
+ if (strcmp (applet, "service_started") == 0)
+ ok = rc_service_state (argv[0], rc_service_started);
+ else if (strcmp (applet, "service_stopped") == 0)
+ ok = rc_service_state (argv[0], rc_service_stopped);
+ else if (strcmp (applet, "service_inactive") == 0)
+ ok = rc_service_state (argv[0], rc_service_inactive);
+ else if (strcmp (applet, "service_starting") == 0)
+ ok = rc_service_state (argv[0], rc_service_starting);
+ else if (strcmp (applet, "service_stopping") == 0)
+ ok = rc_service_state (argv[0], rc_service_stopping);
+ else if (strcmp (applet, "service_coldplugged") == 0)
+ ok = rc_service_state (argv[0], rc_service_coldplugged);
+ else if (strcmp (applet, "service_wasinactive") == 0)
+ ok = rc_service_state (argv[0], rc_service_wasinactive);
+ else if (strcmp (applet, "service_started_daemon") == 0)
+ {
+ int idx = 0;
+ if (argc > 2)
+ sscanf (argv[2], "%d", &idx);
+ exit (rc_service_started_daemon (argv[0], argv[1], idx)
+ ? 0 : 1);
+ }
+ else
+ eerrorx ("%s: unknown applet", applet);
+
+ return (ok ? EXIT_SUCCESS : EXIT_FAILURE);
+}
+
+static int do_mark_service (int argc, char **argv)
+{
+ bool ok = false;
+ char *svcname = getenv ("SVCNAME");
+
+ if (argc < 1 || ! argv[0] || strlen (argv[0]) == 0)
+ eerrorx ("%s: no service specified", applet);
+
+ if (strcmp (applet, "mark_service_started") == 0)
+ ok = rc_mark_service (argv[0], rc_service_started);
+ else if (strcmp (applet, "mark_service_stopped") == 0)
+ ok = rc_mark_service (argv[0], rc_service_stopped);
+ else if (strcmp (applet, "mark_service_inactive") == 0)
+ ok = rc_mark_service (argv[0], rc_service_inactive);
+ else if (strcmp (applet, "mark_service_starting") == 0)
+ ok = rc_mark_service (argv[0], rc_service_starting);
+ else if (strcmp (applet, "mark_service_stopping") == 0)
+ ok = rc_mark_service (argv[0], rc_service_stopping);
+ else if (strcmp (applet, "mark_service_coldplugged") == 0)
+ ok = rc_mark_service (argv[0], rc_service_coldplugged);
+ else
+ eerrorx ("%s: unknown applet", applet);
+
+ /* If we're marking ourselves then we need to inform our parent runscript
+ process so they do not mark us based on our exit code */
+ if (ok && svcname && strcmp (svcname, argv[0]) == 0)
+ {
+ char *runscript_pid = getenv ("RC_RUNSCRIPT_PID");
+ char *mtime;
+ pid_t pid = 0;
+ int l;
+
+ if (runscript_pid && sscanf (runscript_pid, "%d", &pid) == 1)
+ if (kill (pid, SIGHUP) != 0)
+ eerror ("%s: failed to signal parent %d: %s",
+ applet, pid, strerror (errno));
+
+ /* Remove the exclsive time test. This ensures that it's not
+ in control as well */
+ l = strlen (RC_SVCDIR "exclusive") +
+ strlen (svcname) +
+ strlen (runscript_pid) +
+ 4;
+ mtime = rc_xmalloc (l);
+ snprintf (mtime, l, RC_SVCDIR "exclusive/%s.%s",
+ svcname, runscript_pid);
+ if (rc_exists (mtime) && unlink (mtime) != 0)
+ eerror ("%s: unlink: %s", applet, strerror (errno));
+ free (mtime);
+ }
+
+ return (ok ? EXIT_SUCCESS : EXIT_FAILURE);
+}
+
+static int do_options (int argc, char **argv)
+{
+ bool ok = false;
+ char *service = getenv ("SVCNAME");
+
+ if (! service)
+ eerrorx ("%s: no service specified", applet);
+
+ if (argc < 1 || ! argv[0] || strlen (argv[0]) == 0)
+ eerrorx ("%s: no option specified", applet);
+
+ if (strcmp (applet, "get_options") == 0)
+ {
+ char buffer[1024];
+ memset (buffer, 0, 1024);
+ ok = rc_get_service_option (service, argv[0], buffer);
+ if (ok)
+ printf ("%s", buffer);
+ }
+ else if (strcmp (applet, "save_options") == 0)
+ ok = rc_set_service_option (service, argv[0], argv[1]);
+ else
+ eerrorx ("%s: unknown applet", applet);
+
+ return (ok ? EXIT_SUCCESS : EXIT_FAILURE);
+}
+
+static char read_key (bool block)
+{
+ struct termios termios;
+ char c = 0;
+
+ if (! isatty (STDIN_FILENO))
+ return (false);
+
+ /* Now save our terminal settings. We need to restore them at exit as we
+ will be changing it for non-blocking reads for Interactive */
+ if (! termios_orig)
+ {
+ termios_orig = rc_xmalloc (sizeof (struct termios));
+ tcgetattr (STDIN_FILENO, termios_orig);
+ }
+
+ tcgetattr (STDIN_FILENO, &termios);
+ termios.c_lflag &= ~(ICANON | ECHO);
+ if (block)
+ termios.c_cc[VMIN] = 1;
+ else
+ {
+ termios.c_cc[VMIN] = 0;
+ termios.c_cc[VTIME] = 0;
+ }
+ tcsetattr (STDIN_FILENO, TCSANOW, &termios);
+
+ read (STDIN_FILENO, &c, 1);
+
+ tcsetattr (STDIN_FILENO, TCSANOW, termios_orig);
+
+ return (c);
+}
+
+static bool want_interactive (void)
+{
+ char c = read_key (false);
+ return ((c == 'I' || c == 'i') ? true : false);
+}
+
+static void mark_interactive (void)
+{
+ FILE *fp = fopen (INTERACTIVE, "w");
+ if (fp)
+ fclose (fp);
+}
+
+static void sulogin (bool cont)
+{
+#ifdef __linux__
+ if (cont)
+ {
+ int status = 0;
+ pid_t pid = fork();
+
+ if (pid == -1)
+ eerrorx ("%s: fork: %s", applet, strerror (errno));
+ if (pid == 0)
+ {
+ newenv = rc_filter_env ();
+ mycmd = rc_xstrdup ("/sbin/sulogin");
+ myarg = rc_xstrdup (getenv ("CONSOLE"));
+ execle (mycmd, mycmd, myarg, NULL, newenv);
+ eerrorx ("%s: unable to exec `/sbin/sulogin': %s", applet, strerror (errno));
+ }
+ waitpid (pid, &status, 0);
+ }
+ else
+ {
+
+ newenv = rc_filter_env ();
+ mycmd = rc_xstrdup ("/sbin/sulogin");
+ myarg = rc_xstrdup (getenv ("CONSOLE"));
+ execle (mycmd, mycmd, myarg, NULL, newenv);
+ eerrorx ("%s: unable to exec `/sbin/sulogin': %s", applet, strerror (errno));
+ }
+#else
+ /* Appease gcc */
+ cont = cont;
+ exit (EXIT_SUCCESS);
+#endif
+}
+
+static void set_ksoftlevel (const char *runlevel)
+{
+ FILE *fp;
+
+ if (! runlevel ||
+ strcmp (runlevel, RC_LEVEL_BOOT) == 0 ||
+ strcmp (runlevel, RC_LEVEL_SINGLE) == 0 ||
+ strcmp (runlevel, RC_LEVEL_SYSINIT) == 0)
+ {
+ if (rc_exists (RC_SVCDIR "ksoftlevel") &&
+ unlink (RC_SVCDIR "ksoftlevel") != 0)
+ eerror ("unlink `%s': %s", RC_SVCDIR "ksoftlevel", strerror (errno));
+ return;
+ }
+
+ if (! (fp = fopen (RC_SVCDIR "ksoftlevel", "w")))
+ {
+ eerror ("fopen `%s': %s", RC_SVCDIR "ksoftlevel", strerror (errno));
+ return;
+ }
+
+ fprintf (fp, "%s", runlevel);
+ fclose (fp);
+}
+
+static void wait_for_services ()
+{
+ int status = 0;
+ struct timeval tv;
+ while (wait (&status) != -1);
+
+ /* Wait for a little bit to flush our ebuffer */
+ tv.tv_usec = 50000;
+ tv.tv_sec = 0;
+ select (0, NULL, NULL, NULL, &tv);
+}
+
+int main (int argc, char **argv)
+{
+ char *RUNLEVEL = NULL;
+ char *PREVLEVEL = NULL;
+ char *runlevel = NULL;
+ char *newlevel = NULL;
+ char *service = NULL;
+ char **deporder = NULL;
+ int i = 0;
+ int j = 0;
+ bool going_down = false;
+ bool interactive = false;
+ int depoptions = RC_DEP_STRICT | RC_DEP_TRACE;
+ char ksoftbuffer [PATH_MAX];
+
+ if (argv[0])
+ applet = basename (argv[0]);
+
+ if (! applet)
+ eerrorx ("arguments required");
+
+ argc--;
+ argv++;
+
+ /* Handle multicall stuff */
+ if (applet[0] == 'e' || (applet[0] == 'v' && applet[1] == 'e'))
+ exit (do_e (argc, argv));
+
+ if (strncmp (applet, "service_", strlen ("service_")) == 0)
+ exit (do_service (argc, argv));
+
+ if (strcmp (applet, "get_options") == 0 ||
+ strcmp (applet, "save_options") == 0)
+ exit (do_options (argc, argv));
+
+ if (strncmp (applet, "mark_service_", strlen ("mark_service_")) == 0)
+ exit (do_mark_service (argc, argv));
+
+ if (strcmp (applet, "is_runlevel_start") == 0)
+ exit (rc_runlevel_starting () ? 0 : 1);
+ else if (strcmp (applet, "is_runlevel_stop") == 0)
+ exit (rc_runlevel_stopping () ? 0 : 1);
+ else if (strcmp (applet, "color_terminal") == 0)
+ exit (colour_terminal () ? 0 : 1);
+
+ if (strcmp (applet, "rc" ) != 0)
+ eerrorx ("%s: unknown applet", applet);
+
+ /* OK, so we really are the main RC process
+ Only root should be able to run us */
+ if (geteuid () != 0)
+ eerrorx ("%s: root access required", applet);
+
+ atexit (cleanup);
+ newlevel = argv[0];
+
+ /* Ensure our environment is pure
+ Also, add our configuration to it */
+ env = rc_filter_env ();
+ env = rc_config_env (env);
+
+ if (env)
+ {
+ char *p;
+
+#ifdef __linux__
+ /* clearenv isn't portable, but there's no harm in using it
+ if we have it */
+ clearenv ();
+#else
+ char *var;
+ /* No clearenv present here then.
+ We could manipulate environ directly ourselves, but it seems that
+ some kernels bitch about this according to the environ man pages
+ so we walk though environ and call unsetenv for each value. */
+ while (environ[0])
+ {
+ tmp = rc_xstrdup (environ[0]);
+ p = tmp;
+ var = strsep (&p, "=");
+ unsetenv (var);
+ free (tmp);
+ }
+ tmp = NULL;
+#endif
+
+ STRLIST_FOREACH (env, p, i)
+ if (strcmp (p, "RC_SOFTLEVEL") != 0 && strcmp (p, "SOFTLEVEL") != 0)
+ putenv (p);
+
+ /* We don't free our list as that would be null in environ */
+ }
+
+ /* Enable logging */
+ setenv ("RC_ELOG", "rc", 1);
+
+ interactive = rc_exists (INTERACTIVE);
+ rc_plugin_load ();
+
+ /* RUNLEVEL is set by sysvinit as is a magic number
+ RC_SOFTLEVEL is set by us and is the name for this magic number
+ even though all our userland documentation refers to runlevel */
+ RUNLEVEL = getenv ("RUNLEVEL");
+ PREVLEVEL = getenv ("PREVLEVEL");
+
+ if (RUNLEVEL && newlevel)
+ {
+ if (strcmp (RUNLEVEL, "S") == 0 || strcmp (RUNLEVEL, "1") == 0)
+ {
+ /* OK, we're either in runlevel 1 or single user mode */
+ if (strcmp (newlevel, RC_LEVEL_SYSINIT) == 0)
+ {
+ struct utsname uts;
+ pid_t pid;
+ pid_t wpid;
+ int status = 0;
+#ifdef __linux__
+ FILE *fp;
+#endif
+
+ uname (&uts);
+
+ printf ("\n");
+ PEINFO_GOOD;
+ printf (" Gentoo/%s; ", uts.sysname);
+ PEINFO_BRACKET;
+ printf ("http://www.gentoo.org/");
+ PEINFO_NORMAL;
+ printf ("\n Copyright 1999-2007 Gentoo Foundation; "
+ "Distributed under the GPLv2\n\n");
+
+ printf ("Press ");
+ PEINFO_GOOD;
+ printf ("I");
+ PEINFO_NORMAL;
+ printf (" to enter interactive boot mode\n\n");
+
+ setenv ("RC_SOFTLEVEL", newlevel, 1);
+ rc_plugin_run (rc_hook_runlevel_start_in, newlevel);
+
+ if ((pid = fork ()) == -1)
+ eerrorx ("%s: fork: %s", applet, strerror (errno));
+
+ if (pid == 0)
+ {
+ mycmd = rc_xstrdup (INITSH);
+ execl (mycmd, mycmd, NULL);
+ eerrorx ("%s: unable to exec `" INITSH "': %s",
+ applet, strerror (errno));
+ }
+
+ do
+ {
+ wpid = waitpid (pid, &status, 0);
+ if (wpid < 1)
+ eerror ("waitpid: %s", strerror (errno));
+ } while (! WIFEXITED (status) && ! WIFSIGNALED (status));
+
+ if (! WIFEXITED (status) || ! WEXITSTATUS (status) == 0)
+ exit (EXIT_FAILURE);
+
+ /* If we requested a softlevel, save it now */
+#ifdef __linux__
+ set_ksoftlevel (NULL);
+
+ if ((fp = fopen ("/proc/cmdline", "r")))
+ {
+ char buffer[RC_LINEBUFFER];
+ char *soft;
+
+ memset (buffer, 0, sizeof (buffer));
+ if (fgets (buffer, RC_LINEBUFFER, fp) &&
+ (soft = strstr (buffer, "softlevel=")))
+ {
+ i = soft - buffer;
+ if (i == 0 || buffer[i - 1] == ' ')
+ {
+ char *level;
+
+ /* Trim the trailing carriage return if present */
+ i = strlen (buffer) - 1;
+ if (buffer[i] == '\n')
+ buffer[i] = 0;
+
+ soft += strlen ("softlevel=");
+ level = strsep (&soft, " ");
+ set_ksoftlevel (level);
+ }
+ }
+ fclose (fp);
+ }
+#endif
+ rc_plugin_run (rc_hook_runlevel_start_out, newlevel);
+
+ if (want_interactive ())
+ mark_interactive ();
+
+ exit (EXIT_SUCCESS);
+ }
+
+#ifdef __linux__
+ /* Parse the inittab file so we can work out the level to telinit */
+ if (strcmp (newlevel, RC_LEVEL_BOOT) != 0 &&
+ strcmp (newlevel, RC_LEVEL_SINGLE) != 0)
+ {
+ char **inittab = rc_get_list (NULL, "/etc/inittab");
+ char *line;
+ char *p;
+ char *token;
+ char lvl[2] = {0, 0};
+
+ STRLIST_FOREACH (inittab, line, i)
+ {
+ p = line;
+ token = strsep (&p, ":");
+ if (! token || token[0] != 'l')
+ continue;
+
+ if ((token = strsep (&p, ":")) == NULL)
+ continue;
+
+ /* Snag the level */
+ lvl[0] = token[0];
+
+ /* The name is spaced after this */
+ if ((token = strsep (&p, " ")) == NULL)
+ continue;
+
+ if ((token = strsep (&p, " ")) == NULL)
+ continue;
+
+ if (strcmp (token, newlevel) == 0)
+ break;
+ }
+ rc_strlist_free (inittab);
+
+ /* We have a level, so telinit into it */
+ if (lvl[0] == 0)
+ {
+ eerrorx ("%s: couldn't find a runlevel called `%s'",
+ applet, newlevel);
+ }
+ else
+ {
+ mycmd = rc_xstrdup ("/sbin/telinit");
+ myarg = rc_xstrdup (lvl);
+ execl (mycmd, mycmd, myarg, NULL);
+ eerrorx ("%s: unable to exec `/sbin/telinit': %s",
+ applet, strerror (errno));
+ }
+ }
+#endif
+ }
+ }
+
+ /* Check we're in the runlevel requested, ie from
+ rc single
+ rc shutdown
+ rc reboot
+ */
+ if (newlevel)
+ {
+ if (myarg)
+ {
+ free (myarg);
+ myarg = NULL;
+ }
+
+ if (strcmp (newlevel, RC_LEVEL_SINGLE) == 0)
+ {
+ if (! RUNLEVEL ||
+ (strcmp (RUNLEVEL, "S") != 0 &&
+ strcmp (RUNLEVEL, "1") != 0))
+ {
+ /* Remember the current runlevel for when we come back */
+ set_ksoftlevel (runlevel);
+#ifdef __linux__
+ mycmd = rc_xstrdup ("/sbin/telinit");
+ myarg = rc_xstrdup ("S");
+ execl (mycmd, mycmd, myarg, NULL);
+ eerrorx ("%s: unable to exec `/%s': %s",
+ mycmd, applet, strerror (errno));
+#else
+ if (kill (1, SIGTERM) != 0)
+ eerrorx ("%s: unable to send SIGTERM to init (pid 1): %s",
+ applet, strerror (errno));
+ exit (EXIT_SUCCESS);
+#endif
+ }
+ }
+ else if (strcmp (newlevel, RC_LEVEL_REBOOT) == 0)
+ {
+ if (! RUNLEVEL ||
+ strcmp (RUNLEVEL, "6") != 0)
+ {
+ mycmd = rc_xstrdup ("/sbin/shutdown");
+ myarg = rc_xstrdup ("-r");
+ tmp = rc_xstrdup ("now");
+ execl (mycmd, mycmd, myarg, tmp, NULL);
+ eerrorx ("%s: unable to exec `%s': %s",
+ mycmd, applet, strerror (errno));
+ }
+ }
+ else if (strcmp (newlevel, RC_LEVEL_SHUTDOWN) == 0)
+ {
+ if (! RUNLEVEL ||
+ strcmp (RUNLEVEL, "0") != 0)
+ {
+ mycmd = rc_xstrdup ("/sbin/shutdown");
+#ifdef __linux__
+ myarg = rc_xstrdup ("-h");
+#else
+ myarg = rc_xstrdup ("-p");
+#endif
+ tmp = rc_xstrdup ("now");
+ execl (mycmd, mycmd, myarg, tmp, NULL);
+ eerrorx ("%s: unable to exec `%s': %s",
+ mycmd, applet, strerror (errno));
+ }
+ }
+ }
+
+ /* Export our current softlevel */
+ runlevel = rc_get_runlevel ();
+
+ /* If we're in the default runlevel and ksoftlevel exists, we should use
+ that instead */
+ if (newlevel &&
+ rc_exists (RC_SVCDIR "ksoftlevel") &&
+ strcmp (newlevel, RC_LEVEL_DEFAULT) == 0)
+ {
+ /* We should only use ksoftlevel if we were in single user mode
+ If not, we need to erase ksoftlevel now. */
+ if (PREVLEVEL &&
+ (strcmp (PREVLEVEL, "1") == 0 ||
+ strcmp (PREVLEVEL, "S") == 0 ||
+ strcmp (PREVLEVEL, "N") == 0))
+ {
+ FILE *fp;
+
+ if (! (fp = fopen (RC_SVCDIR "ksoftlevel", "r")))
+ eerror ("fopen `%s': %s", RC_SVCDIR "ksoftlevel",
+ strerror (errno));
+ else
+ {
+ if (fgets (ksoftbuffer, sizeof (ksoftbuffer), fp))
+ {
+ i = strlen (ksoftbuffer) - 1;
+ if (ksoftbuffer[i] == '\n')
+ ksoftbuffer[i] = 0;
+ newlevel = ksoftbuffer;
+ }
+ fclose (fp);
+ }
+ }
+ else
+ set_ksoftlevel (NULL);
+ }
+
+ if (newlevel &&
+ (strcmp (newlevel, RC_LEVEL_REBOOT) == 0 ||
+ strcmp (newlevel, RC_LEVEL_SHUTDOWN) == 0 ||
+ strcmp (newlevel, RC_LEVEL_SINGLE) == 0))
+ {
+ going_down = true;
+ rc_set_runlevel (newlevel);
+ setenv ("RC_SOFTLEVEL", newlevel, 1);
+ rc_plugin_run (rc_hook_runlevel_stop_in, newlevel);
+ }
+ else
+ {
+ rc_plugin_run (rc_hook_runlevel_stop_in, runlevel);
+ }
+
+ /* Check if runlevel is valid if we're changing */
+ if (newlevel && strcmp (runlevel, newlevel) != 0 && ! going_down)
+ {
+ tmp = rc_strcatpaths (RC_RUNLEVELDIR, newlevel, NULL);
+ if (! rc_is_dir (tmp))
+ eerrorx ("%s: is not a valid runlevel", newlevel);
+ CHAR_FREE (tmp);
+ }
+
+ /* Load our deptree now */
+ if ((deptree = rc_load_deptree ()) == NULL)
+ eerrorx ("failed to load deptree");
+
+ /* Clean the failed services state dir now */
+ if (rc_is_dir (RC_SVCDIR "failed"))
+ rc_rm_dir (RC_SVCDIR "failed", false);
+
+ mkdir (RC_SVCDIR "/softscripts.new", 0755);
+
+#ifdef __linux__
+ /* udev likes to start services before we're ready when it does
+ its coldplugging thing. runscript knows when we're not ready so it
+ stores a list of coldplugged services in DEVBOOT for us to pick up
+ here when we are ready for them */
+ if (rc_is_dir (DEVBOOT))
+ {
+ start_services = rc_ls_dir (NULL, DEVBOOT, RC_LS_INITD);
+ rc_rm_dir (DEVBOOT, true);
+
+ STRLIST_FOREACH (start_services, service, i)
+ if (rc_allow_plug (service))
+ rc_mark_service (service, rc_service_coldplugged);
+ /* We need to dump this list now.
+ This may seem redunant, but only Linux needs this and saves on
+ code bloat. */
+ rc_strlist_free (start_services);
+ start_services = NULL;
+ }
+#else
+ /* BSD's on the other hand populate /dev automagically and use devd.
+ The only downside of this approach and ours is that we have to hard code
+ the device node to the init script to simulate the coldplug into
+ runlevel for our dependency tree to work. */
+ if (newlevel && strcmp (newlevel, RC_LEVEL_BOOT) == 0 &&
+ (strcmp (runlevel, RC_LEVEL_SINGLE) == 0 ||
+ strcmp (runlevel, RC_LEVEL_SYSINIT) == 0) &&
+ rc_is_env ("RC_COLDPLUG", "yes"))
+ {
+ /* The net interfaces are easy - they're all in net /dev/net :) */
+ start_services = rc_ls_dir (NULL, "/dev/net", 0);
+ STRLIST_FOREACH (start_services, service, i)
+ {
+ j = (strlen ("net.") + strlen (service) + 1);
+ tmp = rc_xmalloc (sizeof (char *) * j);
+ snprintf (tmp, j, "net.%s", service);
+ if (rc_service_exists (tmp) && rc_allow_plug (tmp))
+ rc_mark_service (tmp, rc_service_coldplugged);
+ CHAR_FREE (tmp);
+ }
+ rc_strlist_free (start_services);
+
+ /* The mice are a little more tricky.
+ If we coldplug anything else, we'll probably do it here. */
+ start_services = rc_ls_dir (NULL, "/dev", 0);
+ STRLIST_FOREACH (start_services, service, i)
+ {
+ if (strncmp (service, "psm", 3) == 0 ||
+ strncmp (service, "ums", 3) == 0)
+ {
+ char *p = service + 3;
+ if (p && isdigit (*p))
+ {
+ j = (strlen ("moused.") + strlen (service) + 1);
+ tmp = rc_xmalloc (sizeof (char *) * j);
+ snprintf (tmp, j, "moused.%s", service);
+ if (rc_service_exists (tmp) && rc_allow_plug (tmp))
+ rc_mark_service (tmp, rc_service_coldplugged);
+ CHAR_FREE (tmp);
+ }
+ }
+ }
+ rc_strlist_free (start_services);
+ start_services = NULL;
+ }
+#endif
+
+ /* Build a list of all services to stop and then work out the
+ correct order for stopping them */
+ stop_services = rc_ls_dir (stop_services, RC_SVCDIR_STARTING, RC_LS_INITD);
+ stop_services = rc_ls_dir (stop_services, RC_SVCDIR_INACTIVE, RC_LS_INITD);
+ stop_services = rc_ls_dir (stop_services, RC_SVCDIR_STARTED, RC_LS_INITD);
+
+ types = rc_strlist_add (NULL, "ineed");
+ types = rc_strlist_add (types, "iuse");
+ types = rc_strlist_add (types, "iafter");
+ deporder = rc_get_depends (deptree, types, stop_services,
+ runlevel, depoptions);
+ rc_strlist_free (stop_services);
+ rc_strlist_free (types);
+ stop_services = deporder;
+ deporder = NULL;
+ types = NULL;
+ rc_strlist_reverse (stop_services);
+
+ /* Load our list of coldplugged services */
+ coldplugged_services = rc_ls_dir (coldplugged_services,
+ RC_SVCDIR_COLDPLUGGED, RC_LS_INITD);
+
+ /* Load our start services now.
+ We have different rules dependent on runlevel. */
+ if (newlevel && strcmp (newlevel, RC_LEVEL_BOOT) == 0)
+ {
+ if (coldplugged_services)
+ {
+ einfon ("Device initiated services:");
+ STRLIST_FOREACH (coldplugged_services, service, i)
+ {
+ printf (" %s", service);
+ start_services = rc_strlist_add (start_services, service);
+ }
+ printf ("\n");
+ }
+ tmp = rc_strcatpaths (RC_RUNLEVELDIR, newlevel ? newlevel : runlevel, NULL);
+ start_services = rc_ls_dir (start_services, tmp, RC_LS_INITD);
+ CHAR_FREE (tmp);
+ }
+ else
+ {
+ /* Store our list of coldplugged services */
+ coldplugged_services = rc_ls_dir (coldplugged_services, RC_SVCDIR_COLDPLUGGED,
+ RC_LS_INITD);
+ if (strcmp (newlevel ? newlevel : runlevel, RC_LEVEL_SINGLE) != 0 &&
+ strcmp (newlevel ? newlevel : runlevel, RC_LEVEL_SHUTDOWN) != 0 &&
+ strcmp (newlevel ? newlevel : runlevel, RC_LEVEL_REBOOT) != 0)
+ {
+ /* We need to include the boot runlevel services if we're not in it */
+ start_services = rc_ls_dir (start_services, RC_RUNLEVELDIR RC_LEVEL_BOOT,
+ RC_LS_INITD);
+ STRLIST_FOREACH (coldplugged_services, service, i)
+ start_services = rc_strlist_add (start_services, service);
+
+ tmp = rc_strcatpaths (RC_RUNLEVELDIR,
+ newlevel ? newlevel : runlevel, NULL);
+ start_services = rc_ls_dir (start_services, tmp, RC_LS_INITD);
+ CHAR_FREE (tmp);
+ }
+ }
+
+ /* Save out softlevel now */
+ if (going_down)
+ rc_set_runlevel (newlevel);
+
+ types = rc_strlist_add (NULL, "needsme");
+ types = rc_strlist_add (types, "usesme");
+ /* Now stop the services that shouldn't be running */
+ STRLIST_FOREACH (stop_services, service, i)
+ {
+ bool found = false;
+ char *conf = NULL;
+ char **stopdeps = NULL;
+ char *svc1 = NULL;
+ char *svc2 = NULL;
+ int k;
+
+ if (rc_service_state (service, rc_service_stopped))
+ continue;
+
+ /* We always stop the service when in these runlevels */
+ if (going_down)
+ {
+ rc_stop_service (service);
+ continue;
+ }
+
+ /* If we're in the start list then don't bother stopping us */
+ STRLIST_FOREACH (start_services, svc1, j)
+ if (strcmp (svc1, service) == 0)
+ {
+ found = true;
+ break;
+ }
+
+ /* Unless we would use a different config file */
+ if (found)
+ {
+ if (! newlevel)
+ continue;
+
+ tmp = rc_xmalloc (strlen (service) + strlen (runlevel) + 2);
+ sprintf (tmp, "%s.%s", service, runlevel);
+ conf = rc_strcatpaths (RC_CONFDIR, tmp, NULL);
+ found = rc_exists (conf);
+ CHAR_FREE (conf);
+ CHAR_FREE (tmp);
+ if (! found)
+ {
+ tmp = rc_xmalloc (strlen (service) + strlen (newlevel) + 2);
+ sprintf (tmp, "%s.%s", service, newlevel);
+ conf = rc_strcatpaths (RC_CONFDIR, tmp, NULL);
+ found = rc_exists (conf);
+ CHAR_FREE (conf);
+ CHAR_FREE (tmp);
+ if (!found)
+ continue;
+ }
+ }
+ else
+ /* Allow coldplugged services not to be in the runlevels list */
+ {
+ if (rc_service_state (service, rc_service_coldplugged))
+ continue;
+ }
+
+ /* We got this far! Or last check is to see if any any service that
+ going to be started depends on us */
+ stopdeps = rc_strlist_add (stopdeps, service);
+ deporder = rc_get_depends (deptree, types, stopdeps,
+ runlevel, RC_DEP_STRICT);
+ rc_strlist_free (stopdeps);
+ stopdeps = NULL;
+ found = false;
+ STRLIST_FOREACH (deporder, svc1, j)
+ {
+ STRLIST_FOREACH (start_services, svc2, k)
+ if (strcmp (svc1, svc2) == 0)
+ {
+ found = true;
+ break;
+ }
+ if (found)
+ break;
+ }
+ rc_strlist_free (deporder);
+ deporder = NULL;
+
+ /* After all that we can finally stop the blighter! */
+ if (! found)
+ rc_stop_service (service);
+ }
+ rc_strlist_free (types);
+ types = NULL;
+
+ /* Wait for our services to finish */
+ if (rc_is_env ("RC_PARALLEL_STARTUP", "yes"))
+ wait_for_services ();
+
+ /* Notify the plugins we have finished */
+ rc_plugin_run (rc_hook_runlevel_stop_out, runlevel);
+
+ rmdir (RC_SVCDIR "/softscripts.new");
+
+ /* Store the new runlevel */
+ if (newlevel)
+ {
+ rc_set_runlevel (newlevel);
+ runlevel = newlevel;
+ setenv ("RC_SOFTLEVEL", runlevel, 1);
+ }
+
+ /* Run the halt script if needed */
+ if (strcmp (runlevel, RC_LEVEL_SHUTDOWN) == 0 ||
+ strcmp (runlevel, RC_LEVEL_REBOOT) == 0)
+ {
+ mycmd = rc_xstrdup (HALTSH);
+ myarg = rc_xstrdup (runlevel);
+ execl (mycmd, mycmd, myarg, NULL);
+ eerrorx ("%s: unable to exec `%s': %s",
+ applet, HALTSH, strerror (errno));
+ }
+
+ /* Single user is done now */
+ if (strcmp (runlevel, RC_LEVEL_SINGLE) == 0)
+ {
+ if (rc_exists (INTERACTIVE))
+ unlink (INTERACTIVE);
+ sulogin (false);
+ }
+
+ mkdir (RC_SVCDIR "/softscripts.old", 0755);
+ rc_plugin_run (rc_hook_runlevel_start_in, runlevel);
+
+ /* Re-add our coldplugged services if they stopped */
+ STRLIST_FOREACH (coldplugged_services, service, i)
+ rc_mark_service (service, rc_service_coldplugged);
+
+ /* Order the services to start */
+ types = rc_strlist_add (NULL, "ineed");
+ types = rc_strlist_add (types, "iuse");
+ types = rc_strlist_add (types, "iafter");
+ deporder = rc_get_depends (deptree, types, start_services,
+ runlevel, depoptions);
+ rc_strlist_free (types);
+ types = NULL;
+ rc_strlist_free (start_services);
+ start_services = deporder;
+ deporder = NULL;
+
+ STRLIST_FOREACH (start_services, service, i)
+ {
+ if (rc_service_state (service, rc_service_stopped))
+ {
+ if (! interactive)
+ interactive = want_interactive ();
+
+ if (interactive)
+ {
+interactive_retry:
+ printf ("\n");
+ einfo ("About to start the service %s", service);
+ eindent ();
+ einfo ("1) Start the service\t\t2) Skip the service");
+ einfo ("3) Continue boot process\t\t4) Exit to shell");
+ eoutdent ();
+interactive_option:
+ switch (read_key (true))
+ {
+ case '1': break;
+ case '2': continue;
+ case '3': interactive = false; break;
+ case '4': sulogin (true); goto interactive_retry;
+ default: goto interactive_option;
+ }
+ }
+ rc_start_service (service);
+ }
+ }
+
+ /* Wait for our services to finish */
+ if (rc_is_env ("RC_PARALLEL_STARTUP", "yes"))
+ wait_for_services ();
+
+ rc_plugin_run (rc_hook_runlevel_start_out, runlevel);
+
+ /* Store our interactive status for boot */
+ if (interactive && strcmp (runlevel, RC_LEVEL_BOOT) == 0)
+ mark_interactive ();
+ else
+ {
+ if (rc_exists (INTERACTIVE))
+ unlink (INTERACTIVE);
+ }
+
+ return (EXIT_SUCCESS);
+}
+
diff --git a/src/rc.h b/src/rc.h
new file mode 100644
index 00000000..3ba7cc56
--- /dev/null
+++ b/src/rc.h
@@ -0,0 +1,180 @@
+/*
+ rc.h
+ Header file for external applications to get RC information.
+ Copyright 2007 Gentoo Foundation
+ Released under the GPLv2
+ */
+
+#ifndef __RC_H__
+#define __RC_H__
+
+#include <sys/types.h>
+#include <stdbool.h>
+
+/* Special level names */
+#define RC_LEVEL_SYSINIT "sysinit"
+#define RC_LEVEL_BOOT "boot"
+#define RC_LEVEL_SINGLE "single"
+#define RC_LEVEL_SHUTDOWN "shutdown"
+#define RC_LEVEL_REBOOT "reboot"
+#define RC_LEVEL_DEFAULT "default"
+
+typedef enum
+{
+ rc_service_started,
+ rc_service_stopped,
+ rc_service_starting,
+ rc_service_stopping,
+ rc_service_inactive,
+ rc_service_wasinactive,
+ rc_service_coldplugged,
+ rc_service_failed,
+ rc_service_scheduled,
+ rc_service_crashed
+} rc_service_state_t;
+
+char *rc_resolve_service (const char *service);
+bool rc_service_exists (const char *service);
+bool rc_service_in_runlevel (const char *service, const char *runlevel);
+bool rc_service_state (const char *service, rc_service_state_t state);
+bool rc_mark_service (const char *service, rc_service_state_t state);
+pid_t rc_stop_service (const char *service);
+pid_t rc_start_service (const char *service);
+void rc_schedule_start_service (const char *service,
+ const char *service_to_start);
+char **rc_services_scheduled_by (const char *service);
+void rc_schedule_clear (const char *service);
+bool rc_wait_service (const char *service);
+bool rc_get_service_option (const char *service, const char *option,
+ char *value);
+bool rc_set_service_option (const char *service, const char *option,
+ const char *value);
+void rc_set_service_daemon (const char *service, const char *exec,
+ const char *name, const char *pidfile,
+ bool started);
+bool rc_service_started_daemon (const char *service, const char *exec,
+ int indx);
+
+bool rc_allow_plug (char *service);
+
+char *rc_get_runlevel (void);
+void rc_set_runlevel (const char *runlevel);
+bool rc_runlevel_exists (const char *runlevel);
+char **rc_get_runlevels (void);
+bool rc_runlevel_starting (void);
+bool rc_runlevel_stopping (void);
+bool rc_service_add (const char *runlevel, const char *service);
+bool rc_service_delete (const char *runlevel, const char *service);
+char **rc_services_in_runlevel (const char *runlevel);
+char **rc_services_in_state (rc_service_state_t state);
+char **rc_services_scheduled (const char *service);
+
+/* Find pids based on criteria - free the pointer returned after use */
+pid_t *rc_find_pids (const char *exec, const char *cmd,
+ uid_t uid, pid_t pid);
+/* Checks that all daemons started with start-stop-daemon by the service
+ are still running. If so, return false otherwise true.
+ You should check that the service has been started before calling this. */
+bool rc_service_daemons_crashed (const char *service);
+
+/* Dependency tree structs and functions. */
+typedef struct rc_deptype
+{
+ char *type;
+ char **services;
+ struct rc_deptype *next;
+} rc_deptype_t;
+
+typedef struct rc_depinfo
+{
+ char *service;
+ rc_deptype_t *depends;
+ struct rc_depinfo *next;
+} rc_depinfo_t;
+
+
+/* Options for rc_dep_depends and rc_order_services.
+ When changing runlevels, you should use RC_DEP_START and RC_DEP_STOP for
+ the start and stop lists as we tweak the provided services for this. */
+#define RC_DEP_TRACE 0x01
+#define RC_DEP_STRICT 0x02
+#define RC_DEP_START 0x04
+#define RC_DEP_STOP 0x08
+
+int rc_update_deptree (bool force);
+rc_depinfo_t *rc_load_deptree (void);
+rc_depinfo_t *rc_get_depinfo (rc_depinfo_t *deptree, const char *service);
+rc_deptype_t *rc_get_deptype (rc_depinfo_t *depinfo, const char *type);
+char **rc_get_depends (rc_depinfo_t *deptree, char **types,
+ char **services, const char *runlevel, int options);
+/* List all the services that should be started, in order, the the
+ given runlevel, including sysinit and boot services where
+ approriate.
+ If reboot, shutdown or single are given then we list all the services
+ we that we need to shutdown in order. */
+char **rc_order_services (rc_depinfo_t *deptree, const char *runlevel,
+ int options);
+
+void rc_free_deptree (rc_depinfo_t *deptree);
+
+/* Plugin handler
+ For each plugin loaded we will call it's _name_hook with the below
+ enum and either the runlevel name or service name. For example
+ int _splash_hook (rc_hook_t hook, const char *name);
+ Plugins are called when rc does something. This does not indicate an
+ end result and the plugin should use the above functions to query things
+ like service status. */
+typedef enum
+{
+ rc_hook_runlevel_stop_in = 1,
+ rc_hook_runlevel_stop_out,
+ rc_hook_runlevel_start_in,
+ rc_hook_runlevel_start_out,
+ rc_hook_service_stop_in,
+ rc_hook_service_stop_out,
+ rc_hook_service_start_in,
+ rc_hook_service_start_out
+} rc_hook_t;
+
+/* RC utility functions.
+ Although not directly related to RC in general, they are used by RC
+ itself and the supporting applications. */
+void *rc_xcalloc (size_t n, size_t size);
+void *rc_xmalloc (size_t size);
+void *rc_xrealloc (void *ptr, size_t size);
+char *rc_xstrdup (const char *str);
+
+/* Concat paths adding '/' if needed. */
+char *rc_strcatpaths (const char *path1, const char *paths, ...);
+
+bool rc_is_env (const char *variable, const char *value);
+bool rc_exists (const char *pathname);
+bool rc_is_file (const char *pathname);
+bool rc_is_link (const char *pathname);
+bool rc_is_dir (const char *pathname);
+bool rc_is_exec (const char *pathname);
+
+#define RC_LS_INITD 0x01
+char **rc_ls_dir (char **list, const char *dir, int options);
+
+bool rc_rm_dir (const char *pathname, bool top);
+
+/* Config file functions */
+char **rc_get_list (char **list, const char *file);
+char **rc_get_config (char **list, const char *file);
+char *rc_get_config_entry (char **list, const char *entry);
+
+/* Make an environment list which filters out all unwanted values
+ and loads it up with our RC config */
+char **rc_filter_env (void);
+char **rc_config_env (char **env);
+
+/* Handy functions for dealing with string arrays of char ** */
+char **rc_strlist_add (char **list, const char *item);
+char **rc_strlist_addsort (char **list, const char *item);
+char **rc_strlist_addsortc (char **list, const char *item);
+char **rc_strlist_delete (char **list, const char *item);
+void rc_strlist_reverse (char **list);
+void rc_strlist_free (char **list);
+
+#endif
diff --git a/src/runscript.c b/src/runscript.c
new file mode 100644
index 00000000..bca1195b
--- /dev/null
+++ b/src/runscript.c
@@ -0,0 +1,1097 @@
+/*
+ * runscript.c
+ * Handle launching of Gentoo init scripts.
+ *
+ * Copyright 1999-2007 Gentoo Foundation
+ * Distributed under the terms of the GNU General Public License v2
+ */
+
+#include <sys/types.h>
+#include <sys/signal.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifndef __linux__
+#include <libgen.h>
+#endif
+
+#include "einfo.h"
+#include "rc.h"
+#include "rc-misc.h"
+#include "rc-plugin.h"
+#include "strlist.h"
+
+#define RCSCRIPT_HELP RC_LIBDIR "/sh/rc-help.sh"
+#define SELINUX_LIB RC_LIBDIR "/runscript_selinux.so"
+
+static char *applet = NULL;
+static char *exclusive = NULL;
+static char *mtime_test = NULL;
+static rc_depinfo_t *deptree = NULL;
+static char **services = NULL;
+static char **svclist = NULL;
+static char **tmplist = NULL;
+static char **providelist = NULL;
+static char **types = NULL;
+static char **restart_services = NULL;
+static char **need_services = NULL;
+static char **env = NULL;
+static char *mycmd = NULL;
+static char *myarg1 = NULL;
+static char *myarg2 = NULL;
+static char *tmp = NULL;
+static char *softlevel = NULL;
+static bool sighup = false;
+static char *ibsave = NULL;
+static bool in_background = false;
+static rc_hook_t hook_out = 0;
+
+extern char **environ;
+
+#ifdef __linux__
+static void (*selinux_run_init_old) (void);
+static void (*selinux_run_init_new) (int argc, char **argv);
+
+void setup_selinux (int argc, char **argv);
+#endif
+
+#ifdef __linux__
+void setup_selinux (int argc, char **argv)
+{
+ void *lib_handle = NULL;
+
+ lib_handle = dlopen (SELINUX_LIB, RTLD_NOW | RTLD_GLOBAL);
+ if (lib_handle)
+ {
+ /* FIXME: the below code generates the warning
+ ISO C forbids assignment between function pointer and 'void *'
+ which sucks ass
+ http://www.opengroup.org/onlinepubs/009695399/functions/dlsym.html */
+ selinux_run_init_old = dlsym (lib_handle, "selinux_runscript");
+ selinux_run_init_new = dlsym (lib_handle, "selinux_runscript2");
+
+ /* Use new run_init if it rc_exists, else fall back to old */
+ if (selinux_run_init_new)
+ selinux_run_init_new (argc, argv);
+ else if (selinux_run_init_old)
+ selinux_run_init_old ();
+ else
+ /* This shouldnt happen... probably corrupt lib */
+ eerrorx ("run_init is missing from runscript_selinux.so!");
+ }
+}
+#endif
+
+static void handle_signal (int sig)
+{
+ pid_t pid;
+ int status;
+ int serrno = errno;
+
+ switch (sig)
+ {
+ case SIGHUP:
+ sighup = true;
+ break;
+
+ case SIGCHLD:
+ do
+ {
+ pid = waitpid (-1, &status, WNOHANG);
+ if (pid < 0)
+ {
+ if (errno != ECHILD)
+ eerror ("waitpid: %s", strerror (errno));
+ return;
+ }
+ } while (! WIFEXITED (status) && ! WIFSIGNALED (status));
+ break;
+
+ case SIGINT:
+ case SIGTERM:
+ case SIGQUIT:
+ eerrorx ("%s: caught signal %d, aborting", applet, sig);
+
+ default:
+ eerror ("%s: caught unknown signal %d", applet, sig);
+ }
+
+ /* Restore errno */
+ errno = serrno;
+}
+
+static time_t get_mtime (const char *pathname, bool follow_link)
+{
+ struct stat buf;
+ int retval;
+
+ if (! pathname)
+ return (0);
+
+ retval = follow_link ? stat (pathname, &buf) : lstat (pathname, &buf);
+ if (retval == 0)
+ return (buf.st_mtime);
+
+ errno = 0;
+ return (0);
+}
+
+static bool in_control ()
+{
+ char *path;
+ time_t mtime;
+ const char *tests[] = { "starting", "started", "stopping",
+ "inactive", "wasinactive", NULL };
+ int i = 0;
+
+ if (sighup)
+ return (false);
+
+ if (mtime_test == NULL || ! rc_exists (mtime_test))
+ return (false);
+
+ if (rc_service_state (applet, rc_service_stopped))
+ return (false);
+
+ if ((mtime = get_mtime (mtime_test, false)) == 0)
+ return (false);
+
+ while (tests[i])
+ {
+ path = rc_strcatpaths (RC_SVCDIR, tests[i], applet, NULL);
+ if (rc_exists (path))
+ {
+ int m = get_mtime (path, false);
+ if (mtime < m && m != 0)
+ {
+ free (path);
+ return (false);
+ }
+ }
+ free (path);
+ i++;
+ }
+
+ return (true);
+}
+
+static void uncoldplug (char *service)
+{
+ char *cold = rc_strcatpaths (RC_SVCDIR "coldplugged", basename (service), NULL);
+ if (rc_exists (cold) && unlink (cold) != 0)
+ eerror ("%s: unlink `%s': %s", applet, cold, strerror (errno));
+ free (cold);
+}
+
+static void cleanup (void)
+{
+ /* Flush our buffered output if any */
+ eflush ();
+
+ if (hook_out)
+ rc_plugin_run (hook_out, applet);
+ rc_plugin_unload ();
+
+ if (deptree)
+ rc_free_deptree (deptree);
+ if (services)
+ rc_strlist_free (services);
+ if (types)
+ rc_strlist_free (types);
+ if (svclist)
+ rc_strlist_free (svclist);
+ if (providelist)
+ rc_strlist_free (providelist);
+ if (restart_services)
+ rc_strlist_free (restart_services);
+ if (need_services)
+ rc_strlist_free (need_services);
+ if (mycmd)
+ free (mycmd);
+ if (myarg1)
+ free (myarg1);
+ if (myarg2)
+ free (myarg2);
+ if (ibsave)
+ free (ibsave);
+
+ if (in_control ())
+ {
+ if (rc_service_state (applet, rc_service_starting))
+ {
+ if (rc_service_state (applet, rc_service_wasinactive))
+ rc_mark_service (applet, rc_service_inactive);
+ else
+ rc_mark_service (applet, rc_service_stopped);
+ }
+ else if (rc_service_state (applet, rc_service_stopping))
+ {
+ /* If the we're shutting down, do it cleanly */
+ if ((softlevel && rc_runlevel_stopping () &&
+ (strcmp (softlevel, RC_LEVEL_SHUTDOWN) == 0 ||
+ strcmp (softlevel, RC_LEVEL_REBOOT) == 0)) ||
+ ! rc_service_state (applet, rc_service_wasinactive))
+ rc_mark_service (applet, rc_service_stopped);
+ else
+ rc_mark_service (applet, rc_service_inactive);
+ }
+ if (exclusive && rc_exists (exclusive))
+ unlink (exclusive);
+ }
+
+ if (env)
+ rc_strlist_free (env);
+
+ if (mtime_test)
+ {
+ unlink (mtime_test);
+ free (mtime_test);
+ }
+ if (exclusive)
+ free (exclusive);
+
+ if (applet)
+ free (applet);
+}
+
+static bool svc_exec (const char *service, const char *arg1, const char *arg2)
+{
+ int status = 0;
+ pid_t pid;
+
+ /* We need to disable our child signal handler now so we block
+ until our script returns. */
+ signal (SIGCHLD, NULL);
+
+ pid = fork();
+
+ if (pid == -1)
+ eerrorx ("%s: fork: %s", service, strerror (errno));
+ if (pid == 0)
+ {
+ mycmd = rc_xstrdup (service);
+ myarg1 = rc_xstrdup (arg1);
+ if (arg2)
+ myarg2 = rc_xstrdup (arg2);
+
+ if (rc_exists (RC_SVCDIR "runscript.sh"))
+ {
+ execl (RC_SVCDIR "runscript.sh", mycmd, mycmd, myarg1, myarg2, NULL);
+ eerrorx ("%s: exec `" RC_SVCDIR "runscript.sh': %s",
+ service, strerror (errno));
+ }
+ else
+ {
+ execl (RC_LIBDIR "sh/runscript.sh", mycmd, mycmd, myarg1, myarg2, NULL);
+ eerrorx ("%s: exec `" RC_LIBDIR "sh/runscript.sh': %s",
+ service, strerror (errno));
+ }
+ }
+
+ do
+ {
+ if (waitpid (pid, &status, 0) < 0)
+ {
+ if (errno != ECHILD)
+ eerror ("waitpid: %s", strerror (errno));
+ break;
+ }
+ } while (! WIFEXITED (status) && ! WIFSIGNALED (status));
+
+ /* Done, so restore the signal handler */
+ signal (SIGCHLD, handle_signal);
+
+ if (WIFEXITED (status))
+ return (WEXITSTATUS (status) == 0 ? true : false);
+
+ return (false);
+}
+
+static rc_service_state_t svc_status (const char *service)
+{
+ char status[10];
+ int (*e) (const char *fmt, ...) = &einfo;
+
+ rc_service_state_t retval = rc_service_stopped;
+
+ if (rc_service_state (service, rc_service_stopping))
+ {
+ snprintf (status, sizeof (status), "stopping");
+ e = &ewarn;
+ retval = rc_service_stopping;
+ }
+ else if (rc_service_state (service, rc_service_starting))
+ {
+ snprintf (status, sizeof (status), "starting");
+ e = &ewarn;
+ retval = rc_service_starting;
+ }
+ else if (rc_service_state (service, rc_service_inactive))
+ {
+ snprintf (status, sizeof (status), "inactive");
+ e = &ewarn;
+ retval = rc_service_inactive;
+ }
+ else if (rc_service_state (service, rc_service_crashed))
+ {
+ snprintf (status, sizeof (status), "crashed");
+ e = &eerror;
+ retval = rc_service_crashed;
+ }
+ else if (rc_service_state (service, rc_service_started))
+ {
+ snprintf (status, sizeof (status), "started");
+ retval = rc_service_started;
+ }
+ else
+ snprintf (status, sizeof (status), "stopped");
+
+ e ("status: %s", status);
+ return (retval);
+}
+
+static void make_exclusive (const char *service)
+{
+ char *path;
+ int i;
+
+ /* We create a fifo so that other services can wait until we complete */
+ if (! exclusive)
+ exclusive = rc_strcatpaths (RC_SVCDIR, "exclusive", applet, NULL);
+
+ if (mkfifo (exclusive, 0600) != 0 && errno != EEXIST &&
+ (errno != EACCES || geteuid () == 0))
+ eerrorx ("%s: unable to create fifo `%s': %s",
+ applet, exclusive, strerror (errno));
+
+ path = rc_strcatpaths (RC_SVCDIR, "exclusive", applet, NULL);
+ i = strlen (path) + 16;
+ mtime_test = rc_xmalloc (sizeof (char *) * i);
+ snprintf (mtime_test, i, "%s.%d", path, getpid ());
+ free (path);
+
+ if (rc_exists (mtime_test) && unlink (mtime_test) != 0)
+ {
+ eerror ("%s: unlink `%s': %s",
+ applet, mtime_test, strerror (errno));
+ free (mtime_test);
+ mtime_test = NULL;
+ return;
+ }
+
+ if (symlink (service, mtime_test) != 0)
+ {
+ eerror ("%s: symlink `%s' to `%s': %s",
+ applet, service, mtime_test, strerror (errno));
+ free (mtime_test);
+ mtime_test = NULL;
+ }
+}
+
+static void unlink_mtime_test ()
+{
+ if (unlink (mtime_test) != 0)
+ eerror ("%s: unlink `%s': %s", applet, mtime_test, strerror (errno));
+ free (mtime_test);
+ mtime_test = NULL;
+}
+
+static void get_started_services ()
+{
+ char *service;
+ int i;
+
+ rc_strlist_free (tmplist);
+ tmplist = rc_services_in_state (rc_service_inactive);
+
+ rc_strlist_free (restart_services);
+ restart_services = rc_services_in_state (rc_service_started);
+
+ STRLIST_FOREACH (tmplist, service, i)
+ restart_services = rc_strlist_addsort (restart_services, service);
+
+ rc_strlist_free (tmplist);
+ tmplist = NULL;
+}
+
+static void svc_start (const char *service, bool deps)
+{
+ bool started;
+ bool background = false;
+ char *svc;
+ char *svc2;
+ int i;
+ int j;
+ int depoptions = RC_DEP_TRACE;
+
+ if (rc_is_env ("RC_STRICT_DEPEND", "yes"))
+ depoptions |= RC_DEP_STRICT;
+
+ if (rc_is_env ("IN_HOTPLUG", "1") || in_background)
+ {
+ if (! rc_service_state (service, rc_service_inactive))
+ exit (EXIT_FAILURE);
+ background = true;
+ }
+
+ if (rc_service_state (service, rc_service_started))
+ ewarnx ("WARNING: %s has already been started", applet);
+ else if (rc_service_state (service, rc_service_starting))
+ ewarnx ("WARNING: %s is already starting", applet);
+ else if (rc_service_state (service, rc_service_stopping))
+ ewarnx ("WARNING: %s is stopping", applet);
+ else if (rc_service_state (service, rc_service_inactive) && ! background)
+ ewarnx ("WARNING: %s has already started, but is inactive", applet);
+
+ if (! rc_mark_service (service, rc_service_starting))
+ eerrorx ("ERROR: %s has been started by something else", applet);
+
+ make_exclusive (service);
+
+ if (deps)
+ {
+ if (! deptree && ((deptree = rc_load_deptree ()) == NULL))
+ eerrorx ("failed to load deptree");
+
+ rc_strlist_free (types);
+ types = rc_strlist_add (NULL, "broken");
+ rc_strlist_free (svclist);
+ svclist = rc_strlist_add (NULL, applet);
+ rc_strlist_free (services);
+ services = rc_get_depends (deptree, types, svclist, softlevel, 0);
+ if (services)
+ {
+ eerrorn ("ERROR: `%s' needs ", applet);
+ STRLIST_FOREACH (services, svc, i)
+ {
+ if (i > 0)
+ fprintf (stderr, ", ");
+ fprintf (stderr, "%s", svc);
+ }
+ exit (EXIT_FAILURE);
+ }
+ rc_strlist_free (services);
+ services = NULL;
+
+ rc_strlist_free (types);
+ types = rc_strlist_add (NULL, "ineed");
+ rc_strlist_free (need_services);
+ need_services = rc_get_depends (deptree, types, svclist,
+ softlevel, depoptions);
+ types = rc_strlist_add (types, "iuse");
+ if (! rc_runlevel_starting ())
+ {
+ services = rc_get_depends (deptree, types, svclist,
+ softlevel, depoptions);
+ STRLIST_FOREACH (services, svc, i)
+ if (rc_service_state (svc, rc_service_stopped))
+ rc_start_service (svc);
+
+ rc_strlist_free (services);
+ }
+
+ /* Now wait for them to start */
+ types = rc_strlist_add (types, "iafter");
+ services = rc_get_depends (deptree, types, svclist,
+ softlevel, depoptions);
+
+ /* We use tmplist to hold our scheduled by list */
+ rc_strlist_free (tmplist);
+ tmplist = NULL;
+
+ STRLIST_FOREACH (services, svc, i)
+ {
+ if (rc_service_state (svc, rc_service_started))
+ continue;
+ if (! rc_wait_service (svc))
+ { eerror ("%s: timed out waiting for %s", applet, svc);
+ system ("ps ax > /tmp/$SVCNAME.waiting"); }
+ if (rc_service_state (svc, rc_service_started))
+ continue;
+
+ STRLIST_FOREACH (need_services, svc2, j)
+ if (strcmp (svc, svc2) == 0)
+ {
+ if (rc_service_state (svc, rc_service_inactive) ||
+ rc_service_state (svc, rc_service_wasinactive))
+ tmplist = rc_strlist_add (tmplist, svc);
+ else
+ eerrorx ("ERROR: cannot start %s as %s would not start",
+ applet, svc);
+ }
+ }
+
+ if (tmplist)
+ {
+ int n = 0;
+ int len = 0;
+ char *p;
+
+ /* Set the state now, then unlink our exclusive so that
+ our scheduled list is preserved */
+ rc_mark_service (service, rc_service_stopped);
+ unlink_mtime_test ();
+
+ rc_strlist_free (types);
+ types = rc_strlist_add (NULL, "iprovide");
+ STRLIST_FOREACH (tmplist, svc, i)
+ {
+ rc_schedule_start_service (svc, service);
+
+ rc_strlist_free (svclist);
+ svclist = rc_strlist_add (NULL, svc);
+ rc_strlist_free (providelist);
+ providelist = rc_get_depends (deptree, types, svclist,
+ softlevel, depoptions);
+ STRLIST_FOREACH (providelist, svc2, j)
+ rc_schedule_start_service (svc2, service);
+
+ len += strlen (svc) + 2;
+ n++;
+ }
+
+ tmp = rc_xmalloc (sizeof (char *) * len + 5);
+ p = tmp;
+ STRLIST_FOREACH (tmplist, svc, i)
+ {
+ if (i > 1)
+ {
+ if (i == n - 1)
+ p += sprintf (p, " or ");
+ else
+ p += sprintf (p, ", ");
+ }
+ p += sprintf (p, "%s", svc);
+ }
+ ewarnx ("WARNING: %s is scheduled to start when %s has started",
+ applet, tmp);
+ }
+
+ rc_strlist_free (services);
+ services = NULL;
+ rc_strlist_free (types);
+ types = NULL;
+ rc_strlist_free (svclist);
+ svclist = NULL;
+ }
+
+ if (ibsave)
+ setenv ("IN_BACKGROUND", ibsave, 1);
+ rc_plugin_run (rc_hook_service_start_in, applet);
+ hook_out = rc_hook_service_start_out;
+ started = svc_exec (service, "start", NULL);
+ if (ibsave)
+ unsetenv ("IN_BACKGROUND");
+
+ if (in_control ())
+ {
+ if (! started)
+ {
+ if (rc_service_state (service, rc_service_wasinactive))
+ rc_mark_service (service, rc_service_inactive);
+ else
+ {
+ rc_mark_service (service, rc_service_stopped);
+ if (rc_runlevel_starting ())
+ rc_mark_service (service, rc_service_failed);
+ }
+ eerrorx ("ERROR: %s failed to start", applet);
+ }
+
+ rc_mark_service (service, rc_service_started);
+ unlink_mtime_test ();
+
+ hook_out = 0;
+ rc_plugin_run (rc_hook_service_start_out, applet);
+ }
+ else
+ {
+ if (rc_service_state (service, rc_service_inactive))
+ ewarn ("WARNING: %s has started, but is inactive", applet);
+ else
+ ewarn ("WARNING: %s not under our control, aborting", applet);
+ }
+
+ /* Now start any scheduled services */
+ rc_strlist_free (services);
+ services = rc_services_scheduled (service);
+ STRLIST_FOREACH (services, svc, i)
+ if (rc_service_state (svc, rc_service_stopped))
+ rc_start_service (svc);
+ rc_strlist_free (services);
+ services = NULL;
+
+ /* Do the same for any services we provide */
+ rc_strlist_free (types);
+ types = rc_strlist_add (NULL, "iprovide");
+ rc_strlist_free (svclist);
+ svclist = rc_strlist_add (NULL, applet);
+ rc_strlist_free (tmplist);
+ tmplist = rc_get_depends (deptree, types, svclist, softlevel, depoptions);
+
+ STRLIST_FOREACH (tmplist, svc2, j)
+ {
+ rc_strlist_free (services);
+ services = rc_services_scheduled (svc2);
+ STRLIST_FOREACH (services, svc, i)
+ if (rc_service_state (svc, rc_service_stopped))
+ rc_start_service (svc);
+ }
+}
+
+static void svc_stop (const char *service, bool deps)
+{
+ bool stopped;
+
+ if (rc_runlevel_stopping () &&
+ rc_service_state (service, rc_service_failed))
+ exit (EXIT_FAILURE);
+
+ if (rc_is_env ("IN_HOTPLUG", "1") || in_background)
+ if (! rc_service_state (service, rc_service_started))
+ exit (EXIT_FAILURE);
+
+ if (rc_service_state (service, rc_service_stopped))
+ ewarnx ("WARNING: %s is already stopped", applet);
+ else if (rc_service_state (service, rc_service_stopping))
+ ewarnx ("WARNING: %s is already stopping", applet);
+
+ if (! rc_mark_service (service, rc_service_stopping))
+ eerrorx ("ERROR: %s has been stopped by something else", applet);
+
+ make_exclusive (service);
+
+ if (! rc_runlevel_stopping () &&
+ rc_service_in_runlevel (service, RC_LEVEL_BOOT))
+ ewarn ("WARNING: you are stopping a boot service");
+
+ if (deps || ! rc_service_state (service, rc_service_wasinactive))
+ {
+ int depoptions = RC_DEP_TRACE;
+ char *svc;
+ int i;
+
+ if (rc_is_env ("RC_STRICT_DEPEND", "yes"))
+ depoptions |= RC_DEP_STRICT;
+
+ if (! deptree && ((deptree = rc_load_deptree ()) == NULL))
+ eerrorx ("failed to load deptree");
+
+ rc_strlist_free (types);
+ types = rc_strlist_add (NULL, "needsme");
+ rc_strlist_free (svclist);
+ svclist = rc_strlist_add (NULL, applet);
+ rc_strlist_free (tmplist);
+ tmplist = NULL;
+ rc_strlist_free (services);
+ services = rc_get_depends (deptree, types, svclist,
+ softlevel, depoptions);
+ rc_strlist_reverse (services);
+ STRLIST_FOREACH (services, svc, i)
+ {
+ if (rc_service_state (svc, rc_service_started) ||
+ rc_service_state (svc, rc_service_inactive))
+ {
+ rc_wait_service (svc);
+ if (rc_service_state (svc, rc_service_started) ||
+ rc_service_state (svc, rc_service_inactive))
+ {
+ rc_stop_service (svc);
+ tmplist = rc_strlist_add (tmplist, svc);
+ }
+ }
+ }
+ rc_strlist_free (services);
+ services = NULL;
+
+ STRLIST_FOREACH (tmplist, svc, i)
+ {
+ if (rc_service_state (svc, rc_service_stopped))
+ continue;
+
+ /* We used to loop 3 times here - maybe re-do this if needed */
+ rc_wait_service (svc);
+ if (! rc_service_state (svc, rc_service_stopped))
+ {
+ if (rc_runlevel_stopping ())
+ rc_mark_service (svc, rc_service_failed);
+ eerrorx ("ERROR: cannot stop %s as %s is still up",
+ applet, svc);
+ }
+ }
+ rc_strlist_free (tmplist);
+ tmplist = NULL;
+
+ /* We now wait for other services that may use us and are stopping
+ This is important when a runlevel stops */
+ types = rc_strlist_add (types, "usesme");
+ types = rc_strlist_add (types, "ibefore");
+ services = rc_get_depends (deptree, types, svclist,
+ softlevel, depoptions);
+ STRLIST_FOREACH (services, svc, i)
+ {
+ if (rc_service_state (svc, rc_service_stopped))
+ continue;
+ rc_wait_service (svc);
+ }
+
+ rc_strlist_free (services);
+ services = NULL;
+ rc_strlist_free (types);
+ types = NULL;
+ }
+
+ if (ibsave)
+ setenv ("IN_BACKGROUND", ibsave, 1);
+ rc_plugin_run (rc_hook_service_stop_in, applet);
+ hook_out = rc_hook_service_stop_out;
+ stopped = svc_exec (service, "stop", NULL);
+ if (ibsave)
+ unsetenv ("IN_BACKGROUND");
+
+ if (! in_control ())
+ ewarnx ("WARNING: %s not under our control, aborting", applet);
+
+ if (! stopped)
+ {
+ if (rc_service_state (service, rc_service_wasinactive))
+ rc_mark_service (service, rc_service_inactive);
+ else
+ rc_mark_service (service, rc_service_stopped);
+ eerrorx ("ERROR: %s failed to stop", applet);
+ }
+
+ if (in_background)
+ rc_mark_service (service, rc_service_inactive);
+ else
+ rc_mark_service (service, rc_service_stopped);
+
+ unlink_mtime_test ();
+ hook_out = 0;
+ rc_plugin_run (rc_hook_service_stop_out, applet);
+}
+
+static void svc_restart (const char *service, bool deps)
+{
+ char *svc;
+ int i;
+ bool inactive = false;
+
+ /* This is hairly and a better way needs to be found I think!
+ The issue is this - openvpn need net and dns. net can restart
+ dns via resolvconf, so you could have openvpn trying to restart dnsmasq
+ which in turn is waiting on net which in turn is waiting on dnsmasq.
+ The work around is for resolvconf to restart it's services with --nodeps
+ which means just that. The downside is that there is a small window when
+ our status is invalid.
+ One workaround would be to introduce a new status, or status locking. */
+ if (! deps)
+ {
+ if (rc_service_state (service, rc_service_started) ||
+ rc_service_state (service, rc_service_inactive))
+ svc_exec (service, "stop", "start");
+ else
+ svc_exec (service, "start", NULL);
+ return;
+ }
+
+ if (! rc_service_state (service, rc_service_stopped))
+ {
+ get_started_services ();
+ svc_stop (service, deps);
+
+ /* Flush our buffered output if any */
+ eflush ();
+ }
+
+ svc_start (service, deps);
+
+ inactive = rc_service_state (service, rc_service_inactive);
+ if (! inactive)
+ inactive = rc_service_state (service, rc_service_wasinactive);
+
+ if (inactive ||
+ rc_service_state (service, rc_service_starting) ||
+ rc_service_state (service, rc_service_started))
+ {
+ STRLIST_FOREACH (restart_services, svc, i)
+ {
+ if (rc_service_state (svc, rc_service_stopped))
+ {
+ if (inactive)
+ {
+ rc_schedule_start_service (service, svc);
+ ewarn ("WARNING: %s is scheduled to started when %s has started",
+ svc, basename (service));
+ }
+ else
+ rc_start_service (svc);
+ }
+ }
+ }
+}
+
+int main (int argc, char **argv)
+{
+ const char *service = argv[1];
+ int i;
+ bool deps = true;
+ bool doneone = false;
+ char pid[16];
+ int retval;
+ bool ifstarted = false;
+
+ applet = strdup (basename (service));
+ atexit (cleanup);
+
+ /* Show help if insufficient args */
+ if (argc < 3)
+ {
+ execl (RCSCRIPT_HELP, RCSCRIPT_HELP, service, NULL);
+ eerrorx ("%s: failed to exec `" RCSCRIPT_HELP "': %s",
+ applet, strerror (errno));
+ }
+
+#ifdef __linux__
+ /* coldplug events can trigger init scripts, but we don't want to run them
+ until after rc sysinit has completed so we punt them to the boot runlevel */
+ if (rc_exists ("/dev/.rcsysinit"))
+ {
+ eerror ("%s: cannot run until sysvinit completes", applet);
+ if (mkdir ("/dev/.rcboot", 0755) != 0 && errno != EEXIST)
+ eerrorx ("%s: mkdir `/dev/.rcboot': %s", applet, strerror (errno));
+ tmp = rc_strcatpaths ("/dev/.rcboot", applet, NULL);
+ symlink (service, tmp);
+ exit (EXIT_FAILURE);
+ }
+#endif
+
+ if ((softlevel = getenv ("RC_SOFTLEVEL")) == NULL)
+ {
+ /* Ensure our environment is pure
+ Also, add our configuration to it */
+ env = rc_filter_env ();
+ env = rc_config_env (env);
+
+ if (env)
+ {
+ char *p;
+
+#ifdef __linux__
+ /* clearenv isn't portable, but there's no harm in using it
+ if we have it */
+ clearenv ();
+#else
+ char *var;
+ /* No clearenv present here then.
+ We could manipulate environ directly ourselves, but it seems that
+ some kernels bitch about this according to the environ man pages
+ so we walk though environ and call unsetenv for each value. */
+ while (environ[0])
+ {
+ tmp = rc_xstrdup (environ[0]);
+ p = tmp;
+ var = strsep (&p, "=");
+ unsetenv (var);
+ free (tmp);
+ }
+ tmp = NULL;
+#endif
+
+ STRLIST_FOREACH (env, p, i)
+ putenv (p);
+
+ /* We don't free our list as that would be null in environ */
+ }
+
+ softlevel = rc_get_runlevel ();
+
+ /* If not called from RC or another service then don't be parallel */
+ unsetenv ("RC_PARALLEL_STARTUP");
+ }
+
+ setenv ("RC_ELOG", service, 1);
+ setenv ("SVCNAME", applet, 1);
+
+ /* Set an env var so that we always know our pid regardless of any
+ subshells the init script may create so that our mark_service_*
+ functions can always instruct us of this change */
+ snprintf (pid, sizeof (pid), "%d", (int) getpid ());
+ setenv ("RC_RUNSCRIPT_PID", pid, 1);
+
+ if (rc_is_env ("RC_PARALLEL_STARTUP", "yes"))
+ {
+ char ebname[PATH_MAX];
+ char *eb;
+
+ snprintf (ebname, sizeof (ebname), "%s.%s", applet, pid);
+ eb = rc_strcatpaths (RC_SVCDIR "ebuffer", ebname, NULL);
+ setenv ("RC_EBUFFER", eb, 1);
+ free (eb);
+ }
+
+ /* Save the IN_BACKGROUND env flag so it's ONLY passed to the service
+ that is being called and not any dependents */
+ if (getenv ("IN_BACKGROUND"))
+ {
+ in_background = rc_is_env ("IN_BACKGROUND", "true");
+ ibsave = strdup (getenv ("IN_BACKGROUND"));
+ unsetenv ("IN_BACKGROUND");
+
+ /* Don't hang around */
+ if (in_background)
+ setenv ("RC_PARALLEL_STARTUP", "yes", 1);
+ }
+
+#ifdef __linux__
+ /* Ok, we are ready to go, so setup selinux if applicable */
+ setup_selinux (argc, argv);
+#endif
+
+ /* Right then, parse any options there may be */
+ for (i = 2; i < argc; i++)
+ {
+ if (strlen (argv[i]) < 2 || argv[i][0] != '-' || argv[i][1] != '-')
+ continue;
+
+ if (strcmp (argv[i], "--debug") == 0)
+ setenv ("RC_DEBUG", "yes", 1);
+ else if (strcmp (argv[i], "--help") == 0)
+ {
+ execl (RCSCRIPT_HELP, RCSCRIPT_HELP, service, NULL);
+ eerrorx ("%s: failed to exec `" RCSCRIPT_HELP "': %s",
+ applet, strerror (errno));
+ }
+ else if (strcmp (argv[i],"--ifstarted") == 0)
+ ifstarted = true;
+ else if (strcmp (argv[i], "--nocolour") == 0 ||
+ strcmp (argv[i], "--nocolor") == 0)
+ setenv ("RC_NOCOLOR", "yes", 1);
+ else if (strcmp (argv[i], "--nodeps") == 0)
+ deps = false;
+ else if (strcmp (argv[i], "--quiet") == 0)
+ setenv ("RC_QUIET", "yes", 1);
+ else if (strcmp (argv[i], "--verbose") == 0)
+ setenv ("RC_VERBOSE", "yes", 1);
+ else if (strcmp (argv[i], "--version") == 0)
+ printf ("version me\n");
+ else
+ eerror ("%s: unknown option `%s'", applet, argv[i]);
+ }
+
+ if (ifstarted && ! rc_service_state (applet, rc_service_started))
+ {
+ if (! rc_is_env("RC_QUIET", "yes"))
+ eerror ("ERROR: %s is not started", applet);
+ exit (EXIT_FAILURE);
+ }
+
+ if (rc_is_env ("IN_HOTPLUG", "1"))
+ {
+ if (! rc_is_env ("RC_HOTPLUG", "yes") || ! rc_allow_plug (applet))
+ eerrorx ("%s: not allowed to be hotplugged", applet);
+ }
+
+ /* Setup a signal handler */
+ signal (SIGHUP, handle_signal);
+ signal (SIGINT, handle_signal);
+ signal (SIGQUIT, handle_signal);
+ signal (SIGTERM, handle_signal);
+ signal (SIGCHLD, handle_signal);
+
+ /* Load our plugins */
+ rc_plugin_load ();
+
+ /* Now run each option */
+ retval = EXIT_SUCCESS;
+ for (i = 2; i < argc; i++)
+ {
+ /* Abort on a sighup here */
+ if (sighup)
+ exit (EXIT_FAILURE);
+
+ if (strlen (argv[i]) < 2 ||
+ (argv[i][0] == '-' && argv[i][1] == '-'))
+ continue;
+
+ /* Export the command we're running.
+ This is important as we stamp on the restart function now but
+ some start/stop routines still need to behave differently if
+ restarting. */
+ unsetenv ("RC_CMD");
+ setenv ("RC_CMD", argv[i], 1);
+
+ doneone = true;
+ if (strcmp (argv[i], "conditionalrestart") == 0 ||
+ strcmp (argv[i], "condrestart") == 0)
+ {
+ if (rc_service_state (service, rc_service_started))
+ svc_restart (service, deps);
+ }
+ else if (strcmp (argv[i], "restart") == 0)
+ svc_restart (service, deps);
+ else if (strcmp (argv[i], "start") == 0)
+ svc_start (service, deps);
+ else if (strcmp (argv[i], "status") == 0)
+ {
+ rc_service_state_t r = svc_status (service);
+ retval = (int) r;
+ }
+ else if (strcmp (argv[i], "stop") == 0)
+ {
+ if (in_background)
+ get_started_services ();
+ else if (! rc_runlevel_stopping ())
+ uncoldplug (applet);
+
+ svc_stop (service, deps);
+
+ if (in_background &&
+ rc_service_state (service, rc_service_inactive))
+ {
+ char *svc;
+ int j;
+ STRLIST_FOREACH (restart_services, svc, j)
+ if (rc_service_state (svc, rc_service_stopped))
+ rc_schedule_start_service (service, svc);
+ }
+ }
+ else if (strcmp (argv[i], "zap") == 0)
+ {
+ einfo ("Manually resetting %s to stopped state", applet);
+ rc_mark_service (applet, rc_service_stopped);
+ uncoldplug (applet);
+ }
+ else if (strcmp (argv[i], "help") == 0)
+ {
+ execl (RCSCRIPT_HELP, RCSCRIPT_HELP, service, "help", NULL);
+ eerrorx ("%s: failed to exec `" RCSCRIPT_HELP "': %s",
+ applet, strerror (errno));
+ }
+ else
+ svc_exec (service, argv[i], NULL);
+
+ /* Flush our buffered output if any */
+ eflush ();
+
+ /* We should ensure this list is empty after an action is done */
+ rc_strlist_free (restart_services);
+ restart_services = NULL;
+ }
+
+ if (! doneone)
+ {
+ execl (RCSCRIPT_HELP, RCSCRIPT_HELP, service, NULL);
+ eerrorx ("%s: failed to exec `" RCSCRIPT_HELP "': %s",
+ applet, strerror (errno));
+ }
+
+ return (retval);
+}
diff --git a/src/splash.c b/src/splash.c
new file mode 100644
index 00000000..3a4edfd9
--- /dev/null
+++ b/src/splash.c
@@ -0,0 +1,130 @@
+/*
+ splash.c
+
+ Splash plugin for the Gentoo RC sytsem.
+ splashutils needs to be re-written to support our new system.
+ Until then, we provide this compatible module which calls the
+ legacy bash scripts which is nasty. And slow.
+
+ For any themes that use scripts, such as the live-cd theme,
+ they will have to source /sbin/splash-functions.sh themselves like so
+
+ if ! type splash >/dev/null 2>/dev/null ; then
+ . /sbin/splash-functions.sh
+ fi
+
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <rc.h>
+
+#ifndef LIBDIR
+# define LIBDIR "lib"
+#endif
+
+#define SPLASH_CACHEDIR "/" LIBDIR "/splash/cache"
+
+#define SPLASH_CMD "bash -c 'export SOFTLEVEL='%s'; export BOOTLEVEL=${RC_BOOTLEVEL}; export DEFAULTLEVEL=${RC_DEFAULTLEVEL}; export svcdir=${RC_SVCDIR}; add_suffix() { echo \"$@\"; }; . /etc/init.d/functions.sh; . /sbin/splash-functions.sh; splash %s %s %s'"
+
+int _splash_hook (rc_hook_t hook, const char *name);
+
+static int _do_splash (const char *cmd, const char *arg1, const char *arg2)
+{
+ char *c;
+ int l;
+ char *soft = getenv ("RC_SOFTLEVEL");
+
+ if (! cmd || ! soft)
+ return (-1);
+
+ l = strlen (SPLASH_CMD) + strlen (soft) + strlen (cmd);
+ if (arg1)
+ l += strlen (arg1);
+ if (arg2)
+ l += strlen (arg2);
+ c = malloc (sizeof (char *) * l);
+ if (! c)
+ return (-1);
+
+ snprintf (c, l, SPLASH_CMD,
+ arg1 ? strcmp (arg1, RC_LEVEL_SYSINIT) == 0 ? RC_LEVEL_BOOT : soft : soft,
+ cmd, arg1 ? arg1 : "", arg2 ? arg2 : "");
+ l = system (c);
+ free (c);
+ return (l);
+}
+
+int _splash_hook (rc_hook_t hook, const char *name)
+{
+ switch (hook)
+ {
+ case rc_hook_runlevel_stop_in:
+ if (strcmp (name, RC_LEVEL_SYSINIT) != 0)
+ return (_do_splash ("rc_init", name, NULL));
+ break;
+ case rc_hook_runlevel_start_out:
+ if (strcmp (name, RC_LEVEL_SYSINIT) == 0)
+ return (_do_splash ("rc_init", name, NULL));
+ else
+ return (_do_splash ("rc_exit", name, NULL));
+ default: ;
+ }
+
+ /* We don't care about splash unless we're changing runlevels */
+ if (! rc_runlevel_starting () &&
+ ! rc_runlevel_stopping ())
+ return (0);
+
+ switch (hook)
+ {
+ case rc_hook_service_stop_in:
+ /* We need to stop localmount from unmounting our cache dir.
+ Luckily plugins can add to the unmount list. */
+ if (name && strcmp (name, "localmount") == 0)
+ {
+ char *umounts = getenv ("RC_NO_UMOUNTS");
+ char *new;
+ int i = strlen (SPLASH_CACHEDIR) + 1;
+
+ if (umounts)
+ i += strlen (umounts) + 1;
+
+ new = malloc (sizeof (char *) * i);
+ if (new)
+ {
+ if (umounts)
+ snprintf (new, i, "%s:%s", umounts, SPLASH_CACHEDIR);
+ else
+ snprintf (new, i, "%s", SPLASH_CACHEDIR);
+ }
+
+ /* We unsetenv first as some libc's leak memory if we overwrite
+ a var with a bigger value */
+ if (umounts)
+ unsetenv ("RC_NO_UMOUNTS");
+ setenv ("RC_NO_UMOUNTS", new, 1);
+
+ free (new);
+ }
+ return (_do_splash ("svc_stop", name, NULL));
+ case rc_hook_service_stop_out:
+ if (rc_service_state (name, rc_service_stopped))
+ return (_do_splash ("svc_stopped", name, "0"));
+ else
+ return (_do_splash ("svc_started", name, "1"));
+ case rc_hook_service_start_in:
+ return (_do_splash ("svc_start", name, NULL));
+ case rc_hook_service_start_out:
+ if (rc_service_state (name, rc_service_stopped))
+ return (_do_splash ("svc_started", name, "1"));
+ else
+ return (_do_splash ("svc_started", name, "0"));
+ default: ;
+ }
+
+ return (0);
+}
diff --git a/src/start-stop-daemon.c b/src/start-stop-daemon.c
new file mode 100644
index 00000000..e5dae783
--- /dev/null
+++ b/src/start-stop-daemon.c
@@ -0,0 +1,1047 @@
+/*
+ start-stop-daemon
+ Starts, stops, tests and signals daemons
+ Copyright 2007 Gentoo Foundation
+ Released under the GPLv2
+
+ This is essentially a ground up re-write of Debians
+ start-stop-daemon for cleaner code and to integrate into our RC
+ system so we can monitor daemons a little.
+ */
+
+#define POLL_INTERVAL 20000
+#define START_WAIT 100000
+
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/termios.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <grp.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifdef HAVE_PAM
+#include <security/pam_appl.h>
+
+/* We are not supporting authentication conversations */
+static struct pam_conv conv = { NULL, NULL} ;
+#endif
+
+#include "einfo.h"
+#include "rc.h"
+#include "rc-misc.h"
+#include "strlist.h"
+
+typedef struct schedulelist
+{
+ enum
+ {
+ schedule_timeout,
+ schedule_signal,
+ schedule_goto,
+ schedule_forever
+ } type;
+ int value;
+ struct schedulelist *gotolist;
+ struct schedulelist *next;
+} schedulelist_t;
+static schedulelist_t *schedule;
+
+static char *progname;
+static char *changeuser;
+static char **newenv;
+
+extern char **environ;
+
+static void free_schedulelist (schedulelist_t **list)
+{
+ schedulelist_t *here;
+ schedulelist_t *next;
+
+ for (here = *list; here; here = next)
+ {
+ next = here->next;
+ free (here);
+ }
+
+ *list = NULL;
+}
+
+static void cleanup (void)
+{
+ if (changeuser)
+ free (changeuser);
+
+ if (schedule)
+ free_schedulelist (&schedule);
+
+ if (newenv)
+ rc_strlist_free (newenv);
+}
+
+static int parse_signal (const char *sig)
+{
+ typedef struct signalpair
+ {
+ const char *name;
+ int signal;
+ } signalpair_t;
+
+ static const signalpair_t signallist[] = {
+ { "ABRT", SIGABRT },
+ { "ALRM", SIGALRM },
+ { "FPE", SIGFPE },
+ { "HUP", SIGHUP },
+ { "ILL", SIGILL },
+ { "INT", SIGINT },
+ { "KILL", SIGKILL },
+ { "PIPE", SIGPIPE },
+ { "QUIT", SIGQUIT },
+ { "SEGV", SIGSEGV },
+ { "TERM", SIGTERM },
+ { "USR1", SIGUSR1 },
+ { "USR2", SIGUSR2 },
+ { "CHLD", SIGCHLD },
+ { "CONT", SIGCONT },
+ { "STOP", SIGSTOP },
+ { "TSTP", SIGTSTP },
+ { "TTIN", SIGTTIN },
+ { "TTOU", SIGTTOU }
+ };
+
+ unsigned int i = 0;
+ char *s;
+
+ if (! sig || strlen (sig) == 0)
+ return (-1);
+
+ if (sscanf (sig, "%u", &i) == 1)
+ {
+ if (i > 0 && i < sizeof (signallist) / sizeof (signallist[0]))
+ return (i);
+ eerrorx ("%s: `%s' is not a valid signal", progname, sig);
+ }
+
+ if (strncmp (sig, "SIG", 3) == 0)
+ s = (char *) sig + 3;
+ else
+ s = NULL;
+
+ for (i = 0; i < sizeof (signallist) / sizeof (signallist[0]); i++)
+ if (strcmp (sig, signallist[i].name) == 0 ||
+ (s && strcmp (s, signallist[i].name) == 0))
+ return (signallist[i].signal);
+
+ eerrorx ("%s: `%s' is not a valid signal", progname, sig);
+}
+
+static void parse_schedule_item (schedulelist_t *item, const char *string)
+{
+ const char *after_hyph;
+ int sig;
+
+ if (strcmp (string,"forever") == 0)
+ item->type = schedule_forever;
+ else if (isdigit (string[0]))
+ {
+ item->type = schedule_timeout;
+ errno = 0;
+ if (sscanf (string, "%d", &item->value) != 1)
+ eerrorx ("%s: invalid timeout value in schedule `%s'", progname,
+ string);
+ }
+ else if ((after_hyph = string + (string[0] == '-')) &&
+ ((sig = parse_signal (after_hyph)) != -1))
+ {
+ item->type = schedule_signal;
+ item->value = (int) sig;
+ }
+ else
+ eerrorx ("%s: invalid schedule item `%s'", progname, string);
+}
+
+static void parse_schedule (const char *string, int default_signal)
+{
+ char buffer[20];
+ const char *slash;
+ int count = 0;
+ schedulelist_t *repeatat = NULL;
+ ptrdiff_t len;
+ schedulelist_t *next;
+
+ if (string)
+ for (slash = string; *slash; slash++)
+ if (*slash == '/')
+ count++;
+
+ if (schedule)
+ free_schedulelist (&schedule);
+
+ schedule = rc_xmalloc (sizeof (schedulelist_t));
+ schedule->gotolist = NULL;
+
+ if (count == 0)
+ {
+ schedule->type = schedule_signal;
+ schedule->value = default_signal;
+ schedule->next = rc_xmalloc (sizeof (schedulelist_t));
+ next = schedule->next;
+ next->type = schedule_timeout;
+ next->gotolist = NULL;
+ if (string)
+ {
+ if (sscanf (string, "%d", &next->value) != 1)
+ eerrorx ("%s: invalid timeout value in schedule", progname);
+ }
+ else
+ next->value = 5;
+ next->next = NULL;
+
+ return;
+ }
+
+ next = schedule;
+ while (string != NULL)
+ {
+ if ((slash = strchr (string, '/')))
+ len = slash - string;
+ else
+ len = strlen (string);
+
+ if (len >= (ptrdiff_t) sizeof (buffer))
+ eerrorx ("%s: invalid schedule item, far too long", progname);
+
+ memcpy (buffer, string, len);
+ buffer[len] = 0;
+ string = slash ? slash + 1 : NULL;
+
+ parse_schedule_item (next, buffer);
+ if (next->type == schedule_forever)
+ {
+ if (repeatat)
+ eerrorx ("%s: invalid schedule, `forever' appears more than once",
+ progname);
+
+ repeatat = next;
+ continue;
+ }
+
+ if (string)
+ {
+ next->next = rc_xmalloc (sizeof (schedulelist_t));
+ next = next->next;
+ next->gotolist = NULL;
+ }
+ }
+
+ if (repeatat)
+ {
+ next->next = rc_xmalloc (sizeof (schedulelist_t));
+ next = next->next;
+ next->type = schedule_goto;
+ next->value = 0;
+ next->gotolist = repeatat;
+ }
+
+ next->next = NULL;
+ return;
+}
+
+static pid_t get_pid (const char *pidfile, bool quiet)
+{
+ FILE *fp;
+ pid_t pid;
+
+ if (! pidfile)
+ return (-1);
+
+ if ((fp = fopen (pidfile, "r")) == NULL)
+ {
+ if (! quiet)
+ eerror ("%s: fopen `%s': %s", progname, pidfile, strerror (errno));
+ return (-1);
+ }
+
+ if (fscanf (fp, "%d", &pid) != 1)
+ {
+ if (! quiet)
+ eerror ("%s: no pid found in `%s'", progname, pidfile);
+ fclose (fp);
+ return (-1);
+ }
+ fclose (fp);
+
+ return (pid);
+}
+
+/* return number of processed killed, -1 on error */
+static int do_stop (const char *exec, const char *cmd,
+ const char *pidfile, uid_t uid,int sig,
+ bool quiet, bool verbose, bool test)
+{
+ pid_t *pids;
+ bool killed;
+ int nkilled = 0;
+ pid_t pid = 0;
+ int i;
+
+ if (pidfile)
+ if ((pid = get_pid (pidfile, quiet)) == -1)
+ return (quiet ? 0 : -1);
+
+ if ((pids = rc_find_pids (exec, cmd, uid, pid)) == NULL)
+ return (0);
+
+ for (i = 0; pids[i]; i++)
+ {
+ if (test)
+ {
+ if (! quiet)
+ einfo ("Would send signal %d to PID %d", sig, pids[i]);
+ nkilled++;
+ continue;
+ }
+
+ if (verbose)
+ ebegin ("Sending signal %d to PID %d", sig, pids[i]);
+ errno = 0;
+ killed = (kill (pids[i], sig) == 0 || errno == ESRCH ? true : false);
+ if (! killed)
+ {
+ if (! quiet)
+ eerror ("%s: failed to send signal %d to PID %d: %s",
+ progname, sig, pids[i], strerror (errno));
+ if (verbose)
+ eend (1, NULL);
+ nkilled = -1;
+ }
+ else
+ {
+ if (verbose)
+ eend (0, NULL);
+ if (nkilled != -1)
+ nkilled++;
+ }
+ }
+
+ free (pids);
+ return (nkilled);
+}
+
+static int run_stop_schedule (const char *exec, const char *cmd,
+ const char *pidfile, uid_t uid,
+ bool quiet, bool verbose, bool test)
+{
+ schedulelist_t *item = schedule;
+ int nkilled = 0;
+ int tkilled = 0;
+ int nrunning = 0;
+ struct timeval tv;
+ struct timeval now;
+ struct timeval stopat;
+
+ if (verbose)
+ {
+ if (pidfile)
+ einfo ("Will stop PID in pidfile `%s'", pidfile);
+ if (uid)
+ einfo ("Will stop processes owned by UID %d", uid);
+ if (exec)
+ einfo ("Will stop processes of `%s'", exec);
+ if (cmd)
+ einfo ("Will stop processes called `%s'", cmd);
+ }
+
+ while (item)
+ {
+ switch (item->type)
+ {
+ case schedule_goto:
+ item = item->gotolist;
+ continue;
+
+ case schedule_signal:
+ nrunning = 0;
+ nkilled = do_stop (exec, cmd, pidfile, uid, item->value,
+ quiet, verbose, test);
+ if (nkilled == 0)
+ {
+ if (tkilled == 0)
+ {
+ if (! quiet)
+ eerror ("%s: no matching processes found", progname);
+ }
+ return (tkilled);
+ }
+ else if (nkilled == -1)
+ return (0);
+
+ tkilled += nkilled;
+ break;
+ case schedule_timeout:
+ if (item->value < 1)
+ {
+ item = NULL;
+ break;
+ }
+
+ if (gettimeofday (&stopat, NULL) != 0)
+ {
+ eerror ("%s: gettimeofday: %s", progname, strerror (errno));
+ return (0);
+ }
+
+ stopat.tv_sec += item->value;
+ while (1)
+ {
+ if ((nrunning = do_stop (exec, cmd, pidfile,
+ uid, 0, true, false, true)) == 0)
+ return (true);
+
+ tv.tv_sec = 0;
+ tv.tv_usec = POLL_INTERVAL;
+ if (select (0, 0, 0, 0, &tv) < 0)
+ {
+ if (errno == EINTR)
+ eerror ("%s: caught an interupt", progname);
+ else
+ eerror ("%s: select: %s", progname, strerror (errno));
+ return (0);
+ }
+
+ if (gettimeofday (&now, NULL) != 0)
+ {
+ eerror ("%s: gettimeofday: %s", progname, strerror (errno));
+ return (0);
+ }
+ if (timercmp (&now, &stopat, >))
+ break;
+ }
+ break;
+
+ default:
+ eerror ("%s: invalid schedule item `%d'", progname, item->type);
+ return (0);
+ }
+
+ if (item)
+ item = item->next;
+ }
+
+ if (test || (tkilled > 0 && nrunning == 0))
+ return (nkilled);
+
+ if (! quiet)
+ {
+ if (nrunning == 1)
+ eerror ("%s: %d process refused to stop", progname, nrunning);
+ else
+ eerror ("%s: %d process(es) refused to stop", progname, nrunning);
+ }
+
+ return (-nrunning);
+}
+
+static void handle_signal (int sig)
+{
+ int pid;
+ int status;
+ int serrno = errno;
+
+ switch (sig)
+ {
+ case SIGINT:
+ case SIGTERM:
+ case SIGQUIT:
+ eerrorx ("%s: caught signal %d, aborting", progname, sig);
+
+ case SIGCHLD:
+ while (1)
+ {
+ if ((pid = waitpid (-1, &status, WNOHANG)) < 0)
+ {
+ if (errno != ECHILD)
+ eerror ("%s: waitpid: %s", progname, strerror (errno));
+ break;
+ }
+ }
+ break;
+
+ default:
+ eerror ("%s: caught unknown signal %d", progname, sig);
+ }
+
+ /* Restore errno */
+ errno = serrno;
+}
+
+int main (int argc, char **argv)
+{
+ int devnull_fd = -1;
+
+#ifdef TIOCNOTTY
+ int tty_fd = -1;
+#endif
+#ifdef HAVE_PAM
+ pam_handle_t *pamh = NULL;
+ int pamr;
+#endif
+
+ static struct option longopts[] = {
+ { "stop", 0, NULL, 'K'},
+ { "nicelevel", 1, NULL, 'N'},
+ { "retry", 1, NULL, 'R'},
+ { "start", 0, NULL, 'S'},
+ { "background", 0, NULL, 'b'},
+ { "chuid", 1, NULL, 'c'},
+ { "chdir", 1, NULL, 'd'},
+ { "group", 1, NULL, 'g'},
+ { "make-pidfile", 0, NULL, 'm'},
+ { "name", 1, NULL, 'n'},
+ { "oknodo", 0, NULL, 'o'},
+ { "pidfile", 1, NULL, 'p'},
+ { "quiet", 0, NULL, 'q'},
+ { "signal", 1, NULL, 's'},
+ { "test", 0, NULL, 't'},
+ { "user", 1, NULL, 'u'},
+ { "chroot", 1, NULL, 'r'},
+ { "verbose", 0, NULL, 'v'},
+ { "exec", 1, NULL, 'x'},
+ { "stdout", 1, NULL, '1'},
+ { "stderr", 1, NULL, '2'},
+ { NULL, 0, NULL, 0}
+ };
+ int c;
+ bool start = false;
+ bool stop = false;
+ bool oknodo = false;
+ bool test = false;
+ bool quiet = false;
+ bool verbose = false;
+ char *exec = NULL;
+ char *cmd = NULL;
+ char *pidfile = NULL;
+ int sig = SIGTERM;
+ uid_t uid = 0;
+ int nicelevel = 0;
+ bool background = false;
+ bool makepidfile = false;
+ uid_t ch_uid = 0;
+ gid_t ch_gid = 0;
+ char *ch_root = NULL;
+ char *ch_dir = NULL;
+ int tid = 0;
+ char *redirect_stderr = NULL;
+ char *redirect_stdout = NULL;
+ int stdout_fd;
+ int stderr_fd;
+ pid_t pid;
+ struct timeval tv;
+ int i;
+ char *svcname = getenv ("SVCNAME");
+ char *env;
+
+ progname = argv[0];
+ atexit (cleanup);
+
+ signal (SIGINT, handle_signal);
+ signal (SIGQUIT, handle_signal);
+ signal (SIGTERM, handle_signal);
+
+ while ((c = getopt_long (argc, argv,
+ "KN:R:Sbc:d:g:mn:op:qs:tu:r:vx:1:2:",
+ longopts, (int *) 0)) != -1)
+ switch (c)
+ {
+ case 'K': /* --stop */
+ stop = true;
+ break;
+
+ case 'N': /* --nice */
+ if (sscanf (optarg, "%d", &nicelevel) != 1)
+ eerrorx ("%s: invalid nice level `%s'", progname, optarg);
+ break;
+
+ case 'R': /* --retry <schedule>|<timeout> */
+ parse_schedule (optarg, sig);
+ break;
+
+ case 'S': /* --start */
+ start = true;
+ break;
+
+ case 'b': /* --background */
+ background = true;
+ break;
+
+ case 'c': /* --chuid <username>|<uid> */
+ /* we copy the string just in case we need the
+ * argument later. */
+ {
+ char *p = optarg;
+ char *cu = strsep (&p, ":");
+ changeuser = strdup (cu);
+ if (sscanf (cu, "%d", &tid) != 1)
+ {
+ struct passwd *pw = getpwnam (cu);
+ if (! pw)
+ eerrorx ("%s: user `%s' not found", progname, cu);
+ ch_uid = pw->pw_uid;
+ }
+ else
+ ch_uid = tid;
+ if (p)
+ {
+ char *cg = strsep (&p, ":");
+ if (sscanf (cg, "%d", &tid) != 1)
+ {
+ struct group *gr = getgrnam (cg);
+ if (! gr)
+ eerrorx ("%s: group `%s' not found", progname, cg);
+ ch_gid = gr->gr_gid;
+ }
+ else
+ ch_gid = tid;
+ }
+ }
+ break;
+
+ case 'd': /* --chdir /new/dir */
+ ch_dir = optarg;
+ break;
+
+ case 'g': /* --group <group>|<gid> */
+ if (sscanf (optarg, "%d", &tid) != 1)
+ {
+ struct group *gr = getgrnam (optarg);
+ if (! gr)
+ eerrorx ("%s: group `%s' not found", progname, optarg);
+ ch_gid = gr->gr_gid;
+ }
+ else
+ ch_gid = tid;
+ break;
+
+ case 'm': /* --make-pidfile */
+ makepidfile = true;
+ break;
+
+ case 'n': /* --name <process-name> */
+ cmd = optarg;
+ break;
+
+ case 'o': /* --oknodo */
+ oknodo = true;
+ break;
+
+ case 'p': /* --pidfile <pid-file> */
+ pidfile = optarg;
+ break;
+
+ case 'q': /* --quiet */
+ quiet = true;
+ break;
+
+ case 's': /* --signal <signal> */
+ sig = parse_signal (optarg);
+ break;
+
+ case 't': /* --test */
+ test = true;
+ break;
+
+ case 'u': /* --user <username>|<uid> */
+ if (sscanf (optarg, "%d", &tid) != 1)
+ {
+ struct passwd *pw = getpwnam (optarg);
+ if (! pw)
+ eerrorx ("%s: user `%s' not found", progname, optarg);
+ uid = pw->pw_uid;
+ }
+ else
+ uid = tid;
+ break;
+
+ case 'r': /* --chroot /new/root */
+ ch_root = optarg;
+ break;
+
+ case 'v': /* --verbose */
+ verbose = true;
+ break;
+
+ case 'x': /* --exec <executable> */
+ exec = optarg;
+ break;
+
+ case '1': /* --stdout /path/to/stdout.lgfile */
+ redirect_stdout = optarg;
+ break;
+
+ case '2': /* --stderr /path/to/stderr.logfile */
+ redirect_stderr = optarg;
+ break;
+
+ default:
+ exit (EXIT_FAILURE);
+ }
+
+ /* Respect RC as well as how we are called */
+ if (rc_is_env ("RC_QUIET", "yes") && ! verbose)
+ quiet = true;
+
+ if (start == stop)
+ eerrorx ("%s: need one of --start or --stop", progname);
+
+ if (start && ! exec)
+ eerrorx ("%s: --start needs --exec", progname);
+
+ if (stop && ! exec && ! pidfile && ! cmd && ! uid)
+ eerrorx ("%s: --stop needs --exec, --pidfile, --name or --user", progname);
+
+ if (makepidfile && ! pidfile)
+ eerrorx ("%s: --make-pidfile is only relevant with --pidfile", progname);
+
+ if (background && ! start)
+ eerrorx ("%s: --background is only relevant with --start", progname);
+
+ if ((redirect_stdout || redirect_stderr) && ! background)
+ eerrorx ("%s: --stdout and --stderr are only relevant with --background",
+ progname);
+
+ argc -= optind;
+ argv += optind;
+
+ /* Validate that the binary rc_exists if we are starting */
+ if (exec && start)
+ {
+ char *tmp;
+ if (ch_root)
+ tmp = rc_strcatpaths (ch_root, exec, NULL);
+ else
+ tmp = exec;
+ if (! rc_is_file (tmp))
+ {
+ eerror ("%s: %s does not exist", progname, tmp);
+ if (ch_root)
+ free (tmp);
+ exit (EXIT_FAILURE);
+ }
+ if (ch_root)
+ free (tmp);
+ }
+
+ if (stop)
+ {
+ int result;
+
+ if (! schedule)
+ {
+ if (test || oknodo)
+ parse_schedule ("0", sig);
+ else
+ parse_schedule (NULL, sig);
+ }
+
+ result = run_stop_schedule (exec, cmd, pidfile, uid, quiet, verbose, test);
+ if (test || oknodo)
+ return (result > 0 ? EXIT_SUCCESS : EXIT_FAILURE);
+ if (result < 1)
+ exit (result == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
+
+ if (pidfile && rc_is_file (pidfile))
+ unlink (pidfile);
+
+ if (svcname)
+ rc_set_service_daemon (svcname, exec, cmd, pidfile, false);
+
+ exit (EXIT_SUCCESS);
+ }
+
+ if (do_stop (exec, cmd, pidfile, uid, 0, true, false, true) > 0)
+ eerrorx ("%s: %s is already running", progname, exec);
+
+ if (test)
+ {
+ if (quiet)
+ exit (EXIT_SUCCESS);
+
+ einfon ("Would start %s", exec);
+ while (argc-- > 0)
+ printf("%s ", *argv++);
+ printf ("\n");
+ eindent ();
+ if (ch_uid != 0)
+ einfo ("as user %d", ch_uid);
+ if (ch_gid != 0)
+ einfo ("as group %d", ch_gid);
+ if (ch_root)
+ einfo ("in root `%s'", ch_root);
+ if (ch_dir)
+ einfo ("in dir `%s'", ch_dir);
+ if (nicelevel != 0)
+ einfo ("with a priority of %d", nicelevel);
+ eoutdent ();
+ exit (EXIT_SUCCESS);
+ }
+
+ /* Ensure this is unset, so if the daemon does /etc/init.d/foo
+ Then we filter the environment accordingly */
+ unsetenv ("RC_SOFTLEVEL");
+
+ if (verbose)
+ {
+ ebegin ("Detaching to start `%s'", exec);
+ eindent ();
+ }
+
+ if (background)
+ signal (SIGCHLD, handle_signal);
+
+ *--argv = exec;
+ if ((pid = fork ()) == -1)
+ eerrorx ("%s: fork: %s", progname, strerror (errno));
+
+ /* Child process - lets go! */
+ if (pid == 0)
+ {
+ pid_t mypid = getpid ();
+
+#ifdef TIOCNOTTY
+ tty_fd = open("/dev/tty", O_RDWR);
+#endif
+
+ devnull_fd = open("/dev/null", O_RDWR);
+
+ if (nicelevel)
+ {
+ if (setpriority (PRIO_PROCESS, mypid, nicelevel) == -1)
+ eerrorx ("%s: setpritory %d: %s", progname, nicelevel,
+ strerror(errno));
+ }
+
+ if (ch_root && chroot (ch_root) < 0)
+ eerrorx ("%s: chroot `%s': %s", progname, ch_root, strerror (errno));
+
+ if (ch_dir && chdir (ch_dir) < 0)
+ eerrorx ("%s: chdir `%s': %s", progname, ch_dir, strerror (errno));
+
+ if (makepidfile && pidfile)
+ {
+ FILE *fp = fopen (pidfile, "w");
+ if (! fp)
+ eerrorx ("%s: fopen `%s': %s", progname, pidfile, strerror
+ (errno));
+ fprintf (fp, "%d\n", mypid);
+ fclose (fp);
+ }
+
+#ifdef HAVE_PAM
+ if (changeuser != NULL)
+ pamr = pam_start ("start-stop-daemon", changeuser, &conv, &pamh);
+ else
+ pamr = pam_start ("start-stop-daemon", "nobody", &conv, &pamh);
+
+ if (pamr == PAM_SUCCESS)
+ pamr = pam_authenticate (pamh, PAM_SILENT);
+ if (pamr == PAM_SUCCESS)
+ pamr = pam_acct_mgmt (pamh, PAM_SILENT);
+ if (pamr == PAM_SUCCESS)
+ pamr = pam_open_session (pamh, PAM_SILENT);
+ if (pamr != PAM_SUCCESS)
+ eerrorx ("%s: pam error: %s", progname, pam_strerror(pamh, pamr));
+#endif
+
+ if ((ch_gid) && setgid(ch_gid))
+ eerrorx ("%s: unable to set groupid to %d", progname, ch_gid);
+ if (changeuser && ch_gid)
+ if (initgroups (changeuser, ch_gid))
+ eerrorx ("%s: initgroups (%s, %d)", progname, changeuser, ch_gid);
+ if (ch_uid && setuid (ch_uid))
+ eerrorx ("%s: unable to set userid to %d", progname, ch_uid);
+ else
+ {
+ struct passwd *passwd = getpwuid (ch_uid);
+ if (passwd)
+ {
+ unsetenv ("HOME");
+ if (passwd->pw_dir)
+ setenv ("HOME", passwd->pw_dir, 1);
+ unsetenv ("USER");
+ if (passwd->pw_name)
+ setenv ("USER", passwd->pw_name, 1);
+ }
+ }
+
+ /* Close any fd's to the passwd database */
+ endpwent ();
+
+#ifdef TIOCNOTTY
+ ioctl(tty_fd, TIOCNOTTY, 0);
+ close(tty_fd);
+#endif
+
+ /* Clean the environment of any RC_ variables */
+ STRLIST_FOREACH (environ, env, i)
+ if (env && strncmp (env, "RC_", 3) != 0)
+ {
+ /* For the path character, remove the rcscript bin dir from it */
+ if (strncmp (env, "PATH=" RC_LIBDIR "bin:",
+ strlen ("PATH=" RC_LIBDIR "bin:")) == 0)
+ {
+ char *path = env;
+ char *newpath;
+ int len;
+ path += strlen ("PATH=" RC_LIBDIR "bin:");
+ len = sizeof (char *) * strlen (path) + 6;
+ newpath = rc_xmalloc (len);
+ snprintf (newpath, len, "PATH=%s", path);
+ newenv = rc_strlist_add (newenv, newpath);
+ free (newpath);
+ }
+ else
+ newenv = rc_strlist_add (newenv, env);
+ }
+
+ umask (022);
+
+ stdout_fd = devnull_fd;
+ stderr_fd = devnull_fd;
+ if (redirect_stdout)
+ {
+ if ((stdout_fd = open (redirect_stdout, O_WRONLY | O_CREAT | O_APPEND,
+ S_IRUSR | S_IWUSR)) == -1)
+ eerrorx ("%s: unable to open the logfile for stdout `%s': %s",
+ progname, redirect_stdout, strerror (errno));
+ }
+ if (redirect_stderr)
+ {
+ if ((stderr_fd = open (redirect_stderr, O_WRONLY | O_CREAT | O_APPEND,
+ S_IRUSR | S_IWUSR)) == -1)
+ eerrorx ("%s: unable to open the logfile for stderr `%s': %s",
+ progname, redirect_stderr, strerror (errno));
+ }
+
+ dup2 (devnull_fd, STDIN_FILENO);
+ if (background)
+ {
+ dup2 (stdout_fd, STDOUT_FILENO);
+ dup2 (stderr_fd, STDERR_FILENO);
+ }
+
+ for (i = getdtablesize () - 1; i >= 3; --i)
+ close(i);
+
+ setsid ();
+
+ execve (exec, argv, newenv);
+#ifdef HAVE_PAM
+ if (pamr == PAM_SUCCESS)
+ pam_close_session (pamh, PAM_SILENT);
+#endif
+ eerrorx ("%s: failed to exec `%s': %s", progname, exec, strerror (errno));
+ }
+
+ /* Parent process */
+ if (! background)
+ {
+ /* As we're not backgrounding the process, wait for our pid to return */
+ int status = 0;
+ int savepid = pid;
+
+ errno = 0;
+ do
+ {
+ pid = waitpid (savepid, &status, 0);
+ if (pid < 1)
+ {
+ eerror ("waitpid %d: %s", savepid, strerror (errno));
+ return (-1);
+ }
+ } while (! WIFEXITED (status) && ! WIFSIGNALED (status));
+
+ if (! WIFEXITED (status) || WEXITSTATUS (status) != 0)
+ {
+ if (! quiet)
+ eerrorx ("%s: failed to started `%s'", progname, exec);
+ exit (EXIT_FAILURE);
+ }
+
+ pid = savepid;
+ }
+
+ /* Wait a little bit and check that process is still running
+ We do this as some badly written daemons fork and then barf */
+ if (START_WAIT > 0)
+ {
+ struct timeval stopat;
+ struct timeval now;
+
+ if (gettimeofday (&stopat, NULL) != 0)
+ eerrorx ("%s: gettimeofday: %s", progname, strerror (errno));
+
+ stopat.tv_usec += START_WAIT;
+ while (1)
+ {
+ bool alive = false;
+
+ tv.tv_sec = 0;
+ tv.tv_usec = POLL_INTERVAL;
+ if (select (0, 0, 0, 0, &tv) < 0)
+ {
+ /* Let our signal handler handle the interupt */
+ if (errno != EINTR)
+ eerrorx ("%s: select: %s", progname, strerror (errno));
+ }
+
+ if (gettimeofday (&now, NULL) != 0)
+ eerrorx ("%s: gettimeofday: %s", progname, strerror (errno));
+
+ /* This is knarly.
+ If we backgrounded then we know the exact pid.
+ Otherwise if we have a pidfile then it *may* know the exact pid.
+ Failing that, we'll have to query processes.
+ We sleep first as some programs like ntp like to fork, and write
+ their pidfile a LONG time later. */
+ if (background)
+ {
+ if (kill (pid, 0) == 0)
+ alive = true;
+ }
+ else
+ {
+ if (pidfile && rc_exists (pidfile))
+ {
+ if (do_stop (NULL, NULL, pidfile, uid, 0, true, false, true) > 0)
+ alive = true;
+ }
+ else
+ {
+ if (do_stop (exec, cmd, NULL, uid, 0, true, false, true) > 0)
+ alive = true;
+ }
+ }
+
+ if (! alive)
+ eerrorx ("%s: %s died", progname, exec);
+
+ if (timercmp (&now, &stopat, >))
+ break;
+ }
+ }
+
+ if (svcname)
+ rc_set_service_daemon (svcname, exec, cmd, pidfile, true);
+
+ exit (EXIT_SUCCESS);
+}
diff --git a/src/start-stop-daemon.pam b/src/start-stop-daemon.pam
new file mode 100644
index 00000000..860a3d52
--- /dev/null
+++ b/src/start-stop-daemon.pam
@@ -0,0 +1,6 @@
+#%PAM-1.0
+
+auth sufficient pam_rootok.so
+account required pam_permit.so
+password required pam_deny.so
+session optional pam_limits.so
diff --git a/src/strlist.h b/src/strlist.h
new file mode 100644
index 00000000..25bbb4e0
--- /dev/null
+++ b/src/strlist.h
@@ -0,0 +1,24 @@
+/*
+ strlist.h
+ String list macros for making char ** arrays
+ Copyright 2007 Gentoo Foundation
+ Based on a previous implementation by Martin Schlemmer
+ Released under the GPLv2
+ */
+
+#ifndef __STRLIST_H__
+#define __STRLIST_H__
+
+/* FIXME: We should replace the macro with an rc_strlist_foreach
+ function, but I'm unsure how to go about this. */
+
+/* Step through each entry in the string list, setting '_pos' to the
+ beginning of the entry. '_counter' is used by the macro as index,
+ but should not be used by code as index (or if really needed, then
+ it should usually by +1 from what you expect, and should only be
+ used in the scope of the macro) */
+#define STRLIST_FOREACH(_list, _pos, _counter) \
+ if ((_list) && _list[0] && ((_counter = 0) == 0)) \
+ while ((_pos = _list[_counter++]))
+
+#endif /* __STRLIST_H__ */