diff options
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 : @@ -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 @@ +[0;35;40m . +[0;35;40m .vir. d$b +[0;35;40m .d$$$$$$b. .cd$$b. .d$$b. d$$$$$$$$$$$b .d$$b. .d$$b. +[0;35;40m $$$$( )$$$b d$$$()$$$. d$$$$$$$b Q$$$$$$$P$$$P.$$$$$$$b. .$$$$$$$b. +[0;35;40m Q$$$$$$$$$$B$$$$$$$$P" d$$$PQ$$$$b. $$$$. .$$$P' `$$$ .$$$P' `$$$ +[0;35;40m "$$$$$$$P Q$$$$$$$b d$$$P Q$$$$b $$$$b $$$$b..d$$$ $$$$b..d$$$ +[0;35;40m d$$$$$$P" "$$$$$$$$ Q$$$ Q$$$$ $$$$$ `Q$$$$$$$P `Q$$$$$$$P +[0;35;40m $$$$$$$P `""""" "" "" Q$$$P "Q$$$P" "Q$$$P" +[0;35;40m `Q$$P" """ +[0;37;40m + +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 @@ +[0;35;40m . +[0;35;40m .vir. d$b +[0;35;40m .d$$$$$$b. .cd$$b. .d$$b. d$$$$$$$$$$$b .d$$b. .d$$b. +[0;35;40m $$$$( )$$$b d$$$()$$$. d$$$$$$$b Q$$$$$$$P$$$P.$$$$$$$b. .$$$$$$$b. +[0;35;40m Q$$$$$$$$$$B$$$$$$$$P" d$$$PQ$$$$b. $$$$. .$$$P' `$$$ .$$$P' `$$$ +[0;35;40m "$$$$$$$P Q$$$$$$$b d$$$P Q$$$$b $$$$b $$$$b..d$$$ $$$$b..d$$$ +[0;35;40m d$$$$$$P" "$$$$$$$$ Q$$$ Q$$$$ $$$$$ `Q$$$$$$$P `Q$$$$$$$P +[0;35;40m $$$$$$$P `""""" "" "" Q$$$P "Q$$$P" "Q$$$P" +[0;35;40m `Q$$P" """ +[0;37;40m + +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__ */ |