commit 5af58b45146ab5253ca964738f4e45287bf963d4 Author: Roy Marples Date: Thu Apr 5 11:18:42 2007 +0000 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/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 : + + Rewrite the core parts in C. We now provide librc so other programs can + query runlevels, services and state without using bash. We also provide + libeinfo so other programs can easily use our informational functions. + + As such, we have dropped the requirement of using bash as the init script + shell. We now use /bin/sh and have strived to make the scripts as portable + as possible. Shells that work are bash and dash. busybox works provided + you disable s-s-d. If you have WIPE_TMP set to yes in conf.d/bootmisc you + should disable find too. + zsh and ksh do not work at this time. + + Networking support is currently being re-vamped also as it was heavily bash + array based. As such, a new config format is available like so + config_eth0="1.2.3.4/24 5.6.7.8/16" + or like so + config_eth0="'1.2.3.4 netmask 255.255.255.0' '5.6.7.8 netmask 255.255.0.0'" + + We will still support the old bash array format provided that /bin/sh IS + a link it bash. + + ChangeLog for baselayout-1 can be found in our SVN repo. diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..b349b879 --- /dev/null +++ b/Makefile @@ -0,0 +1,108 @@ +# baselayout Makefile +# Copyright 2006-2007 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# +# We've moved the installation logic from Gentoo ebuild into a generic +# Makefile so that the ebuild is much smaller and more simple. +# It also has the added bonus of being easier to install on systems +# without an ebuild style package manager. + +SUBDIRS = conf.d etc init.d man net sh share src + +NAME = baselayout +#VERSION = 2.0.0_alpha1 +VERSION = 1.13.99 + +PKG = $(NAME)-$(VERSION) + +ARCH = x86 +ifeq ($(OS),) +OS=$(shell uname -s) +ifneq ($(OS),Linux) +OS=BSD +endif +endif + +BASE_DIRS = /$(LIB)/rcscripts/init.d /$(LIB)/rcscripts/tmp +KEEP_DIRS = /boot /home /mnt /root \ + /usr/local/bin /usr/local/sbin /usr/local/share/doc /usr/local/share/man \ + /var/lock /var/run + +ifeq ($(OS),Linux) + KEEP_DIRS += /dev /sys + NET_LO = net.lo +endif +ifneq ($(OS),Linux) + NET_LO = net.lo0 +endif + +TOPDIR = . +include $(TOPDIR)/default.mk + +install:: + # These dirs may not exist from prior versions + for x in $(BASE_DIRS) ; do \ + $(INSTALL_DIR) $(DESTDIR)$$x || exit $$? ; \ + touch $(DESTDIR)$$x/.keep || exit $$? ; \ + done + # Don't install runlevels if they already exist + if ! test -d $(DESTDIR)/etc/runlevels ; then \ + (cd runlevels; $(MAKE) install) ; \ + test -d runlevels.$(OS) && (cd runlevels.$(OS); $(MAKE) install) ; \ + $(INSTALL_DIR) $(DESTDIR)/etc/runlevels/single || exit $$? ; \ + $(INSTALL_DIR) $(DESTDIR)/etc/runlevels/nonetwork || exit $$? ; \ + fi + ln -snf ../../$(LIB)/rcscripts/sh/net.sh $(DESTDIR)/etc/init.d/$(NET_LO) || exit $$? + ln -snf ../../$(LIB)/rcscripts/sh/functions.sh $(DESTDIR)/etc/init.d || exit $$? + # Handle lib correctly + if test $(LIB) != "lib" ; then \ + sed -i'.bak' -e 's,/lib/,/$(LIB)/,g' $(DESTDIR)/$(LIB)/rcscripts/sh/functions.sh || exit $$? ; \ + rm -f $(DESTDIR)/$(LIB)/rcscripts/sh/functions.sh.bak ; \ + fi + +.PHONY: all clean install + +layout: + # Create base filesytem layout + for x in $(KEEP_DIRS) ; do \ + $(INSTALL_DIR) $(DESTDIR)$$x || exit $$? ; \ + touch $(DESTDIR)$$x/.keep || exit $$? ; \ + done + # Special dirs + install -m 0700 -d $(DESTDIR)/root || exit $$? + touch $(DESTDIR)/root/.keep || exit $$? + install -m 1777 -d $(DESTDIR)/var/tmp || exit $$? + touch $(DESTDIR)/var/tmp/.keep || exit $$? + install -m 1777 -d $(DESTDIR)/tmp || exit $$? + touch $(DESTDIR)/tmp/.keep || exit $$? + # FHS compatibility symlinks stuff + ln -snf /var/tmp $(DESTDIR)/usr/tmp || exit $$? + ln -snf share/man $(DESTDIR)/usr/local/man || exit $$? + +distcheck: + if test -d .svn ; then \ + svnfiles=`svn status 2>&1 | egrep -v '^(U|P)'` ; \ + if test "x$$svnfiles" != "x" ; then \ + echo "Refusing to package tarball until svn is in sync:" ; \ + echo "$$svnfiles" ; \ + echo "make distforce to force packaging" ; \ + exit 1 ; \ + fi \ + fi + +distforce: + install -d /tmp/$(PKG) + cp -PRp . /tmp/$(PKG) + `which find` /tmp/$(PKG) -depth -path "*/.svn/*" -delete + `which find` /tmp/$(PKG) -depth -path "*/.svn" -delete + rm -rf /tmp/$(PKG)/src/core /tmp/$(PKG)/po + $(MAKE) -C /tmp/$(PKG) clean + sed -i'.bak' -e '/-Wl,-rpath ./ s/^/#/g' /tmp/$(PKG)/src/Makefile + rm -f /tmp/$(PKG)/src/Makefile.bak + tar -C /tmp -cvjpf /tmp/$(PKG).tar.bz2 $(PKG) + rm -Rf /tmp/$(PKG) + du /tmp/$(PKG).tar.bz2 + +dist: distcheck distforce + +# vim: set ts=4 : diff --git a/STYLE b/STYLE new file mode 100644 index 00000000..0fbd2845 --- /dev/null +++ b/STYLE @@ -0,0 +1,53 @@ +This is the rc-scripts style manual. It governs the coding style +of rc-scripts. Everything here might as well have been spoken by +God. If you find any issues, please talk to base-system@gentoo.org +or #gentoo-base on irc.freenode.net. + +############# +# VARIABLES # +############# +- User Variables - + Variables must always be enclosed by {} + e.g. ${foo} ${bar} +- Internal Shell Variables - + Do not use {} with internal variables unless appropriate + e.g. case $1 in + e.g. foo=$IFS + e.g. echo "blah${1}123" +- Assigning with Quotes - + When assigning to a variable from another variable, you should + not need quotes. However, you do when assigning from a subshell. + e.g. foo=${bar} + e.g. foo="$(uname -a)" + +######### +# TESTS # +######### +- Brackets - + Always use the [ ... ] form instead of [[ ... ]] as the later only really + works in bash, and we should support as many shells as we can. +- Quoting - + When dealing with strings, you should quote both sides. + +############### +# CODE BLOCKS # +############### +- Structure - + Use the more compact form + e.g. if ... ; then + e.g. while ... ; do + Do not use the older form + e.g. if ... + then +- Functions - + Use the more compact form + e.g. foo() { + Do not lead with 'function ' + e.g. function foo() { + +############ +# COMMENTS # +############ +- General - + Try to include a comment block before sections + of code to explain what you're attempting diff --git a/conf.d.BSD/Makefile b/conf.d.BSD/Makefile new file mode 100644 index 00000000..13731e61 --- /dev/null +++ b/conf.d.BSD/Makefile @@ -0,0 +1,5 @@ +DIR = /etc/conf.d +FILES = localmount net.example wireless.example + +TOPDIR = .. +include $(TOPDIR)/default.mk diff --git a/conf.d.BSD/localmount b/conf.d.BSD/localmount new file mode 100644 index 00000000..2002beb6 --- /dev/null +++ b/conf.d.BSD/localmount @@ -0,0 +1,31 @@ +# /etc/conf.d/localmount + +# Kernel core dump options for FreeBSD kernel. +# Unless you're a FreeBSD kernel developer or driver writer then this won't +# be of any interest to you at all. + +# The following options allow to configure the kernel's core dump +# facilities. Please read +# http://www.freebsd.org/doc/en_US.ISO8859-1/books/developers-handbook/kerneldebug.html +# for more information about Kernel core dumps and kernel debugging. + +# KERNEL_DUMP_DEVICE variable is used to specify which device will be +# used by the kernel to write the dump down. This has to be a swap +# partition, and has to be at least big enough to contain the whole +# physical memory (see hw.physmem sysctl(8) variable). +# When the variable is commented out, no core dump will be enabled for +# the kernel. +#KERNEL_DUMP_DEVICE="/dev/ad0s1b" + +# KERNEL_DUMP_DIR variable is used to tell savecore(8) utility where +# to save the kernel core dump once it's restored from the dump +# device. If unset, /var/crash will be used, as the default of +# FreeBSD. +#KERNEL_DUMP_DIR="/var/crash" + +# KERNEL_DUMP_COMPRESS variable decide whether to compress with +# gzip(1) the dump or leave it of its original size (the size of the +# physical memory present on the system). If set to yes, the -z option +# will be passed to savecore(8) that will proceed on compressing the +# dump. +#KERNEL_DUMP_COMPRESS="no" diff --git a/conf.d.BSD/net.example b/conf.d.BSD/net.example new file mode 100644 index 00000000..7108c0f6 --- /dev/null +++ b/conf.d.BSD/net.example @@ -0,0 +1,309 @@ +# BSD NOTE: Network functionality support is still being written and +# many parts here are missing compared to Gentoo/Linux +# Feel free to write the needed modules and submit them to us :) +# +############################################################################## +# QUICK-START +# +# The quickest start is if you want to use DHCP. +# In that case, everything should work out of the box, no configuration +# necessary, though the startup script will warn you that you haven't +# specified anything. + +# WARNING :- some examples have a mixture of IPv4 (ie 192.168.0.1) and IPv6 +# (ie 4321:0:1:2:3:4:567:89ab) internet addresses. They only work if you have +# the relevant kernel option enabled. So if you don't have an IPv6 enabled +# kernel then remove the IPv6 address from your config. + +# If you want to use a static address or use DHCP explicitly, jump +# down to the section labelled INTERFACE HANDLERS. +# +# If you want to do anything more fancy, you should take the time to +# read through the rest of this file. + +############################################################################## +# MODULES +# +# We now support modular networking scripts which means we can easily +# add support for new interface types and modules while keeping +# compatability with existing ones. +# +# Modules load by default if the package they need is installed. If +# you specify a module here that doesn't have it's package installed +# then you get an error stating which package you need to install. +# Ideally, you only use the modules setting when you have two or more +# packages installed that supply the same service. +# +# In other words, you probably should DO NOTHING HERE... + +############################################################################## +# INTERFACE HANDLERS + +# For a static configuration, use something like this +# (They all do exactly the same thing btw) +#config_eth0="192.168.0.2/24" +#config_eth0="'192.168.0.2 netmask 255.255.255.0'" + +# We can also specify a broadcast +#config_eth0="'192.168.0.2/24 brd 192.168.0.255'" +#config_eth0="'192.168.0.2 netmask 255.255.255.0 broadcast 192.168.0.255'" + +# If you need more than one address, you can use something like this +# NOTE: ifconfig creates an aliased device for each extra IPv4 address +# (eth0:1, eth0:2, etc) +# iproute2 does not do this as there is no need to +#config_eth0="'192.168.0.2/24' '192.168.0.3/24' '192.168.0.4/24'" +# Or you can use sequence expressions +#config_eth0="'192.168.0.{2..4}/24'" FIXME - may not work with baselayout2 +# which does the same as above. Be careful though as if you use this and +# fallbacks, you have to ensure that both end up with the same number of +# values otherwise your fallback won't work correctly. + +# You can also use IPv6 addresses +# (you should always specify a prefix length with IPv6 here) +#config_eth0="192.168.0.2/24 \ +#4321:0:1:2:3:4:567:89ab/64 \ +#4321:0:1:2:3:4:567:89ac/64" + +# If you wish to keep existing addresses + routing and the interface is up, +# you can specify a noop (no operation). If the interface is down or there +# are no addresses assigned, then we move onto the next step (default dhcp) +# This is useful when configuring your interface with a kernel command line +# or similar +#config_eth0="noop 192.168.0.2/24" + +# If you don't want ANY address (only useful when calling for advanced stuff) +#config_eth0="null" + +# Here's how to do routing if you need it +# We add an IPv4 default route, IPv4 subnet route and an IPv6 unicast route +#routes_eth0=" \ +# 'default via 192.168.0.1' \ +# '10.0.0.0/8 via 192.168.0.1' \ +# '::/0' \ +#" + +# If a specified module fails (like dhcp - see below), you can specify a +# fallback like so +#fallback_eth0="'192.168.0.2 netmask 255.255.255.0'" +#fallback_route_eth0="'default via 192.168.0.1'" + +# NOTE: fallback entry must match the entry location in config_eth0 +# As such you can only have one fallback route. + +# Some users may need to alter the MTU - here's how +#mtu_eth0="1500" + +# Most drivers that report carrier status function correctly, but some do not +# One of these faulty drivers is for the Intel e1000 network card, but only +# at boot time. To get around this you may alter the carrier_timeout value for +# the interface. -1 is disable, 0 is infinite and any other number of seconds +# is how long we wait for carrier. The current default is 3 seconds +#carrier_timeout_eth0=-1 + +############################################################################## +# OPTIONAL MODULES + +#----------------------------------------------------------------------------- +# WIRELESS (802.11 support) +# Wireless can be provided by BSDs ifconfig or wpa_supplicant + +# ifconfig support is a one shot script - wpa_supplicant is daemon that +# scans, assoicates and re-configures if assocation is lost. +# wpa_supplicant is preferred +# See wireless.example for details about using ifconfig for wireless + +# emerge net-wireless/wpa-supplicant +# Wireless options are held in /etc/wpa_supplicant/wpa_supplicant.conf +# Console the wpa_supplicant.conf.example that is installed in +# /usr/share/doc/wpa_supplicant + +# By default we don't wait for wpa_suppliant to associate and authenticate. +# If you would like to, so can specify how long in seconds +#associate_timeout_eth0=60 +# A value of 0 means wait forever. + +# You can also override any settings found here per SSID - which is very +# handy if you use different networks a lot. See below for using the SSID +# in our variables +#config_SSID="dhcp" +# See the System module below for setting dns/nis/ntp per SSID + +# You can also override any settings found here per MAC address of the AP +# in case you use Access Points with the same SSID but need different +# networking configs. Below is an example - of course you use the same +# method with other variables +#mac_config_001122334455="dhcp" +#mac_dns_servers_001122334455="192.168.0.1 192.168.0.2" + +# When an interface has been associated with an Access Point, a global +# variable called SSID is set to the Access Point's SSID for use in the +# pre/post user functions below (although it's not available in preup as you +# won't have associated then) + +# If you're using anything else to configure wireless on your interface AND +# you have installed wpa_supplicant, you need to disable wpa_supplicant +#modules="!iwconfig !wpa_supplicant" +#or +#modules="!wireless" + +############################################################################## +# WIRELESS SSID IN VARIABLES +############################################################################## +# Remember to change SSID to your SSID. +# Say that your SSID is My NET - the line +# #key_SSID="s:passkey" +# becomes +# #key_My_NET="s:passkey" +# Notice that the space has changed to an underscore - do the same with all +# characters not in a-z A-Z (English alphabet) 0-9. This only applies to +# variables and not values. +# +# Any SSID's in values like essid_eth0="My NET" may need to be escaped +# This means placing the character \ before the character +# \" need to be escaped for example +# So if your SSID is +# My "\ NET +# it becomes +# My \"\\ NET +# for example +# #essid_eth0="My\"\\NET" +# +# So using the above we can use +# #dns_domain_My____NET="My\"\\NET" +# which is an invalid dns domain, but shows the how to use the variable +# structure +######################################################### + +#----------------------------------------------------------------------------- +# DHCP +# DHCP can be provided by dhclient. +# +# dhcpcd: emerge net-misc/dhcpcd +# dhclient: emerge net-misc/dhcp + +# Regardless of which DHCP client you prefer, you configure them the +# same way using one of following depending on which interface modules +# you're using. +#config_eth0="dhcp" + +# For passing custom options to dhcpcd use something like the following. This +# example reduces the timeout for retrieving an address from 60 seconds (the +# default) to 10 seconds. +#dhcpcd_eth0="-t 10" + +# GENERIC DHCP OPTIONS +# Set generic DHCP options like so +#dhcp_eth0="release nodns nontp nonis nogateway nosendhost" + +# This tells the dhcp client to release it's lease when it stops, not to +# overwrite dns, ntp and nis settings, not to set a default route and not to +# send the current hostname to the dhcp server and when it starts. +# You can use any combination of the above options - the default is not to +# use any of them. + + +#----------------------------------------------------------------------------- +# System +# For configuring system specifics such as domain, dns, ntp and nis servers +# It's rare that you would need todo this, but you can anyway. +# This is most benefit to wireless users who don't use DHCP so they can change +# their configs based on SSID. See above for more details + +# Setting name/domain server causes /etc/resolv.conf to be overwritten +# Note that if DHCP is used, and you want this to take precedence then +# set dhcp_SSID="nodns" +# To use dns settings such as these, dns_servers_eth0 must be set! +# If you omit the _eth0 suffix, then it applies to all interfaces unless +# overridden by the interface suffix. +#dns_domain_eth0="your.domain" +#dns_servers_eth0="192.168.0.2 192.168.0.3" +#dns_search_eth0="this.domain that.domain" +#dns_options_eth0="'timeout 1' 'rotate'" +#dns_sortlist_eth0="130.155.160.0/255.255.240.0 130.155.0.0" +# See the man page for resolv.conf for details about the options and sortlist +# directives + +#ntp_servers_eth0="192.168.0.2 192.168.0.3" + +#nis_domain_eth0="domain" +#nis_servers_eth0="192.168.0.2 192.168.0.3" + +# NOTE: Setting any of these will stamp on the files in question. So if you +# don't specify dns_servers but you do specify dns_domain then no nameservers +# will be listed in /etc/resolv.conf even if there were any there to start +# with. +# If this is an issue for you then maybe you should look into a resolv.conf +# manager like resolvconf-gentoo to manage this file for you. All packages +# that baselayout supports use resolvconf-gentoo if installed. + +#----------------------------------------------------------------------------- +# Cable in/out detection +# Sometimes the cable is in, others it's out. Obviously you don't want to +# restart net.eth0 every time when you plug it in either. +# BSD has the Device State Change Daemon - or devd for short +# To enable this, simple add devd to the boot runlevel +#rc-update add devd boot +#rc + +############################################################################## +# ADVANCED CONFIGURATION +# +# Four functions can be defined which will be called surrounding the +# start/stop operations. The functions are called with the interface +# name first so that one function can control multiple adapters. An extra two +# functions can be defined when an interface fails to start or stop. +# +# The return values for the preup and predown functions should be 0 +# (success) to indicate that configuration or deconfiguration of the +# interface can continue. If preup returns a non-zero value, then +# interface configuration will be aborted. If predown returns a +# non-zero value, then the interface will not be allowed to continue +# deconfiguration. +# +# The return values for the postup, postdown, failup and faildown functions are +# ignored since there's nothing to do if they indicate failure. +# +# ${IFACE} is set to the interface being brought up/down +# ${IFVAR} is ${IFACE} converted to variable name bash allows + +#preup() { +# # Remember to return 0 on success +# return 0 +#} + +#predown() { +# # The default in the script is to test for NFS root and disallow +# # downing interfaces in that case. Note that if you specify a +# # predown() function you will override that logic. Here it is, in +# # case you still want it... +# if is_net_fs /; then +# eerror "root filesystem is network mounted -- can't stop ${IFACE}" +# return 1 +# fi +# +# # Remember to return 0 on success +# return 0 +#} + +#postup() { +# # This function could be used, for example, to register with a +# # dynamic DNS service. Another possibility would be to +# # send/receive mail once the interface is brought up. + +#} + +#postdown() { +# # Return 0 always +# return 0 +#} + +#failup() { +# # This function is mostly here for completeness... I haven't +# # thought of anything nifty to do with it yet ;-) +#} + +#faildown() { +# # This function is mostly here for completeness... I haven't +# # thought of anything nifty to do with it yet ;-) +#} diff --git a/conf.d.BSD/wireless.example b/conf.d.BSD/wireless.example new file mode 100644 index 00000000..d9dadcbe --- /dev/null +++ b/conf.d.BSD/wireless.example @@ -0,0 +1,190 @@ +# /etc/conf.d/wireless: +# Global wireless config file for net.* rc-scripts + +############################################################################## +# HINTS +############################################################################## +# see net.example for using ESSID in variable names +# +# Most users will just need to set the following options +# key_ESSID1="s:yourkeyhere enc open" # s: means a text key +# key_ESSID2="aaaa-bbbb-cccc-dd" # no s: means a hex key +# preferred_aps="'ESSID1' 'ESSID2'" +# +# Clear? Good. Now configure your wireless network below +############################################################################# + +############################################################################## +# SETTINGS +############################################################################## +# Hard code an ESSID to an interface - leave this unset if you wish the driver +# to scan for available Access Points +# I would only set this as a last resort really - use the preferred_aps +# setting at the bottom of this file +#essid_eth0='foo' + +# Some drivers/hardware don't scan all that well. We have no control over this +# but we can say how many scans we want to do to try and get a better sweep of +# the area. The default is 1. +#scans_eth0="1" + +#Channel can be set (1-14), but defaults to 3 if not set. +# +# The below is taken verbatim from the BSD wavelan documentation found at +# http://www.netbsd.org/Documentation/network/wavelan.html +# There are 14 channels possible; We are told that channels 1-11 are legal for +# North America, channels 1-13 for most of Europe, channels 10-13 for France, +# and only channel 14 for Japan. If in doubt, please refer to the documentation +# that came with your card or access point. Make sure that the channel you +# select is the same channel your access point (or the other card in an ad-hoc +# network) is on. The default for cards sold in North America and most of Europe +# is 3; the default for cards sold in France is 11, and the default for cards +# sold in Japan is 14. +#channel_eth0="3" + +# Setup any other config commands. This is basically the ifconfig argument +# without the ifconfig $iface. +#ifconfig_eth0="" +# You can do the same per ESSID too. +#ifconfig_ESSID="" + +# Seconds to wait until associated. The default is to wait 10 seconds. +# 0 means wait indefinitely. WARNING: this can cause an infinite delay when +# booting. +#associate_timeout_eth0="5" + +# Define a WEP key per ESSID or MAC address (of the AP, not your card) +# The encryption type (open or restricted) must match the +# encryption type on the Access Point. +# To set a hex key, prefix with 0x +#key_ESSID="0x12341234123412341234123456" +# or you can use strings. Passphrase IS NOT supported +#key_ESSID="foobar" +#key_ESSID="foobar" + +# WEP key for the AP with MAC address 001122334455 +#mac_key_001122334455="foobar" + +# You can also override the interface settings found in /etc/conf.d/net +# per ESSID - which is very handy if you use different networks a lot +#config_ESSID="dhcp" +#routes_ESSID= +#fallback_ESSID= + +# Setting name/domain server causes /etc/resolv.conf to be overwritten +# Note that if DHCP is used, and you want this to take precedence then +# please put -R in your dhcpcd options +#dns_servers_ESSID="192.168.0.1 192.168.0.2" +#dns_domain_ESSID="some.domain" +#dns_search_path_ESSID="search.this.domain search.that.domain" +# Please check the man page for resolv.conf for more information +# as domain and search (searchdomains) are mutually exclusive and +# searchdomains takes precedence + +# You can also set any of the /etc/conf.d/net variables per MAC address +# incase you use Access Points with the same ESSID but need different +# networking configs. Below is an example - of course you use the same +# method with other variables +#config_001122334455="dhcp" +#dns_servers_001122334455="192.168.0.1 192.168.0.2" + +# Map a MAC address to an ESSID +# This is used when the Access Point is not broadcasting it's ESSID +# WARNING: This will override the ESSID being broadcast due to some +# Access Points sending an ESSID even when they have been configured +# not to! +# Change 001122334455 to the MAC address and ESSID to the ESSID +# it should map to +#mac_essid_001122334455="ESSID" + +# This lists the preferred ESSIDs to connect to in order +# ESSID's can contain any characters here as they must match the broadcast +# ESSID exactly. +# Surround each ESSID with the " character and seperate them with a space +# If the first ESSID isn't found then it moves onto the next +# If this isn't defined then it connects to the first one found +#preferred_aps="'ESSID 1' 'ESSID 2'" + +# You can also define a preferred_aps list per interface +#preferred_aps_eth0="'ESSID 3' 'ESSID 4'" + +# You can also say whether we only connect to preferred APs or not +# Values are "any", "preferredonly", "forcepreferred", "forcepreferredonly" +# and "forceany" +# "any" means it will connect to visible APs in the preferred list and then +# any other available AP +# "preferredonly" means it will only connect to visible APs in the preferred +# list +# "forcepreferred" means it will forceably connect to APs in order if it does +# not find them in a scan +# "forcepreferredonly" means it forceably connects to the APs in order and +# does not bother to scan +# "forceany" does the same as forcepreferred + connects to any other +# available AP +# Default is "any" +#associate_order="any" +#associate_order_eth0="any" + +# You can define blacklisted Access Points in the same way +#blacklist_aps="'ESSID 1' 'ESSID 2'" +#blacklist_aps_eth0="'ESSID 3' 'ESSID 4'" + +# If you have more than one wireless card, you can say if you want +# to allow each card to associate with the same Access Point or not +# Values are "yes" and "no" +# Default is "yes" +#unique_ap="yes" +#unique_ap_eth0="yes" + +# IMPORTANT: preferred_only, blacklisted_aps and unique_ap only work when +# essid_eth0 is not set and your card is capable of scanning + +# NOTE: preferred_aps list ignores blacklisted_aps - so if you have +# the same ESSID in both, well, you're a bit silly :p + + +############################################################################## +# ADVANCED CONFIGURATION +# +# Two functions can be defined which will be called surrounding the +# associate function. The functions are called with the interface +# name first so that one function can control multiple adapters. +# +# The return values for the preassociate function should be 0 +# (success) to indicate that configuration or deconfiguration of the +# interface can continue. If preassociate returns a non-zero value, then +# interface configuration will be aborted. +# +# The return value for the postassociate function is ignored +# since there's nothing to do if it indicates failure. + +#preassociate() { +# # The below adds two configuration variables leap_user_ESSID +# # and leap_pass_ESSID. When they are both confiugred for the ESSID +# # being connected to then we run the CISCO LEAP script +# +# local user pass +# eval user=\"\$\{leap_user_${ESSIDVAR}\}\" +# eval pass=\"\$\{leap_pass_${ESSIDVAR}\}\" +# +# if [ -n "${user}" -a -n "${pass}" ]; then +# if [ ! -x /opt/cisco/bin/leapscript ]; then +# eend "For LEAP support, please emerge net-misc/cisco-aironet-client-utils" +# return 1 +# fi +# einfo "Waiting for LEAP Authentication on \"${ESSID}\"" +# if /opt/cisco/bin/leapscript ${user} ${pass} | grep -q 'Login incorrect'; then +# ewarn "Login Failed for ${user}" +# return 1 +# fi +# fi +# +# return 0 +#} + +#postassociate() { +# # This function is mostly here for completeness... I haven't +# # thought of anything nifty to do with it yet ;-) +# # Return 0 always +# return 0 +#} diff --git a/conf.d.Linux/Makefile b/conf.d.Linux/Makefile new file mode 100644 index 00000000..6a87562d --- /dev/null +++ b/conf.d.Linux/Makefile @@ -0,0 +1,7 @@ +DIR = /etc/conf.d +FILES = net.example wireless.example +FILES_APPEND = clock rc +FILES_NOEXIST = consolefont keymaps volumes + +TOPDIR = .. +include $(TOPDIR)/default.mk diff --git a/conf.d.Linux/clock b/conf.d.Linux/clock new file mode 100644 index 00000000..0ff87c01 --- /dev/null +++ b/conf.d.Linux/clock @@ -0,0 +1,31 @@ + +# If you wish to pass any other arguments to hwclock during bootup, +# you may do so here. + +CLOCK_OPTS="" + +# If you want to set the Hardware Clock to the current System Time +# during shutdown, then say "yes" here. + +CLOCK_SYSTOHC="no" + +# Newer FHS specs say this file should live in /var/lib rather than +# /etc. If you care about such things, feel free to change this value. +# Note that a blank value means that you do not wish to even use the +# adjtime facility. This is the default behavior as adjtime can be +# very fragile. If the clock is updated without updating the adjtime +# file (which is common when using services such as ntp), then the +# clock can be screwed up when it gets updated at next boot. + +#CLOCK_ADJTIME="/var/lib/adjtime" +#CLOCK_ADJTIME="/etc/adjtime" +CLOCK_ADJTIME="" + + +### ALPHA SPECIFIC OPTIONS ### + +# If your alpha uses the SRM console, set this to "yes". +SRM="no" + +# If your alpha uses the ARC console, set this to "yes". +ARC="no" diff --git a/conf.d.Linux/consolefont b/conf.d.Linux/consolefont new file mode 100644 index 00000000..d1c29a6d --- /dev/null +++ b/conf.d.Linux/consolefont @@ -0,0 +1,19 @@ +# /etc/conf.d/consolefont + +# CONSOLEFONT specifies the default font that you'd like Linux to use on the +# console. You can find a good selection of fonts in /usr/share/consolefonts; +# you shouldn't specify the trailing ".psf.gz", just the font name below. +# To use the default console font, comment out the CONSOLEFONT setting below. +# This setting is used by the /etc/init.d/consolefont script (NOTE: if you do +# not want to use it, run "rc-update del consolefont" as root). +CONSOLEFONT="default8x16" + +# CONSOLETRANSLATION is the charset map file to use. Leave commented to use +# the default one. Have a look in /usr/share/consoletrans for a selection of +# map files you can use. +#CONSOLETRANSLATION="8859-1_to_uni" + +# UNICODEMAP is the unicode map file to use. Leave commented to use the +# default one. Have a look in /usr/share/unimaps for a selection of map files +# you can use. +#UNICODEMAP="iso01" diff --git a/conf.d.Linux/keymaps b/conf.d.Linux/keymaps new file mode 100644 index 00000000..eb68fbe2 --- /dev/null +++ b/conf.d.Linux/keymaps @@ -0,0 +1,26 @@ +# /etc/conf.d/keymaps + +# Use KEYMAP to specify the default console keymap. There is a complete tree +# of keymaps in /usr/share/keymaps to choose from. + +KEYMAP="us" + + +# Should we first load the 'windowkeys' console keymap? Most x86 users will +# say "yes" here. Note that non-x86 users should leave it as "no". + +SET_WINDOWKEYS="no" + + +# The maps to load for extended keyboards. Most users will leave this as is. + +EXTENDED_KEYMAPS="" +#EXTENDED_KEYMAPS="backspace keypad euro" + + +# Tell dumpkeys(1) to interpret character action codes to be +# from the specified character set. +# This only matters if you set UNICODE="yes" in /etc/rc.conf. +# For a list of valid sets, run `dumpkeys --help` + +DUMPKEYS_CHARSET="" diff --git a/conf.d.Linux/net.example b/conf.d.Linux/net.example new file mode 100644 index 00000000..ffbece15 --- /dev/null +++ b/conf.d.Linux/net.example @@ -0,0 +1,846 @@ +############################################################################## +# QUICK-START +# +# The quickest start is if you want to use DHCP. +# In that case, everything should work out of the box, no configuration +# necessary, though the startup script will warn you that you haven't +# specified anything. + +# WARNING :- some examples have a mixture of IPv4 (ie 192.168.0.1) and IPv6 +# (ie 4321:0:1:2:3:4:567:89ab) internet addresses. They only work if you have +# the relevant kernel option enabled. So if you don't have an IPv6 enabled +# kernel then remove the IPv6 address from your config. + +# If you want to use a static address or use DHCP explicitly, jump +# down to the section labelled INTERFACE HANDLERS. +# +# If you want to do anything more fancy, you should take the time to +# read through the rest of this file. + + +############################################################################## +# VARIABLES +# +# We've changed from using arrays to evaluated strings. +# This has the benefit of being slightly more readable but more importantly it +# works across all shells. +# OLD +# config_eth0=( "192.168.0.24 netmask 255.255.255.0" "192.168.0.25/24" ) +# NEW +# config_eth0="'192.168.0.24 netmask 255.255.255.0' 192.168.0.25/24" +# INVALID +# config_eth0='192.168.0.24 netmask 255.255.255.0' +# +# As the 1st value has spaces in it, it needs additional quoting. The 2nd +# value has no spaces, therefore no additional quoting is required. +# The last statement is invalid because when it is evaluated, it only has one +# set of quotes. + +############################################################################## +# MODULES +# +# We now support modular networking scripts which means we can easily +# add support for new interface types and modules while keeping +# compatability with existing ones. +# +# Modules load by default if the package they need is installed. If +# you specify a module here that doesn't have it's package installed +# then you get an error stating which package you need to install. +# Ideally, you only use the modules setting when you have two or more +# packages installed that supply the same service. +# +# In other words, you probably should DO NOTHING HERE... + +# Prefer ifconfig over iproute2 +#modules="ifconfig" + +# You can also specify other modules for an interface +# In this case we prefer udhcpc over dhcpcd +#modules_eth0="udhcpc" + +# You can also specify which modules not to use - for example you may be +# using a supplicant or linux-wlan-ng to control wireless configuration but +# you still want to configure network settings per SSID associated with. +#modules="!iwconfig !wpa_supplicant" +# IMPORTANT: If you need the above, please disable modules in that order + + +############################################################################## +# INTERFACE HANDLERS +# +# We provide two interface handlers presently: ifconfig and iproute2. +# You need one of these to do any kind of network configuration. +# For ifconfig support, emerge sys-apps/net-tools +# For iproute2 support, emerge sys-apps/iproute2 + +# If you don't specify an interface then we prefer iproute2 if it's installed +# To prefer ifconfig over iproute2 +#modules="ifconfig" + +# For a static configuration, use something like this +# (They all do exactly the same thing btw) +#config_eth0="192.168.0.2/24" +#config_eth0="'192.168.0.2 netmask 255.255.255.0'" + +# We can also specify a broadcast +#config_eth0="'192.168.0.2/24 brd 192.168.0.255'" +#config_eth0="'192.168.0.2 netmask 255.255.255.0 broadcast 192.168.0.255'" + +# If you need more than one address, you can use something like this +# NOTE: ifconfig creates an aliased device for each extra IPv4 address +# (eth0:1, eth0:2, etc) +# iproute2 does not do this as there is no need to +#config_eth0="'192.168.0.2/24' '192.168.0.3/24' '192.168.0.4/24'" +# Or you can use sequence expressions +#config_eth0="192.168.0.{2..4}/24" # FIXME - does it work? +# which does the same as above. Be careful though as if you use this and +# fallbacks, you have to ensure that both end up with the same number of +# values otherwise your fallback won't work correctly. + +# You can also use IPv6 addresses +# (you should always specify a prefix length with IPv6 here) +#config_eth0="192.168.0.2/24 \ +#4321:0:1:2:3:4:567:89ab/64 \ +#4321:0:1:2:3:4:567:89ac/64" +#) + +# If you wish to keep existing addresses + routing and the interface is up, +# you can specify a noop (no operation). If the interface is down or there +# are no addresses assigned, then we move onto the next step (default dhcp) +# This is useful when configuring your interface with a kernel command line +# or similar +#config_eth0="noop 192.168.0.2/24" + +# If you don't want ANY address (only useful when calling for advanced stuff) +#config_eth0="null" + +# Here's how to do routing if you need it +# We add an IPv4 default route, IPv4 subnet route and an IPv6 unicast route +#routes_eth0=" \ +# 'default via 192.168.0.1' \ +# '10.0.0.0/8 via 192.168.0.1' \ +# '::/0' \ +#" + +# If a specified module fails (like dhcp - see below), you can specify a +# fallback like so +#fallback_eth0="'192.168.0.2 netmask 255.255.255.0'" +#fallback_route_eth0="'default via 192.168.0.1'" + +# NOTE: fallback entry must match the entry location in config_eth0 +# As such you can only have one fallback route. + +# Some users may need to alter the MTU - here's how +#mtu_eth0="1500" + +# Each module described below can set a default base metric, lower is +# preferred over higher. This is so we can prefer a wired route over a +# wireless route automaticaly. You can override this by setting +#metric_eth0="100" +# or on a global basis +#metric="100" +# The only downside of the global setting is that you have to ensure that +# there are no conflicting routes yourself. For users with large routing +# tables you may have to set a global metric as the due to a simple read of +# the routing table taking over a minute at a time. + +############################################################################## +# OPTIONAL MODULES + +#----------------------------------------------------------------------------- +# WIRELESS (802.11 support) +# Wireless can be provided by iwconfig or wpa_supplicant + +# iwconfig +# emerge net-wireless/wireless-tools +# Wireless options are held in /etc/conf.d/wireless - but could be here too +# Consult the sample file /etc/conf.d/wireless.example for instructions +# wpa_supplicant is the default if it is installed + +# wpa_supplicant +# emerge net-wireless/wpa-supplicant +# Wireless options are held in /etc/wpa_supplicant/wpa_supplicant.conf +# Console the wpa_supplicant.conf.example that is installed in +# /usr/share/doc/wpa_supplicant +# To configure wpa_supplicant +#wpa_supplicant_ath0="-Dmadwifi" # For Atheros based cards +# Consult wpa_supplicant for more drivers - the default is -Dwext which should +# work for most cards. + +# By default we don't wait for wpa_suppliant to associate and authenticate. +# If you need to change this behaviour then you don't know how our scripts work +# and setting this value could cause strange things to happen. +# If you would like to, so can specify how long in seconds. +#associate_timeout_eth0=60 +# A value of 0 means wait forever. + +# You can also override any settings found here per SSID - which is very +# handy if you use different networks a lot. See below for using the SSID +# in our variables +#config_SSID="dhcp" +# See the System module below for setting dns/nis/ntp per SSID + +# You can also override any settings found here per MAC address of the AP +# in case you use Access Points with the same SSID but need different +# networking configs. Below is an example - of course you use the same +# method with other variables +#mac_config_001122334455="dhcp" +#mac_dns_servers_001122334455="192.168.0.1 192.168.0.2" + +# When an interface has been associated with an Access Point, a global +# variable called SSID is set to the Access Point's SSID for use in the +# pre/post user functions below (although it's not available in preup as you +# won't have associated then) + +# If you're using anything else to configure wireless on your interface AND +# you have installed wpa_supplicant, you need to disable wpa_supplicant +#modules="!iwconfig !wpa_supplicant" +#or +#modules="!wireless" + +############################################################################## +# WIRELESS SSID IN VARIABLES +############################################################################## +# Remember to change SSID to your SSID. +# Say that your SSID is My NET - the line +# #key_SSID="s:passkey" +# becomes +# #key_My_NET="s:passkey" +# Notice that the space has changed to an underscore - do the same with all +# characters not in a-z A-Z (English alphabet) 0-9. This only applies to +# variables and not values. +# +# Any SSID's in values like essid_eth0="My NET" may need to be escaped +# This means placing the character \ before the character +# \" need to be escaped for example +# So if your SSID is +# My "\ NET +# it becomes +# My \"\\ NET +# for example +# #essid_eth0="My\"\\NET" +# +# So using the above we can use +# #dns_domain_My____NET="My\"\\NET" +# which is an invalid dns domain, but shows the how to use the variable +# structure +######################################################### + + +#----------------------------------------------------------------------------- +# DHCP +# DHCP can be provided by dhclient, dhcpcd, pump or udhcpc. +# +# dhclient: emerge net-misc/dhcp +# dhcpcd: emerge net-misc/dhcpcd +# pump: emerge net-misc/pump +# udhcpc: emerge net-misc/udhcp + +# If you have more than one DHCP client installed, you need to specify which +# one to use - otherwise we default to dhcpcd if available. +#modules=( "dhclient" ) # to select dhclient over dhcpcd +# +# Notes: +# - All clients send the current hostname to the DHCP server by default +# - dhcpcd does not daemonize when the lease time is infinite +# - udhcp-0.9.3-r3 and earlier do not support getting NTP servers +# - pump does not support getting NIS servers +# - DHCP tends to erase any existing device information - so add +# static addresses after dhcp if you need them +# - dhclient and udhcpc can set other resolv.conf options such as "option" +# and "sortlist"- see the System module for more details + +# Regardless of which DHCP client you prefer, you configure them the +# same way using one of following depending on which interface modules +# you're using. +#config_eth0="dhcp" + +# For passing custom options to dhcpcd use something like the following. This +# example reduces the timeout for retrieving an address from 60 seconds (the +# default) to 10 seconds. +#dhcpcd_eth0="-t 10" + +# dhclient, udhcpc and pump don't have many runtime options +# You can pass options to them in a similar manner to dhcpcd though +#dhclient_eth0="..." +#udhcpc_eth0="..." +#pump_eth0="..." + +# GENERIC DHCP OPTIONS +# Set generic DHCP options like so +#dhcp_eth0="release nodns nontp nonis nogateway nosendhost" + +# This tells the dhcp client to release it's lease when it stops, not to +# overwrite dns, ntp and nis settings, not to set a default route and not to +# send the current hostname to the dhcp server and when it starts. +# You can use any combination of the above options - the default is not to +# use any of them. + +#----------------------------------------------------------------------------- +# For APIPA support, emerge net-misc/iputils or net-analyzer/arping + +# APIPA is a module that tries to find a free address in the range +# 169.254.0.0-169.254.255.255 by arping a random address in that range on the +# interface. If no reply is found then we assign that address to the interface + +# This is only useful for LANs where there is no DHCP server and you don't +# connect directly to the internet. +#config_eth0="dhcp" +#fallback_eth0="apipa" + +#----------------------------------------------------------------------------- +# ARPING Gateway configuration +# and +# Automatic Private IP Addressing (APIPA) +# For arpingnet / apipa support, emerge net-misc/iputils or net-analyzer/arping +# +# This is a module that tries to find a gateway IP. If it exists then we use +# that gateways configuration for our own. For the configuration variables +# simply ensure that each octet is zero padded and the dots are removed. +# Below is an example. +# +#gateways_eth0="192.168.0.1 10.0.0.1" +#config_192168000001="192.168.0.2/24" +#routes_192168000001="'default via 192.168.0.1'" +#dns_servers_192168000001="192.168.0.1" +#config_010000000001="10.0.0.254/8" +#routes_010000000001="default via 10.0.0.1" +#dns_servers_010000000001="10.0.0.1" + +# We can also specify a specific MAC address for each gateway if different +# networks have the same gateway. +#gateways_eth0="192.168.0.1,00:11:22:AA:BB:CC 10.0.0.1,33:44:55:DD:EE:FF" +#config_192168000001_001122AABBCC="192.168.0.2/24" +#routes_192168000001_001122AABBCC="default via 192.168.0.1" +#dns_servers_192168000001_001122AABBCC="192.168.0.1" +#config_010000000001_334455DDEEFF="10.0.0.254/8" +#routes_010000000001_334455DDEEFF="default via 10.0.0.1" +#dns_servers_010000000001_334455DDEEFF="10.0.0.1" + +# If we don't find any gateways (or there are none configured) then we try and +# use APIPA to find a free address in the range 169.254.0.0-169.254.255.255 +# by arping a random address in that range on the interface. If no reply is +# found then we assign that address to the interface. + +# This is only useful for LANs where there is no DHCP server. +#config_eth0="arping" + +# or if no DHCP server can be found +#config_eth0="dhcp" +#fallback_eth0="arping" + +# NOTE: We default to sleeping for 1 second the first time we attempt an +# arping to give the interface time to settle on the LAN. This appears to +# be a good default for most instances, but if not you can alter it here. +#arping_sleep=5 +#arping_sleep_lan=7 + +# NOTE: We default to waiting 3 seconds to get an arping response. You can +# change the default wait like so. +#arping_wait=3 +#arping_wait_lan=2 + +#----------------------------------------------------------------------------- +# VLAN (802.1q support) +# For VLAN support, emerge net-misc/vconfig + +# Specify the VLAN numbers for the interface like so +# Please ensure your VLAN IDs are NOT zero-padded +#vlans_eth0="1 2" + +# You may not want to assign an IP the the physical interface, but we still +# need it up. +#config_eth0="null" + +# You can also configure the VLAN - see for vconfig man page for more details +#vconfig_eth0="'set_name_type VLAN_PLUS_VID_NO_PAD'" +#vconfig_vlan1="'set_flag 1' 'set_egress_map 2 6'" +#config_vlan1="'172.16.3.1 netmask 255.255.254.0'" +#config_vlan2="'172.16.2.1 netmask 255.255.254.0'" + +# NOTE: Vlans can be configured with a . in their interface names +# When configuring vlans with this name type, you need to replace . with a _ +#config_eth0.1="dhcp" - does not work +#config_eth0_1="dhcp" - does work + +# NOTE: Vlans are controlled by their physical interface and not per vlan +# This means you do not need to create init scripts in /etc/init.d for each +# vlan, you must need to create one for the physical interface. +# If you wish to control the configuration of each vlan through a separate +# script, or wish to rename the vlan interface to something that vconfig +# cannot then you need to do this. +#vlan_start_eth0="no" + +# If you do the above then you may want to depend on eth0 like so +# RC_NEED_vlan1="net.eth0" +# NOTE: depend functions only work in /etc/conf.d/net +# and not in profile configs such as /etc/conf.d/net.foo + +#----------------------------------------------------------------------------- +# Bonding +# For link bonding/trunking emerge net-misc/ifenslave + +# To bond interfaces together +#slaves_bond0="eth0 eth1 eth2" +#config_bond0="null" # You may not want to assign an IP the the bond + +# If any of the slaves require extra configuration - for example wireless or +# ppp devices - we need to depend function on the bonded interfaces +#RC_NEED_bond0="net.eth0 net.eth1" + + +#----------------------------------------------------------------------------- +# Classical IP over ATM +# For CLIP support emerge net-dialup/linux-atm + +# Ensure that you have /etc/atmsigd.conf setup correctly +# Now setup each clip interface like so +#clip_atm0=( "peer_ip [if.]vpi.vci [opts]" ... ) +# where "peer_ip" is the IP address of a PVC peer (in case of an ATM connection +# with your ISP, your only peer is usually the ISP gateway closest to you), +# "if" is the number of the ATM interface which will carry the PVC, "vpi.vci" +# is the ATM VC address, and "opts" may optionally specify VC parameters like +# qos, pcr, and the like (see "atmarp -s" for further reference). Please also +# note quoting: it is meant to distinguish the VCs you want to create. You may, +# in example, create an atm0 interface to more peers, like this: +#clip_atm0="'1.1.1.254 0.8.35' 1.1.1.253 1.8.35'" + +# By default, the PVC will use the LLC/SNAP encapsulation. If you rather need a +# null encapsulation (aka "VC mode"), please add the keyword "null" to opts. + + +#----------------------------------------------------------------------------- +# PPP +# For PPP support, emerge net-dialup/ppp +# PPP is used for most dialup connections, including ADSL. +# The older ADSL module is documented below, but you are encouraged to try +# this module first. +# +# You need to create the PPP net script yourself. Make it like so +#ln -s net.lo /etc/init.d/net.ppp0 +# +# We have to instruct ppp0 to actually use ppp +#config_ppp0="ppp" +# +# Each PPP interface requires an interface to use as a "Link" +#link_ppp0="/dev/ttyS0" # Most PPP links will use a serial port +#link_ppp0="eth0" # PPPoE requires an ethernet interface +#link_ppp0="[itf.]vpi.vci" # PPPoA requires the ATM VC's address +#link_ppp0="/dev/null" # ISDN links should have this +#link_ppp0="pty 'your_link_command'" # PPP links over ssh, rsh, etc +# +# Here you should specify what pppd plugins you want to use +# Available plugins are: pppoe, pppoa, capi, dhcpc, minconn, radius, +# radattr, radrealms and winbind +#plugins_ppp0="pppoe" # Required plugin for PPPoE +#plugins_ppp0="pppoa vc-encaps" # Required plugin for PPPoA with an option +#plugins_ppp0="capi" # Required plugin for ISDN +# +# PPP requires at least a username. You can optionally set a password here too +# If you don't, then it will use the password specified in /etc/ppp/*-secrets +# against the specified username +#username_ppp0='user' +#password_ppp0='password' +# NOTE: You can set a blank password like so +#password_ppp0= +# +# The PPP daemon has many options you can specify - although there are many +# and may seem daunting, it is recommended that you read the pppd man page +# before enabling any of them +#pppd_ppp0=( +# "maxfail 0" # WARNING: It's not recommended you use this +# # if you don't specify maxfail then we assume 0 +# "updetach" # If not set, "/etc/init.d/net.ppp0 start" will return +# # immediately, without waiting the link to come up +# # for the first time. +# # Do not use it for dial-on-demand links! +# "debug" # Enables syslog debugging +# "noauth" # Do not require the peer to authenticate itself +# "defaultroute" # Make this PPP interface the default route +# "usepeerdns" # Use the DNS settings provided by PPP +# +# On demand options +# "demand" # Enable dial on demand +# "idle 30" # Link goes down after 30 seconds of inactivity +# "10.112.112.112:10.112.112.113" # Phony IP addresses +# "ipcp-accept-remote" # Accept the peers idea of remote address +# "ipcp-accept-local" # Accept the peers idea of local address +# "holdoff 3" # Wait 3 seconds after link dies before re-starting +# +# Dead peer detection +# "lcp-echo-interval 15" # Send a LCP echo every 15 seconds +# "lcp-echo-failure 3" # Make peer dead after 3 consective +# # echo-requests +# +# Compression options - use these to completely disable compression +# noaccomp noccp nobsdcomp nodeflate nopcomp novj novjccomp +# +# Dial-up settings +# "lock" # Lock serial port +# "115200" # Set the serial port baud rate +# "modem crtscts" # Enable hardware flow control +# "192.168.0.1:192.168.0.2" # Local and remote IP addresses +#) +# +# Dial-up PPP users need to specify at least one telephone number +#phone_number_ppp0=( "12345689" ) # Maximum 2 phone numbers are supported +# They will also need a chat script - here's a good one +#chat_ppp0=( +# 'ABORT' 'BUSY' +# 'ABORT' 'ERROR' +# 'ABORT' 'NO ANSWER' +# 'ABORT' 'NO CARRIER' +# 'ABORT' 'NO DIALTONE' +# 'ABORT' 'Invalid Login' +# 'ABORT' 'Login incorrect' +# 'TIMEOUT' '5' +# '' 'ATZ' +# 'OK' 'AT' # Put your modem initialization string here +# 'OK' 'ATDT\T' +# 'TIMEOUT' '60' +# 'CONNECT' '' +# 'TIMEOUT' '5' +# '~--' '' +#) + +# If the link require extra configuration - for example wireless or +# RFC 268 bridge - we need to depend on the bridge so they get +# configured correctly. +#RC_NEED_ppp0="net.nas0" + +#WARNING: if MTU of the PPP interface is less than 1500 and you use this +#machine as a router, you should add the following rule to your firewall +# +#iptables -I FORWARD 1 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu + +#----------------------------------------------------------------------------- +# ADSL +# For ADSL support, emerge net-dialup/rp-pppoe +# WARNING: This ADSL module is being deprecated in favour of the PPP module +# above. +# You should make the following settings and also put your +# username/password information in /etc/ppp/pap-secrets + +# Configure the interface to use ADSL +#config_eth0="adsl" + +# You probably won't need to edit /etc/ppp/pppoe.conf if you set this +#adsl_user_eth0="my-adsl-username" + +#----------------------------------------------------------------------------- +# ISDN +# For ISDN support, emerge net-dialup/isdn4k-utils +# You should make the following settings and also put your +# username/password information in /etc/ppp/pap-secrets + +# Configure the interface to use ISDN +#config_ippp0="dhcp" +# It's important to specify dhcp if you need it! +#config_ippp0="192.168.0.1/24" +# Otherwise, you can use a static IP + +# NOTE: The interface name must be either ippp or isdn followed by a number + +# You may need this option to set the default route +#ipppd_eth0="defaultroute" + +#----------------------------------------------------------------------------- +# MAC changer +# To set a specific MAC address +#mac_eth0="00:11:22:33:44:55" + +# For changing MAC addresses using the below, emerge net-analyzer/macchanger +# - to randomize the last 3 bytes only +#mac_eth0="random-ending" +# - to randomize between the same physical type of connection (e.g. fibre, +# copper, wireless) , all vendors +#mac_eth0="random-samekind" +# - to randomize between any physical type of connection (e.g. fibre, copper, +# wireless) , all vendors +#mac_eth0="random-anykind" +# - full randomization - WARNING: some MAC addresses generated by this may NOT +# act as expected +#mac_eth0="random-full" +# custom - passes all parameters directly to net-analyzer/macchanger +#mac_eth0="some custom set of parameters" + +# You can also set other options based on the MAC address of your network card +# Handy if you use different docking stations with laptops +#config_001122334455="dhcp" + +#----------------------------------------------------------------------------- +# TUN/TAP +# For TUN/TAP support emerge net-misc/openvpn or sys-apps/usermode-utilities +# +# You must specify if we're a tun or tap device. Then you can give it any +# name you like - such as vpn +#tuntap_vpn="tun" +#config_vpn="192.168.0.1/24" + +# Or stick wit the generic names - like tap0 +#tuntap_tap0="tap" +#config_tap0="192.168.0.1/24" + +# For passing custom options to tunctl use something like the following. This +# example sets the owner to adm +#tunctl_tun1="-u adm" +# When using openvpn, there are no options + +#----------------------------------------------------------------------------- +# Bridging (802.1d) +# For bridging support emerge net-misc/bridge-utils + +# To add ports to bridge br0 +#bridge_br0="eth0 eth1" +# or dynamically add them when the interface comes up +#bridge_add_eth0="br0" +#bridge_add_eth1="br0" + +# You need to configure the ports to null values so dhcp does not get started +#config_eth0="null" +#config_eth1="null" + +# Finally give the bridge an address - dhcp or a static IP +#config_br0="dhcp" # may not work when adding ports dynamically +#config_br0="192.168.0.1/24" + +# If any of the ports require extra configuration - for example wireless or +# ppp devices - we need to depend on them like so. +#RC_NEED_br0="net.eth0 net.eth1" + +# Below is an example of configuring the bridge +# Consult "man brctl" for more details +#brctl_br0="'setfd 0' 'sethello 0' 'stp off'" + +#----------------------------------------------------------------------------- +# RFC 2684 Bridge Support +# For RFC 2684 bridge support emerge net-misc/br2684ctl + +# Interface names have to be of the form nas0, nas1, nas2, etc. +# You have to specify a VPI and VCI for the interface like so +#br2684ctl_nas0="-a 0.38" # UK VPI and VCI + +# You may want to configure the encapsulation method as well by adding the -e +# option to the command above (may need to be before the -a command) +# -e 0 # LLC (default) +# -e 1 # VC mux + +# Then you can configure the interface as normal +#config_nas0="'192.168.0.1/24'" + +#----------------------------------------------------------------------------- +# Tunnelling +# WARNING: For tunnelling it is highly recommended that you +# emerge sys-apps/iproute2 +# +# For GRE tunnels +#iptunnel_vpn0="mode gre remote 207.170.82.1 key 0xffffffff ttl 255" + +# For IPIP tunnels +#iptunnel_vpn0="mode ipip remote 207.170.82.2 ttl 255" + +# To configure the interface +#config_vpn0="'192.168.0.2 pointopoint 192.168.1.2'" # ifconfig style +#config_vpn0="'192.168.0.2 peer 192.168.1.1'" # iproute2 style + +# 6to4 Tunnels allow IPv6 to work over IPv4 addresses, provided you +# have a non-private address configured on an interface. +# link_6to4="eth0" # Interface to base it's addresses on +# config_6to4="ip6to4" +# You may want to depend on eth0 like so +#RC_NEED_6to4="net.eth0" +# To ensure that eth0 is configured before 6to4. Of course, the tunnel could be +# any name and this also works for any configured interface. +# NOTE: If you're not using iproute2 then your 6to4 tunnel has to be called +# sit0 - otherwise use a different name like 6to4 in the example above. + +# You can also specify a relay and suffix if you like. +# The default relay is 192.88.99.1 and the defualt suffix is :1 +#relay_6to4="192.168.3.2" +#suffix_6to4=":ff" + + +#----------------------------------------------------------------------------- +# System +# For configuring system specifics such as domain, dns, ntp and nis servers +# It's rare that you would need todo this, but you can anyway. +# This is most benefit to wireless users who don't use DHCP so they can change +# their configs based on SSID. See wireless.example for more details + +# To use dns settings such as these, dns_servers_eth0 must be set! +# If you omit the _eth0 suffix, then it applies to all interfaces unless +# overridden by the interface suffix. +#dns_domain_eth0="your.domain" +#dns_servers_eth0="192.168.0.2 192.168.0.3" +#dns_search_eth0="this.domain that.domain" +#dns_options_eth0="'timeout 1' rotate" +#dns_sortlist_eth0="130.155.160.0/255.255.240.0 130.155.0.0" +# See the man page for resolv.conf for details about the options and sortlist +# directives + +#ntp_servers_eth0="192.168.0.2 192.168.0.3" + +#nis_domain_eth0="domain" +#nis_servers_eth0="192.168.0.2 192.168.0.3" + +# NOTE: Setting any of these will stamp on the files in question. So if you +# don't specify dns_servers but you do specify dns_domain then no nameservers +# will be listed in /etc/resolv.conf even if there were any there to start +# with. +# If this is an issue for you then maybe you should look into a resolv.conf +# manager like resolvconf-gentoo to manage this file for you. All packages +# that baselayout supports use resolvconf-gentoo if installed. + +#----------------------------------------------------------------------------- +# Cable in/out detection +# Sometimes the cable is in, others it's out. Obviously you don't want to +# restart net.eth0 every time when you plug it in either. +# +# netplug is a package that detects this and requires no extra configuration +# on your part. +# emerge sys-apps/netplug +# or +# emerge sys-apps/ifplugd +# and you're done :) + +# By default we don't wait for netplug/ifplugd to configure the interface. +# If you would like it to wait so that other services now that network is up +# then you can specify a timeout here. +#plug_timeout="10" +# A value of 0 means wait forever. + +# If you don't want to use netplug on a specific interface but you have it +# installed, you can disable it for that interface via the modules statement +#modules_eth0="!netplugd" +# You can do the same for ifplugd +# +# You can disable them both with the generic plug +#modules_eth0="!plug" + +# To use specific ifplugd options, fex specifying wireless mode +#ifplugd_eth0="--api-mode=wlan" +# man ifplugd for more options + +############################################################################## +# ADVANCED CONFIGURATION +# +# Four functions can be defined which will be called surrounding the +# start/stop operations. The functions are called with the interface +# name first so that one function can control multiple adapters. An extra two +# functions can be defined when an interface fails to start or stop. +# +# The return values for the preup and predown functions should be 0 +# (success) to indicate that configuration or deconfiguration of the +# interface can continue. If preup returns a non-zero value, then +# interface configuration will be aborted. If predown returns a +# non-zero value, then the interface will not be allowed to continue +# deconfiguration. +# +# The return values for the postup, postdown, failup and faildown functions are +# ignored since there's nothing to do if they indicate failure. +# +# ${IFACE} is set to the interface being brought up/down +# ${IFVAR} is ${IFACE} converted to variable name bash allows + +#preup() { +# # Test for link on the interface prior to bringing it up. This +# # only works on some network adapters and requires the mii-diag +# # package to be installed. +# if mii-tool "${IFACE}" 2> /dev/null | grep -q 'no link'; then +# ewarn "No link on ${IFACE}, aborting configuration" +# return 1 +# fi +# +# # Test for link on the interface prior to bringing it up. This +# # only works on some network adapters and requires the ethtool +# # package to be installed. +# if ethtool "${IFACE}" | grep -q 'Link detected: no'; then +# ewarn "No link on ${IFACE}, aborting configuration" +# return 1 +# fi +# +# +# # Remember to return 0 on success +# return 0 +#} + +#predown() { +# # The default in the script is to test for NFS root and disallow +# # downing interfaces in that case. Note that if you specify a +# # predown() function you will override that logic. Here it is, in +# # case you still want it... +# if is_net_fs /; then +# eerror "root filesystem is network mounted -- can't stop ${IFACE}" +# return 1 +# fi +# +# # Remember to return 0 on success +# return 0 +#} + +#postup() { +# # This function could be used, for example, to register with a +# # dynamic DNS service. Another possibility would be to +# # send/receive mail once the interface is brought up. + +# # Here is an example that allows the use of iproute rules +# # which have been configured using the rules_eth0 variable. +# #rules_eth0=" \ +# # 'from 24.80.102.112/32 to 192.168.1.0/24 table localnet priority 100' \ +# # 'from 216.113.223.51/32 to 192.168.1.0/24 table localnet priority 100' \ +# #" +# eval set -- $\rules_${IFVAR} +# if [ -n "$@" ] ; then +# einfo "Adding IP policy routing rules" +# eindent +# # Ensure that the kernel supports policy routing +# if ! ip rule list | grep -q "^" ; then +# eerror "You need to enable IP Policy Routing (CONFIG_IP_MULTIPLE_TABLES)" +# eerror "in your kernel to use ip rules" +# else +# for x in "$@" ; do +# ebegin "${x}" +# ip rule add ${x} dev "${IFACE}" +# eend $? +# done +# fi +# eoutdent +# # Flush the cache +# ip route flush cache dev "${IFACE}" +# fi + +#} + +#postdown() { +# # Enable Wake-On-LAN for every interface except for lo +# # Probably a good idea to set RC_DOWN_INTERFACE="no" in /etc/conf.d/rc +# # as well ;) +# [[ ${IFACE} != "lo" ]] && ethtool -s "${IFACE}" wol g + +# Automatically erase any ip rules created in the example postup above +# if interface_exists "${IFACE}" ; then +# # Remove any rules for this interface +# local rule +# ip rule list | grep " iif ${IFACE}[ ]*" | { +# while read rule ; do +# rule="${rule#*:}" +# ip rule del ${rule} +# done +# } +# # Flush the route cache +# ip route flush cache dev "${IFACE}" +# fi + +# # Return 0 always +# return 0 +#} + +#failup() { +# # This function is mostly here for completeness... I haven't +# # thought of anything nifty to do with it yet ;-) +#} + +#faildown() { +# # This function is mostly here for completeness... I haven't +# # thought of anything nifty to do with it yet ;-) +#} diff --git a/conf.d.Linux/rc b/conf.d.Linux/rc new file mode 100644 index 00000000..bd41acf7 --- /dev/null +++ b/conf.d.Linux/rc @@ -0,0 +1,34 @@ + +############################################################################## +# LINUX SPECIFIC OPTIONS + +# This is the number of tty's used in most of the rc-scripts (like +# consolefont, numlock, etc ...) +RC_TTY_NUMBER=11 + +# RC_DOWN_INTERFACE allows you to specify if RC will bring the interface +# completely down when it stops. The default is yes, but there are some +# instances where you may not want this to happen such as using Wake On LAN. +RC_DOWN_INTERFACE="yes" + +# RC_DOWN_HARDDISK allows you to specify if RC will put harddisks to +# standby mode when it stops. +RC_DOWN_HARDDISK="yes" + +# Use this variable to control the /dev management behavior. +# auto - let the scripts figure out what's best at boot +# devfs - use devfs (requires sys-fs/devfsd) +# udev - use udev (requires sys-fs/udev) +# static - let the user manage /dev (YOU need to create ALL device nodes) +RC_DEVICES="auto" + +# UDEV OPTION: +# Set to "yes" if you want to save /dev to a tarball on shutdown +# and restore it on startup. This is useful if you have a lot of +# custom device nodes that udev does not handle/know about. +RC_DEVICE_TARBALL="no" + +# RC_DMESG_LEVEL sets the level at which logging of messages is done to the +# console. See dmesg(8) for more info. +RC_DMESG_LEVEL="1" + diff --git a/conf.d.Linux/volumes b/conf.d.Linux/volumes new file mode 100644 index 00000000..da70e9f6 --- /dev/null +++ b/conf.d.Linux/volumes @@ -0,0 +1,15 @@ +# IMPORTANT +# volumes dependancy order is specified here so users can move it before +# checkroot so that it can create the needed nodes in /dev. +# By default it comes after modules in case the volume required modules +# are not compiled into the kernel. + +#RC_BEFORE="checkroot" +RC_NEED="checkroot" +RC_USE="modules" + +# VOLUME_ORDER allows you to specify, or even remove the volume setup +# for various volume managers (MD, EVMS2, LVM, DM, etc). Note that they are +# stopped in reverse order. + +#VOLUME_ORDER="raid evms lvm dm" diff --git a/conf.d.Linux/wireless.example b/conf.d.Linux/wireless.example new file mode 100644 index 00000000..7b0edd68 --- /dev/null +++ b/conf.d.Linux/wireless.example @@ -0,0 +1,266 @@ +# /etc/conf.d/wireless: +# Global wireless config file for net.* rc-scripts + +############################################################################## +# IMPORTANT +# linux-wlan-ng is not supported as they have their own configuration program +# ensure that /etc/conf.d/net has the entry "!iwconfig" in it's modules line +# Try and use an alternative driver if you need to use this - hostap-driver +# supports non-usb linux-wlan-ng driven devices +############################################################################## + +############################################################################## +# HINTS +############################################################################## +# see net.example for using SSID in variable names +# +# Most users will just need to set the following options +# key_SSID1="s:yourkeyhere enc open" # s: means a text key +# key_SSID2="aaaa-bbbb-cccc-dd" # no s: means a hex key +# preferred_aps="'SSID 1' 'SSID 2'" +# +# Clear? Good. Now configure your wireless network below +############################################################################# + +############################################################################## +# SETTINGS +############################################################################## +# Hard code an SSID to an interface - leave this unset if you wish the driver +# to scan for available Access Points +# Set to "any" to connect to any SSID - the driver picks an Access Point +# This needs to be done when the driver doesn't support scanning +# This may work for drivers that don't support scanning but you need automatic +# AP association +# I would only set this as a last resort really - use the preferred_aps +# setting at the bottom of this file + +# However, using ad-hoc (without scanning for APs) and master mode +# do require the SSID to be set - do this here +#essid_eth0="any" + +# Set the mode of the interface (managed, ad-hoc, master or auto) +# The default is auto +# If it's ad-hoc or master you also may need to specify the channel below +#mode_eth0="auto" + +# If managed mode fails, drop to ad-hoc mode with the below SSID? +#adhoc_essid_eth0="WLAN" + +# Some drivers/hardware don't scan all that well. We have no control over this +# but we can say how many scans we want to do to try and get a better sweep of +# the area. The default is 1. +#scans_eth0="1" + +#Channel can be set (1-14), but defaults to 3 if not set. +# +# The below is taken verbatim from the BSD wavelan documentation found at +# http://www.netbsd.org/Documentation/network/wavelan.html +# There are 14 channels possible; We are told that channels 1-11 are legal for +# North America, channels 1-13 for most of Europe, channels 10-13 for France, +# and only channel 14 for Japan. If in doubt, please refer to the documentation +# that came with your card or access point. Make sure that the channel you +# select is the same channel your access point (or the other card in an ad-hoc +# network) is on. The default for cards sold in North America and most of Europe +# is 3; the default for cards sold in France is 11, and the default for cards +# sold in Japan is 14. +#channel_eth0="3" + +# Setup any other config commands. This is basically the iwconfig argument +# without the iwconfig $iface. +#iwconfig_eth0="" + +# Set private driver ioctls. This is basically the iwpriv argument without +# the iwpriv $iface. If you use the rt2500 driver (not the rt2x00 one) then +# you can set WPA here, below is an example. +#iwpriv_eth0="" +#iwpriv_SSID=" \ +# 'set AuthMode=WPAPSK' \ +# 'set EncrypType=TKIP' \ +# 'set WPAPSK=yourpasskey' \ +#" +#NOTE: Even though you can use WPA like so, you may have to set a WEP key +#if your driver claims the AP is encrypted. The WEP key itself will not be +#used though. + +# Seconds to wait before scanning +# Some drivers need to wait until they have finished "loading" +# before they can scan - otherwise they error and claim that they cannot scan +# or resource is unavailable. The default is to wait zero seconds +#sleep_scan_eth0="1" + +# Seconds to wait until associated. The default is to wait 10 seconds. +# 0 means wait indefinitely. WARNING: this can cause an infinite delay when +# booting. +#associate_timeout_eth0="5" + +# By default a successful association in Managed mode sets the MAC +# address of the AP connected to. However, some drivers (namely +# the ipw2100) don't set an invalid MAC address when association +# fails - so we need to check on link quality which some drivers +# don't report properly either. +# So if you have connection problems try flipping this setting +# Valid options are MAC, quality and all - defaults to MAC +#associate_test_eth0="MAC" + +# Some driver/card combinations need to scan in Ad-Hoc mode +# After scanning, the mode is reset to the one defined above +#scan_mode_eth0="Ad-Hoc" + +# Below you can define private ioctls to run before and after scanning +# Format is the same as the iwpriv_eth0 above +# This is needed for the HostAP drivers +#iwpriv_scan_pre_eth0="'host_roaming 2'" +#iwpriv_scan_post_eth0="'host_roaming 0'" + +# Define a WEP key per SSID or MAC address (of the AP, not your card) +# The encryption type (open or restricted) must match the +# encryption type on the Access Point +# You can't use "any" for an SSID here +#key_SSID="1234-1234-1234-1234-1234-1234-56" +# or you can use strings. Passphrase IS NOT supported +# To use a string, prefix it with s: +# Note - this example also sets the encryption method to open +# which is regarded as more secure than restricted +#key_SSID="s:foobar enc open" +#key_SSID="s:foobar enc restricted" + +# If you have whitespace in your key, here's how to set it and use other +# commands like using open encryption. +#key_SSID="s:'foo bar' enc open" + +# WEP key for the AP with MAC address 001122334455 +#mac_key_001122334455="s:foobar" + +# Here are some more examples of keys as some users find others work +# and some don't where they should all do the same thing +#key_SSID="open s:foobar" +#key_SSID="open 1234-5678-9012" +#key_SSID="s:foobar enc open" +#key_SSID="1234-5678-9012 enc open" + +# You may want to set muliple keys - here's an example +# It sets 4 keys on the card and instructs to use key 2 by default +#key_SSID="[1] s:passkey1 key [2] s:passkey2 key [3] s:passkey3 key [4] s:passkey4 key [2]" + +# You can also override the interface settings found in /etc/conf.d/net +# per SSID - which is very handy if you use different networks a lot +#config_SSID="dhcp" +#dhcpcd_SSID="-t 5" +#routes_SSID= +#fallback_SSID= + +# Setting name/domain server causes /etc/resolv.conf to be overwritten +# Note that if DHCP is used, and you want this to take precedence then +# please put -R in your dhcpcd options +#dns_servers_SSID="192.168.0.1 192.168.0.2" +#dns_domain_SSID="some.domain" +#dns_search_path_SSID="search.this.domain search.that.domain" +# Please check the man page for resolv.conf for more information +# as domain and search (searchdomains) are mutually exclusive and +# searchdomains takes precedence + +# You can also set any of the /etc/conf.d/net variables per MAC address +# incase you use Access Points with the same SSID but need different +# networking configs. Below is an example - of course you use the same +# method with other variables +#config_001122334455="dhcp" +#dhcpcd_001122334455="-t 10" +#dns_servers_001122334455="192.168.0.1 192.168.0.2" + +# Map a MAC address to an SSID +# This is used when the Access Point is not broadcasting it's SSID +# WARNING: This will override the SSID being broadcast due to some +# Access Points sending an SSID even when they have been configured +# not to! +# Change 001122334455 to the MAC address and SSID to the SSID +# it should map to +#mac_essid_001122334455="SSID" + +# This lists the preferred SSIDs to connect to in order +# SSID's can contain any characters here as they must match the broadcast +# SSID exactly. +# Surround each SSID with the " character and seperate them with a space +# If the first SSID isn't found then it moves onto the next +# If this isn't defined then it connects to the first one found +#preferred_aps="'SSID 1' 'SSID 2'" + +# You can also define a preferred_aps list per interface +#preferred_aps_eth0="'SSID 3' 'SSID 4'" + +# You can also say whether we only connect to preferred APs or not +# Values are "any", "preferredonly", "forcepreferred", "forcepreferredonly" and "forceany" +# "any" means it will connect to visible APs in the preferred list and then any +# other available AP +# "preferredonly" means it will only connect to visible APs in the preferred list +# "forcepreferred" means it will forceably connect to APs in order if it does not find +# them in a scan +# "forcepreferredonly" means it forceably connects to the APs in order and does not bother +# to scan +# "forceany" does the same as forcepreferred + connects to any other available AP +# Default is "any" +#associate_order="any" +#associate_order_eth0="any" + +# You can define blacklisted Access Points in the same way +#blacklist_aps="'SSID 1' 'SSID 2'" +#blacklist_aps_eth0="'SSID 3' 'SSID 4'" + +# If you have more than one wireless card, you can say if you want +# to allow each card to associate with the same Access Point or not +# Values are "yes" and "no" +# Default is "yes" +#unique_ap="yes" +#unique_ap_eth0="yes" + +# IMPORTANT: preferred_only, blacklisted_aps and unique_ap only work when +# essid_eth0 is not set and your card is capable of scanning + +# NOTE: preferred_aps list ignores blacklisted_aps - so if you have +# the same SSID in both, well, you're a bit silly :p + + +############################################################################## +# ADVANCED CONFIGURATION +# +# Two functions can be defined which will be called surrounding the +# associate function. The functions are called with the interface +# name first so that one function can control multiple adapters. +# +# The return values for the preassociate function should be 0 +# (success) to indicate that configuration or deconfiguration of the +# interface can continue. If preassociate returns a non-zero value, then +# interface configuration will be aborted. +# +# The return value for the postassociate function is ignored +# since there's nothing to do if it indicates failure. + +#preassociate() { +# # The below adds two configuration variables leap_user_SSID +# # and leap_pass_SSID. When they are both confiugred for the SSID +# # being connected to then we run the CISCO LEAP script +# +# local user pass +# eval user=\"\$\{leap_user_${SSIDVAR}\}\" +# eval pass=\"\$\{leap_pass_${SSIDVAR}\}\" +# +# if [ -n "${user}" -a -n "${pass}" ]; then +# if [ ! -x /opt/cisco/bin/leapscript ]; then +# eend "For LEAP support, please emerge net-misc/cisco-aironet-client-utils" +# return 1 +# fi +# einfo "Waiting for LEAP Authentication on \"${SSID//\\\\//}\"" +# if /opt/cisco/bin/leapscript ${user} ${pass} | grep -q 'Login incorrect'; then +# ewarn "Login Failed for ${user}" +# return 1 +# fi +# fi +# +# return 0 +#} + +#postassociate() { +# # This function is mostly here for completeness... I haven't +# # thought of anything nifty to do with it yet ;-) +# # Return 0 always +# return 0 +#} diff --git a/conf.d/Makefile b/conf.d/Makefile new file mode 100644 index 00000000..5f9f1411 --- /dev/null +++ b/conf.d/Makefile @@ -0,0 +1,6 @@ +DIR = /etc/conf.d +FILES_NOEXIST = bootmisc checkfs clock env_whitelist hostname \ + local.start local.stop net rc + +TOPDIR = .. +include $(TOPDIR)/default.mk diff --git a/conf.d/bootmisc b/conf.d/bootmisc new file mode 100644 index 00000000..e33c03b3 --- /dev/null +++ b/conf.d/bootmisc @@ -0,0 +1,12 @@ +# /etc/conf.d/bootmisc + +# Put a nologin file in /etc to prevent people from logging in before +# system startup is complete + +DELAYLOGIN="no" + + +# Should we completely wipe out /tmp or just selectively remove known +# locks / files / etc... ? + +WIPE_TMP="yes" diff --git a/conf.d/checkfs b/conf.d/checkfs new file mode 100644 index 00000000..868dfaba --- /dev/null +++ b/conf.d/checkfs @@ -0,0 +1,8 @@ +# FSCK_SHUTDOWN causes checkfs to trigger during shutdown as well as startup. +# The end result of this is that if any periodic non-root filesystem checks are +# scheduled, under normal circumstances the actual check will happen during +# shutdown rather than at next boot. +# This is useful when periodic filesystem checks are causing undesirable +# delays at startup, but such delays at shutdown are acceptable. + +FSCK_SHUTDOWN="no" diff --git a/conf.d/clock b/conf.d/clock new file mode 100644 index 00000000..f11df3fa --- /dev/null +++ b/conf.d/clock @@ -0,0 +1,16 @@ +# /etc/conf.d/clock + +# Set CLOCK to "UTC" if your system clock is set to UTC (also known as +# Greenwich Mean Time). If your clock is set to the local time, then +# set CLOCK to "local". Note that if you dual boot with Windows, then +# you should set it to "local". + +CLOCK="UTC" + +# Select the proper timezone. For valid values, peek inside of the +# /usr/share/zoneinfo/ directory. For example, some common values are +# "America/New_York" or "EST5EDT" or "Europe/Berlin". If you want to +# manage /etc/localtime yourself, set this to "". + +#TIMEZONE="Factory" + diff --git a/conf.d/env_whitelist b/conf.d/env_whitelist new file mode 100644 index 00000000..30a3695a --- /dev/null +++ b/conf.d/env_whitelist @@ -0,0 +1,6 @@ +# /etc/conf.d/env_whitelist: Environment whitelist for rc-system + +# Specify which variables are allowed to be passed from the environment to the +# rc-system. If it is not set by the environment, then the variable will be +# taken from /etc/profile.env - meaning, if you need to set LANG or such, +# do it in a /etc/env.d/99myownstuff file for example, and run env-update. diff --git a/conf.d/hostname b/conf.d/hostname new file mode 100644 index 00000000..619abcd3 --- /dev/null +++ b/conf.d/hostname @@ -0,0 +1,4 @@ +# /etc/conf.d/hostname + +# Set to the hostname of this machine +HOSTNAME="localhost" diff --git a/conf.d/local.start b/conf.d/local.start new file mode 100644 index 00000000..7a20c142 --- /dev/null +++ b/conf.d/local.start @@ -0,0 +1,5 @@ +# /etc/conf.d/local.start + +# This is a good place to load any misc programs +# on startup (use &>/dev/null to hide output) + diff --git a/conf.d/local.stop b/conf.d/local.stop new file mode 100644 index 00000000..7dc89f63 --- /dev/null +++ b/conf.d/local.stop @@ -0,0 +1,8 @@ +# /etc/conf.d/local.stop + +# This is a good place to unload any misc. +# programs you started above. +# For example, if you are using OSS and have +# "/usr/local/bin/soundon" above, put +# "/usr/local/bin/soundoff" here. + diff --git a/conf.d/net b/conf.d/net new file mode 100644 index 00000000..54337cf0 --- /dev/null +++ b/conf.d/net @@ -0,0 +1,4 @@ +# This blank configuration will automatically use DHCP for any net.* +# scripts in /etc/init.d. To create a more complete configuration, +# please review /etc/conf.d/net.example and save your configuration +# in /etc/conf.d/net (this file :]!). diff --git a/conf.d/rc b/conf.d/rc new file mode 100644 index 00000000..25203f3e --- /dev/null +++ b/conf.d/rc @@ -0,0 +1,87 @@ +# /etc/conf.d/rc: Global config file for the Gentoo RC System + +# Set to "yes" if you want the rc system to try and start services +# in parallel for a slight speed improvement. NOTE: When enabled +# init script output is buffered and displayed in one go when finished. +RC_PARALLEL_STARTUP="no" + +# Set RC_INTERACTIVE to "yes" and you'll be able to press the I key during +# boot so you can choose to start specific services. Set to "no" to disable +# this feature. +RC_INTERACTIVE="yes" + +# RC_VERBOSE will make init scripts more verbose and adds +# "Service FOO starting/started/stopping/stopped" messages around each +# init script. +RC_VERBOSE="no" + +# RC_QUIET on the other hand will make init scripts quiet and produce no +# output. +RC_QUIET="no" + + +# Do we allow any started service in the runlevel to satisfy the depedency +# or do we want all of them regardless of state? For example, if net.eth0 +# and net.eth0 are in the default runlevel then with RC_STRICT_DEPEND="no" +# both will be started, but services that depend on 'net' will work if either +# one comes up. With RC_STRICT_DEPEND="yes" we would require them both to +# come up. +RC_STRICT_DEPEND="no" + +# Do we allow services to be hotplugged? If not, set to RC_HOTPLUG="no" +# NOTE: This does not affect anything hotplug/udev/devd related, just the +# starting/stopping of the init.d service triggered by it. +RC_HOTPLUG="yes" + +# Dynamic /dev managers can trigger coldplug events which cause services to +# start before we are ready for them. If this happens, we can defer these +# services to start in the boot runlevel. Set RC_COLDPLUG="no" if you don't +# want this. +# NOTE: This also affects module coldplugging in udev-096 and higher +# If you want module coldplugging but not coldplugging of services then you +# can set RC_COLDPLUG="yes" and RC_PLUG_SERVICES="!*" +RC_COLDPLUG="yes" + +# Some people want a finer grain over hotplug/coldplug. RC_PLUG_SERVICES is a +# list of services that are matched in order, either allowing or not. By +# default we allow services through as RC_COLDPLUG/RC_HOTPLUG has to be yes +# anyway. +# Example - RC_PLUG_SERVICES="net.wlan !net.*" +# This allows net.wlan and any service not matching net.* to be plugged. +RC_PLUG_SERVICES="" + +# Define network fstypes. Below is the default. +#RC_NET_FS_LIST="afs cifs coda davfs fuse gfs ncpfs nfs nfs4 ocfs2 shfs smbfs" + +# RC_FORCE_AUTO tries its best to prevent user interaction during the boot and +# shutdown process. For example, fsck will automatically be run or volumes +# remounted to create proper directory trees. This feature can be dangerous +# and is meant ONLY for headless machines where getting a physical console +# hooked up is a huge pita. +RC_FORCE_AUTO="no" + + +############################################################################## +# SERVICE CONFIGURATION VARIABLES +# These variables are documented here, but should be configured in +# /etc/conf.d/foo for service foo and NOT enabled here unless you +# really want them to work on a global basis. + +# Some daemons are started and stopped via start-stop-daemon. +# We can launch them through other daemons here, for example valgrind. +# This is only useful for serious debugging of the daemon +# WARNING: If the script's "stop" function does not supply a PID file then +# all processes using the same daemon will be killed. +#RC_DAEMON="/usr/bin/valgrind --tool=memcheck --log-file=/tmp/valgrind.syslog-ng" + +# strace needs to be prefixed with --background as it does not detach when +# it's following +#RC_DAEMON="--background /usr/sbin/strace -f -o /tmp/strace.syslog-ng" + +# Pass ulimit parameters +#RC_ULIMIT="-u 30" + +# It's possible to define extra dependencies for services like so +#RC_NEED="openvpn" +#RC_USE="net.eth0" + diff --git a/default.mk b/default.mk new file mode 100644 index 00000000..e65bad87 --- /dev/null +++ b/default.mk @@ -0,0 +1,54 @@ +# Common makefile settings +# Copyright 2006-2007 Gentoo Foundation + +DESTDIR = / +ROOT = / +LIB = lib + +# +# Recursive rules +# + +SUBDIRS_ALL = $(patsubst %,%_all,$(SUBDIRS)) +SUBDIRS_CLEAN = $(patsubst %,%_clean,$(SUBDIRS)) +SUBDIRS_INSTALL = $(patsubst %,%_install,$(SUBDIRS)) + +all:: $(SUBDIRS_ALL) +clean:: $(SUBDIRS_CLEAN) +install:: $(SUBDIRS_INSTALL) + +# Hmm ... possible to combine these three and not be ugly ? +%_all: + $(MAKE) -C $(patsubst %_all,%,$@) all + if test -d $(patsubst %_all,%,$@).$(OS) ; then $(MAKE) -C $(patsubst %_all,%,$@).$(OS) all ; fi +%_clean: + $(MAKE) -C $(patsubst %_clean,%,$@) clean + if test -d $(patsubst %_clean,%,$@).$(OS) ; then $(MAKE) -C $(patsubst %_clean,%,$@).$(OS) clean ; fi +%_install: + $(MAKE) -C $(patsubst %_install,%,$@) install + if test -d $(patsubst %_install,%,$@).$(OS) ; then $(MAKE) -C $(patsubst %_install,%,$@).$(OS) install ; fi + + +# +# Install rules +# + +INSTALL_DIR = install -m 0755 -d +INSTALL_EXE = install -m 0755 +INSTALL_FILE = install -m 0644 +INSTALL_SECURE = install -m 0600 + +install:: $(EXES) $(FILES) $(FILES_NOEXIST) $(MANS) + test -n $(DIR) && $(INSTALL_DIR) $(DESTDIR)$(DIR) + for x in $(EXES) ; do $(INSTALL_EXE) $$x $(DESTDIR)$(DIR) || exit $$? ; done + for x in $(FILES) ; do $(INSTALL_FILE) $$x $(DESTDIR)$(DIR) || exit $$? ; done + for x in $(FILES_APPEND) ; do if test -e $(DESTDIR)$(DIR)/$$x ; then cat $$x >> $(DESTDIR)$(DIR)/$$x || exit $$? ; else $(INSTALL_FILE) $$x $(DESTDIR)$(DIR) || exit $$? ; fi ; done + for x in $(FILES_NOEXIST) ; do if ! test -e $(DESTDIR)$(DIR)/$$x ; then $(INSTALL_FILE) $$x $(DESTDIR)$(DIR) || exit $$? ; fi ; done + for x in $(FILES_SECURE) ; do $(INSTALL_SECURE) $$x $(DESTDIR)$(DIR) || exit $$? ; done + for x in $(MANS) ; do \ + ext=`echo $$x | sed -e 's/^.*\\.//'` ; \ + $(INSTALL_DIR) $(DESTDIR)$(DIR)/man$$ext || exit $$? ; \ + $(INSTALL_FILE) $$x $(DESTDIR)$(DIR)/man$$ext || exit $$? ; \ + done + +.PHONY: all clean install diff --git a/etc.BSD/COPYRIGHT b/etc.BSD/COPYRIGHT new file mode 100644 index 00000000..378f62fc --- /dev/null +++ b/etc.BSD/COPYRIGHT @@ -0,0 +1,2 @@ +Copyright 1996-2007 Gentoo Foundation +Copyright 1992-2007 The FreeBSD Project diff --git a/etc.BSD/Makefile b/etc.BSD/Makefile new file mode 100644 index 00000000..b78ea8b4 --- /dev/null +++ b/etc.BSD/Makefile @@ -0,0 +1,5 @@ +DIR = /etc +FILES = COPYRIGHT issue issue.logo login.conf rc rc.shutdown + +TOPDIR = .. +include $(TOPDIR)/default.mk diff --git a/etc.BSD/issue b/etc.BSD/issue new file mode 100644 index 00000000..7a303dfb --- /dev/null +++ b/etc.BSD/issue @@ -0,0 +1,3 @@ + +This is %h (%s %m %r) %d + diff --git a/etc.BSD/issue.logo b/etc.BSD/issue.logo new file mode 100644 index 00000000..81946e24 --- /dev/null +++ b/etc.BSD/issue.logo @@ -0,0 +1,13 @@ + . + .vir. d$b + .d$$$$$$b. .cd$$b. .d$$b. d$$$$$$$$$$$b .d$$b. .d$$b. + $$$$( )$$$b d$$$()$$$. d$$$$$$$b Q$$$$$$$P$$$P.$$$$$$$b. .$$$$$$$b. + Q$$$$$$$$$$B$$$$$$$$P" d$$$PQ$$$$b. $$$$. .$$$P' `$$$ .$$$P' `$$$ + "$$$$$$$P Q$$$$$$$b d$$$P Q$$$$b $$$$b $$$$b..d$$$ $$$$b..d$$$ + d$$$$$$P" "$$$$$$$$ Q$$$ Q$$$$ $$$$$ `Q$$$$$$$P `Q$$$$$$$P + $$$$$$$P `""""" "" "" Q$$$P "Q$$$P" "Q$$$P" + `Q$$P" """ + + +This is %h (%s %m %r) %d + diff --git a/etc.BSD/login.conf b/etc.BSD/login.conf new file mode 100644 index 00000000..e38f1703 --- /dev/null +++ b/etc.BSD/login.conf @@ -0,0 +1,65 @@ +# login.conf - login class capabilities database. +# +# Remember to rebuild the database after each change to this file: +# +# cap_mkdb /etc/login.conf +# +# This file controls resource limits, accounting limits and +# default user environment settings. + +# defaults +# These settings are used by login(1) by default for classless users +# Note that entries like "cputime" set both "cputime-cur" and "cputime-max" + +default:\ + :passwd_format=md5:\ + :copyright=/etc/COPYRIGHT:\ + :welcome=/etc/motd:\ + :setenv=FTP_PASSIVE_MODE=YES:\ + :path=/sbin /bin /usr/sbin /usr/bin /usr/local/sbin /usr/local/bin ~/bin:\ + :nologin=/etc/nologin:\ + :cputime=unlimited:\ + :datasize=unlimited:\ + :stacksize=unlimited:\ + :memorylocked=unlimited:\ + :memoryuse=unlimited:\ + :filesize=unlimited:\ + :coredumpsize=unlimited:\ + :openfiles=unlimited:\ + :maxproc=unlimited:\ + :sbsize=unlimited:\ + :vmemoryuse=unlimited:\ + :priority=0:\ + :ignoretime@:\ + :umask=022: + +# +# Root can always login +# +# N.B. login_getpwclass(3) will use this entry for the root account, +# in preference to 'default'. +root:\ + :ignorenologin:\ + :tc=default: + +# +# A collection of common class names - forward them all to 'default' +# (login would normally do this anyway, but having a class name +# here suppresses the diagnostic) +# +standard:\ + :tc=default: +xuser:\ + :tc=default: +daemon:\ + :tc=default: +news:\ + :tc=default: + +# +# Russian Users Accounts. Setup proper environment variables. +# +#russian|Russian Users Accounts:\ +# :charset=KOI8-R:\ +# :lang=ru_RU.KOI8-R:\ +# :tc=default: diff --git a/etc.BSD/rc b/etc.BSD/rc new file mode 100644 index 00000000..64fb4df9 --- /dev/null +++ b/etc.BSD/rc @@ -0,0 +1,14 @@ +#!/bin/sh +# Copyright 2006-2007 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 + +# Ensure we are called by init +[ "$PPID" = "1" ] || exit 0 + +# BSD's init works somewhat differently to sysvinit. +# This block should 'translate' from the way init calls it to the way it would +# be called by sysvinit on linux. + +RUNLEVEL="1" /sbin/rc sysinit || exit 1 +RUNLEVEL="1" /sbin/rc boot || exit 1 +/sbin/rc default || exit 1 diff --git a/etc.BSD/rc.shutdown b/etc.BSD/rc.shutdown new file mode 100644 index 00000000..737002d4 --- /dev/null +++ b/etc.BSD/rc.shutdown @@ -0,0 +1,17 @@ +#!/bin/sh +# Copyright 2006-2007 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 + +# Ensure we are called by init +[ "$PPID" = "1" ] || exit 0 + +# Try and use stuff in /lib over anywhere else so we can shutdown +# local mounts correctly. +LD_LIBRARY_PATH="/lib${LD_LIBRARY_PATH:+:}${LDLIBRARY_PATH}" +export LD_LIBRARY_PATH + +# BSD's init works somewhat differently to sysvinit. +# This block should 'translate' from the way init calls it to the way it would +# be called by sysvinit on linux. +export RUNLEVEL=S +exec /sbin/rc "$1" diff --git a/etc.Linux/Makefile b/etc.Linux/Makefile new file mode 100644 index 00000000..8a14505b --- /dev/null +++ b/etc.Linux/Makefile @@ -0,0 +1,7 @@ +SUBDIRS = modules.d modules.autoload.d +DIR = /etc +FILES = filesystems inputrc issue issue.logo +FILES_NOEXIST = sysctl.conf + +TOPDIR = .. +include $(TOPDIR)/default.mk diff --git a/etc.Linux/filesystems b/etc.Linux/filesystems new file mode 100644 index 00000000..0bb9c3c5 --- /dev/null +++ b/etc.Linux/filesystems @@ -0,0 +1,14 @@ +# /etc/filesystems +# +# This file defines the filesystems search order used by a +# 'mount -t auto' command. +# + +# Uncomment the following line if your modular kernel has vfat +# support and you want mount to try vfat. +#vfat + +# Keep the last '*' intact as it directs mount to use the +# filesystems list available at /proc/filesystems also. +# Don't remove it unless you REALLY know what you are doing! +* diff --git a/etc.Linux/inputrc b/etc.Linux/inputrc new file mode 100644 index 00000000..8fe3ae15 --- /dev/null +++ b/etc.Linux/inputrc @@ -0,0 +1,67 @@ +# /etc/inputrc: initialization file for readline +# +# For more information on how this file works, please see the +# INITIALIZATION FILE section of the readline(3) man page +# +# Quick dirty little note: +# To get the key sequence for binding, you can abuse bash. +# While running bash, hit CTRL+V, and then type the key sequence. +# So, typing 'ALT + left arrow' in Konsole gets you back: +# ^[[1;3D +# The readline entry to make this skip back a word will then be: +# "\e[1;3D" backward-word +# + +# do not bell on tab-completion +#set bell-style none + +set meta-flag on +set input-meta on +set convert-meta off +set output-meta on + +# Completed names which are symbolic links to +# directories have a slash appended. +set mark-symlinked-directories on + +$if mode=emacs + +# for linux console and RH/Debian xterm +"\e[1~": beginning-of-line +"\e[4~": end-of-line +#"\e[5~": beginning-of-history +#"\e[6~": end-of-history +"\e[5~": history-search-backward +"\e[6~": history-search-forward +"\e[3~": delete-char +"\e[2~": quoted-insert + +# gnome-terminal (escape + arrow key) +"\e[5C": forward-word +"\e[5D": backward-word +# konsole / xterm / rxvt (escape + arrow key) +"\e\e[C": forward-word +"\e\e[D": backward-word +# konsole (alt + arrow key) +"\e[1;3C": forward-word +"\e[1;3D": backward-word +# aterm / eterm (control + arrow key) +"\eOc": forward-word +"\eOd": backward-word + +$if term=rxvt +"\e[8~": end-of-line +$endif + +# for non RH/Debian xterm, can't hurt for RH/Debian xterm +"\eOH": beginning-of-line +"\eOF": end-of-line + +# for freebsd console +"\e[H": beginning-of-line +"\e[F": end-of-line +$endif + +# fix Home and End for German users +"\e[7~": beginning-of-line +"\e[8~": end-of-line diff --git a/etc.Linux/issue b/etc.Linux/issue new file mode 100644 index 00000000..015e46d5 --- /dev/null +++ b/etc.Linux/issue @@ -0,0 +1,3 @@ + +This is \n.\O (\s \m \r) \t + diff --git a/etc.Linux/issue.logo b/etc.Linux/issue.logo new file mode 100644 index 00000000..d8e20efd --- /dev/null +++ b/etc.Linux/issue.logo @@ -0,0 +1,13 @@ + . + .vir. d$b + .d$$$$$$b. .cd$$b. .d$$b. d$$$$$$$$$$$b .d$$b. .d$$b. + $$$$( )$$$b d$$$()$$$. d$$$$$$$b Q$$$$$$$P$$$P.$$$$$$$b. .$$$$$$$b. + Q$$$$$$$$$$B$$$$$$$$P" d$$$PQ$$$$b. $$$$. .$$$P' `$$$ .$$$P' `$$$ + "$$$$$$$P Q$$$$$$$b d$$$P Q$$$$b $$$$b $$$$b..d$$$ $$$$b..d$$$ + d$$$$$$P" "$$$$$$$$ Q$$$ Q$$$$ $$$$$ `Q$$$$$$$P `Q$$$$$$$P + $$$$$$$P `""""" "" "" Q$$$P "Q$$$P" "Q$$$P" + `Q$$P" """ + + +This is \n.\O (\s \m \r) \t + diff --git a/etc.Linux/modules.autoload.d/Makefile b/etc.Linux/modules.autoload.d/Makefile new file mode 100644 index 00000000..b940e73b --- /dev/null +++ b/etc.Linux/modules.autoload.d/Makefile @@ -0,0 +1,5 @@ +DIR = /etc/modules.autoload.d +FILES_NOEXIST = kernel-2.4 kernel-2.6 + +TOPDIR = ../.. +include $(TOPDIR)/default.mk diff --git a/etc.Linux/modules.autoload.d/kernel-2.4 b/etc.Linux/modules.autoload.d/kernel-2.4 new file mode 100644 index 00000000..56bd841b --- /dev/null +++ b/etc.Linux/modules.autoload.d/kernel-2.4 @@ -0,0 +1,11 @@ +# /etc/modules.autoload.d/kernel-2.4: kernel modules to load when system boots. +# +# Note that this file is for 2.4 kernels. If you need different modules +# for a 2.6 kernel, you can create /etc/modules.autoload.d/kernel-2.6 +# +# Add the names of modules that you'd like to load when the system +# starts into this file, one per line. Comments begin with # and +# are ignored. Read man modules.autoload for additional details. + +# For example: +# aic7xxx diff --git a/etc.Linux/modules.autoload.d/kernel-2.6 b/etc.Linux/modules.autoload.d/kernel-2.6 new file mode 100644 index 00000000..89edd3b9 --- /dev/null +++ b/etc.Linux/modules.autoload.d/kernel-2.6 @@ -0,0 +1,10 @@ +# /etc/modules.autoload.d/kernel-2.6: kernel modules to load when system boots. +# +# Note that this file is for 2.6 kernels. +# +# Add the names of modules that you'd like to load when the system +# starts into this file, one per line. Comments begin with # and +# are ignored. Read man modules.autoload for additional details. + +# For example: +# aic7xxx diff --git a/etc.Linux/modules.d/Makefile b/etc.Linux/modules.d/Makefile new file mode 100644 index 00000000..26c24963 --- /dev/null +++ b/etc.Linux/modules.d/Makefile @@ -0,0 +1,5 @@ +DIR = /etc/modules.d +FILES_NOEXIST = aliases i386 + +TOPDIR = ../.. +include $(TOPDIR)/default.mk diff --git a/etc.Linux/modules.d/aliases b/etc.Linux/modules.d/aliases new file mode 100644 index 00000000..52f30c9b --- /dev/null +++ b/etc.Linux/modules.d/aliases @@ -0,0 +1,42 @@ +# Aliases to tell insmod/modprobe which modules to use + +# Uncomment the network protocols you don't want loaded: +# alias net-pf-1 off # Unix +# alias net-pf-2 off # IPv4 +# alias net-pf-3 off # Amateur Radio AX.25 +# alias net-pf-4 off # IPX +# alias net-pf-5 off # DDP / appletalk +# alias net-pf-6 off # Amateur Radio NET/ROM +# alias net-pf-9 off # X.25 +# alias net-pf-10 off # IPv6 +# alias net-pf-11 off # ROSE / Amateur Radio X.25 PLP +# alias net-pf-19 off # Acorn Econet + +alias char-major-10-175 agpgart +alias char-major-10-200 tun +alias char-major-81 bttv +alias char-major-108 ppp_generic +alias /dev/ppp ppp_generic +alias tty-ldisc-3 ppp_async +alias tty-ldisc-14 ppp_synctty +alias ppp-compress-21 bsd_comp +alias ppp-compress-24 ppp_deflate +alias ppp-compress-26 ppp_deflate + +# Crypto modules (see http://www.kerneli.org/) +alias loop-xfer-gen-0 loop_gen +alias loop-xfer-3 loop_fish2 +alias loop-xfer-gen-10 loop_gen +alias cipher-2 des +alias cipher-3 fish2 +alias cipher-4 blowfish +alias cipher-6 idea +alias cipher-7 serp6f +alias cipher-8 mars6 +alias cipher-11 rc62 +alias cipher-15 dfc2 +alias cipher-16 rijndael +alias cipher-17 rc5 + +# Support for i2c and lm_sensors +alias char-major-89 i2c-dev diff --git a/etc.Linux/modules.d/i386 b/etc.Linux/modules.d/i386 new file mode 100644 index 00000000..b89459f1 --- /dev/null +++ b/etc.Linux/modules.d/i386 @@ -0,0 +1,4 @@ +alias parport_lowlevel parport_pc +alias char-major-10-144 nvram +alias binfmt-0064 binfmt_aout +alias char-major-10-135 rtc diff --git a/etc.Linux/sysctl.conf b/etc.Linux/sysctl.conf new file mode 100644 index 00000000..b3a209e8 --- /dev/null +++ b/etc.Linux/sysctl.conf @@ -0,0 +1,54 @@ +# /etc/sysctl.conf +# +# For more information on how this file works, please see +# the manpages sysctl(8) and sysctl.conf(5). +# +# In order for this file to work properly, you must first +# enable 'Sysctl support' in the kernel. +# +# Look in /proc/sys/ for all the things you can setup. +# + +# Disables packet forwarding +#net.ipv4.ip_forward = 0 +# Disables IP dynaddr +#net.ipv4.ip_dynaddr = 0 +# Disable ECN +#net.ipv4.tcp_ecn = 0 +# Enables source route verification +net.ipv4.conf.default.rp_filter = 1 +# Enable reverse path +net.ipv4.conf.all.rp_filter = 1 + +# Enable SYN cookies (yum!) +# http://cr.yp.to/syncookies.html +#net.ipv4.tcp_syncookies = 1 + +# Disable source route +#net.ipv4.conf.all.accept_source_route = 0 +#net.ipv4.conf.default.accept_source_route = 0 + +# Disable redirects +#net.ipv4.conf.all.accept_redirects = 0 +#net.ipv4.conf.default.accept_redirects = 0 + +# Disable secure redirects +#net.ipv4.conf.all.secure_redirects = 0 +#net.ipv4.conf.default.secure_redirects = 0 + +# Ignore ICMP broadcasts +#net.ipv4.icmp_echo_ignore_broadcasts = 1 + +# Disables the magic-sysrq key +#kernel.sysrq = 0 +# When the kernel panics, automatically reboot in 3 seconds +#kernel.panic = 3 +# Allow for more PIDs (cool factor!); may break some programs +#kernel.pid_max = 999999 + +# You should compile nfsd into the kernel or add it +# to modules.autoload for this to work properly +# TCP Port for lock manager +#fs.nfs.nlm_tcpport = 0 +# UDP Port for lock manager +#fs.nfs.nlm_udpport = 0 diff --git a/etc/Makefile b/etc/Makefile new file mode 100644 index 00000000..190239ec --- /dev/null +++ b/etc/Makefile @@ -0,0 +1,7 @@ +SUBDIRS = env.d + +DIR = /etc +FILES = hosts networks profile protocols rc.conf services shells + +TOPDIR = .. +include $(TOPDIR)/default.mk diff --git a/etc/env.d/00basic b/etc/env.d/00basic new file mode 100644 index 00000000..d19d5401 --- /dev/null +++ b/etc/env.d/00basic @@ -0,0 +1,10 @@ +# /etc/env.d/00basic + +PATH="/opt/bin" +ROOTPATH="/opt/bin" +LDPATH="/usr/local/lib" +MANPATH="/usr/local/share/man:/usr/share/man" +INFOPATH="/usr/share/info" +CVS_RSH="ssh" +PAGER="/usr/bin/less" +LESSOPEN="|lesspipe.sh %s" diff --git a/etc/env.d/Makefile b/etc/env.d/Makefile new file mode 100644 index 00000000..69a3150c --- /dev/null +++ b/etc/env.d/Makefile @@ -0,0 +1,5 @@ +DIR = /etc/env.d +FILES = 00basic + +TOPDIR = ../.. +include $(TOPDIR)/default.mk diff --git a/etc/hosts b/etc/hosts new file mode 100644 index 00000000..8a37ca53 --- /dev/null +++ b/etc/hosts @@ -0,0 +1,31 @@ +# /etc/hosts: Local Host Database +# +# This file describes a number of aliases-to-address mappings for the for +# local hosts that share this file. +# +# In the presence of the domain name service or NIS, this file may not be +# consulted at all; see /etc/host.conf for the resolution order. +# + +# IPv4 and IPv6 localhost aliases +127.0.0.1 localhost +::1 localhost + +# +# Imaginary network. +#10.0.0.2 myname +#10.0.0.3 myfriend +# +# According to RFC 1918, you can use the following IP networks for private +# nets which will never be connected to the Internet: +# +# 10.0.0.0 - 10.255.255.255 +# 172.16.0.0 - 172.31.255.255 +# 192.168.0.0 - 192.168.255.255 +# +# In case you want to be able to connect directly to the Internet (i.e. not +# behind a NAT, ADSL router, etc...), you need real official assigned +# numbers. Do not try to invent your own network numbers but instead get one +# from your network provider (if any) or from your regional registry (ARIN, +# APNIC, LACNIC, RIPE NCC, or AfriNIC.) +# diff --git a/etc/networks b/etc/networks new file mode 100644 index 00000000..48327f00 --- /dev/null +++ b/etc/networks @@ -0,0 +1,8 @@ +# /etc/networks +# +# This file describes a number of netname-to-adress +# mappings for the TCP/IP subsytem. It is mostly +# used at boot time, when no name servers are running. +# + +loopback 127.0.0.0 diff --git a/etc/profile b/etc/profile new file mode 100644 index 00000000..27d6b4d1 --- /dev/null +++ b/etc/profile @@ -0,0 +1,67 @@ +# /etc/profile: login shell setup +# +# That this file is used by any Bourne-shell derivative to setup the +# environment for login shells. +# + +# Load environment settings from profile.env, which is created by +# env-update from the files in /etc/env.d +if [ -e /etc/profile.env ] ; then + . /etc/profile.env +fi + +# 077 would be more secure, but 022 is generally quite realistic +umask 022 + +# Set up PATH depending on whether we're root or a normal user. +# There's no real reason to exclude sbin paths from the normal user, +# but it can make tab-completion easier when they aren't in the +# user's PATH to pollute the executable namespace. +# +# It is intentional in the following line to use || instead of -o. +# This way the evaluation can be short-circuited and calling whoami is +# avoided. +if [ "$EUID" = "0" ] || [ "$USER" = "root" ] ; then + PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:${ROOTPATH}" +else + PATH="/usr/local/bin:/usr/bin:/bin:${PATH}" +fi +export PATH +unset ROOTPATH + +# Extract the value of EDITOR +[ -z "$EDITOR" ] && EDITOR="`. /etc/rc.conf 2>/dev/null; echo $EDITOR`" +[ -z "$EDITOR" ] && EDITOR="/bin/nano" +export EDITOR + +if [ -n "${BASH_VERSION}" ] ; then + # Newer bash ebuilds include /etc/bash/bashrc which will setup PS1 + # including color. We leave out color here because not all + # terminals support it. + if [ -f /etc/bash/bashrc ] ; then + # Bash login shells run only /etc/profile + # Bash non-login shells run only /etc/bash/bashrc + # Since we want to run /etc/bash/bashrc regardless, we source it + # from here. It is unfortunate that there is no way to do + # this *after* the user's .bash_profile runs (without putting + # it in the user's dot-files), but it shouldn't make any + # difference. + . /etc/bash/bashrc + else + PS1='\u@\h \w \$ ' + fi +else + # Setup a bland default prompt. Since this prompt should be useable + # on color and non-color terminals, as well as shells that don't + # understand sequences such as \h, don't put anything special in it. + if type whoami >/dev/null 2>/dev/null && \ + type cut >/dev/null 2>/dev/null && \ + type uname >/dev/null 2>/dev/null ; then + PS1="`whoami`@`uname -n | cut -f1 -d.` \$ " + fi +fi + +for sh in /etc/profile.d/*.sh ; do + [ -r "$sh" ] && . "$sh" +done +unset sh diff --git a/etc/protocols b/etc/protocols new file mode 100644 index 00000000..798a5c8e --- /dev/null +++ b/etc/protocols @@ -0,0 +1,147 @@ +# +# Internet protocols +# +# $FreeBSD: src/etc/protocols,v 1.20 2005/02/22 13:04:02 glebius Exp $ +# from: @(#)protocols 5.1 (Berkeley) 4/17/89 +# +# See also http://www.iana.org/assignments/protocol-numbers +# +ip 0 IP # internet protocol, pseudo protocol number +#hopopt 0 HOPOPT # hop-by-hop options for ipv6 +icmp 1 ICMP # internet control message protocol +igmp 2 IGMP # internet group management protocol +ggp 3 GGP # gateway-gateway protocol +ipencap 4 IP-ENCAP # IP encapsulated in IP (officially ``IP'') +st2 5 ST2 # ST2 datagram mode (RFC 1819) +tcp 6 TCP # transmission control protocol +cbt 7 CBT # CBT, Tony Ballardie +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- - 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 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\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\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 "\/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. +# + +# + +/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. +# + +# + +# 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 +#include + +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 +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include + +/* 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 +#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 +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 +#include + +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined (__OpenBSD__) +#include +#include +#include +#include +#include +#endif + +#ifndef __linux__ +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#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 +#include + +#include +#include +#include +#include +#include +#include +#include + +#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 +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 +#include +#include + +#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 +#include +#include +#include +#include +#include +#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 +#endif +#include +#include +#include +#include +#include +#include +#include + +#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 +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) +#include +#include +#include +#elif defined(__linux__) +#include +#endif + +#include +#include +#include +#include +#include +#include + +#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 +#include + +#include +#include +#include +#include + +#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 +#include +#include +#include +#include + +#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 +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 +#include + +/* 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef __linux__ +#include +#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 +#include +#include +#include + +#include + +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_PAM +#include + +/* 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 | */ + parse_schedule (optarg, sig); + break; + + case 'S': /* --start */ + start = true; + break; + + case 'b': /* --background */ + background = true; + break; + + case 'c': /* --chuid | */ + /* 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 | */ + 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 */ + cmd = optarg; + break; + + case 'o': /* --oknodo */ + oknodo = true; + break; + + case 'p': /* --pidfile */ + pidfile = optarg; + break; + + case 'q': /* --quiet */ + quiet = true; + break; + + case 's': /* --signal */ + sig = parse_signal (optarg); + break; + + case 't': /* --test */ + test = true; + break; + + case 'u': /* --user | */ + 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 */ + 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__ */