summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog4442
-rwxr-xr-xbin/rc-status217
-rw-r--r--etc/conf.d/bootmisc12
-rw-r--r--etc/conf.d/clock26
-rw-r--r--etc/conf.d/consolefont16
-rw-r--r--etc/conf.d/domainname17
-rw-r--r--etc/conf.d/env_whitelist10
-rw-r--r--etc/conf.d/hostname4
-rw-r--r--etc/conf.d/keymaps26
-rw-r--r--etc/conf.d/local.start5
-rw-r--r--etc/conf.d/local.stop8
-rw-r--r--etc/conf.d/net4
-rw-r--r--etc/conf.d/net.example570
-rw-r--r--etc/conf.d/rc180
-rw-r--r--etc/conf.d/wireless.example283
-rw-r--r--etc/env.d/00basic10
-rw-r--r--etc/filesystems14
-rw-r--r--etc/fstab30
-rw-r--r--etc/group43
-rw-r--r--etc/hosts31
-rw-r--r--etc/inittab45
-rw-r--r--etc/inputrc56
-rw-r--r--etc/issue3
-rw-r--r--etc/issue.devfix21
-rw-r--r--etc/issue.logo13
-rw-r--r--etc/modules.autoload.d/kernel-2.411
-rw-r--r--etc/modules.autoload.d/kernel-2.610
-rw-r--r--etc/modules.d/aliases46
-rw-r--r--etc/modules.d/i3864
-rw-r--r--etc/networks8
-rw-r--r--etc/passwd28
-rw-r--r--etc/profile58
-rw-r--r--etc/protocols42
-rw-r--r--etc/rc.conf39
-rw-r--r--etc/services969
-rw-r--r--etc/shadow18
-rw-r--r--etc/shells9
-rw-r--r--etc/sysctl.conf48
-rwxr-xr-xinit.d/bootmisc141
-rwxr-xr-xinit.d/checkfs54
-rwxr-xr-xinit.d/checkroot124
-rwxr-xr-xinit.d/clock144
-rwxr-xr-xinit.d/consolefont68
-rwxr-xr-xinit.d/domainname60
-rwxr-xr-xinit.d/halt.sh242
-rwxr-xr-xinit.d/hostname39
-rwxr-xr-xinit.d/keymaps79
-rwxr-xr-xinit.d/local34
-rwxr-xr-xinit.d/localmount47
-rwxr-xr-xinit.d/modules122
l---------init.d/net.eth01
-rwxr-xr-xinit.d/netmount93
-rwxr-xr-xinit.d/numlock34
-rwxr-xr-xinit.d/reboot.sh8
-rwxr-xr-xinit.d/rmnologin16
-rwxr-xr-xinit.d/shutdown.sh8
-rwxr-xr-xinit.d/urandom37
-rw-r--r--lib/rcscripts/net.modules.d/adsl101
-rw-r--r--lib/rcscripts/net.modules.d/apipa105
-rw-r--r--lib/rcscripts/net.modules.d/bonding125
-rw-r--r--lib/rcscripts/net.modules.d/bridge227
-rw-r--r--lib/rcscripts/net.modules.d/dhclient196
-rw-r--r--lib/rcscripts/net.modules.d/dhcpcd166
-rw-r--r--lib/rcscripts/net.modules.d/essidnet79
-rwxr-xr-xlib/rcscripts/net.modules.d/helpers.d/dhclient-wrapper45
-rwxr-xr-xlib/rcscripts/net.modules.d/helpers.d/dhcp130
-rw-r--r--lib/rcscripts/net.modules.d/helpers.d/dhcp-state31
-rwxr-xr-xlib/rcscripts/net.modules.d/helpers.d/dhcpcd-wrapper48
-rw-r--r--lib/rcscripts/net.modules.d/helpers.d/functions526
-rw-r--r--lib/rcscripts/net.modules.d/helpers.d/module-loader47
-rwxr-xr-xlib/rcscripts/net.modules.d/helpers.d/pump-wrapper14
-rwxr-xr-xlib/rcscripts/net.modules.d/helpers.d/udhcpc-wrapper20
-rw-r--r--lib/rcscripts/net.modules.d/ifconfig435
-rw-r--r--lib/rcscripts/net.modules.d/ipppd103
-rw-r--r--lib/rcscripts/net.modules.d/iproute2376
-rw-r--r--lib/rcscripts/net.modules.d/iptunnel84
-rw-r--r--lib/rcscripts/net.modules.d/iwconfig923
-rw-r--r--lib/rcscripts/net.modules.d/macchanger126
-rw-r--r--lib/rcscripts/net.modules.d/macnet72
-rw-r--r--lib/rcscripts/net.modules.d/netplug123
-rw-r--r--lib/rcscripts/net.modules.d/pump136
-rw-r--r--lib/rcscripts/net.modules.d/rename86
-rw-r--r--lib/rcscripts/net.modules.d/system134
-rw-r--r--lib/rcscripts/net.modules.d/tuntap116
-rw-r--r--lib/rcscripts/net.modules.d/udhcpc153
-rw-r--r--lib/rcscripts/net.modules.d/vlan167
-rw-r--r--lib/rcscripts/net.modules.d/wpa_supplicant350
-rw-r--r--man/MAKEDEV.8392
-rw-r--r--man/consoletype.128
-rw-r--r--man/modules-update.851
-rw-r--r--man/modules.autoload.519
-rw-r--r--man/rc-status.839
-rw-r--r--man/rc-update.846
-rw-r--r--man/start-stop-daemon.8233
-rw-r--r--rc-lists/boot14
-rw-r--r--rc-lists/default3
-rw-r--r--rc-lists/nonetwork1
-rw-r--r--rc-lists/single0
-rwxr-xr-xsbin/MAKEDEV1894
-rwxr-xr-xsbin/MAKEDEV-gentoo.patch210
-rwxr-xr-xsbin/depscan.sh93
-rwxr-xr-xsbin/env-update.sh42
-rwxr-xr-xsbin/functions.sh868
-rwxr-xr-xsbin/modules-update240
-rwxr-xr-xsbin/rc975
-rwxr-xr-xsbin/rc-daemon.sh382
-rwxr-xr-xsbin/rc-help.sh186
-rwxr-xr-xsbin/rc-services.sh883
-rwxr-xr-xsbin/rc-update162
-rwxr-xr-xsbin/runscript.sh581
-rw-r--r--src/.cvsignore5
-rw-r--r--src/Makefile49
-rw-r--r--src/awk/cachedepends.awk210
-rw-r--r--src/awk/functions.awk156
-rw-r--r--src/awk/gendepends.awk562
-rw-r--r--src/awk/genenviron.awk179
-rw-r--r--src/consoletype.c38
-rw-r--r--src/core/.cvsignore3
-rw-r--r--src/core/ChangeLog163
-rw-r--r--src/core/Makefile81
-rw-r--r--src/core/README15
-rw-r--r--src/core/debug.h85
-rw-r--r--src/core/depend.c532
-rw-r--r--src/core/depend.h75
-rw-r--r--src/core/depscan.c297
-rw-r--r--src/core/list.h446
-rw-r--r--src/core/misc.c649
-rw-r--r--src/core/misc.h288
-rw-r--r--src/core/parse.c1033
-rw-r--r--src/core/parse.h110
-rw-r--r--src/core/simple-regex.c854
-rw-r--r--src/core/simple-regex.h86
-rw-r--r--src/core/test-regex.c80
-rw-r--r--src/env_whitelist26
-rw-r--r--src/filefuncs/Makefile17
-rw-r--r--src/filefuncs/filefuncs.c486
-rw-r--r--src/headers.h26
-rw-r--r--src/runscript.c250
-rw-r--r--src/start-stop-daemon.c1375
139 files changed, 29489 insertions, 0 deletions
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..849dc2a
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,4442 @@
+# ChangeLog for Gentoo System Intialization ("rc") scripts
+# Copyright 1999-2005 Gentoo Foundation; Distributed under the GPLv2
+
+* baselayout-1.12.0_pre8 (02 Sep 2005)
+
+ 02 Sep 2005; Martin Schlemmer <azarah@gentoo.org>:
+
+ Split the enviroment whitelist for runscript into a system and user part.
+ Update it to use LIBDIR so that we can set 'lib' or 'lib64'.
+
+ 02 Sep 2005; Roy Marples <uberlord@gentoo.org>:
+
+ netplug module added + documentation for it.
+
+ We also set MTU in the pre_start of ifconfig/iproute2 incase a DHCP
+ client or similar needs it.
+
+ 01 Sep 2005; Roy Marples <uberlord@gentoo.org>:
+
+ Altered iproute2 to use the same lo logic as ifconfig below
+
+ Fixed ifconfig bringing lo up and then working out aliases, bug #104415
+
+ 31 Aug 2005; Martin Schlemmer <azarah@gentoo.org>:
+
+ Add the initial stuff for filtering of env variables for the rc-system.
+
+ Use /sbin/functions.sh instead of /etc/init.d/functions.sh.
+
+ Fix for the 'local starts and stops unneeded' issue when calling /sbin/rc
+ in some cases.
+
+* baselayout-1.12.0_pre7 (31 Aug 2005)
+
+ 31 Aug 2005; Roy Marples <uberlord@gentoo.org>:
+
+ service status requests (either by /etc/init.d/foo status or rc-status)
+ now update the service status by checking daemons and/or pidfiles to check
+ if they are still running or not. To update the status in your own code,
+ source "${svclib}/sh/rc-daemon.sh" and call
+ update_service_status "${service}"
+
+ Trimmed $Header$ from a few files
+
+ 30 Aug 2005; Roy Marples <uberlord@gentoo.org>:
+
+ iwconfig fixed for scanned ad-hoc networks
+ we now prefer managed over ad-hoc when processing scan results
+
+ iwconfig associate_test_quality now works. Fixes #103579 thanks to
+ Harald Schioeberg
+
+ iproute2 now understands ifconfig style netmask routes
+
+ fixed IPv6 address problems in ifconfig and iproute2 modules
+
+ 24 Aug 2005; Roy Marples <uberlord@gentoo.org>:
+
+ rc-daemon now handles --signal correct - fixes #103182
+
+ 19 Aug 2005; Roy Marples <uberlord@gentoo.org>:
+
+ dhcpcd now reports the correct needed version
+
+ iwconfig and wpa_supplicant have better tests for wireless interface
+ which fixes the "lan wlan" problem
+
+* baselayout-1.12.0_pre6 (18 Aug 2005)
+
+ 18 Aug 2005; Roy Marples <uberlord@gentoo.org>:
+
+ RC_AUTO_INTERFACE defaults to NO - but we still default to DHCP
+
+ consoletype is now cached. This has the benefit of being very slightly
+ faster and you now get coloured text for parallel startup
+
+ Parallel startup also does parallel shutdown as well
+
+ You're now warned if you're using a deprecated conf.d/net syntax
+
+ 15 Aug 2005; Roy Marples <uberlord@gentoo.org>:
+
+ iproute2 now understands the old iface_xxx syntax, but this only works
+ if ifconfig (from net-tools) is installed
+
+ 14 Aug 2005; Roy Marples <uberlord@gentoo.org>:
+
+ fallback_route_eth0 now works again
+
+ Implemented interactive startup - fixes #5353
+ Thanks to Paul Pacheco for the patch
+
+ 13 Aug 2005; Roy Marples <uberlord@gentoo.org>:
+
+ Parallel startup races should now be fixed
+
+ iwconfig now scans for mode so you can prefer ad-hoc networks
+
+ 12 Aug 2005; Roy Marples <uberlord@gentoo.org>:
+
+ RC_AUTO_INTERFACE now defaults to no - we no longer mess with /etc unless
+ told too
+
+ tuntap no longer complains about ${devnull}
+
+ We now merge resolv.conf and ntp.conf from active interfaces
+
+ 11 Aug 2005; Roy Marples <uberlord@gentoo.org>:
+
+ Add support for --pid ${pidfile} and --pidfile=${pidfile} in rc-daemon.sh
+
+ Remove tail from depdir() in /sbin/modules-update
+
+* baselayout-1.12.0_pre5 (11 Aug 2005)
+
+ 08 Aug 2005; Roy Marples <uberlord@gentoo.org>:
+
+ Add failup/faildown user functions when an interface fails to come up/go
+ down. Fixes bug #101087.
+
+ 06 Aug 2005; Martin Schlemmer <azarah@gentoo.org>:
+
+ Revert 'mtime' changes to depscan.sh, and just make it warn if it detects
+ that there are files with mtime in the future.
+
+ 06 Aug 2005; Martin Schlemmer <azarah@gentoo.org>:
+
+ Enhance gendepends.awk to check more than one level of dependencies. Also
+ break checking of NEED/USE/BEFORE/AFTER into more stages, so that we can
+ but sure that all NEED's will override the rest, that USE will override
+ BEFORE/AFTER, and also check both the resolved and unresolved trees.
+
+ Also test if RUNLEVEL is '1' besides 'S', fixing 'init 1'.
+
+ Hack init.d/clock to wait for /dev/rtc if compiled as a module ... hopefully
+ udev will get sorted soon.
+
+ Try a workaround for the "mtime in future" issues we have with depscan.sh.
+
+* baselayout-1.12.0_pre4 (05 Aug 2005)
+
+ 05 Aug 2005; Roy Marples <uberlord@gentoo.org>:
+
+ Rationalise if/then/else login in runscript.sh svc_start() and svc_stop()
+
+ Fixed a few quoting issues in iwconfig
+ Use return values instead of capturing stderr output for iwconfig commands
+
+ Added # vim:ts=4 to all net-script files and re-indented
+
+ ${svcdir}/dep{cache,tree} are now chmodded 0644 so users can read them
+
+ 04 Aug 2005; Martin Schlemmer <azarah@gentoo.org>:
+
+ Update /sbin/rc to actually use init's single level, and also to launch
+ sulogin, bug #66834.
+
+ Fix a typo and some logic issues in new trace_dependencies().
+
+ Whitespace cleanups in new trace_dependencies().
+
+ Fix my own logic issue in new trace_dependencies().
+
+ 04 Aug 2005; Roy Marples <uberlord@gentoo.org>:
+
+ interface state directories are now created with -m 0755 to ensure that
+ everyone can read them
+
+ rc-daemon.sh now supports multiple cmds - partial fix for #98745
+
+ trace_dependencies gets a re-write (again) to try and solve the hanging
+ issues that many people are reporting
+
+ More anal about RHS quoting
+
+ 02 Aug 2005; Roy Marples <uberlord@gentoo.org>:
+
+ 0 timeout now means infinite for wpa_supplicant and iwconfig wrt #90443
+
+ iwconfig no longer downs and ups the interface after a scan - instead we
+ set essid any just before doing it
+
+ 01 Aug 2005; Roy Marples <uberlord@gentoo.org>:
+
+ dhclient now has to be told it can edit dhclient.conf instead of assuming
+ it. Final fix to #100745.
+
+ Tweaked module depends to fix order when no dhcp client is found.
+
+ rc-daemon now works with mysql - fixes #100982, thanks to bju from the
+ forums.
+
+ We now only link /etc/{resolv,ntp,yp}.conf when the file exists.
+ We now link back everything in the state dir except for .sv files.
+
+ 30 Jul 2005; Roy Marples <uberlord@gentoo.org>:
+
+ Fixed associate_order "forcepreferred" #100799, thanks to Benoit Boissinot.
+
+ 29 Jul 2005; Roy Marples <uberlord@gentoo.org>:
+
+ Fixed dhclient sending hostname #100745, thanks to Benoit Boissinot.
+
+* baselayout-1.12.0_pre3 (29 Jul 2005)
+
+ 26 Jul 2005; Martin Schlemmer <azarah@gentoo.org>:
+
+ Remove the "parallel" depend stuff from the awk backend.
+
+ Remove the "parallel" depend stuff from the help.
+
+ 26 Jul 2005; Roy Marples <uberlord@gentoo.org>:
+
+ Removed the "parallel" depend for init scripts and related functions.
+ The RC_PARALLEL_STARTUP works well for all - no need for init scripts to
+ state if they parallel or not.
+
+ Removed loops from trace_dependencies for a nice speed boost.
+
+ Fixed failure in runscript.sh to proceed when a non needed dependency
+ (ie use, after, before) failed to start.
+
+ 25 Jul 2005; Martin Schlemmer <azarah@gentoo.org>:
+
+ If we do not have net services, check both boot and current runlevel for
+ net services in trace_dependencies(). Sort services and make sure they
+ are unique.
+
+ Fix the adding of dependencies to properly add netservices as 'net'.
+
+ 25 Jul 2005; Roy Marples <uberlord@gentoo.org>:
+
+ trace_dependencies no longer clobbers the net service.
+
+ RC_AUTO_INTERFACE no longer symlinks /etc/{resolv,ntp,yp}.conf when no.
+
+ 25 Jul 2005; Martin Schlemmer <azarah@gentoo.org>:
+
+ Do not restart dependencies on runlevel change if the service that needs
+ them are in the next runlevel.
+
+* baselayout-1.12.0_pre2 (22 Jul 2005)
+
+ 22 Jul 2005; Roy Marples <uberlord@gentoo.org>:
+
+ When a service is stopped, the IN_BACKGROUND variable is cleared
+ before any dependencies are stopped so they are not marked inactive.
+ The IN_BACKGROUND variable is then restored so the parent script can be
+ marked inactive.
+
+ 21 Jul 2005; Mike Frysinger <vapier@gentoo.org>:
+
+ Change the -l option to tar to --one-file-system #99775.
+
+ Add a --debug option to depscan.sh.
+
+ 21 Jul 2005; Martin Schlemmer <azarah@gentoo.org>:
+
+ Fix hangs in bootup, bug #99663.
+
+ 21 Jul 2005; Roy Marples <uberlord@gentoo.org>:
+
+ dhclient now sets the hostname correctly.
+
+ Fixed some start/stop/restart logic for #99663.
+
+ Stopped rc-status from checking failed and broken which no longer apply.
+
+ 20 Jul 2005; Mike Frysinger <vapier@gentoo.org>:
+
+ Make sure the X11 dirs are always created in /tmp #99679 by Marc Ballarin.
+
+ 20 Jul 2005; Roy Marples <uberlord@gentoo.org>:
+
+ Fixed <wpa_supplicant-0.4 support
+
+ Removed trailing tab from local.start - fixes #99624
+
+ Moved RC_AUTO_INTERFACE definition to /etc/conf.d/rc
+
+ 19 Jul 2005; Mike Frysinger <vapier@gentoo.org>:
+
+ Punt the cyrus/mysql/slocate/vpopmail users/groups to the
+ respective ebuilds.
+
+ Removed trailing tab from local.start - fixes #99624
+
+ 19 Jul 2005; Roy Marples <uberlord@gentoo.org>:
+
+ ${ESSID} and ${ESSIDVAR} are now available in predown() - fixes #99106
+
+ 18 Jul 2005; Roy Marples <uberlord@gentoo.org>:
+
+ Changed wpa-supplicant to wpa_supplicant when reporting that it is not
+ installed. Fixes #99381
+
+ Fixed some startup problems caused by a mixture of inactive +
+ begin_service/end_service functions.
+
+ 16 Jul 2005; Martin Schlemmer <azarah@gentoo.org>:
+
+ Add Darwin support for start-stop-daemon, bug #82421.
+
+ 15 Jul 2005; Martin Schlemmer <azarah@gentoo.org>:
+
+ Do not run depmod in modules-update if System.map is missing, bug #59188.
+
+* baselayout-1.12.0_pre1 (14 Jul 2005)
+
+ 13 Jul 2005; Roy Marples <uberlord@gentoo.org>:
+
+ pump-0.8.21-r4 now creates ntp.conf by itself so the ntp.conf creation
+ code has been removed from the pump module and helper.
+
+ Moved wpa_supplicant and iwconfig et all from /usr/sbin to /sbin
+
+ 12 Jul 2005; Roy Marples <uberlord@gentoo.org>:
+
+ Added dhcp_eth0="nogateway" option, generic to all dhcp clients.
+ Fixes #98466
+
+ 11 Jul 2005; Martin Schlemmer <azarah@gentoo.org>:
+
+ Add fix -r to unmount to be -n .. bug #98667, thanks to Patrick McLean.
+
+ 11 Jul 2005; Roy Marples <uberlord@gentoo.org>:
+
+ udhcpc/dhclient helpers no longer flush IPv6 addresses - fixes #98539
+
+ wpa_supplicant now marks service as stopped when using wpa_supplicant-0.4.x
+ and we have associated but failed to configure in the background.
+
+ 09 Jul 2005; Mike Frysinger <vapier@gentoo.org>:
+
+ Only remount the / filesystem readonly if it isn't already and don't
+ screw around with net filesystems #98405 in init.d/checkroot.
+
+ Add support for completely wiping out /tmp and in general clean up
+ the bootmisc file #56592.
+
+ Add back in support for mounting usbfs under usbgid #35860.
+
+ 09 Jul 2005; Martin Schlemmer <azarah@gentoo.org>:
+
+ Add workaround for evms device names and 'RC_DEVICE_TARBALL="yes"'. Patch
+ by Olaf Niermann, bug #95799.
+
+ 07 Jul 2005; Roy Marples <uberlord@gentoo.org>:
+
+ Added "nosendhost" dhcp option so users can request not to send their
+ machines hostname by default. Fixes #98132 - Patch by Eli.
+
+ 04 Jul 2005; Roy Marples <uberlord@gentoo.org>:
+
+ Added a rename module to rename interfaces based on MAC address
+ (preferred) or current name. Fixes #76328
+
+ 03 Jul 2005; Roy Marples <uberlord@gentoo.org>:
+
+ Fixed module depends in net.lo
+
+ Remove the "no net scripts in boot runlevel" restriction as we now
+ have a hotplug policy setup instead
+
+ 02 Jul 2005; Roy Marples <uberlord@gentoo.org>:
+
+ net.lo no longer needs find or diff
+
+ 01 Jul 2005; Roy Marples <uberlord@gentoo.org>:
+
+ Minor tweaks to all dhcp modules - basically better quoting so that
+ the eval ${dhcpclient} calls work better
+
+ pump can now be backgrounded
+
+ Tweaked the dhcp helpers so that more code is shared
+
+ A few tweaks to runscript.sh and rc-services.sh to avoid races
+
+ bootmisc now cleans /var/lib/net-scripts/state/*
+
+ 30 Jun 2005; Roy Marples <uberlord@gentoo.org>:
+
+ pump can now use route metrics and store it's configs in
+ /var/lib/net-scripts/state/${iface}
+
+ 29 Jun 2005; Roy Marples <uberlord@gentoo.org>:
+
+ dhclient now parses dhclient_eth0 for -cf parameter to set ${cffile}
+ dhclient now strips lines starting with script and send host-name
+ from ${cffile} and adds send host-name "${HOSTNAME}"; at the top
+ To stop this behaviour, add dhclient_edit_config="no" to /etc/conf.d/net
+ Fixes #96322
+
+ Removed killing udhcpc hard as it now dies nicely
+
+ wireless.runlevel now works
+
+ 28 Jun 2005; Mike Frysinger <vapier@gentoo.org>:
+
+ Add davfs to the net list #97283 by Erik Grinaker.
+
+ 28 Jun 2005; Roy Marples <uberlord@gentoo.org>:
+
+ wpa_supplicant now respects the background=no option if
+ wpa_suppliant>=0.4.0 is installed
+
+ fixed network dependencies some more
+
+ You can now restart a script marked starting/inactive
+
+ Documented the use of the RC_USE_CONFIG_PROFILE variable in conf.d/rc
+
+ udhcpc now removes stale pidfiles and parses for -(h|H) instead of
+ just --hostname
+
+ 24 Jun 2005; Roy Marples <uberlord@gentoo.org>:
+
+ udhcpc now doesn't send hostname if it's set at the default of localhost
+
+ net.lo will not take down the interface if it does not exist and starting
+ failed to work
+
+ 21 Jun 2005; Roy Marples <uberlord@gentoo.org>:
+
+ interfaces can now dynamically add themselves to a bridge using
+ bridge_add_eth0="br0" - they are dynamically removed as well. Fixes #93321
+
+ 20 Jun 2005; Roy Marples <uberlord@gentoo.org>:
+
+ ifconfig now reports correct MAC address
+
+ ifconfig and iproute2 now support mtu_eth0 option
+
+ net.lo attemts to arping the requested address when RC_AUTO_INTERFACE==yes
+
+ iwconfig and wpa_supplicant now check rk_kill if available and produce a
+ suitable error if rf is killed #56430
+
+ added hotplug policy check for interface name #78495
+
+ 19 Jun 2005; Mike Frysinger <vapier@gentoo.org>:
+
+ Make sure /proc/cmdline is readable before using it in get_bootconfig()
+ in /sbin/functions.sh.
+
+ 17 Jun 2005; Roy Marples <uberlord@gentoo.org>:
+
+ Fixed VLAN documentation for working with eth0.1 style names #95121
+
+ tarball.sh now works with svn
+
+ dhclient and udhcpc now report any errors to stdout
+
+ RC_DEVICE_TARBALL now defaults to "no"
+
+ STYLE updates to all modules
+
+ 16 Jun 2005; Mike Frysinger <vapier@gentoo.org>:
+
+ Add lmtp as an alias to the 2003 tcp port #96190.
+
+ Add support for Xen to clock init.d #96240 by Christopher G. Stach II.
+
+ When we mount readonly, make sure we don't attempt the same mountpoint
+ twice #96259 by Toralf Förster.
+
+ 14 Jun 2005; Roy Marples <uberlord@gentoo.org>:
+
+ dhclient now calls /etc/dhcp/dhclient-exit-hooks when it exits
+ fixes #96000
+
+ 13 Jun 2005; Roy Marples <uberlord@gentoo.org>:
+
+ /etc/{resolv,ntp,yp}.conf now link to /var/lib/net-scripts
+
+ 13 Jun 2005; Mike Frysinger <vapier@gentoo.org>:
+
+ Remove etc/ppp since the ppp package provides this stuff.
+
+ 05 Jun 2005; Mike Frysinger <vapier@gentoo.org>:
+
+ Run sysctl in quiet mode so we don't force errors to /dev/null.
+
+ 02 Jun 2005; Roy Marples <uberlord@gentoo.org>:
+
+ dhcp helper module fixes
+
+ dhcpcd-backgrounder renamed to dhcpcd-wrapper
+
+ dhcpcd-wrapper applies dns_search_domains_* to /etc/resolv.conf
+ fixes #94027 when used with dhcpcd-1.3.22_p4-r10
+
+ dhcpcd module now applies route metric if possible
+
+ 01 Jun 2005; Roy Marples <uberlord@gentoo.org>:
+
+ removed cruft from net-scripts functions helper as rc-services.sh can
+ now be sourced by our dhcp helpers without causing errors.
+
+ system module now creates it's temporary files in /tmp instead of /etc
+
+ 31 May 2005; Mike Frysinger <vapier@gentoo.org>:
+
+ Add support for bootlogging (via blogd in showconsole package).
+
+ Rewrite the modules.autoload code in init.d/modules to work off the
+ current arbitrary kernel version #35872.
+
+ 29 May 2005; Mike Frysinger <vapier@gentoo.org>:
+
+ Make sure we quote EDITOR in /etc/profile #94412 by Stanislav Brabec.
+
+ 27 May 2005; Roy Marples <uberlord@gentoo.org>:
+
+ Added macnet module (like essidnet but for mac addresses)
+ Regresses macchanger one version
+ Tweaked module depends for macnet
+ dhcp helper now uses macnet
+
+ is_net_fs now works with what $1 was mounted as, not would it would
+ be remounted as - fixes #53104
+
+ 26 May 2005; Roy Marples <uberlord@gentoo.org>:
+
+ report ${myservice} instead of $0 when disallowing net scripts to work in
+ the boot runlevel - fixes #91534
+
+ You can now configure all options via the MAC address of your network card
+ and the MAC address of AP you connect to like so
+ config_001122334455=( "192.168.0.2/24 brd +")
+ Fixes the last part of #52975
+
+ The old way of configuring for the MAC address of the AP is no longer
+ supported
+
+ 25 May 2005; Mike Frysinger <vapier@gentoo.org>:
+
+ Add gfs to the NET_FS_LIST #93911 by Thomas Rasch.
+
+ 25 May 2005; Roy Marples <uberlord@gentoo.org>:
+
+ networking now expands configuration parameters - fixes #91564
+ so config_eth0=( "192.168.{1..3}.{1..3}/24 brd +" ) expands into
+ config_eth0=(
+ "192.168.1.1/24 brd +"
+ "192.168.1.2/24 brd +"
+ "192.168.1.3/24 brd +"
+ "192.168.2.1/24 brd +"
+ "192.168.2.2/24 brd +"
+ "192.168.2.3/24 brd +"
+ "192.168.3.1/24 brd +"
+ "192.168.3.2/24 brd +"
+ "192.168.3.3/24 brd +"
+ )
+
+ updated ESSID variables example in wireless.example - fixes #92469
+
+ 21 May 2005; Martin Schlemmer <azarah@gentoo.org>:
+
+ Quiet down valid_i() if ${svcdir}/softlevel do not yet exist, try #2.
+
+ 20 May 2005; Roy Marples <uberlord@gentoo.org>:
+
+ fix ifconfig to understand CIDR addresses - bug #93237
+ iproute2 now works out broadcast addresses
+
+ added #!/bin/bash or #!/bin/sh to modules and helpers so they now get
+ nice syntax highlighting and indenting
+
+ 20 May 2005; Martin Schlemmer <azarah@gentoo.org>:
+
+ Fixup sbin/{depscan.sh,modules-update} to use is_older_than() for mtime
+ logic. Some small tweaks regarding 2.6 systems and modules-update.
+
+ 19 May 2005; Roy Marples <uberlord@gentoo.org>:
+
+ Merged Paul Pacheco's parallel startup #69854 and modules update
+ #55329 patches
+
+ If RC_PARALLEL_STARTUP==yes then we no longer output einfo/ebegin
+ messages as they don't line up on screen correctly - instead we output
+ service ${myservice} starting/started/stopping/stopped/failed
+
+ 17 May 2005; Mike Frysinger <vapier@gentoo.org>:
+
+ Make sure /dev is mounted with exec since many video drivers need to
+ mmap() device nodes in there with exec access #92921 by Lachlan Pease.
+
+ 16 May 2005; Mike Frysinger <vapier@gentoo.org>:
+
+ If halt/reboot failed, try to force it as a fallback.
+
+ Add RC_FORCE_AUTO setting so people can try to minimize amount of
+ user interaction required for booting.
+
+ Move nsswitch.conf to glibc.
+
+ 15 May 2005; Roy Marples <uberlord@gentoo.org>:
+
+ udhcpc and dhclient now select the best interface when one goes down
+
+ 14 May 2005; Mike Frysinger <vapier@gentoo.org>:
+
+ Make sure /dev is mounted with sane permissions #87745 by Jordan.
+
+ When we search /etc/fstab for /, make sure we handle mounts that have
+ UUID/LABEL info in them #90603 by Alessandro Sappia.
+
+ Simplify rc-script error checking so we don't need a tempfile and so
+ non-root users can run /etc/init.d/status #85892 by Stuart Shelton.
+
+ Add a sanity check for devs who write bad scripts and call exit #85298.
+
+ Run irqbalance after /var is rw #85304 by Miroslaw Mieszczak.
+
+ Redo the addon code to prepare for profiling support #74425.
+
+ 12 May 2005; Mike Frysinger <vapier@gentoo.org>:
+
+ Move pam files out of baselayout and into packages #92387.
+
+ 10 May 2005; Martin Schlemmer <azarah@gentoo.org>:
+
+ Really fix trace_dependencies() to handle net.* services properly.
+
+ Quiet down valid_i() if ${svcdir}/softlevel do not yet exist.
+
+ 10 May 2005; Martin Schlemmer <azarah@gentoo.org>:
+
+ Fix get_service_index() being off by one. Fix trace_dependencies() to also
+ take "net" into regard if its a net_service. This fixes two problems, first
+ shutdown should bring services down that uses net before the net.* services,
+ and secondly '/etc/init.d/net.eth0 needsme', etc should now work properly.
+ All changes to sbin/rc-services.sh.
+
+ 03 May 2005; Roy Marples <uberlord@gentoo.org>:
+
+ changed default indentation to 2 spaces to match rcscripts in functions.sh
+
+ wpa_supplicant now stops wpa_cli before wpa_supplicant to fix a potential
+ future error
+
+ 02 May 2005; Roy Marples <uberlord@gentoo.org>:
+
+ Fix user function hooks for echoing to stdout and protecting our vars
+
+ 30 Apr 2005; Martin Schlemmer <azarah@gentoo.org>:
+
+ Do not create the udev devices.tar.bz2 if we do not have write permissions
+ for /. Request by Donnie (spyderous) for boxes with / on NFS.
+
+ 30 Apr 2005; Martin Schlemmer <azarah@gentoo.org>:
+
+ Fixor column/color logic for when used in portage.
+
+ 29 Apr 2005; Mike Frysinger <vapier@gentoo.org>:
+
+ Move crypto-loop to util-linux and skel bash files to bash.
+
+ 28 Apr 2005; Mike Frysinger <vapier@gentoo.org>:
+
+ Export the 'service name' for init scripts #86348.
+
+ 28 Apr 2005; Martin Schlemmer <azarah@gentoo.org>:
+
+ If no /etc/modules.conf exist, do not 'touch' it, but create a new
+ file with the 'modules-update header' in it to get modules-update
+ to do the right thing (regen), and not just quit (init.d/modules).
+
+ 27 Apr 2005; Mike Frysinger <vapier@gentoo.org>:
+
+ Ignore trailing comments in module files #88553.
+
+ 26 Apr 2005; Mike Frysinger <vapier@gentoo.org>:
+
+ Sync special var's with portage's env-update.sh and ours #88819.
+
+ 26 Apr 2005; Roy Marples <uberlord@gentoo.org>:
+
+ wpa_supplicant now supports wpa_supplicant-0.4.0
+
+ iwconfig downs and ups the interface after a scan
+
+ 25 Apr 2005; Roy Marples <uberlord@gentoo.org>:
+
+ iproute2 now handles mtu the same way as ifconfig - fixes #90242
+
+ net.lo no longer errors when using postdown and postup functions
+
+ 22 Apr 2005; Roy Marples <uberlord@gentoo.org>:
+
+ Address network routes now get metrics applied as well
+ (ie a route automatically added when an address is added)
+
+ net.lo no longer errors when exlcuding modules who are installed
+
+* rc-scripts 1.7.1 (19 Apr 2005)
+
+ 18 Apr 2005; Roy Marples <uberlord@gentoo.org>:
+
+ Changed "sed -ne" to "sed -n -e" for portability.
+
+ Added auto_interface (default yes).
+ if auto_interface is yes then we
+ *) default to dhcp
+ *) automatically calculate a metric (this may need work)
+ *) select the best interface based on metric
+ (restore resolv.conf, ntp.conf and yp.conf we have saved)
+ otherwise we
+ *) default to null
+
+ wpa_supplicant no longer kills itself when we're not stopping the interface
+ it's running on.
+
+ wpa_supplicant now uses wpa_monitor (yet to be released) if available.
+
+ Added a new module called system which enables the definition of domain
+ name, dns servers, ntp servers, nis domain and nis servers per interface.
+ essidnet and dhcp helpers have been re-coded around this module.
+
+ 15 Apr 2005; Chris Gianelloni <wolf31o2@gentoo.org> -bin/bashlogin,
+ -sbin/livecd-functions.sh:
+ Removed sbin/livecd-functions.sh and bin/bashlogin as they are only used in
+ release building, and they have been moved to livecd-tools.
+
+ 14 Apr 2005; Martin Schlemmer <azarah@gentoo.org>:
+
+ Do not kill udevd in /sbin/rc, as it is apparently evil.
+
+ 14 Apr 2005; Roy Marples <uberlord@gentoo.org>:
+
+ Fixed ifconfig and iproute2 erroring from new lo code - fixes #88006
+
+ If /proc/net/netlink does not exist then iproute2 will fail the
+ check_installed function with an appropriate error - Thanks to
+ Jeremy Huddleston for the patch.
+
+ If /proc/net/packet does not exist then wpa_supplicant will fail
+ check_installed function with an appropriate error
+
+ Background fixes for net.lo, udhcpc and wpa_supplicant
+
+ 11 Apr 2005; Roy Marples <uberlord@gentoo.org>:
+
+ removed ${devnull} from net.lo and net-script modules
+ updated all modules not to re-direct stderr where appropriate
+
+ iwconfig and wpa_supplicant now save their current ESSID via save_options
+ and reload it in their pre_stops so that ${ESSID} and ${ESSIDVAR} can be
+ used in users custom postdown functions
+
+ wpa_supplicant now calls iwconfig_defaults and iwconfig_user_config
+ if available - fixes #88703
+
+ 09 Apr 2005; Mike Frysinger <vapier@gentoo.org>:
+
+ Have the 'status' function return 0/1 based upon the status of the
+ init script #88319 by Josh Nichols.
+
+ 08 Apr 2005; Roy Marples <uberlord@gentoo.org>:
+
+ added a bash_variable to functions.sh which converts the given string
+ into a variable that bash can use - fixes #88175
+
+ net scripts can only launch if we're not in ${BOOTLEVEL} - fixes #78495
+
+ 01 Apr 2005; Roy Marples <uberlord@gentoo.org>:
+
+ RC_DAEMON_syslog_ng allows syslog-ng to be started with the specified
+ launcher - like valgrind or strace. Handy for debugging/auditing.
+ Thanks to Rob Holland for the idea.
+
+ Stopped setting ESSID in predown functions in iwconfig and wpa_supplicant
+ as there is no guarantee that the current ESSID is the one we started with
+ Also, we may not have an ESSID at all...
+
+ 23 Mar 2005; Roy Marples <uberlord@gentoo.ord>:
+
+ bridge stops removing IP addresses from bridge ports.
+ iwconfig no longer tries to get an ESSID from non-wireless interfaces.
+ ifconfig no longer errors when deleting addresses on a non-existant
+ interface.
+
+ 23 Mar 2005; Martin Schlemmer <azarah@gentoo.org>:
+
+ Get modules-update to clean up after itself if we on a 2.6 kernel without
+ modules.conf.
+
+ 22 Mar 2005; Roy Marples <uberlord@gentoo.org>:
+
+ revamped rc-services.sh for STYLE updates and code rationalisation.
+
+ 21 Mar 2005; Roy Marples <uberlord@gentoo.org>:
+
+ udhcpc now checks for custom hostname correctly
+
+ 21 Mar 2005; Martin Schlemmer <azarah@gentoo.org>:
+
+ Fix tracing for current service as list_depend_trace() was removed.
+ Fix mylevel not being set if valid_iuse(), etc is called from /sbin/rc.
+
+ 20 Mar 2005; Martin Schlemmer <azarah@gentoo.org>:
+
+ Take sort_services function from bug #70009, and fix the removing of a
+ service from a array properly by using unset. Use this instead of the
+ trace_* stuff, and fixup shutdown order.
+
+ 19 Mar 2005; Mike Frysinger <vapier@gentoo.org>:
+
+ Make sure we mount svcdir with 0755 and not 0644 #85888.
+
+ 15 Mar 2005; Martin Schlemmer <azarah@gentoo.org>:
+
+ Export myservice when starting critical services, as its needed by
+ some of the addons (dmcrypt for example).
+
+ 12 Mar 2005; Mike Frysinger <vapier@gentoo.org>:
+
+ When shutting down, pass -h to halt too #84654 by Dmitry Karasik.
+
+ 11 Mar 2005; Roy Marples <uberlord@gentoo.org>:
+
+ Prepend rc-daemon.sh functions with rc_ to avoid name conflicts
+
+ 11 Mar 2005; Martin Schlemmer <azarah@gentoo.org>:
+
+ Make sure the last test in init.d/modules do not bork the return
+ value of the script if not true.
+
+ 10 Mar 2005; Mike Frysinger <vapier@gentoo.org>:
+
+ Add udev/selinux support by Chris PeBenito #84337.
+
+ 10 Mar 2005; Martin Schlemmer <azarah@gentoo.org>:
+
+ The system() stuff in *depends.awk should be dosystem().
+
+* rc-scripts 1.7.0 (10 Mar 2005)
+
+ 09 Mar 2005; Roy Marples <uberlord@gentoo.org>:
+
+ changed from $( cat ${file} ) to $( < ${file ) in net-scripts
+
+ fixed ChangeLog corruption
+
+ rc-daemon.sh now works with the env program
+
+ 08 Mar 2005; Roy Marples <uberlord@gentoo.org>:
+
+ rc-services.sh now does a /sbin/depscan.sh -u if we have not got
+ our deptree loaded
+
+ removed net_start/stop function from net.lo, bridge and bonding
+
+ net.lo now supports depend() per interface like so
+ depend_br0() { need net.eth0 net.eth1 }
+
+ 04 Mar 2005; Roy Marples <uberlord@gentoo.org>:
+
+ applied STYLE updates to rc-status
+
+ rc-status now uses find correctly for -maxdepth which fixes #84055
+
+ 03 Mar 2005; Roy Marples <uberlord@gentoo.org>:
+
+ iwconfig now defaults the transmit key to 1
+ bridging and bonding modules now start an interface if it's not
+ marked as started
+
+ 02 Mar 2005; Roy Marples <uberlord@gentoo.org>:
+
+ net_service() now returns 1 for non net-services
+ fixes bug #83352
+
+ 02 Mar 2005; Aron Griffis <agriffis@gentoo.org>:
+
+ Add requote() to functions.sh to help rc-daemon.sh
+
+ 01 Mar 2005; Martin Schlemmer <azarah@gentoo.org>:
+
+ Fix braindead logic in init.d/checkfs ([[ -z $CDBOOT ]] &&, not -n).
+
+ 01 Mar 2005; Roy Marples <uberlord@gentoo.org>
+
+ rc-daemon.sh now provides a working wrapper for start-stop-daemon
+ fixes bug #7198
+
+ removed ps calls from net scripts
+
+ 25 Feb 2005; Chris Gianelloni <wolf31o2@gentoo.org>
+
+ Updated livecd-functions.sh to match what we are using on the LiveCD.
+
+ 25 Feb 2005; Martin Schlemmer <azarah@gentoo.org>:
+
+ Style updates for init.d/halt.sh.
+
+ Only run pam_console_apply if we are actually using pam_console.
+
+ Fix init.d/checkfs, init.d/localmount and init.d/halt.sh to call
+ start_addon, stop_addon, start_volumes and stop_volumes.
+
+ 24 Feb 2005; Martin Schlemmer <azarah@gentoo.org>:
+
+ Update /sbin/modules-update to work without modprobe.old (modutils) for
+ 2.6 kernels.
+
+ Update /etc/init.d/modules so that it will only touch modules.conf if we
+ have a <= 2.4 kernel, or have /sbin/modprobe.old.
+
+ 23 Feb 2005; Martin Schlemmer <azarah@gentoo.org>:
+
+ Remove RAID/LVM/EVMS2/dm-crypt from checkfs and localmount, and
+ add needed {start,stop}-volumes() and {start,stop}-addons().
+
+ Add use tempory file for deptree, bug #48303, thanks to patch from
+ Stefan Hoefer <stefan@hoefer.ch>.
+
+ Add {start,stop}-volumes() to /sbin/functions.sh, as well as
+ RC_VOLUME_ORDER to /etc/conf.d/rc.
+
+ 21 Feb 2005; Mike Frysinger <vapier@gentoo.org>:
+
+ Move the serial init.d to the setserial package.
+
+ Create a rc-status.8 manpage #81917.
+
+ 11 Feb 2005; Mike Frysinger <vapier@gentoo.org>:
+
+ Add UPS kill fixes for halt.sh by Lee Weisz / Remy Blank #46440.
+
+ Define a few more {for,back}ward-word bindings in inputrc to fix up
+ the different GUI terminals #53770 by Arturo Alberto Busleiman.
+
+ 10 Feb 2005; Roy Marples <uberlord@gentoo.org>:
+
+ net.lo now supports fallback_route - fixes #75676
+ due to bash limitations, only one fallback route is supported
+
+ cleaned up dhcp helper
+
+ iproute now appends routes instead of adding them - this allows multiple
+ default routes
+
+ RC_STRICT_NET_CHECKING now supports the none "option" which means
+ that the net service is always up
+
+ 31 Jan 2005; Mike Frysinger <vapier@gentoo.org>:
+
+ Punt the PROTOCOL variable from rc.conf since nothing uses it.
+
+ Punt the consolefont related variables from rc.conf since they've
+ been moved to conf.d/consolefont.
+
+ Import some VServer support from #55973. For now, just add the
+ detection function to functions.sh and support in init.d/clock.
+
+ 07 Feb 2005; Martin Schlemmer <azarah@gentoo.org>:
+
+ Fix /sbin/functions.sh not to run stty during 'emerge depend'.
+
+ 07 Feb 2005; Roy Marples <uberlord@gentoo.org>:
+
+ netmask2cidr now works correctly - fixes #81119
+ Thanks to Benoit Boissinot for the patch
+
+ 06 Feb 2005; Mike Frysinger <vapier@gentoo.org>:
+
+ Remove the apache user and let apache ebuilds handle it #77738.
+
+ 04 Feb 2005; Roy Marples <uberlord@gentoo.org>:
+
+ It's now possible to configure addresses and routes for the loopback
+ interface if required - however you cannot override our defaults
+
+ wpa_supplicant and iwconfig now loop for 5 seconds if essid is
+ not returned straight away
+
+ 31 Jan 2005; Mike Frysinger <vapier@gentoo.org>:
+
+ Fix the test for device-mapper in checkfs #80206.
+
+ Change home of man to /usr/share/man.
+
+* rc-scripts 1.6.9 (30 Jan 2004)
+
+ 30 Jan 2005; Mike Frysinger <vapier@gentoo.org>:
+
+ Use clock, don't need it. Not everyone has a RTC #78997.
+
+ Rewrite the KV_* functions to use pure bash rather than awk #75836.
+
+ Don't use 'none' when mounting virtual filesystems since `umount` can
+ produce some pretty vague output #78684. Fixed sbin/rc and etc/fstab
+ and etc/halt.sh to handle the new format.
+
+ modules-update.8 touchups by Benno Schulenberg #77582.
+
+ Don't symlink /etc/filesystems since it is an user config file #74176.
+
+ Punt the 'guest' user #74737.
+
+ Add support for loopback dm-crypt by Dylan Carlson #73598 and for gpg
+ dm-crypt by Lars Strojny #75659.
+
+ Update crypto-loop to newer util-linux #40874 by jochen / Jürgen Hötzel
+
+ 27 Jan 2005; Roy Marples <uberlord@gentoo.org>:
+
+ removed udhcpc-* and dhclient-* helper modules and replaced them with a
+ generic dhcp module which caters for all interfaces and dhcp clients that
+ need it.
+ We now prefer iproute2 over ifconfig if both are installed.
+
+ 24 Jan 2005; Roy Marples <uberlord@gentoo.org>:
+
+ replaced awk commands with sed equivalents in net-scripts to make us
+ more portable
+ STYLE fixes to many net-scripts modules
+ Removed hardcoded Version and replaced with cvs $Header:
+
+ 17 Jan 2005; Roy Marples <uberlord@gentoo.org>:
+
+ net.lo changed logic to read "only fail if no configuration parameters
+ work, bring interface down and abort". Fixes #78092
+ all modules should now check interface existance correctly - fixes #76385
+ wpa_supplicant now works with EAP - fixes #78367
+
+ 13 Jan 2005; Roy Marples <uberlord@gentoo.org>:
+
+ wpa_supplicant forces ctrl_interface to /var/run/wpa_supplicant
+ and removes stale directories
+ clean_pidfile function no longer errors on empty pidfiles
+ net dependancies corrected in runscript.sh - fixes #77839
+ allow pure IPv6 addresses - fixes #73844
+
+ 12 Jan 2005; Roy Marples <uberlord@gentoo.org>:
+
+ net.lo now ignores dot files when loading modules
+ ipppd module now stops correctly - fixes #73067 again
+
+ 11 Jan 2005; Roy Marples <uberlord@gentoo.org>:
+
+ added "noop" config parameter which means take no action if the interface
+ is up and has an address configured, otherwise continue
+ addresses are now removed when starting an interface - fixes #77111
+
+ 06 Jan 2005; Roy Marples <uberlord@gentoo.org>:
+
+ ifconfig, udhcpc-ifconfig now deletes addresses using 0.0.0.0 for uclibc
+ - fixes #76846
+
+ 04 Jan 2005; Roy Marples <uberlord@gentoo.org>:
+
+ bridge now marks interfaces as UP - fixes #75354
+ bridge, net.lo, iwconfig touched up to match new STYLE
+ net.lo tests the return value of modprobe - fixes #76385
+ iwconfig now sets enc keys through an eval statement - fixes #76601
+ updated wireless.example for whitespace in keys
+ iwconfig now accepts mode "auto" and defaults to it
+
+ 30 Dec 2004; Mike Frysinger <vapier@gentoo.org>:
+
+ Touch up rc-update to match our new STYLE. Also tweak the help
+ to fit in the standard console.
+
+ 23 Dec 2004; Mike Frysinger <vapier@gentoo.org>:
+
+ Merge a bunch of BSD fixes into our .c files.
+
+ 18 Dec 2004; Roy Marples <uberlord@gentoo.org>:
+
+ iwconfig now sets ESSIDVAR for master/ad-hoc modes - fixes #74802
+
+ 17 Dec 2004; Roy Marples <uberlord@gentoo.org>:
+
+ wpa_supplicant - fixed file location for wpa_cli and association test
+ as it they changed in wpa_supplicant-0.3.x
+ wpa_supplicant now brings the interface up before launching - fixes #74637
+
+* rc-scripts 1.6.8 (15 Dec 2004)
+
+ 15 Dec 2004; Mike Frysinger <vapier@gentoo.org>:
+
+ start_critical_service in /sbin/rc should rely on $1 instead of
+ the external variable $x for the service name. #74425
+
+ 15 Dec 2004; Roy Marples <uberlord@gentoo.org>:
+
+ rc-status now reports stopping status
+ Updated documentation to point non-usb linux-wlan-ng users to use
+ hostap-driver instead
+
+ 13 Dec 2004; Martin Schlemmer <azarah@gentoo.org>:
+
+ Tweak init.d/halt.sh to support new text based udev_db ('udevinfo -d' do
+ not work anymore, and there is no space after '(S|N):'). Also check if
+ devices.tar.bz2 is empty before trying to create it, bug #71143.
+
+ 12 Dec 2004; Mike Frysinger <vapier@gentoo.org>:
+
+ Tweak get_mount_fstab to only print the first mount point found and then
+ spit warning messages for extra matches. Also add support for RC_USE_FSTAB
+ so normal users don't have to worry about a broken /etc/fstab.
+
+ Add an additional sanity check to the udev tarball usage. Don't try to
+ unpack an empty or non-existant tarball.
+
+ Tweak the 'static' description so users know they can use it to make
+ /sbin/rc ignore /dev completely.
+
+ 12 Dec 2004; Martin Schlemmer <azarah@gentoo.org>:
+
+ Add suport for using /sbin/udevsend from new udev-048 as hotplug multiplexer.
+
+ 12 Dec 2004; Roy Marples <uberlord@gentoo.org>:
+
+ fixed installed typo in net.lo - fixes #74152. Thanks to Federico Galassi
+
+ dhcpcd and udhcpc now run via the eval statement so quotes can be used
+ in options. Fixes #74053 - thanks to Evan Buswell
+
+ 09 Dec 2004; Roy Marples <uberlord@gentoo.org>:
+
+ fixed net.lo getting vlan config
+ rc doesn't stop hotplugged devices when system is booting - fixes #61594
+ thanks to Andreas Sundebo for the fix
+ rc-status now reports stopping
+
+ 08 Dec 2004; Roy Marples <uberlord@gentoo.org>:
+
+ iwconfig now unsets wireless config and downs interface when backgrounding
+ fails
+ wpa_supplicant now supports backgrounding
+ removed is_in_fstab function and replaced with get_mount_fstab which
+ returns a mount command based on the contents of fstab. Resolves bugs
+ #70044 and #73762
+
+ 07 Dec 2004; Roy Marples <uberlord@gentoo.org>:
+
+ essidnet - fixed setting up search domains
+ ifconfig now reads the old gateway variable correctly - fixes #73641
+ iwconfig now supports backgrounding
+ ifconfig and iproute2 now support function interface_set_mac_address
+ macchanger no longer depends on macchanger if configuring a specific
+ mac address
+
+ fix depstop for net-services when system is booting - should fix #61594
+ added service_stopped function to make reading code easier and trying
+ to avoid race conditions
+
+ 06 Dec 2004; Roy Marples <uberlord@gentoo.org>:
+
+ macchanger defaults to setting the interface down, and then trying
+ with it up - fixes #71929
+ macchanger converts mac_${IFACE} to lowercase - fixes #73549
+ iproute2 now configures the interface up everytime we add an address
+ removed "need interface" from all modules depends as net.lo requires
+ interface anyway
+ removed hardcoded ath0 in wpa_supplicant
+
+ added rc-script statuses "starting", "stopping" and "inactive"
+ dhcpcd, udhcpc and dhclient now support backgrounding - fixes #52975
+
+ 05 Dec 2004; Roy Marples <uberlord@gentoo.org>:
+
+ dhclient now kill it's process if it failed to get a lease on startup
+ all dhclient responses are now handled correctly
+
+ 04 Dec 2004; Roy Marples <uberlord@gentoo.org>:
+
+ fixed dhclient-ifconfig to look for dhclient-udhcpc-wrapper in the correct
+ place and changed hardcoded eth1 to ${interface} in udhcpc-ifconfig.
+ Fixes #73327 - thanks to Benoit Boissinot
+
+ essidnet gets the essid itself instead of relying on ${ESSID}
+ wpa_supplicant module added
+ config-system now creates files as .tmp instead of .new and loads
+ the wpa_supplicant module if needed
+ ifconfig now addes aliases to devices other than eth0
+ dhcpcd, dhclient, pump and udhcpc now expose the dhcp_${IFACE} variable
+ instead of the old peer_dns_${IFACE}, peer_ntp_${IFACE}, peer_nis_${IFACE}
+ ones
+
+ removed modules use dependancy in net.lo and added installed
+ - this allows use to provide "virtual" modules which are only "installed"
+ when other depended modules are installed
+
+* rc-scripts 1.6.7 (03 Dec 2004)
+
+ 03 Dec 2004; Mike Frysinger <vapier@gentoo.org>:
+
+ Simply filesystem unmounting in halt.sh. Based upon work by Georg Sauthoff
+ #68697. Also clean up the filesystem remounting readonly. As a last
+ resort to filesystems which won't remount readonly, we try to unmount them
+ with the force/readonly options. Idea from #70349.
+
+ 03 Dec 2004; Roy Marples <uberlord@gentoo.org>:
+
+ Fixed config-system for only changing hostname when needed
+ udhcpc and dhclient now restore saved configs when stopping and work
+ with non-infinite leases
+ Moved generic dhcp options into a space seperated string
+ udhcpc now caches it's IP address and requests it the next time it starts
+ if the address is not released
+ udhcpc and dhclient no longer flush interfaces if we don't need too
+ ipppd module now looks for ipppd in /usr/sbin - fixes #73067
+
+ 02 Dec 2004; Mike Frysinger <vapier@gentoo.org>:
+
+ Merge time checking function (is_older_than) to help simplify config
+ file update checking. Used for now in env-update.sh #71285. Function
+ written by Paul Pacheco #55329.
+
+ 02 Dec 2004; Roy Marples <uberlord@gentoo.org>:
+
+ Added option dhcp_release to specify if we release the DHCP lease or not
+ defaults to no
+ Changed variables peer_* to dhcp_*
+ dhclient and udhcpc now specify a pidfile
+ Fixed iwconfig report if iwgetid does not support --channel
+
+ 01 Dec 2004; Mike Frysinger <vapier@gentoo.org>:
+
+ Refix and clean up the netmount script to kill processes #64034.
+
+ 01 Dec 2004; Roy Marples <uberlord@gentoo.org>:
+
+ Documentation fixes regarding iwconfig and linux-wlan-ng
+ Fixed bonding deps per bug #71419
+
+ 30 Nov 2004; Mike Frysinger <vapier@gentoo.org>:
+
+ Fix the UML/coLinux check in init.d/clock #72937.
+
+ Allow the user to override the default mount options via /etc/fstab
+ for all the mounts. Added a 'is_in_fstab' function to see if the
+ user has defined the mount, and if not, fall back to the hardcoded
+ stuff from before. This also lets us get rid of $RC_DEVICE_FS #70044.
+
+ 26 Nov 2004; Roy Marples <uberlord@gentoo.org>:
+
+ Fixed up address detection in apipa
+ net.lo now checks for duplicate static IPv4 addresses before assigning
+ iwconfig now supports preassociate and postassociate user hooks
+ net.example - changed $1 to ${IFACE} in examples
+ clarified lack of linux-wlan-ng support
+
+ 24 Nov 2004; Mike Frysinger <vapier@gentoo.org>:
+
+ Allow users to specify charset option to dumpkeys when using unicode
+ in conf.d/keymaps #72225. Also move all the init.d/keymap specific
+ options out of rc.conf and into conf.d/keymaps and add some config
+ checks to init.d/keymaps like the clock/hostname init.d scripts.
+
+ Make sure /etc/rc.conf overrides conf.d files when starting up
+ critical services. Should help out with transition from rc.conf.
+
+ 24 Nov 2004; Roy Marples <uberlord@gentoo.org>:
+
+ Ensure all net-scripts modules depend on interface_variable function
+ where applicable
+ Fixed adsl stopping - #68934. Thanks to Andreas Kauer
+
+ 23 Nov 2004; Roy Marples <uberlord@gentoo.org>:
+
+ iproute2 does not need to create dummy interfaces for aliases
+ unlike ifconfig so we no longer do this
+ We now bring down all aliases and addresses properly
+ Split off some functions from net.lo into helpers.d/functions
+ so that our DHCP helper scripts can use them too :)
+ Deprecated interface specific setup in favour of a generic config
+ macchanger brings interface up now - fixes #71929
+ DHCP over VLAN now works - fixes #71860
+ Disabled modified function checking as it's far too expensive on CPU
+ and still isn't 100% reliable
+ When specifing a module that isn't emerged, you now get an error
+ telling you what to emerge
+ Removed -p option from the diff call used for function removal
+ Removed rp_filter setting - fixes first part of bug #71971
+ Added sysctl.conf settings relating to rp_filter to sysctl.conf
+ - fixes last part of bug #71971
+ Fixed pump exporing ntp servers
+ implemented MODULES_DIR so we can change directory we load from on the fly
+ fixed variables for vlans in most modules
+
+ 19 Nov 2004; Aron Grffis <agriffis@gentoo.org>:
+
+ Remove crap "ll" and "d" aliases from skel .bashrc
+
+ 19 Nov 2004; Roy Marples <uberlord@gentoo.org>:
+
+ tests for hostname (none) when sending hostname via dhcpcd, udhpc or pump
+ udhcpc now does correct signal handling so we can release leases and
+ terminate cleanly
+ Improved pump process detection
+ Rewrote udhcpc helper scripts around udhcpc and wrapped dhclient to udhcpc
+ scripts. This makes things much saner as udhcpc is much saner - also fixed
+ essidnet and ipv6 local link for them.
+ removed iproute2 udhcpc reliance on the "bc" command
+
+ 17 Nov 2004; Roy Marples <uberlord@gentoo.org>:
+
+ Fixed invalid variable handling in bonding and vlan - bug #71419
+ apipa now brings the interface up before testing if address exists
+ Updated bonding documentation - bug #71419
+ Fixed iproute2 adding addresses for vlans - bug #71419
+ ifconfig handle inet6 routing automatically - bug #33310
+ ifconfig - fixed old gateway + gateway in routes conflict
+ iproute2 cleaned up some functions
+
+ 16 Nov 2004; Roy Marples <uberlord@gentoo.org>:
+
+ We no longer default a fallback to APIPA when no config is given
+ net.example fleshed out a bit more for dhcpcd - fixes #60845
+ Improved forced module handling a touch
+ modules_sort and modules_check_user in net.lo buffer _provides,
+ _before and _after in arrays to avoid shelling out
+
+ 15 Nov 2004; Mike Frysinger <vapier@gentoo.org>:
+
+ Add a check to clock init.d to make sure users dont try to set
+ config their clock in rc.conf anymore.
+
+ Redo hostname/domainname scripts to use files in /etc/conf.d/
+ instead of creating files in /etc/. Allows for controlling things
+ like the behavior of setting the 'domain' in resolv.conf since users
+ may not always understand exactly what's going on.
+
+ Stop referring to conf.d/basic as a global rc config option. That
+ file hasn't been used in a long time and has since been replaced
+ with env.d/00basic. Updated sbin/runscript.sh, etc/profile,
+ sbin/rc-help.sh, and src/awk/cachedepends.awk.
+
+ Run `find | xargs` instead of `find -exec`. Much better performance
+ this way, and busybox friendly #59732.
+
+ 15 Nov 2004; Roy Marples <uberlord@gentoo.org>:
+
+ Split modules_load into smaller more managable functions in net.lo
+ Added modules_force option to net.lo with a big phat warning in
+ net.example about it potentially breaking networking
+ Added searchdomains_ESSID option to essidnet
+ Stopped the domain setting from putting the same entry in search
+ in config-system and essidnet
+ Removed second warning in net.lo when configuration not set
+ Documented APIPA module in net.example
+ Added kernel checking for vlan - fixes #70829
+ Added kernel checking for bonding, bridging and tuntap
+ Added iproute2 support to the APIPA module
+
+ 13 Nov 2004; Mike Frysinger <vapier@gentoo.org>:
+
+ Update the svcdir mounting #69595. Instead of mounting in /mnt
+ and then bind mounting to $svcdir, we mount the ramdisk on $svcidr.
+
+ 12 Nov 2004; Roy Marples <uberlord@gentoo.org>:
+
+ Added arping duplicate address detection to net.lo
+ Created Automatic Private IP Addressing (APIPA) module
+
+ Added dependancy checking to ipppd
+ Bonding is now started pre instead of post
+ Fixed iface variable in dhcp modules for vlans
+ Changed get_device to interface_device
+ Changed get_type to interface_type
+ Added vlan configuration options and documented them in net.example
+ Fixed bridge configuration handling
+ Removed _get_vlans from iproute2 and ifconfig as vlan now does it itself
+
+ 11 Nov 2004; Roy Marples <uberlord@gentoo.org>:
+
+ Fixed category of rp-pppoe to net-dialup error when requesting ADSL
+ Improved inet6 address deletion and detection in iproute2
+ Improved gateway logic in ifconfig
+ Changed all wireless reporting functions to use iwgetid instead of
+ parsing iwconfig output except for essid
+
+* rc-scripts 1.6.6 (08 Nov 2004)
+
+ 08 Nov 2004; Roy Marples <uberlord@gentoo.org>:
+
+ Added options to configure bridge
+ Added bridge configuration example to net.example
+ Added missing required function interface_exists to iptunnel check_depends
+
+ 07 Nov 2004; Aron Griffis <agriffis@gentoo.org>:
+
+ Fix shell scripting errors that would result in
+ /sbin/functions.sh: line 166: [: too many arguments.
+
+ 05 Nov 2004; Roy Marples <uberlord@gentoo.org>:
+
+ net-scripts/net.modules.d/bridge
+ - fixed destroying a bridge if no ports were added
+ - starts interfaces if they don't exist - fixed bug #65153
+
+ net-scrips/net.modules.d/bonding
+ - starts interfaces if they don't exist
+
+ net-scripts/init.d/net.lo
+ - added net_start() function to start depandant ifaces
+ so that bridge br0 can active tun0 which net.tun0 has to create
+ - added use dependany on wlan incase we're using linux-wlan-ng drivers
+ fixes bug #64978
+ - moved start() to run_start() and stop() to run_stop()
+ created run() and new start()/stop() functions
+ this is so that we have one single entry point to localise variables
+ and to remove any added functions loaded by our modules
+ - removed redundant interface_exists() as it's provided by
+ ifconfig and/or iproute2
+
+ net-scripts/net.modules.d/ifconfig and iproute2
+ - added ifconfig_tunnel and iproute2_tunnel functions
+
+ addred gre/ipip tunnel support via the the tunnel module
+ - fixes bug #50765
+
+ 04 Nov 2004; Roy Marples <uberlord@gentoo.org>:
+
+ net-scripts/net.modules.d/pump
+ - fixed setting ntp servers
+
+ net-scripts/net.modules.d/dhcpcd
+ - fixed stopping function
+
+ net-scripts/net.modules.d/bonding
+ - fixed module to actually work with the interface
+
+ net-scripts/init.d/net.lo
+ - we remove all added functions when restarting an interface
+ this relies on the diff command being available
+
+ added isdn support via the new ipppd module - fixes bug #69035
+
+ net-scripts/conf.d/net.example
+ - added sample isdn setup
+
+ net-scripts/conf.d/wireless.example
+ - added better descriptions to the _sleep variables
+
+ Fixed boolean logic error when testing is_net_up in /sbin/runscript.sh
+ - fixed bug #70022
+
+ net.lo - added get_type function to return the type of the interface
+ - eth, ippp, etc
+
+ ipppd, tuntap
+ - start() moved to pre_start() and we now test by type
+ this means you no longer need ifconfig_ippp0=( "isdn" "dhcp" )
+ as ippp0 is always an isdn device
+
+ bridge - fixed stop function and moved start() to pre_start()
+ and automatically start if the variable bridge_${iface} exists
+
+ net.example - fixed up documentation for changed behaviour above
+
+ 03 Nov 2004; Mike Frysinger <vapier@gentoo.org>:
+
+ When launching critical services in /sbin/rc, make sure we source
+ the conf.d file (if it exists). Resolves #69956.
+
+ 03 Nov 2004; Roy Marples <uberlord@gentoo.org>:
+
+ net-scripts/init.d/net.lo
+ - fixed !module when it's not installed
+ - we can now specify null inet addresses in the config
+ this allows a pure inet6 setup
+ - shutdown lo the same way we bring it up
+
+ net-scripts/net.modules.d/ifconfig
+ - changed IPv6 to inet6 in output of adding inet6 addresses
+ - just output inet6 address removed, not eth0 del foo
+
+ net-scripts/net.modules.d/iproute2
+ - fix deletion of non-link addresses - fixes bug #65417 (again)
+ - handle inet6 addresses like ifconfig - fixes more bug #65417
+
+ net-scripts/conf.d/net.example
+ - noted that inet6 addresses do not create aliases
+ - added examples of assigning inet6 addresses
+
+ net-scripts/net.modules.d/iwconfig
+ - improve error message when card does not support scanning
+
+ net-scripts/conf.d/wireless.example
+ - fixed comment regarding preferred_aps not working with cards that don't
+ support scanning
+
+ 02 Nov 2004; Roy Marples <uberlord@gentoo.org>:
+
+ net-scripts/conf.d/net.example
+ - added bridging and tuntap examples
+
+ net-scripts/init.d/net.lo
+ - modprobe ${IFACE} when ${IFACE} does not exist
+
+ net-scripts/net.modules.d/ifconfig
+ - fixed interface existance check
+
+ net-scripts/net.modules.d
+ ifconfig & iproute2
+ - added boolean to interface_exists to report if it exists or not
+ - added checks to see if the interface exists or not when starting
+
+ dhcpcd
+ - removed debug line
+
+ bonding, dhclient, dhcpcd, essidnet, macchanger, pump, udhcpc
+ - added checks to see if the interface exists or not when starting
+
+ tuntap
+ - added checks to see if the interface exists or not when stopping
+
+ 01 Nov 2004; Mike Frysinger <vapier@gentoo.org>:
+
+ Dump the error message that hwclock returns since it tends to be
+ quite useful. Modified init.d/clock.
+
+ Fix error in functions.sh [ -z "$@" ] -> [[ -z "$@" ]] #69789.
+
+ Don't create /dev/sndstat link anymore in populate_udev per #69635.
+
+ 01 Nov 2004; Roy Marples <uberlord@gentoo.org>:
+
+ net-scripts/init.d/net.lo:
+ - modules specified by interface config now error if they are not loaded
+ - moved interface check to after preup incase user preup loads drivers
+ - modules can be explicitly not used by prefixing them with a !
+ however, they are still available to other modules
+ fixes bugs #68908, #69027
+ - remove check to see if interface exists
+ - modules may setup new interfaces and still require config
+ so we have a new label counter in iface_start
+ - removed the check to see if a class wrapping already exists
+ this fixes the bug where ifconfig and iproute2 are installed, but
+ ifconfig is asked for and the interface is restarted.
+ - added check to see if the configured module is loaded
+ and installed or not in iface_start
+ - add dependancy on isdn4linux - fixes bug #69035
+ - interface_exists moved to iproute and ifconfig
+
+ net-scripts/net.modules.d
+ - Split wireless module into iwconfig and essidnet modules
+ - Added tuntap and bridge modules, fixes bug #55394, #30688
+
+ net-scripts/init.d/iwconfig:
+ - wep mode is now reported
+ - removed post_stop function so we keep existing config
+ - added pre_stop to set the ESSID variable
+ - changed to veinfo/vewarn where appropriate
+ - check if interface exists otherwise abort gracefully
+ - no longer deletes addresses as we now avoid
+ ipv6 local addresses in detecting if interface has an addresses or not
+
+ net-scripts/init.d/ifconfig:
+ - added flag enable/disable function
+ - scope:link inet6 addresses are ignored when testing is_up and
+ del_addresses - fixes bug #65417
+
+ net-scripts/init.d/iproute2:
+ - added flag enable/disable function
+ - scope:link inet6 addresses are ignored when testing is_up and
+ del_addresses - fixes bug #65417
+
+ net-scripts/init.d/macchanger:
+ - fixed detecting whether the change worked or not, fixes bug #68893
+
+ net-scripts/init.d/vlan:
+ - fixed old config problem
+
+ 31 Oct 2004; Martin Schlemmer <azarah@gentoo.org>:
+
+ Do not delete depscan and envupdate caches on reboot, as this should
+ improve bootup times - works nicely with the '-u' parameters of both.
+ Also move the '-u' parameter test of depscan.sh after the directory
+ exist test, else ${svcdir}/started/, etc do not exist. Modified both
+ /sbin/rc and /sbin/depscan.sh for this.
+
+ Move things around in /sbin/functions.sh to have all functions above.
+
+ Add the 'lo' option to RC_NET_STRICT_CHECKING to resolve bug #29225.
+
+ 28 Oct 2004; Martin Schlemmer <azarah@gentoo.org>:
+
+ Only add files not managed by udev to device tarball, bug #57110.
+
+ 28 Oct 2004; Mike Frysinger <vapier@gentoo.org>:
+
+ Revert pam_console_apply udev check in bootmisc/halt.sh since
+ the bug is with pam_console_apply and not udev/pam.
+
+ Use ${EUID} instead of $(id -u) to help out BSD in runscript.sh.
+
+ Allow users to select ramfs instead of default tmpfs for mounting
+ on /dev with udev #69091.
+
+ Add issue.devfix which would be auto copied to /etc/issue if
+ /sbin/rc detects the user is missing /dev/null or /dev/console.
+ Includes a simple explanation/fix for what's wrong.
+
+ Make sure the clock init script runs after checkroot/modules/localmount
+ so that timestamps are synchronized asap #68133 / #70008.
+
+ Accept '-nc' as a short option to '--nocolor' #64736.
+
+ 26 Oct 2004; Mike Frysinger <vapier@gentoo.org>:
+
+ Don't use -A with fsck to respect the fs_passno since it'll try
+ to fsck all filesystems, not just the ones specified. Instead,
+ awk /etc/fstab to review the passno field in checkroot #68822.
+
+ Add support for 'gentoo=forcefsck' boot option in checkroot.
+
+ Make sure we run devfsd in /sbin/rc even when /dev has been
+ automounted by the kernel #68795.
+
+ Don't generate the device tarball in halt.sh with livecds #68469.
+
+ 25 Oct 2004; Aron Griffis <agriffis@gentoo.org>:
+
+ net-scripts/net.modules.d/ifconfig:
+ - Simplify ifconfig_is_up()
+ - Fix ifconfig_get_aliases_rev() to actually work... you can't
+ specify an interface name to ifconfig if you want to see the
+ aliases.
+ - Workaround a couple ifconfig bugs dealing with aliases
+ - Correct a return status in ifconfig_interface_del_addresses()
+ - ifconfig_iface_stop() is bool, not void; fix the comments
+
+ net-scripts/net.modules.d/iproute2:
+ - iproute2_iface_stop() is bool, not void. Fix the code so it
+ returns meaningful values
+
+ net-scripts/init.d/net.lo:
+ - Fix preferred (ifconfig/dhcpcd) module loading so it doesn't
+ barf when a preferred module is either (1) missing from
+ net.modules.d or (2) not available due to missing dependencies
+ - When loading all modules in order to stop an interface, only use
+ the first available to satisfy each class wrapper
+
+ 24 Oct 2004; Aron Griffis <agriffis@gentoo.org>:
+
+ Include livecd patch that was applied to baselayout-1.9.4-r6
+ to use agetty instead of mingetty
+
+ 24 Oct 2004; Mike Frysinger <vapier@gentoo.org>:
+
+ Mount tmpfs instead of ramfs on /dev when using udev systems.
+ The problem with ramfs is that it has no size limitations so
+ one could easily take down their machine by accident #68653.
+
+* rc-scripts 1.6.3 (23 Oct 2004)
+
+ 22 Oct 2004; Aron Griffis <agriffis@gentoo.org>:
+
+ Add support for user_eth0 in the adsl module and in net.example.
+ This means that most users won't need to edit pppoe.conf at all
+
+ 21 Oct 2004; Aron Griffis <agriffis@gentoo.org>:
+
+ Remove old etc/conf.d/net and try to clarify instructions in
+ net-scripts/conf.d/net.example. Add example for ADSL
+
+ 21 Oct 2004; Mike Frysinger <vapier@gentoo.org>:
+
+ Merge all of the UML checks into one function, is_uml_sys(),
+ which is now in functions.sh.
+
+ 18 Oct 2004; Aron Griffis <agriffis@gentoo.org>:
+
+ Add v-e-commands (veinfo, vbegin, etc) to sbin/functions.sh that
+ depend on RC_VERBOSE which defaults to no. Add --verbose to args
+ understood by runscript.sh.
+
+ In net.lo, use veinfo and friends when loading modules since this
+ information is confusing to users.
+
+ In net.lo, always load global "modules" setting in following
+ "modules_iface" since this is a little easier for users to
+ understand.
+
+ In net.lo, use eindent for output of pre/post scripts
+
+ 18 Oct 2004; Mike Frysinger <vapier@gentoo.org>:
+
+ Add shfs to our list of net filesystems #61452. Also add afs/nfs4.
+
+ Add a '-u' parameter to depscan.sh to allow for updates only when
+ the config files have changed. With /sbin/rc using this, we speed
+ up bootup by only regenerating the cache when need be #67976. Also
+ add a '-u' parameter to env-update.sh for same reasons.
+
+ Don't run depscan.sh in rc-update anymore since the cache files don't
+ depend on runlevels (which is all that rc-update modifies).
+
+ Add unicode support to keymaps/consolefont #32111 and UML support #29707.
+
+ Add checks to many filesystem operations in the eventuality that the
+ filesystems are mounted read only.
+
+ 16 Oct 2004; Mike Frysinger <vapier@gentoo.org>:
+
+ Update the default fstab /dev/shm mount to include the nodev, nosuid,
+ and noexec mount flags. No reason for the filesystem to have those.
+
+ Cleaned up the clock init script. Moved the clock options out of
+ rc.conf and into its own conf.d/clock file. Added support for the
+ weird Alpha consoles SRM/ARC since they need special config options.
+ Also made the syncing of system clock to hardware clock at shutdown
+ optional (with the default being off) #15834. Don't try to set the
+ clock if running inside a coLinux environment #52870.
+
+ Update default PATH ordering to try to follow default behavior in
+ other distro's and because it's logical that /usr/local should
+ override /usr which should override /. Fixes #12531.
+
+ Move devfs stuff out of baselayout and into the devfsd package.
+
+ Don't run /sbin/pam_console_apply -r if using udev on /dev #50315.
+
+ 14 Oct 2004; Aron Griffis <agriffis@gentoo.org>:
+
+ Fix rc-status to work with new COLS code.
+
+ 14 Oct 2004; Mike Frysinger <vapier@gentoo.org>:
+
+ Allow users to mount ramfs/tmpfs/ramdisk as their svcdir and
+ stop assuming ramfs==ramdisk #64079.
+
+ 13 Oct 2004; Mike Frysinger <vapier@gentoo.org>:
+
+ Rework the code for managing /dev to make it more flexible for
+ users. Some don't want to use devfs/udev but rather just create
+ their own nodes. Handles some issues with #44906 / #67276.
+
+ Move the utmp clearing code out of bootmisc and into /sbin/rc.
+ The utmp log must be cleared while in the initial boot level
+ (meaning inside /sbin/rc) because as soon as rc exists, init
+ writes a 'boot' record (`who -b`) which would normally be lost
+ when the bootmisc init.d script is run #61727.
+
+ 13 Oct 2004; Aron Griffis <agriffis@gentoo.org>:
+
+ Cosmetic fixes for starting loopback interface
+
+ SpanKY doesn't like the dots... disable them by default, but you
+ can set RC_DOT_PATTERN=' .' in /etc/conf.d/rc to get them back
+
+* rc-scripts 1.6.2 (13 Oct 2004)
+
+ 13 Oct 2004; Aron Griffis <agriffis@gentoo.org>:
+
+ Install net.modules.d to /lib/rcscripts instead of /etc so we
+ don't have to deal with CONFIG_PROTECT
+
+ Fix diff code in modules_load so it can identify which functions
+ have been modified
+
+ Fix fallback mechanism in iface_start so that it works correctly
+ and doesn't report a bogus error message when trying the fallback
+
+ Get rid of need_begin trickery in iface_stop
+
+ Simplify eend processing in dhcp modules
+
+ Implement eindent, eoutdent, esetdent in functions.sh and adjust
+ net-scripts to use them.
+
+ Re-write einfo, ewarn, eerror, ebegin, eend, ewend to use
+ RC_INDENTATION and to work better on serial terminals
+
+ Remove conf.d/net.ppp0 since that is provided by net-dialup/ppp
+
+ 12 Oct 2004; Aron Griffis <agriffis@gentoo.org>:
+
+ Fix ipaddr_fallback in net-scripts/conf.d/net.example
+
+ 09 Oct 2004; Aron Griffis <agriffis@gentoo.org>:
+
+ Remove init.d/net.eth0 net.lo and net.ppp0. The first two are
+ provided now by net-scripts and net.ppp0 is shipped in
+ net-dialup/ppp
+
+ Create NET_FS_LIST and is_net_fs in functions.sh and use them in
+ checkroot, localmount, netmount, net.example, and net.lo
+
+ 09 Oct 2004; Mike Frysinger <vapier@gentoo.org>:
+
+ If the hostname has already been set via the kernel/dhcp, don't
+ force it to 'localhost'. Used in netboot/terminal setups #38172.
+
+ Add domainname to default boot runlevel list #47041.
+
+ 08 Oct 2004; Mike Frysinger <vapier@gentoo.org>:
+
+ Make sure that when we try to mount /sys, we do so with -n (tigger).
+
+ Add some examples for nfs to sysctl.conf #66575.
+
+ 06 Oct 2004; Aron Griffis <agriffis@gentoo.org>:
+
+ Update to net-scripts 1.0.2 from Roy
+ ------------------------------------
+ - wireless module: replaced preferred_only var with
+ associate_order this makes more sense now as we have changed the
+ possible values
+ - wireless module: added patch from Daniel Zappala we should call
+ wireless_get_essid everywhere now
+ - wireless module: don't declare ESSID local in
+ wireless_configure(). This allows ESSID to be tested in the
+ user defined postup() function
+ - wireless module: test type != "NOT READY!" instead of testing =
+ IEEE. this resolves problems with intel and ra-tech drivers
+ - net.lo start() now errors when the interface does not exist
+ - dhcpcd, dhclient, udhcpc and pump now expose peer_* vars this
+ enables wireless to map them from peer_dns_ESSID
+ - config-system helper now loads wireless module to remap
+ variables from ESSID this allows udhcpc and dhclient to use
+ remapped wireless vars
+ - fixed dhcpcd and pump modules using peer_* vars
+ - wireless aborts after 5 seconds if it cannot report a valid
+ ESSID this fixes a potential infinite loop problem
+ - wireless_setup_iface() renamed to wireless_map_essid_vars() this
+ avoids confusion about what the function actually does
+
+ 06 Oct 2004; Mike Frysinger <vapier@gentoo.org>:
+
+ Change the default net.ipv4.conf.default.rp_filter setting to 1
+ in sysctl.conf since it shouldn't be harmful in anyway. Redhat
+ does the same.
+
+ 05 Oct 2004; Aron Griffis <agriffis@gentoo.org>:
+
+ Get rid of getcols() in sbin/functions.sh. Use COLUMNS when
+ possible and otherwise clean up the COLS code. Fix the "emerge
+ depend" detection code to use RC_ENDCOL="no"
+
+ 05 Oct 2004; Mike Frysinger <vapier@gentoo.org>:
+
+ Changed behavior of the domainname init.d script. It will now
+ override any settings obtained via dhcp/whatever. See #48277.
+
+ Updated bootmisc to dump the output of `dmesg` to /var/log/dmesg.
+ This way users have an 'after-boot' log of their dmesg saved
+ somewhere useful #55421.
+
+ Added the 'eend' back to depscan.sh since the script starts with a
+ call to 'ebegin' #59694.
+
+ Add selinux update from Chris PeBenito for src/runscript.c #64019.
+
+ Add more quoting to rc-help.sh to fix some non-critical errors.
+ Make rc-help.sh respect the value of RC_NOCOLOR. Allow RC_NOCOLOR
+ in functions.sh to be set via the environment.
+
+ Flesh out the default sysctl.conf with comments and more examples
+ since our previous one was pretty sparse #59993.
+
+ Change calls to `uniq` to `sort -u` in checkroot/halt.sh. This way
+ we only require sort in / and not both #36453.
+
+ 04 Oct 2004; Mike Frysinger <vapier@gentoo.org>:
+
+ More (I mean a LOT more) services. This takes care of #44458,
+ #52881 #55939 #58997 #66166 #66297. Gleaned many from the IANA
+ list/Fedora/FreeBSD/Debian.
+
+ Change the test for /proc/cmdline from -e to -r. On grsecurity
+ based systems for example, the file may exist, but not be readable
+ by non-root users (patch by Ned Ludd).
+
+ 03 Oct 2004; Mike Frysinger <vapier@gentoo.org>:
+
+ Add support for NFSv4 from #25106 to the netmount script. Don't
+ try to fsck / if the root is a remote filesystem (like NFS) #36624.
+
+ Update the fs_passno values in the default fstab to match the
+ settings suggested by the manpage #37314. Make checkroot respect
+ a fs_passno setting of 0 when dealing with / #39212. Change
+ default / filesystem type to ext3 instead of xfs #42670.
+
+ Re-order the arguments to mount to match POSIX requirements #66225.
+
+ Don't pipe swapon in localmount to /dev/null and ignore return
+ codes anymore. A swapon that works shows no output #39834.
+
+ 02 Oct 2004; Mike Frysinger <vapier@gentoo.org>:
+
+ Break up the COL/COLOR code properly this time. Not all serial
+ consoles can handle adjusting to the end of the line, so let's not
+ bother running stty at all anymore. This should fix up #32453.
+
+ 30 Sep 2004; Mike Frysinger <vapier@gentoo.org>:
+
+ Disable cryptfs by default in the conf.d file. Also cleanup
+ the output generated in localmount/checkfs/halt.sh for dm-crypt.
+ Add an extra check so that cryptfs is only run when the conf.d
+ file exists as well as /bin/cryptsetup.
+
+ 29 Sep 2004; Mike Frysinger <vapier@gentoo.org>:
+
+ Let glibc install nscd since different versions of glibc will
+ need to be handled differently. See #43076 by Rui Malheiro.
+
+ 29 Sep 2004; Aron Griffis <agriffis@gentoo.org>:
+
+ Prefer ~/.dir_colors over /etc/DIR_COLORS when it exists #64489
+
+ 27 Sep 2004; Aron Griffis <agriffis@gentoo.org>:
+
+ Clear the screen in .bash_logout #32330
+
+* rc-scripts 1.6.1 (27 Sep 2004)
+
+ 27 Sep 2004; Aron Griffis <agriffis@gentoo.org>:
+
+ Update dm-crypt to work with multi-line configuration files.
+ Also don't set status in a subshell; it was being lost before.
+
+ 23 Sep 2004; Mike Frysinger <vapier@gentoo.org>:
+
+ Rework the logic behind the $COLS code. It should not depend
+ on whether color is enabled. Also add a check for negative
+ values (like when using a serial console).
+
+* rc-scripts 1.6.0 (15 Sep 2004)
+
+ 15 Sep 2004; Aron Griffis <agriffis@gentoo.org>:
+
+ Fix bug 64034: simplify netmount script's stop function so that
+ mountpoints containing spaces work correctly
+
+ Update tarball.sh to use net-scripts
+
+ 14 Sep 2004; Aron Griffis <agriffis@gentoo.org>:
+
+ Commit dm-crypt enablement patch from Tigger (Rob Holland) in
+ bug 43146
+
+* rc-scripts 1.5.3 (18 Aug 2004)
+
+ 18 Aug 2004; Aron Griffis <agriffis@gentoo.org>:
+
+ Fix bug 60719 (request for better error messages from runscript)
+ by allowing errors to show on the screen when they're encountered
+ in wrap_rcscript
+
+ Apply Spock's bootsplash patch from bug 45784. This moves most of
+ the splash functionality out of baselayout.
+
+ 13 Aug 2004; Aron Griffis <agriffis@gentoo.org>:
+
+ Don't export PS1. Continuation of bug 26951, comments 60-62.
+
+* rc-scripts 1.5.2 (02 Aug 2004)
+
+ 02 Aug 2004; Aron Griffis <agriffis@gentoo.org>:
+
+ Related to bug 38955, don't set INPUTRC. Instead patch bash so
+ that it looks for /etc/inputrc automatically if ~/.inputrc is
+ missing. This is better than using INPUTRC since that will
+ override even after the user creates ~/.inputrc.
+
+ Fix bug 54275: Don't set INFODIR. The correct variable used by
+ texinfo is INFOPATH, which is already set in 00basic. Setting
+ INFODIR is useless, and breaks a NetBSD cross compile from Gentoo
+
+ 01 Aug 2004; Aron Griffis <agriffis@gentoo.org>:
+
+ Fix bug 58805: net.eth0 should use bridge so that bridge
+ interfaces are configured prior to net.br0 running
+
+ Fix bug 56856: Get rid of net.rej and integrate missing stuff to
+ conf.d/net
+
+ Apply half of spock's patch in bug 45784: Check for
+ conf.d/bootsplash instead of conf.d/bootsplash.conf
+
+ Fix bug 51351: Quote parsed output of /proc/filesystems to handle
+ octal sequences in mountpoint such as encoded spaces (\040)
+
+ Fix bug 46680: Add cifs support to localmount and netmount.
+ Thanks to Ronald Moesbergen for the patches
+
+ 21 Jul 2004; Aron Griffis <agriffis@gentoo.org>:
+
+ Fix bug 26952: Use /etc/bash/bashrc to setup PS1, testing $- to
+ determine if shell is interactive. The new system-wide bashrc is
+ installed by bash-2.05b-r10
+
+ 19 Jul 2004; Aron Griffis <agriffis@gentoo.org>:
+
+ Fix bug 38743: strip leading and trailing spaces from variable
+ values in genenviron.awk. Thanks to Marius Mauch for the patch.
+
+ 09 Jul 2004; Aron Griffis <agriffis@gentoo.org>:
+
+ Fix bug 55576: swap words "start" and "stop" in runscript.sh error
+ message
+
+* rc-scripts 1.5.1 (28 Jun 2004)
+
+ 28 Jun 2004; Aron Griffis <agriffis@gentoo.org>:
+
+ Fix dhcp in iface_start_ifconfig: It was re-using the variable
+ ${i} which would result in the following error:
+ /sbin/runscript.sh: line 441: ((: 16.141.88.153: syntax error
+ in expression (error token is ".141.88.153")
+
+ Use vlan_IFACE instead of iface_IFACE_vlans in net.eth0 for more
+ consistent vlan configuration. Thanks to robbat2 in bug 55394
+ (not fully resolved)
+
+ Add example for checking if root filesystem is NFS-mounted via
+ predown function in conf.d/net for bug 53104. This might be
+ better integrated at some point into net.eth0
+
+* rc-scripts 1.5.0 (26 Jun 2004)
+
+ 26 Jun 2004; Aron Griffis <agriffis@gentoo.org>:
+
+ Fix bug 47659: support iproute2-style configuration. Thanks to
+ Dean Bailey for some fantastic patches, including documentation
+ for conf.d/net. This is a pretty huge re-write of net.eth0
+
+ Fix bug 34607: provide examples for in conf.d/net for preup,
+ postup, predown, postdown functions. Also pay attention to return
+ value from predown function (previously ignored)
+
+ 15 Jun 2004; Aron Griffis <agriffis@gentoo.org>:
+
+ Fix bug 25975: support adsl in net.eth0. Thanks to Patrick McLean
+ for the initial pass at the code.
+
+ Fix bug 34140: add --servicelist option to rc-status. Thanks to
+ Eldad Zack for the patch.
+
+ Fix bug 37418: fix order of LVM and RAID in checkfs. Thanks to
+ Raimondo Giammanco for the patch.
+
+* rc-scripts 1.4.16 (06 Jun 2004)
+
+ 06 Jun 2004; Aron Griffis <agriffis@gentoo.org>:
+
+ Only call generate-modprobe.conf with --assume-kernel if
+ modules-update was called with --assume-kernel. This means that
+ only catalyst has the dependency on module-init-tools, not
+ everybody with the newer baselayout
+
+* rc-scripts 1.4.15 (21 May 2004)
+
+ 21 May 2004; Aron Grifis <agriffis@gentoo.org>:
+
+ Fix bug 51570: typo on line 161 of /sbin/livecd-functions.sh
+
+ Fix bug 51626: wrong variable declaration at top of
+ get_bootparam() in /sbin/functions.sh
+
+* rc-scripts 1.4.14 (17 May 2004)
+
+ 17 May 2004; Aron Griffis <agriffis@gentoo.org>:
+
+ Bump version to 1.4.14 to push out gmsoft's fix for hppa console
+ on ttyB0
+
+* rc-scripts 1.4.13 (15 May 2004)
+
+ 15 May 2004; Aron Griffis <agriffis@gentoo.org>:
+
+ Bump version to 1.4.13 to push out Gustavo's livecd serial console
+ fixes for sparc and hppa.
+
+* rc-scripts 1.4.12 (07 May 2004)
+
+ 10 May 2004; Aron Griffis <agriffis@gentoo.org>:
+
+ Bump version to 1.4.12 to release these critical bug fixes
+
+ Fix bug 50434: The new version of start-stop-daemon changes
+ directory to / by default unless --chdir is specified. Revert
+ this behavior to maintain working directory. This fixes openvpn
+ startup (probably among other things). Thanks to Sven Wegener for
+ the patch.
+
+ Fix bug 50448: Four days ago I changed bash loops to use the wrong
+ conditional syntax in net.eth0. Thanks to Sven Wegener for
+ pointing out the problem and providing a patch.
+
+* rc-scripts 1.4.11 (07 May 2004)
+
+ 07 May 2004; Aron Griffis <agriffis@gentoo.org>:
+
+ Fix bug 20597: Skip RCS files when updating modules
+
+ Fix bug 49926: Add a --assume-kernel flag to modules-update. This
+ requires a companion patch in module-init-tools-3.0-r2 to handle
+ the same flag in generate-modprobe.conf; this dependency won't be
+ handled in the baselayout ebuild since it only affects livecd
+ building.
+
+ 06 May 2004; Aron Griffis <agriffis@gentoo.org>:
+
+ In net.eth0, fix many instances of loops like "for ((i = 0; i <
+ 100; i = i + 1))". The problem here is that the middle comparison
+ is being interpreted as a bash conditional, which means that it's
+ doing string comparison by default. It needs to be "i -lt 100"
+
+ Fix bug 34827: net.eth0 breaks when localized because the ifconfig
+ output changes. Wrap ifconfig in a function that overrides
+ LC_ALL=C
+
+ Fix bug 48305: Provide a new network configuration variable
+ ifconfig_fallback_eth0 which allows one to specify a fallback
+ configuration in case DHCP fails.
+
+ Fix bug 50246: Give root an invalid password ("*" in /etc/shadow)
+ in the default baselayout. This prevents the first reboot after
+ installation from having a blank password.
+
+ 05 May 2004; Aron Griffis <agriffis@gentoo.org>:
+
+ Fix bug 48595: Make sure $(id -u) is zero (root user) when running
+ init scripts to avoid a lot of error messages.
+
+ Replace many lines of awk with two lines of grep in
+ init.d/localmount
+
+ Fix bug 44316: Use 0644 instead of 0640 for resolv.conf in net.ppp0
+
+ 03 May 2004; Aron Griffis <agriffis@gentoo.org>:
+
+ Update to version 1.10.20 of Debian's start-stop-daemon (contained
+ in dpkg at http://packages.debian.org/testing/base/dpkg). This
+ fixes bug 22686 (start-stop-daemon in baselayout doesn't allow
+ altered nicelevel).
+
+* rc-scripts 1.4.10 (25 Apr 2004)
+
+ 25 Apr 2004; Aron Griffis <agriffis@gentoo.org>:
+
+ Fix typos in sbin/rc: "try try mount" and "mount ... & >/dev/null"
+ Also removed the errstr double-checking since the need for that is
+ alleviated by these typo fixes.
+
+ 23 Apr 2004; Aron Griffis <agriffis@gentoo.org>:
+
+ Fix bug 48629 (/sbin/rc fixups for udev) with patch from GregKH
+
+ Fix bug 40987 (gentoo should be able to boot with an empty /dev)
+ with patch from Spanky. The patch avoids redirection to /dev/null
+ when it doesn't exist; this was breaking /sbin/rc.
+
+* rc-scripts 1.4.9 (15 Apr 2004)
+
+ 15 Apr 2004; Aron Griffis <agriffis@gentoo.org>:
+
+ Fix bug 47111 (severe depcache problems) with tons of help from
+ dswhite42 and the rest of the crew in that bug. Thanks guys!
+
+* rc-scripts 1.4.8 (14 Apr 2004)
+
+ 14 Apr 2004; Aron Griffis <agriffis@gentoo.org>:
+
+ Fix bug 47623 (error removing inet6 addresses) with patch provided
+ by Vlad Yasevich.
+
+* rc-scripts 1.4.7 (12 Apr 2004)
+
+ 12 Apr 2004; Aron Griffis <agriffis@gentoo.org>:
+
+ Fix bug 47218 (net.eth0 broken for vlans) with patch provided by
+ Andy Dustman. Fix bug 47250 (depscan.sh fails to create
+ /var/lib/init.d/* directories) with patch from Terje Bergström
+
+* rc-scripts 1.4.6 (08 Apr 2004)
+
+ 08 Apr 2004; Aron Griffis <agriffis@gentoo.org>:
+
+ Update patch from Gustavoz; -ln /bin/bash should have been -nl /bin/bash
+
+* rc-scripts 1.4.5 (08 Apr 2004)
+
+ 08 Apr 2004; Aron Griffis <agriffis@gentoo.org>:
+
+ Patch init.d/checkroot to list / (root) only once in mtab; see bug 38360.
+ Patch from Gustavoz to livecd-functions.sh to run bash instead of login on
+ serial consoles, necessary due to scrambled root passwords.
+
+* rc-scripts 1.4.4 (07 Apr 2004)
+
+ 07 Apr 2004; Aron Griffis <agriffis@gentoo.org>:
+
+ Patch from Gustavoz for Sparc console: Fetch LIVECD_CONSOLE from dmesg
+ output. Also support 4800 baud correctly.
+
+ 16 Mar 2004; Aron Griffis <agriffis@gentoo.org>:
+
+ The changes in this commit pertain primarily to
+ http://bugs.gentoo.org/show_bug.cgi?id=19695
+ http://bugs.gentoo.org/show_bug.cgi?id=35736
+
+ Specify routes as an array per interface, for example:
+ routes_eth0=(
+ "-net 10.1.0.0 netmask 255.255.0.0 gw 10.0.0.5"
+ "-net 10.2.0.0 netmask 255.255.0.0 gw 10.0.0.6"
+ "-host 10.3.0.1 dev eth0"
+ )
+
+ You can optionally use the gateway variable or just put the default route
+ in the routes variable. The following two are REDUNDANT:
+
+ routes_eth0=( "default gw 10.0.0.5" )
+ gateway="eth0/10.0.0.5"
+
+ Old configuration variables in /etc/conf.d/net are fully supported and
+ used transparently if ifconfig_eth0 is missing. In other words, this new
+ script is fully backward-compatible. However you can get rid of
+ iface_eth0, alias_eth0, broadcast_eth0 and netmask_eth0 if you want by
+ using the new syntax:
+
+ ifconfig_eth0=(
+ "10.0.0.6 broadcast 10.0.255.255 netmask 255.255.0.0"
+ "192.168.1.1 netmask 255.255.255.0"
+ "123.456.789.1"
+ )
+
+ Full backward compatibility so no danger to screwing up users relying on
+ existing /etc/conf.d/net setup
+
+ NET_DEBUG can be set in the environment for copious debugging output
+
+ Deprecate [ ] in favor of [[ ]] which has fewer quoting issues and
+ better functionality (and is even slightly faster)
+
+ Properly localize all variables, including variables returned by
+ setup_vars
+
+ Allow full options for every ifconfig command, both base address and
+ aliases via ifconfig_eth0, replacing the convoluted and less-functional
+ iface_eth0, alias_eth0, broadcast_eth0, netmask_eth0
+
+ Provide full support for static routes via routes_eth0
+
+ Fix potential quoting problems in setup_vars by using better eval syntax
+ instead of eval echo
+
+ Display IP addresses while configuring, both DHCP-retrieved and
+ statically set addresses
+
+ Collapse redundant caching of $? since eend returns $? again
+
+ Report when keeping kernel configuration for an interface along with IP
+ address gleaned
+
+ Don't reset the default gateway if it is already set correctly
+
+ Don't bind default gateway to particular interface when /sbin/route is
+ called so that it can survive if there is more than one interface on the
+ required subnet. (Old behavior can be obtained by setting
+ routes_eth0="default gw 1.2.3.4 dev eth0" if you really want it)
+
+ Don't bomb if default gateway can't be set since that doesn't
+ necessarily mean that the interface configuration is invalid.
+ (Old behavior was completely broken, but commented section
+ demonstrates how to do it right if necessary)
+
+ iface_stop no longer relies on configuration in /etc/conf.d/net AT ALL.
+ This is very good because it means you can put new configuration in
+ /etc/conf.d/net, then restart the interface and the old configuration will
+ be properly shut down.
+
+ iface_stop reports when it is releasing the DHCP lease
+
+* rc-scripts 1.4.3.13p1 (26 Feb 2004)
+
+ 26 Feb 2004; Martin Schlemmer <azarah@gentoo.org>:
+
+ Remove /etc/DIR_COLORS, as coreutils provides it now.
+
+ Add RC_DEVICE_TARBALL to /etc/conf.d/rc to control use of device tarball.
+ Also modified /sbin/rc and /etc/init.d/halt.sh for this.
+
+ Start udevd if present.
+
+ Small fix to sbin/rc-services.sh related to mtime checking and 'net'
+ virtual service - it had no mtime generated, so check_mtime() failed
+ for it ...
+
+ 25 Feb 2004; Martin Schlemmer <azarah@gentoo.org>:
+
+ Update to enable checking of mtimes on rc-scripts, and auto running
+ depscan.sh if needed. Also try to run depscan.sh when RC_GOT_DEPTREE_INFO
+ is not set instead of just erroring.
+
+ 19 Feb 2004; Martin Schlemmer <azarah@gentoo.org>:
+
+ Fix irda type-o in /sbin/MAKEDEV, thanks to Tobias Sager <moixa@gmx.ch>.
+
+ Fix type-o in /etc/initrc, bug #41666 (Tom Vergote <bugzilla@tomvergote.be>).
+
+ 15 Feb 2004; Martin Schlemmer <azarah@gentoo.org>:
+
+ Add RC_TTY_NUMBER to /etc/conf.d/rc to configure how many tty devices
+ are used in scripts such as consolefonts, numlock, etc. This should
+ close bug #39863.
+
+ Fix type-o in /etc/init.d/consolefont, bug #40938, thanks to patch from
+ Cory Tusar <ctusar@adelphia.net>.
+
+ 09 Feb 2004; Martin Schlemmer <azarah@gentoo.org>:
+
+ Add SELinux modifications to /sbin/runscript. This allows runscript to
+ make sure it is running in the right domain. Patch done by
+ Chris PeBenito <pebenito@gentoo.org>.
+
+* rc-scripts 1.4.3.13 (08 Feb 2004)
+
+ 08 Feb 2004; Martin Schlemmer <azarah@gentoo.org>:
+
+ Fix wrong logic in /etc/init.d/halt.sh which did not umount all mounts
+ _but_ /mnt/cdrom and /mnt/livecd.
+
+ Update /etc/init.d/consolefont to use newer kbd. Should also close
+ bug #39864.
+
+ Fix /sbin/depscan.sh, /sbin/functions.sh and /sbin/rc to use mkdir rather
+ than install, as newer versions of install is located in /usr/bin. This
+ closes bug #39648.
+
+ 06 Feb 2004; Martin Schlemmer <azarah@gentoo.org>:
+
+ Tweak livecd support changes and add some more to hopefully sort out
+ last issues, with help from Brad House <brad_mssw@gentoo.org>.
+
+ Add code to generate /dev/fd, /dev/std* and /dev/core to /sbin/rc,
+ bug #37349.
+
+* rc-scripts 1.4.3.12p3 (21 Jan 2004)
+
+ 19 Jan 2004; Martin Schlemmer <azarah@gentoo.org>:
+
+ Add /sbin/livecd-functions.sh from Brad House <brad_mssw@gentoo.org>
+ for livecd support. Add bits to /sbin/rc to support it.
+
+ 06 Jan 2004; Martin Schlemmer <azarah@gentoo.org>:
+
+ Fix type-o in /etc/init.d/checkfs, bug #37113.
+
+ 29 Dec 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Update /sbin/depscan.sh, /sbin/env-update.sh, src/awk/cachedepends.awk,
+ src/awk/gendepends.awk and src/awk/genenviron.awk to use ENVIRON rather
+ then gawk -v. Also add some tests to see if we got the environment
+ variables.
+
+ 28 Dec 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Fix /sbin/rc to mount /dev/pts with gid=5 and mode=0620, bug #36088.
+
+* rc-scripts 1.4.3.12p2 (27 Dec 2003)
+
+ 26 Dec 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Update code to generate /dev from /sys. Add UDEV_NO_SLEEP=1 for
+ hack to not make udev sleep - its not needed as these entries
+ are already present, and not a hotplug event.
+
+ Update /etc/init.d/{consolefont,numlock} to work with udev managed
+ /dev that have devfs layout.
+
+ 14 Dec 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Fix type-o in /sbin/rc, bug #34837.
+
+* rc-scripts 1.4.3.12p1 (26 Nov 2003)
+
+ 26 Nov 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Fix /etc/init.d/halt.sh to reset pam_console permissions, else
+ the next bootup might be done with some non-root nodes which cause
+ some odd issues.
+
+ Add code to generate /dev from sysfs entries - not much it currently
+ support but block/tty devices, but it is a start for when we have
+ full sysfs support in all drivers.
+
+ Revert carrier detection check, as there is currently too many
+ issues with it, bug #33272.
+
+ Make sure we mount already mounted mount (done in /sbin/rc) with
+ correct permissions, etc, bug #33764. Modified /etc/init.d/checkroot
+ for this.
+
+ 16 Nov 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Fix carrier detection - we need to do a 'ifconfig $IFACE up' else
+ some drivers do not set the IFF_RUNNING bit, bug #33272, thanks to
+ Jason Rhinelander <jason-gentoo@gossamer-threads.com> for the fix.
+
+ 15 Nov 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Add a warning to cachedepends.awk if a rc-script's name ends in
+ '.sh', bug #33134. Add better error checking to /sbin/depscan.sh.
+
+ Fix /etc/init.d/halt.sh to not try and remount virtual devices,
+ also do a few cleanups. Closes bug #33271.
+
+* rc-scripts 1.4.3.12 (11 Nov 2003)
+
+ 11 Nov 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Add carrier detection to /etc/init.d/net.eth0 closing bug #25480;
+ patch by Jordan Ritter <jpr5+gentoo@darkridge.com>.
+
+ Add extra checks for critical directories to /sbin/rc.
+
+ 04 Nov 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Update /bin/rc-status giving a working '-u' parameter, bug #32417.
+ Fix by Michael Frysinger <vapier@gentoo.org>.
+
+ 31 Oct 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Add support for --tty switch added to setfont and remove consolechars
+ support; modified /etc/init.d/consolefont for this. Also remove
+ consoletools support from /etc/init.d/keymaps.
+
+ 29 Oct 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ We should still use /sbin/udev as hotplug agent if /sbin/hotplug do
+ not exist. Updated /sbin/rc for this.
+
+ Add a fix to /etc/init.d/keymaps for bug #32111 (we should not have
+ '-u' in the call to loadkeys when using unicode).
+
+ We should not use '-' in variable names for bash, bug #31184, thanks
+ to Andreas Simon <yuipx@gmx.net>. Updated /sbin/MAKEDEV.
+
+ 27 Oct 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Fix return code checking of fsck in /etc/init.d/checkfs, bug #31349.
+
+ 26 Oct 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ The unmount stuff in /etc/init.d/halt.sh was flawed, in the fact that
+ it called 'umount -t no<insert_fs_here>', which resulted in /proc, etc
+ unmounted anyhow. Change it to remount the last filesystems readonly
+ without trying to unmount any. This fixes a few cases where reboot
+ would halt due to unmounted /proc, etc.
+
+ This change set fixes two things:
+ 1) In exporting all functions/variables in functions.sh, rc-services.sh
+ and rc-daemon.sh, we created an overly large environment, and also
+ broke stuff like glftpd. Do not do this, and hope whatever caused
+ the issues previously is fixed in the meantime. This should close
+ bugs #25754 and #31794.
+ 2) gendepend.awk used to generate deptree with functions called
+ depinfo_<scriptname> which set appropriate variables when called.
+ This broke if the scriptname contained characters that is not valid
+ for bash variable names. Changed things to use an array fixing this.
+ This closes bug #24092.
+
+ Change /sbin/rc again to not set the hotplug agent to /sbin/udev, as
+ /sbin/hotplug will call udev as well.
+
+ Fix a logic error in /lib/rcscripts/sh/rc-services.sh that cause the
+ get_dep_info() function to skip the last entry in the RC_DEPEND_TREE
+ array (in my case 'net').
+
+ We did not handle the 'net' dependency properly in valid_iuse() and
+ valid_iafter(). Fix this in /lib/rcscripts/sh/rc-services.sh, closing
+ bugs #30327 and #31950.
+
+ Change an occurance of /etc/modutils in modules-update.8 to
+ /etc/modules.d/ closing bug #31171.
+
+ 19 Oct 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ More bootsplash fixes, bug #21019 (comment #21).
+
+ Remove the killall5 stuff from /etc/init.d/halt.sh, as it messes with
+ bootsplash. Add support to kill processes still using non-critical
+ mounts with fuser though.
+
+ 17 Oct 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Bootsplash fixes from Michael Aichler <micha@aichler.net>, (comment #15
+ and #16 from bug #21019).
+
+ Bootsplash coded did not play nice with boot profiles, so I fixed that
+ as well. Some other style tweaks.
+
+ Fix /sbin/MAKEDEV to use 'user:group' form, and not depriciated '.'.
+ Also changed the permissions on tty's, ibcs and scanner devices
+ to 0660.
+
+* rc-scripts 1.4.3.11p2 (14 Sep 2003)
+
+ 14 Oct 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Revert previous changes, and substitute it for the bootsplash patches
+ from Michael Aichler <micha@aichler.net>, bug #21019. His www pages
+ can be reached at:
+
+ http://www.aichler.net/gentoo/bootsplash/
+
+ I should note that the bootsplash stuff is not 100% tested.
+
+
+* rc-scripts 1.4.3.11p1 (14 Sep 2003)
+
+ 14 Oct 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Initial bootsplash patch as from LiveCD's.
+
+ Add more tty's to /etc/init.d/numlock, bug #28252.
+
+* rc-scripts 1.4.3.11 (14 Sep 2003)
+
+ 14 Oct 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Add initial udev support. Modified /sbin/rc and /etc/init.d/halt.sh.
+ Resolves bug #27527.
+
+ Add squid to /etc/services, bug #30995. Other cleanups from rac.
+
+ Add patch from Kumba <kumba@gentoo.org> to MAKEDEV to not allow
+ running while pwd is root (/).
+
+ Add 'after hotplug' to /etc/init.d/consolefont, bug #30856.
+
+ Add entry for floppy in /etc/fstab, bug #30574.
+
+ Remove changing group of /tmp/.{X,ICE}-unix, as it it not needed,
+ bug #28861.
+
+ Apply a patch from Mike Frysinger <vapier@gentoo.org> for rc-status.
+ It now will work with runlevels named with any characters (other than
+ ones found in default bash IFS). It also adds a few sanity/error
+ checks, bug #26432.
+
+ Change /etc/inputrc to have PageUp/PageDown search through bash
+ history again, bug #26036.
+
+ 14 Sep 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Change update-modules to modules-update in manpage, bug #28101.
+
+* rc-scripts 1.4.3.10p1 (08 Sep 2003)
+
+ 08 Sep 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Change the '-k' switch to dhcpcd to '-z' in /etc/init.d/net.eth0.
+
+ 12 Aug 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Add missing 'local x' to filter_environ() (bug #26429), thanks to
+ Mark Wagner <mark@lanfear.net>. Modified rc-services.sh for this.
+
+ 11 Aug 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Modify /etc/init.d/modules not to print the autoloading stuff if
+ no modules should be loaded (resolving bug #26288), per request from
+ Michael Frysinger <vapier@gentoo.org>.
+
+ Fix get_bootparam() in /sbin/functions.sh to check for existance of
+ the /proc/cmdline proc entry.
+
+ 10 Aug 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Modify /etc/init.d/halt.sh to first kill, and then deactivate swap on
+ request of Luke-Jr <luke-jr@gentoo.org>. It should be ok now, as the
+ whole way of devfs handling changed long ago already.
+
+ Fix /etc/init.d/halt.sh to unmount the mount point and not the device.
+ Also change it to 'mount -d' to detach the loop device. Patch by
+ Kalin KOZHUHAROV <kalin@ThinRope.net>, bug #26256.
+
+ Fix /etc/init.d/consolefont to not error out if CONSOLEFONT in rc.conf
+ is not set, bug #26278 (noted by Michael Frysinger <vapier@gentoo.org>).
+
+* rc-scripts 1.4.3.10 (04 Aug 2003)
+
+ 04 Aug 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Add /bin/rc-status and 'show' support to /sbin/rc-update (long overdue),
+ bug #4222, thanks to Sean E Russell <ser@germane-software.com>,
+ Michael Frysinger <vapier@gentoo.org> (/bin/rc-status) and for the 'show'
+ stuff to /sbin/rc-update, Max Kalika <max@gentoo.org>.
+
+ Fixed modules-update to only do the /etc/modprobe.conf generation if we
+ are actually running a 2.5+ kernel.
+
+ Add pop3 entries to /etc/services, bug #25501.
+
+ Add a switch for devfsd startup to /etc/conf.d/rc, fix /sbin/rc to check
+ RC_DEVFSD_STARTUP. Closes bug #24361, thanks to patches from
+ Kurt V. Hindenburg <khindenburg@cherrynebula.net>.
+
+ Add LVM2 support thanks to Max Kalika <max@gentoo.org> (bug #21908).
+
+ Add IPV6 versions of localhost and co in /etc/hosts, bug #25859.
+
+ Fix type-o in /sbin/rc-update, bug #25854.
+
+ 29 Jul 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Tweak /etc/init.d/check{root,fs} to set retval after each fsck call,
+ and not the whole block. Tweak check checkroot to reboot if need be
+ (This is with sufficient warning and message). Tweak checkfs to not
+ drop to a sulogin if return code 2 or 3 is given - as we did not
+ mount the filesystems yet, we should not need to reboot ... bug #25398.
+
+ Add '-T' option to fsck (/etc/init.d/check{root,fs} - requested by
+ Michael Frysinger <vapier@gentoo.org>.
+
+ 28 Jul 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Rework changes for the Adelie project to support boot config profiles
+ better. Added support for /etc/runlevels/LEVEL/.fake to specify which
+ runlevels should be marked started or stopped without executing the
+ script. Renamed the /etc/runlevels/LEVEL/critical to ".critical" for
+ more uniformity. Modified /sbin/rc, /sbin/functions.sh, /sbin/runscript.sh
+ for this.
+
+ Add better support for services that provide the "logger" virtual. We
+ should really start the logger earlier, and stop it as late as possible.
+ Modified /sbin/rc, /lib/rcscripts/sh/rc-services.sh and gendepends.awk
+ for this.
+
+ Fix .../boot/... paths hardcoded in /lib/rcscripts/sh/rc-services.sh,
+ thanks to Jean-Francois Richard <jean-francois@richard.name>.
+
+ Replace the Suse /etc/inputrc with a non copyrighted one, bug #24918.
+
+ 23 Jul 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ From Jean-Francois Richard <jean-francois@richard.name> and
+ Olivier Crete <tester@gentoo.org> from the Adelie project:
+
+ The last four patches are the "adaptation" of our previous patches to
+ the new "no-tmpfs" init system in Gentoo. Since we were using quite
+ different scripts for the boot runlevel (no "checkroot" for example) and
+ that the new system hardcodes some of the boot services, we had to find
+ a simple yet elegant solution.
+
+ We chose to make init scripts read "/etc/runlevels/LEVEL/critical" to
+ know what are the boot runlevel services. If this file is not present,
+ it uses the Gentoo hardcoded defaults.
+
+ This touches /sbin/rc, /sbin/functions.sh, /sbin/runscript.sh and
+ /etc/init.d/halt.sh.
+
+ I just changed the behaviour of 'softlevel' kernel command line argument
+ to not only add a suffix and some other cleanups.
+
+ Add support for irqbalance.
+
+ 22 Jul 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Fix the /dev/root entry in /etc/mtab, bug #24916.
+
+ Add EVMS2 support, thanks to Mike Javorski <mike_javorski@bigfoot.com>,
+ bug #24064.
+
+* rc-scripts 1.4.3.9 (17 Jul 2003)
+
+ 17 Jul 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Add vlan support to /etc/init.d/net.eth0, bug #15588, thanks to
+ Andy Dustman <andy-gentoo.54e552@dustman.net>.
+
+ Add 'TERM=Eterm' to /etc/DIR_COLORS, bug #23423.
+
+ Add mdadm support to /etc/init.d/checkfs, bug #23437, many thanks
+ to Wes Kurdziolek <wkurdzio@vtluug.org>.
+
+ Rather use 'uname -r' to get kernel version, as else we need sysctl.
+ This closes bug #23923, modified /etc/init.d/modules.
+
+ Fix a type-o in /etc/fstab, bug #23308.
+
+ Add support for the new 'O' agetty option to display the DNS domainname
+ in the issue file thanks to Marius Mauch <genone@genone.de>, bug #22275.
+ Updated /etc/issue and /etc/issue.logo for this.
+
+ 16 Jul 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Add aliases for add/del to /sbin/rc-update closing bug #24317, thanks
+ to Antonio Dolcetta <zagarna@yahoo.com>.
+
+ Fix /etc/init.d/net.eth0 to not set rp_filter if already set via
+ /etc/sysctl.conf, bug #24235 - thanks jochen <jochen.eisinger@gmx.de>.
+
+ Fix /sbin/runscript.sh and /lib/rcscripts/awk/cachedepend.awk to work
+ with symlinks in /etc/init.d/, closing bug #24228.
+
+ Fix /etc/init.d/clock to work with UML, closing bug #24225 thanks to
+ John Mylchreest <johnm@gentoo.org>.
+
+ Fix hardcoded color escape sequence in /sbin/rc, closing bug #24109,
+ thanks to splite <splite-gentoo@sigint.cs.purdue.edu>.
+
+ Fix /sbin/functions.sh to disable color printing if NOCOLOR is set to
+ "true" in /etc/make.conf, closing bug #24107.
+
+ Fix /etc/init.d/keymaps to be more non-x86 friendly, and also allow
+ more keymaps to be specified in /etc/rc.conf, bug #24084.
+
+ 15 Jul 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Add /bin/csh to /etc/shells.
+
+ Add new protocols to /etc/services, thanks Rajiv Aaron Manglani
+ <rajiv@gentoo.org>.
+
+ 23 Jun 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Cleanups for bug #21438 from bug #22637, thanks to
+ Christian Strauf <christian.strauf@gmx.de> and Ian Abbott <ian@abbott.org>.
+
+ 22 Jun 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Really commit fix for bug #21438 to CVS.
+
+ 21 May 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Call /proc mount with explicit options to fix issues where user
+ have 'bind' mounts for /proc in fstab as well, bug #21068.
+
+ Fix /etc/init.d/bootmisc to check for /sbin/env-update.sh, bug #21384,
+ reported by Gunnlaugur Thor Briem <gthb@hi.is>.
+
+ Add 'before bootmisc' to /etc/init.d/domainname, as we need to start
+ it before 'env-update.sh' gets run by /etc/init.d/bootmisc.
+
+* rc-scripts 1.4.3.8p1 (21 May 2003)
+
+ 21 May 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Last fix I did not use the modified 'myservice', but used $1 again,
+ causing the network dependencies to bork. I did not notice this
+ as I have net.eth0 in default runlevel.
+
+* rc-scripts 1.4.3.8 (20 May 2003)
+
+ 20 May 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ A '-' in a bash variable is not valid as well. Fix gendepend.awk and
+ rc-service.sh to handle this, thanks to YAMAKURA Makoto
+ <makoto@dsb.club.ne.jp>.
+
+ Move /etc/issue to /etc/issue.logo, and have /etc/issue only print info
+ about the host it is running on.
+
+ 18 May 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Do not let devfsd handle /dev/log's permission management, as it breaks
+ selinux. Modified /etc/devfsd.conf, changes submited by Chris PeBenito
+ <pebenito@gentoo.org>.
+
+ Fix type-o in /etc/init.d/net.ppp0, and add local ip-up/ip-down support.
+
+ 14 May 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ We should not export the RC_GOT_* variables, as it breaks on some systems,
+ thanks to J?rg Gollnick <gentoo-bugs@wurzelbenutzer.de>, bug #20851.
+
+ From C. Brewer <killian@gentoo.org>:
+ - Add hide-password to the connect cmd-line of /etc/init.d/net.ppp0, which is
+ suppose to be default, but why take chances?
+ - Also, echoing chmod 640 in the resolv.conf two-step at the end to solve the
+ kppp complaint.
+
+ 13 May 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ For the network functions, the dependency code tried to create a funcion
+ with a '.' in the name, causing the network rc-scripts to not have any
+ dependencies. This should fix bug #20849 's order issue, thanks to
+ YAMAKURA Makoto <makoto@dsb.club.ne.jp> for noticing.
+
+ Fix query_{before,after} to also check 'net' if 'service2' is a network
+ service.
+
+ 12 May 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ More cleanups:
+ - Move the broken stuff from symlinks to a DB entry in ${svcdir}/deptree.
+ Updated /sbin/runscript.sh, /sbin/rc-services.sh and gendepend.awk for
+ this.
+ - Add functions for more common tasks in /sbin/runscript.sh to
+ /sbin/rc-services.sh.
+ - Move 'consoletype' to /sbin.
+ - Rename /sbin/rc-envupdate.sh to /sbin/env-update.sh; updated
+ /etc/init.d/bootmisc for this.
+ - Move rc-services.sh, rc-daemon.sh and rc-help.sh to /lib/rcscripts/sh.
+ - Improve detection of circular depends ... modified gendepend.awk for this.
+
+* rc-scripts 1.4.3.7 (11 May 2003)
+
+ 11 May 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Too many things to remember, so here is changes of note:
+ - More changes to gendepend.awk. This basically modifies it to not use
+ symlinks in $svcdir/{need,use,before,after,provide} anymore, but rather
+ create a file that can be sourced. Seems to speedup things nicely.
+ - Add /sbin/rc-services.sh. This is basically a module to get dependency
+ info from the new $svcdir/deptree, and some other new service functions.
+ - Modify the whole works to *only* source all needed files once. This
+ includes /sbin/{functions.sh,rc-services.sh,rc-daemon.sh}. Also
+ rc-services.sh will only source $svcdir/deptree once. /sbin/runscript.sh
+ is sourced more than once (actually each time a service is started or
+ stopped, but is is cut down much). Also seems to speed things up again.
+ - Fix a long outstanding bug in gendepend.awk that caused the 'net'
+ dependency to not be actually used in shutdown, causing the services
+ needing it to be stoped before net.* services.
+ - Add the RC_PARALLEL_STARTUP variable, with schedule_service_startup() to
+ /sbin/rc-services.sh and /etc/conf.d/rc. This is experimental parallel
+ startup of services, and seems to work nicely. Only issues to date is
+ that printing of messages is not synced, and a race very intermittantly
+ that causes a service to be started when it was already scheduled.
+ - Add a new dependency type 'parallel' that can be used to control if a
+ service can be started in paralled or not. Possible arguments is "yes"
+ or "no"; if it is not present, it is considered as "yes":
+
+ depend() {
+ parallel yes|no
+ }
+
+ Modified cachedepend.awk, gendepend.awk and /sbin/rc-services.sh.
+ - Fix the 'single' runlevel to actually work properly, and without a
+ /etc/runlevels/single directory.
+ - Remove the BOOT variable, and update /sbin/rc to set SOFTLEVEL properly.
+ Fix /etc/init.d/{checkroot,bootmisc} to use SOFTLEVEL instead of BOOT.
+
+ 08 May 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Major rework of /lib/rcscript/awk/gendepend.awk, cleaning it up nicely,
+ and adding more sanity checks.
+
+ 04 May 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Revert /etc/init.d/hostname the way it was, as it should be the user's
+ choice if he want to have a FQDN in there or not, bug #14946.
+
+ Add /etc/init.d/domainname for those that want to use it.
+
+ 29 Apr 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Change the root check back the way it was, else it breaks with non bash
+ shells; modified /etc/profile.
+
+ 29 Apr 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Change test in /etc/profile for root to '[ "$EUID" -eq 0 ]', bug #20140.
+
+ 27 Apr 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Add various patches from Rachel Holmes <rach@gmx.net>:
+
+ Dropped use of 'cat' in bash scripts, '$(<$file)' is there for that
+ purpose. Modified:
+
+ /etc/init.d/net.ppp0
+ /etc/init.d/nscd
+ /sbin/functions.sh
+ /sbin/rc
+ /sbin/rc-daemon.sh
+ /sbin/rc-envupdate.sh.bash
+ /sbin/runscript.sh
+
+ Exchanged some gratuitous use of awk for grep. Awk is a little resource
+ hungry just for a simple test. (I [azarah] did not apply the changes to
+ tests for 'devfs', as having 'usbdevfs' in the equation will break
+ things). Modified /sbin/rc for this.
+
+ Gentoo enforces having /proc, so uname -r is a little redundant when the
+ information is available without an external command. Modified:
+
+ /etc/init.d/modules
+ /etc/init.d/serial
+ /sbin/functions.sh
+ /sbin/modules-update
+
+ Changed 'id -u' commands to use $EUID in bash executed scripts, same
+ result no extra command. Modified:
+
+ /sbin/rc-envupdate.sh
+ /sbin/rc-envupdate.sh.bash
+ /sbin/rc-update
+
+ Removed all the cat sections, and the separate echo sections. The output
+ is _exactly_ the same, minus some spare spaces that have been removed.
+ Fourfold speed increase in the (granted flimsy) tests I have done.
+ Modified /sbin/rc-help.sh for this.
+
+ Final remaining 'cat' commands removed, in favour of using bash's internal
+ '$(< )' or 'echo'. Use of echo leads the way to future support for bash's
+ i18n anyway. Modified:
+
+ /sbin/rc
+ /sbin/rc-envupdate.sh
+ /sbin/rc-envupdate.sh.bash
+
+
+
+* rc-scripts 1.4.3.6 (27 Apr 2003)
+
+ 27 Apr 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Add a 'save' function /etc/init.d/clock, bug #19685.
+
+ Add a slocate group to /etc/group, bug #19604.
+
+ Do not stop a network service if we do not reboot on runlevel change,
+ as it could have been started by the user or hotplug. This should
+ address bug #12763; modified /sbin/rc for this.
+
+ Fix /etc/init.d/hostname to set only the hostname, and not the NIS
+ domainname.
+
+ Fix /etc/init.d/keymaps to be able to set the extended keymap in rc.conf.
+ This should close bug #16884.
+
+ Fix /etc/profile to be /bin/sh compadible, bug #18918.
+
+ Change the swap comments in /sbin/rc to "Activating (possible) swap" to
+ be more 'generic' ? Only try to disable swap if any devices/files was
+ activated. This should close bug #19089.
+
+ Fix /etc/init.d/checkroot to only remount / rw if not set explicitly to
+ rw in /etc/fstab, bug #19158.
+
+ 24 Apr 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Fix /etc/init.d/net.ppp0 to do the right thing if stopped was called,
+ but the ppp link was already down, bug #15333.
+
+ 12 Apr 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Fix type-o in /etc/init.d/consolefont (line 38 should be 'retval=$?').
+ Thanks to Matt Taylor <liverbugg@juno.com> (comment #6, bug #18344).
+
+ From linux-2.5.68, we need to mount devpts on /dev/pts again ...
+ updated /sbin/rc for this.
+
+ 11 Apr 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Fix errors on sourcing /etc/profile if EDITOR is not set, bug #18995.
+
+ 10 Apr 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Make checking in unmount more strict, fixing bug #19007.
+
+ 09 Apr 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Add one more check to genenviron.awk, to spot cases where there is a
+ space between the variable and the '='.
+
+ 08 Apr 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Fix interactive shell not to have coloured prompt when used as a
+ dumb client, bug #18886. Fix was inspired by patch from
+ Matthew Kennedy <mkennedy@gentoo.org>.
+
+* rc-scripts 1.4.3.5 (06 Apr 2003)
+
+ 06 Apr 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Hopefully get the serial support sane again. Added /bin/consoletype
+ from Redhat to check for serial console. This should resolve bug
+ #18329 partly.
+
+ Add the --nocolor option to suppress the use of colors.
+
+ Change the 'status' option to return true if the service is running,
+ and false if stopped. This is only if the '--quiet' flag was also
+ given.
+
+ Change the start and stop options not to output or return false if
+ the '--quiet' flag was given.
+
+ Redirect stderr for consolechars in /etc/init.d/consolefont to /dev/null
+ as well, fixing bug #18344.
+
+ Optimize $EDITOR extraction in /etc/profile closing bug #18614, thanks to
+ Aron Griffis <agriffis@gentoo.org>.
+
+ Set HALT to 'shutdown' or 'reboot' depending on if we are shutting down
+ or rebooting.
+
+ 30 Mar 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Fix bug #18329 ... $COLS was not setup properly for serial console.
+
+ 24 Mar 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Optimize USB fs stuff in /etc/init.d/localmount to use less cats etc.
+ Fix a problem where it might not have mounted the USB fs when usbcore
+ was compiled as module, and the kernel did not mount it by the time
+ the script was started. Get it to rather check what filesystems is
+ supported when deciding if it should use 'usbdevfs' or 'usbfs', as
+ later 2.4 kernels now also support the newer 'usbfs'.
+
+ Optimize RAID stuff in /etc/init.d/checkfs a bit.
+
+ 16 Mar 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Update sbin/rc-envupdate.sh.bash for bug #17549.
+
+* rc-scripts 1.4.3.4 (16 Mar 2003)
+
+ 16 Mar 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Add /etc/issue done by a Polish ascii-artists, v|rus with some slight
+ modifications (purple and display hostname, etc). Closes bug #16806.
+
+ Add 'use hotplug' to /etc/init.d/net.eth0, to get cardbus hardware to
+ work properly. Closes bug #17348.
+
+ Add update from Wout Mertens <wmertens@gentoo.org> to speedup shutdown
+ of dhcp interfaces, closing bug #17378. This modified /etc/init.d/net.eth0.
+
+ 11 Mar 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Fix usage of /usr/bin/cut in /sbin/functions.sh, thanks Brandon Low
+ <lostlogic@gentoo.org>!
+
+ 10 Mar 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Add sysfs support for 2.5 kernels (mounted to /sys). Updated /sbin/rc
+ and /etc/init.d/halt.sh for this.
+
+ Update /etc/fstab to correctly mount /proc with:
+
+ mount -t proc none /proc
+
+ Do the same for /dev/shm:
+
+ mount -t tmpfs none /dev/shm
+
+ Fix a typeo in /etc/init.d/checkroot that caused 'umount -a' to output
+ noise if we exited a recovery console.
+
+ Fix /etc/init.d/hostname using /usr/bin/cut, closing bug #17175, thanks
+ to Bobby Bingham <uhmmmm@columbus.rr.com> for noticing this.
+
+ Bring down default gateway before adding new one .. this fixes issues
+ where eth0/whatever was brought up by kernel. Changed /etc/init.d/net.eth0
+ for this, closing bug #17164. Thanks to nth <y.lesaint@free.fr> for the
+ fix.
+
+ Fix /etc/init.d/modules to call modprobe with -q .. this fix issues where
+ it fails for module-init-tools if the module is already loaded. This
+ closes bug #17163, thanks to nth <y.lesaint@free.fr>.
+
+* rc-scripts 1.4.3.3 (09 Mar 2003)
+
+ 09 Mar 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Fix /etc/init.d/netmount not to unmount / on nfs/whatever, bug #16274.
+
+ Fix net.eth0 not to try and start an interface if already up.
+
+ Update MAKEDEV from Debian to support more archs. This adds support
+ for 'arm', 'hppa' among others. URL:
+
+ http://packages.debian.org/stable/base/makedev.html
+
+ Add support to /etc/init.d/modules to use /etc/modules.autoload/kernel-2.4
+ if we are using a 2.4 kernel, and /etc/modules.autoload/kernel-2.5 if we
+ are using a 2.5 kernel ... bug #17109.
+
+ 02 Mar 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Update /etc/init.d/hostname to only set the hostname to whatever is before
+ the first '.', and then set the domainname to the rest, closing bug #14946.
+
+ 28 Feb 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Merge some of the optimizations from Graham Forest <vladimir@gentoo.org>.
+
+ Fix spelling of dependency and some other spelling/grammer issues.
+ Thanks goes to Kerin Millar <kerin@recruit2recruit.net> and
+ Mike Frysinger <vapier@gentoo.org>, bug #15498.
+
+ Change $svcdir to '/var/lib/init.d' to be more FHS compliant, bug #15192.
+
+ Add 'Eterm' to /etc/skel/.bashrc, closing bug #14662.
+
+ Adjust comments about PROTOCOLS in /etc/rc.conf to try and prevent
+ bug #14556.
+
+ 27 Feb 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Finally fix /etc/init.d/halt.sh to unmount non critical mounts properly.
+
+ 20 Feb 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Kill /dev/ttyp0 error at boot by changing test in /etc/init.d/modules
+ to 'test -c /dev/ttyp0 &> /dev/null'.
+
+ 18 Feb 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Update /sbin/modules-update to generate /etc/modprobe.devfs from
+ /etc/modules.devfs. This along with the devfs-hack.patch in the latest
+ module-init-tools-0.9.9 should get rid of many of the warnings/errors
+ with devfs, and makes it work a bit better.
+
+ 17 Feb 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Fix /etc/inputrc for dvorak keyboard layout, bug #2599 again.
+
+ 16 Feb 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Fix the 'source /etc/profile.env' to be '. /etc/profile' to have ksh
+ support. This resolves bug #14994.
+
+ Move EDITOR to /etc/rc.conf. Also update /etc/profile to set EDITOR
+ according to /etc/rc.conf.
+
+ Update /etc/init.d/checkfs to fix bug #14282. It did not exclude comments,
+ and used 'basename' which is located in /usr/bin.
+
+ 13 Feb 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Merge changes from Nick Jones <carpaski@gentoo.org> to not run stty if
+ used in portage. Fix the NOCOLOR stuff. Updated /sbin/functions.sh for
+ this.
+
+ 06 Feb 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Update src/awk/genenviron.awk to properly set the environment for each
+ rc-script's depend() function by sourcing required config files.
+
+ 05 Feb 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Fix /sbin/rc-envupdate.sh to use $svcdir to set SVCDIR. This is thanks
+ to Max Kalika <alkern23@yahoo.com>, bug #15050.
+
+ 03 Feb 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Fix /sbin/modules-update to work with module-init-tools-0.9.9.
+
+ 30 Jan 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Add 'use isapnp' to /etc/init.d/modules, closing bug #14677, thanks to
+ Hubert Hanghofer <hubert.hanghofer@netbeer.co.at>.
+
+ 27 Jan 2003; Donny Davies <woodchip@gentoo.org>:
+
+ Fix halt.sh by moving the nut UPS kill power stuff back into a function!
+ Add fix from the wonderful analysis of Toby Dickenson
+ <tdickenson@geminidataloggers.com> in #12947.
+
+ 26 Jan 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Fix start-stop-daemon to check the call to nice() correctly for failure,
+ closing bug #14359, thanks to YAMAKURA Makoto <makoto@dsb.club.ne.jp>.
+
+ Fix globbing $? when checking return value of fsck in /etc/init.d/checkroot
+ and /etc/init.d/checkfs. This closes bug #13320, thanks to good work from
+ Malcolm Scott <m@lcolm.org.uk>.
+
+ 21 Jan 2003; Mike Frysinger <vapier@gentoo.org>:
+
+ Updated /etc/rc.conf to add elogin/entrance support #13790.
+
+ 21 Jan 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Update /etc/init.d/keymaps to enable unicode if required. This closes
+ bug #14306 thanks to Danny Milosavljevic <danny_milo@yahoo.com>.
+
+ 19 Jan 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Fix deadlock durning shutdown if tmpfs filesystems larger than free
+ memory, and swap gets deactivated, bug #13599. Updated /etc/init.d/halt.sh
+ for this.
+
+ Merge in some fixes from Vapier <vapier@gentoo.org> to /sbin/functions.sh.
+ This closes bug #13868.
+
+ Always add "/bin:/sbin:/usr/bin:/usr/sbin" to PATH, as it fixes both
+ 'su -c foo' not finding start-stop-daemon (etc), and bug #14127.
+
+ Add route for lo interface to /etc/init.d/net.lo, closing bug #14055.
+
+ 15 Jan 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Clear $svcdir in /sbin/rc before we run depscan to make sure we do
+ not have stale entries left from hard reboot, thanks to pac1085 on
+ irc.
+
+* rc-scripts 1.4.3.2 (15 Jan 2003)
+
+ 15 Jan 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Truely fix bootup on seperate /var.
+
+ Add some fixes and optimizations to /sbin/rc-update, thanks to
+ Daniel Robbins <drobbins@gentoo.org>.
+
+* rc-scripts 1.4.3.1 (15 Jan 2003)
+
+ 15 Jan 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Fix bootup on seperate /var.
+
+ 14 Jan 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Fix /etc/init.d/hostname and /etc/init.d/serial to close bug #13636.
+
+ 07 Jan 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Fix /etc/init.d/keymaps to force linux keycodes for PPC, thanks
+ to Olaf Hering <gentoo@aepfle.de>, bug #13193.
+
+ Turn on -C option to fsck on for all calls to fsck. Updated scripts
+ /etc/init.d/checkroot and /etc/init.d/checkfs, closing bug #13321.
+
+* rc-scripts 1.4.3.0 (07 Jan 2003)
+
+ 07 Jan 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Too much to mention, but here are a few:
+ - Major rewrite of software RAID startup, based on Mandrake's, as
+ ours was pretty broken :(
+ - Redone /sbin/rc to work without the tmpfs/ramfs stat directory.
+ Much of /sbin/functions.sh and other scripts have been changed
+ to support this.
+ - Reworked /etc/inittab to support this. Also moved critical
+ mounting of local filesystems to 'sysinit' function of /sbin/rc.
+ - Move state directory to /var/state/init.d/ ($svcdir).
+ - Move Adelie node init to /sbin/functions.sh to try and simplify
+ /sbin/rc a bit.
+ - Updated Copyright dates to 2003.
+
+* rc-scripts 1.4.2.8 (06 Jan 2003)
+
+ 02 Jan 2003; Martin Schlemmer <azarah@gentoo.org>:
+
+ Fix src/awk/genenviron.awk to work with multiple 'need', 'use', etc
+ lines, as it seems users do not note the need to have them all on
+ one line ....
+
+ Fix /sbin/runscript.sh to detect 'net.adsl', or any other net.*
+ script not ending on a digit. This closes bug #12887.
+
+ Fix get_KV to also check micro version of kernel; add KV_to_int()
+ helper function for get_KV. Update /etc/init.d/localmount to work
+ with new get_KV ...
+
+ 28 Dec 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Add support for generate-modprobe.conf or generating /etc/modprobe.conf
+ in the new sys-apps/module-init-tools. Note that you need version
+ 0.9.7 or later of sys-apps/module-init-tools. Updated
+ /sbin/modules-update for this.
+
+ Change /etc/init.d/localmount to use 'usbfs' and not 'usbdevfs' if
+ we are running kernel 2.5 or later ...
+
+ 26 Dec 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Add /etc/init.d/crypto-loop and /etc/conf.d/crypto-loop, a cool
+ rc-script to setup encrypted loopback devices. This was kindly
+ donated by Matthew Kennedy <mkennedy@gentoo.org> (bug #11471).
+
+ 25 Dec 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Fix src/awk/genenviron.awk stripping *all* '=', closing
+ bug #8901.
+
+ Fix src/awk/genenviron.awk not seperating CONFIG_PROTECT with
+ spaces ...
+
+* rc-scripts 1.4.2.7 (24 Dec 2002)
+
+ 24 Dec 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Add a fix to /sbin/functions.sh for bug #12601.
+
+ 22 Dec 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Add INFOPATH to /etc/env.d/00basic.
+
+ Fix src/awk/genenviron.awk to get the order of the env.d files
+ correct. Also fix it to handle *all* the SPECIALS correctly.
+ This closes bug #12411.
+
+* rc-scripts 1.4.2.6 (18 Dec 2002)
+
+ 18 Dec 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Add mips changes to sbin/MAKEDEV. This should close bug #12329,
+ thanks to Nicholas Wourms <nwourms@netscape.net>.
+
+ Quote some tests in /sbin/rc-update to fix/avoid the problem
+ in bug #
+
+ Fix awk regex in /etc/init.d/halt.sh to fix bug #11795.
+
+ Update shell for postgres user, closing bug #12258.
+
+ 11 Dec 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Fix src/awk/genenviron.awk not to add duplicate entries, closing
+ bug #8999.
+
+* rc-scripts 1.4.2.5 (09 Dec 2002)
+
+ 08 Dec 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Add another sync to /etc/init.d/halt.sh, closing bug 8173.
+
+ Add smmsp uid and gid. Closes bug #8952.
+
+ 04 Dec 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Setup colums, etc up properly for serial consoles in /sbin/functions.sh.
+ Closes bug #11557, thanks to Erik Scrafford <erik@scrafford.org>.
+
+ Add headers similar to that of portage-2.0.45 and up to the
+ generated profile files (/etc/{profile,csh}.env). Updated
+ src/awk/genenviron.awk for this.
+
+ 01 Dec 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Fix typeo in /etc/devfsd.conf, closing bug #11424, thanks to the
+ sharp eye of Techie2000 <Linux@mochamail.com>.
+
+ Rename /sbin/update-modules to /sbin/modules-update, closing
+ bug #11445.
+
+ Nano moved from /usr/bin/nano to /bin/nano. Fix this in
+ /etc/env.d/00basic, bug #10916.
+
+ 27 Nov 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Add more improvements to clustering code. This is from
+ Olivier Crete <crete@cerca.umontreal.ca>, bug #4151.
+
+ 26 Nov 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Change default 'net' dependency behaviour to be more suited
+ for notebook users. Basically if at least one net.* service
+ beside net.lo start successfully, the 'net' dependency is
+ considered up. Server admin can set RC_NET_STRICT_CHECKING="yes"
+ in /etc/conf.d/rc to change this back to the old default.
+ This is the start to address bug #2706.
+
+* rc-scripts 1.4.2.4 (26 Nov 2002)
+
+ 26 Nov 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Initial merge of bits for Adelie Linux for SSI clusters. More
+ info at:
+
+ http://www.cerca.umontreal.ca/hpc/en/projects/adelie/index.html
+
+ 25 Nov 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ One liner fix to src/awk/cachedepends.awk to once again fix
+ bug #7803.
+
+ 18 Nov 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Add 'alias char-major-89 i2c-dev' to /etc/modules.d/aliases.
+ This should close bug #10891.
+
+* rc-scripts 1.4.2.3 (18 Nov 2002)
+
+ 18 Nov 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Add some more checks to src/awk/*. Fix error printing for
+ /sbin/depscan.sh.
+
+ Link awk module with gcc and not with ld. This should fix
+ problems on sparc and alpha. Many thanks for this fix to
+ Stephan Jones <cretin@gentoo.org>.
+
+ Remove the copyright info from config files, thanks to
+ Matthew Kennedy <mkennedy@gentoo.org>.
+
+* rc-scripts 1.4.2.2 (18 Nov 2002)
+
+ 18 Nov 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Add src/awk/genenviron.awk which is rc-envupdate.sh ported
+ to awk. This is also much faster than its bash version.
+
+ Remove the 'Spider cat fix' from depscan.sh.bash, as it makes
+ things even slower on older boxes. Bug #10548.
+
+ After a bored Vapier decided that he needed to update the
+ licenses of things in /etc :P, I did the rest. Hopefully
+ not too many people will nuke thier fstab :/
+
+* rc-scripts 1.4.2.1 (18 Nov 2002)
+
+ 18 Nov 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Update src/awk/cachedepends.awk to find its own rc-scripts,
+ fixing the need for find which broke systems with /usr on
+ a different partition.
+
+ 17 Nov 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Add some extra checks to src/awk/cachedepends.awk and
+ src/awk/gendepends.awk.
+
+ Move some of the more generic functions in src/awk/gendepends.awk
+ to src/awk/functions.awk.
+
+* rc-scripts 1.4.2 (17 Nov 2002)
+
+ 17 Nov 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Add initial version of new depscan.sh. This uses awk scripts
+ to do the main work, giving about 10 times speed improvement on
+ slower machines. Updated /sbin/depscan.sh, src/filefuncts.c,
+ src/Makefile, src/awk/cachedepends.awk and src/awk/gendepends.awk
+ for this. This should close bug #10548.
+
+* rc-scripts 1.4.1.2 (5 Nov 2002)
+
+ 5 Nov 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Add UID/GID of 250 for Portage Fakeroot account.
+
+ 4 Nov 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Change /etc/init.d/clock to depend on localmount again, fixing
+ bug #10048.
+
+ Get deps on logger sane again. I wanted to get the logger started
+ as early as possible, but clock for one breaks if /usr is mounted
+ on seperate partition.
+
+ 29 Oct 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Fix return in /etc/init.d/modules to return 0 if /proc/modules
+ do not exists. Closes bug #7738, comment #5.
+
+* rc-scripts 1.4.1.1 (28 Oct 2002)
+
+ 28 Oct 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Fix /sbin/update-modules not to include backup files. Closes
+ bug #9707.
+
+ 26 Oct 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Fix update-modules borking if there are directories present
+ in /etc/modules.d/. Closes bug #9632.
+
+ 17 Oct 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Change deps on /etc/init.d/{clock,hostname,modules} not to
+ depend on localmount, but rather on checkroot, as all of them
+ just need / to be mounted. This should fix race conditions
+ because of checkfs dependency on modules. This should close
+ bug #9266.
+
+* rc-scripts 1.4.1 (13 Oct 2002)
+
+ 13 Oct 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Create and fix permissions on /tmp/.{ICE,X11}-unix/. This
+ is additional measures for bug #8281.
+
+ 12 Oct 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Update /etc/init.d/net.eth0 to fix bug #8626.
+
+ Fix /sbin/rc-update to check return code of "ln". This should
+ close bug #8867.
+
+ 29 Sep 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Fix indentation in /etc/inputrc. This should close
+ bug #8368.
+
+ Add extended status functionality. Should close bug #2462.
+
+ Add support for /sbin/rc-update to check if the rc-script
+ is executable or not. Thanks to widersacher@gmx.net, closing
+ bug #8326.
+
+ 25 Sep 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Fix /etc/init.d/bootmisc not to kill pidfiles of running
+ daemons. Improve NGPT support in /sbin/rc a bit.
+
+ 23 Sep 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Fix my last screwup with /etc/init.d/net.ppp0. Basically
+ forgot to change a few DEVICE's to IFACE ...
+
+ 22 Sep 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ NGPT support.
+
+ 17 Sep 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Did a small fix to /etc/init.d/net.eth0, thanks to
+ naanyaar2000@yahoo.com, bug #7407.
+
+ 16 Sep 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Add the permission stuff for generic scsi when compiled as
+ module, thanks to Bauno <bauno@inwind.it>.
+
+ Add support for /etc/devfs.d/ for additional devfs config
+ stuff .. idea from Denys Duchier <Denys.Duchier@ps.uni-sb.de>.
+
+ 11 Sep 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Fix small type-o from last changes to /etc/init.d/netmount.
+ Should resolve bug #7803.
+
+* rc-scripts 1.4.0 (7 Sep 2002)
+
+ 7 Sep 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Update /etc/init.d/net.eth0 to handle individual broadcast
+ and netmask for aliases. Should close bug #7407.
+
+ Give /var/run/utmp and /var/log/wtmp the proper permissions
+ and ownership. First steps in fixing bug #7630.
+
+ Change Raid stuff again in /etc/init.d/checkfs.
+
+ 26 Aug 2002; Donny Davies <woodchip@gentoo.org>:
+
+ Give root a 'root' GECOS in /etc/passwd, was NULL before.
+
+* rc-scripts 1.3.9 (25 Aug 2002)
+
+ 25 Aug 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Update /sbin/rc to fix some spelling/slang mistakes. Closes
+ bug #6887.
+
+ Move /etc/init.d/net.ppp0 's config to /etc/conf.d/net.ppp0.
+ This closes bug #6378.
+
+ Add IPv6 support to /etc/init.d/net.eth0. Closes bug #6175,
+ with many thanks to Asbjorn Sannes <ace@sannes.org>.
+
+ 20 Aug 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Update /etc/init.d/bootmisc to reset pam_console permissions.
+
+ Update /etc/devfsd.conf to have the "pam_console_apply_devfsd.so"
+ line for getting devfs to work with pam_console.
+
+ 12 Aug 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Update /etc/init.d/keymaps to first load the windowkeys.inc then
+ the user selected one, fixing bug #6295.
+
+ 11 Aug 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Change the 'cat' in check_rcscript() to a single 'awk' in
+ /sbin/depscan.sh. This should fix broken pipe issues if the
+ loop exists too early. Resolves bug #5961.
+
+ Fix software RAID startup/shutdown, bug #5310. Modified
+ /etc/init.d/checkfs and /etc/init.d/halt.sh for this.
+
+* rc-scripts 1.3.8 (08 Aug 2002)
+
+ 7 Aug 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Move the color ls stuff to .bashrc. Fix bug #5250.
+
+ 6 Aug 2002; Dan Armak <danarmak@gentoo.org>:
+
+ Correct the comments in rc.conf about the XSESSION variable: it should
+ be set to "kde-<version>" not "KDE". Closes bug #5948.
+
+ 5 Aug 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Fix the 'Usage' line in the help to return the correct options for
+ the script (/sbin/runscript.sh). Resolve bug #6029.
+
+ 3 Aug 2002; Donny Davies <woodchip@gentoo.org>:
+
+ Added UPS shutdown support for nut to halt.sh.
+ Added nut user/group as uid/gid 84.
+
+ 27 Jul 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Updated /sbin/rc's way of checking for devfs support (now rather uses
+ awk, as it is more accurate). Closes bug #5458.
+
+ Add the Redhat/Mandrake /forcefsck and /fastboot options to our checkroot
+ and checkfs. Updated /etc/init.d/{checkroot,checkfs,halt.sh} for this.
+ Thanks goes to Chris PeBenito (bug #5570).
+
+ Changed most daemons to use /bin/false as shell. Should close bug #5388.
+
+ 27 Jul 2002; Nicholas Jones <carpaski@gentoo.org>:
+
+ Added vpopmail user and group as 89:89
+
+ 22 Jul 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Add the cyrus user to /etc/passwd. Resolves bug #4100.
+
+ Some bugfixes and speed improvements to /sbin/depscan.sh after
+ last changes.
+
+ Replace some cat/grep's in /sbin/rc-envupdate.sh with awk's to
+ get some speed improvements.
+
+ 21 Jul 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Fix LVM support in /etc/init.d/checkfs again, thanks to help from
+ Kyle Manna <nitro@gentoo.org>.
+
+ Add software RAID support to /etc/init.d/checkfs, thanks to
+ Daniel Ahlberg <aliz@gentoo.org>.
+
+ Update the cache_depend() funtion in /sbin/depscan.sh not to
+ quit on any "}", but only on the one matching the first "{". This
+ requires wc in /bin, so baselayout should depend on
+ >=sys-apps/textutils-2.0.19-r2
+
+ Update /etc/init.d/netmount to try and detect nfs mounts that should be
+ mounted automatically on boot. This requires awk in /bin, so baselayout
+ should depend on >=sys-apps/gawk-3.1.0-r3.
+
+* rc-scripts 1.3.7 (17 Jul 2002)
+
+ 17 Jul 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Add logging functionality to the rc-scripts, thanks to Alexander Holler,
+ bug #4037 for the basic idea. Updated /sbin/functions.sh for this.
+
+ 16 Jul 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Add additional entries to /etc/services to support cyrus-imapd, thanks
+ to Nick Hadaway <raker@gentoo.org>.
+
+ Update /etc/init.d/consolefont to resolve bug #4968. This fixes a
+ problem with non 7bit ascii symbols.
+
+ Updated /etc/init.d/checkfs to detect if lvm is already active.
+ This should resolve bug #3613.
+
+ 5 Jun 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Add "usb" group, gid 85. Move "sshd" user and group to 22. Move
+ "games" user and group to 35
+
+ 3 Jun 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Update Copyright displayed at boot, thanks to Sascha Schwabbauer
+ (aka cybersystem). Updated /sbin/rc for this.
+
+ 30 Jun 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Update /etc/skel/.bashrc to update the window title of X terminals
+ that supports it. Closes bug #4232.
+
+ 26 Jun 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Add sshd user and group. Updated /etc/passwd and /etc/group for this.
+
+ Update /etc/inputrc to resolve bug #2599.
+
+ 20 Jun 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Add /opt/bin to $PATH and $ROOTPATH, closing bug #3603. Modified
+ /etc/env.d/00basic for this.
+
+ Add some new daemon stop and pid detection stuff to /sbin/functions.sh.
+ Nothing official, but I spent enough time on it not to want to loose it :)
+
+ Fixed a bug in /sbin/functions.sh that caused rc-scripts run as cron jobs
+ to give output to stderr. This was caused by a call to "stty", which when
+ run without a attatched terminal, have this effect. Basically just pipe
+ stderr to /dev/null.
+
+ 5 Jun 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Add /usr/local/share/man to $MANPATH (/etc/env.d/00basic), resolving
+ bug #3363
+
+ 26 May 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Update /etc/init.d/netmount not to try and mount NFS filesystems
+ if portmap was not started. This is to stop "hang" problems for
+ new users who do not add portmap to the default runlevel. See
+ bug #2555.
+
+ Add the video4linux stuff to /etc/devfsd.conf. Resolves bug #2015.
+
+ 19 May 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Move $EDITOR from /etc/profile to /etc/env.d/00basic.
+
+ 13 May 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Change the homes of user "at" and "cron" in /etc/passwd, as
+ they moved to /var/spool/cron...
+
+* rc-scripts 1.3.5 (12 May 2002)
+
+ 12 May 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Make slight modifications to /sbin/depscan.sh to improve speed (about
+ 1 second on a celeron 633).
+
+ Finally fix /sbin/runscript.sh to properly handle interdependencies
+ between types need/use and before/after on runlevel change. I can
+ actually kick myself for previous implementations, as this fix simplifies
+ things a lot, and is almost 30 lines of code less!
+
+ Change /etc/init.d/netmount not to fail if all mounts are not mounted.
+ It rather just exit with a warning, as I think most people have like
+ me mounts that are to boxes that are not always up.
+
+ Resolve bug #2439 (should not use try with the dd command for ramdisk
+ stuff). Also increase the number of inodes used for the ramdisk to
+ fix "out of space" errors. Updated /sbin/rc for this.
+
+ 10 May 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Resolve bug #2505 ... /sbin/rc-envupdate.sh should not use
+ backup files to generate /etc/profile.env.
+
+ Resolve bug #2489 and #2175. Modified /etc/init.d/net.eth0
+ for this.
+
+ 6 May 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Fixed /sbin/rc-envupdate.sh to only use the $KDEDIR of the highest
+ /etc/env.d/ file. Same for $QTDIR.
+
+ 5 May 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Add /etc/DIR_COLORS as it is no longer shipped with fileutils,
+ and is needed for some fixes.
+
+ 28 Apr 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Update /etc/rc.conf to be more clear and state that you should
+ remove consolefont from startup if you do not use it. Should
+ resolve bug #2174.
+
+ 26 Apr 2002; Donny Davies <woodchip@gentoo.org> passwd, group :
+
+ Added user/group apache with uid/gid 81.
+
+ 25 Apr 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Remove the "-net" from the line setting the default gateway
+ in /etc/init.d/net.eth0. Thanks to Peter W. Michaleas for
+ noting this.
+
+ 24 Apr 2002; Donny Davies <woodchip@gentoo.org> rc.conf :
+
+ Remove NFSSERVER from rc.conf since it's now covered in /etc/conf.d/nfs
+ which is installed with the nfs-utils package. Also tidied up some
+ really old, leftover junk like the non-supported stuff from rc5.
+ Closes #1754.
+
+ 23 Apr 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Remove creation of /var/run/utmpx from bootmisc again. Seems
+ other people have wierd problems.
+
+* rc-scripts 1.3.4 (21 Apr 2002)
+
+ 21 Apr 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Add /sbin/rc-envupdate.sh to speedup updating of /etc/profile.env,
+ and /etc/csh.env. Update /etc/init.d/bootmisc to use this.
+
+ Implement the status commandline argument. Updated /sbin/runscript.sh
+ and /sbin/rc-help.sh for this.
+
+ Fix /sbin/depscan.sh to honour NEED and USE overriding BEFORE
+ and AFTER.
+
+ 12 Apr 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Update /etc/init.d/bootmisc to create /var/run/utmpx. This
+ is needed, else /usr/bin/newgrp segfault.
+
+ 11 Apr 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Update /etc/skel/.bash_profile to make it tcsh compadible.
+ Thanks to Väinö Järvelä for this fix.
+
+ Update /etc/profile to also set the PS? variables if $SHELL
+ is set to /bin/sh. This should make prompt colours in
+ bootstrap work again.
+
+ Move LVM stuff to checkfs to ensure that they get fscked.
+ This resolves bug #1552.
+
+* rc-scripts 1.3.3 (5 Apr 2002)
+
+ 5 Apr 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Move /etc/init.d/{depscan.sh,runscript.sh,functions.sh} to /sbin.
+ This is done to try and ensure system integrity.
+
+ 1 Apr 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Add quotes to the "export INPUTRC=/etc/inputrc" line to resolve bug #1391.
+
+ Add a error message to /etc/init.d/consolefont, resolving bug #1415.
+
+ Add a bash check to the code that sets the prompt, fixing bug #1078.
+
+* rc-scripts 1.3.2 (24 Mar 2002)
+
+ 24 Mar 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Resolve bug #1274. Updated /etc/init.d/hostname and /etc/init.d/bootmisc
+ for this.
+
+ With the "before" and "after" stuff, recursion levels was getting too high,
+ and with some cases, things just plain did not work as it should. Reworked
+ things to to lower the levels of recursion and get the order right. Updated
+ /etc/init.d/runscript.sh for this.
+
+ Fixed a problem in /sbin/rc and /etc/init.d/runscript.sh where
+ ${svcdir}/softlevel did not always exist, but runscript.sh tried to open it.
+
+ Enhance --quiet support. Updated /etc/init.d/functions.sh for this.
+
+ Remove /etc/pwdb.conf, as pwdb already install a copy of this.
+
+ Remove /etc/pam.d/{rexec,rlogin,rsh} as pam already install this.
+
+ Added $INPUTRC to /etc/profile, since too many people keep on bugging me,
+ and it seems it has fallen now to my discression.
+
+* rc-scripts 1.3.1 (23 Mar 2002)
+
+ 23 Mar 2002; Daniel Robbins <drobbins@gentoo.org>: init.d/net.eth0: fix for
+ DHCP lease release from Jim Nutt.
+
+ 23 Mar 2002; Daniel Robbins <drobbins@gentoo.org>: rolling a new release
+ since there are a lot of important bug fixes in here that are needed.
+
+ 23 Mar 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Resolve bug #1292.
+
+ Remove the extra 'depmod -a' in /etc/init.d/modules, thanks to
+ Spidler.
+
+ 21 Mar 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Update /sbin/rc to fix a 'cat mounts' instead of the correct
+ version, 'cat /proc/mounts'.
+
+ 19 Mar 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Add initial support for the --quiet flag that suppress output.
+
+ 18 Mar 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Remove the 'try' from 'try /etc/init.d/depscan.sh' in /sbin/rc
+ as not all errors by depscan.sh is critical. It should be
+ reworked to do better error handeling.
+
+ 14 Mar 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Fix the GID and UID of nobody and nogroup in /etc/passwd and
+ /etc/group to match those of Debian, FBSD and others. Thanks
+ to those who reported it, and Woodchip for looking up the
+ proper values.
+
+ Update /etc/init.d/net.eth0 to properly down DHCP interfaces.
+ This resolves bug #1150, thanks to Paul Fleischer.
+
+ 11 Mar 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Updated /etc/init.d/functions.sh not to use /usr/bin/basename,
+ as some users have /usr on seperate partition which is not
+ mounted when depscan.sh is run the first time.
+
+ Updated the checking for more than one service providing the
+ same virtual function in /etc/init.d/depscan.sh. It should
+ be working now, and this also fix a problem that when there is no
+ service providing a virtual, counter was used uninitialized.
+
+* rc-scripts 1.3.0 (10 Mar 2002)
+
+ 10 Mar 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Resolved bug #1021; updated /etc/init.d/consolefont for this.
+
+ Resolved bug #1029; updated /etc/init.d/net.eth0 for this.
+
+ Resolved bug #990; updated /etc/init.d/net.eth0, /etc/init.d/netmount
+ and /etc/init.d/localmount for this.
+
+ Lots of form/syntax cleanups, most things should be more
+ consistant now. Fixed fail detection/return values of lots of
+ scripts.
+
+ Lots of cleanup/fixes in the three main scripts behind our
+ rc-system, /sbin/rc, /etc/init.d/depscan.sh, /etc/init.d/runscript.sh
+
+ Fix a bug regarding a invalid $PATH for portage if /etc/init.d/functions.sh
+ is sourced in a ebuild.
+
+ Fix a bug that our rc-script wrapper introduced: Global variables
+ in scripts no longer worked. Updated /etc/init.d/runscript.sh for
+ this.
+
+ Implemented more error checking for the main startup code in /sbin/rc.
+ Also fixed try() for mounting /proc (maybe all mount commands).
+ The function worked fine in a simulated test, but in real life failed
+ to detect a error when mounting /proc (remember to thank Grant for
+ his UserMode ebuilds, and Guide).
+
+* rc-scripts 1.2.9 (6 Mar 2002)
+
+ 6 Mar 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ General form updates and some piping fixes.
+
+ Updated /etc/inittab, /etc/init.d/xdm and /etc/X11/startDM.sh
+ to fix a problem where startDM.sh would be respawned repeatedly
+ if xdm was not in the default runlevel.
+
+* rc-scripts 1.2.8 (4 Mar 2002)
+
+ 4 Mar 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Add /etc/init.d/xdm, /etc/X11/startDM.sh and updated /etc/inittab
+ to fix the "dead key" problem we had with xdm/gdm/kdm. We should
+ move them to the xfree ebuild later on when things settles down.
+
+ Added some sanity checks to /sbin/rc, /etc/init.d/runscripts.sh.
+
+ Added a basic $PATH to /etc/init.d/functions.sh to fix a problem
+ where we had a invalid $PATH on boot in some cases.
+
+ Updated /etc/init.d/keymap and /etc/init.d/consolefont to work with
+ the new sys-apps/kbd package.
+
+* rc-scripts 1.2.7 (3 Mar 2002)
+
+ 3 Mar 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Fixed the problem of rc-scripts trying to start/stop a service multiple
+ times if it fails to do so. Updated /etc/init.d/runscript.sh and /sbin/rc
+ for this.
+
+ Fixing some variable declarations in /etc/init.d/runscript.sh caused
+ /etc/init.d/net.lo to fail on stop ($IFACE was set invalid). Fixed
+ this.
+
+ Added caching of the "depend() { need foo; } " lines, and updated
+ /etc/init.d/depscan.sh to touch the actual files less. This should
+ speedup dependency caching a lot, especially on slow machines.
+
+ Updated /etc/passwd to have users with no shell defined, use /bin/false
+ for security.
+
+ Update /etc/fstab to mention /dev/shm since we dont mount it anymore.
+
+ 1 Mar 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Added a wrapper for sourcing the rc-scripts to eliminate syntax errors.
+ Thanks to Karl Trygve Kalleberg (aka karltk) for the idea. Updated
+ /etc/init.d/depscan.sh, /etc/init.d/functions.sh and
+ /etc/init.d/runscript.sh for this (added wrap_rcscript() function).
+
+ Removed stopping of dependent services that have current service as
+ a 'use'dependency ... should be less confusing now.
+ Updated /etc/init.d/runscript.sh for this.
+
+ 28 Feb 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Add /etc/conf.d/local.start and /etc/conf.d/local.stop for adding any misc
+ programs to startup. This should pretty much have /etc/init.d/ static,
+ except for baselayout updates, etc.
+
+ 27 Feb 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ In some wierd cases, a redundent /dev/.devfsd on a unmounted /dev can cause
+ problems. Fixed this in /sbin/rc.
+
+ Added the patches from Grant Goodyear (aka g2boojum) to enable us to
+ use a ramdisk to store the contents of ${svcdir}. Updated /sbin/rc,
+ /etc/init.d/functions.sh and /etc/init.d/checkroot for this.
+
+ 26 Feb 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Fix my brain dead update of the 25th. It really should keep
+ "gentoo=nodevfs" in mind. Also added 'get_bootparam()' to help in
+ retrieving kernel options. Updated /etc/init.d/functions.sh,
+ /etc/init.d/checkroot and /sbin/rc for this.
+
+ Updated /etc/init.d/consolefont to work without devfs as well.
+
+ When rebooting or shutting down, a service should not fail to stop
+ if a service it depends on, fails. Updated /etc/init.d/runscript.sh
+ for this.
+
+ 25 Feb 2002; Martin Schlemmer <azarah@gentoo.org>:
+
+ Added a check if /dev is mounted when creating entries for /etc/mtab.
+ This should solve a invalid entry or /dev being mounted even with
+ 'gentoo=nodevfs' option. Updated /etc/init.d/checkroot for this.
+
+ 17 Feb 2002: Daniel Robbins <drobbins@gentoo.org>: Made "xfs" the default
+ filesystem in /etc/fstab (from ReiserFS) and removed "notail" option (it's
+ just in a comment now)
+
+ 17 Feb 2002: Martin Schlemmer (azarah@gentoo.org):
+
+ Mmore fixes to 'after' and 'before', updated /etc/init.d/runscript.sh for
+ this. This should fix services not getting started in the correct order
+ in a tight loop, services getting stopped out of order, and some other
+ sanity checks. Updated rc-script.sh for updated help.
+
+ 15 Feb 2002: Martin Schlemmer (azarah@gentoo.org):
+
+ Update /etc/profile to resolve bug #588. Reimplemented things a bit,
+ and added the 'after' type. 'before' and 'after' will only work currently
+ for a change of runlevel. Updated /etc/init.d/depscan.sh,
+ /etc/init.d/runscript.sh and /sbin/rc for this.
+
+ 13 Feb 2002: Martin Schlemmer (azarah@gentoo.org):
+
+ Add some more entries to /etc/devfsd.conf to make alsa users life
+ easier ... thanks Tod.
+
+ 12 Feb 2002: Martin Schlemmer (azarah@gentoo.org):
+
+ Some more cleanups to /etc/init.d/depscan.sh and /etc/init.d/runscript.sh.
+
+ Fixed some services not starting again when restarting a service.
+ Seems simple is still the best way.
+
+ Fixed some other problems created with feature additions and cleanups.
+
+ 11 Feb 2002: Martin Schlemmer (azarah@gentoo.org):
+
+ General cleanups to /etc/init.d/depscan.sh and /etc/init.d/runscript.sh.
+
+ Added 'before *' to /etc/init.d/checkroot to make sure it gets
+ started first.
+
+ Added 'use *' to /etc/init.d/local to make sure it gets started
+ last.
+
+ 10 Feb 2002: Martin Schlemmer (azarah@gentoo.org):
+
+ Fixed /sbin/rc to stop a service on change of runlevel if it is
+ in 'use' by another service.
+
+ Added the 'provide' depend type for creating virtual services.
+ Updated /etc/init.d/depscan.sh for this.
+
+ Added the 'before' depend type. This is more for changing the
+ order services start in. Updated /etc/init.d/depscan.sh and
+ /etc/init.d/functions.sh for this.
+
+ Updated /etc/init.d/depscan.sh to work with '*' as argument for
+ dependency types. This can be used with 'use' and 'before' to
+ start a script last or first respectively.
+
+ Added save_options() and get_options() to /etc/init.d/functions.sh
+ for saving misc settings between startup/shutdown. Updated
+ /etc/init.d/net.eth0 to use these and properly down virtual
+ interfaces.
+
+ 6 Feb 2002: Martin Schlemmer (azarah@gentoo.org):
+
+ Updated both /etc/init.d/bootmisc and /etc/init.d/keymaps to be quiet
+ on no errors.
+
+* rc-scripts 1.2.6 (6 Feb 2002)
+
+ 2 Feb 2002: Martin Schlemmer (azarah@gentoo.org):
+
+ Updated /etc/net.eth0 to specify the gateway device via the $gateway
+ variable (something like gateway="eth0/192.168.0.1").
+
+ 2 Feb 2002: Martin Schlemmer (azarah@gentoo.org):
+
+ Added rc-script /etc/init.d/numlock, for enabling numlock at boot.
+
+ 29 Jan 2002: Martin Schlemmer (azarah@gentoo.org):
+
+ Hopefully the last fix to /etc/init.d/netmount to umount cleanly. This fix
+ implements a retry if not successful the first time, and will kill
+ processess using the mount. Also small type-o fix to /etc/init.d/halt.sh.
+
+ 27 Jan 2002: Donny Davies (woodchip@gentoo.org): security fix to
+ /etc/pam.d/sshd,login,chsh: added pam_shells.so to the stack.
+ Fixed /etc/passwd,group for user/group mysql.
+
+ 27 Jan 2002: Martin Schlemmer (azarah@gentoo.org): added charset
+ map file support to /etc/init.d/consolefont and the setting to
+ /etc/rc.conf.
+
+ 25 Jan 2002: Martin Schlemmer (azarah@gentoo.org): fixed dircolors
+ in skel files to support both versions of dircolors.
+
+ 23 Jan 2002: Martin Schlemmer (azarah@gentoo.org): fixed bug
+ in the restart stuff of /etc/init.d/runscript.sh that caused
+ a restart of a 'net' service not to restart services again
+ that depended on it.
+
+* rc-scripts 1.2.5 (20 Jan 2002)
+
+ 20 Jan 2002: Martin Schlemmer (azarah@gentoo.org): updated
+ /etc/init.d/net.eth0 to 'use' pcmcia.
+
+ 8 Jan 2002: Martin Schlemmer (azarah@gentoo.org): added '--sh' to
+ the dircolors command in /etc/skel/.bash_profile to handle cases
+ where bash do not export $SHELL.
+
+ 6 Jan 2002: Martin Schlemmer (azarah@gentoo.org): updated
+ /etc/init.d/runscripts.sh, /etc/init.d/net.eth0, /etc/conf.d/net and
+ removed /etc/init.d/net.eth0-dhcp to reflect a new 'bsd-ish' config
+ scheme for the net.eth* scripts.
+
+ 6 Jan 2002: Donny Davies (woodchip@gentoo.org): Removed email address
+ from manpages; no need for that..
+
+ 5 Jan 2002: Martin Schlemmer (azarah@gentoo.org): fix type-o in
+ /etc/devfsd.conf; had 'dvd' in the cdrw stuff.
+
+* rc-scripts 1.2.4 (30 Dec 2001)
+
+ 30 Dec 2001: Daniel Robbins (drobbins@gentoo.org): Changed default umask
+ back to 022 as it should be.
+
+ 30 Dec 2001; Martin Schlemmer (azarah@gentoo.org): Updated
+ /etc/init.d/checkfs to return 0 if the fs was successfully repaired.
+
+ 29 Dec 2001; Donny Davies (woodchip@gentoo.org):
+ sort -t: -k3,3 -n /etc/passwd,group. Ahhhh :))
+
+ 28 Dec 2001; Martin Schlemmer (azarah@gentoo.org);
+
+ Updated /etc/init.d/depscan.sh to store info about missing dependencies
+ of type 'need' in ${svcdir}/broken. Also updated /etc/init.d/runscript.sh
+ to use this when starting a script ('need' dependencies is critical for
+ startup). Added the broken() function to /etc/init.d/runscript.sh
+ to list the missing dependencies.
+
+ Updated /etc/init.d/runscript.sh for svc_start() to have better error
+ checking.
+
+ Updated /etc/init.d/functions.sh with ewend(), which is the same as
+ eend(), but print a warning on error, not a error. Updated
+ /etc/init.d/checkroot and /etc/init.d/checkfs to use this function.
+
+ 27 Dec 2001; Martin Schlemmer (azarah@gentoo.org);
+
+ Update /sbin/runscript.c to run /etc/init.d/rc-help.sh if no arguments
+ is passed to a rc-script.
+
+ Added /etc/init.d/rc-help.sh, simple script that prints out help for
+ the rc-scripts.
+
+ 25 Dec 2001; Martin Schlemmer (azarah@gentoo.org);
+
+ Update /etc/init.d/shutdown.sh and /etc/init.d/reboot.sh not to force the
+ halt and reboot. This fixes a problem where / was not unmounted properly
+ in some cases.
+
+ 24 Dec 2001; Martin Schlemmer (azarah@gentoo.org):
+
+ Move $svcdir to to /etc/init.d/functions.sh, and update
+ /etc/init.d/runscript.sh and /etc/init.d/depscan.sh for this
+
+ Modified /etc/init.d/runscript.sh to also restart the services that
+ depend on a service if that service is restarted. Enhanced the
+ restart function to be able to have custom restart() functions in
+ rc-scripts. The custom restart() have to use svc_stop() and
+ svc_start() to restart the service.
+
+ Add a pause function to /etc/init.d/runscript.sh. It will basically
+ stop a service without stopping the services that depends on that
+ service.
+
+ Add a pause function to /etc/init.d/runscript.sh. It will basically stop a
+ service without stopping the services that depends on that service.
+
+* rc-scripts 1.2.3 (18 Dec 2001)
+
+ 16 Dec 2001; Martin Schlemmer (azarah@gentoo.org):
+
+ Moved the stuff from /sbin/init (old) to /sbin/rc (basically drop the
+ init wrapper we used).
+
+ Some cleanups: take out the shm resize comment;
+
+ remove the $wrongmount;
+
+ remove the mountshm() function and insert it directly
+ where needed;
+
+ remove the setting of $PATH as /sbin/init already do
+ this for us.
+
+ Added the if statement to detect if it is the first time the 'boot'
+ runlevel is executed (if [ "$RUNLEVEL" = "S" ] && [ "$argv1" = "boot" ]).
+ $RUNLEVEL is a env var set by /sbin/init.
+
+ Also added functionality to detect if the kernel have DEVFS support
+ compiled in; seems new users thinks devfs is unstable and as they do
+ not always read the docs, it does not get compiled in ;/ Should
+ make live for us a bit easier.
+
+ 14 Dec 2001; Martin Schlemmer (azarah@gentoo.org):
+
+ Fixed /sbin/rc to kill a cosmetic bug in the part that stops all
+ the unneeded services.
+
+* rc-scripts 1.2.2 (8 Dec 2001)
+
+ 10 Dec 2001; Added a localhost entry in /etc/hosts.
+
+ 8 Dec 2001; Donny Davies (woodchip@gentoo.org): Added start-stop-daemon.c
+ to rc-scripts/sbin source. Moved rc-scripts/init.d/runscript.c to
+ rc-scripts/sbin/runscript.c. Added manpage for start-stop-daemon.
+ Start-stop-daemon is moved here from sysvinit by the way. There is stuff
+ in this ChangeLog that needs to be removed! Like the changes to hosts,
+ profile. /etc/{passwd,group} have minor UID and GID type fixes for
+ users ftp, postgres, xfs. Tweaked tarball.sh to not include CVS
+ directories.
+
+ 29 Nov 2001; Donny Davies (woodchip@gentoo.org): Added a man directory
+ to rc-scripts. Checked in two manpages there, one for modules.autoload.5
+ and one for update-modules.8. These were adapted from Debian. Updated
+ tarball.sh to include the new man directory. Updated baselayout to install
+ these manpages. Slightly tweak the /etc/modules.autoload comments.
+
+ 28 Nov 2001; Martin Schlemmer (azarah@gentoo.org):
+
+ Updated /sbin/init to work correctly with the 'gentoo=nodevfs' option,
+ and cleaned out old code.
+
+ Updated /etc/init.d/bootmisc with additional lock files to clean.
+
+ 27 Nov 2001; Martin Schlemmer (azarah@gentoo.org):
+
+ Updated /etc/init.d/depscan.sh for a virtual 'use' depend, called 'logger'
+ that can be used for services that needs to have a logger started before
+ they are started. Updated /etc/conf.d/basic with $SYSLOGGER that is used
+ to define what loggers the 'logger' depend represent.
+
+ 26 Nov 2001; Martin Schlemmer (azarah@gentoo.org):
+
+ Updated /etc/passwd and /etc/group with minor fixes to pass pwck
+ and grpck.
+
+ 25 Nov 2001; Martin Schlemmer (azarah@gentoo.org):
+
+ Changed umask in /etc/profile for the user to 077 for security.
+
+ Added a stop() function to /etc/init.d/clock. Also removed uneeded
+ 'source /etc/rc.conf' line.
+
+ Updated /etc/init.d/hostname to set the hostname to 'localhost' if
+ /etc/hostname is invalid.
+
+ Updated /sbin/init to move the entries in /lib/dev-state to /dev before
+ running devfsd, as it did still not save settings properly. Also removed
+ old /dev-state/compat stuff.
+
+ 25 Nov 2001; ncsd, the name service cache daemon script, has been removed
+ from the default "default" runlevel. It still exists in the archive so that
+ users who want/need it can add it easily.
+
+ 25 Nov 2001; Updated the /etc/fstab; removed usbdevfs (explicitly mounted),
+ removed notail from the ext2 boot partition, other cleanups.
+
+ 25 Nov 2001; Fixed init.d/clock script to work in UTC mode.
+
+ 24 Nov 2001; Martin Schlemmer (azarah@gentoo.org):
+
+ Added /etc/devfsd.conf and updated /sbin/init to use a new scheme for saving
+ /dev permissions. Also moved /dev-state to /lib/dev-state which is a more
+ standard location.
+
+ Fixed a ugly bug in /etc/init.d/depscan.sh. If a service depended on
+ itself, calling depscan.sh or changing runlevels cause a tempory effect
+ similar to a 'mini fork bomb'. Afterwards the depends was broken, and
+ changing runlevels did not want to work.
+
+ Updated /etc/init.d/halt.sh to terminate and display message for devfsd.
+ More cosmetic than anything else, but cant hurt with the new dev-state
+ scheme.
+
+ Updated /sbin/init to set the console log level to 1, so that bootup
+ can be much cleaner. Also updated /etc/init.d/modules not to have
+ a logger in it 'use' depends, as it should not be needed anymore.
+
+ Updated /sbin/rc to check if devfsd is still running between runlevel
+ changes.
+
+ Updated /etc/init.d/modules to run update-modules. We want to be sure
+ /etc/modules.conf is updated when running depmod -a.
+
+ Change ftp's uid to 21 in /etc/passwd (was the same as bind). Also
+ added a entry for xfs (X Font Server) in /etc/passwd and /etc/group.
+
+ Added /etc/init.d/net.ppp0, /etc/conf.d/net.ppp0 and
+ /usr/lib/ppp/chat-default as part of my new pppd scripts. Also
+ updated tarball.sh to handle ppp/chat-default.
+
+ Added /etc/skel/.bash* to make things cleaner.
+
+ Other minor changes.
+
+ 17 Nov 2001; Donny Davies (woodchip@gentoo.org): Added /etc/shells file
+ to rc-scripts. Can remove it from sys-libs/shadow at the next release.
+
+* rc-scripts 1.1.8 (15 Nov 2001)
+
+ 16 Nov 2001; removed bogus "mountall.test" script.
+
+ 15 Nov 2001; Martin Schlemmer (azarah@gentoo.org):
+
+ Updated init.d/{runscript.sh,depscan.sh}, sbin/rc to the new dep being
+ 'use' not 'uses', as it fits better with 'need' (not 'needs'). Also
+ removed unneeded for loop from init.d/depscan.sh, and other fixes. Updated
+ names of new functions in init.d/runscript.sh to better sounding ones.
+ Updated init.d/modules, init.d/netmount to use 'use'. Lots of other
+ fixes/cleanups.
+
+ Removed try() out of init.d/runscript.sh (why was this here ?).
+
+ 14 Nov 2001; Martin Schlemmer (azarah@gentoo.org):
+
+ Now init.d/bootmisc cleans /tmp. Also creates /etc/resolv.conf if it
+ doesn't exist.
+
+ init.d/hostname: Added check for a valid /etc/hostname.
+
+ init.d/keymaps: Added check for valid $KEYMAP.
+
+ init.d/modules: Added sysklogd, metalog, syslog-ng as 'use' deps. This
+ should solve Woodchip's syslog+glue issue. We just have to change the
+ console loglevel for metalog and syslog-ng (sysklogd already updated) not to
+ output info and warnings, etc to the console, then boot will be much cleaner.
+ Also the install guide will need changing to add the loggers to 'boot' and
+ not 'default' runlevel.
+
+ init.d/mountall.test: Hopefully updated to the new rc-scripts style. Is
+ this really needed (I cannot see that it is used anywhere ...)?
+
+ 13 Nov 2001; Martin Schlemmer (azarah@gentoo.org):
+
+ Updated init.d/runscript.sh, init.d/depscan.sh and sbin/rc with a new depend
+ called 'uses'. It basically have the same usage as 'need', except that it
+ do not start services that is not in the current and 'boot' runlevels.
+
+ Updated init.d/netmount to use the 'uses' depend.
+
+ 11 Nov 2001; Martin Schlemmer (azarah@gentoo.org):
+
+ Fixed init.d/runscript.sh not to destroy the 'need' depends in
+ /${svcdir}/need. This caused subsequent starting and stopping of services
+ not to start depends.
+
+ 7 Nov 2001; Martin Schlemmer (azarah@gentoo.org):
+
+ Fixed a problem in sbin/rc where the ${svcdir}/softscripts directory got
+ destroyed before stopping running services scheduled to be stopped. This
+ with the fact that $SOFTLEVEL was set too early, caused the services to be
+ stopped in the wrong order.
+
+ 30 Oct 2001; Martin Schlemmer (azarah@gentoo.org):
+
+ Modified init.d/netmount to check if any network filesystems is mounted.
+
+ 29 Oct 2001; init.d/netmount: umount -art doesn't seem to work, so I added
+ some awk and grep magic to find all remote filesystems and umount them.
+
+ 29 Oct 2001; Martin Schlemmer (azarah@gentoo.org):
+
+ A fix for checkroot (missing "/"); it now actually checks the root
+ filesystem. Also, a localmount cleanliness fix.
+
+* rc-scripts 1.1.7 (18 Oct 2001)
+
+[old changelog format follows]
+
+ *lots of scripts; woodchip
+ removed old rc5 scripts from cvs
+
+ *init.d/runscript.sh; agriffis
+ Added support for rc.conf and home-grown functions
+
+ *init.d/modules;
+ Now correctly looks at /etc/modules.autoload
+
+rc-scripts-1.1.6, released 15 Sep 2001
+======================================
+
+ *init.d/runscript.sh, others
+ Handling of "net" dependencies resolve to all net devices in
+ /etc/runlevels/boot and /etc/runlevels/[curr-runlevel]. INTERFACES
+ variable in /etc/rc.conf has been removed.
+
+ *init.d/runscript.sh
+ New "zap" option for manually resetting the state of an initscript
+ to stopped.
+
+ *init.d/{samba,sysklogd,sshd}
+ Removed from CVS; they live in their respective packages.
+
+rc-scripts-1.1.5, released 02 Sep 2001
+====================================
+
+ *sbin/rc-update
+ New version of the rc-update command for the new initscripts. Works
+ similarly to the old version, except this one updates our dependency
+ cache.
+
+ *init.d/functions.sh
+ New and better looking informational message functions (einfo, einfon).
+ Brand new message functions (ewarn).
+
+ *sbin/init, init.d/checkroot
+ We're going back to a /proc/mounts-based mtab symlink because it's
+ just plain better. Appropriate changes made.
+
+# vim:expandtab
diff --git a/bin/rc-status b/bin/rc-status
new file mode 100755
index 0000000..1476175
--- /dev/null
+++ b/bin/rc-status
@@ -0,0 +1,217 @@
+#!/bin/bash
+################################################################################
+# #
+# Author: Sean E. Russell <ser@germane-software.com> #
+# Version: 1.0 #
+# Date: Jun 26, 2002 #
+# Adaptation: Mike Frysinger [SpanKY] <vapier@gentoo.org> #
+# Original code was in Ruby ... recoded into bash (at syntax level) #
+# #
+# This application displays information about the RC system used by Gentoo. #
+# In particular, it displays a tree-like format of a run level, showing #
+# all of the services that are installed at that level, and what each #
+# service's status is (running, stopped, etc.) #
+# #
+# -a can be used to display all runlevels #
+# -d can be used to display service dependancies #
+# -u will display all unassigned services #
+# -s will display all services #
+# -h will display help #
+# <runlevel> is used to choose the run level for which information is #
+# displayed #
+# #
+# By default, rc-status only displays information about the current #
+# runlevel; services installed and services running. #
+# #
+################################################################################
+
+# grab code from functions.sh so we don't have to reproduce it
+source /sbin/functions.sh
+runleveldir=/etc/runlevels
+
+# grab settings from conf.d/rc
+source /etc/conf.d/rc
+source "${svclib}/sh/rc-daemon.sh"
+
+################################################################################
+# Parse command line options #
+################################################################################
+do_opt() {
+ case $1 in
+ --all|-a)
+ ALL=true
+ ;;
+ --depend)
+ DEPEND=true
+ ;;
+ --unused|-u)
+ ALL=true
+ UNUSED=true
+ ;;
+ --list|-l)
+ ls -1 ${runleveldir}
+ exit 0
+ ;;
+ --servicelist|-s)
+ ALL=true
+ SERVICELIST=true
+ ;;
+ --nocolor|-nc)
+ ;;
+ --help|-h|-*)
+ echo "USAGE: $0 [command | <runlevel>]"
+ echo
+ echo "Commands:"
+ echo " -a, --all Show services at all run levels"
+ echo " -l, --list Show list of run levels"
+ echo " -u, --unused Show services not assigned to any run level"
+ echo " -s, --servicelist Show service list"
+ echo " -nc,--nocolor Monochrome output only"
+ echo " <runlevel> Show services assigned to <runlevel>"
+ echo
+ echo "If no arguments are supplied, shows services for current run level."
+ exit 0
+ ;;
+ *)
+ runlevel=$1
+ ;;
+ esac
+}
+for opt in "$@" ; do
+ do_opt ${opt}
+ [[ -n $2 ]] && shift
+done
+
+################################################################################
+# Find the current runlevel being queried. This is either something supplied #
+# on the command line, or pulled from softlevel #
+################################################################################
+if [[ -z ${runlevel} ]] ; then
+ if [[ -e ${svcdir}/softlevel ]] ; then
+ runlevel=$(<${svcdir}/softlevel)
+ else
+ ewarn "Could not local current runlevel in ${svcdir}/softlevel"
+ if [[ -d ${runleveldir}/single ]] ; then
+ runlevel=single
+ elif [[ -d ${runleveldir}/default ]] ; then
+ runlevel=default
+ else
+ eerror "Your installation is probably broken ... please \`emerge baselayout\`"
+ exit 1
+ fi
+ ewarn "Assuming current runrevel is '${runlevel}'"
+ fi
+fi
+if [[ ! -d ${runleveldir}/${runlevel} ]] ; then
+ eerror "${runlevel} is not a valid run level !"
+ eerror "Valid runlevels (obtained from \`rc-status --list\`):"
+ rc-status --list
+ exit 1
+fi
+
+################################################################################
+# Build up a hash of the services associated with each run level. In the most #
+# trivial case, this is simply the current runlevel. If --all was specified, #
+# we gather information about all of the runlevels. If --unused was #
+# specified, we pull info about all of the services and filter for the ones #
+# that don't appear in any runlevel. #
+################################################################################
+runlevelidxs=$(ls ${runleveldir})
+declare -a runlevels
+# For each directory in /etc/runlevels, do ...
+arridx=0
+for level in ${runlevelidxs} ; do
+ if [[ ${level} == ${runlevel} || -n ${ALL} ]] ; then
+ runlevels[${arridx}]=$(find ${runleveldir}/${level} -maxdepth 1 -type l -printf '%f ')
+ let "arridx += 1"
+ fi
+done
+
+# In case --all was specified, get a list of all the services set up in
+# /etc/init.d; services can be added, but not enabled, and we need to
+# identify these 'orphan' services.
+in_list() { #$1=list $2=find
+ for ele in $1 ; do
+ if [[ ${ele} == $2 ]] ; then
+ echo 1
+ return 0
+ fi
+ done
+ echo 0
+ return 0
+}
+if [[ -n ${ALL} ]] ; then
+ unassigned=
+ allservices=
+ for service in $(ls -1 /etc/init.d | grep -v '\.sh$') ; do
+ if [[ $(in_list "${runlevels[*]}" "${service}") -eq 0 ]] ; then
+ unassigned="${unassigned} ${service}"
+ fi
+ allservices="${allservices} ${service}"
+ done
+ runlevelidxs="${runlevelidxs} UNASSIGNED"
+ runlevels[${arridx}]="${unassigned}"
+ runlevels[${arridx}+1]="${allservices}"
+fi
+
+################################################################################
+# Now collect information about the status of the various services; whether #
+# they're started, broken, or failed. Put all of this into arrays. #
+################################################################################
+if [[ -x ${svcdir}/started ]]; then
+ started=$(ls ${svcdir}/started)
+ # If we're root then update service statuses incase any naughty daemons
+ # stopped running without our say so
+ if [[ ${EUID} == 0 ]]; then
+ for service in ${started}; do
+ update_service_status "${service}"
+ done
+ started=$(ls ${svcdir}/started)
+ fi
+fi
+[[ -x ${svcdir}/starting ]] && starting=$(ls ${svcdir}/starting)
+[[ -x ${svcdir}/inactive ]] && inactive=$(ls ${svcdir}/inactive)
+[[ -x ${svcdir}/stopping ]] && stopping=$(ls ${svcdir}/stopping)
+
+################################################################################
+# Now print out the information we've gathered. We do this by going through #
+# the hash of 'runlevels' information, and for each String key/Array value #
+# pair, print the runlevel; then for each service in that runlevel, print the #
+# service name and its status. #
+################################################################################
+# Define a helper method for printing the status of a service; '[ xxx ]'
+print_msg() {
+ printf " %-$((COLS - 5 - ${#3}))s%s\n" "$1" "${BRACKET}[ $2$3 ${BRACKET}]${NORMAL}"
+}
+
+# if --all wasnt specified, dont print everything
+[[ -z ${ALL} ]] && runlevelidxs=${runlevel}
+if [[ -z ${UNUSED} ]] ; then
+ if [[ -z ${SERVICELIST} ]] ; then
+ arridx=0
+ else
+ runlevelidxs="all"
+ let "arridx += 1"
+ fi
+else
+ runlevelidxs="unused"
+fi
+
+for level in ${runlevelidxs} ; do
+ echo "Runlevel: ${HILITE}${level}${NORMAL}"
+ for service in ${runlevels[${arridx}]} ; do
+ if [[ -n ${inactive} && $(in_list "${inactive}" "${service}") -eq 1 ]] ; then
+ print_msg "${service}" "${WARN}" 'inactive'
+ elif [[ $(in_list "${started}" "${service}") -eq 1 ]] ; then
+ print_msg "${service}" "${GOOD}" 'started'
+ elif [[ -n ${starting} && $(in_list "${starting}" "${service}") -eq 1 ]] ; then
+ print_msg "${service}" "${GOOD}" 'starting'
+ elif [[ -n ${stopping} && $(in_list "${stopping}" "${service}") -eq 1 ]] ; then
+ print_msg "${service}" "${BAD}" 'stopping'
+ else
+ print_msg "${service}" "${BAD}" 'stopped'
+ fi
+ done
+ let "arridx += 1"
+ [ -n "${UNUSED}" ] && exit 0
+done
diff --git a/etc/conf.d/bootmisc b/etc/conf.d/bootmisc
new file mode 100644
index 0000000..e3292f9
--- /dev/null
+++ b/etc/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="no"
diff --git a/etc/conf.d/clock b/etc/conf.d/clock
new file mode 100644
index 0000000..0d2cc1e
--- /dev/null
+++ b/etc/conf.d/clock
@@ -0,0 +1,26 @@
+# /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".
+
+CLOCK="UTC"
+
+# 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"
+
+
+### 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/etc/conf.d/consolefont b/etc/conf.d/consolefont
new file mode 100644
index 0000000..7f430b1
--- /dev/null
+++ b/etc/conf.d/consolefont
@@ -0,0 +1,16 @@
+# /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"
diff --git a/etc/conf.d/domainname b/etc/conf.d/domainname
new file mode 100644
index 0000000..75631ac
--- /dev/null
+++ b/etc/conf.d/domainname
@@ -0,0 +1,17 @@
+# /etc/conf.d/domainname
+
+# When setting up resolv.conf, what should take precedence?
+# If you wish to always override DHCP/whatever, set this to 1.
+OVERRIDE=1
+
+# To have a proper FQDN, you need to setup /etc/hosts and /etc/resolv.conf
+# properly (domain entry in /etc/resolv.conf, and FQDN in /etc/hosts).
+#
+#DNSDOMAIN=""
+
+# This only set what /bin/hostname returns. If you need to setup NIS, meaning
+# what /bin/domainname returns, please see:
+#
+# http://www.linux-nis.org/nis-howto/HOWTO/
+#
+#NISDOMAIN=""
diff --git a/etc/conf.d/env_whitelist b/etc/conf.d/env_whitelist
new file mode 100644
index 0000000..03fc270
--- /dev/null
+++ b/etc/conf.d/env_whitelist
@@ -0,0 +1,10 @@
+# /etc/conf.d/env_whitelist: Environment whitelist for rc-system
+
+# Specify which variables is 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/00myownstuff file for example, and run env-update.
+
+# User controlled
+LANG
+
diff --git a/etc/conf.d/hostname b/etc/conf.d/hostname
new file mode 100644
index 0000000..619abcd
--- /dev/null
+++ b/etc/conf.d/hostname
@@ -0,0 +1,4 @@
+# /etc/conf.d/hostname
+
+# Set to the hostname of this machine
+HOSTNAME="localhost"
diff --git a/etc/conf.d/keymaps b/etc/conf.d/keymaps
new file mode 100644
index 0000000..eb68fbe
--- /dev/null
+++ b/etc/conf.d/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/etc/conf.d/local.start b/etc/conf.d/local.start
new file mode 100644
index 0000000..a55d2cc
--- /dev/null
+++ b/etc/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 1>&2 to hide output)
+
diff --git a/etc/conf.d/local.stop b/etc/conf.d/local.stop
new file mode 100644
index 0000000..7dc89f6
--- /dev/null
+++ b/etc/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/etc/conf.d/net b/etc/conf.d/net
new file mode 100644
index 0000000..54337cf
--- /dev/null
+++ b/etc/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/etc/conf.d/net.example b/etc/conf.d/net.example
new file mode 100644
index 0000000..dda45a1
--- /dev/null
+++ b/etc/conf.d/net.example
@@ -0,0 +1,570 @@
+##############################################################################
+# 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.
+#
+# 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.
+
+##############################################################################
+# DEFAULTS
+#
+# hotplug_eth0="yes"
+# Do we allow hotplug to bring up interfaces or not? The default is we do,
+# otherwise put no in the above value.
+# NOTE: hotplug just has to be installed for hotplugging to work - it does
+# not matter if it's in any runlevel or not.
+
+##############################################################################
+# 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=( "iproute2" )
+
+# 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 ESSID 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 expresions
+#config_eth0=( "192.168.0.{2..4}/24" )
+# 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
+#config_eth0=(
+# "192.168.0.2/24"
+# "4321:0:1:2:3:4:567:89ab"
+# "4321:0:1:2:3:4:567:89ac"
+#)
+
+# 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 todo routing if you need it - the below sets the default gateway
+#routes_eth0=(
+# "default via 192.168.0.1"
+# "default via 4321:0:1:2:3:4:567:89ab"
+#)
+
+# 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"
+
+##############################################################################
+# OPTIONAL MODULES
+
+# INTERFACE RENAMING
+# There is no consistent device renaming scheme for Linux.
+# The preferred way of naming devices is via the kernel module directly or
+# by using udev (http://www.reactivated.net/udevrules.php)
+
+# If you are unable to write udev rules, then we do provide a way of renaming
+# the interface based on it's MAC address, but it is not optimal.
+# Here is how to rename an interface whose MAC address is 00:11:22:33:44:55
+# to foo1
+#rename_001122334455="foo1"
+
+# You can also do this based on current device name - although this is not
+# recommended. Here we rename eth1 to foo2.
+#rename_eth1="foo2"
+
+#-----------------------------------------------------------------------------
+# 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
+# iwconfig is the default
+
+# wpa_supplicant
+# emerge net-wireless/wpa-supplicant
+# Wireless options are held in /etc/wpa_supplicant.conf
+# Consult the sample file /etc/wpa_supplicant.conf.example for instructions
+# To choose wpa_supplicant over iwconfig
+#modules=( "wpa_supplicant" )
+# To configure wpa_supplicant
+#wpa_supplicant_eth0="-Dprism54" # For Prism54 based cards
+#wpa_supplicant_ath0="-Dmadwifi" # For Atheros based cards
+# Consult wpa_supplicant for more drivers
+# By default we give wpa_suppliant 60 seconds to associate and authenticate
+# 0 means we wait indefinitely
+#associate_timeout_eth0=60
+
+# GENERIC WIRELESS OPTIONS
+# PLEASE READ THE INSTRUCTIONS IN /etc/conf.d/wireless.example FOR
+# HOW TO USE THIS ESSID VARIABLE
+# You can also override any settings found here per ESSID - which is very
+# handy if you use different networks a lot
+#config_ESSID=( "dhcp" )
+#dhcpcd_ESSID="-t 5"
+
+# 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_ESSID="nodns"
+#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 are mutually exclusive.
+
+# You can also override any settings found here per MAC address of the AP
+# 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
+#mac_config_001122334455=( "dhcp" )
+#mac_dhcpcd_001122334455="-t 10"
+#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 ESSID is set to the Access Point's ESSID 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 any of the above packages, you need to disable them
+#modules=( "!iwconfig" "!wpa_supplicant" )
+
+#-----------------------------------------------------------------------------
+# DHCP
+# DHCP can be provided by dhcpcd, dhclient, udhcpc or pump
+#
+# 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=( "udhcpc" ) # to select udhcpc over dhcpcd
+#
+# Notes:
+# - dhcpcd, udhcpc and pump send the current hostname
+# to the DHCP server by default
+# pump always sends the current hostname - so below to disable
+# udhcpc and dhcpcd from doing this
+# - dhcpcd does not daemonize when the lease time is infinite
+# - udhcp-0.9.3-r3 and earlier does not support getting NTP servers
+# - dhclient does 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
+
+# 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="..."
+
+# To set options for dhclient, you need to have an /etc/dhclient.conf file
+# See the dhclient man page for details
+
+# 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.
+
+# DHCLIENT
+# dhclient can modify /etc/dhclient.conf (or the file specified by the -cf
+# option) with the current hostname and to strip any script lines. To enable
+# this, add dhclient_edit_config="yes" to /etc/conf.d/net
+
+#-----------------------------------------------------------------------------
+# Automatic Private IP Addressing (APIPA)
+# 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" )
+
+#-----------------------------------------------------------------------------
+# 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 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
+
+#-----------------------------------------------------------------------------
+# 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 write a depend function for the bond so they get
+# configured correctly.
+# This is exactly the same as a depend() function in our init scripts
+#depend_br0() {
+# need net.eth0 net.eth1
+#}
+
+#-----------------------------------------------------------------------------
+# ADSL
+# For ADSL support, emerge net-dialup/rp-pppoe
+# 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 (eg fibre,
+# copper, wireless) , all vendors
+#mac_eth0="random-samekind"
+# - to randomize between any physical type of connection (eg 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 sys-apps/usermode-utilities
+#
+# NOTE: The interface name must be either tun or tap followed by a number
+#config_tun1=( "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"
+
+#-----------------------------------------------------------------------------
+# 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 write a depend function for the bridge so they get
+# configured correctly.
+# This is exactly the same as a depend() function in our init scripts
+#depend_br0() {
+# need net.eth0 net.eth1
+#}
+
+# NOTE: This creates an interface called br0 - you can give the interface
+# any name you like
+
+# Below is an example of configuring the bridge
+# Consult "man brctl" for more details
+#brctl_br0=( "setfd 0" "sethello 0" "stp off" )
+
+#-----------------------------------------------------------------------------
+# Tunnelling
+# 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
+
+#-----------------------------------------------------------------------------
+# 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 ESSID. See wireless.example for more details
+
+# To use dns settings such as these, dns_servers_eth0 must be set!
+# dns_domain_eth0="your.domain"
+# dns_servers_eth0="192.168.0.2 192.168.0.3"
+# dns_search_path_eth0="this.domain that.domain"
+
+# 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"
+
+#-----------------------------------------------------------------------------
+# 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
+# and you're done :)
+
+# By default we wait 10 seconds for netplug to configure the interface for us
+# if it doesn't, we abort but leave netplug running and the net.eth0 service
+# marked as inactive so when a cable is plugged in it starts fine.
+# plug_timeout="10"
+
+# 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=( "!netplug" )
+
+##############################################################################
+# 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.
+# return 0
+#}
+
+#postdown() {
+# # This function is mostly here for completeness... I haven't
+# # thought of anything nifty to do with it yet ;-)
+# # 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 ;-)
+#}
+
+##############################################################################
+# FORCING MODULES
+# The Big Fat Warning :- If you use module forcing do not complain to us or
+# file bugs about it not working!
+#
+# Loading modules is a slow afair - we have to check each one for the following
+# 1) Code sanity
+# 2) Has the required package been emerged?
+# 3) Has it modified anything?
+# 4) Have all the dependant modules been loaded?
+
+# Then we have to strip out the conflicting modules based on user preference
+# and default configuration and sort them into the correct order.
+# Finally we check the end result for dependancies.
+
+# This, of course, takes valuable CPU time so we provide module forcing as a
+# means to speed things up. We still do *some* checking but not much.
+
+# It is essential that you force modules in the correct order and supply all
+# the modules you need. You must always supply an interface module - we
+# supply ifconfig or iproute2.
+
+# The Big Fat Warning :- If you use module forcing do not complain to us or
+# file bugs about it not working!
+
+# Now that we've warned you twice, here's how to do it
+#modules_force=( "ifconfig" )
+#modules_force=( "iproute2" "dhcpcd" )
+
+# We can also apply this to a specific interface
+#modules_force_eth1=( "iproute2" )
+
+# The below will not work
+#modules_force=( "dhcpcd" )
+# No interface (ifconfig/iproute2)
+#modules_force=( "ifconfig" "essidnet" "iwconfig" )
+# Although it will not crash, essidnet will not work as it has to come after
+# iwconfig
+#modules_force=( "iproute2" "ifconfig" )
+# The interface will be setup twice which will cause problems
diff --git a/etc/conf.d/rc b/etc/conf.d/rc
new file mode 100644
index 0000000..b0b6167
--- /dev/null
+++ b/etc/conf.d/rc
@@ -0,0 +1,180 @@
+# /etc/conf.d/rc: Global config file for the Gentoo RC System
+
+# This is the number of tty's used in most of the rc-scripts (like
+# consolefont, numlock, etc ...)
+
+RC_TTY_NUMBER=11
+
+# Set to "yes" if you want the rc system to try and start services
+# in parallel for a slight speed improvement.
+
+RC_PARALLEL_STARTUP="no"
+
+# RC_NET_STRICT_CHECKING allows some flexibility with the 'net' service.
+# The following values are allowed:
+# none - The 'net' service is always considered up.
+# no - This basically means that at least one net.* service besides net.lo
+# must be up. This can be used by notebook users that have a wifi and
+# a static nic, and only wants one up at any given time to have the
+# 'net' service seen as up.
+# lo - This is the same as the 'no' option, but net.lo is also counted.
+# This should be useful to people that do not care about any specific
+# interface being up at boot.
+# yes - For this ALL network interfaces MUST be up for the 'net' service to
+# be considered up.
+
+RC_NET_STRICT_CHECKING="no"
+
+# RC_AUTO_INTERFACE allows us to try and configure your interfaces
+# automatically. This includes:
+# - link /etc/{resolv,ntp,yp}.conf to /var/lib/net-scripts
+# - calculate a metric based on what interfaces are up and type
+# - apply interface state (resolv.conf, ntp.conf, etc)
+# - merge resolv.conf and ntp.conf from active interfaces based on metric
+# otherwise we don't do the above
+
+RC_AUTO_INTERFACE="no"
+
+# RC_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.
+
+RC_VOLUME_ORDER="raid evms lvm dm"
+
+# RC_BOOTLOG will generate a log of the boot messages shown on the console.
+# Useful for headless machines or debugging. You need to emerge the
+# app-admin/showconsole package for this to work.
+
+RC_BOOTLOG="no"
+
+# RC_USE_FSTAB allows you to override the default mount options for the
+# standard /proc, /sys, /dev, and /dev/pts mount points. Note that this
+# is the new way for selecting ramfs/tmpfs/etc... for udev mounting.
+
+RC_USE_FSTAB="no"
+
+# RC_USE_CONFIG_PROFILE allows you to have different /etc/conf.d files
+# based on your runlevel - if a conf.d file for your profile does not exist
+# then we try and use the default one.
+# To enable runlevel selection at boot, append "softlevel=foobar" to your
+# kernel line to change to the foobar runlevel. Here we would search for
+# /etc/conf.d/<service>.foobar config files before trying to use the default
+# /etc/conf.d/<service>.
+# Note that it is only active if 'softlevel' was specified via the kernel line,
+# and it is intended to use for different grub/lilo entries to specify config
+# changes for say laptops between home and work, where you would have setup
+# 'work' and 'home' runlevels, with /etc/conf.d/*.<runlevel> as needed.
+
+RC_USE_CONFIG_PROFILE="yes"
+
+# 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"
+
+# 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
+
+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"
+
+
+
+#
+# Controlling start-stop-daemon behavior
+
+# Set to "yes" if stop_daemon() should always retry killing the
+# service with sig KILL if it fails the first time.
+
+RC_RETRY_KILL="yes"
+
+
+# Set the amount of seconds stop_daemon() should wait between
+# retries.
+
+RC_RETRY_TIMEOUT=1
+
+
+# Set the amount of times stop_daemon() should try to kill
+# a service before giving up.
+
+RC_RETRY_COUNT=5
+
+
+# Set to "yes" if stop_daemon() should fail if the service
+# is marked as started, but not actually running on stop.
+
+RC_FAIL_ON_ZOMBIE="no"
+
+
+# Set to "yes" if stop_daemon() should attempt to kill
+# any children left in the system. This does not affect sshd.
+
+RC_KILL_CHILDREN="yes"
+
+
+# Set the amount of seconds start_daemon() waits after starting
+# the daemon to check it is still running. If it's not then we
+# try and stop any children if possible.
+RC_WAIT_ON_START="0.1"
+
+
+# Some daemons are started and stopped via start_stop_daemon.
+# We can change launch them through other daemons here, for example valgrind.
+# This is only useful for serious debugging of the daemon
+# Note non alphanumeric chars in the script name need to be changed to _
+# This is shown in the below example.
+# 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_syslog_ng="/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_syslog_ng="--background /usr/sbin/strace -f -o /tmp/strace.syslog-ng"
+
+#
+# Internal configuration variables
+#
+# NB: These are for advanced users, and you should really
+# know what you are doing before changing them!
+#
+
+
+# rc-scripts dep-cache directory
+#
+# NOTE: Do not remove the next line, as its needed by the baselayout ebuild!
+#
+# svcdir="/var/lib/init.d"
+
+svcdir="/var/lib/init.d"
+
+
+# Should we mount $svcdir in a ram disk for some speed increase
+# for slower machines, or for the more extreme setups ?
+
+svcmount="no"
+
+
+# FS type that should be used for $svcdir. Note that you need
+# $svcmount above set to "yes" for this to work ... Currently
+# tmpfs, ramfs, and ramdisk are supported (tmpfs is the default).
+
+svcfstype="tmpfs"
+
+
+# Size of $svcdir in KB. Note that ramfs doesn't support this
+# due to kernel limitations.
+
+svcsize=2048
diff --git a/etc/conf.d/wireless.example b/etc/conf.d/wireless.example
new file mode 100644
index 0000000..94c7918
--- /dev/null
+++ b/etc/conf.d/wireless.example
@@ -0,0 +1,283 @@
+# /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
+##############################################################################
+# Remember to change eth0 to your wireless interface which may be
+# eth0, eth1, wlan0, ath0 - you get the idea. If you're not sure
+# you can type "iwconfig" at the command prompt and it will tell you which
+# interfaces are wireless.
+# Say that your wireless interface is ath0 - the line
+# #essid_eth0="any"
+# becomes
+# #essid_ath0="any"
+#
+# Remember to change ESSID to your ESSID.
+# Say that your ESSID is My NET - the line
+# #key_ESSID="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 ESSID'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 ESSID 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
+#
+# As a final note, 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
+# Set to "any" to connect to any ESSID - 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 ESSID 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 ESSID?
+#adhoc_essid_eth0="WLAN"
+
+#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
+#iwpriv_eth0=""
+
+# 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 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
+# You can't use "any" for an ESSID here
+#key_ESSID="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_ESSID="s:foobar enc open"
+#key_ESSID="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_ESSID="s:'foo bar' enc open"
+
+# WEP key for the AP with MAC address 001122334455
+#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_ESSID="open s:foobar"
+#key_ESSID="open 1234-5678-9012"
+#key_ESSID="s:foobar enc open"
+#key_ESSID="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_ESSID="[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 ESSID - which is very handy if you use different networks a lot
+#config_ESSID=( "dhcp" )
+#dhcpcd_ESSID="-t 5"
+#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" )
+#dhcpcd_001122334455="-t 10"
+#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 too!
+# Change 001122334455 to the MAC address and ESSID to the ESSID
+# it should map to
+#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} && -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/etc/env.d/00basic b/etc/env.d/00basic
new file mode 100644
index 0000000..d19d540
--- /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/filesystems b/etc/filesystems
new file mode 100644
index 0000000..de172c9
--- /dev/null
+++ b/etc/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 knows what you are doing!
+*
diff --git a/etc/fstab b/etc/fstab
new file mode 100644
index 0000000..64cb8de
--- /dev/null
+++ b/etc/fstab
@@ -0,0 +1,30 @@
+# /etc/fstab: static file system information.
+#
+# noatime turns off atimes for increased performance (atimes normally aren't
+# needed; notail increases performance of ReiserFS (at the expense of storage
+# efficiency). It's safe to drop the noatime options if you want and to
+# switch between notail / tail freely.
+#
+# The root filesystem should have a pass number of either 0 or 1.
+# All other filesystems should have a pass number of 0 or greater than 1.
+#
+# See the manpage fstab(5) for more information.
+#
+
+# <fs> <mountpoint> <type> <opts> <dump/pass>
+
+# NOTE: If your BOOT partition is ReiserFS, add the notail option to opts.
+/dev/BOOT /boot ext2 noauto,noatime 1 2
+/dev/ROOT / ext3 noatime 0 1
+/dev/SWAP none swap sw 0 0
+/dev/cdroms/cdrom0 /mnt/cdrom iso9660 noauto,ro 0 0
+#/dev/fd0 /mnt/floppy auto noauto 0 0
+
+# NOTE: The next line is critical for boot!
+proc /proc proc defaults 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/etc/group b/etc/group
new file mode 100644
index 0000000..2d58052
--- /dev/null
+++ b/etc/group
@@ -0,0 +1,43 @@
+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
+man::15:man
+cron::16:cron
+console::17:
+audio::18:
+cdrom::19:
+dialout::20:root
+ftp::21:
+sshd::22:
+at::25:at
+tape::26:root
+video::27:root
+squid::31:squid
+gdm::32:gdm
+xfs::33:xfs
+games::35:
+postgres::70:
+cdrw::80:
+nut::84:
+usb::85:
+users::100:games
+nofiles:x:200:
+postfix:x:207:
+postdrop:x:208:
+smmsp:x:209:smmsp
+portage::250:portage
+utmp:x:406:
+nogroup::65533:
+nobody::65534:
diff --git a/etc/hosts b/etc/hosts
new file mode 100644
index 0000000..53f39d3
--- /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/inittab b/etc/inittab
new file mode 100644
index 0000000..a2c679a
--- /dev/null
+++ b/etc/inittab
@@ -0,0 +1,45 @@
+# /etc/inittab:
+#
+# This file describes how the INIT process should set up
+# the system in a certain run-level.
+#
+
+# Default runlevel.
+id:3:initdefault:
+
+# System initialization, mount local filesystems, etc.
+si::sysinit:/sbin/rc sysinit
+
+# Further system initialization, brings up the boot runlevel.
+rc::bootwait:/sbin/rc boot
+
+l0:0:wait:/sbin/rc shutdown
+l1:S1:wait:/sbin/rc single
+l2:2:wait:/sbin/rc nonetwork
+l3:3:wait:/sbin/rc default
+l4:4:wait:/sbin/rc default
+l5:5:wait:/sbin/rc default
+l6:6:wait:/sbin/rc reboot
+#z6:6:respawn:/sbin/sulogin
+
+# TERMINALS
+c1:12345:respawn:/sbin/agetty 38400 tty1 linux
+c2:12345:respawn:/sbin/agetty 38400 tty2 linux
+c3:12345:respawn:/sbin/agetty 38400 tty3 linux
+c4:12345:respawn:/sbin/agetty 38400 tty4 linux
+c5:12345:respawn:/sbin/agetty 38400 tty5 linux
+c6:12345:respawn:/sbin/agetty 38400 tty6 linux
+
+# SERIAL CONSOLES
+#s0:12345:respawn:/sbin/agetty 9600 ttyS0 vt100
+#s1:12345:respawn:/sbin/agetty 9600 ttyS1 vt100
+
+# What to do at the "Three Finger Salute".
+ca:12345:ctrlaltdel:/sbin/shutdown -r now
+
+# Used by /etc/init.d/xdm to control DM startup.
+# Read the comments in /etc/init.d/xdm for more
+# info. Do NOT remove, as this will start nothing
+# extra at boot if /etc/init.d/xdm is not added
+# to the "default" runlevel.
+x:a:once:/etc/X11/startDM.sh
diff --git a/etc/inputrc b/etc/inputrc
new file mode 100644
index 0000000..aaabc80
--- /dev/null
+++ b/etc/inputrc
@@ -0,0 +1,56 @@
+# /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
+#
+
+# 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
+# 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/issue b/etc/issue
new file mode 100644
index 0000000..015e46d
--- /dev/null
+++ b/etc/issue
@@ -0,0 +1,3 @@
+
+This is \n.\O (\s \m \r) \t
+
diff --git a/etc/issue.devfix b/etc/issue.devfix
new file mode 100644
index 0000000..163e50f
--- /dev/null
+++ b/etc/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/etc/issue.logo b/etc/issue.logo
new file mode 100644
index 0000000..d8e20ef
--- /dev/null
+++ b/etc/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/modules.autoload.d/kernel-2.4 b/etc/modules.autoload.d/kernel-2.4
new file mode 100644
index 0000000..a92bec1
--- /dev/null
+++ b/etc/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:
+# 3c59x
diff --git a/etc/modules.autoload.d/kernel-2.6 b/etc/modules.autoload.d/kernel-2.6
new file mode 100644
index 0000000..6a9efab
--- /dev/null
+++ b/etc/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:
+# 3c59x
diff --git a/etc/modules.d/aliases b/etc/modules.d/aliases
new file mode 100644
index 0000000..85ff710
--- /dev/null
+++ b/etc/modules.d/aliases
@@ -0,0 +1,46 @@
+# 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
+
+# Old nvidia support ...
+alias char-major-195 NVdriver
+alias /dev/nvidiactl char-major-195
diff --git a/etc/modules.d/i386 b/etc/modules.d/i386
new file mode 100644
index 0000000..b89459f
--- /dev/null
+++ b/etc/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/networks b/etc/networks
new file mode 100644
index 0000000..48327f0
--- /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/passwd b/etc/passwd
new file mode 100644
index 0000000..e30265c
--- /dev/null
+++ b/etc/passwd
@@ -0,0 +1,28 @@
+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
+man:x:13:15:man:/usr/share/man:/bin/false
+postmaster:x:14:12:postmaster:/var/spool/mail:/bin/false
+cron:x:16:16:cron:/var/spool/cron:/bin/false
+ftp:x:21:21::/home/ftp:/bin/false
+sshd:x:22:22:sshd:/dev/null:/bin/false
+at:x:25:25:at:/var/spool/cron/atjobs:/bin/false
+squid:x:31:31:Squid:/var/cache/squid:/bin/false
+gdm:x:32:32:GDM:/var/lib/gdm:/bin/false
+xfs:x:33:33:X Font Server:/etc/X11/fs:/bin/false
+games:x:35:35:games:/usr/games:/bin/false
+postgres:x:70:70::/var/lib/postgresql:/bin/bash
+nut:x:84:84:nut:/var/state/nut:/bin/false
+postfix:x:207:207:postfix:/var/spool/postfix:/bin/false
+smmsp:x:209:209:smmsp:/var/spool/mqueue:/bin/false
+portage:x:250:250:portage:/var/tmp/portage:/bin/false
+nobody:x:65534:65534:nobody:/:/bin/false
diff --git a/etc/profile b/etc/profile
new file mode 100644
index 0000000..835b0ab
--- /dev/null
+++ b/etc/profile
@@ -0,0 +1,58 @@
+# /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.
+ PS1="`whoami`@`uname -n | cut -f1 -d.` \$ "
+fi
diff --git a/etc/protocols b/etc/protocols
new file mode 100644
index 0000000..3f48ccb
--- /dev/null
+++ b/etc/protocols
@@ -0,0 +1,42 @@
+# /etc/protocols
+#
+# Internet (IP) protocols definition file
+#
+# See protocols(5) for more info
+#
+
+ip 0 IP # internet protocol, pseudo protocol number
+icmp 1 ICMP # internet control message protocol
+igmp 2 IGMP # Internet Group Management
+ggp 3 GGP # gateway-gateway protocol
+ipencap 4 IP-ENCAP # IP encapsulated in IP (officially ``IP'')
+st 5 ST # ST datagram mode
+tcp 6 TCP # transmission control protocol
+egp 8 EGP # exterior gateway protocol
+pup 12 PUP # PARC universal packet protocol
+udp 17 UDP # user datagram protocol
+hmp 20 HMP # host monitoring protocol
+xns-idp 22 XNS-IDP # Xerox NS IDP
+rdp 27 RDP # "reliable datagram" protocol
+iso-tp4 29 ISO-TP4 # ISO Transport Protocol class 4
+xtp 36 XTP # Xpress Tranfer Protocol
+ddp 37 DDP # Datagram Delivery Protocol
+idpr-cmtp 38 IDPR-CMTP # IDPR Control Message Transport
+ipv6 41 IPv6 # IPv6
+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 # Reservation Protocol
+gre 47 GRE # General Routing Encapsulation
+esp 50 ESP # Encap Security Payload for IPv6
+ah 51 AH # Authentication Header for IPv6
+skip 57 SKIP # SKIP
+ipv6-icmp 58 IPv6-ICMP # ICMP for IPv6
+ipv6-nonxt 59 IPv6-NoNxt # No Next Header for IPv6
+ipv6-opts 60 IPv6-Opts # Destination Options for IPv6
+rspf 73 RSPF # Radio Shortest Path First.
+vmtp 81 VMTP # Versatile Message Transport
+ospf 89 OSPFIGP # Open Shortest Path First IGP
+ipip 94 IPIP # IP-within-IP Encapsulation Protocol
+encap 98 ENCAP # Yet Another IP encapsulation
+pim 103 PIM # Protocol Independent Multicast
diff --git a/etc/rc.conf b/etc/rc.conf
new file mode 100644
index 0000000..b1c90e5
--- /dev/null
+++ b/etc/rc.conf
@@ -0,0 +1,39 @@
+# /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"
+
+# What display manager do you use ? [ xdm | gdm | kdm | entrance ]
+#DISPLAYMANAGER="xdm"
+
+# XSESSION is a new variable to control what window manager to start
+# default with X if run with xdm, startx or xinit. The default behavior
+# is to look in /etc/X11/Sessions/ and run the script in matching the
+# value that XSESSION is set to. The support scripts are smart enough to
+# look in all bin directories if it cant find a match in /etc/X11/Sessions/,
+# so setting it to "enlightenment" can also work. This is basically used
+# as a way for the system admin to configure a default system wide WM,
+# allthough it will work if the user export XSESSION in his .bash_profile, etc.
+#
+# NOTE: 1) this behaviour is overridden when a ~/.xinitrc exists, and startx
+# is called.
+# 2) even if ~/.xsession exists, if XSESSION can be resolved, it will
+# be executed rather than ~/.xsession, else KDM breaks ...
+#
+# Defaults depending on what you install currently include:
+#
+# Gnome - will start gnome-session
+# kde-<version> - will start startkde (ex: kde-3.0.2)
+# Xsession - will start a terminal and a few other nice apps
+
+#XSESSION="Gnome"
diff --git a/etc/services b/etc/services
new file mode 100644
index 0000000..eabc167
--- /dev/null
+++ b/etc/services
@@ -0,0 +1,969 @@
+# /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]
+#
+
+#
+# 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 # 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 # SUN Remote Procedure Call
+sunrpc 111/udp portmapper
+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
+photuris 468/tcp
+photuris 468/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
+ha-cluster 694/tcp # Heartbeat HA-cluster
+ha-cluster 694/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
+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.
+#
+socks 1080/tcp # socks proxy server
+socks 1080/udp
+rmiregistry 1099/tcp # Java RMI Registry
+rmiregistry 1099/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
+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
+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
+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
+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
+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
+corbaloc 2809/tcp # CORBA LOC
+corbaloc 2809/udp
+ndtp 2882/tcp # Network Dictionary Transfer Protocol
+ndtp 2882/udp
+gds_db 3050/tcp # InterBase server
+gds_db 3050/udp
+icpv2 3130/tcp icp # Internet Cache Protocol (Squid)
+icpv2 3130/udp icp
+mysql 3306/tcp # MySQL
+mysql 3306/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
+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
+netboot-pxe 3928/tcp pxe # PXE NetBoot Manager
+netboot-pxe 3928/udp pxe
+smauth-port 3929/tcp # AMS Port
+smauth-port 3929/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
+rwhois 4321/tcp # Remote Who Is
+rwhois 4321/udp
+krb524 4444/tcp
+krb524 4444/udp
+hylafax 4559/tcp # HylaFAX client-server protocol (new)
+hylafax 4559/udp
+piranha1 4600/tcp
+piranha1 4600/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
+xmpp-client 5222/tcp # XMPP Client Connection
+xmpp-client 5222/udp
+xmpp-server 5269/tcp # XMPP Server Connection
+xmpp-server 5269/udp
+cfengine 5308/tcp # CFengine
+cfengine 5308/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
+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
+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
+http-alt 8008/tcp # HTTP Alternate
+http-alt 8008/udp
+http-alt 8080/tcp # HTTP Alternate
+http-alt 8080/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
+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
+amanda 10080/tcp # amanda backup services
+amanda 10080/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
+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
+traceroute 33434/tcp # traceroute use
+traceroute 33434/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
+kerberos_master 751/tcp # Kerberos authentication
+kerberos_master 751/udp
+passwd_server 752/tcp # Kerberos passwd server
+passwd_server 752/udp
+krb_prop 754/tcp # Kerberos slave propagation
+krbupdate 760/tcp kreg # Kerberos registration
+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'
+linuxconf 98/tcp # LinuxConf
+smtps 465/tcp ssmtp # smtp protocol over TLS/SSL
+smtps 465/udp ssmtp
+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)
+noclog 5354/tcp # noclogd with TCP (nocol)
+noclog 5354/udp
+hostmon 5355/tcp # hostmon uses TCP (nocol)
+hostmon 5355/udp
+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
+webcache 8080/tcp # WWW caching service
+webcache 8080/udp
+tproxy 8081/tcp # Transparent Proxy
+tproxy 8081/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/shadow b/etc/shadow
new file mode 100644
index 0000000..03ecc34
--- /dev/null
+++ b/etc/shadow
@@ -0,0 +1,18 @@
+root:*:10770:0:::::
+halt:*:9797:0:::::
+operator:*:9797:0:::::
+shutdown:*:9797:0:::::
+sync:*:9797:0:::::
+bin:*:9797:0:::::
+ftp:*:9797:0:::::
+daemon:*:9797:0:::::
+adm:*:9797:0:::::
+lp:*:9797:0:::::
+mail:*:9797:0:::::
+postmaster:*:9797:0:::::
+news:*:9797:0:::::
+uucp:*:9797:0:::::
+man:*:9797:0:::::
+games:*:9797:0:::::
+guest:*:9797:0:::::
+nobody:*:9797:0:::::
diff --git a/etc/shells b/etc/shells
new file mode 100644
index 0000000..41347b5
--- /dev/null
+++ b/etc/shells
@@ -0,0 +1,9 @@
+# /etc/shells: valid login shells
+/bin/sh
+/bin/bash
+/bin/tcsh
+/bin/csh
+/bin/esh
+/bin/ksh
+/bin/zsh
+/bin/sash
diff --git a/etc/sysctl.conf b/etc/sysctl.conf
new file mode 100644
index 0000000..973c6b3
--- /dev/null
+++ b/etc/sysctl.conf
@@ -0,0 +1,48 @@
+# /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
+
+# 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
+
+# TCP Port for lock manager
+#fs.nfs.nlm_tcpport = 0
+# UDP Port for lock manager
+#fs.nfs.nlm_udpport = 0
diff --git a/init.d/bootmisc b/init.d/bootmisc
new file mode 100755
index 0000000..ad7637f
--- /dev/null
+++ b/init.d/bootmisc
@@ -0,0 +1,141 @@
+#!/sbin/runscript
+# Copyright 1999-2005 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+depend() {
+ use clock hostname
+ need localmount
+ before logger
+}
+
+start() {
+ [[ ${BOOT} != "yes" ]] && return 0
+
+ #
+ # 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 &> /dev/null
+ fi
+
+ if [[ -e /etc/sysctl.conf ]] ; then
+ ebegin "Configuring kernel parameters"
+ /sbin/sysctl -q -p /etc/sysctl.conf
+ eend 0
+ fi
+
+ if [[ -z ${CDBOOT} ]] && ! touch /var/run/.keep 2> /dev/null ; then
+ ewarn "Skipping /var and /tmp initialization (ro root?)"
+ return 0
+ fi
+
+ if [[ -x /sbin/env-update.sh ]] ; then
+ ebegin "Updating environment"
+ /sbin/env-update.sh -u > /dev/null
+ eend 0
+ fi
+
+ #
+ # Take care of random stuff [ /var/lock | /var/run | pam ]
+ #
+
+ if [[ -d /var/lib/net-scripts/state ]] ; then
+ ebegin "Cleaning /var/lib/net-scripts/state"
+ rm -rf /var/lib/net-scripts/state/*
+ eend 0
+ fi
+
+ ebegin "Cleaning /var/lock, /var/run"
+ rm -rf /var/run/console.lock /var/run/console/*
+
+ if [[ -z ${CDBOOT} ]] ; then
+ #
+ # 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 that we can login.
+ #
+ for x in $(find /var/run/ ! -type d ! -name utmp ! -name innd.pid ! -name random-seed) ; do
+ local daemon=${x##*/}
+ daemon=${daemon%*.pid}
+ # Do not remove pidfiles of already running daemons
+ if [[ -z $(ps --no-heading -C "${daemon}") ]] ; then
+ if [[ -f ${x} || -L ${x} ]] ; then
+ rm -f "${x}"
+ fi
+ fi
+ done
+ fi
+
+ # Reset pam_console permissions if we are actually using it
+ if [[ -x /sbin/pam_console_apply && ! -c /dev/.devfsd && \
+ -n $(grep -v -e '^[[:space:]]*#' /etc/pam.d/* | grep 'pam_console') ]] ; then
+ /sbin/pam_console_apply -r
+ fi
+
+ # Create the .keep to stop portage from removing /var/lock
+ > /var/lock/.keep
+ eend 0
+
+ #
+ # Clean up /tmp directory
+ #
+ if [[ -z ${CDBOOT} ]] && [[ -d /tmp ]] ; then
+ cd /tmp
+ if [[ ${WIPE_TMP} == "yes" ]] ; then
+ ebegin "Wiping /tmp directory"
+ # This eval stuff sucks, so if someone has a better *working*
+ # solution, please file a bug at http://bugs.gentoo.org/
+ # Originally ripped from Debian init scripts
+ local exceptions="
+ '!' -name . -a
+ '!' '(' -uid 0 -a
+ '('
+ -path './lost+found/*' -o
+ -path './quota.user/*' -o
+ -path './aquota.user/*' -o
+ -path './quota.group/*' -o
+ -path './aquota.group/*' -o
+ -path './.journal/*'
+ ')'
+ ')'"
+ # First kill most files, then kill empty dirs
+ eval find . -xdev -depth ${exceptions} ! -type d -print0 | xargs -0 rm -f --
+ eval find . -xdev -depth ${exceptions} -type d -empty -exec rmdir '{}' \\';'
+ eend 0
+ else
+ ebegin "Cleaning /tmp directory"
+ (
+ rm -f /tmp/.X*-lock /tmp/esrv* /tmp/kio* /tmp/jpsock.* /tmp/.fam*
+ rm -rf /tmp/.esd* /tmp/orbit-* /tmp/ssh-* /tmp/ksocket-* /tmp/.*-unix
+ ) &> /dev/null
+ eend 0
+ fi
+
+ (
+ # Make sure our X11 stuff have the correct permissions
+ mkdir -p /tmp/.{ICE,X11}-unix
+ chown 0:0 /tmp/.{ICE,X11}-unix
+ chmod 1777 /tmp/.{ICE,X11}-unix
+ [[ -x /sbin/restorecon ]] && restorecon /tmp/.{ICE,X11}-unix
+ ) &> /dev/null
+ 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 &> /dev/null
+}
+
+
+# vim:ts=4
diff --git a/init.d/checkfs b/init.d/checkfs
new file mode 100755
index 0000000..dbdfd0a
--- /dev/null
+++ b/init.d/checkfs
@@ -0,0 +1,54 @@
+#!/sbin/runscript
+# Copyright 1999-2005 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+depend() {
+ need checkroot modules
+}
+
+start() {
+ local retval=0
+
+ # Start RAID/LVM/EVMS/DM volumes for /usr, /var, etc.
+ # NOTE: this should be done *before* mounting anything
+ [[ -z ${CDBOOT} ]] && start_volumes
+
+ # Setup dm-crypt mappings if any
+ start_addon dm-crypt
+
+ if [[ -f /fastboot ]] || [[ -n ${CDBOOT} ]] ; then
+ rm -f /fastboot
+ else
+ ebegin "Checking all filesystems"
+ if [[ -f /forcefsck ]] ; then
+ ewarn "A full fsck has been forced"
+ fsck -C -R -A -a -f
+ retval=$?
+ rm -f /forcefsck
+ else
+ fsck -C -T -R -A -a
+ retval=$?
+ fi
+ if [[ ${retval} -eq 0 ]] ; then
+ eend 0
+ elif [[ ${retval} -ge 1 && ${retval} -le 3 ]] ; then
+ ewend 1 "Filesystem errors corrected."
+ # Everything should be ok, so return a pass
+ return 0
+ else
+ if [[ ${RC_FORCE_AUTO} == "yes" ]] ; then
+ eend 2 "Fsck could not correct all errors, rerunning"
+ fsck -C -T -R -A -a -y
+ retval=$?
+ fi
+
+ if [[ ${retval} -gt 3 ]] ; then
+ eend 2 "Fsck could not correct all errors, manual repair needed"
+ /sbin/sulogin ${CONSOLE}
+ fi
+ fi
+ fi
+}
+
+
+# vim:ts=4
diff --git a/init.d/checkroot b/init.d/checkroot
new file mode 100755
index 0000000..613f88a
--- /dev/null
+++ b/init.d/checkroot
@@ -0,0 +1,124 @@
+#!/sbin/runscript
+# Copyright 1999-2005 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+depend() {
+ before *
+}
+
+start() {
+ local retval=0
+
+ if [[ ! -f /fastboot && -z ${CDBOOT} ]] && ! is_net_fs / ; then
+ if touch -c / >& /dev/null ; then
+ ebegin "Remounting root filesystem read-only"
+ mount -n -o remount,ro /
+ eend $?
+ fi
+
+ if [[ -f /forcefsck ]] || get_bootparam "forcefsck" ; then
+ ebegin "Checking root filesystem (full fsck forced)"
+ fsck -C -a -f /
+ # /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
+ if [[ -n $(awk '($1 ~ /^(\/|UUID|LABEL)/ && $2 == "/" \
+ && NF == 6 && $6 != 0) { print }' /etc/fstab) ]]
+ then
+ ebegin "Checking root filesystem"
+ fsck -C -T -a /
+ 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"
+ elif [[ ${retval} -eq 2 || ${retval} -eq 3 ]] ; then
+ ewend 1 "Filesystem repaired, but reboot needed!"
+ echo -ne "\a"; sleep 1; echo -ne "\a"; sleep 1
+ echo -ne "\a"; sleep 1; echo -ne "\a"; sleep 1
+ ewarn "Rebooting in 10 seconds ..."
+ sleep 10
+ einfo "Rebooting"
+ /sbin/reboot -f
+ else
+ if [[ ${RC_FORCE_AUTO} == "yes" ]] ; then
+ eend 2 "Rerunning fsck in force mode"
+ fsck -y -C -T -a /
+ else
+ eend 2 "Filesystem couldn't be fixed :("
+ /sbin/sulogin ${CONSOLE}
+ fi
+ einfo "Unmounting filesystems"
+ /bin/mount -a -o remount,ro &> /dev/null
+ einfo "Rebooting"
+ /sbin/reboot -f
+ fi
+ fi
+
+ # Should we mount root rw ?
+ if mount -vf -o remount / 2> /dev/null | \
+ awk '{ if ($6 ~ /rw/) exit 0; else exit 1; }'
+ then
+ ebegin "Remounting root filesystem read/write"
+ mount -n -o remount,rw / &> /dev/null
+ if [[ $? -ne 0 ]] ; then
+ eend 2 "Root filesystem could not be mounted read/write :("
+ if [[ ${RC_FORCE_AUTO} != "yes" ]] ; then
+ /sbin/sulogin ${CONSOLE}
+ fi
+ else
+ eend 0
+ fi
+ fi
+
+ if [[ ${BOOT} == "yes" ]] ; then
+ local x=
+ local y=
+
+ #
+ # Create /etc/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
+ awk '$2 != "/" {print}' /proc/mounts >> /etc/mtab
+
+ # Now make sure /etc/mtab have additional info (gid, etc) in there
+ for x in $(awk '{ print $2 }' /proc/mounts | sort -u) ; do
+ for y in $(awk '{ print $2 }' /etc/fstab) ; do
+ if [[ ${x} == ${y} ]] ; then
+ mount -f -o remount $x
+ continue
+ fi
+ done
+ done
+
+ # Remove stale backups
+ rm -f /etc/mtab~ /etc/mtab~~
+ fi
+}
+
+
+# vim:ts=4
diff --git a/init.d/clock b/init.d/clock
new file mode 100755
index 0000000..2ce9616
--- /dev/null
+++ b/init.d/clock
@@ -0,0 +1,144 @@
+#!/sbin/runscript
+# Copyright 1999-2005 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+opts="save"
+
+depend() {
+ need localmount
+}
+
+setupopts() {
+ if is_uml_sys ; then
+ TBLURB="UML"
+ fakeit=1
+ elif is_vserver_sys ; then
+ TBLURB="VServer"
+ fakeit=1
+ elif is_xenU_sys ; then
+ TBLURB="xen"
+ fakeit=1
+ elif 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
+ [[ ${fakeit} -eq 1 ]] && return 0
+
+ if [[ ${readonly} == "yes" ]] ; then
+ myadj="--noadjfile"
+ else
+ myadj="--adjust"
+ fi
+
+ if [[ ${SRM} == "yes" ]] ; then
+ myopts="${myopts} --srm"
+ fi
+ if [[ ${ARC} == "arc" ]] ; then
+ myopts="${myopts} --arc"
+ fi
+ myopts="${myopts} ${CLOCK_OPTS}"
+
+ # Make sure user isn't using rc.conf anymore.
+ if grep -qs ^CLOCK= /etc/rc.conf ; then
+ ewarn "CLOCK should not be set in /etc/rc.conf but in /etc/conf.d/clock"
+ fi
+}
+
+start() {
+ local myopts=""
+ local myadj=""
+ local TBLURB="" fakeit=0
+ local errstr=""
+ local readonly="no"
+ local ret=0
+
+ if ! touch /etc/adjtime 2>/dev/null ; then
+ readonly="yes"
+ elif [[ ! -s /etc/adjtime ]] ; then
+ echo "0.0 0 0.0" > /etc/adjtime
+ fi
+
+ setupopts
+
+ if [[ ${fakeit} -ne 1 && ! -e /dev/rtc ]] ; then
+ local x
+ einfon "Waiting for /dev/rtc to appear"
+ for x in $(seq 10) ; do
+ if [[ ! -e /dev/rtc ]] ; then
+ echo -n "."
+ sleep 1
+ else
+ echo
+ fi
+ done
+ fi
+
+ ebegin "Setting system clock to 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 system clock to hardware clock"
+ else
+ ret=1
+ errstr="/sbin/hwclock not found"
+ fi
+ eend ${ret} "${errstr}"
+}
+
+stop() {
+ # Don't tweak the hardware clock on LiveCD halt.
+ [[ -n ${CDBOOT} ]] && return 0
+
+ [[ ${CLOCK_SYSTOHC} != "yes" ]] && return 0
+
+ local myopts=""
+ local TBLURB=""
+ local errstr=""
+ local ret=0
+
+ setupopts
+
+ ebegin "Syncing system clock to hardware clock [${TBLURB}]"
+ if [[ ${fakeit} -eq 1 ]] ; then
+ ret=0
+
+ elif [[ -x /sbin/hwclock ]] ; then
+ errstr=$(/sbin/hwclock --systohc ${myopts} 2>&1 >/dev/null)
+
+ if [[ -n ${errstr} ]] ; then
+ ret=1
+ else
+ ret=0
+ fi
+ errstr="Failed to sync clocks"
+ else
+ ret=1
+ errstr="/sbin/hwclock not found"
+ fi
+ eend ${ret} "${errstr}"
+}
+
+save() {
+ CLOCK_SYSTOHC="yes"
+ stop
+}
+
+
+# vim:ts=4
diff --git a/init.d/consolefont b/init.d/consolefont
new file mode 100755
index 0000000..35daa11
--- /dev/null
+++ b/init.d/consolefont
@@ -0,0 +1,68 @@
+#!/sbin/runscript
+# Copyright 1999-2005 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() {
+ if is_uml_sys ; then
+ ebegin "Setting user font"
+ eend 0
+ return 0
+ elif [[ -z ${CONSOLEFONT} ]] ; then
+ ebegin "Using the default console font"
+ eend 0
+ return 0
+ fi
+
+ local x=
+ local param=
+ local sf_param=
+ local retval=1
+
+ # Get additional parameters
+ if [[ -n ${CONSOLETRANSLATION} ]] ; then
+ param="-m ${CONSOLETRANSLATION}"
+ 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
+
+ for x in $(seq 1 "${RC_TTY_NUMBER}") ; do
+ /bin/setfont ${CONSOLEFONT} ${param} \
+ ${sf_param}/${ttydev}${x} > /dev/null
+ retval=$?
+ 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}"
+}
+
+
+# vim:ts=4
diff --git a/init.d/domainname b/init.d/domainname
new file mode 100755
index 0000000..aa5fbc7
--- /dev/null
+++ b/init.d/domainname
@@ -0,0 +1,60 @@
+#!/sbin/runscript
+# Copyright 1999-2005 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+depend() {
+ need checkroot hostname
+ before bootmisc
+}
+
+checkconfig_nis() {
+ if [[ -f /etc/nisdomainname ]] ; then
+ ewarn "You should stop using /etc/nisdomainname and use /etc/conf.d/domainname"
+ export NISDOMAIN=$(</etc/nisdomainname)
+ return 0
+ fi
+ [[ -n ${NISDOMAIN} ]]
+}
+
+checkconfig_dns() {
+ if [[ -f /etc/dnsdomainname ]] ; then
+ ewarn "You should stop using /etc/dnsdomainname and use /etc/conf.d/domainname"
+ export DNSDOMAIN=$(</etc/dnsdomainname)
+ fi
+ [[ -z ${DNSDOMAIN} ]] && return 1
+
+ if ! touch /etc/resolv.conf 2> /dev/null ; then
+ ewarn "Unable to set domain in resolv.conf (ro root?)"
+ return 1
+ else
+ return 0
+ fi
+}
+
+start() {
+ local retval=0
+ local retval2=0
+
+ if checkconfig_nis ; then
+ ebegin "Setting NIS domainname to ${NISDOMAIN}"
+ /bin/domainname "${NISDOMAIN}"
+ retval=$?
+ eend ${retval} "Failed to set the NIS domainname"
+ fi
+
+ if checkconfig_dns ; then
+ ebegin "Setting DNS domainname to ${DNSDOMAIN}"
+ resolv=$(grep -v '^[[:space:]]*domain' /etc/resolv.conf)
+ [[ ${OVERRIDE} == "1" ]] \
+ && resolv="${resolv}"$'\n'"domain ${DNSDOMAIN}" \
+ || resolv="domain ${DNSDOMAIN}"$'\n'"${resolv}"
+ echo "${resolv}" > /etc/resolv.conf
+ retval2=$?
+ eend ${retval2} "Failed to set the DNS domainname"
+ fi
+
+ return $((retval + retval2))
+}
+
+
+# vim:ts=4
diff --git a/init.d/halt.sh b/init.d/halt.sh
new file mode 100755
index 0000000..1d7a670
--- /dev/null
+++ b/init.d/halt.sh
@@ -0,0 +1,242 @@
+# Copyright 1999-2005 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+# Check to see if this is a livecd, if it is read the commandline
+# this mainly makes sure $CDBOOT is defined if it's a livecd
+[[ -f /sbin/livecd-functions.sh ]] && \
+ source /sbin/livecd-functions.sh && \
+ livecd_read_commandline
+
+# Reset pam_console permissions if we are actually using it
+if [[ -x /sbin/pam_console_apply && ! -c /dev/.devfsd && \
+ -n $(grep -v -e '^[[:space:]]*#' /etc/pam.d/* | grep 'pam_console') ]]; then
+ /sbin/pam_console_apply -r
+fi
+
+# We need to properly terminate devfsd to save the permissions
+if [[ -n $(ps --no-heading -C 'devfsd') ]]; then
+ ebegin "Stopping devfsd"
+ killall -15 devfsd &>/dev/null
+ eend $?
+elif [[ ! -e /dev/.devfsd && -e /dev/.udev && -z ${CDBOOT} && \
+ ${RC_DEVICE_TARBALL} == "yes" ]] && \
+ touch /lib/udev-state/devices.tar.bz2 2>/dev/null
+then
+ ebegin "Saving device nodes"
+ # Handle our temp files
+ devices_udev=$(mktemp /tmp/devices.udev.XXXXXX)
+ devices_real=$(mktemp /tmp/devices.real.XXXXXX)
+ devices_totar=$(mktemp /tmp/devices.totar.XXXXXX)
+ device_tarball=$(mktemp /tmp/devices-XXXXXX)
+
+ if [[ -z ${devices_udev} || -z ${devices_real} || \
+ -z ${device_tarball} ]]; then
+ eend 1 "Could not create temporary files!"
+ else
+ cd /dev
+ # Find all devices
+ find . -xdev -type b -or -type c -or -type l | cut -d/ -f2- > \
+ "${devices_real}"
+ # Figure out what udev created
+ eval $(grep '^[[:space:]]*udev_db=' /etc/udev/udev.conf)
+ if [[ -d ${udev_db} ]]; then
+ # New udev_db is clear text ...
+ udevinfo=$(cat "${udev_db}"/*)
+ else
+ # Old one is not ...
+ udevinfo=$(udevinfo -d)
+ fi
+ # This basically strips 'S:' and 'N:' from the db output, and then
+ # print all the nodes/symlinks udev created ...
+ echo "${udevinfo}" | gawk '
+ /^(N|S):.+/ {
+ sub(/^(N|S):/, "")
+ split($0, nodes)
+ for (x in nodes)
+ print nodes[x]
+ }' > "${devices_udev}"
+ # These ones we also do not want in there
+ for x in MAKEDEV core fd initctl pts shm stderr stdin stdout; do
+ echo "${x}" >> "${devices_udev}"
+ done
+ fgrep -x -v -f "${devices_udev}" < "${devices_real}" > "${devices_totar}"
+ # Now only tarball those not created by udev if we have any
+ if [[ -s ${devices_totar} ]]; then
+ try tar --one-file-system -jcpf "${device_tarball}" -T "${devices_totar}"
+ try mv -f "${device_tarball}" /lib/udev-state/devices.tar.bz2
+ try rm -f "${devices_udev}" "${devices_real}"
+ else
+ rm -f /lib/udev-state/devices.tar.bz2
+ fi
+ eend 0
+ fi
+fi
+
+# Try to unmount all tmpfs filesystems not in use, else a deadlock may
+# occure, bug #13599.
+umount -at tmpfs &>/dev/null
+
+if [[ -n $(swapon -s 2>/dev/null) ]]; then
+ ebegin "Deactivating swap"
+ swapoff -a
+ eend $?
+fi
+
+# Write a reboot record to /var/log/wtmp before unmounting
+
+halt -w &>/dev/null
+
+# Unmounting should use /proc/mounts and work with/without devfsd running
+
+# Credits for next function to unmount loop devices, goes to:
+#
+# Miquel van Smoorenburg, <miquels@drinkel.nl.mugnet.org>
+# Modified for RHS Linux by Damien Neil
+#
+#
+# Unmount file systems, killing processes if we have to.
+# Unmount loopback stuff first
+# Use `umount -d` to detach the loopback device
+
+# Remove loopback devices started by dm-crypt
+
+remaining=$(awk '!/^#/ && $1 ~ /^\/dev\/loop/ && $2 != "/" {print $2}' /proc/mounts | \
+ sort -r | grep -v '/newroot' | grep -v '/mnt/livecd')
+[[ -n ${remaining} ]] && {
+ sig=
+ retry=3
+
+ while [[ -n ${remaining} && ${retry} -gt 0 ]]; do
+ if [[ ${retry} -lt 3 ]]; then
+ ebegin "Unmounting loopback filesystems (retry)"
+ umount -d ${remaining} &>/dev/null
+ eend $? "Failed to unmount filesystems this retry"
+ else
+ ebegin "Unmounting loopback filesystems"
+ umount -d ${remaining} &>/dev/null
+ eend $? "Failed to unmount filesystems"
+ fi
+
+ remaining=$(awk '!/^#/ && $1 ~ /^\/dev\/loop/ && $2 != "/" {print $2}' /proc/mounts | \
+ sort -r | grep -v '/newroot' | grep -v '/mnt/livecd')
+ [[ -z ${remaining} ]] && break
+
+ /bin/fuser -k -m ${sig} ${remaining} &>/dev/null
+ sleep 5
+ retry=$((${retry} - 1))
+ sig=-9
+ done
+}
+
+# Try to unmount all filesystems (no /proc,tmpfs,devfs,etc).
+# This is needed to make sure we dont have a mounted filesystem
+# on a LVM volume when shutting LVM down ...
+ebegin "Unmounting filesystems"
+unmounts=$( \
+ awk '{ \
+ if (($3 !~ /^(proc|devpts|sysfs|devfs|tmpfs|usb(dev)?fs)$/) && \
+ ($1 != "none") && \
+ ($1 !~ /^(rootfs|\/dev\/root)$/) && \
+ ($2 != "/")) \
+ print $2 }' /proc/mounts | sort -ur)
+for x in ${unmounts}; do
+ # Do not umount these if we are booting off a livecd
+ if [[ -n ${CDBOOT} ]] && \
+ [[ ${x} == "/mnt/cdrom" || ${x} == "/mnt/livecd" ]] ; then
+ continue
+ fi
+
+ x=${x//\\040/ }
+ if ! umount "${x}" &>/dev/null; then
+ # Kill processes still using this mount
+ /bin/fuser -k -m -9 "${x}" &>/dev/null
+ sleep 2
+ # Now try to unmount it again ...
+ umount -f -r "${x}" &>/dev/null
+ fi
+done
+eend 0
+
+# Try to remove any dm-crypt mappings
+stop_addon dm-crypt
+
+# Stop LVM, etc
+stop_volumes
+
+# This is a function because its used twice below
+ups_kill_power() {
+ local UPS_CTL UPS_POWERDOWN
+ 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"
+ else
+ return 0
+ 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"
+ /sbin/halt -id
+ while [ 1 ]; do sleep 60; done
+ fi
+}
+
+mount_readonly() {
+ local x=
+ local retval=0
+ local cmd=$1
+
+ # Get better results with a sync and sleep
+ sync; sync
+ sleep 1
+
+ for x in $(awk '$1 != "none" { print $2 }' /proc/mounts | sort -ur) ; do
+ x=${x//\\040/ }
+ if [[ ${cmd} == "u" ]]; then
+ umount -n -r "${x}"
+ else
+ mount -n -o remount,ro "${x}" &>/dev/null
+ fi
+ retval=$((${retval} + $?))
+ done
+ [[ ${retval} -ne 0 ]] && killall5 -9 &>/dev/null
+
+ return ${retval}
+}
+
+# Since we use `mount` in mount_readonly(), but we parse /proc/mounts, we
+# have to make sure our /etc/mtab and /proc/mounts agree
+cp /proc/mounts /etc/mtab &>/dev/null
+ebegin "Remounting remaining filesystems readonly"
+mount_worked=0
+if ! mount_readonly ; then
+ if ! mount_readonly ; then
+ # If these things really don't want to remount ro, then
+ # let's try to force them to unmount
+ if ! mount_readonly u ; then
+ mount_worked=1
+ fi
+ fi
+fi
+eend ${mount_worked}
+if [[ ${mount_worked} -eq 1 ]]; then
+ ups_kill_power
+ /sbin/sulogin -t 10 /dev/console
+fi
+
+# Inform if there is a forced or skipped fsck
+if [[ -f /fastboot ]]; then
+ echo
+ ewarn "Fsck will be skipped on next startup"
+elif [[ -f /forcefsck ]]; then
+ echo
+ ewarn "A full fsck will be forced on next startup"
+fi
+
+ups_kill_power
+
+
+# vim:ts=4
diff --git a/init.d/hostname b/init.d/hostname
new file mode 100755
index 0000000..7d10dd8
--- /dev/null
+++ b/init.d/hostname
@@ -0,0 +1,39 @@
+#!/sbin/runscript
+# Copyright 1999-2005 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+depend() {
+ need checkroot
+}
+
+start() {
+ local myhost=$(/bin/hostname 2>/dev/null)
+ local retval=0
+
+ # If the hostname is already set via the kernel, and /etc/hostname
+ # isn't setup, then we shouldn't go reseting the configuration #38172.
+ if [[ -z ${myhost} ]] || [[ ${myhost} == "(none)" ]] ; then
+ myhost="localhost"
+ fi
+
+ if [[ -f /etc/hostname ]] ; then
+ ewarn "You should stop using /etc/hostname and use /etc/conf.d/hostname"
+ myhost=$(</etc/hostname)
+ else
+ myhost=${HOSTNAME}
+ fi
+
+ ebegin "Setting hostname to ${myhost}"
+ /bin/hostname "${myhost}"
+ retval=$?
+ eend ${retval} "Failed to set the hostname"
+
+ if [[ ${retval} -eq 0 ]] ; then
+ # setup $HOSTNAME, ignore errors in case /etc is readonly.
+ echo "HOSTNAME=\"${myhost}\"" 2>/dev/null > /etc/env.d/01hostname
+ fi
+
+ return ${retval}
+}
+
+# vim:ts=4
diff --git a/init.d/keymaps b/init.d/keymaps
new file mode 100755
index 0000000..255abd2
--- /dev/null
+++ b/init.d/keymaps
@@ -0,0 +1,79 @@
+#!/sbin/runscript
+# Copyright 1999-2005 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 -qs ^KEYMAP= /etc/rc.conf ; then
+ ewarn "KEYMAP should not be set in /etc/rc.conf but in /etc/conf.d/keymaps"
+ fi
+}
+
+start() {
+ if is_uml_sys ; then
+ ebegin "Loading key mappings"
+ eend 0
+ return 0
+ fi
+
+ 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
+ if [[ ${UNICODE} == "yes" ]] ; then
+ /usr/bin/kbd_mode -u
+ fi
+
+ ebegin "Loading key mappings"
+ if [[ -x /bin/loadkeys ]] ; then
+ [[ ${SET_WINDOWKEYS} == "yes" ]] && WINDOWKEYS_KEYMAP="windowkeys"
+ /bin/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 ttydev=""
+ [[ -d /dev/vc ]] \
+ && ttydev=/dev/vc/ \
+ || ttydev=/dev/tty
+ ebegin "Setting terminal encoding to ${termmsg}"
+ for n in $(seq 1 "${RC_TTY_NUMBER}") ; do
+ echo -n -e ${termencoding} > ${ttydev}${n}
+ done
+ eend 0
+}
+
+
+# vim:ts=4
diff --git a/init.d/local b/init.d/local
new file mode 100755
index 0000000..b729e9d
--- /dev/null
+++ b/init.d/local
@@ -0,0 +1,34 @@
+#!/sbin/runscript
+# Copyright 1999-2005 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
+ source /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
+ source /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 0000000..fc49539
--- /dev/null
+++ b/init.d/localmount
@@ -0,0 +1,47 @@
+#!/sbin/runscript
+# Copyright 1999-2005 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+depend() {
+ need checkfs
+}
+
+start() {
+ # Mount local filesystems in /etc/fstab.
+ ebegin "Mounting local filesystems"
+ mount -at noproc,noshm,no${NET_FS_LIST// /,no} >/dev/null
+ eend $? "Some local filesystem failed to mount"
+
+ # Make sure we insert usbcore if its a module
+ if [[ -f /proc/modules && ! -d /proc/bus/usb ]] ; then
+ # >/dev/null to hide errors from non-USB users
+ modprobe usbcore &> /dev/null
+ fi
+
+ # Check what USB fs the kernel support. Currently
+ # 2.5+ kernels, and later 2.4 kernels have 'usbfs',
+ # while older kernels have 'usbdevfs'.
+ local usbfs=$(grep -Fow usbfs /proc/filesystems ||
+ grep -Fow usbdevfs /proc/filesystems)
+
+ if [[ -n ${usbfs} ]] && \
+ [[ -e /proc/bus/usb && ! -e /proc/bus/usb/devices ]]
+ then
+ ebegin "Mounting USB device filesystem (${usbfs})"
+ usbgid=$(awk -F: '/^usb:/{print $3; exit}' /etc/group)
+ mount -t ${usbfs} usbfs /proc/bus/usb \
+ ${usbgid:+-o devmode=0664,devgid=${usbgid}}
+ eend $? "Failed to mount USB device filesystem"
+ fi
+
+ # Swap on loopback devices, and other weirdnesses
+ ebegin "Activating (possibly) more swap"
+ /sbin/swapon -a
+ eend $?
+
+ # Start dm-crypt mappings, if any
+ start_addon dm-crypt
+}
+
+
+# vim:ts=4
diff --git a/init.d/modules b/init.d/modules
new file mode 100755
index 0000000..38e0f44
--- /dev/null
+++ b/init.d/modules
@@ -0,0 +1,122 @@
+#!/sbin/runscript
+# Copyright 1999-2005 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+depend() {
+ need checkroot hostname
+ use isapnp
+}
+
+load_modules() {
+ local x=
+ local i=0
+ local retval=0
+ local modules=
+ local modargs=
+ local modcount=0
+ local config="$1"
+
+ [[ -z ${config} || ! -r ${config} ]] && return 0
+
+ # Loop over every line in $config
+ eval $(awk '
+ BEGIN {
+ COUNT = 0 # Make sure COUNT is set
+ }
+
+ $0 !~ /(^[[:space:]]*(#|$))/ {
+ if (MODULES == "")
+ MODULES = $1
+ else
+ MODULES = MODULES " " $1
+
+ # Not the greatest method to remove $1 from $0, but it works
+ sub(/^[[:space:]]*[^[:space:]]*[[:space:]]*/, "")
+ # Trim trailing comments on the line
+ sub(/#.*$/, "")
+ ARGS[COUNT] = $0
+ COUNT++
+ }
+
+ END {
+ # 'eval' will make sure these are set to proper bash variables
+ print "modcount=" COUNT
+ print "modules=\"" MODULES "\""
+ for (x = 0;x < COUNT;x++)
+ print "modargs[" x "]=\"" ARGS[x] "\""
+ }
+ ' "${config}")
+
+ if [[ ${modcount} -gt 0 ]]; then
+ einfo "Using ${config} as config:"
+
+ for x in ${modules}; do
+ ebegin " Loading module ${x}"
+ modprobe -q ${x} ${modargs[${i}]} &>/dev/null
+ retval=$?
+ eend ${retval} " Failed to load ${x}"
+
+ i=$((i+1))
+ [[ ${retval} -eq 0 ]] || modcount=$((modcount-1))
+ done
+
+ einfo "Autoloaded ${modcount} module(s)"
+ fi
+
+ return 0
+}
+
+start() {
+ local KV=$(uname -r)
+ local KV_MAJOR=$(KV_major "${KV}")
+ local KV_MINOR=$(KV_minor "${KV}")
+ local KV_MICRO=$(KV_micro "${KV}")
+
+ # Should not fail if kernel do not have module
+ # support compiled in ...
+ [[ -f /proc/modules ]] || return 0
+
+ # 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}" ]] && [[ ! -e /etc/modules.conf ]] && \
+ [[ $(get_KV) -lt $(KV_to_int '2.5.48') || -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 || $(get_KV) -ge $(KV_to_int '2.5.48') ]]
+ then
+ /sbin/modules-update
+ fi
+
+ local autoload=""
+ if [[ -f /etc/modules.autoload && ! -L /etc/modules.autoload ]]; then
+ autoload=/etc/modules.autoload
+ else
+ local x
+ for x in "${KV}" ${KV_MAJOR}.${KV_MINOR}.${KV_MICRO} ${KV_MAJOR}.${KV_MINOR} ; do
+ if [[ -f /etc/modules.autoload.d/kernel-"${x}" ]] ; then
+ autoload="/etc/modules.autoload.d/kernel-${x}"
+ break
+ fi
+ done
+ fi
+ [[ -n ${autoload} ]] && load_modules "${autoload}"
+
+ #
+ # 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 \* &>/dev/null
+
+ # Above test clobbers the return
+ return 0
+}
+
+
+# vim:ts=4
diff --git a/init.d/net.eth0 b/init.d/net.eth0
new file mode 120000
index 0000000..3843c79
--- /dev/null
+++ b/init.d/net.eth0
@@ -0,0 +1 @@
+net.lo \ No newline at end of file
diff --git a/init.d/netmount b/init.d/netmount
new file mode 100755
index 0000000..104bfd8
--- /dev/null
+++ b/init.d/netmount
@@ -0,0 +1,93 @@
+#!/sbin/runscript
+# Copyright 1999-2005 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+depend() {
+ local myneed="net"
+ local myuse=""
+
+ # Only have Portmap as a dependency if there is a nfs mount in fstab
+ # that should be mounted at boot time. Also filter out comments.
+ local nfsmounts=$(awk '!/^#/ && ($3=="nfs" || $3=="nfs4") && $4 !~ /noauto/ { print $0 }' /etc/fstab)
+
+ if [ -n "${nfsmounts}" ]
+ then
+ myneed="${myneed} portmap"
+ myuse="${myuse} nfs nfsmount"
+ fi
+
+ need ${myneed}
+ use ${myuse}
+}
+
+start() {
+ local rcfilesystems=""
+
+ # 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 [ -L "${svcdir}/started/portmap" ]
+ then
+ rcfilesystems="${NET_FS_LIST// /,}" # convert to comma-separated
+ else
+ rcfilesystems=" ${NET_FS_LIST} "
+ rcfilesystems=${rcfilesystems// nfs /} # remove nfs
+ rcfilesystems=${rcfilesystems// nfs4 /} # remove nfs4
+ rcfilesystems=${rcfilesystems# } # remove front and
+ rcfilesystems=${rcfilesystems% } # back spaces
+ rcfilesystems=${rcfilesystems// /,} # convert to comma-separated
+ fi
+
+ ebegin "Mounting network filesystems"
+ mount -at ${rcfilesystems} >/dev/null
+
+ if [ "$?" -ne 0 ]
+ then
+ ewend 1 "Could not mount all network filesystems!"
+ else
+ eend 0
+ fi
+
+ return 0
+}
+
+stop() {
+ local ret
+ ebegin "Unmounting network filesystems"
+ [ -z "$(umount -art ${NET_FS_LIST// /,} 2>&1)" ]
+ ret=$?
+ eend ${ret} "Failed to simply unmount filesystems"
+ [ ${ret} -eq 0 ] && return 0
+
+ # `umount -a` will fail if the filesystems are in use.
+ # Here we use fuser to kill off processes that are using
+ # the filesystems so that we can unmount properly.
+ # We will gradually use harsher kill signals so that the
+ # processes know we aren't screwing around here ;).
+ declare -a siglist=( "TERM" "KILL" "KILL" )
+ local retry=0
+ local remaining="go"
+
+ while [ -n "${remaining}" -a ${retry} -lt 3 ]
+ do
+ # Populate $remaining with a newline-delimited list of network
+ # filesystems. Mount points have spaces swapped for '\040' (see
+ # fstab(5)) so we have to translate them back to spaces.
+ remaining="$(awk '$3 ~ /'${NET_FS_LIST// /|}'/ { if ($2 != "/") print $2 }' /proc/mounts | sort -r)"
+ # Since we have to worry about the spaces being quoted properly,
+ # we'll use `set --` and then "$@" to get the correct result.
+ IFS=$'\n'
+ set -- ${remaining//\\040/ }
+ unset IFS
+ [ -z "${remaining}" ] && break
+
+ # try to unmount again
+ ebegin $'\t'"Unmounting network filesystems (retry #$((retry+1)))"
+ /bin/fuser -k -${siglist[$((retry++))]} -m "$@" &>/dev/null
+ sleep 5
+ umount "$@" &>/dev/null
+ eend $? $'\t'"Failed to unmount filesystems"
+ done
+}
+
+# vim:ts=4
diff --git a/init.d/numlock b/init.d/numlock
new file mode 100755
index 0000000..22654f0
--- /dev/null
+++ b/init.d/numlock
@@ -0,0 +1,34 @@
+#!/sbin/runscript
+# Copyright 1999-2005 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+depend() {
+ need localmount
+}
+
+start() {
+ ebegin "Enabling numlock on ttys"
+ local dev
+ [[ -d /dev/vc ]] \
+ && dev=/dev/vc/ \
+ || dev=/dev/tty
+ for tty in $(seq 1 "${RC_TTY_NUMBER}") ; do
+ setleds -D +num < ${dev}${tty} &> /dev/null
+ done
+ eend $? "Failed to enable numlock"
+}
+
+stop() {
+ ebegin "Disabling numlock on ttys"
+ local dev
+ [[ -d /dev/vc ]] \
+ && dev=/dev/vc/ \
+ || dev=/dev/tty
+ for tty in $(seq 1 "${RC_TTY_NUMBER}") ; do
+ setleds -D -num < ${dev}${tty} &> /dev/null
+ done
+ eend $? "Failed to disable numlock"
+}
+
+
+# vim:ts=4
diff --git a/init.d/reboot.sh b/init.d/reboot.sh
new file mode 100755
index 0000000..fb67439
--- /dev/null
+++ b/init.d/reboot.sh
@@ -0,0 +1,8 @@
+# Copyright 1999-2005 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+/sbin/reboot -idp
+
+# hmm, if the above failed, that's kind of odd ...
+# so let's force a reboot
+/sbin/reboot -f
diff --git a/init.d/rmnologin b/init.d/rmnologin
new file mode 100755
index 0000000..559b660
--- /dev/null
+++ b/init.d/rmnologin
@@ -0,0 +1,16 @@
+#!/sbin/runscript
+# Copyright 1999-2005 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 &> /dev/null
+ fi
+}
+
+
+# vim:ts=4
diff --git a/init.d/shutdown.sh b/init.d/shutdown.sh
new file mode 100755
index 0000000..4672211
--- /dev/null
+++ b/init.d/shutdown.sh
@@ -0,0 +1,8 @@
+# Copyright 1999-2005 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+/sbin/halt -ihdp
+
+# hmm, if the above failed, that's kind of odd ...
+# so let's force a halt
+/sbin/halt -f
diff --git a/init.d/urandom b/init.d/urandom
new file mode 100755
index 0000000..368130d
--- /dev/null
+++ b/init.d/urandom
@@ -0,0 +1,37 @@
+#!/sbin/runscript
+# Copyright 1999-2005 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 &> /dev/null ; 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 &> /dev/null
+ eend $? "Error initializing random number generator"
+ umask 022
+}
+
+stop() {
+ [[ -n ${CDBOOT} ]] && return 0
+
+ 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 &> /dev/null
+ eend $? "Failed to save random seed"
+}
+
+
+# vim:ts=4
diff --git a/lib/rcscripts/net.modules.d/adsl b/lib/rcscripts/net.modules.d/adsl
new file mode 100644
index 0000000..87bf6ab
--- /dev/null
+++ b/lib/rcscripts/net.modules.d/adsl
@@ -0,0 +1,101 @@
+#!/bin/bash
+# Copyright (c) 2004-2005 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+# Contributed by Roy Marples (uberlord@gentoo.org)
+
+# char* adsl_provides(void)
+#
+# Returns a string to change module definition for starting up
+adsl_provides() {
+ echo "adsl"
+}
+
+# void adsl_depend(void)
+#
+# Sets up the dependancies for the module
+adsl_depend() {
+ after interface
+ before dhcp
+}
+
+# bool adsl_check_installed(void)
+#
+# Returns 1 if rp-pppoe is installed, otherwise 0
+adsl_check_installed() {
+ [[ -x /usr/sbin/adsl-start ]] && return 0
+ ${1:-false} && eerror "For ADSL support, emerge net-dialup/rp-pppoe"
+ return 1
+}
+
+# bool adsl_check_depends(void)
+#
+# Checks to see if we have the needed functions
+adsl_check_depends() {
+ return 0
+}
+
+# bool adsl_setup_vars(char *iface)
+#
+# Checks to see if the ADSL script has been created or not
+adsl_setup_vars() {
+ local iface="$1"
+
+ # 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 adsl-setup to create one"
+ return 1
+ fi
+
+ return 0
+}
+
+# bool adsl_start(char *iface)
+#
+# Start ADSL on an interface by calling adsl-start
+#
+# Returns 0 (true) when successful, non-zero otherwise
+adsl_start() {
+ local iface="$1" user ifvar=$( bash_variable "$1" ) cfgfile
+
+ adsl_setup_vars "${iface}" || 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}"
+ /usr/sbin/adsl-start <(cat "${cfgfile}"; \
+ echo "ETH=${iface}"; \
+ echo "PIDFILE=/var/run/adsl-${iface}.pid"; \
+ [[ -n ${user} ]] && echo "USER=${user}") \
+ >/dev/null
+ eend $?
+}
+
+# bool adsl_stop(char *iface)
+#
+# Stop ADSL on an interface by calling adsl-stop
+# Returns 0 when there is no ADSL to stop or we stop ADSL successfully
+# Otherwise 1
+adsl_stop() {
+ local iface="$1" cfgfile
+
+ adsl_check_installed || return 0
+ [[ ! -f "/var/run/adsl-${iface}.pid" ]] && return 0
+
+ adsl_setup_vars "${iface}" || return 0
+
+ einfo "Stopping ADSL for ${iface}"
+ /usr/sbin/adsl-stop <(cat "${cfgfile}"; \
+ echo "ETH=${iface}"; echo "PIDFILE=/var/run/adsl-${iface}.pid") \
+ >/dev/null
+ eend $?
+}
+
+# vim:ts=4
diff --git a/lib/rcscripts/net.modules.d/apipa b/lib/rcscripts/net.modules.d/apipa
new file mode 100644
index 0000000..cd61ebb
--- /dev/null
+++ b/lib/rcscripts/net.modules.d/apipa
@@ -0,0 +1,105 @@
+#!/bin/bash
+# Copyright (c) 2004-2005 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+# Contributed by Roy Marples (uberlord@gentoo.org)
+
+# char* apipa_provides(void)
+#
+# Returns a string to change module definition for starting up
+apipa_provides() {
+ echo "apipa"
+}
+
+# void apipa_depend(void)
+#
+# Sets up the dependancies for the module
+apipa_depend() {
+ after system dhcp vlan
+}
+
+# bool apipa_check_installed(void)
+#
+# Returns 1 if ifenslave is installed, otherwise 0
+apipa_check_installed() {
+ [[ -x /sbin/arping || -x /usr/sbin/arping2 ]] && return 0
+ if ${1:-false}; then
+ eerror "For Automatic Private IP Addressing (APIPA) support"
+ eerror "emerge net-misc/iputils or net-analyzer/arping"
+ fi
+ return 1
+}
+
+# bool apipa_check_depends(void)
+#
+# Checks to see if we have the needed functions
+apipa_check_depends() {
+ local f
+
+ for f in interface_exists interface_up; do
+ [[ $( type -t "${f}" ) == "function" ]] && continue
+ eerror "apipa: missing required function ${f}\n"
+ return 1
+ done
+
+ return 0
+}
+
+# bool address_exists(char *interface, char *address)
+#
+# Returns 0 if the address on the interface responds to an arping
+# 1 if not - packets defaults to 1
+# If neither arping (net-misc/iputils) or arping2 (net-analyzer/arping)
+# is installed then we return 1
+address_exists() {
+ local iface="$1" address="${2%%/*}" i
+
+ # We only handle IPv4 addresses
+ [[ ${address} != *.*.*.* ]] && return 1
+
+ # We need to bring the interface up to test
+ interface_up "${iface}"
+
+ if [[ -x /sbin/arping ]]; then
+ /sbin/arping -q -c 2 -w 3 -D -f -I "${iface}" "${address}" \
+ &>/dev/null || return 0
+ elif [[ -x /usr/sbin/arping2 ]]; then
+ for (( i=0; i<3; i++ )); do
+ /usr/sbin/arping2 -0 -c 1 -i "${iface}" "${address}" \
+ &>/dev/null && return 0
+ done
+ fi
+ return 1
+}
+
+# bool apipa_start(char *iface)
+#
+# Tries to locate an address in the 169.254.0.0 netmask 169.254.255.255 range
+apipa_start() {
+ local iface="$1" i1 i2 addr i=0
+
+ interface_exists "${iface}" true || return 1
+
+ ebegin "Searching for free addresses"
+ interface_up "${iface}"
+
+ while [[ ${i} -lt 64516 ]]; do
+ (( i1=${RANDOM}%255 ))
+ (( i2=${RANDOM}%255 ))
+
+ addr="169.254.${i1}.${i2}"
+ if ! address_exists "${iface}" "${addr}" ; then
+ config[config_counter]="${addr}/16 broadcast 169.254.255.255"
+ (( config_counter-- ))
+ eend 0
+ return 0
+ fi
+
+ (( i++ ))
+ done
+
+ eend 1 "No free address found!"
+ return 1
+}
+
+# vim:ts=4
diff --git a/lib/rcscripts/net.modules.d/bonding b/lib/rcscripts/net.modules.d/bonding
new file mode 100644
index 0000000..68df44a
--- /dev/null
+++ b/lib/rcscripts/net.modules.d/bonding
@@ -0,0 +1,125 @@
+#!/bin/bash
+# Copyright (c) 2004-2005 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+# Contributed by Roy Marples (uberlord@gentoo.org)
+
+# char* bonding_provides(void)
+#
+# Returns a string to change module definition for starting up
+bonding_provides() {
+ echo "bonding"
+}
+
+# void bonding_depend(void)
+#
+# Sets up the dependancies for the module
+bonding_depend() {
+ after interface
+ before vlan dhcp apipa
+}
+
+# bool bonding_check_installed(void)
+#
+# Returns 1 if ifenslave is installed, otherwise 0
+bonding_check_installed() {
+ [[ -x /sbin/ifenslave ]] && return 0
+ ${1:-false} && eerror "For link aggregation (bonding) support, emerge net-misc/ifenslave"
+ return 1
+}
+
+# bool bonding_check_depends(void)
+#
+# Checks to see if we have the needed functions
+bonding_check_depends() {
+ local f
+
+ for f in interface_exists interface_up interface_down interface_del_addresses; do
+ [[ $( type -t "${f}" ) == "function" ]] && continue
+ eerror "bonding: missing required function ${f}\n"
+ return 1
+ done
+
+ return 0
+}
+
+# bool bonding_post_start(char *iface)
+#
+# Bonds the interface
+bonding_pre_start() {
+ local iface="$1" slaves s ifvar=$( bash_variable "$1" )
+
+ eval slaves=\"\$\{slaves_${ifvar}\[@\]\}\"
+ [[ -z ${slaves} ]] && return 0
+
+ interface_exists "${iface}" true || return 1
+
+ if [[ ! -f "/proc/net/bonding/${iface}" ]]; then
+ eerror "${iface} is not capable of bonding"
+ return 1
+ fi
+
+ ebegin "Adding slaves to ${iface}"
+ eindent
+ einfo "${slaves}"
+
+ # Check that our slaves exist
+ for s in ${slaves}; do
+ interface_exists "${s}" && continue
+ ewarn "interface ${s} does not exist"
+ return 1
+ done
+
+ # Must force the slaves to a particular state before adding them
+ for s in ${slaves}; do
+ interface_del_addresses "${s}"
+ interface_up "${s}"
+ done
+
+ # now force the master to up
+ interface_up "${iface}"
+
+ # finally add in slaves
+ eoutdent
+ /sbin/ifenslave "${iface}" ${slaves} >/dev/null
+ eend $?
+
+ return 0 #important
+}
+
+# bool bonding_pre_stop(void)
+# Unbonds bonded interfaces
+#
+# Always returns 0 (true)
+bonding_pre_stop() {
+ local iface="$1" slaves s
+
+ bonding_check_installed || return 0
+
+ # return silently if this is not a bonding interface
+ [[ ! -f "/proc/net/bonding/${iface}" ]] && return 0
+
+ # don't trust the config, get the active list instead
+ slaves=$( sed -n -e 's/^Slave Interface: //p' "/proc/net/bonding/${iface}" )
+ [[ -z ${slaves} ]] && return 0
+
+ # remove all slaves
+ ebegin "Removing slaves from ${iface}"
+ eindent
+ einfo "${slaves}"
+ eoutdent
+ /sbin/ifenslave -d "${iface}" ${slaves} &>${devnull}
+
+ # reset all slaves
+ for s in ${slaves}; do
+ if interface_exists "${s}" ; then
+ interface_del_addresses "${s}"
+ interface_down "${s}"
+ fi
+ done
+
+ eend 0
+ return 0
+}
+
+# vim:ts=4
diff --git a/lib/rcscripts/net.modules.d/bridge b/lib/rcscripts/net.modules.d/bridge
new file mode 100644
index 0000000..612ca5b
--- /dev/null
+++ b/lib/rcscripts/net.modules.d/bridge
@@ -0,0 +1,227 @@
+#!/bin/bash
+# Copyright (c) 2004-2005 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+# Contributed by Roy Marples (uberlord@gentoo.org)
+
+# Fix any potential localisation problems
+# Note that LC_ALL trumps LC_anything_else according to locale(7)
+brctl() {
+ LC_ALL=C /sbin/brctl "$@"
+}
+
+# char* bridge_provides(void)
+#
+# Returns a string to change module definition for starting up
+bridge_provides() {
+ echo "bridge"
+}
+
+# void bridge_depend(void)
+#
+# Sets up the dependancies for the module
+bridge_depend() {
+ after interface tuntap
+ before dhcp apipa
+}
+
+# bool bridge_check_installed(void)
+#
+# Returns 1 if bridge is installed, otherwise 0
+bridge_check_installed() {
+ [[ -x /sbin/brctl ]] && return 0
+ ${1:-false} && eerror "For bridge support, emerge net-misc/bridge-utils"
+ return 1
+}
+
+# bool bridge_check_depends(void)
+#
+# Checks to see if we have the needed functions
+bridge_check_depends() {
+ local f
+
+ for f in interface_down interface_del_addresses interface_set_flag; do
+ [[ $( type -t "${f}" ) == "function" ]] && continue
+ eerror "bridge: missing required function ${f}\n"
+ return 1
+ done
+
+ return 0
+}
+
+# char* bridge_get_vars(char *interface)
+#
+# Returns a string spaced with possible user set
+# configuration variables
+bridge_get_vars() {
+ echo "bridge_$1 brctl_$1"
+}
+
+# char* bridge_get_ports(char *interface)
+#
+# Returns the interfaces added to the given bridge
+bridge_get_ports() {
+ brctl show 2>/dev/null \
+ | sed -n -e '/^'"$1"'/,/^\S/ { /^\('"$1"'\|\t\)/s/^.*\t//p }'
+}
+
+# char* bridge_get_bridge(char *interface)
+#
+# Returns the bridge interface of the given interface
+bridge_get_bridge() {
+ local x=$( brctl show 2>/dev/null \
+ | sed -e '1 {d}; /^[^ ]/ { N }; /.*'"$1"'.*/ {s/^\([^ \t]\+\).*/\1/p}; d' )
+
+ local -a a=( ${x} )
+ if [[ ${#a[@]} == "1" ]]; then
+ echo "${x}"
+ elif [[ $1 == "${a[3]}" ]]; then
+ echo "${a[0]}"
+ fi
+}
+
+# bool bridge_exists(char *interface)
+#
+# Returns 0 if the bridge exists, otherwise 1
+bridge_exists() {
+ brctl show 2>/dev/null | grep -q "^$1"
+}
+
+# bool bridge_create(char *interface)
+#
+# Creates the bridge - no ports are added here though
+# Returns 0 on success otherwise 1
+bridge_create() {
+ local iface="$1" ifvar=$( bash_variable "$1" ) x i
+ local -a opts
+
+ ebegin "Creating bridge ${iface}"
+ x=$( brctl addbr "${iface}" 2>&1 )
+ if [[ -n ${x} ]]; then
+ if [[ ${x} == "br_add_bridge: Package not installed" ]]; then
+ eend 1 "Bridging (802.1d) support is not present in this kernel"
+ else
+ eend 1 "${x}"
+ fi
+ return 1
+ fi
+
+ eval opts=( \"\$\{brctl_${ifvar}\[@\]\}\" )
+ for (( i=0; i<${#opts[@]}; i++ )); do
+ x="${opts[i]/ / ${iface} }"
+ [[ ${x} == "${opts[i]}" ]] && x="${x} ${iface}"
+ x=$( brctl ${x} 2>&1 1>/dev/null )
+ [[ -n ${x} ]] && ewarn "${x}"
+ done
+ eend 0
+}
+
+# bool bridge_add_port(char *interface, char *port)
+#
+# Adds the port to the bridge
+bridge_add_port() {
+ local iface="$1" port="$2" e
+
+ interface_set_flag "${port}" promisc true
+ interface_up "${port}"
+ e=$( brctl addif "${iface}" "${port}" 2>&1 )
+ if [[ -n ${e} ]]; then
+ interface_set_flag "${port}" promisc false
+ echo "${e}" >&2
+ return 1
+ fi
+ return 0
+}
+
+# bool bridge_delete_port(char *interface, char *port)
+#
+# Deletes a port from a bridge
+bridge_delete_port() {
+ interface_set_flag "$2" promisc false
+ brctl delif "$1" "$2"
+}
+
+# bool bridge_start(char *iface)
+#
+# set up bridge
+# This can also be called by non-bridges so that the bridge can be created
+# dynamically
+bridge_pre_start() {
+ local iface="$1" ports briface i ifvar=$( bash_variable "$1" ) opts
+ eval ports=\"\$\{bridge_${ifvar}\[@\]\}\"
+ eval briface=\"\$\{bridge_add_${ifvar}\}\"
+ eval opts=\"\$\{brctl_${ifvar}\}\"
+
+ [[ -z ${ports} && -z ${briface} && -z ${opts} ]] && return 0
+
+ # Destroy the bridge if it exists
+ [[ -n ${ports} ]] && bridge_stop "${iface}"
+
+ # Allow ourselves to add to the bridge
+ if [[ -z ${ports} && -n ${briface} ]]; then
+ ports="${iface}"
+ iface="${briface}"
+ fi
+
+ # Create the bridge if needed
+ bridge_exists "${iface}" || bridge_create "${iface}"
+
+ if [[ -n ${ports} ]]; then
+ einfo "Adding ports to ${iface}"
+ eindent
+
+ for i in ${ports}; do
+ interface_exists "${i}" && continue
+ eerror "interface ${i} does not exist"
+ return 1
+ done
+
+ for i in ${ports}; do
+ ebegin "${i}"
+ bridge_add_port "${iface}" "${i}"
+ eend $? || return 1
+ done
+ eoutdent
+ fi
+
+ return 0
+}
+
+# bool bridge_stop(char *iface)
+#
+# Removes the device
+# returns 0
+bridge_stop() {
+ bridge_check_installed || return 0
+
+ local iface="$1" ports i deletebridge=false extra=""
+
+ if bridge_exists "${iface}" ; then
+ ebegin "Destroying bridge ${iface}"
+ interface_down "${iface}"
+ ports=$( bridge_get_ports "${iface}" )
+ deletebridge=true
+ eindent
+ else
+ # Work out if we're added to a bridge for removal or not
+ ports="${iface}"
+ iface=$( bridge_get_bridge "${iface}" )
+ [[ -z ${iface} ]] && return 0
+ extra=" from ${iface}"
+ fi
+
+ for i in ${ports}; do
+ ebegin "Removing port ${i}${extra}"
+ bridge_delete_port "${iface}" "${i}"
+ eend $?
+ done
+
+ if ${deletebridge} ; then
+ eoutdent
+ brctl delbr "${iface}" &>/dev/null
+ eend 0
+ fi
+ return 0
+}
+
+# vim:ts=4
diff --git a/lib/rcscripts/net.modules.d/dhclient b/lib/rcscripts/net.modules.d/dhclient
new file mode 100644
index 0000000..6d31321
--- /dev/null
+++ b/lib/rcscripts/net.modules.d/dhclient
@@ -0,0 +1,196 @@
+#!/bin/bash
+# Copyright (c) 2004-2005 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+# Contributed by Roy Marples (uberlord@gentoo.org)
+
+# Fix any potential localisation problems
+# Note that LC_ALL trumps LC_anything_else according to locale(7)
+dhclient() {
+ LC_ALL=C /sbin/dhclient "$@"
+}
+
+# char* dhclient_provides(void)
+#
+# Returns a string to change module definition for starting up
+dhclient_provides() {
+ echo "dhcp"
+}
+
+# void dhclient_depend(void)
+#
+# Sets up the dependancies for the module
+dhclient_depend() {
+ after interface
+}
+
+# bool dhclient_check_installed(void)
+#
+# Returns 1 if dhclient is installed, otherwise 0
+dhclient_check_installed() {
+ [[ -x /sbin/dhclient ]] && return 0
+ ${1:-false} && eerror "For DHCP (dhclient) support, emerge net-misc/dhcp"
+ return 1
+}
+
+# bool dhclient_check_depends(void)
+#
+# Checks to see if we have the needed functions
+dhclient_check_depends() {
+ local f
+
+ for f in interface_exists interface_get_address; do
+ [[ $( type -t "${f}" ) == "function" ]] && continue
+ eerror "dhclient: missing required function ${f}\n"
+ return 1
+ done
+
+ return 0
+}
+
+# char* dhclient_get_vars(char *interface)
+#
+# Returns a string spaced with possible user set
+# configuration variables
+dhclient_get_vars() {
+ echo "dhclient_$1 dhcp_$1"
+}
+
+# bool dhclient_stop(char *iface)
+#
+# Stop dhclient on an interface
+# Always returns 0
+dhclient_stop() {
+ local iface="$1" d
+ local pidfile="/var/run/dhclient-${iface}.pid"
+
+ dhclient_check_installed || return 0
+ [[ ! -f ${pidfile} ]] && return 0
+
+ # We check for a dhclient process first as if we attempt to release
+ # an interface for which dhclient has obtained an IP in the past
+ # it causes a "RELEASE" event anyway.
+ local pid=$( < "${pidfile}" )
+
+ local ifvar=$( bash_variable "${iface}" )
+ eval d=\" \$\{dhcp_${ifvar}\} \"
+ [[ ${d} == " " ]] && d=" ${dhcp} "
+
+ ebegin "Stopping dhclient on ${iface}"
+ if [[ ${d} == *" release "* ]]; then
+ local r=$( dhclient -q -r -pf "${pidfile}" \
+ -sf "${MODULES_DIR}/helpers.d/dhclient-wrapper" "${iface}" )
+ [[ ${r} == "deconfig" ]]
+ eend $? "dhclient returned a ${r}"
+ [[ -f "/var/cache/dhcp-${iface}.lease" ]] \
+ && rm -f "/var/cache/dhcp-${iface}.lease"
+ else
+ kill -s TERM "${pid}" 2>/dev/null
+ clean_pidfile "${pidfile}"
+ eend 0
+ fi
+
+ return 0
+}
+
+# bool dhclient_start(char *iface)
+#
+# Start DHCP on an interface by calling dhclient $iface $options
+#
+# Returns 0 (true) when a DHCP address is obtained, otherwise 1
+dhclient_start() {
+ local iface="$1" opts ifvar=$( bash_variable "$1" )
+ local pidfile="/var/run/dhclient-${iface}.pid" edit=""
+ local cffile="/etc/dhcp/dhclient.conf"
+ local d
+
+ interface_exists "${iface}" true || return 1
+
+ eval edit=\"\$\{dhclient_edit_config_${ifvar}\}\"
+ [[ -z ${edit} ]] && eval edit="${dhclient_edit_config:-no}"
+ if [[ ${edit} == "yes" || ${edit} == "true" ]]; then
+ edit=true
+ else
+ edit=false
+ fi
+
+ # Load our options
+ eval opts=\" \$\{dhclient_${ifvar}\} \"
+
+ # Work out our cffile
+ x="${opts##* -cf }"
+ if [[ ${x} != "${opts}" ]]; then
+ x="${x%% *}"
+ if [[ -n ${x} ]]; then
+ cffile="${x}"
+ opts="${opts//-cf ${cffile}/}"
+ fi
+ fi
+ opts="${opts} -cf ${cffile}"
+
+ # Ensure that the cffile does not contain any script lines
+ # as that will stop our helpers from running
+ if [[ -e ${cffile} ]] ; then
+ if grep -q "^[ \t]*script " "${cffile}" 2>/dev/null ; then
+ if ${edit} ; then
+ sed -i '/^[ \t]*script /d' "${cffile}" || return 1
+ else
+ eerror "You have to remove the script parameter from ${cffile}"
+ return 1
+ fi
+ fi
+ else
+ ${edit} && touch "${cffile}" 2>/dev/null
+ fi
+
+ eval d=\" \$\{dhcp_${ifvar}\} \"
+ [[ ${d} == " " ]] && d=" ${dhcp} "
+
+ # Send our hostname by editing cffile
+ if ${edit} && [[ -e ${cffile} && ${d} != *" nosendhost "* ]] ; then
+ local hostname=$( hostname )
+ if [[ ${hostname} != "(none)" && ${hostname} != "localhost" ]]; then
+ sed -i '/^[ \t]*send[ \t]*host-name[ \t]*/d' "${cffile}"
+ if [[ -s ${cffile} ]]; then
+ sed -i '1 isend host-name "'"${hostname}"'";' "${cffile}"
+ else
+ echo "send host-name \"${hostname}\";" > "${cffile}"
+ fi
+ fi
+ fi
+
+ # Bring up DHCP for this interface (or alias)
+ ebegin "Running dhclient"
+
+ # Stop dhclient if it's already running
+ dhclient_stop "${iface}"
+
+ if [[ ${background} == "yes" ]]; then
+ eval dhclient ${opts} -pf "${pidfile}" -q \
+ -sf "${MODULES_DIR}/helpers.d/dhclient-wrapper" \
+ "${iface}" &>/dev/null &
+ eend 0
+ go_background
+ fi
+
+ local x=$( eval dhclient ${opts} -1 -pf "${pidfile}" \
+ -sf "${MODULES_DIR}/helpers.d/dhclient-wrapper" -q "${iface}" 2>&1 )
+ # We just check the last 5 letters
+ [[ ${x:${#x} - 5:5} == "bound" ]]
+ if [[ $? != "0" ]]; then
+ echo "${x}"
+ # We need to kill the process if we fail
+ [[ -e ${pidfile} ]] && kill -s TERM $( < "${pidfile}" ) 2>/dev/null
+ eend 1
+ return 1
+ fi
+ eend 0
+
+ # DHCP succeeded, show address retrieved
+ local addr=$( interface_get_address "${iface}" )
+ einfo "${iface} received address ${addr}"
+
+ return 0
+}
+
+# vim:ts=4
diff --git a/lib/rcscripts/net.modules.d/dhcpcd b/lib/rcscripts/net.modules.d/dhcpcd
new file mode 100644
index 0000000..25e3069
--- /dev/null
+++ b/lib/rcscripts/net.modules.d/dhcpcd
@@ -0,0 +1,166 @@
+#!/bin/bash
+# Copyright (c) 2004-2005 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+# Contributed by Roy Marples (uberlord@gentoo.org)
+
+# Fix any potential localisation problems
+# Note that LC_ALL trumps LC_anything_else according to locale(7)
+dhcpcd() {
+ LC_ALL=C /sbin/dhcpcd "$@"
+}
+
+# char* dhcpcd_provides(void)
+#
+# Returns a string to change module definition for starting up
+dhcpcd_provides() {
+ echo "dhcp"
+}
+
+# void dhcpcd_depend(void)
+#
+# Sets up the dependancies for the module
+dhcpcd_depend() {
+ after interface
+}
+
+# bool dhcpcd_check_installed(void)
+#
+# Returns 1 if dhcpcd is installed, otherwise 0
+dhcpcd_check_installed() {
+ if [[ -x /sbin/dhcpcd ]]; then
+ if dhcpcd -h 2>&1 | grep -q "etcDir" ; then
+ return 0
+ else
+ ${1:-false} && eerror "We require dhcpcd-1.3.22_p4-r12 or newer"
+ return 1
+ fi
+ fi
+
+ ${1:-false} && eerror "For DHCP (dhcpcd) support, emerge net-misc/dhcpcd"
+ return 1
+}
+
+# bool dhcpcd_check_depends(void)
+#
+# Checks to see if we have the needed functions
+dhcpcd_check_depends() {
+ local f
+
+ for f in interface_exists interface_get_address; do
+ [[ $( type -t "${f}" ) == "function" ]] && continue
+ eerror "dhcpcd: missing required function ${f}\n"
+ return 1
+ done
+
+ return 0
+}
+
+# char* dhcpcd_get_vars(char *interface)
+#
+# Returns a string spaced with possible user set
+# configuration variables
+dhcpcd_get_vars() {
+ echo "dhcpcd_$1 dhcp_$1"
+}
+
+# bool dhcpcd_stop(char *iface)
+#
+# Stop DHCP on an interface by calling dhcpcd -z $iface
+#
+# Returns 0 (true) when a DHCP address dropped
+# otherwise return 1
+dhcpcd_stop() {
+ local iface=$1 count signal pidfile="/var/run/dhcpcd-$1.pid" d
+
+ dhcpcd_check_installed || return 0
+
+ [[ ! -f ${pidfile} ]] && return 0
+
+ ebegin "Stopping dhcpcd on ${iface}"
+ local pid=$( < "${pidfile}" )
+
+ local ifvar=$( bash_variable "${iface}" )
+ eval d=\" \$\{dhcp_${ifvar}\} \"
+ [[ ${d} == " " ]] && d=" ${dhcp} "
+
+ if [[ ${d} == *" release "* ]]; then
+ signal="HUP"
+ else
+ signal="TERM"
+ fi
+
+ kill -s "${signal}" "${pid}" &>/dev/null
+ process_finished "${pid}" dhcpcd
+ eend $? "timed out"
+ return $?
+}
+
+# bool dhcpcd_start(char *iface)
+#
+# Start DHCP on an interface by calling dhcpcd $iface $options
+#
+# Returns 0 (true) when a DHCP address is obtained, otherwise 1
+dhcpcd_start() {
+ local iface="$1" opts hostname pidfile="/var/run/dhcpcd-$1.pid"
+ local ifvar=$( bash_variable "${iface}" ) metric d
+
+ interface_exists "${iface}" true || return 1
+
+ # Get our options
+ eval opts=\" \$\{dhcpcd_${ifvar}\} \"
+
+ # Map some generic options to dhcpcd
+ eval d=\" \$\{dhcp_${ifvar}\} \"
+ [[ ${d} == " " ]] && d=" ${dhcp} "
+ [[ ${d} == *" nodns "* ]] && opts="${opts} -R"
+ [[ ${d} == *" nontp "* ]] && opts="${opts} -N"
+ [[ ${d} == *" nonis "* ]] && opts="${opts} -Y"
+ [[ ${d} == *" nogateway "* ]] && opts="${opts} -G"
+
+ # We transmit the hostname by default
+ if [[ ${d} != *" nosendhost "* && ${opts} != *" -h "* ]]; then
+ hostname=$( hostname )
+ [[ -n ${hostname} && ${hostname} != "(none)" \
+ && ${hostname} != "localhost" ]] \
+ && opts="-h \"${hostname}\" ${opts}"
+ fi
+
+ # Stop dhcpcd from bringing the interface down when we exit
+ opts="${opts} -o"
+
+ # Add our route metric
+ eval metric=\"\$\{metric_${ifvar}\}\"
+ [[ -n ${metric} ]] && opts="${opts} -m ${metric}"
+
+ # Instruct dhcpcd to use our wrapper
+ opts="${opts} -c \"/lib/rcscripts/net.modules.d/helpers.d/dhcpcd-wrapper\""
+
+ # Instruct dhcpcd to create it's files in our state dir
+ opts="${opts} -e \"${statedir}/${iface}\""
+
+ # Bring up DHCP for this interface (or alias)
+ ebegin "Running dhcpcd"
+
+ # Halt any existing dhcpcd process
+ dhcpcd_stop "${iface}"
+
+ [[ ! -d "${statedir}/${iface}" ]] && mkdir -m 0755 -p "${statedir}/${iface}"
+
+ if [[ ${background} == "yes" ]]; then
+ eval dhcpcd ${opts} ${iface} &
+ eend 0
+ go_background
+ fi
+
+ eval dhcpcd ${opts} ${iface}
+ eend $? || return 1
+
+ # DHCP succeeded, show address retrieved
+ local addr=$( interface_get_address "${iface}" )
+ einfo "${iface} received address ${addr}"
+
+ return 0
+}
+
+# vim:ts=4
diff --git a/lib/rcscripts/net.modules.d/essidnet b/lib/rcscripts/net.modules.d/essidnet
new file mode 100644
index 0000000..967776b
--- /dev/null
+++ b/lib/rcscripts/net.modules.d/essidnet
@@ -0,0 +1,79 @@
+#!/bin/bash
+# Copyright (c) 2004-2005 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+# Contributed by Roy Marples (uberlord@gentoo.org)
+# 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
+
+# Load our config if it exists
+[[ -f $(add_suffix "/etc/conf.d/wireless" ) ]] \
+&& source $(add_suffix "/etc/conf.d/wireless" )
+
+# void essidnet_depend(void)
+#
+# Sets up the dependancies for the module
+essidnet_depend() {
+ before interface
+ after wireless
+ installed wireless
+}
+
+# bool essidnet_check_installed(void)
+#
+# Always returns 0 as we are "installed" by wireless in the depend function
+essidnet_check_installed() {
+ return 0
+}
+
+# char* essidnet_provides(void)
+#
+# Returns a string to change module definition for starting up
+essidnet_provides() {
+ echo "essidnet"
+}
+
+# bool essidnet_check_depends(void)
+#
+# Checks to see if we have the needed functions
+essidnet_check_depends() {
+ local f
+
+ for f in wireless_check_extensions wireless_get_essid wireless_get_ap_mac_address; do
+ [[ $( type -t "${f}" ) == "function" ]] && continue
+ eerror "essidnet: missing required function ${f}\n"
+ return 1
+ done
+
+ return 0
+}
+
+# bool essidnet_start(char *iface)
+#
+# All interfaces and module scripts expose modulename_get_vars
+# which returns a space seperated list of user configuration variables
+# We can override each variable here from a given ESSID or the MAC
+# of the AP connected to. MAC configuration takes precedence
+# Always returns 0
+essidnet_pre_start() {
+ local iface="$1"
+
+ wireless_check_extensions "${iface}" || return 0
+
+ local mac=$( wireless_get_ap_mac_address "${iface}" )
+ local ESSID=$( wireless_get_essid "${iface}" )
+ local essid=$( bash_variable ${ESSID} )
+ mac="${mac//:/}"
+
+ vebegin "Configuring ${iface} for ESSID \"${ESSID//\\\\/\\\\}\"" 2>/dev/null
+ configure_variables "${iface}" "${essid}" "${mac}"
+
+ # Backwards compat for old gateway var
+ eval x=\"\$\{gateway_${essid}\}\"
+ [[ -n ${x} ]] && gateway="${iface}/${x}"
+
+ veend 0 2>/dev/null
+ return 0
+}
+
+# vim:ts=4
diff --git a/lib/rcscripts/net.modules.d/helpers.d/dhclient-wrapper b/lib/rcscripts/net.modules.d/helpers.d/dhclient-wrapper
new file mode 100755
index 0000000..075229d
--- /dev/null
+++ b/lib/rcscripts/net.modules.d/helpers.d/dhclient-wrapper
@@ -0,0 +1,45 @@
+#!/bin/bash
+# Copyright (c) 2004-2005 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+# Contributed by Roy Marples (uberlord@gentoo.org)
+
+# Instead of writing new functions for dhclient, we simply map their variables
+# over to udhcpc style ones and call those scripts!
+
+case "${reason}" in
+ BOUND|REBOOT|REBIND) action="bound" ;;
+ RENEW) action="renew" ;;
+ RELEASE|PREINIT|FAIL|EXPIRE|TIMEOUT) action="deconfig" ;;
+ MEDIUM) exit 0 ;;
+esac
+
+if [[ -z ${action} ]]; then
+ echo "dhclient sent an unknown action ${reason}!" >&2
+ exit 1
+fi
+
+export ip="${new_ip_address}"
+export subnet="${new_subnet_mask}"
+export broadcast="${new_broadcast_address}"
+export routers="${new_routers}"
+
+export hostname="${new_host_name}"
+
+export dns_domain_${interface}="${new_domain_name}"
+export dns_servers_${interface}="${new_domain_name_servers}"
+
+export ntp_servers_${interface}="${new_domain_name_servers}"
+
+export nis_domain_${interface}="${new_nis_domain}"
+export nis_servers_${interface}="${new_nis_servers}"
+
+/lib/rcscripts/net.modules.d/helpers.d/dhcp "${action}"
+result="$?"
+
+[[ -e /etc/dhcp/dhclient-exit-hooks ]] \
+&& ( . /etc/dhcp/dhclient-exit-hooks )
+
+exit "${result}"
+
+# vim:ts=4
diff --git a/lib/rcscripts/net.modules.d/helpers.d/dhcp b/lib/rcscripts/net.modules.d/helpers.d/dhcp
new file mode 100755
index 0000000..3996c1a
--- /dev/null
+++ b/lib/rcscripts/net.modules.d/helpers.d/dhcp
@@ -0,0 +1,130 @@
+#!/bin/bash
+# Copyright (c) 2004-2005 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+# Contributed by Roy Marples (uberlord@gentoo.org)
+
+action="$1"
+service="net.${interface}"
+
+. /lib/rcscripts/net.modules.d/helpers.d/module-loader
+
+# Bring the interface up
+interface_is_up "${interface}" || interface_up "${interface}"
+
+case "${action}" in
+ bound|renew)
+ # We handle these actions below
+ ;;
+ deconfig)
+ # Just remove IPv4 / inet addresses
+ interface_del_addresses "${interface}" true
+ if service_starting "${service}" || service_started "${service}" ; then
+ mark_service_inactive "net.${interface}"
+ fi
+ remove_state "${interface}"
+ if [[ ${RC_AUTO_INTERFACE} == "yes" ]]; then
+ best_interface=$( select_best_interface )
+ apply_state "${best_interface}"
+ fi
+ echo "${action}"
+ exit 0
+ ;;
+ nak)
+ echo "${action}"
+ exit 0
+ ;;
+ leasefail)
+ if service_starting "${service}" || service_started "${service}" ; then
+ mark_service_inactive "net.${interface}"
+ fi
+ echo "${action}"
+ exit 0
+ ;;
+ *)
+ echo "${action}"
+ echo "We don't handle that action" >&2
+ exit 1
+ ;;
+esac
+
+# Map MAC address variables to interface variables
+macnet_pre_start "${interface}" 1>/dev/null
+
+# Map wireless ESSID variables to interface variables
+if [[ -n ${wireless_module} ]]; then
+ if wireless_check_extensions "${interface}" ; then
+ essidnet_pre_start "${interface}" 1>/dev/null
+ fi
+fi
+
+# Calculate the metric for our routes
+ifvar=$( bash_variable "${interface}" )
+eval metric=\"\$\{metric_${ifvar}\}\"
+if [[ -z ${metric} ]]; then
+ if [[ ${RC_AUTO_INTERFACE} == "yes" ]]; then
+ metric=$( calculate_metric "${interface}" )
+ else
+ metric="0"
+ fi
+ eval metric_${ifvar}="${metric}"
+fi
+
+
+eval d=\" \$\{dhcp_${ifvar}\} \"
+[[ ${d} == " " ]] && d=" ${dhcp} "
+
+# Configure our IP address
+ip="${ip// }"
+subnet="${subnet// }"
+cidr=$( netmask2cidr "${subnet}" )
+broadcast="${broadcast// }"
+[[ -n ${broadcast} ]] && broadcast="broadcast ${broadcast}"
+
+# If we don't have our address then we flush it and then add our new one
+curip=$( interface_get_address "${interface}" )
+if [[ ${curip} != "${ip}/${cidr}" ]] ; then
+ # Just remove IPv4 / inet addresses
+ interface_del_addresses "${interface}" true
+ interface_add_address "${interface}" "${ip}/${cidr}" "${broadcast}"
+fi
+
+# Store the address in a cache for future usage
+echo "${ip}" > "/var/cache/dhcp-${interface}.lease"
+chmod 600 "/var/cache/dhcp-${interface}.lease"
+
+# Configure our default route - we only have 1 default route
+if [[ ${d} != *" nogateway "* ]]; then
+ for r in ${routers}; do
+ interface_default_route "${interface}" "${r}" "${metric:-0}" && break
+ done
+fi
+
+# Configure our hostname - but only if we need it
+if [[ -n ${hostname} ]]; then
+ x=$( /bin/hostname )
+ [[ ${x} == "(none)" || ${x} == "localhost" ]] && /bin/hostname "${hostname}"
+fi
+
+[[ ! -d "${statedir}/${interface}" ]] \
+&& mkdir -m 0755 -p "${statedir}/${interface}"
+
+# Only setup the information we're told to
+# By default that's everything
+[[ ${d} != *" nodns "* ]] && system_dns "${interface}"
+[[ ${d} != *" nontp "* ]] && system_ntp "${interface}"
+[[ ${d} != *" nonis "* ]] && system_nis "${interface}"
+
+if [[ ${RC_AUTO_INTERFACE} == "yes" ]]; then
+ best_interface=$( select_best_interface )
+ apply_state "${best_interface}"
+else
+ apply_state "${interface}"
+fi
+
+! service_stopping "${service}" && mark_service_started "${service}"
+
+echo "${action}"
+exit 0
+
+# vim:ts=4
diff --git a/lib/rcscripts/net.modules.d/helpers.d/dhcp-state b/lib/rcscripts/net.modules.d/helpers.d/dhcp-state
new file mode 100644
index 0000000..8bc2681
--- /dev/null
+++ b/lib/rcscripts/net.modules.d/helpers.d/dhcp-state
@@ -0,0 +1,31 @@
+#!/bin/bash
+# Copyright (c) 2005 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+# Contributed by Roy Marples (uberlord@gentoo.org)
+
+MODULES_DIR="/lib/rcscripts/net.modules.d"
+. /lib/rcscripts/sh/rc-services.sh
+. "${MODULES_DIR}/helpers.d/functions"
+conf=$(add_suffix "/etc/conf.d/net")
+[[ -e ${conf} ]] && source "${conf}"
+
+service="net.${interface}"
+
+if [[ ${action} != "up" ]]; then
+ if service_starting "${service}" || service_started "${service}" ; then
+ mark_service_inactive "${service}"
+ fi
+ remove_state "${interface}" false
+else
+ ! service_stopping "${service}" && mark_service_started "${service}"
+fi
+
+if [[ ${RC_AUTO_INTERFACE} == "yes" ]]; then
+ best_interface=$( select_best_interface )
+ apply_state "${best_interface}"
+elif [[ ${action} == "up" ]]; then
+ apply_state "${interface}"
+fi
+
+# vim:ts=4
diff --git a/lib/rcscripts/net.modules.d/helpers.d/dhcpcd-wrapper b/lib/rcscripts/net.modules.d/helpers.d/dhcpcd-wrapper
new file mode 100755
index 0000000..5aa1c53
--- /dev/null
+++ b/lib/rcscripts/net.modules.d/helpers.d/dhcpcd-wrapper
@@ -0,0 +1,48 @@
+#!/bin/bash
+# Copyright (c) 2005 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+# Contributed by Roy Marples (uberlord@gentoo.org)
+
+interface="${1##*/dhcpcd-}"
+interface="${interface%%.info}"
+
+if [[ $2 != "up" && $2 != "new" ]]; then
+ action="down"
+else
+ action="up"
+fi
+
+. /lib/rcscripts/net.modules.d/helpers.d/module-loader
+
+if [[ ${action} == "up" ]]; then
+ # Map MAC address variables to interface variables
+ macnet_pre_start "${interface}" 1>/dev/null
+
+ # Map wireless ESSID variables to interface variables
+ if [[ -n ${wireless_module} ]]; then
+ if wireless_check_extensions "${interface}" ; then
+ essidnet_pre_start "${interface}" 1>/dev/null
+ fi
+ fi
+
+ # Add any search paths if we have any defined
+ ifvar=$( bash_variable "${interface}" )
+ eval d=\" \$\{dhcp_${ifvar}\} \"
+ [[ ${d} == " " ]] && d=" ${dhcp} "
+
+ if [[ ${d} != *" nodns "* ]]; then
+ eval search=\"\$\{dns_search_path_${ifvar}\}\"
+ if [[ -n ${search} ]]; then
+ resolv="${statedir}/${interface}/resolv.conf"
+ tmp="${revolv}.$$"
+ egrep -v "^[ \t]*(search|domain)[ \t]*" "${resolv}" > "${tmp}"
+ echo "search ${search}" >> "${tmp}"
+ mv "${tmp}" "${resolv}"
+ fi
+ fi
+fi
+
+. /lib/rcscripts/net.modules.d/helpers.d/dhcp-state
+
+# vim:ts=4
diff --git a/lib/rcscripts/net.modules.d/helpers.d/functions b/lib/rcscripts/net.modules.d/helpers.d/functions
new file mode 100644
index 0000000..f09d15d
--- /dev/null
+++ b/lib/rcscripts/net.modules.d/helpers.d/functions
@@ -0,0 +1,526 @@
+#!/bin/bash
+# Copyright (c) 2004-2005 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+# We will be loaded after conf.d/rc and conf.d/net so we can set a default
+# here.
+RC_AUTO_INTERFACE="${RC_AUTO_INTERFACE:-no}"
+
+netdir="/var/lib/net-scripts"
+statedir="${netdir}/state"
+
+# Contributed by Roy Marples (uberlord@gentoo.org)
+
+# char* interface_device(char *iface)
+#
+# Gets the base device of the interface
+# Can handle eth0:1 and eth0.1
+# Which returns eth0 in this case
+interface_device() {
+ local dev="${1%%.*}"
+ [[ ${dev} == "$1" ]] && dev="${1%%:*}"
+ echo "${dev}"
+}
+
+# char* interface_type(char* iface)
+#
+# Returns the base type of the interface
+# eth, ippp, etc
+interface_type() {
+ echo "${1%%[0-9]*}"
+}
+
+# void save_state(char *interface)
+#
+# Saves state information regarding the interface
+save_state() {
+ local iface="$1"
+ local d="${statedir}/${iface}"
+
+ [[ ! -d ${d} ]] && mkdir -m 0755 -p "${d}"
+ cp -a /etc/resolv.conf /etc/ntp.conf /etc/yp.conf "${d}" 2>/dev/null
+}
+
+# void remove_state(char *interface)
+#
+# Removes state information regarding the interface
+remove_state() {
+ local d="${statedir}/$1"
+
+ [[ -d ${d} ]] && rm -Rf "${d}"
+ [[ ! ${2:-true} ]] && mkdir -m 0755 -p "${d}"
+}
+
+# void apply_state(char *interface)
+#
+# Apply's state information about the interface to the system
+# If the files in the state dir are not links back to etc then
+# we create them if RC_AUTO_INTERFACE="yes"
+#
+apply_state() {
+ local iface="$1"
+
+ if [[ -z ${iface} ]]; then
+ iface=$( select_best_interface )
+ [[ -z ${iface} ]] && return
+ fi
+
+ local d="${statedir}/${iface}"
+ if [[ -d ${d} ]]; then
+ local files=$( ls "${d}" )
+ if [[ -n ${files} ]] ; then
+ if [[ ${RC_AUTO_INTERFACE} == "yes" ]]; then
+ cp -aR "${d}"/* "${netdir}"
+ local file
+ for file in ${files} ; do
+ # Skip .sv files
+ [[ ${file} == *".sv" ]] && contine
+ local link=$( readlink "/etc/${file}" 2>/dev/null )
+ if [[ ${link} != "${netdir}/${file}" ]]; then
+ [[ -e "/etc/${file}" ]] && rm -f "/etc/${file}"
+ ln -snf "${netdir}/${file}" "/etc/${file}"
+ fi
+ done
+ else
+ cp -ar "${d}"/* /etc
+ fi
+ fi
+ fi
+
+ [[ ${RC_AUTO_INTERFACE} == "yes" ]] && merge_configs
+}
+
+# char* order_interfaces(bool require_gateway)
+#
+# Lists the interfaces in route metric order that we have configured
+# (ie a state dir exists)
+# require_gateway defaults to false
+order_interfaces() {
+ local ifaces
+ if [[ ${1:-false} == "true" ]]; then
+ ifaces=$(awk '$2!="Gateway" { print $7, $1 }' /proc/net/route \
+ | sort -n | cut -d' ' -f2 | uniq)
+ else
+ ifaces=$(awk '$2=="00000000" { print $7, $1 }' /proc/net/route \
+ | sort -n | cut -d' ' -f2 )
+ fi
+ local i order
+ for i in ${ifaces}; do
+ [[ -d "${statedir}/${i}" ]] && order="${order}${i} "
+ done
+
+ echo "${order}"
+}
+
+# void merge_resolv()
+#
+# Merges the resolv.conf info from active interfaces
+merge_resolv() {
+ local -a ifaces=( $(order_interfaces) )
+ local i j f
+
+ # We only work for ifaces with a resolv.conf
+ j=${#ifaces[@]}
+ for (( i=0; i<j; i++ )); do
+ [[ ! -e "${statedir}/${ifaces[i]}/resolv.conf" ]] && unset ifaces[i]
+ done
+ ifaces=( "${ifaces[@]}" )
+
+ # No point merging unless there are two or more interfaces
+ [[ ${#ifaces[@]} -lt 2 ]] && return
+
+ veinfo "Merging resolv.conf from interfaces ${ifaces[@]}"
+
+ local -a search srvs
+ j=0
+ for (( i=0; i<${#ifaces[@]}; i++ )); do
+ f="${statedir}/${ifaces[i]}/resolv.conf"
+ srvs[i]=$( sed -n -e 's/^[ \t]*nameserver[ \t]*\([^#]\)/\1/p' "${f}" \
+ | sed 2q )
+ if [[ -z ${srvs[i]} ]]; then
+ unset srvs[i]
+ continue
+ fi
+
+ search[i]=$( sed -n -e 's/^[ \t]*\(domain\|search\)[ \t]*\([^#]\)/\2/p' \
+ "${f}" | sed -e '$!d' )
+
+ # No point in handling more than 3 interfaces due to libc limits
+ (( j++ ))
+ [[ ${j} -gt 2 ]] && break
+ done
+ srvs=( "${srvs[@]}" )
+ search=( ${search[@]} )
+
+ local new_srvs
+ j=0
+ # Add interface primary nameservers
+ for (( i=0;i<${#srvs[@]}; i++ )); do
+ local -a n=( ${srvs[i]} )
+ if [[ " ${new_srvs} " != *" ${n[0]} "* ]]; then
+ new_srvs="${new_srvs} ${n[0]}"
+ # libc can only handle 3 name servers
+ (( j++ ))
+ [[ ${j} -gt 2 ]] && break
+ fi
+ done
+
+ # Add interface secondary nameservers
+ if [[ ${j} -lt 3 ]]; then
+ for (( i=0;i<${#srvs[@]}; i++ )); do
+ local -a n=( ${srvs[i]} )
+ [[ -z ${n[1]} ]] && continue
+ if [[ " ${new_srvs} " != *" ${n[1]} "* ]]; then
+ new_srvs="${new_srvs} ${n[1]}"
+ # libc can only handle 3 name servers
+ (( j++ ))
+ [[ ${j} -gt 2 ]] && break
+ fi
+ done
+ fi
+
+ local new_search n_search=0
+ for i in ${search[@]}; do
+ if [[ " ${new_search} " != *" ${i} "* ]]; then
+ new_search="${new_search} ${i}"
+ # lib limits us to 6 search domains
+ (( n_search++ ))
+ [[ ${n_search} -gt 5 ]] && break
+ fi
+ done
+
+ # Now we create a new resolv.conf to use
+ local f="${netdir}/resolv.conf.$$"
+ echo "# Generated by net-scripts from interfaces ${ifaces[@]}" > "${f}"
+ chmod 644 "${f}"
+ for i in ${new_srvs[@]}; do
+ echo "nameserver ${i}" >> "${f}"
+ done
+ if [[ -n ${new_search} ]]; then
+ if [[ ${n_search} == "1" ]]; then
+ echo "domain${new_search}" >> "${f}"
+ else
+ echo "search${new_search}" >> "${f}"
+ fi
+ fi
+ mv "${f}" "${netdir}/resolv.conf"
+}
+
+
+# void merge_ntp()
+#
+# Merges the ntp.conf info from active interfaces
+merge_ntp() {
+ local -a ifaces=( $(order_interfaces) )
+ local i j f
+
+ # We only work for ifaces with a ntp.conf
+ j=${#ifaces[@]}
+ for (( i=0; i<j; i++ )); do
+ [[ ! -e "${statedir}/${ifaces[i]}/ntp.conf" ]] && unset ifaces[i]
+ done
+ ifaces=( "${ifaces[@]}" )
+
+ # No point merging unless there are two or more interfaces
+ [[ ${#ifaces[@]} -lt 2 ]] && return
+
+ veinfo "Merging ntp.conf from interfaces ${ifaces[@]}"
+
+ local srvs
+ for (( i=0; i<${#ifaces[@]}; i++ )); do
+ f="${statedir}/${ifaces[i]}/ntp.conf"
+ srvs="${srvs} $( sed -n -e 's/^[ \t]*server[ \t]*\([^#]\)/\1/p' "${f}" )"
+ done
+
+ # ntp does it's own preference list, so we just remove duplicates
+ sort_unique() {
+ set -- " ${@/%/\n}"
+ echo -e "$@" | sort -u
+ }
+
+ srvs=$( sort_unique ${srvs} )
+
+ f="${netdir}/ntp.conf.$$"
+ echo "# Generated by net-scripts for interfaces ${ifaces[@]}" > "${f}"
+ chmod 644 "${f}"
+
+ echo "restrict default noquery notrust nomodify" >> "${f}"
+ echo "restrict 127.0.0.1" >> "${f}"
+
+ for i in ${srvs}; do
+ echo "restrict ${i} nomodify notrap noquery" >> "${f}"
+ echo "server ${i}" >> "${f}"
+ done
+
+ echo "driftfile /var/lib/ntp/ntp.drift" >> "${f}"
+ echo "logfile /var/log/ntp.log" >> "${f}"
+
+ mv "${f}" "${netdir}/ntp.conf"
+}
+
+# void merge_configs()
+#
+# Merge config files together
+merge_configs() {
+ merge_resolv
+ merge_ntp
+}
+
+# char* select_best_interface()
+#
+# Selects the best interface to apply state information to
+# This is currently based on routing metrics
+select_best_interface() {
+ local -a ifs=( $(order_interfaces true) )
+
+ # We never select lo as the best interface
+ local x=" ${ifs[@]} "
+ ifs=( ${x// lo / } )
+
+ local iface
+ for iface in ${ifs[@]} ; do
+ if [[ -e "${statedir}/${iface}/resolv.conf" ]]; then
+ echo "${iface}"
+ return 0
+ fi
+ done
+
+ echo "${ifs[0]}"
+}
+
+# int calculate_metric(char *interface)
+#
+# Calculates the best metric for the interface
+# The Linux kernel does not use this at the moment, but we use it so that
+# default routes remain and we can work out the "best" interface
+calculate_metric() {
+ local iface="$1" exclude='$1!="Iface" && $1!="lo"'
+
+ # Have we already got a metric?
+ local m=$( awk '$1=="'${iface}'" && $2=="00000000" { print $7 }' \
+ /proc/net/route )
+ if [[ -n ${m} ]]; then
+ echo "${m}"
+ return 0
+ fi
+
+ local itype=$( interface_type "${iface}" ) x i
+
+ # If we're not a wireless device then exclude wireless from the
+ # routing table so we stay < 1000
+ if [[ -e /proc/net/wireless ]]; then
+ if ! grep -q "^[ \t]*${iface}:[ \t]" /proc/net/wireless ; then
+ local i=$( sed -n -e 's/^[ \t]*\(.*\):.*/\1/p' /proc/net/wireless )
+ for x in ${i} ; do
+ exclude="${exclude} && "'$1'"!=\"${x}\""
+ done
+ fi
+ fi
+
+ # Exclude ppp and ippp as well
+ local ix="ppp|ippp"
+ [[ ${itype} == "ppp" ]] && ix="ippp"
+ [[ ${itype} == "ippp" ]] && ix="ppp"
+ i=$( sed -n -e 's/^[ ]*\('${ix}'[0-9]*\):.*$/\1/p' /proc/net/dev )
+ for x in ${i} ; do
+ exclude="${exclude} && "'$1'"!=\"${x}\""
+ done
+
+ local m=$( awk "${exclude} { print "'$7'" }" /proc/net/route \
+ | sort -rn | head -n 1 | cut -d' ' -f2 )
+ m="${m:--1}"
+ (( m ++ ))
+
+ # If we're a wireless device then add 1000 so that wired interfaces take preference
+ if [[ -e /proc/net/wireless ]]; then
+ grep -q "^[ \t]*${iface}:[ \t]" /proc/net/wireless && (( m+= 1000 ))
+ fi
+
+ # If we're a ppp device then we add 2000 for ISDN, otherwise 3000
+ [[ ${itype} == "ippp" ]] && (( m+= 2000 ))
+ [[ ${itype} == "ppp" ]] && (( m+= 3000 ))
+
+ echo "${m}"
+}
+
+# int netmask2cidr(char *netmask)
+#
+# Returns the CIDR of a given netmask
+netmask2cidr() {
+ local binary="" i bin
+
+ for i in ${1//./ }; do
+ bin=""
+ while [[ ${i} != "0" ]]; do
+ bin=$[${i}%2]${bin}
+ (( i=i>>1 ))
+ done
+ binary="${binary}${bin}"
+ done
+ binary="${binary%%0*}"
+ echo "${#binary}"
+}
+
+# char* netmask2cidr(int cidr)
+#
+# Returns the netmask of a given CIDR
+cidr2netmask() {
+ local cidr="$1" netmask="" done=0 i sum=0 cur=128
+ local octets frac
+
+ (( octets=cidr/8 ))
+ (( frac=cidr%8 ))
+ while [[ octets -gt 0 ]]; do
+ netmask="${netmask}.255"
+ (( octets-- ))
+ (( done++ ))
+ done
+
+ if [[ ${done} -lt 4 ]]; then
+ for (( i=0; i<${frac}; i++ )); do
+ (( sum+=cur ))
+ (( cur/=2 ))
+ done
+ netmask="${netmask}.${sum}"
+ (( done++ ))
+
+ while [[ ${done} -lt 4 ]]; do
+ netmask="${netmask}.0"
+ (( done++ ))
+ done
+ fi
+
+ echo "${netmask:1}"
+}
+
+# char* ip_network(char *ip, char *netmask)
+#
+# Returns the network of the ip address
+# ip can be 192.168.0.51/24
+# or
+# ip can be 192.168.0.51 and netmask is 255.255.255.0
+ip_network() {
+ local ip="$1" mask="$2" i network x
+
+ # If we didn't get parameter 2 then assume we have a CIDR
+ if [[ -z ${mask} ]]; then
+ mask="${ip##*/}"
+ [[ -z ${mask} || ${mask} == ${ip} ]] && return 1
+ mask=$( cidr2netmask "${mask}" )
+ ip="${ip%%/*}"
+ fi
+
+ ip=( ${ip//./ } )
+ mask=( ${mask//./ } )
+
+ for (( i=0; i<4; i++ )); do
+ (( x=ip[i] & mask[i] ))
+ network="${network}${x}"
+ [[ ${i} -lt 3 ]] && network="${network}."
+ done
+
+ echo "${network}"
+}
+
+# bool clean_pidfile(char *file)
+#
+# Removes the given pidfile if the process is not running
+# Returns 1 if the process is still running otherwise 0
+clean_pidfile() {
+ local pidfile="$1"
+
+ [[ ! -f ${pidfile} ]] && return 0
+ local pid=$( < "${pidfile}" )
+
+ if [[ -n ${pid} ]]; then
+ local cmd="${pidfile##*/}"
+ cmd="${cmd%%-*}"
+ ps -p "${pid}" 2>/dev/null | grep -q "${cmd}" && return 1
+ fi
+
+ rm -f "${pidfile}"
+ return 0
+}
+
+# bool process_finished(int pid, char* cmd)
+#
+# We wait for 10 seconds until the command ${cmd}
+# stops running on the process ${pid}
+process_finished() {
+ local i pid="$1" cmd="$2" secs="${3:-9}"
+
+ for (( i=0; i<secs; i++ )); do
+ ps -p "${pid}" 2>/dev/null | grep -q "${cmd}" || return 0
+ sleep 1
+ done
+
+ return 1
+}
+
+# void function_wrap(char* source, char* target)
+#
+# wraps function calls - for example function_wrap(this, that)
+# maps function names this_* to that_*
+function_wrap() {
+ local i
+
+ [[ $( type -t "${2}_provides" ) == "function" ]] && return
+
+ for i in $( typeset -f | grep -o '^'"${1}"'_[^ ]*' ); do
+ eval "${2}${i#${1}}() { ${i} \"\$@\"; }"
+ done
+}
+
+# char[] * expand_parameters(char *cmd)
+#
+# Returns an array after expanding parameters. For example
+# "192.168.{1..3}.{1..3}/24 brd +"
+# will return
+# "192.168.1.1/24 brd +"
+# "192.168.1.2/24 brd +"
+# "192.168.1.3/24 brd +"
+# "192.168.2.1/24 brd +"
+# "192.168.2.2/24 brd +"
+# "192.168.2.3/24 brd +"
+# "192.168.3.1/24 brd +"
+# "192.168.3.2/24 brd +"
+# "192.168.3.3/24 brd +"
+expand_parameters() {
+ local x="$( eval echo ${@// /_} )"
+ local -a a=( ${x} )
+
+ a=( "${a[@]/#/\"}" )
+ a=( "${a[@]/%/\"}" )
+ echo "${a[*]//_/ }"
+}
+
+# void configure_variables(char *interface, char *option1, [char *option2])
+#
+# Maps configuration options from <variable>_<option> to <variable>_<iface>
+# option2 takes precedence over option1
+configure_variables() {
+ local iface="$1" option1="$2" option2="$3"
+
+ local mod func x i
+ local -a ivars ovars1 ovars2
+ local ifvar=$( bash_variable "${iface}" )
+
+ for mod in ${MODULES[@]}; do
+ func="${mod}_get_vars"
+ if [[ $( type -t ${func} ) == "function" ]]; then
+ ivars=( $( "${func}" "${ifvar}" ) )
+ ovars1=( $( "${func}" "${option1}" ) )
+ [[ -n ${option2} ]] && ovars2=( $( "${func}" "${option2}" ) )
+ for ((i = 0; i<${#ivars[@]}; i++)); do
+ x=""
+ [[ -n ${ovars2[i]} ]] && eval x=( \"\$\{${ovars2[i]}\[@\]\}\" )
+ [[ -z ${x} ]] && eval x=( \"\$\{${ovars1[i]}\[@\]\}\" )
+ [[ -n ${x} ]] && eval "${ivars[i]}=( "\"\$\{x\[@\]\}\"" )"
+ done
+ fi
+ done
+
+ return 0
+}
+
+# vim:ts=4
diff --git a/lib/rcscripts/net.modules.d/helpers.d/module-loader b/lib/rcscripts/net.modules.d/helpers.d/module-loader
new file mode 100644
index 0000000..f4f5f95
--- /dev/null
+++ b/lib/rcscripts/net.modules.d/helpers.d/module-loader
@@ -0,0 +1,47 @@
+#!/bin/bash
+# Copyright (c) 2004-2005 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+# Contributed by Roy Marples (uberlord@gentoo.org)
+
+[[ -z ${MODULES_DIR} ]] && MODULES_DIR="/lib/rcscripts/net.modules.d"
+. "${MODULES_DIR}/system"
+. /lib/rcscripts/sh/rc-services.sh
+. "${MODULES_DIR}/helpers.d/functions"
+conf=$(add_suffix "/etc/conf.d/net")
+[[ -e ${conf} ]] && source "${conf}"
+
+# Guess which interface module to load - we prefer iproute2
+if [[ -x /sbin/ip ]]; then
+ interface_module="iproute2"
+elif [[ -x /sbin/ifconfig ]]; then
+ interface_module="ifconfig"
+else
+ echo "Can't find a known interface module" >&2
+ exit 1
+fi
+
+# iwconfig is the best bet for wireless - we use wpa_supplicant
+# only if we need to
+if [[ -x /sbin/iwconfig ]]; then
+ wireless_module="iwconfig"
+elif [[ -x /sbin/wpa_supplicant \
+ && -S "/var/run/wpa_supplicant/${interface}" ]]; then
+ wireless_module="wpa_supplicant"
+fi
+
+MODULES=( "system" )
+
+# Load our modules
+. "${MODULES_DIR}/${interface_module}"
+function_wrap "${interface_module}" interface
+. "${MODULES_DIR}/macnet"
+. "${MODULES_DIR}/system"
+
+if [[ -n ${wireless_module} ]]; then
+ . "${MODULES_DIR}/${wireless_module}"
+ function_wrap "${wireless_module}" wireless
+ . "${MODULES_DIR}/essidnet"
+fi
+
+# vim:ts=4
diff --git a/lib/rcscripts/net.modules.d/helpers.d/pump-wrapper b/lib/rcscripts/net.modules.d/helpers.d/pump-wrapper
new file mode 100755
index 0000000..93566b5
--- /dev/null
+++ b/lib/rcscripts/net.modules.d/helpers.d/pump-wrapper
@@ -0,0 +1,14 @@
+#!/bin/bash
+# Copyright (c) 2005 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+# Contributed by Roy Marples (uberlord@gentoo.org)
+
+[[ $1 == "renewal" ]] && exit 0
+
+action="$1"
+interface="$2"
+
+. /lib/rcscripts/net.modules.d/helpers.d/dhcp-state
+
+# vim:ts=4
diff --git a/lib/rcscripts/net.modules.d/helpers.d/udhcpc-wrapper b/lib/rcscripts/net.modules.d/helpers.d/udhcpc-wrapper
new file mode 100755
index 0000000..feb01e6
--- /dev/null
+++ b/lib/rcscripts/net.modules.d/helpers.d/udhcpc-wrapper
@@ -0,0 +1,20 @@
+#!/bin/sh
+# Copyright (c) 2004-2005 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+# Contributed by Roy Marples (uberlord@gentoo.org)
+
+# Map the dns, ntp and nis info so our system module can apply the setup
+
+export dns_domain_${interface}="${domain}"
+export dns_servers_${interface}="${dns}"
+export routers="${router}"
+
+export ntp_servers_${interface}="${ntpsrv}"
+
+export nis_domain_${interface}="${nisdomain}"
+export nis_servers_${interface}="${nissrv}"
+
+/lib/rcscripts/net.modules.d/helpers.d/dhcp "$@"
+
+# vim:ts=4
diff --git a/lib/rcscripts/net.modules.d/ifconfig b/lib/rcscripts/net.modules.d/ifconfig
new file mode 100644
index 0000000..0344647
--- /dev/null
+++ b/lib/rcscripts/net.modules.d/ifconfig
@@ -0,0 +1,435 @@
+#!/bin/bash
+# Copyright (c) 2004-2005 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+# Contributed by Roy Marples (uberlord@gentoo.org)
+
+# Fix any potential localisation problems
+# Note that LC_ALL trumps LC_anything_else according to locale(7)
+ifconfig() {
+ LC_ALL=C /sbin/ifconfig "$@"
+}
+
+ifconfig_tunnel() {
+ LC_ALL=C /sbin/iptunnel "$@"
+}
+
+route() {
+ LC_ALL=C /sbin/route "$@"
+}
+
+# void ifconfig_depend(void)
+#
+# Sets up the dependancies for the module
+ifconfig_depend() {
+ after macnet wireless
+}
+
+# bool ifconfig_check_installed(void)
+#
+# Returns 1 if ifconfig is installed, otherwise 0
+ifconfig_check_installed() {
+ [[ -x /sbin/ifconfig ]] && return 0
+ ${1:-false} && eerror "For ifconfig support, emerge sys-apps/net-tools"
+ return 1
+}
+
+# char* ifconfig_provides(void)
+#
+# Returns a string to change module definition for starting up
+ifconfig_provides() {
+ echo "interface"
+}
+
+# char* ifconfig_module(void)
+#
+# Returns the module name
+# This is needed by dhclient as we run different scripts
+# based on the interface
+ifconfig_module() {
+ echo "ifconfig"
+}
+
+# bool ifconfig_check_depends(void)
+#
+# Checks to see if we have the needed functions
+ifconfig_check_depends() {
+ return 0
+}
+
+# bool ifconfig_exists(char *interface, bool report)
+#
+# Returns 1 if the interface exists, otherwise 0
+ifconfig_exists() {
+ local e=$( ifconfig -a | grep -o "^$1" ) report="${2:-false}"
+ [[ -n ${e} ]] && return 0
+ ${report} && eerror "$1 does not exist"
+ return 1
+}
+
+# void ifconfig_up(char *iface)
+#
+# provides a generic interface for bringing interfaces up
+ifconfig_up() {
+ ifconfig "$1" up
+}
+
+# void ifconfig_down(char *iface)
+#
+# provides a generic interface for bringing interfaces down
+ifconfig_down() {
+ ifconfig "$1" down
+}
+
+# bool ifconfig_is_up(char *iface, bool withaddress)
+#
+# Returns 0 if the interface is up, otherwise 1
+# If withaddress is true then the interface has to have an IPv4 address
+# assigned as well
+ifconfig_is_up() {
+ local check="\<UP\>" addr="${2:-false}"
+ ${addr} && check="\<inet addr:.*${check}"
+ ifconfig "$1" | grep -Eq "${check}" && return 0
+ return 1
+}
+
+# void ifconfig_set_flag(char *iface, char *flag, bool enabled)
+#
+# Sets or disables the interface flag
+ifconfig_set_flag() {
+ local iface="$1" flag="$2" enable="$3"
+ ${enable} || flag="-${flag}"
+ ifconfig "${iface}" "${flag}"
+}
+
+# void ifconfig_get_address(char *interface)
+#
+# Fetch the address retrieved by DHCP. If successful, echoes the
+# address on stdout, otherwise echoes nothing.
+ifconfig_get_address() {
+ local -a x=( $( ifconfig "$1" \
+ | sed -n -e 's/.*inet addr:\([^ ]*\).*Mask:\([^ ]*\).*/\1 \2/p' ) )
+ x[1]=$( netmask2cidr "${x[1]}" )
+ echo "${x[0]}/${x[1]}"
+}
+
+# void ifconfig_get_mac_address(char *interface)
+#
+# Fetch the mac address assingned to the network card
+ifconfig_get_mac_address() {
+ ifconfig "$1" | sed -n -e 's/.*HWaddr .*\<\(..:..:..:..:..:..\)\>.*/\U\1/p'
+}
+
+# void ifconfig_set_mac_address(char *interface, char *mac)
+#
+# Assigned the mac address to the network card
+ifconfig_set_mac_address() {
+ ifconfig "$1" hw ether "$2"
+}
+
+# int ifconfig_set_name(char *interface, char *new_name)
+#
+# Renames the interface
+# This will not work if the interface is setup!
+ifconfig_set_name() {
+ [[ -z $2 ]] && return 1
+ local current="$1" new="$2"
+
+ local mac=$( ifconfig_get_mac_address "${current}" )
+ if [[ -z ${mac} ]]; then
+ eerror "${iface} does not have a MAC address"
+ return 1
+ fi
+
+ /sbin/nameif "${new}" "${mac}"
+}
+
+# void ifconfig_get_aliases_rev(char *interface)
+#
+# Fetch the list of aliases for an interface.
+# Outputs a space-separated list on stdout, in reverse order, for
+# example "eth0:2 eth0:1"
+ifconfig_get_aliases_rev() {
+ ifconfig | grep -o "^$1:[0-9]* " | tac
+}
+
+# bool ifconfig_del_addresses(char *interface, bool onlyinet)
+#
+# Remove addresses from interface. Returns 0 (true) if there
+# were addresses to remove (whether successful or not). Returns 1
+# (false) if there were no addresses to remove.
+# If onlyinet is true then we only delete IPv4 / inet addresses
+ifconfig_del_addresses() {
+ local iface="$1" i onlyinet="${2:-false}"
+ # We don't remove addresses from aliases
+ [[ ${iface} == *:* ]] && return 0
+
+ # If the interface doesn't exist, don't try and delete
+ ifconfig_exists "${iface}" || return 0
+
+ # iproute2 can add many addresses to an iface unlike ifconfig ...
+ # iproute2 added addresses cause problems for ifconfig
+ # as we delete an address, a new one appears, so we have to
+ # keep polling
+ while ifconfig "${iface}" | grep -q -m1 -o 'inet addr:[^ ]*' ; do
+ ifconfig "${iface}" 0.0.0.0 || break
+ done
+
+ # Remove IPv6 addresses
+ if ! ${onlyinet} ; then
+ for i in $( ifconfig "${iface}" \
+ | sed -n -e 's/^.*inet6 addr: \([^ ]*\) Scope:[^L].*/\1/p' ) ; do
+ /sbin/ifconfig "${iface}" inet6 del "${i}"
+ done
+ fi
+ return 0
+}
+
+# char* ifconfig_get_vars(char *interface)
+#
+# Returns a string spaced with possible user set
+# configuration variables
+ifconfig_get_vars() {
+ echo "config_$1 routes_$1 fallback_$1 metric_$1 ifconfig_$1 \
+ ifconfig_fallback_$1 routes_$1 inet6_$1 iface_$1 alias_$1 \
+ broadcast_$1 netmask_$1"
+ # The depreciated gateway var has to be handled by
+ # each module if needed
+}
+
+# bool ifconfig_get_old_config(char *iface)
+#
+# Returns config and config_fallback for the given interface
+ifconfig_get_old_config() {
+ local iface="$1" ifvar=$( bash_variable "$1" ) i inet6
+
+ eval config=( \"\$\{ifconfig_${ifvar}\[@\]\}\" )
+ eval config_fallback=( \"\$\{ifconfig_fallback_${ifvar}\[@\]\}\" )
+ eval inet6=( \"\$\{inet6_${ifvar}\[@\]\}\" )
+
+ # BACKWARD COMPATIBILITY: populate the config_IFACE array
+ # if iface_IFACE is set (fex. iface_eth0 instead of ifconfig_eth0)
+ eval i=\"\$\{iface_${ifvar}\}\"
+ if [[ -n ${i} && -z ${config} ]]; then
+ # Make sure these get evaluated as arrays
+ local -a aliases broadcasts netmasks
+
+ # Start with the primary interface
+ config=( "${i}" )
+
+ # ..then add aliases
+ eval aliases=( \$\{alias_${ifvar}\} )
+ eval broadcasts=( \$\{broadcast_${ifvar}\} )
+ eval netmasks=( \$\{netmask_${ifvar}\} )
+ for (( i=0; i<${#aliases[@]}; i++ )); do
+ config[i+1]="${aliases[i]} ${broadcasts[i]:+broadcast ${broadcasts[i]}} ${netmasks[i]:+netmask ${netmasks[i]}}"
+ done
+ fi
+
+ # BACKWARD COMPATIBILITY: check for space-separated inet6 addresses
+ [[ ${#inet6[@]} == 1 && ${inet6} == *' '* ]] && inet6=( ${inet6} )
+
+ # Add inet6 addresses to our config if required
+ [[ -n ${inet6} ]] && config=( "${config[@]}" "${inet6[@]}" )
+
+ return 0
+}
+
+# bool ifconfig_iface_stop(char *interface)
+#
+# Do final shutdown for an interface or alias.
+#
+# Returns 0 (true) when successful, non-zero (false) on failure
+ifconfig_iface_stop() {
+ # If an alias is already down, then "ifconfig eth0:1 down"
+ # will try to bring it up with an address of "down" which
+ # fails. Do some double-checking before returning error
+ # status
+ ifconfig_is_up "$1" || return 0
+ ifconfig_down "$1" && return 0
+
+ # It is sometimes impossible to transition an alias from the
+ # UP state... particularly if the alias has no address. So
+ # ignore the failure, which should be okay since the entire
+ # interface will be shut down eventually.
+ [[ $1 == *:* ]] && return 0
+ return 1
+}
+
+# bool ifconfig_pre_start(char *interface)
+#
+# Runs any pre_start stuff on our interface - just the MTU atm
+# We set MTU twice as it may be needed for DHCP - a dhcp client could
+# change it in error, so we set MTU in post start too
+ifconfig_pre_start() {
+ local iface="$1"
+
+ interface_exists "${iface}" || return 0
+
+ local ifvar=$( bash_variable "$1" ) mtu
+
+ # MTU support
+ eval mtu=\"\$\{mtu_${ifvar}\}\"
+ [[ -n ${mtu} ]] && ifconfig "${iface}" mtu "${mtu}"
+
+ return 0
+}
+
+
+# bool ifconfig_post_start(char *iface)
+#
+# Bring up iface using ifconfig utilities, called from iface_start
+#
+# Returns 0 (true) when successful on the primary interface, non-zero
+# (false) when the primary interface fails. Aliases are allowed to
+# fail, the routine should still return success to indicate that
+# net.eth0 was successful
+ifconfig_post_start() {
+ local iface="$1" ifvar=$( bash_variable "$1" ) routes x metric mtu cidr
+ eval metric=\"\$\{metric_${ifvar}\}\"
+
+ # Make sure interface is marked UP
+ ifconfig_up "${iface}"
+
+ # MTU support
+ eval mtu=\"\$\{mtu_${ifvar}\}\"
+ [[ -n ${mtu} ]] && ifconfig "${iface}" mtu "${mtu}"
+
+ eval routes=( \"\$\{routes_${ifvar}\[@\]\}\" )
+
+ # BACKWARD COMPATIBILITY: set the default gateway
+ if [[ ${gateway} == "${iface}/"* ]]; then
+ # We don't add the old gateway if one has been set in routes_IFACE
+ local gw=true
+ for x in "${routes[@]}"; do
+ [[ ${x} != *"default gw"* ]] && continue
+ gw=false
+ break
+ done
+ ${gw} && routes=( "${routes[@]}" "default gw ${gateway#*/}" )
+ fi
+
+ [[ -z ${routes} ]] && return 0
+
+ # Add routes for this interface, might even include default gw
+ einfo "Adding routes"
+ eindent
+ for x in "${routes[@]}"; do
+ ebegin "${x}"
+
+ # Support iproute2 style routes
+ x="${x//via/gw} "
+ x="${x//scope * / }"
+
+ # Assume we're a net device unless told otherwise
+ [[ " ${x} " != *" -net "* && " ${x} " != *" -host "* ]] && x="-net ${x}"
+
+ # Support adding IPv6 addresses easily
+ [[ ${x} == *:* && ${x} != *"-A inet6"* ]] && x="-A inet6 ${x}"
+
+ # Add a metric if we don't have one
+ [[ ${x} != *" metric "* ]] && x="${x} metric ${metric}"
+
+ route add ${x} dev "${iface}"
+ eend $?
+ done
+ eoutdent
+
+ return 0
+}
+
+# bool ifconfig_add_address(char *iface, char *options ...)
+#
+# Adds the given address to the interface
+ifconfig_add_address() {
+ local iface="$1" i=0 r e
+
+ ifconfig_exists "${iface}" true || return 1
+
+ # Extract the config
+ local -a config=( "$@" )
+ config=( ${config[@]:1} )
+
+ if [[ ${config[0]} == *:* ]]; then
+ # Support IPv6 - nice and simple
+ config[0]="inet6 add ${config[0]}"
+ else
+ # IPv4 is tricky - ifconfig requires an aliased device
+ # for multiple addresses
+ if ifconfig "${iface}" | grep -Eq "\<inet addr:.*" ; then
+ # Get the last alias made for the interface and add 1 to it
+ i=$( ifconfig | tac | grep -m 1 -o "^${iface}:[0-9]*" \
+ | sed -n -e 's/'"${iface}"'://p' )
+ i="${i:-0}"
+ (( i++ ))
+ iface="${iface}:${i}"
+ fi
+
+ # ifconfig doesn't like CIDR addresses
+ local ip="${config[0]%%/*}" cidr="${config[0]##*/}" netmask
+ if [[ -n ${cidr} && ${cidr} != "${ip}" ]]; then
+ netmask=$( cidr2netmask "${cidr}" )
+ config[0]="${ip} netmask ${netmask}"
+ fi
+
+ # Support iproute2 style config where possible
+ r="${config[@]}"
+ config=( ${r//brd +/} )
+ config=( "${config[@]//brd/broadcast}" )
+ config=( "${config[@]//peer/pointtopoint}" )
+ fi
+
+ # Ensure that the interface is up so we can add IPv6 addresses
+ interface_up "${iface}"
+
+ # Some kernels like to apply lo with an address when they are brought up
+ if [[ ${iface} == "lo" && ${config[@]} == "127.0.0.1 netmask 255.0.0.0 broadcast 127.255.255.255" ]]; then
+ ifconfig "${iface}" 0.0.0.0
+ fi
+
+ ifconfig "${iface}" ${config[@]}
+ r="$?"
+ [[ ${r} != "0" ]] && return ${r}
+
+ local metric ifvar=$( bash_variable "${iface}" )
+ # Remove the newly added route and replace with our metric
+ eval metric=\"\$\{metric_${ifvar}\}\"
+ [[ ${metric} == "0" || ${RC_AUTO_INTERFACE} != "yes" ]] && return ${r}
+
+ if [[ -z ${netmask} ]]; then
+ for (( i=1; i<${#config[@]}-1; i++ )); do
+ if [[ ${config[i]} == "netmask" ]]; then
+ netmask="${config[i+1]}"
+ cidr=$( netmask2cidr "${netmask}" )
+ break
+ fi
+ done
+ [[ -z ${netmask} ]] && return ${r}
+ fi
+
+ local network=$( ip_network "${ip}" "${netmask}" )
+
+ if route del -net "${network}/${cidr}" metric 0 dev "${iface}" \
+ 2>/dev/null ; then
+ route add -net "${network}/${cidr}" metric "${metric}" dev "${iface}"
+ fi
+
+ return ${r}
+}
+
+# void ifconfig_default_route(char* interface, char* gateway_ip, int metric)
+#
+# Force default route to the specified gateway
+ifconfig_default_route() {
+ local metric="${3:-0}"
+
+ # Delete any existing default routes
+ while true ; do
+ route del default metric "${metric}" dev "$1" 2>/dev/null || break
+ done
+
+ # Then we add our route
+ route add default gw "$2" metric "${metric}" dev "$1"
+}
+
+# vim:ts=4
diff --git a/lib/rcscripts/net.modules.d/ipppd b/lib/rcscripts/net.modules.d/ipppd
new file mode 100644
index 0000000..8f5fc37
--- /dev/null
+++ b/lib/rcscripts/net.modules.d/ipppd
@@ -0,0 +1,103 @@
+#!/bin/bash
+# Copyright (c) 2004-2005 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+# Contributed by Roy Marples (uberlord@gentoo.org)
+
+# char* ipppd_provides(void)
+#
+# Returns a string to change module definition for starting up
+ipppd_provides() {
+ echo "isdn"
+}
+
+# void ipppd_depend(void)
+#
+# Sets up the dependancies for the module
+ipppd_depend() {
+ after macnet
+ before interface
+}
+
+# bool ipppd_check_installed(void)
+#
+# Returns 1 if isnd4k-utils is installed, otherwise 0
+ipppd_check_installed() {
+ [[ -x /usr/sbin/ipppd ]] && return 0
+ ${1:-false} && eerror "For ISDN (ipppd) support, emerge net-dialup/isdn4k-utils"
+ return 1
+}
+
+# bool ipppd_check_depends(void)
+#
+# Checks to see if we have the needed functions
+ipppd_check_depends() {
+ local f
+
+ for f in interface_exists interface_type clean_pidfile; do
+ [[ $( type -t "${f}" ) == "function" ]] && continue
+ eerror "ipppd: missing required function ${f}\n"
+ return 1
+ done
+
+ return 0
+}
+
+# bool ipppd_start(char *iface)
+#
+# Start isdn on an interface
+#
+# Returns 0 (true) when successful, non-zero otherwise
+ipppd_pre_start() {
+ local iface="$1" opts itype=$( interface_type "$1" )
+ local pidfile="/var/run/ipppd-${iface}.pid"
+
+ # Check that we are a valid isdn interface
+ [[ ${itype} != "ippp" && ${itype} != "isdn" ]] && return 0
+
+ # Check that the interface exists
+ interface_exists "${iface}" true || return 1
+
+ if ! clean_pidfile "${pidfile}" ; then
+ ewarn "ipppd is already running on ${iface}"
+ eend 0
+ return 0
+ fi
+
+ local ifvar=$( bash_variable "${iface}" )
+ # Might or might not be set in conf.d/net
+ eval opts=\"\$\{ipppd_${ifvar}\}\"
+
+ einfo "Starting ipppd for ${iface}"
+ /usr/sbin/ipppd "${opts}" pidfile "${pidfile}" \
+ file "/etc/ppp/options.${iface}" >/dev/null
+ eend $? || return $?
+
+ return 0
+}
+
+# bool ipppd_stop(char *iface)
+#
+# Stop isdn on an interface
+# Returns 0 (true) when successful, non-zero otherwise
+ipppd_stop() {
+ local iface="$1" pidfile="/var/run/ipppd-$1.pid"
+
+ ipppd_check_installed || return 0
+ [[ ! -f ${pidfile} ]] && return 0
+
+ clean_pidfile "${pidfile}" && return 0
+ local pid=$( < "${pidfile}" ) r=0
+
+ einfo "Stopping ipppd for ${iface}"
+ kill -s TERM "${pid}"
+ if ! process_finished "${pid}" ipppd 10 ; then
+ kill -s KILL "${pid}"
+ process_finished "${pid}" ipppd 10 || r=1
+ fi
+
+ eend ${r}
+ return ${r}
+}
+
+# vim:ts=4
diff --git a/lib/rcscripts/net.modules.d/iproute2 b/lib/rcscripts/net.modules.d/iproute2
new file mode 100644
index 0000000..06a8f27
--- /dev/null
+++ b/lib/rcscripts/net.modules.d/iproute2
@@ -0,0 +1,376 @@
+#!/bin/bash
+# Copyright (c) 2004-2005 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+# Contributed by Roy Marples (uberlord@gentoo.org)
+
+# Fix any potential localisation problems
+# Note that LC_ALL trumps LC_anything_else according to locale(7)
+ip() {
+ LC_ALL=C /sbin/ip "$@"
+}
+
+iproute2_tunnel() {
+ LC_ALL=C /sbin/ip tunnel "$@"
+}
+
+# void iproute2_depend(void)
+#
+# Sets up the dependancies for the module
+iproute2_depend() {
+ after macnet wireless
+}
+
+# bool iproute2_check_installed(void)
+#
+# Returns 1 if iproute2 is installed, otherwise 0
+iproute2_check_installed() {
+ local report="${1:-false}" installed="0"
+ if [[ ! -x /sbin/ip ]]; then
+ installed="1"
+ ${report} && eerror "For iproute2 support, emerge sys-apps/iproute2"
+ fi
+ if [[ ! -e /proc/net/netlink ]]; then
+ installed="1"
+ ${report} && eerror "iproute2 requires NetLink enabled in the kernel"
+ fi
+ return "${installed}"
+}
+
+# char* iproute2_provides(void)
+#
+# Returns a string to change module definition for starting up
+iproute2_provides() {
+ echo "interface"
+}
+
+# char* iproute2_module(void)
+#
+# Returns the module name
+# This is needed by dhclient as we run different scripts
+# based on the interface
+iproute2_module() {
+ echo "iproute2"
+}
+
+# bool iproute2_check_depends(void)
+#
+# Checks to see if we have the needed functions
+iproute2_check_depends() {
+ local f
+
+ for f in interface_device; do
+ [[ $( type -t "${f}" ) == "function" ]] && continue
+ eerror "iproute2: missing required function ${f}\n"
+ return 1
+ done
+
+ return 0
+}
+
+# bool iproute2_exists(char *interface, bool report)
+#
+# Returns 1 if the interface exists, otherwise 0
+iproute2_exists() {
+ local e=$( ip addr show label "$1" ) report="${2:-false}"
+ [[ -n ${e} ]] && return 0
+
+ ${report} && eerror "$1 does not exist"
+ return 1
+}
+
+# void iproute2_up(char *interface)
+#
+# provides a generic interface for bringing interfaces up
+iproute2_up() {
+ ip link set up dev "$1"
+}
+
+# void iproute2_down(char *interface)
+#
+# provides a generic interface for bringing interfaces up
+iproute2_down() {
+ ip link set down dev "$1"
+}
+
+# bool ifproute2_is_up(char *iface, bool withaddress)
+#
+# Returns 0 if the interface is up, otherwise 1
+# If withaddress is true then the interface has to have an IPv4 address
+# assigned as well
+iproute2_is_up() {
+ local check="\<UP\>" addr="${2:-false}"
+ ${addr} && check="${check}.*inet "
+ ip addr show "$1" | grep -Eq "${check}" && return 0
+ return 1
+}
+
+# void iproute2_set_flag(char *iface, char *flag, bool enabled)
+#
+# Sets or disables the interface flag
+iproute2_set_flag() {
+ local enable="$3" opt="on"
+ ${enable} || opt="off"
+ ip link set "$1" "$2" "${opt}"
+}
+
+# void iproute2_get_address(char *interface)
+#
+# Fetch the address retrieved by DHCP. If successful, echoes the
+# address on stdout, otherwise echoes nothing.
+iproute2_get_address() {
+ ip -family inet addr show "$1" \
+ | sed -n -e 's/.*inet \([^ ]*\).*/\1/p'
+}
+
+# void iproute2_get_mac_address(char *interface)
+#
+# Fetch the mac address assingned to the network card
+iproute2_get_mac_address() {
+ ip link show "$1" \
+ | sed -n -e 's/^.*\<\(..:..:..:..:..:..\)\>.*/\U\1/p'
+}
+
+# void iproute2_set_mac_address(char *interface, char *mac)
+#
+# Assigned the mac address to the network card
+iproute2_set_mac_address() {
+ ip link set address "$2" dev "$1"
+}
+
+# int iproute2_set_name(char *interface, char *new_name)
+#
+# Renames the interface
+# This will not work if the interface is setup!
+iproute2_set_name() {
+ ip link set name "$2" dev "$1"
+}
+
+# void iproute2_get_aliases_rev(char *interface)
+#
+# Fetch the list of aliases for an interface.
+# Outputs a space-separated list on stdout, in reverse order, for
+# example "eth0:2 eth0:1"
+iproute2_get_aliases_rev() {
+ local iface=$( interface_device "$1" )
+ ip addr show dev "${iface}" | grep -o "${iface}:[0-9].*" | tac
+}
+
+# bool iproute2_del_addresses(char *interface, bool onlyinet)
+#
+# Remove addresses from interface.
+# If onlyinet is true, then we only remove IPv4 / inet addresses.
+iproute2_del_addresses() {
+ local pre=""
+ ${2:-false} && pre="-f inet"
+ ip ${pre} addr flush label "$1" scope global &>/dev/null
+ ip ${pre} addr flush label "$1" scope host &>/dev/null
+ return 0
+}
+
+# char* iproute2_get_vars(char *interface)
+#
+# Returns a string spaced with possible user set
+# configuration variables
+iproute2_get_vars() {
+ echo "config_$1 routes_$1 fallback_$1 metric_$1 ipaddr_$1 ipaddr_fallback_$1 iproute_$1 inet6_$1"
+}
+
+# bool iproute2_get_old_config(char *iface)
+#
+# Returns config and config_fallback for the given interface
+iproute2_get_old_config() {
+ local ifvar=$( bash_variable "$1" ) inet6
+
+ # iproute2-style config vars
+ eval config=( \"\$\{ipaddr_${ifvar}\[@\]\}\" )
+ eval config_fallback=( \"\$\{ipaddr_fallback_${ifvar}\[@\]\}\" )
+ eval inet6=( \"\$\{inet6_${ifvar}\[@\]\}\" )
+
+ # BACKWARD COMPATIBILITY: check for space-separated inet6 addresses
+ [[ ${#inet6[@]} == "1" && ${inet6} == *" "* ]] && inet6=( ${inet6} )
+
+ # Add inet6 addresses to our config if required
+ [[ -n ${inet6} ]] && config=( "${config[@]}" "${inet6[@]}" )
+
+ # Support old style iface_xxx syntax
+ [[ -z ${config} && $(type -t ifconfig_get_old_config) == "function" ]] \
+ && ifconfig_get_old_config "${iface}"
+
+ return 0
+}
+
+# bool iproute2_iface_stop(char *interface)
+#
+# Do final shutdown for an interface or alias.
+#
+# Returns 0 (true) when successful, non-zero (false) on failure
+iproute2_iface_stop() {
+ local label="$1" iface=$( interface_device "$1" )
+
+ # Shut down the link if this isn't an alias or vlan
+ if [[ ${label} == "${iface}" ]]; then
+ iproute2_down "${iface}"
+ return $?
+ fi
+ return 0
+}
+
+# bool iproute2_add_address(char *interface, char *options ...)
+#
+# Adds an the specified address to the interface
+# returns 0 on success and non-zero on failure
+iproute2_add_address() {
+ local iface="$1" x
+
+ iproute2_exists "${iface}" true || return 1
+
+ # Extract the config
+ local -a config=( "$@" )
+ config=( ${config[@]:1} )
+
+ # Convert an ifconfig line to iproute2
+ local n="${#config[@]}"
+ for (( x=0; x<n; x++ )); do
+ case "${config[x]}" in
+ netmask)
+ config[0]="${config[0]}/$( netmask2cidr ${config[x+1]} )"
+ unset config[x] config[x+1]
+ ;;
+ mtu)
+ ip link set mtu "${config[x+1]}" dev "${iface}"
+ unset config[x] config[x+1]
+ ;;
+ esac
+ done
+ config=( "${config[@]//pointtopoint/peer}" )
+
+ # Always scope lo addresses as host unless specified otherwise
+ [[ ${iface} == "lo" && " ${config[@]} " != *" scope "* ]] \
+ && config=( "${config[@]}" "scope host" )
+
+ # IPv4 specifics
+ if [[ ${config[@]} == *.*.*.* ]]; then
+ # Work out a broadcast if none supplied
+ [[ ${config[@]} != *" brd "* && ${config[@]} != *" broadcast "* ]] \
+ && config=( "${config[@]}" "brd +" )
+ fi
+
+ # Ensure that the interface is up so we can add IPv6 addresses
+ interface_up "${iface}"
+
+ # Some kernels like to apply lo with an address when they are brought up
+ if [[ ${iface} == "lo" \
+ && ${config[@]} == "127.0.0.1/8 brd 127.255.255.255 scope host" ]]; then
+ ip addr del dev "${iface}" 127.0.0.1/8 2>/dev/null
+ fi
+
+ ip addr add dev "${iface}" ${config[@]}
+ local r="$?"
+ [[ ${r} != "0" ]] && return "${r}"
+
+ local metric ifvar=$( bash_variable "${iface}" )
+ # Remove the newly added route and replace with our metric
+ eval metric=\"\$\{metric_${ifvar}\}\"
+ [[ ${metric} == "0" || ${RC_AUTO_INTERFACE} != "yes" ]] && return "${r}"
+
+ local network=$( ip_network "${config[0]}" )
+ [[ -z ${network} ]] && return "${r}"
+
+ local cidr="${config[0]##*/}"
+ if ip route del "${network}/${cidr}" metric 0 dev "${iface}" \
+ 2>/dev/null ; then
+ ip route add "${network}/${cidr}" metric "${metric}" dev "${iface}"
+ fi
+
+ return "${r}"
+}
+
+# bool iproute2_pre_start(char *interface)
+#
+# Runs any pre_start stuff on our interface - just the MTU atm
+# We set MTU twice as it may be needed for DHCP - a dhcp client could
+# change it in error, so we set MTU in post start too
+iproute2_pre_start() {
+ local iface="$1"
+
+ interface_exists "${iface}" || return 0
+
+ local ifvar=$( bash_variable "$1" ) mtu
+
+ # MTU support
+ eval mtu=\"\$\{mtu_${ifvar}\}\"
+ [[ -n ${mtu} ]] && ip link set mtu "${mtu}" dev "${iface}"
+
+ return 0
+}
+
+# bool iproute2_post_start(char *interface)
+#
+# Runs any post_start stuff on our interface and adds routes
+# Always returns 0
+iproute2_post_start() {
+ local iface="$1" ifvar=$( bash_variable "$1" ) routes metric mtu x netmask
+
+ # Make sure interface is marked UP
+ iproute2_up "${iface}"
+
+ # MTU support
+ eval mtu=\"\$\{mtu_${ifvar}\}\"
+ [[ -n ${mtu} ]] && ip link set mtu "${mtu}" dev "${iface}"
+
+ eval routes=( \"\$\{routes_${ifvar}\[@\]\}\" )
+ eval metric=\"\$\{metric_${ifvar}\:-0}\"
+
+ # Test for old style ipaddr variable
+ if [[ -z ${routes} ]]; then
+ eval routes=( \"\$\{iproute_${ifvar}\[@\]\}\" )
+ fi
+
+ [[ -z ${routes} ]] && return 0
+
+ # Set routes with ip route -- this might also include default route
+ einfo "Adding routes"
+ eindent
+ for x in "${routes[@]}"; do
+ ebegin "${x}"
+
+ # Support net-tools routing too
+ x="${x//gw/via}"
+ x="${x//-A inet6}"
+ x="${x//-net}"
+ [[ " ${x} " == *" -host "* ]] && x="${x//-host} scope host"
+
+ # Attempt to support net-tools route netmask option
+ netmask="${x##* netmask }"
+ if [[ -n ${netmask} && ${x} != "${netmask}" ]]; then
+ netmask="${netmask%% *}"
+ x="${x// netmask ${netmask} / }"
+ local -a a=( ${x} )
+ a[0]="${a[0]}/$( netmask2cidr ${netmask} )"
+ x="${a[@]}"
+ fi
+
+ # Add a metric if we don't have one
+ [[ " ${x} " != *" metric "* ]] && x="${x} metric ${metric}"
+
+ ip route append ${x} dev "${iface}"
+ eend $?
+ done
+ eoutdent
+
+ return 0
+}
+
+# void iproute2_default_route(char* interface, char* gateway_ip, int metric)
+#
+# Force default route to the specified gateway, optionally on
+# the given interface
+iproute2_default_route() {
+ local metric="${3:-0}"
+
+ ip route change default via "$2" metric "${metric}" dev "$1" 2>/dev/null \
+ || ip route append default via "$2" metric "${metric}" dev "$1" 2>/dev/null
+}
+
+# vim:ts=4
diff --git a/lib/rcscripts/net.modules.d/iptunnel b/lib/rcscripts/net.modules.d/iptunnel
new file mode 100644
index 0000000..f547a99
--- /dev/null
+++ b/lib/rcscripts/net.modules.d/iptunnel
@@ -0,0 +1,84 @@
+#!/bin/bash
+# Copyright (c) 2004-2005 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+# Contributed by Roy Marples (uberlord@gentoo.org)
+
+# char* iptunnel_provides(void)
+#
+# Returns a string to change module definition for starting up
+iptunnel_provides() {
+ echo "iptunnel"
+}
+
+# void iptunnel_depend(void)
+#
+# Sets up the dependancies for the module
+iptunnel_depend() {
+ after wireless
+ before interface
+}
+
+# bool iptunnel_check_installed(void)
+#
+# Tunnelling is provided by the interface
+iptunnel_check_installed() {
+ return 0
+}
+
+# bool iptunnel_check_depends(void)
+#
+# Checks to see if we have the needed functions
+iptunnel_check_depends() {
+ local f
+
+ for f in interface_exists interface_tunnel; do
+ [[ $( type -t "${f}" ) == "function" ]] && continue
+ eerror "iptunnel: missing required function ${f}\n"
+ return 1
+ done
+
+ return 0
+}
+
+# char* iptunnel_get_vars(char *interface)
+#
+# Returns a string spaced with possible user set
+# configuration variables
+iptunnel_get_vars() {
+ echo "iptunnel_$1"
+}
+
+# bool iptunnel_pre_start(char *iface)
+#
+# Create the device, give it the right perms
+iptunnel_pre_start() {
+ local iface="$1" opts ifvar=$( bash_variable "$1" )
+
+ # Get our options
+ eval opts=\"\$\{iptunnel_${ifvar}\}\"
+ [[ -z ${opts} ]] && return 0
+
+ ebegin "Creating tunnel ${iface}"
+ interface_tunnel add "${iface}" ${opts}
+ eend "$?"
+ return "$?"
+
+}
+
+# bool iptunnel_stop(char *iface)
+#
+# Removes the device
+iptunnel_stop() {
+ local iface="$1"
+
+ interface_exists "${iface}" || return 0
+ [[ -z $( interface_tunnel show "${iface}" 2>/dev/null ) ]] && return 0
+
+ ebegin "Destroying tunnel ${iface}"
+ interface_tunnel del "${iface}"
+ eend "$?"
+ return "$?"
+}
+
+# vim:ts=4
diff --git a/lib/rcscripts/net.modules.d/iwconfig b/lib/rcscripts/net.modules.d/iwconfig
new file mode 100644
index 0000000..9401c9f
--- /dev/null
+++ b/lib/rcscripts/net.modules.d/iwconfig
@@ -0,0 +1,923 @@
+#!/bin/bash
+# Copyright (c) 2004-2005 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+# Contributed by Roy Marples (uberlord@gentoo.org)
+# 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
+
+# Fix any potential localisation problems
+# Note that LC_ALL trumps LC_anything_else according to locale(7)
+iwconfig() {
+ LC_ALL=C /sbin/iwconfig "$@"
+}
+iwgetid() {
+ LC_ALL=C /sbin/iwgetid "$@"
+}
+iwlist() {
+ LC_ALL=C /sbin/iwlist "$@"
+}
+iwpriv() {
+ LC_ALL=C /sbin/iwpriv "$@"
+}
+
+# void iwconfig_depend(void)
+#
+# Sets up the dependancies for the module
+iwconfig_depend() {
+ before interface
+}
+
+# bool iwconfig_check_installed(void)
+#
+# Returns 1 if wireless-tools is installed, otherwise 0
+iwconfig_check_installed() {
+ [[ -x /sbin/iwconfig ]] && return 0
+ ${1:-false} && eerror "For Wireless (802.11) support, emerge net-wireless/wireless-tools"
+ return 1
+}
+
+# char* iwconfig_provides(void)
+#
+# Returns a string to change module definition for starting up
+iwconfig_provides() {
+ echo "wireless"
+}
+
+# bool iwconfig_check_depends(void)
+#
+# Checks to see if we have the needed functions
+iwconfig_check_depends() {
+ local f
+
+ for f in interface_up interface_down interface_exists; do
+ [[ $( type -t "${f}" ) == "function" ]] && continue
+ eerror "iwconfig: missing required function ${f}\n"
+ return 1
+ done
+
+ return 0
+}
+
+# bool iwconfig_check_extensions(char *interface)
+#
+# Checks to see if wireless extensions are enabled on the interface
+iwconfig_check_extensions() {
+ grep -q "^[ \t]*$1:[ \t]" /proc/net/wireless
+}
+
+# char* iwconfig_get_wep_status(char *interface)
+#
+# Echos a string showing whether WEP is enabled or disabled
+# for the given interface
+iwconfig_get_wep_status() {
+ local key=$( iwconfig "$1" | grep -i -o "Encryption key:[0-9,A-F]" )
+ local mode status="disabled"
+
+ if [[ -n ${key} ]]; then
+ status="enabled"
+ mode=" - $( iwconfig "$1" | sed -n -e 's/^.*Security mode:\(.*[^ ]\).*/\1/p' )"
+ fi
+
+ echo "(WEP ${status}${mode})"
+}
+
+# char* iwconfig_get_essid(char *iface)
+#
+# Gets the current ESSID of the iface
+iwconfig_get_essid() {
+ local i essid
+
+ for (( i=0; i<5; i++ )); do
+ essid=$( iwgetid "$1" 2>/dev/null | sed -n -e 's/^.*ESSID:"\(.*\)"$/\1/p' )
+ if [[ -n ${essid} ]]; then
+ echo "${essid}"
+ return 0
+ fi
+ sleep 1
+ done
+
+ return 1
+}
+
+# char* iwconfig_get_ap_mac_address(char *interface)
+#
+# Returns the MAC address of the Access Point
+# the interface is connected to
+iwconfig_get_ap_mac_address() {
+ iwgetid --ap "$1" | sed -n -e 's/^.*Cell: .*\<\(..:..:..:..:..:..\)\>.*/\U\1/p'
+}
+
+# char* iwconfig_get_mode(char *interface)
+#
+# Returns the wireless mode in lower case
+iwconfig_get_mode() {
+ iwgetid --mode "$1" | sed -n -e 's/^.*Mode:\(.*\)/\L\1/p'
+}
+
+# char* iwconfig_get_type(char *interface)
+#
+# Returns the type of interface - the IEEE part
+iwconfig_get_type() {
+ iwconfig "$1" | sed -n -e 's/^'"$1"' *\([^ ]* [^ ]*\).*/\1/p'
+}
+
+# void iwconfig_report(char *interface)
+#
+# Output how our wireless interface has been configured
+iwconfig_report() {
+ local iface="$1" essid mac m="to"
+
+ essid=$( iwconfig_get_essid "${iface}" )
+
+ local wep_status=$( iwconfig_get_wep_status "${iface}" )
+ local channel=$( iwgetid --channel "${iface}" 2>/dev/null | cut -d: -f2 )
+ [[ -n ${channel} ]] && channel="on channel ${channel} "
+
+ essid="${essid//\\\\/\\\\}"
+ local mode=$( iwconfig_get_mode "${iface}" )
+ if [[ ${mode} == "master" ]]; then
+ m="as"
+ else
+ mac=$( iwconfig_get_ap_mac_address "${iface}" )
+ [[ -n ${mac} ]] && mac=" at ${mac}"
+ fi
+
+ eindent
+ einfo "${iface} connected ${m} \"${essid}\"${mac}"
+ einfo "in ${mode} mode ${channel}${wep_status}"
+ eoutdent
+}
+
+# char* iwconfig_get_wep_key(char *mac_address)
+#
+# Returns the configured WEP key for the given mac address
+# or the given ESSID. The mac address setting takes precendence
+iwconfig_get_wep_key() {
+ local mac="$1" key
+ eval key=\"\${mac_key_${mac//:/}\}\"
+ [[ -z ${key} ]] && eval key=\"\${key_${ESSIDVAR}\}\"
+ echo "${key:-off}"
+}
+
+# void iwconfig_user_config(char *iface)
+#
+# Applies the user configuration to the interface
+iwconfig_user_config() {
+ local iface="$1" conf ifvar=$( bash_variable "$1" )
+
+ # Apply the user configuration
+ eval conf=\"\$\{iwconfig_${ifvar}\}\"
+ if [[ -n ${conf} ]]; then
+ if ! eval iwconfig "${iface}" ${conf} ; then
+ ewarn "${iface} does not support the following configuration commands"
+ ewarn " \"${conf}\""
+ fi
+ fi
+
+ eval conf=\"\$\{iwpriv_${ifvar}\}\"
+ if [[ -n ${conf} ]]; then
+ if ! eval iwpriv "${iface}" ${conf} ; then
+ ewarn "${iface} does not support the following private ioctls"
+ ewarn " \"${conf}\""
+ fi
+ fi
+}
+
+# bool iwconfig_setup_specific(char *iface)
+#
+# Sets up our wireless interface to operate in ad-hoc or master mode
+iwconfig_setup_specific() {
+ local iface="$1" mode="$2" channel key dessid
+ local ifvar=$( bash_variable "$1" )
+
+ if [[ -z ${ESSID} ]]; then
+ eerror "${iface} requires an ESSID to be set to operate in ${mode} mode"
+ eerror "adjust the essid_${iface} setting in /etc/conf.d/wireless"
+ return 1
+ fi
+ dessid="${ESSID//\\\\/\\\\}"
+ ESSIDVAR=$( bash_variable "${ESSID}" )
+
+ # We only change the mode if it's not the same
+ local cur_mode=$( iwconfig_get_mode "${iface}" )
+ if [[ ${cur_mode} != "${mode}" ]]; then
+ if ! iwconfig "${iface}" mode "${mode}" ; then
+ eerror "${iface} does not support setting the mode to \"${mode}\""
+ return 1
+ fi
+ fi
+
+ key=$( iwconfig_get_wep_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_${ESSIDVAR}\" or \"key_${ESSIDVAR}\" is incorrect"
+ fi
+ fi
+
+ if ! iwconfig "${iface}" essid "${ESSID}" ; then
+ eerror "${iface} does not support setting ESSID to \"${dessid}\""
+ return 1
+ fi
+ iwconfig "${iface}" nick "${ESSID}" 2>/dev/null
+
+ eval channel=\"\$\{channel_${ifvar}\}\"
+ # We default the channel to 3
+ channel=${channel:-3}
+
+ if ! iwconfig "${iface}" channel "${channel}" ; then
+ ewarn "${iface} does not support setting the channel to \"${channel}\""
+ return 1
+ fi
+
+ iwconfig_user_config "${iface}"
+ iwconfig_report "${iface}"
+
+ if ${IN_BACKGROUND}; then
+ mark_service_inactive "net.${iface}"
+ export IN_BACKGROUND
+ /etc/init.d/net.${iface} start &
+ exit 0
+ fi
+
+ return 0
+}
+
+# bool iwconfig_associate_mac(char *iface)
+#
+# Returns true if the AP MAC address is valid or not
+iwconfig_associate_mac() {
+ # Checks if a MAC address has been assigned
+ local mac=$( iwconfig_get_ap_mac_address "$1" ) i
+ local -a invalid_macs=(
+ "00:00:00:00:00:00"
+ "44:44:44:44:44:44"
+ "FF:00:00:00:00:00"
+ "FF:FF:FF:FF:FF:FF"
+ )
+
+ [[ -z ${mac} ]] && return 1
+ for i in "${invalid_macs[@]}"; do
+ [[ ${mac} == "${i}" ]] && return 1
+ done
+ return 0
+}
+
+# bool iwconfig_associate_quality(char *iface)
+#
+# Returns true if the link quality is not 0 or 0.
+iwconfig_associate_quality() {
+ local quality=$( \
+ sed -n -e 's/^.*'"$1"': *[0-9]* *\([0-9]*\).*/\1/p' \
+ /proc/net/wireless
+ )
+ [[ ${quality} != "0" ]]
+ return "$?"
+}
+
+# bool iwconfig_test_associated(char *iface)
+#
+# Returns true if the interface has associated with an Access Point
+iwconfig_test_associated() {
+ local iface="$1" ttype ifvar=$( bash_variable "$1" )
+ # Some drivers don't set MAC to a bogus value when assocation is lost/fails
+ # whereas they do set link quality to 0
+
+ ttype=$( eval echo \"\$\{associate_test_${ifvar}\:-mac}\" | tr '[:upper:]' '[:lower:]' )
+ if [[ ${ttype} != "mac" && ${ttype} != "quality" && ${ttype} != "all" ]]; then
+ ewarn " associate_test_${iface} is not set to mac, quality or all"
+ ewarn " defaulting to \"mac\""
+ test="mac"
+ fi
+
+ case "${ttype}" in
+ mac) iwconfig_associate_mac "${iface}" && return 0 ;;
+ quality) iwconfig_associate_quality "${iface}" && return 0 ;;
+ all) iwconfig_associate_mac "${iface}" \
+ && iwconfig_associate_quality "${iface}" && return 0 ;;
+ esac
+
+ return 1
+}
+
+# bool iwconfig_wait_for_association(char *iface)
+#
+# Waits for a configured ammount of time until
+# we are assocaited with an Access Point
+iwconfig_wait_for_association() {
+ local iface="$1" i=0 timeout ifvar=$( bash_variable "$1" )
+ eval timeout=\"\$\{associate_timeout_${ifvar}\}\"
+ [[ -z ${timeout} ]] && eval timeout=\"\$\{sleep_associate_${ifvar}\:-10\}\"
+
+ [[ ${timeout} == "0" ]] \
+ && vewarn "WARNING: infinite timeout set for association on ${iface}"
+
+ while true; do
+ iwconfig_test_associated "${iface}" && return 0
+ sleep 1
+ [[ ${timeout} == "0" ]] && continue
+ (( i++ ))
+ [[ ${i} == "${timeout}" || ${i} -gt ${timeout} ]] && break
+ done
+ return 1
+}
+
+# bool iwconfig_associate(char *interface, char *mac_address, char *wep_required)
+#
+# Tries to associate the interface with an Access Point
+# If we scanned the Access Point we know if we need WEP to associate or not
+# and if we have a WEP key for the ESSID or not
+# so we can fail gracefully without even trying to connect
+iwconfig_associate() {
+ local iface="$1" mode="${2:-managed}"
+ local mac="$3" wep_required="$4" w="(WEP Disabled)"
+ local dessid="${ESSID//\\\\/\\\\}" key
+ wep_required="${wep_required:-off}"
+
+ iwconfig "${iface}" mode "${mode}" 2>/dev/null
+ if [[ ${ESSID} == "any" ]]; then
+ iwconfig "${iface}" ap any 2>/dev/null
+ dessid="any"
+ unset ESSIDVAR
+ else
+ ESSIDVAR=$( bash_variable "${ESSID}" )
+ key=$( iwconfig_get_wep_key "${mac}" )
+ if [[ ${wep_required} == "yes" && ${key} == "off" ]]; then
+ vewarn "WEP key is not set for \"${dessid}\" - not connecting"
+ return 1
+ fi
+ if [[ ${wep_required} == "no" && ${key} != "off" ]]; then
+ key="off"
+ vewarn "\"${dessid}\" 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_${ESSIDVAR}\" or \"key_${ESSIDVAR}\" is incorrect"
+ return 1
+ fi
+ fi
+ [[ ${key} != "off" ]] && w=$( iwconfig_get_wep_status "${iface}" )
+ fi
+
+ if ! iwconfig "${iface}" essid "${ESSID}" ; then
+ if [[ ${ESSID} != "any" ]]; then
+ ewarn "${iface} does not support setting ESSID to \"${dessid}\""
+ fi
+ fi
+ iwconfig "${iface}" nick "${ESSID}" 2>/dev/null
+
+ vebegin "Connecting to \"${dessid}\" ${w}"
+
+ if [[ ${ESSID} != "any" && $( type -t preassociate ) == "function" ]]; then
+ veinfo "Running preassociate function"
+ eindent
+ ( preassociate "${iface}" )
+ e="$?"
+ eoutdent
+ if [[ ${e} != 0 ]]; then
+ veend 1 "preassociate \"${dessid}\" on ${iface} failed"
+ return 1
+ fi
+ fi
+
+ if ! iwconfig_wait_for_association "${iface}" ; then
+ veend 1
+ return 1
+ fi
+ veend 0
+
+ if [[ ${ESSID} == "any" ]]; then
+ ESSID=$( iwconfig_get_essid "${iface}" )
+ iwconfig_associate "${iface}"
+ return $?
+ fi
+
+ iwconfig_user_config "${iface}"
+ iwconfig_report "${iface}"
+
+ if [[ $( type -t postassociate ) == "function" ]]; then
+ veinfo "Running postassociate function"
+ eindent
+ ( postassociate "${iface}" )
+ eoutdent
+ fi
+
+ if ${IN_BACKGROUND}; then
+ mark_service_started "net.${iface}"
+ mark_service_inactive "net.${iface}"
+ export IN_BACKGROUND
+ /etc/init.d/net.${iface} start &
+ exit 0
+ fi
+
+ return 0
+}
+
+# bool iwconfig_scan(char *iface)
+#
+# Fills 3 arrays with information from a wireless scan
+iwconfig_scan() {
+ local iface="$1" mode x ifvar=$( bash_variable "$1" )
+
+ # First, we may need to change mode to scan in
+ mode=$( eval echo \"\$\{scan_mode_${ifvar}\}\" | tr '[:upper:]' '[:lower:]' )
+ if [[ -n ${mode} ]]; then
+ if ! iwconfig "${iface}" mode "${mode}" ; then
+ ewarn "${iface} does not support setting the mode to \"${mode}\""
+ fi
+ fi
+
+ # Next we set any private driver ioctls needed
+ eval x=\"\$\{iwpriv_scan_pre_${ifvar}\}\"
+ if [[ -n ${x} ]]; then
+ if ! eval iwpriv "${iface}" ${x} ; then
+ ewarn "${iface} does not support the following private ioctls" \
+ ewarn " \"${x}\""
+ fi
+ fi
+
+ # Set the essid to any. This is required for scanning
+ iwconfig "${iface}" essid any
+
+ veinfo "Scanning for access points"
+
+ # Sleep if required
+ eval x=\"\$\{sleep_scan_${ifvar}\}\"
+ [[ -n ${x} ]] && sleep "${x}"
+
+ local error=true i=-1 line
+ local -a mac essid enc qual mode
+
+ while read line; do
+ error=false
+ case "${line}" in
+ *Address:*)
+ (( i++ ))
+ mac[i]=$( echo "${line#*: }" | tr '[:lower:]' '[:upper:]' )
+ ;;
+ *ESSID:*)
+ essid[i]="${line#*\"}"
+ essid[i]="${essid[i]%*\"}"
+ ;;
+ *Mode:*)
+ mode[i]=$(echo "${line#*:}" | tr '[:upper:]' '[:lower:]' )
+ [[ ${mode[i]} == "master" ]] && mode[i]="managed"
+ ;;
+ *'Encryption key:'*)
+ enc[i]="${line#*:}"
+ ;;
+ *Quality*)
+ qual[i]="${line#*:}"
+ qual[i]="${qual[i]%/*}"
+ qual[i]="${qual[i]//[![:digit:]]/}"
+ qual[i]="${qual[i]:-0}"
+ ;;
+ esac
+ done < <( iwlist "${iface}" scan 2>/dev/null )
+
+ if ${error}; then
+ ewarn "${iface} does not support scanning"
+ 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=( \"ESSID1\" \"ESSID2\" )"
+ eerror " and set associate_order_${iface}=\"forcepreferred\""
+ eerror " or set associate_order_${iface}=\"forcepreferredonly\""
+ eerror "or hardcode the ESSID to \"any\" and let the driver find an Access Point"
+ eerror " essid_${iface}=\"any\""
+ eerror "or configure defaulting to Ad-Hoc when Managed fails"
+ eerror " adhoc_essid_${iface}=\"WLAN\""
+ eerror "or hardcode the ESSID against the interface (not recommended)"
+ eerror " essid_${iface}=\"ESSID\""
+ return 1
+ fi
+
+ # We may need to unset the previous private driver ioctls
+ eval x=\"\$\{iwpriv_scan_post_${ifvar}\}\"
+ if [[ -n ${x} ]]; then
+ if ! eval iwpriv "${iface}" ${x} ; then
+ ewarn "${iface} does not support the following private ioctls" \
+ ewarn " \"${x}\""
+ fi
+ fi
+
+ # Change back mode if needed
+ x=$( eval echo \"\$\{mode_${ifvar}\:-managed}\" | tr '[:upper:]' '[:lower:]' )
+ [[ ${mode} != "${x}" ]] && iwconfig "${iface}" mode "${x}"
+
+ for (( i=0; i<${#mac[@]}; i++ )); do
+ # Don't like ad-hoc nodes by default
+ [[ ${mode[i]} == "ad-hoc" ]] && (( qual[i]-=10000 ))
+ sortline="${sortline}${qual[i]} ${i}\n"
+ done
+
+ sortline=( $( echo -e "${sortline}" | sort -nr ) )
+
+ for (( i=0; i<${#mac[@]}; i++ )); do
+ (( x=(i * 2) + 1 ))
+ mac_APs[i]="${mac[${sortline[x]}]}"
+ essid_APs[i]="${essid[${sortline[x]}]}"
+ mode_APs[i]="${mode[${sortline[x]}]}"
+ enc_APs[i]="${enc[${sortline[x]}]}"
+ done
+
+ return 0
+}
+
+# void iwconfig_scan_report(void)
+#
+# Report the results of the scan and re-map any ESSIDs if they
+# have been configured for the MAC address found
+iwconfig_scan_report() {
+ local i k m remove
+ local -a u
+
+ [[ -z ${mac_APs} ]] && ewarn " no access points found"
+
+ # We need to do the for loop like this so we can
+ # dynamically remove from the array
+ eindent
+ for ((i=0; i<${#mac_APs[@]}; i++)); do
+ k=""
+ [[ ${enc_APs[i]} == "yes" ]] && k="(WEP required)"
+
+ if [[ -z ${essid_APs[i]} ]]; then
+ veinfo "Found ${mac_APs[i]} ${k}"
+ else
+ veinfo "Found \"${essid_APs[i]//\\\\/\\\\}\" at ${mac_APs[i]} ${k}"
+ fi
+
+ eindent
+
+ eval m=\"\$\{mac_essid_${mac_APs[i]//:/}\}\"
+ if [[ -n ${m} ]]; then
+ essid_APs[i]="${m}"
+ veinfo "mapping to \"${m//\\\\/\\\\}\""
+ fi
+
+ remove=false
+ # If we don't know the essid then we cannot connect to them
+ # so we remove them from our array
+ if [[ -z ${essid_APs[i]} ]]; then
+ remove=true
+ else
+ for k in "${blacklist_aps[@]}"; do
+ if [[ ${k} == "${essid_APs[i]}" ]]; then
+ vewarn "\"${k//\\\\/\\\\}\" has been blacklisted - not connecting"
+ remove=true
+ break
+ fi
+ done
+ fi
+
+ eoutdent
+
+ ${remove} && u=( "${u[@]}" "${i}" )
+ done
+
+ eoutdent
+
+ # Now we remove any duplicates
+ for ((i=0; i < ${#essid_APs[@]} - 1; i++)); do
+ for ((j=${i} + 1; j <${#essid_APs[@]}; j++)); do
+ [[ ${essid_APs[i]} == "${essid_APs[j]}" ]] && u=( "${u[@]}" "${j}" )
+ done
+ done
+
+ for i in ${u[@]}; do
+ unset essid_APs[i]
+ unset mode_APs[i]
+ unset mac_APs[i]
+ unset enc_APs[i]
+ done
+
+ # We need to squash our arrays so indexes work again
+ essid_APs=( "${essid_APs[@]}" )
+ mode_APs=( "${mode_APs[@]}" )
+ mac_APs=( "${mac_APs[@]}" )
+ enc_APs=( "${enc_APs[@]}" )
+}
+
+# bool iwconfig_force_preferred(char *iface)
+#
+# Forces the preferred_aps list to associate in order
+# but only if they were not picked up by our scan
+iwconfig_force_preferred() {
+ local iface=$1 essid i
+
+ [[ -z ${preferred_aps} ]] && return 1
+
+ ewarn "Trying to force preferred in case they are hidden"
+ for essid in "${preferred_aps[@]}"; do
+ local found_AP=false
+ for ((i = 0; i < ${#mac_APs[@]}; i++)); do
+ if [[ ${essid} == "${essid_APs[i]}" ]]; then
+ found_AP=true
+ break
+ fi
+ done
+ if ! ${found_AP} ; then
+ ESSID="${essid}"
+ iwconfig_associate "${iface}" && return 0
+ fi
+ done
+
+ ewarn "Failed to associate with any preferred access points on ${iface}"
+ return 1
+}
+
+# bool iwconfig_connect_preferred(char *iface)
+#
+# Connects to preferred_aps in order if they were picked up
+# by our scan
+iwconfig_connect_preferred() {
+ local iface="$1" essid i
+
+ for essid in "${preferred_aps[@]}"; do
+ for ((i=0; i<${#essid_APs[@]}; i++)); do
+ if [[ ${essid} == "${essid_APs[i]}" ]]; then
+ ESSID="${essid}"
+ iwconfig_associate "${iface}" "${mode_APs[i]}" "${mac_APs[i]}" \
+ "${enc_APs[i]}" && return 0
+ break
+ fi
+ done
+ done
+
+ return 1
+}
+
+# bool iwconfig_connect_not_preferred(char *iface)
+#
+# Connects to any AP's found that are not in
+# our preferred list
+iwconfig_connect_not_preferred() {
+ local iface=$1 i ap has_preferred
+
+ for ((i=0; i<${#mac_APs[@]}; i++)); do
+ has_preferred=false
+ for ap in "${preferred_aps[@]}"; do
+ if [[ ${ap} == "${essid_APs[i]}" ]]; then
+ has_preferred=true
+ break
+ fi
+ done
+ if ! ${has_preferred} ; then
+ ESSID="${essid_APs[i]}"
+ iwconfig_associate "${iface}" "${mode_APs[i]}" "${mac_APs[i]}" \
+ "${enc_APs[i]}" && return 0
+ fi
+ done
+
+ return 1
+}
+
+# void iwconfig_defaults(char *iface)
+#
+# Apply some sane defaults to the wireless interface
+# incase the user already applied some changes
+iwconfig_defaults() {
+ local iface="$1"
+
+ # Set some defaults
+ iwconfig "${iface}" rate auto &>/dev/null
+ iwconfig "${iface}" rts off &>/dev/null
+ iwconfig "${iface}" frag off &>/dev/null
+ iwconfig "${iface}" power off &>/dev/null
+ iwconfig "${iface}" txpower auto &>/dev/null
+ iwconfig "${iface}" key [1] off &>/dev/null
+ iwconfig "${iface}" mode managed &>/dev/null
+}
+
+# void iwconfig_strip_associated(char *iface)
+#
+# We check to see which ifaces have associated AP's except for the iface
+# given and remove those AP's from the scan list
+# We also remove from the preferred list
+iwconfig_strip_associated() {
+ local iface="$1" e a j
+ local essid=$( iwconfig_get_essid "${iface}" )
+ local -a ifaces=( $( iwconfig 2>/dev/null | grep -o "^\w*" ) )
+
+ for i in "${ifaces[@]}"; do
+ [[ ${i} == ${iface} ]] && continue
+ interface_is_up "${i}" || continue
+ iwconfig_test_associated "${i}" || continue
+ e=$( iwconfig_get_essid "${i}" )
+ u=()
+ for ((j=0; j<${#mac_APs[@]}; j++)); do
+ if [[ ${essid_APs[j]} == "${e}" ]]; then
+ ewarn "${e} has already been associated with ${i}"
+ unset essid_APs[j]
+ unset mode_Aps[j]
+ unset mac_APs[j]
+ unset enc_APs[j]
+ # We need to squash our arrays so that indexes work
+ essid_APs=( "${essid_APs[@]}" )
+ mode_APs=( "${mode_APs[@]}" )
+ mac_APs=( "${mac_APs[@]}" )
+ enc_APs=( "${enc_APs[@]}" )
+ break
+ fi
+ done
+ for ((j=0; j<${#preferred_aps[@]}; j++)); do
+ if [[ ${preferred_aps[j]} == "${e}" ]]; then
+ unset preferred_aps[j]
+ preferred_aps=( "${preferred_aps[@]}" )
+ break
+ fi
+ done
+ done
+}
+
+# bool iwconfig_configure(char *iface)
+#
+# The main startup code
+# First we bring the interface up, apply defaults, apply user configuration
+# Then we test to see if ad-hoc mode has been requested and branch if needed
+# Then we scan for access points and try to connect to them in a predetermined order
+# Once we're connected we show a report and then configure any interface
+# variables for the ESSID
+iwconfig_configure() {
+ local iface="$1" test x e ifvar=$( bash_variable "$1" )
+ local -a essid_APs mac_APs mode_APs enc_APs
+
+ iwconfig_defaults "${iface}"
+ iwconfig_user_config "${iface}"
+
+ eval ESSID=\"\$\{essid_${ifvar}\}\"
+
+ # Setup ad-hoc mode?
+ x=$( eval echo \"\$\{mode_${ifvar}:-managed\}\" | tr '[:upper:]' '[:lower:]' )
+ if [[ ${x} == "ad-hoc" || ${x} == "master" ]]; then
+ iwconfig_setup_specific "${iface}" "${x}"
+ return $?
+ fi
+
+ if [[ ${x} != "managed" && ${x} != "auto" ]]; then
+ eerror "Only managed, ad-hoc, master and auto modes are supported"
+ return 1
+ fi
+
+ # We only change the mode if it's not the same as some drivers
+ # only do managed and throw an error changing to managed
+ local cur_mode=$( iwconfig_get_mode "${iface}" )
+ if [[ ${cur_mode} != "${x}" ]]; then
+ if ! iwconfig "${iface}" mode "${x}" ; then
+ eerror "${iface} does not support setting the mode to \"${x}\""
+ return 1
+ fi
+ fi
+
+ # These arrays hold the results of our scan
+ local -a mac_APs essid_APs enc_APs
+
+ # Has an ESSID been forced?
+ if [[ -n ${ESSID} ]]; then
+ iwconfig_associate "${iface}" && return 0
+ [[ ${ESSID} == "any" ]] && iwconfig_force_preferred "${iface}" && return 0
+
+ eval ESSID=\"\$\{adhoc_essid_${ifvar}\}\"
+ if [[ -n ${ESSID} ]]; then
+ iwconfig_setup_specific "${iface}" ad-hoc
+ return $?
+ fi
+ return 1
+ fi
+
+ # Do we have a preferred Access Point list specific to the interface?
+ eval x=( \"\$\{preferred_aps_${ifvar}\[@\]\}\" )
+ [[ -n ${x} ]] && preferred_aps=( "${x[@]}" )
+
+ # Do we have a blacklist Access Point list specific to the interface?
+ eval x=( \"\$\{blacklist_aps_${ifvar}\[@\]\}\" )
+ [[ -n ${e} ]] && blacklist_aps=( "${x[@]}" )
+
+ # Are we forcing preferred only?
+ eval x=\"\$\{associate_order_${ifvar}\}\"
+ [[ -n ${x} ]] && associate_order="${x}"
+ associate_order=$( echo "${associate_order:-any}" | tr '[:upper:]' '[:lower:]' )
+
+ if [[ ${associate_order} == "forcepreferredonly" ]]; then
+ iwconfig_force_preferred "${iface}" && return 0
+ else
+ iwconfig_scan "${iface}" || return 1
+ iwconfig_scan_report
+
+ # Strip AP's from the list that have already been associated with
+ # other wireless cards in the system if requested
+ eval x=\"\$\{unique_ap_${ifvar}\}\"
+ [[ -n ${x} ]] && unique_ap="${x}"
+ unique_ap=$( echo "${unique_ap:-no}" | tr '[:upper:]' '[:lower:]' )
+ [[ ${unique_ap} != "no" ]] && iwconfig_strip_associated "${iface}"
+
+ iwconfig_connect_preferred "${iface}" && return 0
+ [[ ${associate_order} == "forcepreferred" ]] \
+ && iwconfig_force_preferred "${iface}" && return 0
+ [[ ${associate_order} == "any" || ${associate_order} == "forceany" ]] \
+ && iwconfig_connect_not_preferred "${iface}" && return 0
+ fi
+
+ e="associate with"
+ [[ -z ${mac_APs} ]] && e="find"
+ [[ ${preferred_only} == "force" || ${preferred_aps} == "forceonly" ]] \
+ && e="force"
+ e="Couldn't ${e} any access points on ${iface}"
+
+ eval ESSID=\"\$\{adhoc_essid_${ifvar}\}\"
+ if [[ -n ${ESSID} ]]; then
+ ewarn "${e}"
+ iwconfig_setup_specific "${iface}" ad-hoc
+ return $?
+ fi
+
+ if ${IN_BACKGROUND}; then
+ export IN_BACKGROUND
+ /etc/init.d/net.${iface} stop &
+ exit 0
+ fi
+
+ eerror "${e}"
+ return 1
+}
+
+# bool iwconfig_pre_start(char *iface)
+#
+# Start entry point
+# First we check if wireless extensions exist on the interface
+# If they are then we configue wireless
+iwconfig_pre_start() {
+ local iface="$1" r=0
+
+ # We don't configure wireless if we're being called from
+ # the background
+ ${IN_BACKGROUND} && return 0
+
+ save_options "ESSID" ""
+ interface_exists "${iface}" || return 0
+
+ # We need to bring the interface up, as some cards do not register
+ # in /proc/wireless until they are brought up.
+ interface_up "${iface}"
+
+ if ! iwconfig_check_extensions "${iface}" ; then
+ veinfo "Wireless extensions not found for ${iface}"
+ return 0
+ fi
+
+ # 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 [[ $( < "/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 "${iface}" )
+ if [[ ${x} == "NOT READY!" ]]; then
+ eerror "Looks like there was a probem loading the firmware for ${iface}"
+ return 1
+ fi
+
+ # Setup IFS incase parent script has modified it
+ local IFS=$' '$'\n'$'\t'
+
+ if [[ ${background} == "yes" ]]; then
+ IN_BACKGROUND=true
+ iwconfig_configure "${iface}" &>/dev/null \
+ && save_options "ESSID" "${ESSID}" \
+ || iwconfig_defaults "${iface}" \
+ && interface_down "${iface}" \
+ && mark_service_stopped "net.${iface}" \
+ &
+ go_background
+ fi
+
+ if iwconfig_configure "${iface}" ; then
+ save_options "ESSID" "${ESSID}"
+ return 0
+ fi
+
+ eerror "Failed to configure wireless for ${iface}"
+ iwconfig_defaults "${iface}"
+ unset ESSID ESSIDVAR
+ interface_down "${iface}"
+ return 1
+}
+
+# vim:ts=4
diff --git a/lib/rcscripts/net.modules.d/macchanger b/lib/rcscripts/net.modules.d/macchanger
new file mode 100644
index 0000000..7cc2c5b
--- /dev/null
+++ b/lib/rcscripts/net.modules.d/macchanger
@@ -0,0 +1,126 @@
+#!/bin/bash
+# Copyright (c) 2004-2005 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+# Contributed by Roy Marples (uberlord@gentoo.org)
+
+# char* macchanger_provides(void)
+#
+# Returns a string to change module definition for starting up
+macchanger_provides() {
+ echo "macchanger"
+}
+
+# void macchanger_depend(void)
+#
+# Sets up the dependancies for the module
+macchanger_depend() {
+ before macnet
+}
+
+# bool macchanger_check_installed(void)
+#
+# macchanger is always installed as an interface can change to a specific
+# mac address, and an interface is always installed
+macchanger_check_installed() {
+ return 0
+}
+
+# bool macchanger_check_depends(void)
+#
+# Checks to see if we have the needed functions
+macchanger_check_depends() {
+ local f
+
+ for f in interface_get_mac_address interface_set_mac_address; do
+ [[ $( type -t "${f}" ) == "function" ]] && continue
+ eerror "macchanger: missing required function ${f}\n"
+ return 1
+ done
+
+ return 0
+}
+
+# bool macchanger_pre_start(char *iface)
+#
+# Configures the MAC address for iface
+macchanger_pre_start() {
+ # We don't change MAC addresses from background
+ ${IN_BACKGROUND} && return 0
+
+ local iface="$1" mac opts ifvar=$( bash_variable "$1" )
+
+ eval mac=\"\$\{mac_${ifvar}\}\"
+ [[ -z ${mac} ]] && return 0
+
+ interface_exists "${iface}" true || return 1
+
+ ebegin "Changing MAC address of ${iface}"
+
+ 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
+ interface_set_mac_address "${iface}" "${mac}"
+ eend "$?"
+ if [[ $? == "0" ]]; then
+ mac=$( interface_get_mac_address "${iface}" )
+ 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) 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
+
+ # The interface needs to be up for macchanger to work most of the time
+ interface_down "${iface}"
+
+ mac=$( /sbin/macchanger ${opts} "${iface}" \
+ | sed -n -e 's/^Faked MAC:.*\<\(..:..:..:..:..:..\)\>.*/\U\1/p' )
+
+ # Sometimes the interface needs to be up ....
+ if [[ -z ${mac} ]]; then
+ interface_up "${iface}"
+ 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 #important
+}
+
+# vim:ts=4
diff --git a/lib/rcscripts/net.modules.d/macnet b/lib/rcscripts/net.modules.d/macnet
new file mode 100644
index 0000000..3ab8cd1
--- /dev/null
+++ b/lib/rcscripts/net.modules.d/macnet
@@ -0,0 +1,72 @@
+#!/bin/bash
+# Copyright (c) 2005 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+# Contributed by Roy Marples (uberlord@gentoo.org)
+# 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
+
+# void macnet_depend(void)
+#
+# Sets up the dependancies for the module
+macnet_depend() {
+ before interface wireless
+ after macchanger
+}
+
+# bool macnet_check_installed(void)
+#
+# Always returns 0 as we are "installed" by wireless in the depend function
+macnet_check_installed() {
+ return 0
+}
+
+# char* macnet_provides(void)
+#
+# Returns a string to change module definition for starting up
+macnet_provides() {
+ echo "macnet"
+}
+
+# bool macnet_check_depends(void)
+#
+# Checks to see if we have the needed functions
+macnet_check_depends() {
+ local f
+
+ for f in interface_get_mac_address; do
+ [[ $( type -t "${f}" ) == "function" ]] && continue
+ eerror "macnet: missing required function ${f}\n"
+ return 1
+ done
+
+ return 0
+}
+
+# bool macnet_start(char *iface)
+#
+# All interfaces and module scripts expose modulename_get_vars
+# which returns a space seperated list of user configuration variables
+# We can override each variable here from a given MAC address of the interface
+# Always returns 0
+macnet_pre_start() {
+ local iface="$1"
+
+ interface_exists "${iface}" || return 0
+
+ # We need to bring the interface up for some interfaces, otherwise the MAC
+ # address isn't consistent - mainly wireless cards with firmware uploading.
+ interface_up "${iface}"
+
+ local mac=$( interface_get_mac_address "${iface}" )
+ [[ -z ${mac} ]] && return 0
+
+ vebegin "Configuring ${iface} for MAC address ${mac}" 2>/dev/null
+ mac="${mac//:}"
+ configure_variables "${iface}" "${mac}"
+ veend 0 2>/dev/null
+
+ return 0
+}
+
+# vim:ts=4
diff --git a/lib/rcscripts/net.modules.d/netplug b/lib/rcscripts/net.modules.d/netplug
new file mode 100644
index 0000000..9f3b77d
--- /dev/null
+++ b/lib/rcscripts/net.modules.d/netplug
@@ -0,0 +1,123 @@
+#!/bin/bash
+# Copyright (c) 2004-2005 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+# Contributed by Roy Marples (uberlord@gentoo.org)
+
+# char* netplug_provides(void)
+#
+# Returns a string to change module definition for starting up
+netplug_provides() {
+ echo "netplug"
+}
+
+# void netplug_depend(void)
+#
+# Sets up the dependancies for the module
+netplug_depend() {
+ after macnet
+ before interface
+}
+
+# bool netplug_check_installed(void)
+#
+# Returns 0 if netplug is installed, otherwise 1
+netplug_check_installed() {
+ if [[ ! -x /sbin/netplugd ]]; then
+ ${1:-false} && eerror "For netplug support, emerge sys-apps/netplug"
+ return 1
+ fi
+ return 0
+}
+
+# bool netplug_check_depends(void)
+#
+# Checks to see if we have the needed functions
+netplug_check_depends() {
+ local f
+
+ for f in interface_exists; do
+ [[ $( type -t "${f}" ) == "function" ]] && continue
+ eerror "netplug: missing required function ${f}\n"
+ return 1
+ done
+
+ return 0
+}
+
+# bool netplug_pre_start(char *interface)
+#
+# Start netplug on an interface
+netplug_pre_start() {
+ local iface="$1" timeout i
+ local pidfile="/var/run/netplug.${iface}.pid"
+
+ # We don't start netplug if we're being called from the background
+ ${IN_BACKGROUND} && return 0
+
+ # We need a valid MAC address
+ # It's a basic test to ensure it's not a virtual interface
+ local mac=$(interface_get_mac_address "${iface}")
+ if [[ -z ${mac} ]]; then
+ vewarn "netplug only works on interfaces with a valid MAC address"
+ return 0
+ fi
+
+ # We don't work on wirelesss interfaces
+ if [[ $(type -t wireless_check_extensions) == "function" ]]; then
+ if wireless_check_extensions "${iface}"; then
+ veinfo "netplug does not work on wireless interfaces"
+ return 0
+ fi
+ fi
+
+ ebegin "Starting netplug on ${iface}"
+
+ # We need the interface up for netplug to listen to netlink events
+ interface_up "${iface}"
+
+ # Mark the us as inactive so netplug can restart us
+ mark_service_inactive "net.${iface}"
+
+ # Start netplug
+ start-stop-daemon --start --exec /sbin/netplugd \
+ --pidfile "${pidfile}" \
+ -- -i "${iface}" -P -p "${pidfile}" -c /dev/null
+ eend "$?" || return 1
+
+ eindent
+ veinfo "Waiting for ${iface} to be marked as started"
+
+ eval timeout=\"\$\{plug_timeout_${ifvar}\:-10}\"
+ [[ ${timeout} == "0" ]] \
+ && vewarn "WARNING: infinite timeout set for ${iface} to come up"
+
+ i=0
+ while true ; do
+ if service_started "net.${iface}"; then
+ local addr=$( interface_get_address "${iface}" )
+ einfo "${iface} configured with address ${addr}"
+ exit 0
+ fi
+ sleep 1
+ (( i++ ))
+ [[ ${i} == "${timeout}" || ${i} -gt "${timeout}" ]] && break
+ done
+
+ eend 1 "Failed to configure ${iface} in the background"
+ exit 0
+}
+
+# bool netplug_post_stop(char *iface)
+#
+# Stops netplug on an interface
+# Returns 0 (true) when successful, non-zero otherwise
+netplug_post_stop() {
+ ${IN_BACKGROUND} && return 0
+ ebegin "Stopping netplug on $1"
+ start-stop-daemon --stop --exec /sbin/netplugd \
+ --pidfile "/var/run/netplug.$1.pid"
+ eend $?
+}
+
+# vim:ts=4
diff --git a/lib/rcscripts/net.modules.d/pump b/lib/rcscripts/net.modules.d/pump
new file mode 100644
index 0000000..98ac556
--- /dev/null
+++ b/lib/rcscripts/net.modules.d/pump
@@ -0,0 +1,136 @@
+#!/bin/bash
+# Copyright (c) 2004-2005 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+# Contributed by Roy Marples (uberlord@gentoo.org)
+
+# Fix any potential localisation problems
+# Note that LC_ALL trumps LC_anything_else according to locale(7)
+pump() {
+ LC_ALL=C /sbin/pump "$@"
+}
+
+# char* pump_provides(void)
+#
+# Returns a string to change module definition for starting up
+pump_provides() {
+ echo "dhcp"
+}
+
+# void pump_depend(void)
+#
+# Sets up the dependancies for the module
+pump_depend() {
+ after interface
+}
+
+# bool pump_check_installed(void)
+#
+# Returns 1 if pump is installed, otherwise 0
+pump_check_installed() {
+ [[ -x /sbin/pump ]] && return 0
+ ${1:-false} && eerror "For DHCP (pump) support, emerge net-misc/pump"
+ return 1
+}
+
+# bool pump_check_depends(void)
+#
+# Checks to see if we have the needed functions
+pump_check_depends() {
+ local f
+
+ for f in interface_exists interface_get_address; do
+ [[ $( type -t "${f}" ) == "function" ]] && continue
+ eerror "pump: missing required function ${f}\n"
+ return 1
+ done
+
+ return 0
+}
+
+# char* pump_get_vars(char *interface)
+#
+# Returns a string spaced with possible user set
+# configuration variables
+pump_get_vars() {
+ echo "pump_$1 dhcp_$1"
+}
+
+# bool pump_stop(char *iface)
+#
+# Stop pump on an interface
+# Return 0 if pump is not running or we stop it successfully
+# Otherwise 1
+pump_stop() {
+ local iface="$1" count e
+
+ pump_check_installed || return 0
+
+ # We check for a pump process first as querying for status
+ # causes pump to spawn a process
+ pidof /sbin/pump &>/dev/null || return 0
+
+ # Check that pump is running on the interface
+ pump --status --interface "${iface}" 2>/dev/null \
+ | grep -q "^Device ${iface}" || return 0
+
+ # Pump always releases the lease
+ ebegin "Stopping pump on ${iface}"
+ pump --release --interface "${iface}"
+ eend "$?" "Failed to stop pump"
+ return "$?"
+}
+
+# bool pump_start(char *iface)
+#
+# Start pump on an interface by calling pumpcd $iface $options
+#
+# Returns 0 (true) when a dhcp address is obtained, otherwise
+# the return value from pump
+pump_start() {
+ local iface="$1" opts d ifvar=$( bash_variable "$1" ) search
+
+ interface_exists "${iface}" true || return 1
+
+ eval opts=\" \$\{pump_${ifvar}\} \"
+
+ # Map some generic options to pump
+ eval d=\" \$\{dhcp_${ifvar}\} \"
+ [[ ${d} == " " ]] && d=" ${dhcp} "
+ [[ ${d} == *" nodns "* ]] && opts="${opts} --no-dns"
+ [[ ${d} == *" nogateway "* ]] && opts="${opts} --no-gateway"
+ [[ ${d} == *" nontp "* ]] && opts="${opts} --no-ntp"
+
+ eval search=\"\$\{dns_search_path_${ifvar}\}\"
+ [[ -n ${search} ]] && opts="${opts} --search-path='"${search}"'"
+
+ # Add our route metric
+ eval metric=\"\$\{metric_${ifvar}\}\"
+ [[ -n ${metric} ]] && opts="${opts} --route-metric ${metric}"
+
+ [[ ! -d "${statedir}/${iface}" ]] && mkdir -m 0755 -p "${statedir}/${iface}"
+
+ opts="${opts} --win-client-ident --etc-dir=${statedir}/${iface}"
+ opts="${opts} --script /lib/rcscripts/net.modules.d/helpers.d/pump-wrapper"
+ opts="${opts} --keep-up --interface ${iface}"
+
+ # Bring up DHCP for this interface (or alias)
+ ebegin "Running pump"
+
+ if [[ ${background} == "yes" ]]; then
+ eval pump ${opts} &
+ eend 0
+ go_background
+ fi
+
+ eval pump ${opts}
+ eend "$?" || return "$?"
+
+ # pump succeeded, show address retrieved
+ local addr=$( interface_get_address "${iface}" )
+ einfo "${iface} received address ${addr}"
+
+ return 0
+}
+
+# vim:ts=4
diff --git a/lib/rcscripts/net.modules.d/rename b/lib/rcscripts/net.modules.d/rename
new file mode 100644
index 0000000..ddab8b0
--- /dev/null
+++ b/lib/rcscripts/net.modules.d/rename
@@ -0,0 +1,86 @@
+#!/bin/bash
+# Copyright (c) 2005 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+# Contributed by Roy Marples (uberlord@gentoo.org)
+
+# char* rename_provides(void)
+#
+# Returns a string to change module definition for starting up
+rename_provides() {
+ echo "rename"
+}
+
+# void rename_depend(void)
+#
+# Sets up the dependancies for the module
+rename_depend() {
+ after macchanger macnet
+ before wireless interface
+}
+
+# bool rename_check_installed(void)
+#
+# We are always installed
+rename_check_installed() {
+ return 0
+}
+
+# bool rename_check_depends(void)
+#
+# Checks to see if we have the needed functions
+rename_check_depends() {
+ return 0
+}
+
+# char* rename_get_vars(char *interface)
+#
+# Returns a string spaced with possible user set
+# configuration variables
+rename_get_vars() {
+ echo "rename_$1"
+}
+
+# bool rename_pre_start(char *iface)
+#
+# Checks to see if we have to rename the interface
+rename_pre_start() {
+ local iface="$1" newname="" mac ifvar=$( bash_variable "$1" )
+
+ interface_exists "${iface}" || return 0
+
+ eval newname=\"\$\{rename_${ifvar}\}\"
+ [[ -z ${newname} || ${iface} == "${newname}" ]] && return 0
+
+ # We cannot rename vlan interfaces as /proc/net/vlan/config always
+ # returns the old interface name. We don't bail out though as it's
+ # not critical that the interface gets renamed.
+ if [[ -d /proc/net/vlan/config ]] ; then
+ if grep -q "^eth0.2 " /proc/net/vlan/config ; then
+ eerror "Cannot rename VLAN interfaces"
+ return 0
+ fi
+ fi
+
+ ebegin "Renaming \"${iface}\" to \"${newname}\""
+
+ # Ensure that we have an init script
+ [[ ! -e "/etc/init.d/net.${newname}" ]] \
+ && ( cd /etc/init.d ; ln -s net.lo "net.${newname}" )
+
+ # Ensure that the interface is down and without any addresses or we
+ # will not work
+ interface_del_addresses "${iface}"
+ interface_down "${iface}"
+ interface_set_name "${iface}" "${newname}"
+ eend "$?" "Failed to rename interface" || return 1
+
+ # Mark us as stopped, start the new interface and bail cleanly
+ mark_service_stopped "net.${iface}"
+ einfo "Stopped configuration of ${iface} due to renaming"
+ service_stopped "net.${newname}" && start_service "net.${newname}"
+
+ exit 1
+}
+
+# vim:ts=4
diff --git a/lib/rcscripts/net.modules.d/system b/lib/rcscripts/net.modules.d/system
new file mode 100644
index 0000000..d6b6f46
--- /dev/null
+++ b/lib/rcscripts/net.modules.d/system
@@ -0,0 +1,134 @@
+#!/bin/bash
+# Copyright (c) 2005 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+# void system_depend(void)
+#
+# Sets up the dependancies for the module
+system_depend() {
+ after interface essidnet
+ before dhcp
+}
+
+# bool system_check_installed(void)
+#
+# Always returns 0 as we are writing to files
+system_check_installed() {
+ return 0
+}
+
+# char* system_provides(void)
+#
+# Returns a string to change module definition for starting up
+system_provides() {
+ echo "system"
+}
+
+# bool system_check_depends(void)
+#
+# Checks to see if we have the needed functions
+system_check_depends() {
+ return 0
+}
+
+# char* ifconfig_get_vars(char *interface)
+#
+# Returns a string spaced with possible user set configuration variables
+system_get_vars() {
+ echo "dns_servers_$1 dns_domain_$1 dns_search_path_$1 ntp_servers_$1 nis_domain_$1 nis_servers_$1"
+}
+
+system_dns() {
+ local iface="$1" ifvar=$( bash_variable "$1" ) x
+ local conffile="${statedir}/${iface}/resolv.conf" tmpfile="${conffile}.$$"
+ local -a servers
+
+ eval servers=( \"\$\{dns_servers_${ifvar}\[@\]\}\" )
+ [[ -z ${servers} ]] && return 0
+
+ echo "# Generated by net-scripts for interface ${iface}" > "${tmpfile}"
+ chmod 644 "${tmpfile}"
+
+ eval x=\"\$\{dns_domain_${ifvar}\}\"
+ [[ -n ${x} ]] && echo "domain ${x}" >> "${tmpfile}"
+
+ for x in ${servers[@]}; do
+ echo "nameserver ${x}" >> "${tmpfile}"
+ done
+
+ eval x=\"\$\{dns_search_path_${ifvar}\}\"
+ [[ -n ${x} ]] && echo "search ${x}" >> "${tmpfile}"
+
+ mv "${tmpfile}" "${conffile}"
+}
+
+system_ntp() {
+ local iface="$1" ifvar=$( bash_variable "$1" ) x
+ local conffile="${statedir}/${iface}/ntp.conf" tmpfile="${conffile}.$$"
+ local -a servers
+
+ eval servers=( \"\$\{ntp_servers_${ifvar}\[\@\]\}\" )
+ [[ -z ${servers} ]] && return 0
+
+ echo "# Generated by net-scripts for interface ${iface}" > "${tmpfile}"
+ chmod 644 "${tmpfile}"
+
+ echo "restrict default noquery notrust nomodify" >> "${tmpfile}"
+ echo "restrict 127.0.0.1" >> "${tmpfile}"
+
+ for x in ${servers[@]}; do
+ echo "restrict ${x} nomodify notrap noquery" >> "${tmpfile}"
+ echo "server ${x}" >> "${tmpfile}"
+ done
+
+ echo "driftfile /var/lib/ntp/ntp.drift" >> "${tmpfile}"
+ echo "logfile /var/log/ntp.log" >> "${tmpfile}"
+
+ mv "${tmpfile}" "${conffile}"
+}
+
+system_nis() {
+ local iface="$1" ifvar=$( bash_variable "$1" ) domain x
+ local conffile="${statedir}/${iface}/yp.conf" tmpfile="${conffile}.$$"
+ local -a servers
+
+ eval servers=( \"\$\{nis_servers_${ifvar}\[\@\]\}\" )
+ eval domain=\"\$\{nis_domain_${ifvar}\}\"
+ [[ -z ${servers} && -z ${domain} ]] && return 0
+
+ echo "# Generated by net-scripts for interface ${iface}" > "${tmpfile}"
+ chmod 644 "${tmpfile}"
+
+ if [[ -n ${domain} ]]; then
+ /bin/hostname -y "${domain}"
+ if [[ -n ${servers} ]]; then
+ for x in ${servers}; do
+ echo "domain ${domain} server ${x}" >> "${tmpfile}"
+ done
+ else
+ echo "domain ${domain} broadcast" >> "${tmpfile}"
+ fi
+ else
+ for x in ${servers}; do
+ echo "ypserver ${x}" >> "${tmpfile}"
+ done
+ fi
+
+ mv "${tmpfile}" "${conffile}"
+}
+
+# bool system_post_start(char *iface)
+#
+# Configures the host system for dns, ntp and nis information
+# Always returns 0
+system_post_start() {
+ local iface="$1"
+
+ system_dns "${iface}"
+ system_ntp "${iface}"
+ system_nis "${iface}"
+
+ return 0
+}
+
+# vim:ts=4
diff --git a/lib/rcscripts/net.modules.d/tuntap b/lib/rcscripts/net.modules.d/tuntap
new file mode 100644
index 0000000..150b892
--- /dev/null
+++ b/lib/rcscripts/net.modules.d/tuntap
@@ -0,0 +1,116 @@
+#!/bin/bash
+# Copyright (c) 2004-2005 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+# Contributed by Roy Marples (uberlord@gentoo.org)
+
+# Fix any potential localisation problems
+# Note that LC_ALL trumps LC_anything_else according to locale(7)
+tunctl() {
+ LC_ALL=C /usr/bin/tunctl "$@"
+}
+
+# char* tuntap_provides(void)
+#
+# Returns a string to change module definition for starting up
+tuntap_provides() {
+ echo "tuntap"
+}
+
+# void tuntap_depend(void)
+#
+# Sets up the dependancies for the module
+tuntap_depend() {
+ after interface
+ before dhcp
+}
+
+# bool tuntap_check_installed(void)
+#
+# Returns 1 if tuntap is installed, otherwise 0
+tuntap_check_installed() {
+ [[ -x /usr/bin/tunctl ]] && return 0
+ ${1:-false} && eerror "For TunTap support, emerge sys-apps/usermode-utilities"
+ return 1
+}
+
+# bool tuntap_check_depends(void)
+#
+# Checks to see if we have the needed functions
+tuntap_check_depends() {
+ local f
+
+ for f in interface_exists interface_type; do
+ [[ $( type -t "${f}" ) == "function" ]] && continue
+ eerror "tuntap: missing required function ${f}\n"
+ return 1
+ done
+
+ return 0
+}
+
+# bool tuntap_check_kernel(void)
+#
+# Checks to see if the tun is present - if not try and load it
+# Returns 1 if there is a problem
+tuntap_check_kernel() {
+ [[ -a /dev/net/tun ]] && return 0
+ /sbin/modprobe tun && sleep 1
+ [[ -a /dev/net/tun ]] && return 0
+ eerror "TUN/TAP support is not present in this kernel"
+ return 1
+}
+
+# char* tuntap_get_vars(char *interface)
+#
+# Returns a string spaced with possible user set
+# configuration variables
+tuntap_get_vars() {
+ echo "tunctl_$1"
+}
+
+# bool tuntap_pre_start(char *iface)
+#
+# Create the device, give it the right perms
+tuntap_pre_start() {
+ local iface="$1" opts ifvar=$( bash_variable "$1" )
+ local itype=$( interface_type "${iface}" )
+
+ # Check that we are a valid tun/tap interface
+ # NOTE - the name can be anything as we define it
+ # but for simplicity in the config we require either
+ # tun or tap
+ [[ ${itype} != "tun" && ${itype} != "tap" ]] && return 0
+
+ tuntap_check_kernel || return 1
+
+ # Get our options
+ eval opts=\"\$\{tunctl_${ifvar}\}\"
+
+ ebegin "Creating Tun/Tap interface ${iface}"
+ tunctl ${opts} -t "${iface}"
+ eend "$?" || return 1
+
+ return 0
+}
+
+# bool tuntap_stop(char *iface)
+#
+# Removes the device
+tuntap_stop() {
+ local iface="$1"
+
+ tuntap_check_installed || return 0
+ interface_exists "${iface}" || return 0
+
+ # tunctl doesn't always error on on tun/tap
+ # interfaces (mainly aliases, etc)
+ if tunctl -d "${iface}" &>/dev/null ; then
+ interface_exists "${iface}" \
+ || einfo "Destroyed Tun/Tap interface ${iface}"
+ fi
+
+ return 0
+}
+
+# vim:ts=4
diff --git a/lib/rcscripts/net.modules.d/udhcpc b/lib/rcscripts/net.modules.d/udhcpc
new file mode 100644
index 0000000..25596c5
--- /dev/null
+++ b/lib/rcscripts/net.modules.d/udhcpc
@@ -0,0 +1,153 @@
+#!/bin/bash
+# Copyright (c) 2004-2005 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+# Contributed by Roy Marples (uberlord@gentoo.org)
+
+# Fix any potential localisation problems
+# Note that LC_ALL trumps LC_anything_else according to locale(7)
+udhcpc() {
+ LC_ALL=C /sbin/udhcpc "$@"
+}
+
+# char* udhcpc_provides(void)
+#
+# Returns a string to change module definition for starting up
+udhcpc_provides() {
+ echo "dhcp"
+}
+
+# void udhcpc_depend(void)
+#
+# Sets up the dependancies for the module
+udhcpc_depend() {
+ after interface
+}
+
+# bool udhcpc_check_installed(void)
+#
+# Returns 1 if udhcpc is installed, otherwise 0
+udhcpc_check_installed() {
+ [[ -x /sbin/udhcpc ]] && return 0
+ ${1:-false} && eerror "For DHCP (udhcpc) support, emerge net-misc/udhcp"
+ return 1
+}
+
+# bool udhcpc_check_depends(void)
+#
+# Checks to see if we have the needed functions
+udhcpc_check_depends() {
+ local f
+
+ for f in interface_exists interface_get_address; do
+ [[ $( type -t "${f}" ) == "function" ]] && continue
+ eerror "udhcpc: missing required function ${f}\n"
+ return 1
+ done
+
+ return 0
+}
+
+# char* udhcpc_get_vars(char *interface)
+#
+# Returns a string spaced with possible user set
+# configuration variables
+udhcpc_get_vars() {
+ echo "udhcpc_$1 dhcp_$1"
+}
+
+# bool udhcpc_stop(char *iface)
+#
+# Stops udhcpc running on an interface
+# Return 1 if we fail to stop udhcpc (if it's running) otherwise 0
+udhcpc_stop() {
+ local iface="$1" pidfile="/var/run/udhcpc-$1.pid" d
+
+ udhcpc_check_installed || return 0
+ [[ ! -f ${pidfile} ]] && return 0
+
+ ebegin "Stopping udhcpc on ${iface}"
+ local pid=$( < "${pidfile}" ) e=true
+
+ local ifvar=$( bash_variable "${iface}" )
+ eval d=\" \$\{dhcp_${ifvar}\} \"
+ [[ ${d} == " " ]] && d=" ${dhcp} "
+
+ if [[ ${d} == *" release "* ]]; then
+ kill -s USR2 "${pid}" &>/dev/null
+ [[ -f "/var/cache/dhcp-${iface}.lease" ]] \
+ && rm "/var/cache/dhcp-${iface}.lease"
+ fi
+
+ kill -s TERM "${pid}" &>/dev/null
+
+ [[ -f ${pidfile} ]] && rm -f "${pidfile}"
+
+ ${e}
+ eend "$?"
+ return "$?"
+}
+
+# bool udhcpc_start(char *iface)
+#
+# Start DHCP on an interface by calling udhcpc $iface $options
+#
+# Returns 0 (true) when a DHCP address is obtained, otherwise 1
+udhcpc_start() {
+ local iface="$1" opts pidfile="/var/run/udhcpc-$1.pid"
+ local cachefile="/var/cache/dhcp-$1.lease" d
+
+ interface_exists "${iface}" true || return 1
+
+ local ifvar=$( bash_variable "${iface}" ) opts hostname
+ eval opts=\"\$\{udhcpc_${ifvar}\}\"
+
+ eval d=\" \$\{dhcp_${ifvar}\} \"
+ [[ ${d} == " " ]] && d=" ${dhcp} "
+
+ if [[ ${d} != *" nosendhost "* ]]; then
+ if [[ ! " ${opts}" =~ " -([hH] |-hostname=)" ]]; then
+ local hostname=$( hostname )
+ [[ -n ${hostname} && ${hostname} != "(none)" \
+ && ${hostname} != "localhost" ]] \
+ && opts="${opts} --hostname=${hostname}"
+ fi
+ fi
+
+ # Bring up DHCP for this interface (or alias)
+ ebegin "Running udhcpc"
+
+ # Stop any instance of udhcpc on this interface
+ udhcpc_stop "${interface}"
+
+ # Try and load the cache if it exists
+ if [[ -f ${cachefile} ]]; then
+ if [[ " ${opts}" != *" --request="* && " ${opts} " != *" -r "* ]]; then
+ local x=$( < "${cachefile}" )
+ [[ -n ${x} ]] && opts="${opts} --request=${x}"
+ fi
+ fi
+
+ if [[ ${background} == "yes" ]]; then
+ eval udhcpc ${opts} --script="${MODULES_DIR}/helpers.d/udhcpc-wrapper" \
+ --pidfile="${pidfile}" --interface="${iface}" &>/dev/null &
+ eend 0
+ go_background
+ fi
+
+ x=$( eval udhcpc ${opts} --now --pidfile="${pidfile}" \
+ --interface="${iface}" \
+ --script="${MODULES_DIR}/helpers.d/udhcpc-wrapper" 2>&1 \
+ | egrep -v '^info,' )
+ # We just check the last 5 letters
+ [[ ${x:((${#x} - 5)):5} == "bound" ]]
+ eend "$?" "${x}" || return 1
+
+ # DHCP succeeded, show address retrieved
+ local addr=$( interface_get_address "${iface}" )
+ einfo "${iface} received address ${addr}"
+
+ return 0
+}
+
+# vim:ts=4
diff --git a/lib/rcscripts/net.modules.d/vlan b/lib/rcscripts/net.modules.d/vlan
new file mode 100644
index 0000000..c154a93
--- /dev/null
+++ b/lib/rcscripts/net.modules.d/vlan
@@ -0,0 +1,167 @@
+#!/bin/bash
+# Copyright (c) 2004-2005 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+# Contributed by Roy Marples (uberlord@gentoo.org)
+
+# Fix any potential localisation problems
+# Note that LC_ALL trumps LC_anything_else according to locale(7)
+vconfig() {
+ LC_ALL=C /sbin/vconfig "$@"
+}
+
+# char* vlan_provides(void)
+#
+# Returns a string to change module definition for starting up
+vlan_provides() {
+ echo "vlan"
+}
+
+# void vlan_depend(void)
+#
+# Sets up the dependancies for the module
+vlan_depend() {
+ after interface
+ before apipa dhcp
+}
+
+# bool vlan_check_installed(void)
+#
+# Returns 1 if vconfig is installed, otherwise 0
+vlan_check_installed() {
+ [[ -x /sbin/vconfig ]] && return 0
+ ${1:-false} && eerror "For VLAN (802.1q) support, emerge net-misc/vconfig"
+ return 1
+}
+
+# bool vlan_check_depends(void)
+#
+# Checks to see if we have the needed functions
+vlan_check_depends() {
+ local f
+
+ for f in iface_start iface_stop; do
+ [[ $( type -t "${f}" ) == function ]] && continue
+ eerror "vlan: missing required function ${f}\n"
+ return 1
+ done
+
+ return 0
+}
+
+# char* vlan_get_vars(char *interface)
+#
+# Returns a string spaced with possible user set
+# configuration variables
+vlan_get_vars() {
+ echo "vlans_$1 iface_$1_vlans"
+}
+
+# char* vlan_get_vlans(char *interface)
+#
+# Fetch the configured vlans for an interface. Outputs a space
+# separated list on stdout. For example "eth0.1 eth0.2 eth0.3"
+vlan_get_vlans() {
+ sed -n -e 's/^\(.*[0-9]\) \(.* \) .*'"$1"'$/\1/p' \
+ /proc/net/vlan/config 2>/dev/null
+}
+
+# bool vlan_check_kernel(void)
+#
+# Checks to see if the 802.1q module is present - if not try and load it
+# Returns 1 if there is a problem
+vlan_check_kernel() {
+ [[ -d /proc/net/vlan ]] && return 0
+ /sbin/modprobe 8021q &>/dev/null
+ [[ -d /proc/net/vlan ]] && return 0
+ eerror "VLAN (802.1q) support is not present in this kernel"
+ return 1
+}
+
+#bool vlan_pre_start(char *iface)
+#
+# Setup vconfig
+vlan_pre_start() {
+ local iface="$1" opts i x e ifvar=$( bash_variable "$1" )
+
+ eval opts=( \"\$\{vconfig_${ifvar}\[@\]\}\" )
+ [[ -z ${opts} ]] && return 0
+
+ vlan_check_kernel || return 1
+
+ for (( i=0; i<${#opts[@]}; i++ )); do
+ if [[ ${opts[i]} == "set_name_type "* ]]; then
+ x="${opts[i]}"
+ else
+ x="${opts[i]/ / ${iface} }"
+ [[ ${x} == "${opts[i]}" ]] && x="${x} ${iface}"
+ fi
+ e=$( vconfig ${x} 2>&1 1>/dev/null )
+ [[ -z ${e} ]] && continue
+ eerror "vconfig ${x}"
+ eerror "${e}"
+ return 1
+ done
+
+ return 0
+}
+
+# bool vlan_post_start(char *iface)
+#
+# Starts VLANs for a given interface
+#
+# Always returns 0 (true)
+vlan_post_start() {
+ local iface="$1" vlan vlans vlans_old e ifname ifvar=$( bash_variable "$1" )
+
+ eval vlans=\"\$\{vlans_${ifvar}\}\"
+
+ # BACKWARD COMPATIBILITY: check for old vlan variable name
+ eval vlans_old=\"\$\{iface_${ifvar}_vlans\}\"
+ [[ -n ${vlans_old} && -z ${vlans} ]] && vlans="${vlans_old}"
+
+ [[ -z ${vlans} ]] && return 0
+
+ vlan_check_kernel || return 1
+
+ # Start vlans for this interface
+ for vlan in ${vlans}; 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
+ eend 0
+
+ # We need to work out the interface name of our new vlan id
+ ifname=$( \
+ sed -n -e 's/^\([^ \t]*\) *| '"${vlan}"' *| .*'"${iface}"'$/\1/p' \
+ /proc/net/vlan/config
+ )
+ iface_start "${ifname}"
+ done
+
+ return 0
+}
+
+# bool vlan_pre_stop(char *iface)
+#
+# Stops VLANs for a given interface
+#
+# Always returns 0 (true)
+vlan_pre_stop() {
+ local iface="$1" vlan
+
+ vlan_check_installed || return 0
+
+ for vlan in $( vlan_get_vlans "${iface}" ); do
+ einfo "Removing VLAN ${vlan##*.} from ${iface}"
+ iface_stop "${vlan}"
+ vconfig rem "${vlan}" >/dev/null
+ done
+
+ return 0
+}
+
+# vim:ts=4
diff --git a/lib/rcscripts/net.modules.d/wpa_supplicant b/lib/rcscripts/net.modules.d/wpa_supplicant
new file mode 100644
index 0000000..f48cf44
--- /dev/null
+++ b/lib/rcscripts/net.modules.d/wpa_supplicant
@@ -0,0 +1,350 @@
+#!/bin/bash
+# Copyright (c) 2004-2005 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+# Contributed by Roy Marples (uberlord@gentoo.org)
+
+# Fix any potential localisation problems
+# Note that LC_ALL trumps LC_anything_else according to locale(7)
+wpa_supplicant() {
+ LC_ALL=C /sbin/wpa_supplicant "$@"
+}
+
+wpa_cli() {
+ LC_ALL=C /bin/wpa_cli "$@"
+}
+
+# char* wpa_supplicant_provides(void)
+#
+# Returns a string to change module definition for starting up
+wpa_supplicant_provides() {
+ echo "wireless"
+}
+
+# void wpa_supplicant_depend(void)
+#
+# Sets up the dependancies for the module
+wpa_supplicant_depend() {
+ after macnet
+ before interface
+}
+
+# bool wpa_supplicant_check_installed(void)
+#
+# Returns 0 if wpa_supplicant is installed, otherwise 1
+wpa_supplicant_check_installed() {
+ local report="${1:-false}" installed="0"
+ if [[ ! -x /sbin/wpa_supplicant ]]; then
+ installed="1"
+ ${report} && eerror "For WPA support (wpa_supplicant) support, emerge net-wireless/wpa_supplicant"
+ fi
+ if [[ ! -e /proc/net/packet ]]; then
+ installed="1"
+ ${report} && eerror "wpa_supplicant requires Packet Socket (CONFIG_PACKET=y) enabled in the kernel"
+ fi
+ return "${installed}"
+}
+
+# bool wpa_supplicant_check_depends(void)
+#
+# Checks to see if we have the needed functions
+wpa_supplicant_check_depends() {
+ local f
+
+ for f in interface_exists; do
+ [[ $( type -t "${f}" ) == "function" ]] && continue
+ eerror "wpa_supplicant: missing required function ${f}\n"
+ return 1
+ done
+
+ return 0
+}
+
+# bool wpa_supplicant_check_extensions(char *interface)
+#
+# Checks to see if wireless extensions are enabled on the interface
+wpa_supplicant_check_extensions() {
+ grep -q "^[ \t]*$1:[ \t]" /proc/net/wireless
+}
+
+# char* wpa_supplicant_get_essid(char *interface)
+#
+# Gets the current ESSID of iface
+wpa_supplicant_get_essid() {
+ local i essid
+
+ for (( i=0; i<5; i++ )); do
+ essid=$( wpa_cli -i"$1" status | sed -n -e 's/^ssid=//p' )
+ if [[ -n ${essid} ]]; then
+ echo "${essid}"
+ return 0
+ fi
+ sleep 1
+ done
+
+ return 1
+}
+
+# char* wpa_supplicant_get_ap_mac_address(char *interface)
+#
+# Returns the MAC address of the Access Point
+# the interface is connected to
+wpa_supplicant_get_ap_mac_address() {
+ wpa_cli -i"$1" status | sed -n -e 's/^bssid=\([^=]\+\).*/\U\1/p'
+}
+
+# bool wpa_supplicant_associated(char *interface)
+#
+# Returns 0 if we're associated correctly or 1 if not
+# Note that just because we are associated does not mean we are using the
+# correct encryption keys
+# We only need this for wpa_supplicant-0.3.x
+wpa_supplicant_associated() {
+ local -a status=( "$( wpa_cli -i"$1" status | sed -n -e 's/^\(key_mgmt\|wpa_state\|EAP state\)=\([^=]\+\).*/\U\2/p' )" )
+
+ case "${status[0]}" in
+ "NONE") [[ ${status[1]} == "ASSOCIATED" ]] ;;
+ "IEEE 802.1X (no WPA)") [[ ${status[2]} == "SUCCESS" ]] ;;
+ *) [[ ${status[1]} == "COMPLETED" ]] ;;
+ esac
+
+ return $?
+}
+
+# void wpa_supplicant_kill(char *interface, bool report)
+#
+# Kills any existing wpa_supplicant process on the interface
+wpa_supplicant_kill() {
+ local iface="$1" report="${2:-false}" pidfile
+
+ # Shutdown wpa_cli first, if it's running
+ # This is important as future versions of wpa_supplicant
+ # may send a disconnect message to wpa_cli when it shutsdown
+ pidfile="/var/run/wpa_cli-${iface}.pid"
+ if ! clean_pidfile "${pidfile}" ; then
+ ${report} && ebegin "Stopping wpa_cli on ${iface}"
+ start-stop-daemon --stop --exec /bin/wpa_cli \
+ --pidfile "${pidfile}"
+ ${report} && eend "$?"
+ fi
+
+ # Now shutdown wpa_supplicant
+ pidfile="/var/run/wpa_supplicant-${iface}.pid"
+ if ! clean_pidfile "${pidfile}" ; then
+ ${report} && ebegin "Stopping wpa_supplicant on ${iface}"
+ start-stop-daemon --stop --exec /sbin/wpa_supplicant \
+ --pidfile "${pidfile}"
+ ${report} && eend "$?"
+ else
+ # Support wpa_supplicant-0.3.x
+ local pid=$( pgrep -f '^/sbin/wpa_supplicant .* -i'"${iface}"'[ ]*$' )
+ if [[ -n ${pid} ]]; then
+ ${report} && ebegin "Stopping wpa_supplicant on ${iface}"
+ kill -s TERM "${pid}"
+ ${report} && eend 0
+ fi
+ 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}"
+}
+
+# bool wpa_supplicant_associate(char *interface)
+#
+# Returns 0 if wpa_supplicant associates and authenticates to an AP
+# otherwise, 1
+wpa_supplicant_associate() {
+ local iface="$1" ifvar=$( bash_variable "$1" ) timeout i
+ eval timeout=\"\$\{associate_timeout_${ifvar}\}\"
+ [[ -z ${timeout} ]] && eval timeout=\"\$\{wpa_timeout_${ifvar}:-60\}\"
+
+ [[ ${timeout} == "0" ]] \
+ && vewarn "WARNING: infinite timeout set for association on ${iface}"
+
+ while true ; do
+ if ${action} ; then
+ service_started "net.${iface}" && return 0
+ else
+ if ! wpa_cli -i"${iface}" status &>/dev/null ; then
+ eend 1 "wpa_supplicant has exited unexpectedly"
+ return 1
+ fi
+ wpa_supplicant_associated "${iface}" && return 0
+ fi
+ sleep 1
+ (( i++ ))
+ [[ ${i} == "${timeout}" || ${i} -gt "${timeout}" ]] && break
+ done
+
+ # Spit out an appropriate error
+ if [[ ${background} != "yes" ]]; then
+ if ${action} ; then
+ eend 1 "Failed to configure ${iface} in the background"
+ else
+ eend 1 "Timed out"
+ fi
+ fi
+
+ # exit without error with wpa_supplicant-0.4.x as we may get kickstarted
+ # when an AP comes in range
+ ${action} && exit 0
+
+ # Kill wpa_supplicant for 0.3.x
+ wpa_supplicant_kill "${iface}"
+ return 1
+}
+
+# bool wpa_supplicant_pre_start(char *interface)
+#
+# Start wpa_supplicant on an interface and wait for association
+# Returns 0 (true) when successful, non-zero otherwise
+wpa_supplicant_pre_start() {
+ local iface="$1" opts timeout action=false
+ local cfgfile="/etc/wpa_supplicant.conf"
+ local actfile="/sbin/wpa_cli.action"
+
+ # We don't configure wireless if we're being called from
+ # the background
+ if ${IN_BACKGROUND} ; then
+ ESSID=$( wpa_supplicant_get_essid "${iface}" )
+ ESSIDVAR=$( bash_variable "${ESSID}" )
+ save_options "ESSID" "${ESSID}"
+ return 0
+ fi
+
+ save_options "ESSID" ""
+
+ # We only work on wirelesss interfaces
+ wpa_supplicant_check_extensions "${iface}" || return 0
+
+ # Kill off any existing wpa_supplicant on this interface
+ # This is so we can re-read the configuration file and clean any stale
+ # directories
+ wpa_supplicant_kill "${iface}" true
+
+ # 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 [[ $( < "/sys/class/net/${iface}/device/rf_kill" ) != 0 ]]; then
+ eerror "Wireless radio has been killed for interface ${iface}"
+ return 1
+ fi
+ fi
+
+ # If wireless-tools is installed, try and apply our user config
+ # This is needed for some drivers - such as hostap because they start
+ # the card in Master mode which causes problems with wpa_supplicant.
+ if [[ $( type -t iwconfig_defaults ) == "function" ]]; then
+ iwconfig_defaults "${iface}"
+ iwconfig_user_config "${iface}"
+ fi
+
+ ebegin "Starting wpa_supplicant on ${iface}"
+
+ if [[ ! -f ${cfgfile} ]]; then
+ eend 1 "configuration file ${cfgfile} not found!"
+ return 1
+ fi
+
+ local ctrl_dir=$( sed -n -e 's/[ \t]*#.*//g;s/[ \t]*$//g;s/^ctrl_interface=//p' "${cfgfile}" )
+ if [[ ${ctrl_dir} != "/var/run/wpa_supplicant" ]]; then
+ eerror "${cfgfile} must set"
+ eerror " ctrl_interface=/var/run/wpa_supplicant"
+ eend 1
+ return 1
+ fi
+
+ local ifvar=$( bash_variable "${iface}" )
+ eval opts=\" \$\{wpa_supplicant_${ifvar}\}\"
+ [[ ${opts} != *" -D"* ]] \
+ && ewarn "wpa_supplicant_${ifvar} does not define a driver"
+
+ # Some drivers require the interface to be up
+ interface_up "${iface}"
+
+ version=$( wpa_cli -v | sed -n -e 's/wpa_cli v//p' )
+ version=( ${version//./ } )
+ (( version = version[0] * 1000 + version[1] * 100 + version[2] ))
+
+ # wpa_supplicant 0.4.0 and greater supports wpa_cli actions
+ # This is very handy as if and when different association mechanisms are
+ # introduced to wpa_supplicant we don't have to recode for them as
+ # wpa_cli is now responsible for informing us of success/failure.
+ # The downside of this is that we don't see the interface being configured
+ # for DHCP/static.
+ if [[ ${version} -gt 399 && -x ${actfile} ]]; then
+ opts="${opts} -W -P/var/run/wpa_supplicant-${iface}.pid"
+ action=true
+ [[ ${RC_PARALLEL_STARTUP} == "yes" ]] && background=no
+ fi
+
+ start-stop-daemon --start --exec /sbin/wpa_supplicant \
+ -- ${opts} -B -c/etc/wpa_supplicant.conf -i"${iface}"
+ eend "$?" || return 1
+
+ # Starting wpa_supplication-0.4.0, we can get wpa_cli to
+ # start/stop our scripts from wpa_supplicant messages
+ if ${action} ; then
+ mark_service_inactive "net.${iface}"
+ ebegin "Starting wpa_cli on ${iface}"
+ start-stop-daemon --start --exec /bin/wpa_cli \
+ -- -a"${actfile}" -i"${iface}" \
+ -P"/var/run/wpa_cli-${iface}.pid" -B
+ eend "$?" || return 1
+ fi
+
+ # Background wpa_supplication if required
+ if [[ ${background} == "yes" ]]; then
+ if ! ${action} ; then
+ wpa_supplicant_associate "${iface}" \
+ && export IN_BACKGROUND=true \
+ && /etc/init.d/net.${iface} start >/dev/null &
+ fi
+ go_background
+ fi
+
+ eindent
+ veinfo "Waiting for association"
+ eend 0
+
+ wpa_supplicant_associate "${iface}" || return 1
+
+ # Set ESSID for essidnet and report
+ ESSID=$( wpa_supplicant_get_essid "${iface}" )
+ ESSIDVAR=$( bash_variable "${ESSID}" )
+ save_options "ESSID" "${ESSID}"
+
+ local -a status=( "$( wpa_cli -i${iface} status | sed -n -e 's/^\(bssid\|pairwise_cipher\|key_mgmt\)=\([^=]\+\).*/\U\2/p' | tr '[:lower:]' '[:upper:]' )" )
+ einfo "${iface} connected to \"${ESSID//\\\\/\\\\}\" at ${status[0]}"
+
+ if [[ ${status[2]} == "NONE" ]]; then
+ if [[ ${status[1]} == "NONE" ]]; then
+ ewarn "not using any encryption"
+ else
+ veinfo "using ${status[1]}"
+ fi
+ else
+ veinfo "using ${status[2]}/${status[1]}"
+ fi
+ eoutdent
+
+ if ${action} ; then
+ local addr=$( interface_get_address "${iface}" )
+ einfo "${iface} configured with address ${addr}"
+ exit 0
+ fi
+
+ return 0
+}
+
+# bool wpa_supplicant_post_stop(char *iface)
+#
+# Stops wpa_supplicant on an interface
+# Returns 0 (true) when successful, non-zero otherwise
+wpa_supplicant_post_stop() {
+ ! ${IN_BACKGROUND} && wpa_supplicant_kill "$1" true
+ return 0
+}
+
+# vim:ts=4
diff --git a/man/MAKEDEV.8 b/man/MAKEDEV.8
new file mode 100644
index 0000000..b3c9b84
--- /dev/null
+++ b/man/MAKEDEV.8
@@ -0,0 +1,392 @@
+.\" $Id: MAKEDEV.8 334 2003-03-09 09:06:23Z azarah $
+.TH MAKEDEV 8 "14th August 1994" Linux "Linux Programmer's Manual"
+.SH NAME
+MAKEDEV \- create devices
+.SH SYNOPSIS
+.B "cd dev; ./MAKEDEV -V"
+.br
+.B "cd dev; ./MAKEDEV [ -n ] [ -v ] update"
+.br
+.BI "cd dev; ./MAKEDEV [ -n ] [ -v ] [ -d ]" " device ..."
+.SH DESCRIPTION
+.B MAKEDEV
+is a script that will create the devices in \fC/dev\fP used to interface
+with drivers in the kernel.
+.PP
+This man page is woefully out of date. A large number of devices are supported
+that are not documented here.
+.PP
+Note that programs giving the error ``ENOENT: No such file or
+directory'' normally means that the device file is missing, whereas
+``ENODEV: No such device'' normally means the kernel does not have the
+driver configured or loaded.
+.SH OPTIONS
+.TP
+.B \-V
+Print out version (actually RCS version information) and exit.
+.TP
+.B \-n
+Do not actually update the devices, just print the actions that would be
+performed.
+.TP
+.B \-d
+Delete the devices. The main use for this flag is by
+.B MAKEDEV
+itself.
+.TP
+.B \-v
+Be verbose. Print out the actions as they are performed. This is the
+same output as produced by
+.BR \-n .
+.SH CUSTOMISATION
+Since there is currently no standardisation in what names are used for
+system users and groups, it is possible that you may need to modify
+.B MAKEDEV
+to reflect your site's settings. Near the top of the file is a mapping
+from device type to user, group and permissions (e.g. all CD-ROM devices
+are set from the \fC$cdrom\fP variable). If you wish to change the
+defaults, this is the section to edit.
+.SH DEVICES
+.TP
+.B General Options
+.TP
+.B update
+This only works on kernels which have \fC/proc/interrupts\fP (introduced
+during 1.1.x). This file is scanned to see what devices are currently
+configured into the kernel, and this is compared with the previous
+settings stored in the file called \fCDEVICES\fP.
+Devices which are new since then or have a different major number are
+created, and those which are no longer configured are deleted.
+.TP
+.B generic
+Create a generic subset of devices. This is the standard devices, plus
+floppy drives, various hard drives, pseudo-terminals, console devices,
+basic serial devices, busmice, and printer ports.
+.TP
+.B
+std
+Standard devices.
+These are:
+.B mem
+\- acess to physical memory;
+.B kmem
+\- access to kernel virtual memory;
+.B null
+\- null device (infinite sink);
+.B port
+\- access to I/O ports;
+.B zero
+\- null byte source (infinite source);
+.B core
+\- symlink to /proc/kcore (for kernel debugging);
+.B full
+\- always returns ENOSPACE on write;
+.B ram
+\- ramdisk;
+.B tty
+\- to access the controlling tty of a process.
+.TP
+.B local
+This simply runs
+.BR MAKEDEV.local .
+This is a script that can create any local devices.
+.TP
+.B Virtual Terminals
+.TP
+.I console
+This creates the devices associated with the console. This is the virtual
+terminals
+.RI tty x ,
+where
+.I x
+can be from 0 though 63. The device tty0 is the currently active vt, and
+is also known as \fCconsole\fP. For each vt, there are two devices
+.RI vcs x
+and
+.RI vcsa x ,
+which are used to generate screen-dumps of the vt (the
+.BI vcs x
+is just the text,
+and
+.BI vcsa x
+includes the attributes).
+.TP
+.B Serial Devices
+.TP
+.I ttyS{0..63}
+Serial ports and corresponding dialout device. For device
+.BI ttyS x ,
+there is also the device
+.BI cua x
+which is used to dial out with. This can avoid the need for cooperative
+locks in simple situations.
+.TP
+.I cyclades
+Dial-in and dial-out devices for the cyclades intelligent I/O serial card.
+The dial in device is
+.BI ttyC x
+and the corresponding dial-out device is
+.BI cub x
+Devices for 32 lines are created.
+.TP
+.B Pseudo Terminals
+.TP
+.I pty[p-s]
+Each possible argument will create a bank of 16 master and slave
+pairs. The current kernel (1.2) is limited to 64 such pairs.
+The master pseudo-terminals are
+.BR pty[p-s][0-9a-f] ,
+and the slaves are
+.BR tty[p-s][0-9a-f] .
+.TP
+.B Parallel Ports
+.TP
+.I lp
+Standard parallel ports. The devices are created
+.BR lp0 ,
+.BR lp1 ,
+and
+.BR lp2 .
+These correspond to ports at 0x3bc, 0x378 and 0x278.
+Hence, on some machines, the first printer port may actually be
+.BR lp1 .
+.TP
+.I par
+Alternative to
+.IR lp .
+Ports are named
+.BI par x
+instead of
+.BI lp x .
+.TP
+.B Bus Mice
+.TP
+.I busmice
+The various bus mice devices. This creates the following devices:
+.B logimouse
+(Logitech bus mouse),
+.B psmouse
+(PS/2-style mouse),
+.B msmouse
+(Microsoft Inport bus mouse) and
+.B atimouse
+(ATI XL bus mouse) and
+.B jmouse
+(J-mouse).
+.TP
+.B Joystick Devices
+.TP
+.I js
+Joystick. Creates
+.B js0
+and
+.BR js1 .
+.TP
+.B Disk Devices
+.TP
+.I fd[0-7]
+Floppy disk devices. The device
+.BI fd x
+is the device which autodetects the format, and the additional devices are
+fixed format (whose size is indicated in the name).
+The other devices are named as
+.BI fd xLn .
+The single letter
+.I L
+identifies the type of floppy disk (d = 5.25" DD, h = 5.25" HD, D = 3.5"
+DD, H = 3.5" HD, E = 3.5" ED). The number
+.I n
+represents the capacity of that format in K. Thus the standard formats
+are
+.BI fd x d360 ,
+.BI fd x h1200 ,
+.BI fd x D720 ,
+.BI fd x H1440 ,
+and
+.RI fd x E2880 .
+.IP
+For more information see Alain Knaff's fdutils package.
+.IP
+Devices
+.BI fd0 *
+through
+.BI fd3 *
+are floppy disks on the first controller, and devices
+.BI fd4 *
+through
+.BI fd7 *
+are floppy disks on the second controller.
+.TP
+.I hd[a-d]
+AT hard disks. The device
+.BI hd x
+provides access to the whole disk, with the partitions being
+.BI hd x [0-20].
+The four primary partitions are
+.BI hd x 1
+through
+.BI hd x 4,
+with the logical partitions being numbered from
+.BI hd x 5
+though
+.BI hd x 20.
+(A primary partition can be made into an extended partition, which can hold
+4 logical partitions).
+By default, only the devices for 4 logical partitions are made. The
+others can be made by uncommenting them.
+.IP
+Drives hda and hdb are the two on the first controller. If using the new
+IDE driver (rather than the old HD driver), then hdc and hdd are the two
+drives on the secondary controller. These devices can also be used to
+acess IDE CDROMs if using the new IDE driver.
+.TP
+.I xd[a-d]
+XT hard disks. Partitions are the same as IDE disks.
+.TP
+.I sd[a-h]
+SCSI hard disks. The partitions are similar to the IDE disks, but there
+is a limit of 11 logical partitions
+.RI (sd x 5
+through
+.RI sd x 15).
+This is to allow there to be 8 SCSI disks.
+.TP
+.I loop
+Loopback disk devices. These allow you to use a regular file as a
+block device. This means that images of filesystems can be mounted,
+and used as normal. This creates 8 devices loop0 through loop7.
+.TP
+.B Tape Devices
+.TP
+.I st[0-7]
+SCSI tapes. This creates the rewinding tape device
+.BI st x
+and the non-rewinding tape device
+.BI nst x .
+.TP
+.I qic
+QIC-80 tapes. The devices created are
+.BR rmt8 ,
+.BR rmt16 ,
+.BR tape-d ,
+and
+.BR tape-reset .
+.TP
+.I ftape
+Floppy driver tapes (QIC-117). There are 4 methods of access depending on
+the floppy tape drive. For each of access methods 0, 1, 2 and 3, the
+devices
+.BI rft x
+(rewinding) and
+.BI nrft x
+(non-rewinding) are created. For compatability, devices
+.B ftape
+and
+.B nftape
+are symlinks to
+.B rft0
+and
+.B nrft0
+respectively.
+.TP
+.B CDROM Devices
+.TP
+.I scd[0-7]
+SCSI CD players.
+.TP
+.I sonycd
+Sony CDU-31A CD player.
+.TP
+.I mcd
+Mitsumi CD player.
+.TP
+.I cdu535
+Sony CDU-535 CD player.
+.TP
+.I lmscd
+LMS/Philips CD player.
+.TP
+.I sbpcd{,1,2,3}
+Sound Blaster CD player. The kernel is capable of supporting 16 CDROMs,
+each of which is accessed as
+.BR sbpcd[0-9a-f] .
+These are assigned in groups of 4 to each controller.
+.B sbpcd
+is a symlink to
+.BR sbpcd0 .
+.\" .TP
+.\" .I idecd
+.\" NEC CDR-260 (note: this will probably be obsoleted by the new IDE driver).
+.TP
+.B Scanner
+.TP
+.I logiscan
+Logitech ScanMan32 & ScanMan 256.
+.TP
+.I m105scan
+Mustek M105 Handscanner.
+.TP
+.I ac4096
+A4Tek Color Handscanner.
+.TP
+.B Audio
+.TP
+.I audio
+This creates the audio devices used by the sound driver. These include
+.BR mixer ,
+.BR sequencer ,
+.BR dsp ,
+and
+.BR audio .
+.TP
+.I pcaudio
+Devices for the PC Speaker sound driver. These are
+.BR pcmixer .
+.BR pxsp ,
+and
+.BR pcaudio .
+.TP
+.B Miscellaneous
+.TP
+.I sg
+Generic SCSI devices. The devices created are
+.B sg0 through
+.BR sg7 .
+These
+allow arbitary commands to be sent to any SCSI device. This allows for
+querying information about the device, or controlling SCSI devices that
+are not one of disk, tape or CDROM (e.g. scanner, writeable CDROM).
+.TP
+.I fd
+To allow an arbitary program to be fed input from file descriptor
+.IR x ,
+use
+.BI /dev/fd/ x
+as the file name. This also creates
+BR /dev/stdin ,
+BR /dev/stdout ,
+and
+BR /dev/stderr .
+(Note, these are just symlinks into /proc/self/fd).
+.TP
+.I ibcs2
+Devices (and symlinks) needed by the IBCS2 emulation.
+.TP
+.I apm
+Devices for power management.
+.TP
+.I dcf
+Driver for DCF-77 radio clock.
+.TP
+.I helloworld
+Kernel modules demonstration device. See the modules source.
+.TP
+.B "Network Devices"
+Linux used to have devices in /dev for controlling network devices, but
+that is no longer the case. To see what network devices are known by the
+kernel, look at /proc/net/dev.
+.SH "SEE ALSO"
+Linux Allocated Devices, maintained by H.\ Peter Anvin,
+<Peter.Anvin@linux.org>.
+.SH AUTHOR
+Nick Holloway
diff --git a/man/consoletype.1 b/man/consoletype.1
new file mode 100644
index 0000000..2720f87
--- /dev/null
+++ b/man/consoletype.1
@@ -0,0 +1,28 @@
+.TH CONSOLETYPE 1 "Red Hat, Inc" "RH" \" -*- nroff -*-
+.SH NAME
+.B consoletype
+\- print type of the console connected to standard input
+.SH SYNOPSIS
+.B consoletype
+.SH DESCRIPTION
+.B consoletype
+prints the type of console connected to standard input. It prints
+.I vt
+if console is a virtual terminal (/dev/tty* or /dev/console device if not on
+a serial console),
+.I serial
+if standard input is a serial console (/dev/console or /dev/ttyS*) and
+.I pty
+if standard input is a pseudo terminal.
+.SH RETURN VALUE
+.B consoletype
+returns
+.TP
+.I 0
+if on virtual terminal
+.TP
+.I 1
+if on serial console
+.TP
+.I 2
+if on a pseudo terminal.
diff --git a/man/modules-update.8 b/man/modules-update.8
new file mode 100644
index 0000000..84ac7a8
--- /dev/null
+++ b/man/modules-update.8
@@ -0,0 +1,51 @@
+.TH MODULES-UPDATE 8 "Gentoo Linux" "2001"
+.SH NAME
+modules\-update \- (re)generate /etc/modules.conf
+.SH SYNOPSIS
+.B modules\-update
+[force]
+.SH DESCRIPTION
+.B modules\-update
+is a simple tool to manage
+.IR /etc/modules.conf .
+The Linux module utilities use a single file for all their
+configuration. This makes it difficult for packages to dynamically add
+information about their own modules.
+.PP
+.B modules-update
+makes the dynamic addition of information easier by generating the
+single configuration file from the many files located in
+.IR /etc/modules.d/ .
+All files in that directory are assembled together to form
+.IR /etc/modules.conf .
+.PP
+After generation, a backup of the old file can be found at
+.IR /etc/modules.conf.old .
+.SH "FILES"
+There are two types of file you can put in
+.IR /etc/modules.d/ :
+normal files and exectuable files. Normal files contain standard modules
+configuration information, as described in
+.BR modules.conf (5).
+Executable files are executed and their output is used as extra configuration
+information. Error messages are sent to stderr and thus do not become
+part of the configuration file.
+.SH OPTIONS
+.TP
+.I force
+.B modules\-update
+will check if the current
+.I /etc/modules.conf
+is a generated file by checking for a special tag on the first line. If this
+tag is not found generation is aborted. By supplying
+.I force
+as parameter only a warning is printed.
+.SH "REPORTING BUGS"
+Please report bugs via http://bugs.gentoo.org/
+.SH "SEE ALSO"
+.BR depmod (1),
+.BR modules.conf (5)
+.SH AUTHOR
+This manual page was written by Wichert Akkerman <wakkerma@debian.org>
+for the Debian GNU/Linux system. Modified for
+.I Gentoo Linux.
diff --git a/man/modules.autoload.5 b/man/modules.autoload.5
new file mode 100644
index 0000000..1a0c3e3
--- /dev/null
+++ b/man/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/rc-status.8 b/man/rc-status.8
new file mode 100644
index 0000000..c91e872
--- /dev/null
+++ b/man/rc-status.8
@@ -0,0 +1,39 @@
+.TH "BASELAYOUT" "8" "May 2004" "baselayout" "baselayout"
+.SH NAME
+rc-status \- show status info about runlevels
+.SH SYNOPSIS
+\fBrc-status\fR \fI[command [runlevel]]\fR
+.SH DESCRIPTION
+\fBrc-status\fR gathers and displays information about the status of init
+scripts in different runlevels. The default behavior is to show information
+about the current runlevel, but any runlevel can be quickly examined.
+directory. They must also conform to the Gentoo runscript standard.
+.SH OPTIONS
+.TP
+\fB\-\-all (\-a)\fR
+Show all runlevels and their services
+.TP
+\fB\-\-list (\-l)\fR
+List all defined runlevels
+.TP
+\fB\-\-nocolor (\-nc)\fR
+Disable color output
+.TP
+\fB\-\-servicelist (\-s)\fR
+Show all services
+.TP
+\fB\-\-unused (\-u)\fR
+Show services not assigned to any runlevel
+.TP
+\fB[runlevel]\fR
+Show information only for the named \fBrunlevel\fR
+.SH "REPORTING BUGS"
+Please report bugs via http://bugs.gentoo.org/
+.SH "SEE ALSO"
+.BR rc-update (8)
+
+http://www.gentoo.org/doc/en/handbook/handbook-x86.xml?part=2&chap=4
+.SH AUTHORS
+Mike Frysinger <vapier@gentoo.org>
+.SH "CVS HEADER"
+$Header$
diff --git a/man/rc-update.8 b/man/rc-update.8
new file mode 100644
index 0000000..b5b1d8c
--- /dev/null
+++ b/man/rc-update.8
@@ -0,0 +1,46 @@
+.TH "BASELAYOUT" "8" "May 2004" "baselayout" "baselayout"
+.SH NAME
+rc-update \- add and remove init scripts to a runlevel
+.SH SYNOPSIS
+\fBrc-update\fR \fIadd\fR \fIscript\fR \fI<runlevels>\fR
+.br
+\fBrc-update\fR \fIdel\fR \fIscript\fR \fI[runlevels]\fR
+.br
+\fBrc-update\fR \fIshow\fR \fI[runlevels]\fR
+.SH DESCRIPTION
+Gentoo's init system uses named runlevels. Rather than editing some obscure
+file or managing a directory of symlinks, \fBrc-update\fR exists to quickly
+add or delete init scripts from different runlevels.
+
+All scripts specified with this utility must reside in the \fI/etc/init.d\fR
+directory. They must also conform to the Gentoo runscript standard.
+.SH OPTIONS
+.TP
+\fBadd (\-a)\fR \fIscript\fR \fI<runlevels>\fR
+Add the specified \fIinit script\fR to the specified \fIrunlevels\fR. You
+must specify at least one runlevel.
+
+Example: rc-update add net.eth0 default
+.TP
+\fBdel (\-d)\fR \fIscript\fR \fI[runlevels]\fR
+Delete the specified \fIinit script\fR from the specified \fIrunlevels\fR.
+If you do not specify the \fIrunlevels\fR from which to delete, the script
+will be removed from all exists runlevels.
+
+Example: rc-update del sysklogd
+.TP
+\fBshow (\-s)\fR \fI[runlevels]\fR
+Show all init scripts and the runlevels they belong to. If you specify
+\fIrunlevels\fR to show, then only those will be included in the output.
+
+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
+.SH AUTHORS
+Mike Frysinger <vapier@gentoo.org>
+.SH "CVS HEADER"
+$Header$
diff --git a/man/start-stop-daemon.8 b/man/start-stop-daemon.8
new file mode 100644
index 0000000..d0d8f0b
--- /dev/null
+++ b/man/start-stop-daemon.8
@@ -0,0 +1,233 @@
+.\" Hey, Emacs! This is an -*- nroff -*- source file.
+.TH START\-STOP\-DAEMON 8 "15th March 1997" "Debian Project" "Debian GNU/Linux"
+.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 (0 if
+.BR --oknodo
+is specified).
+If such a process does not exist, it starts an
+instance, using either the executable specified by
+.BR --exec ,
+(or, if specified, by
+.BR --startas ).
+Any arguments given after
+.BR --
+on the command line are passed unmodified to the program being
+started. If
+.B --retry
+is specified then start-stop-daemon will check that the process(es)
+have terminated.
+
+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,
+.B start\-stop\-daemon
+exits with error status 1
+(0 if
+.BR --oknodo
+is specified).
+
+.SH OPTIONS
+
+.TP
+\fB-x\fP|\fB--exec\fP \fIexecutable\fP
+Check for processes that are instances of this executable (according to
+.B /proc/
+.I pid
+.B /exe
+).
+.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
+(according to
+.B /proc/
+.I pid
+.B /stat
+).
+.TP
+\fB-s\fP|\fB--signal\fP \fIsignal\fP
+With
+.BR --stop
+, specifies the signal to send to processes being stopped (default 15).
+.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 /KILL/ 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
+\fB-a\fP|\fB--startas\fP \fIpathname\fP
+With
+.BR --start ,
+start the process specified by
+.IR pathname .
+If not specified, defaults to the argument given to
+.BR --exec .
+.TP
+.BR -t | --test
+Print actions that would be taken and set appropriate return value,
+but take no action.
+.TP
+.BR -o | --oknodo
+Return exit status 0 instead of 1 if no actions are (would be) taken.
+.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.
+.B WARNING: start-stop-daemon
+cannot check the exit status if the process fails to execute for
+.B any
+reason. This is a last resort, and is only meant for programs that either
+make no sense forking on their own, or where it's not feasible to add the
+code for it to do this itself.
+.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.
+
+.SH AUTHORS
+Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl> based on
+a previous version by Ian Jackson <ian@chiark.greenend.org.uk>.
+
+Manual page by Klee Dienes <klee@mit.edu>, partially reformatted
+by Ian Jackson.
diff --git a/rc-lists/boot b/rc-lists/boot
new file mode 100644
index 0000000..069346d
--- /dev/null
+++ b/rc-lists/boot
@@ -0,0 +1,14 @@
+bootmisc
+checkroot
+consolefont
+keymaps
+modules
+rmnologin
+urandom
+checkfs
+clock
+domainname
+hostname
+localmount
+net.lo
+serial
diff --git a/rc-lists/default b/rc-lists/default
new file mode 100644
index 0000000..d6763ae
--- /dev/null
+++ b/rc-lists/default
@@ -0,0 +1,3 @@
+hdparm
+local
+netmount
diff --git a/rc-lists/nonetwork b/rc-lists/nonetwork
new file mode 100644
index 0000000..4083037
--- /dev/null
+++ b/rc-lists/nonetwork
@@ -0,0 +1 @@
+local
diff --git a/rc-lists/single b/rc-lists/single
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/rc-lists/single
diff --git a/sbin/MAKEDEV b/sbin/MAKEDEV
new file mode 100755
index 0000000..8b720d7
--- /dev/null
+++ b/sbin/MAKEDEV
@@ -0,0 +1,1894 @@
+#! /bin/sh -
+
+RCSID='$Id: MAKEDEV 560 2004-09-19 05:39:28Z vapier $'
+
+#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#
+# Customisation:
+# The devices fall into various classes. This section contains the mapping
+# from a class name into a group name and permission.
+# You will almost certainly need to edit the group name to match your
+# system, and you may change the permissions to suit your preference. These
+# lines _must_ be of the format "user group perm".
+
+ public=" root root 0666"
+private=" root root 0600"
+ system=" root root 0660"
+ kmem=" root kmem 0640"
+ tty=" root tty 0660" # Perms was 0666
+ cons=" root tty 0600"
+ vcs=" root root 0600"
+dialout=" root dialout 0660"
+ dip=" root dip 0660"
+ mouse=" root root 0660"
+printer=" root lp 0660"
+ floppy=" root floppy 0660"
+ disk=" root disk 0660"
+ scsi=" root root 0600"
+ cdrom=" root cdrom 0660"
+ tape=" root tape 0660"
+ audio=" root audio 0660"
+ video=" root video 0660"
+ fb=" root video 0620"
+ ibcs2=" root root 0660" # Perms was 0666
+scanner=" root root 0660" # Perms was 0666
+ coda=" root root 0600"
+ ipsec=" root root 0200"
+readable=" root root 0444"
+
+MAXVT=63
+
+# defaults for $major_*
+major_ide0=3
+major_ide1=22
+major_sd=8
+major_lp=6
+
+# Remark: OSS/Linux becomes major_OSSLinux
+
+#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#
+
+# don't stomp on devfs users
+if [ -c .devfsd ]
+then
+ echo ".devfsd presence implies active DevFS. Aborting MAKEDEV invocation."
+ # use exit 0, not 1, so postinst scripts don't fail on this
+ exit 0
+fi
+
+
+# make sure we are not in /
+if [ "`pwd`" = "/" ]; then
+ echo "Running MAKEDEV in your root filesystem is a VERY BAD IDEA."
+ exit 0
+fi
+
+#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#
+
+procfs=/proc
+
+opt_v=
+opt_d=
+opt_n=
+
+while [ $# -ge 1 ]
+do
+ case $1 in
+ --) shift; break ;;
+ -v) shift; opt_v=1 ;;
+ -d) shift; opt_d=1 ;;
+ -n) shift; opt_n=1; opt_v=1 ;;
+ -V) shift; opt_V=1 ;;
+ -*) echo "$0: unknown flag \"$1\"" >&2; exit 1 ;;
+ *) break ;;
+ esac
+done
+
+if [ "$opt_V" ]
+then
+ echo "$RCSID"
+ exit 0
+fi
+
+opts="${opt_n:+-n} ${opt_v:+-v} ${opt_d:+-d}"
+
+#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#
+
+makedev () { # usage: makedev name [bcu] major minor owner group mode
+ if [ "$opt_v" ]
+ then if [ "$opt_d" ]
+ then echo "delete $1"
+ else echo "create $1 $2 $3 $4 $5:$6 $7"
+ fi
+ fi
+ if [ ! "$opt_n" ]
+ then if [ "$opt_d" ]
+ then
+ rm -f $1
+ else
+ rm -f $1-
+ mknod $1- $2 $3 $4 &&
+ chown $5:$6 $1- &&
+ chmod $7 $1- &&
+ mv $1- $1
+ fi
+ fi
+}
+symlink () { # usage: symlink name target
+ if [ "$opt_v" ]
+ then if [ "$opt_d" ]
+ then echo "delete $1"
+ else echo "create $1 -> $2"
+ fi
+ fi
+ [ ! "$opt_n" ] && rm -f $1 &&
+ [ ! "$opt_d" ] && ln -s $2 $1
+}
+
+#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#
+
+# Debian allows us to assume /bin/sh is a POSIX compliant shell, so go for it!
+
+math () {
+ eval echo "\$(($*))"
+}
+index () { # index string c
+ eval "I=\${1%$2*}"
+ eval echo "\${#I}"
+}
+suffix () {
+ eval echo "\${1#$2}"
+}
+strip () {
+ eval echo "\${1% $2 *} \${1#* $2 }"
+}
+first () {
+ eval echo "\${1:0:1}"
+}
+second () {
+ eval echo "\${1:1:1}"
+}
+substr () {
+ echo $1 | cut -c $2
+}
+
+#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#
+
+devices=
+if [ ! -f $procfs/devices ]
+then
+ echo "$0: warning: can't read $procfs/devices" >&2
+else
+ exec 3<$procfs/devices
+ while read major device <&3
+ do
+ device=`echo $device | sed 's#/.*##'`
+ case "$major" in
+ Character|Block|'')
+ ;;
+ *)
+ eval "major_${device/-/_}=$major"
+ devices="$devices $device"
+ ;;
+ esac
+ done
+ exec 3<&-
+fi
+
+Major () {
+ device=$2
+ if [ "$opt_d" ]
+ then
+ echo -1 # don't care
+ else
+ eval echo \${major_${1/-/_}:-\${device:?\"unknown major number for $1\"}}
+ fi
+}
+
+cvt () {
+ while [ $# -ne 0 ]
+ do
+ case "$1" in
+ mem|tty|ttyp|cua|cub|cui) ;;
+ hd) (for d in a b c d e f g h ; do
+ echo -n hd$d " "
+ done) ; echo
+ ;;
+ ide0) echo hda hdb ;;
+ ide1) echo hdc hdd ;;
+ ide2) echo hde hdf ;;
+ ide3) echo hdg hdh ;;
+ ide4) echo hdi hdj ;;
+ ide5) echo hdk hdl ;;
+ sd) echo sda sdb sdc sdd ;;
+ dasd) (for d in a b c d e f g h i j k l m \
+ n o p q r s t u v w x y z ; do
+ echo -n dasd$d " "
+ done) ; echo
+ ;;
+ raw) echo raw ;;
+ sg) echo sg ;;
+ sr) echo scd ;;
+ st) echo st0 ;;
+ xd) echo xda xdb ;;
+ ad) echo ada adb ;;
+ fd) echo fd0 fd1 ;;
+ lp) echo lp ;;
+ mt) echo ftape ;;
+ qft) echo ftape ;;
+ loop) echo loop ;;
+ md) echo md ;;
+ ibcs2) echo ibcs2 ;;
+ tpqic02) echo qic ;;
+ sound) echo audio ;;
+ logiscan) echo logiscan ;;
+ ac4096) echo ac4096 ;;
+ hw) echo helloworld ;;
+ sbpcd | sbpcd[123]) echo $1 ;;
+ joystick) echo js ;;
+ input) echo input ;;
+ apm_bios) echo apm ;;
+ dcf) echo dcf ;;
+ aztcd) echo aztcd ;;
+ cm206cd) echo cm206cd ;;
+ gscd) echo gscd ;;
+ pcmcia) ;; # taken care of by its own driver
+ ttyC) echo cyclades ;;
+ isdn) echo isdnmodem isdnbri dcbri ;;
+ vcs) ;;
+ pty) echo pty ;;
+ misc) echo misc ;;
+ 3dfx) echo 3dfx ;;
+ agpgart) echo agpgart ;;
+ microcode) echo microcode ;;
+ ipmi|ipmikcs) echo ipmi ;;
+ fb) echo fb ;;
+ nb) echo nb0 nb1 ;;
+ netlink) echo netlink ;;
+ tap) echo netlink ;;
+ hamradio) echo hamradio ;;
+ snd) ;;
+ ptm) ;;
+ pts) ;;
+ ttyS) echo ttyS0 ttyS1 ttyS2 ttyS3 ;;
+ ttyI) echo ttyI0 ttyI1 ttyI2 ttyI3 ;;
+ ircomm|irlpt) echo irda ;;
+ ppp) echo ppp ;;
+ usb) echo usb ;;
+ lvm) ;; # taken care of by LVM userspace tools
+ ramdisk) echo ram ;;
+ *) echo "$0: don't know what \"$1\" is" >&2 ;;
+ esac
+ shift
+ done
+}
+
+for arg
+do
+# case `cvt $arg` in
+ case $arg in
+ generic)
+ if [ -n "`which dpkg 2> /dev/null`" ]
+ then
+ # pick the right generic-<arch> using dpkg's knowledge
+ case `dpkg --print-installation-architecture` in
+ alpha)
+ $0 $opts generic-alpha
+ ;;
+ arm)
+ $0 $opts generic-arm
+ ;;
+ hppa)
+ $0 $opts generic-hppa
+ ;;
+ i386)
+ $0 $opts generic-i386
+ ;;
+ ia64)
+ $0 $opts generic-ia64
+ ;;
+ m68k)
+ $0 $opts generic-m68k
+ ;;
+ mips)
+ $0 $opts generic-mips
+ ;;
+ mipsel)
+ $0 $opts generic-mipsel
+ ;;
+ powerpc)
+ $0 $opts generic-powerpc
+ ;;
+ s390)
+ $0 $opts generic-s390
+ ;;
+ sparc)
+ $0 $opts generic-sparc
+ ;;
+ *)
+ echo "$0: no support for generic on this arch" >&2
+ exit 1
+ ;;
+ esac
+ else
+ $0 $opts std
+ $0 $opts fd
+ $0 $opts fd0 fd1
+ $0 $opts hda hdb
+ $0 $opts xda xdb
+ $0 $opts sda sdb
+ $0 $opts pty
+ $0 $opts console
+ $0 $opts ttyS0 ttyS1 ttyS2 ttyS3
+ $0 $opts busmice
+ $0 $opts lp
+ $0 $opts par
+ fi
+ ;;
+ generic-alpha)
+ export MDARCH="alpha"
+ $0 $opts std
+ $0 $opts fd
+ $0 $opts fd0 fd1
+ $0 $opts hda hdb hdc hdd
+ $0 $opts xda xdb
+ $0 $opts sda sdb sdc sdd
+ $0 $opts scd0 scd1
+ $0 $opts st0 st1
+ $0 $opts sg
+ $0 $opts pty
+ $0 $opts console
+ $0 $opts ttyS0 ttyS1 ttyS2 ttyS3
+ $0 $opts busmice
+ $0 $opts lp
+ $0 $opts par
+ $0 $opts audio
+ $0 $opts fb
+ ;;
+ generic-arm)
+ export MDARCH="arm"
+ $0 $opts std
+ $0 $opts fd
+ $0 $opts fd0 fd1
+ $0 $opts hda hdb hdc hdd
+ $0 $opts xda xdb
+ $0 $opts sda sdb sdc sdd
+ $0 $opts scd0 scd1
+ $0 $opts st0 st1
+ $0 $opts sg
+ $0 $opts pty
+ $0 $opts console
+ $0 $opts ttyS0 ttyS1 ttyS2 ttyS3
+ $0 $opts busmice
+ $0 $opts lp
+ $0 $opts par
+ $0 $opts audio
+ $0 $opts fb
+ ;;
+ generic-hppa)
+ export MDARCH="hppa"
+ $0 $opts std
+ $0 $opts fd
+ $0 $opts fd0 fd1
+ $0 $opts sda sdb sdc sdd
+ $0 $opts scd0 scd1
+ $0 $opts st0 st1
+ $0 $opts sg
+ $0 $opts pty
+ $0 $opts console
+ $0 $opts ttyS0 ttyS1 ttyS2 ttyS3
+ $0 $opts busmice
+ $0 $opts lp
+ $0 $opts par
+ $0 $opts audio
+ $0 $opts fb
+ $0 $opts rtc
+ ;;
+ generic-i386)
+ export MDARCH="i386"
+ $0 $opts std
+ $0 $opts fd
+ $0 $opts fd0 fd1
+ $0 $opts hda hdb hdc hdd
+ $0 $opts xda xdb
+ $0 $opts sda sdb sdc sdd
+ $0 $opts scd0 scd1
+ $0 $opts st0 st1
+ $0 $opts sg
+ $0 $opts pty
+ $0 $opts console
+ $0 $opts ttyS0 ttyS1 ttyS2 ttyS3
+ $0 $opts busmice
+ $0 $opts lp
+ $0 $opts par
+ $0 $opts audio
+ $0 $opts fb
+ $0 $opts isdn-io eda edb sonycd mcd mcdx cdu535
+ $0 $opts optcd sjcd cm206cd gscd
+ $0 $opts lmscd sbpcd aztcd bpcd dac960 ida ataraid cciss
+ ;;
+ generic-ia64)
+ export MDARCH="ia64"
+ $0 $opts std
+ $0 $opts fd
+ $0 $opts fd0 fd1
+ $0 $opts hda hdb hdc hdd
+ $0 $opts xda xdb
+ $0 $opts sda sdb sdc sdd
+ $0 $opts scd0 scd1
+ $0 $opts st0 st1
+ $0 $opts sg
+ $0 $opts pty
+ $0 $opts console
+ $0 $opts ttyS0 ttyS1 ttyS2 ttyS3 ttyS4 ttyS5
+ $0 $opts busmice
+ $0 $opts lp
+ $0 $opts par
+ $0 $opts audio
+ $0 $opts fb
+ $0 $opts efirtc
+ ;;
+ generic-m68k)
+ export MDARCH="m68k"
+ $0 $opts std
+ $0 $opts fd
+ $0 $opts fd0 fd1
+ $0 $opts hda hdb hdc hdd
+ $0 $opts sda sdb sdc sdd
+ $0 $opts sg
+ $0 $opts ada adb adc add ade adf
+ $0 $opts pty
+ $0 $opts console
+ $0 $opts ttyS0 ttyS1 ttyS2 ttyS3 ttyS5
+ $0 $opts m68k-mice
+ $0 $opts lp
+ $0 $opts par
+ $0 $opts nvram
+ $0 $opts audio
+ $0 $opts fb
+ ;;
+ generic-mips)
+ export MDARCH="mips"
+ $0 $opts std
+ $0 $opts fd
+ $0 $opts fd0 fd1
+ $0 $opts hda hdb
+ $0 $opts sda sdb sdc sdd
+ $0 $opts scd0 scd1
+ $0 $opts st0 st1
+ $0 $opts sg
+ $0 $opts pty
+ $0 $opts console
+ $0 $opts ttyS0 ttyS1 ttyS2 ttyS3
+ $0 $opts lp
+ $0 $opts par
+ $0 $opts audio
+ $0 $opts fb
+ $0 $opts busmice
+ ;;
+ generic-mipsel)
+ export MDARCH="mipsel"
+ $0 $opts std
+ $0 $opts fd
+ $0 $opts fd0 fd1
+ $0 $opts hda hdb
+ $0 $opts sda sdb sdc sdd
+ $0 $opts scd0 scd1
+ $0 $opts st0 st1
+ $0 $opts sg
+ $0 $opts pty
+ $0 $opts console
+ $0 $opts ttyS0 ttyS1 ttyS2 ttyS3
+ $0 $opts lp
+ $0 $opts par
+ $0 $opts audio
+ $0 $opts fb
+ $0 $opts rtc
+ ;;
+ generic-powerpc)
+ export MDARCH="powerpc"
+ $0 $opts std
+ $0 $opts fd
+ $0 $opts fd0 fd1
+ $0 $opts hda hdb hdc hdd
+ $0 $opts sda sdb sdc sdd
+ $0 $opts scd0 scd1
+ $0 $opts st0 st1
+ $0 $opts sg
+ $0 $opts pty
+ $0 $opts console
+ $0 $opts ttyS0 ttyS1 ttyS2 ttyS3
+ $0 $opts busmice
+ $0 $opts m68k-mice
+ $0 $opts input
+ $0 $opts lp
+ $0 $opts par
+ $0 $opts nvram
+ $0 $opts audio
+ $0 $opts adb
+ $0 $opts fb
+ $0 $opts rtc
+ $0 $opts isdn-io
+ ;;
+ generic-s390)
+ export MDARCH="s390"
+ $0 $opts std
+ $0 $opts fd
+ $0 $opts dasda dasdb dasdc dasdd dasde dasdf dasdg dasdh \
+ dasdi dasdj dasdk dasdl dasdm dasdn dasdo dasdp \
+ dasdq dasdr dasds dasdt dasdu dasdv dasdw dasdx \
+ dasdy dasdz
+ $0 $opts pty
+ $0 $opts consoleonly
+ $0 $opts rtc
+ ;;
+ generic-sparc)
+ export MDARCH="sparc"
+ $0 $opts std
+ $0 $opts fd0-bare fd1-bare
+ $0 $opts hda hdb hdc hdd
+ $0 $opts sda sdb sdc sdd
+ $0 $opts scd0 scd1
+ $0 $opts st0 st1
+ $0 $opts sg
+ $0 $opts pty
+ $0 $opts console
+ $0 $opts ttyS0 ttyS1 ttyS2 ttyS3
+ $0 $opts busmice
+ $0 $opts fb
+ $0 $opts rtc
+ makedev kbd c 11 0 $cons
+ makedev sunmouse c 10 6 $mouse
+ symlink mouse sunmouse
+ makedev openprom c 10 139 $mouse
+ ;;
+ local)
+ $0.local $opts
+ ;;
+ std)
+ makedev mem c 1 1 $kmem
+ makedev kmem c 1 2 $kmem
+ makedev null c 1 3 $public
+ makedev port c 1 4 $kmem
+ makedev zero c 1 5 $public
+ symlink core $procfs/kcore
+ makedev full c 1 7 $public
+ makedev random c 1 8 $public
+ makedev urandom c 1 9 $readable
+ makedev tty c 5 0 $tty
+ $0 $opts ram
+ $0 $opts loop
+ ;;
+ hamradio)
+ $0 $opts scc
+ $0 $opts bc
+ ;;
+ scc)
+ for unit in 0 1 2 3 4 5 6 7
+ do
+ makedev scc$unit c 34 $unit $system
+ done
+ ;;
+ bc)
+ for unit in 0 1 2 3
+ do
+ makedev bc$unit c 51 $unit $system
+ done
+ ;;
+ random)
+ makedev random c 1 8 $public
+ ;;
+ urandom)
+ makedev urandom c 1 9 $readable
+ ;;
+ ram)
+ for i in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ; do
+ makedev ram$i b 1 $i $disk
+ done
+ symlink ram ram1
+ ;;
+ ram[0-9]|ram1[0-6])
+ unit=`suffix $arg ram`
+ makedev ram$unit b 1 $unit $disk
+ ;;
+ initrd)
+ makedev initrd b 1 250 $disk
+ ;;
+ raw)
+ makedev raw c 162 0 $disk
+ symlink rawctl raw
+ for i in 1 2 3 4 5 6 7 8; do
+ makedev raw$i c 162 $i $disk
+ done
+ ;;
+ consoleonly)
+ makedev tty0 c 4 0 $cons
+ # new kernels need a device, old ones a symlink... sigh
+ kern_rev1=`uname -r | awk -F'.' '{print $1}'`
+ kern_rev2=`uname -r | awk -F'.' '{print $2}'`
+ if [ $kern_rev1 -gt 2 ]
+ then
+ makedev console c 5 1 $cons
+ else
+ if [ $kern_rev1 -eq 2 -a $kern_rev2 -ge 1 ]
+ then
+ makedev console c 5 1 $cons
+ else
+ symlink console tty0
+ fi
+ fi
+ ;;
+ console)
+ $0 $opts consoleonly
+ major=`Major vcs 7` # not fatal
+ [ "$major" ] && makedev vcs0 c $major 0 $vcs
+ symlink vcs vcs0
+ [ "$major" ] && makedev vcsa0 c $major 128 $vcs
+ symlink vcsa vcsa0
+ # individual vts
+ line=1
+ while [ $line -le $MAXVT -a $line -le 63 ]
+ do
+ makedev tty$line c 4 $line $tty
+ [ "$major" ] && makedev vcs$line c $major $line $vcs
+ [ "$major" ] && makedev vcsa$line c $major `math $line + 128` $vcs
+ line=`math $line + 1`
+ done
+ ;;
+ adb)
+ myarch=
+
+ if [ -n "`which dpkg 2> /dev/null`" ]
+ then
+ # pick the right arch device using dpkg's knowledge
+ myarch="`dpkg --print-installation-architecture`"
+
+ elif [ -n "${MDARCH}" ]
+ then
+ myarch="${MDARCH}"
+ fi
+
+ case $myarch in
+ powerpc)
+ # ADB bus devices (char)
+ makedev adb c 56 0 $mouse
+ makedev adbmouse c 10 10 $mouse
+ ;;
+ m68k)
+ # ACSI disk 2, whole device (block)
+ makedev adb b 28 16 $disk
+ for part in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+ do
+ minor=$(( 16 + $part ))
+ makedev adb$part b 28 $minor $disk
+ done
+ ;;
+ *)
+ echo "no support for adb on this arch" >&2
+ exit 1
+ ;;
+ esac
+ ;;
+ raw1394)
+ makedev raw1394 c 171 0 $disk
+ ;;
+ nvram)
+ makedev nvram c 10 144 $mouse
+ ;;
+ tty[1-9]|tty[1-5][0-9]|tty[6][0-3])
+ line=`suffix $arg tty`
+ makedev tty$line c 4 $line $tty
+ ;;
+ ttyS[0-9]|ttyS[1-5][0-9]|ttyS[6][0-3])
+ line=`suffix $arg ttyS`
+ minor=`math 64 + $line`
+ makedev ttyS$line c 4 $minor $dialout
+ ;;
+ pty[a-ep-z])
+ bank=`suffix $arg pty`
+ base=`index pqrstuvwxyzabcde $bank`
+ base=`math $base \* 16`
+ for i in 0 1 2 3 4 5 6 7 8 9 a b c d e f
+ do
+ j=`index 0123456789abcdef $i`
+ makedev pty$bank$i c 2 `math $base + $j` $tty
+ makedev tty$bank$i c 3 `math $base + $j` $tty
+ done
+ ;;
+ pty)
+ ptysufs=""
+ for i in p q r s t u v w x y z a b c d e
+ do
+ ptysufs="$ptysufs pty$i"
+ done
+ $0 $opts $ptysufs ptmx
+ ;;
+ ptmx)
+ # master pty multiplexer for 2.1 kernels
+ makedev ptmx c 5 2 $tty
+ ;;
+ cyclades|ttyC)
+ major1=`Major ttyC 19` || continue
+ #major2=`Major cub 20` || continue
+ for i in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 \
+ 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
+ do
+ makedev ttyC$i c $major1 $i $dialout
+ #makedev cub$i c $major2 $i $dialout
+ done
+ ;;
+ stallion|ttyE)
+ major1=`Major ttyE 24` || continue
+ #major2=`Major cue 25` || continue
+ majorc=28
+ minor=0
+ until [ $minor -gt 256 ]
+ do
+ makedev ttyE$minor c $major1 $minor $dialout
+ #makedev cue$minor c $major2 $minor $dialout
+ minor=`math $minor + 1`
+ done
+ for i in 0 1 2 3
+ do
+ makedev staliomem$i c $majorc $i $private
+ done
+ ;;
+ chase|ttyH)
+ major1=`Major ttyH 17` || continue
+ #major2=`Major cuh 18` || continue
+ minor=0
+ until [ $minor -gt 16 ] # tell me if 16 is wrong
+ do
+ makedev ttyH$minor c $major1 $minor $dialout
+ #makedev cuh$minor c $major2 $minor $dialout
+ minor=`math $minor + 1`
+ done
+ ;;
+ rocketport|ttyR)
+ major1=`Major ttyR 46` || continue
+ #major2=`Major cur 47` || continue
+ minor=0
+ until [ $minor -gt 64 ] # tell me if 64 is wrong
+ do
+ makedev ttyR$minor c $major1 $minor $dialout
+ #makedev cur$minor c $major2 $minor $dialout
+ minor=`math $minor + 1`
+ done
+ ;;
+ ttyV)
+ major1=`Major ttyV 105` || continue
+ #major2=`Major cuv 106` || continue
+ minor=0
+ until [ $minor -gt 16 ] # tell me if 16 is wrong
+ do
+ makedev ttyV$minor c $major1 $minor $dialout
+ #makedev cuv$minor c $major2 $minor $dialout
+ minor=`math $minor + 1`
+ done
+ ;;
+ digi|ttyD)
+ major1=`Major ttyD 22` || continue
+ #major2=`Major cud 23` || continue
+ minor=0
+ until [ $minor -gt 16 ] # tell me if 16 is wrong
+ do
+ makedev ttyD$minor c $major1 $minor $dialout
+ #makedev cud$minor c $major2 $minor $dialout
+ minor=`math $minor + 1`
+ done
+ ;;
+ specialix|ttyX)
+ major1=`Major ttyX 32` || continue
+ #major2=`Major cux 33` || continue
+ minor=0
+ until [ $minor -gt 16 ] # tell me if 16 is wrong
+ do
+ makedev ttyX$minor c $major1 $minor $dialout
+ #makedev cux$minor c $major2 $minor $dialout
+ minor=`math $minor + 1`
+ done
+ ;;
+ specialixIO8|ttyW)
+ major1=`Major ttyW 75` || continue
+ #major2=`Major cuw 76` || continue
+ minor=0
+ until [ $minor -gt 16 ] # tell me if 16 is wrong
+ do
+ makedev ttyW$minor c $major1 $minor $dialout
+ #makedev cuw$minor c $major2 $minor $dialout
+ minor=`math $minor + 1`
+ done
+ ;;
+ PAM|ttyM)
+ major1=`Major ttyM 79` || continue
+ #major2=`Major cum 80` || continue
+ minor=0
+ until [ $minor -gt 16 ] # tell me if 16 is wrong
+ do
+ makedev ttyM$minor c $major1 $minor $dialout
+ #makedev cum$minor c $major2 $minor $dialout
+ minor=`math $minor + 1`
+ done
+ ;;
+ riscom|ttyL)
+ major=`Major ttyL 48` || continue
+ minor=0
+ until [ $minor -gt 16 ] # tell me if 16 is wrong
+ do
+ makedev ttyL$minor c $major $minor $dialout
+ minor=`math $minor + 1`
+ done
+ ;;
+ computone|ttyF)
+ major=`Major ttyF 71` || continue
+ #major2=`Major cuf 72` || continue
+ minor=0
+ until [ $minor -gt 255 ]
+ do
+ makedev ttyF$minor c $major $minor $dialout
+ #makedev cuf$minor c $major2 $minor $dialout
+ minor=`math $minor + 1`
+ done
+ major=73
+ for i in 0 4 8 12
+ do
+ makedev ip2ipl$i c $major $i $private
+ makedev ip2stat$i c $major `math $i + 1` $private
+ done
+ ;;
+ ESP|ttyP)
+ major=`Major ttyP 57` || continue
+ #major2=`Major cup 58` || continue
+ minor=0
+ until [ $minor -gt 4 ] # tell me if 4 is wrong
+ do
+ makedev ttyP$minor c $major $minor $dialout
+ #makedev cup$minor c $major2 $minor $dialout
+ minor=`math $minor + 1`
+ done
+ ;;
+ COMX|comx)
+ major=`Major comx 88` || continue
+ minor=0
+ until [ $minor -gt 4 ] # tell me if 4 is wrong
+ do
+ makedev comx$minor c $major $minor $private
+ minor=`math $minor + 1`
+ done
+ ;;
+ isdnmodem|ttyI)
+ major1=`Major ttyI 43` || continue
+ #major2=`Major cui 44` || continue
+ minor=0
+ until [ $minor -gt 63 ]
+ do
+ makedev ttyI$minor c $major1 $minor $dialout
+ #makedev cui$minor c $major2 $minor $dialout
+ minor=`math $minor + 1`
+ done
+ ;;
+ isdnbri)
+ major=45
+ minor=0
+ until [ $minor -gt 63 ]
+ do
+ makedev isdn$minor c $major $minor $dialout
+ makedev isdnctrl$minor c $major `math $minor + 64` $dialout
+ makedev ippp$minor c $major `math $minor + 128` $dialout
+ minor=`math $minor + 1`
+ done
+ makedev isdninfo c $major 255 $private
+ ;;
+ dcbri)
+ major=52
+ for i in 0 1 2 3
+ do
+ makedev dcbri$i c $major $i $dialout
+ done
+ ;;
+ capi)
+ major=68
+ makedev capi20 c $major 0 $dialout
+ for i in 0 1 2 3 4 5 6 7 8 9
+ do
+ makedev capi20.0$i c $major `math $i + 1` $dialout
+ done
+ for i in 10 11 12 13 14 15 16 17 18 19
+ do
+ makedev capi20.$i c $major `math $i + 1` $dialout
+ done
+ ;;
+ ubd)
+ major=98
+ minor=0
+ until [ $minor -gt 255 ]
+ do
+ makedev ubd$minor b $major $minor $disk
+ minor=`math $minor + 1`
+ done
+ ;;
+ fb)
+ for i in 0 1 2 3 4 5 6 7
+ do
+ makedev fb$i c 29 `math 32 \* $i` $fb
+ makedev fb${i}current c 29 `math 32 \* $i` $fb
+ makedev fb${i}autodetect c 29 `math 32 \* $i + 1` $fb
+ done
+ ;;
+ fb[0-7])
+ dev=`suffix $arg fb`
+ base=`math 32 \* $dev`
+ makedev fb$dev c 29 $base $fb
+ makedev fb${dev}current c 29 $base $fb
+ makedev fb${dev}autodetect c 29 `math $base + 1` $fb
+ for i in 0 1 2 3 4 5 6 7
+ do
+ makedev fb${dev}user$i c 29 `math $base + 24 + $i` $fb
+ done
+ ;;
+ netlink|tap|tap[0-9]|tap1[0-5])
+ makedev route c 36 0 $coda
+ makedev skip c 36 1 $coda
+ makedev fwmonitor c 36 3 $coda
+ for i in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+ do
+ makedev tap$i c 36 `math $i + 16` $coda
+ done
+ ;;
+ lp)
+ major=`Major lp 6` || continue
+ makedev ${arg}0 c $major 0 $printer
+ makedev ${arg}1 c $major 1 $printer
+ makedev ${arg}2 c $major 2 $printer
+ ;;
+ par)
+ major=`Major lp 6` || continue
+ makedev ${arg}0 c $major 0 $printer
+ makedev ${arg}1 c $major 1 $printer
+ makedev ${arg}2 c $major 2 $printer
+ ;;
+ parport)
+ major=`Major parport 99` || continue
+ makedev ${arg}0 c $major 0 $printer
+ makedev ${arg}1 c $major 1 $printer
+ makedev ${arg}2 c $major 2 $printer
+ ;;
+ slm)
+ major=`Major slm 28` || continue
+ for i in 0 1 2 3
+ do
+ makedev slm c $major $i $printer
+ done
+ ;;
+ input)
+ major=`Major pcsp 13` || continue
+ mkdir -p input
+ for i in 0 1 2 3
+ do
+ makedev input/js$i c $major $i $mouse
+ makedev input/mouse$i c $major `math $i + 32` $mouse
+ makedev input/event$i c $major `math $i + 64` $mouse
+ done
+ makedev input/mice c $major 63 $mouse
+ ;;
+ busmice)
+ major=`Major mouse 10` || continue
+ makedev logibm c $major 0 $mouse
+ makedev psaux c $major 1 $mouse
+ makedev inportbm c $major 2 $mouse
+ makedev atibm c $major 3 $mouse
+ makedev jbm c $major 4 $mouse
+ ;;
+ m68k-mice)
+ major=`Major mouse 10` || continue
+ makedev amigamouse c $major 4 $mouse
+ makedev atarimouse c $major 5 $mouse
+ makedev amigamouse1 c $major 7 $mouse
+ makedev adbmouse c $major 10 $mouse
+ ;;
+ 3dfx)
+ major=`Major $arg 107` || continue
+ makedev $arg c $major 0 $video
+ ;;
+ agpgart)
+ major=`Major $arg 10` || continue
+ makedev $arg c $major 175 $video
+ ;;
+ intel_rng)
+ major=`Major $arg 10` || continue
+ makedev $arg c $major 183 $private
+ ;;
+ cpu|microcode)
+ mkdir -p cpu
+ makedev cpu/microcode c 10 184 $private
+ for i in 0 1 2 3
+ do
+ mkdir -p cpu/$i
+ makedev cpu/$i/msr c 202 $i $private
+ makedev cpu/$i/cpuid c 203 $i $private
+ done
+ ;;
+ ipmi|ipmikcs)
+ major=`Major ipmikcs 10` || continue
+ makedev ipmikcs c $major 173 $private
+ ;;
+ irda)
+ for i in 0 1
+ do
+ makedev ircomm$i c 161 $i $dialout
+ makedev irlpt$i c 161 `math $i + 16` $printer
+ done
+ ;;
+ misc)
+ major=`Major mouse 10` || continue
+ makedev logibm c $major 0 $mouse
+ makedev psaux c $major 1 $mouse
+ makedev inportbm c $major 2 $mouse
+ makedev atibm c $major 3 $mouse
+ makedev jbm c $major 4 $mouse
+ makedev amigamouse c $major 4 $mouse
+ makedev atarimouse c $major 5 $mouse
+ makedev sunmouse c $major 6 $mouse
+ makedev amigamouse1 c $major 7 $mouse
+ makedev smouse c $major 8 $mouse
+ makedev pc110pad c $major 9 $mouse
+ makedev adbmouse c $major 10 $mouse
+ makedev beep c $major 128 $mouse
+ makedev modreq c $major 129 $mouse
+ makedev watchdog c $major 130 $mouse
+ makedev temperature c $major 131 $mouse
+ makedev hwtrap c $major 132 $mouse
+ makedev exttrp c $major 133 $mouse
+ makedev apm_bios c $major 134 $mouse
+ makedev rtc c $major 135 $mouse
+ makedev openprom c $major 139 $mouse
+ makedev relay8 c $major 140 $mouse
+ makedev relay16 c $major 141 $mouse
+ makedev msr c $major 142 $mouse
+ makedev pciconf c $major 143 $mouse
+ makedev nvram c $major 144 $mouse
+ makedev hfmodem c $major 145 $mouse
+ makedev led c $major 151 $mouse
+ makedev mergemem c $major 153 $mouse
+ makedev pmu c $major 154 $mouse
+ ;;
+ smapi|thinkpad)
+ major=`Major mouse 10` || continue
+ makedev smapi c $major 170 $mouse
+ symlink thinkpad smapi
+ ;;
+ rtc)
+ major=`Major mouse 10` || continue
+ makedev rtc c $major 135 $mouse
+ ;;
+ efirtc)
+ major=`Major mouse 10` || continue
+ makedev efirtc c $major 136 $mouse
+ ;;
+ js)
+ major=`Major Joystick 13` || continue
+ for unit in 0 1 2 3
+ do
+ makedev js$unit c $major $unit $readable
+ makedev djs$unit c $major `math $unit + 128` $readable
+ done
+ ;;
+ fd[0-7]-bare)
+ sarg="${arg%-bare}"
+ major=`Major fd 2` || continue
+ base=`suffix $sarg fd`
+ if [ $base -ge 4 ]
+ then
+ base=`math $base + 124`
+ fi
+ makedev ${sarg} b $major $base $floppy
+ ;;
+ fd[0-7])
+ major=`Major fd 2` || continue
+ base=`suffix $arg fd`
+ if [ $base -ge 4 ]
+ then
+ base=`math $base + 124`
+ fi
+ makedev ${arg} b $major $base $floppy
+ makedev ${arg}d360 b $major `math $base + 4` $floppy
+ makedev ${arg}h1200 b $major `math $base + 8` $floppy
+ makedev ${arg}u360 b $major `math $base + 12` $floppy
+ makedev ${arg}u720 b $major `math $base + 16` $floppy
+ makedev ${arg}h360 b $major `math $base + 20` $floppy
+ makedev ${arg}h720 b $major `math $base + 24` $floppy
+ makedev ${arg}u1440 b $major `math $base + 28` $floppy
+ makedev ${arg}u2880 b $major `math $base + 32` $floppy
+ makedev ${arg}CompaQ b $major `math $base + 36` $floppy
+
+ makedev ${arg}h1440 b $major `math $base + 40` $floppy
+ makedev ${arg}u1680 b $major `math $base + 44` $floppy
+ makedev ${arg}h410 b $major `math $base + 48` $floppy
+ makedev ${arg}u820 b $major `math $base + 52` $floppy
+ makedev ${arg}h1476 b $major `math $base + 56` $floppy
+ makedev ${arg}u1722 b $major `math $base + 60` $floppy
+ makedev ${arg}h420 b $major `math $base + 64` $floppy
+ makedev ${arg}u830 b $major `math $base + 68` $floppy
+ makedev ${arg}h1494 b $major `math $base + 72` $floppy
+ makedev ${arg}u1743 b $major `math $base + 76` $floppy
+ makedev ${arg}h880 b $major `math $base + 80` $floppy
+ makedev ${arg}u1040 b $major `math $base + 84` $floppy
+ makedev ${arg}u1120 b $major `math $base + 88` $floppy
+ makedev ${arg}h1600 b $major `math $base + 92` $floppy
+ makedev ${arg}u1760 b $major `math $base + 96` $floppy
+ makedev ${arg}u1920 b $major `math $base + 100` $floppy
+ makedev ${arg}u3200 b $major `math $base + 104` $floppy
+ makedev ${arg}u3520 b $major `math $base + 108` $floppy
+ makedev ${arg}u3840 b $major `math $base + 112` $floppy
+ makedev ${arg}u1840 b $major `math $base + 116` $floppy
+ makedev ${arg}u800 b $major `math $base + 120` $floppy
+ makedev ${arg}u1600 b $major `math $base + 124` $floppy
+ ;;
+ ed[a-b])
+ major=`Major ed 36` || continue
+ unit=`suffix $arg ed`
+ base=`index ab $unit`
+ base=`math $base \* 64`
+ makedev ed$unit b $major $base $disk
+ for part in 1 2 3 4 5 6 7 8 # 9 10 11 12 13 14 15 16 17 18 19 20
+ do
+ makedev ed$unit$part b $major `math $base + $part` $disk
+ done
+ ;;
+ hd[a-b])
+ major=`Major ide0` || major=`Major hd 3` || continue
+ unit=`suffix $arg hd`
+ base=`index ab $unit`
+ base=`math $base \* 64`
+ makedev hd$unit b $major $base $disk
+ for part in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
+ do
+ makedev hd$unit$part b $major `math $base + $part` $disk
+ done
+ ;;
+ hd[c-d])
+ major=`Major ide1 22` || continue
+ unit=`suffix $arg hd`
+ base=`index cd $unit`
+ base=`math $base \* 64`
+ makedev hd$unit b $major $base $disk
+ for part in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
+ do
+ makedev hd$unit$part b $major $(( $base + $part )) $disk
+ done
+ ;;
+ hd[e-f])
+ major=`Major ide2 33` || continue
+ unit=`suffix $arg hd`
+ base=`index ef $unit`
+ base=`math $base \* 64`
+ makedev hd$unit b $major $base $disk
+ for part in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
+ do
+ makedev hd$unit$part b $major $(( $base + $part )) $disk
+ done
+ ;;
+ hd[g-h])
+ major=`Major ide3 34` || continue
+ unit=`suffix $arg hd`
+ base=`index gh $unit`
+ base=`math $base \* 64`
+ makedev hd$unit b $major $base $disk
+ for part in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
+ do
+ makedev hd$unit$part b $major $(( $base + $part )) $disk
+ done
+ ;;
+ hd[i-j])
+ major=`Major ide4 56` || continue
+ unit=`suffix $arg hd`
+ base=`index ij $unit`
+ base=`math $base \* 64`
+ makedev hd$unit b $major $base $disk
+ for part in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
+ do
+ makedev hd$unit$part b $major $(( $base + $part )) $disk
+ done
+ ;;
+ hd[k-l])
+ major=`Major ide5 57` || continue
+ unit=`suffix $arg hd`
+ base=`index kl $unit`
+ base=`math $base \* 64`
+ makedev hd$unit b $major $base $disk
+ for part in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
+ do
+ makedev hd$unit$part b $major $(( $base + $part )) $disk
+ done
+ ;;
+ ht0)
+ major=`Major ht0 37` || continue
+ # Only one IDE tape drive is currently supported; ht0.
+ makedev ht0 c $major 0 $tape
+ makedev nht0 c $major 128 $tape
+ ;;
+ pt)
+ major=`Major pt 96` || continue
+ for i in 0 1 2 3
+ do
+ makedev pt$i c $major $i $tape
+ makedev npt$i c $major `math $i + 128` $tape
+ done
+ ;;
+ xd[a-d])
+ major=`Major xd 13` || continue
+ unit=`suffix $arg xd`
+ base=`index abcd $unit`
+ base=`math $base \* 64`
+ makedev xd$unit b $major $base $disk
+ for part in 1 2 3 4 5 6 7 8 # 9 10 11 12 13 14 15 16 17 18 19 20
+ do
+ makedev xd$unit$part b $major $(( $base + $part )) $disk
+ done
+ ;;
+ sd[a-z])
+ major=`Major sd 8` || continue
+ unit=`suffix $arg sd`
+ base=`index abcdefghijklmnopqrstuvwxyz $unit`
+ base=$(( $base * 16 ))
+ if [ $base -lt 256 ]; then
+ major=8
+ else
+ major=65
+ base=$(( $base - 256 ))
+ fi
+ makedev sd$unit b $major $base $disk
+ for part in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+ do
+ minor=$(( $base + $part ))
+ makedev sd$unit$part b $major $minor $disk
+ done
+ ;;
+ sd[a-d][a-z])
+ unit=`suffix $arg sd`
+ unitmaj=`first $unit`
+ unitmin=`second $unit`
+ basemaj=`index Xabcd $unitmaj`
+ basemin=`index abcdefghijklmnopqrstuvwxyz $unitmin`
+ basemaj=`math $basemaj \* 416`
+ basemin=`math $basemin \* 16`
+ base=`math $basemaj + $basemin`
+ basemaj=`math $base / 256`
+ base=`math $base % 256`
+ major=`math basemaj \+ 64`
+ if [ $major -gt 71 ]; then
+ echo "$0: don't know how to make device \"$arg\"" >&2
+ exit 0
+ fi
+ makedev sd$unit b $major $base $disk
+ for part in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+ do
+ minor=$(( $base + $part ))
+ makedev sd$unit$part b $major $minor $disk
+ done
+ ;;
+ dasd[a-z])
+ major=`Major dasd 94` || continue
+ unit=`suffix $arg dasd`
+ base=`index abcdefghijklmnopqrstuvwxyz $unit`
+ base=$(( $base * 4 ))
+ if [ $base -lt 256 ]; then
+ major=94
+ else
+ major=65
+ base=$(( $base - 256 ))
+ fi
+ makedev dasd$unit b $major $base $disk
+ # Not yet implemented. (Feb. 8, 2001)
+ # for part in 1 2 3
+ for part in 1
+ do
+ minor=$(( $base + $part ))
+ makedev dasd$unit$part b $major $minor $disk
+ done
+ ;;
+ ad[a-p])
+ major=`Major ad 28` || continue
+ unit=`suffix $arg ad`
+ base=`index abcdefghijklmnop $unit`
+ base=`math $base \* 16`
+ makedev ad$unit b $major $base $disk
+ for part in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+ do
+ minor=$(( $base + $part ))
+ makedev ad$unit$part b $major $minor $disk
+ done
+ ;;
+ dac960)
+ for ctr in 0 1 2 3 4 5 6 7
+ do
+ $0 $opts dac960.$ctr
+ done
+ ;;
+ dac960.[0-7])
+ [ -d rd ] || {
+ mkdir rd
+ chown root:root rd
+ chmod 755 rd
+ }
+ unit=`suffix $arg dac960.`
+ major=`math 48 + $unit`
+ minor=0
+ for ld in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 \
+ 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
+ do
+ makedev rd/c${unit}d${ld} b $major $minor $disk
+ minor=`math $minor + 1`
+ for part in 1 2 3 4 5 6 7
+ do
+ makedev rd/c${unit}d${ld}p$part b $major $minor $disk
+ minor=`math $minor + 1`
+ done
+ done
+ ;;
+ ataraid)
+ for ctr in 0 1 2 # 3 4 5 6 7
+ do
+ $0 $opts ataraid.$ctr
+ done
+ ;;
+ ataraid.[0-7])
+ [ -d ataraid ] || {
+ mkdir ataraid
+ chown root:root ataraid
+ chmod 755 ataraid
+ }
+ unit=`suffix $arg ataraid.`
+ major=114
+ minor=`math $unit \* 16`
+ makedev ataraid/d${unit} b $major $minor $disk
+ for part in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+ do
+ minor=`math $minor + 1`
+ makedev ataraid/d${unit}p$part b $major $minor $disk
+ done
+ ;;
+ ida)
+ for ctr in 0 1 2 # 3 4 5 6 7
+ do
+ $0 $opts ida.$ctr
+ done
+ ;;
+ ida.[0-7])
+ [ -d ida ] || {
+ mkdir ida
+ chown root:root ida
+ chmod 755 ida
+ }
+ unit=`suffix $arg ida.`
+ major=`math 72 + $unit`
+ minor=0
+ for ld in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+ do
+ makedev ida/c${unit}d${ld} b $major $minor $disk
+ minor=`math $minor + 1`
+ for part in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+ do
+ makedev ida/c${unit}d${ld}p$part b $major $minor $disk
+ minor=`math $minor + 1`
+ done
+ done
+ ;;
+ cciss)
+ for ctr in 0 1 2 # 3 4 5 6 7
+ do
+ $0 $opts cciss.$ctr
+ done
+ ;;
+ cciss.[0-7])
+ [ -d cciss ] || {
+ mkdir cciss
+ chown root:root cciss
+ chmod 755 cciss
+ }
+ unit=`suffix $arg cciss.`
+ major=`math 104 + $unit`
+ minor=0
+ for ld in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+ do
+ makedev cciss/c${unit}d${ld} b $major $minor $disk
+ minor=`math $minor + 1`
+ for part in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+ do
+ makedev cciss/c${unit}d${ld}p$part b $major $minor $disk
+ minor=`math $minor + 1`
+ done
+ done
+ ;;
+ rom)
+ major=`Major rom 31`
+ for i in 0 1 2 3 4 5 6 7
+ do
+ makedev rom$i b $major $i $disk
+ makedev rrom$i b $major `math $i +8` $disk
+ makedev flash$i b $major `math $i +16` $disk
+ makedev rflash$i b $major `math $i +24` $disk
+ done
+ ;;
+ nb[0-7])
+ major=`Major nbd 43` || continue
+ minor=`suffix $arg nb`
+ makedev nb$minor b $major $minor $disk
+ ;;
+ loop)
+ for part in 0 1 2 3 4 5 6 7
+ do
+ makedev loop$part b 7 $part $disk
+ done
+ ;;
+ md)
+ major=`Major md 9` || continue
+ for part in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+ do
+ makedev md$part b $major $part $disk
+ done
+ ;;
+ st[0-7])
+ major=`Major st 9`
+ unit=`suffix $arg st`
+ makedev st${unit} c $major $unit $tape
+ makedev nst${unit} c $major `math 128 + $unit` $tape
+
+ makedev st${unit}l c $major `math 32 + $unit` $tape
+ makedev nst${unit}l c $major `math 160 + $unit` $tape
+
+ makedev st${unit}m c $major `math 64 + $unit` $tape
+ makedev nst${unit}m c $major `math 192 + $unit` $tape
+
+ makedev st${unit}a c $major `math 96 + $unit` $tape
+ makedev nst${unit}a c $major `math 224 + $unit` $tape
+ ;;
+ qic)
+ major=`Major tpqic02 12`
+ makedev ntpqic11 c $major 2 $tape
+ makedev tpqic11 c $major 3 $tape
+ makedev ntpqic24 c $major 4 $tape
+ makedev tpqic24 c $major 5 $tape
+ makedev ntpqic120 c $major 6 $tape
+ makedev tpqic120 c $major 7 $tape
+ makedev ntpqic150 c $major 8 $tape
+ makedev tpqic150 c $major 9 $tape
+ makedev rmt8 c $major 6 $tape
+ makedev rmt16 c $major 8 $tape
+ makedev tape-d c $major 136 $tape
+ makedev tape-reset c $major 255 $tape
+ $0 $opts qft
+ ;;
+ ftape)
+ major=`Major qft 27` || continue
+ for unit in 0 1 2 3
+ do
+ makedev qft$unit c $major $unit $tape
+ makedev nqft$unit c $major `math $unit + 4` $tape
+ makedev zqft$unit c $major `math $unit + 16` $tape
+ makedev nzqft$unit c $major `math $unit + 20` $tape
+ makedev rawqft$unit c $major `math $unit + 32` $tape
+ makedev nrawqft$unit c $major `math $unit + 36` $tape
+ done
+ symlink ftape qft0
+ symlink nftape nqft0
+ ;;
+ sr|scd|scd-all)
+ major=`Major sr 11` || continue
+ for unit in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
+ do
+ makedev scd$unit b $major $unit $cdrom
+ symlink sr$unit scd$unit
+ done
+ ;;
+ pktcdvd)
+ major=97
+ for unit in 0 1 2 3
+ do
+ makedev pktcdvd$unit b $major $unit $cdrom
+ done
+ ;;
+ cfs0)
+ makedev cfs0 c 67 0 $coda
+ ;;
+ scd[0-9]|scd[0-1][0-9])
+ major=`Major sr 11` || continue
+ unit=`suffix $arg scd`
+ makedev scd$unit b $major $unit $cdrom
+ ln -f scd$unit sr$unit
+ ;;
+ ttyI[0-9]|ttyI[1-5][0-9]|ttyI[6][0-3])
+ major=43
+ unit=`suffix $arg ttyI`
+ makedev ttyI$unit c $major $unit $dialout
+ ;;
+ ppp)
+ major=108
+ makedev ppp c $major 0 $dip
+ ;;
+ ippp[0-9]|ippp[1-5][0-9]|ippp[6][0-3])
+ major=45
+ unit=`suffix $arg ippp`
+ minor=`math $unit + 128`
+ makedev ippp$unit c $major $minor $dialout
+ ;;
+ isdn[0-9]|isdn[1-5][0-9]|isdn[6][0-3])
+ major=45
+ unit=`suffix $arg isdn`
+ minor=`math $unit + 0`
+ makedev isdn$unit c $major $minor $dialout
+ ;;
+ isdnctrl[0-9]|isdnctrl[1-5][0-9]|isdnctrl[6][0-3])
+ major=45
+ unit=`suffix $arg isdnctrl`
+ minor=`math $unit + 64`
+ makedev isdnctrl$unit c $major $minor $dialout
+ ;;
+ isdninfo)
+ makedev isdninfo c 45 255 $private
+ ;;
+ isdn-tty)
+ major=43
+ for unit in 0 1 2 3 4 5 6 7
+ do
+ makedev ttyI$unit c $major $unit $dialout
+ done
+ ;;
+ isdn-ippp)
+ major=45
+ for unit in 0 1 2 3 4 5 6 7
+ do
+ makedev ippp$unit c $major `math $unit + 128` $dialout
+ done
+ ;;
+ isdn-io)
+ for unit in 0 1 2 3 4 5 6 7
+ do
+ makedev isdn$unit c 45 $unit $dialout
+ makedev isdnctrl$unit c 45 `math $unit + 64` $dialout
+ makedev ippp$unit c 45 `math $unit + 128` $dialout
+ done
+ makedev isdninfo c 45 255 $dialout
+ ;;
+ sonycd)
+ major=`Major sonycd 15` || continue
+ makedev $arg b $major 0 $cdrom
+ ;;
+ mcd)
+ major=`Major mcd 23` || continue
+ makedev $arg b $major 0 $cdrom
+ ;;
+ mcdx|mcdx[0-4])
+ major=`Major $arg 20` || continue
+ for unit in 0 1 2 3 4
+ do
+ makedev mcdx$unit b $major $unit $cdrom
+ done
+ test -r mcdx || symlink mcdx mcdx0
+ ;;
+ cdu535)
+ makedev $arg b 24 0 $cdrom
+ ;;
+ lmscd)
+ makedev $arg b 24 0 $cdrom
+ ;;
+ sbpcd|sbpcd[123])
+ major=`Major $arg 25` || continue
+ base=`suffix ${arg}0 sbpcd`
+ for minor in 0 1 2 3
+ do
+ # XXX
+ unit=$(substr 0123456789abcdef $(( $base * 4 + $minor + 1 )) )
+ makedev sbpcd$unit b $major $minor $cdrom
+ done
+ [ $arg = sbpcd ] && symlink $arg ${arg}0
+ ;;
+ aztcd)
+ major=`Major $arg 29` || continue
+ makedev ${arg}0 b $major 0 $cdrom
+ ;;
+ cm206cd)
+ major=`Major $arg 30` || continue
+ makedev ${arg}0 b $major 0 $cdrom
+ ;;
+ gscd)
+ major=`Major $arg 16` || continue
+ makedev ${arg}0 b $major 0 $cdrom
+ ;;
+ pcd)
+ for unit in 0 1 2 3
+ do
+ makedev pcd$unit b 46 $unit $cdrom
+ done
+ ;;
+ bpcd)
+ makedev $arg b 41 0 $cdrom
+ ;;
+ optcd)
+ makedev $arg b 17 0 $cdrom
+ ;;
+ sjcd)
+ makedev $arg b 18 0 $cdrom
+ ;;
+ cfs|coda)
+ makedev cfs0 c 67 0 $private
+ ;;
+ xfs|arla)
+ makedev xfs0 c 103 0 $private
+ ;;
+ logiscan)
+ major=`Major logiscan` || continue
+ makedev $arg c $major 0 $scanner
+ ;;
+ toshiba)
+ major=`Major $arg 10` || continue
+ makedev $arg c $major 181 root root 0666
+ ;;
+ m105scan)
+ major=`Major m105` || continue
+ makedev $arg c $major 0 $scanner
+ ;;
+ ac4096)
+ major=`Major ac4096` || continue
+ makedev $arg c $major 0 $scanner
+ ;;
+ audio)
+ major=`Major sound 14`
+ makedev mixer c $major 0 $audio
+ makedev mixer1 c $major 16 $audio
+ makedev mixer2 c $major 32 $audio
+ makedev mixer3 c $major 48 $audio
+ makedev sequencer c $major 1 $audio
+ makedev midi00 c $major 2 $audio
+ makedev midi01 c $major 18 $audio
+ makedev midi02 c $major 34 $audio
+ makedev midi03 c $major 50 $audio
+ makedev dsp c $major 3 $audio
+ makedev dsp1 c $major 19 $audio
+ makedev dsp2 c $major 35 $audio
+ makedev dsp3 c $major 51 $audio
+ makedev audio c $major 4 $audio
+ makedev audio1 c $major 20 $audio
+ makedev audio2 c $major 36 $audio
+ makedev audio3 c $major 52 $audio
+ makedev sndstat c $major 6 $audio
+ makedev audioctl c $major 7 $audio
+ major=31
+ makedev mpu401data c $major 0 $audio
+ makedev mpu401stat c $major 1 $audio
+ major=35
+ for i in 0 1 2 3
+ do
+ makedev midi$i c $major $i $audio
+ makedev rmidi$i c $major `math $i + 64` $audio
+ makedev smpte$i c $major `math $i + 128` $audio
+ done
+ ;;
+ pcaudio)
+ major=`Major pcsp 13` || continue
+ makedev pcmixer c $major 0 $audio
+ makedev pcsp c $major 3 $audio
+ makedev pcaudio c $major 4 $audio
+ ;;
+ video|video4linux|v4l|radio)
+ # video4linux api includes radio, teletext, etc.
+ major=`Major video 81` || continue
+ minor=0
+ until [ $minor -gt 63 ]
+ do
+ makedev video$minor c $major $minor $video
+ makedev radio$minor c $major `math $minor + 64` $video
+ minor=`math $minor + 1`
+ done
+ symlink radio radio0
+ minor=0
+ until [ $minor -gt 31 ]
+ do
+ makedev vtx$minor c $major `math $minor + 192` $video
+ makedev vbi$minor c $major `math $minor + 224` $video
+ minor=`math $minor + 1`
+ done
+ symlink video video0
+ symlink vbi vbi0
+ major=82
+ minor=0
+ until [ $minor -gt 1 ]
+ do
+ makedev winradio$minor c $major $minor $video
+ minor=`math $minor + 1`
+ done
+ major=83
+ makedev vtx c $major 0 $video
+ makedev vttuner c $major 16 $video
+ ;;
+ i2c)
+ # making it possible to create an arbitrary number of i2c
+ # devices might be good, but 8 should suffice for now
+ major=`Major i2c 89` || continue
+ minor=0
+ until [ $minor -gt 7 ]
+ do
+ makedev i2c-$minor c $major $minor $private
+ minor=`math $minor + 1`
+ done
+ ;;
+ tlk)
+ major=102
+ minor=0
+ until [ $minor -gt 3 ] # tell me if 3 is wrong...
+ do
+ makedev tlk$minor c $major $minor $video
+ minor=`math $minor + 1`
+ done
+ ;;
+ srnd)
+ makedev srnd0 c 110 0 $video
+ makedev srnd1 c 110 1 $video
+ ;;
+ fgrab)
+ makedev mmetfgrab c 40 0 $video
+ makedev wvisfgrab c 26 0 $video
+ for i in 0 1 # more?
+ do
+ makedev iscc$i c 93 $i $video
+ makedev isccctl$i c 93 `math $i + 128` $video
+ done
+ for i in 0 1 # more?
+ do
+ makedev dcxx$i c 94 $i $video
+ done
+ ;;
+ sg|sg-all)
+ major=`Major sg 21`
+ for unit in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
+ do
+ makedev sg$unit c $major $unit $scsi
+ done
+ ;;
+ pg)
+ major=`Major pg 97`
+ for unit in 0 1 2 3
+ do
+ makedev pg$unit c $major $unit $scsi
+ done
+ ;;
+ fd)
+ # not really devices, we use the /proc filesystem
+ symlink fd $procfs/self/fd
+ symlink stdin fd/0
+ symlink stdout fd/1
+ symlink stderr fd/2
+ ;;
+ ibcs2)
+ major=`Major ibcs2 30` || continue
+ makedev socksys c $major 0 $ibcs2
+ symlink nfsd socksys
+ makedev spx c $major 1 $ibcs2
+ symlink X0R null
+ ;;
+ netlink)
+ major=36
+ makedev route c $major 0 $private
+ makedev skip c $major 1 $private
+ ;;
+ enskip)
+ major=64
+ makedev enskip c $major 0 $private
+ ;;
+ ipfilt*)
+ major=95
+ makedev ipl c $major 0 $private
+ makedev ipnat c $major 1 $private
+ makedev ipstate c $major 2 $private
+ makedev ipauth c $major 3 $private
+ ;;
+ qng)
+ makedev qng c 77 0 $private
+ ;;
+ apm)
+ major=`Major mouse 10` || continue
+ makedev apm_bios c $major 134 $mouse
+ ;;
+ dcf)
+ major=`Major dcf` || continue
+ makedev $arg c $major 0 $system
+ ;;
+ helloworld)
+ major=`Major hw` || continue
+ makedev helloworld c $major 0 $public
+ ;;
+ ipsec)
+ # For the Free S/WAN (http://www.xs4all.nl/~freeswan/)
+ # implementation of IPSEC
+ makedev ipsec c 36 10 $ipsec
+ ;;
+ comedi)
+ major=98
+ for minor in 0 1 2 3
+ do
+ makedev comedi$minor c $major $minor $public
+ done
+ ;;
+ usb)
+ mkdir -p usb
+ major=180
+ for i in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+ do
+ makedev usb/lp$i c $major $i $printer
+ makedev usb/mouse$i c $major `math $i + 16` $mouse
+ makedev usb/ez$i c $major `math $i + 32` $system
+ makedev usb/scanner$i c $major `math $i + 48` $scanner
+ makedev ttyACM$i c 166 $i $dialout
+ makedev ttyUSB$i c 188 $i $dialout
+ done
+ makedev usb/rio500 c $major 64 $audio
+ ;;
+ paride)
+ major=45
+ for unit in a b c d
+ do
+ base=`index abcd $unit`
+ base=`math $base \* 16`
+ makedev pd$unit b $major $base $disk
+ for part in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+ do
+ makedev pd$unit$part b $major $(( $base + $part )) $disk
+ done
+ done
+ for i in 0 1 2 3
+ do
+ makedev pcd$i b 46 $i $cdrom
+ makedev pf$i b 47 $i $floppy
+ done
+ ;;
+ update)
+ if [ ! "$devices" ]
+ then
+ echo "$0: don't appear to have any devices" >&2
+ continue
+ fi
+ if [ "$opt_d" ]
+ then
+ echo "$0: can't delete an update" >&2
+ continue
+ fi
+ create=
+ delete=
+ devs="$devices"
+ if [ -f DEVICES ]
+ then
+ exec 3<DEVICES
+ while read device major <&3
+ do
+ eval now=\$major_${device/-/_}
+ if [ "$now" = "" ]
+ then
+ delete="$delete `cvt $device`"
+ continue
+ elif [ "$now" != $major ]
+ then
+ create="$create "`cvt $device`
+ fi
+ devs=`strip " $devs " $device`
+ done
+ exec 3<&-
+ fi
+ create="$create "`cvt $devs`
+ [ "$delete" != "" ] && $0 $opts -d $delete
+ [ "$create" != " " ] && $0 $opts $create
+ [ "$opt_n" ] && continue
+ for device in $devices
+ do
+ if [ "`cvt $device`" ]
+ then
+ eval echo $device \$major_${device/-/_}
+ fi
+ done > DEVICES
+ ;;
+ *)
+ echo "$0: don't know how to make device \"$arg\"" >&2
+ exit 1
+ ;;
+ esac
+done
+
+exit 0
diff --git a/sbin/MAKEDEV-gentoo.patch b/sbin/MAKEDEV-gentoo.patch
new file mode 100755
index 0000000..14e5edf
--- /dev/null
+++ b/sbin/MAKEDEV-gentoo.patch
@@ -0,0 +1,210 @@
+--- MAKEDEV.orig 2003-03-09 08:12:11.000000000 +0200
++++ MAKEDEV 2003-03-09 08:26:25.000000000 +0200
+@@ -260,48 +260,65 @@
+ # case `cvt $arg` in
+ case $arg in
+ generic)
+- # pick the right generic-<arch> using dpkg's knowledge
+- case `dpkg --print-installation-architecture` in
+- alpha)
+- $0 $opts generic-alpha
+- ;;
+- arm)
+- $0 $opts generic-arm
+- ;;
+- hppa)
+- $0 $opts generic-hppa
+- ;;
+- i386)
+- $0 $opts generic-i386
+- ;;
+- ia64)
+- $0 $opts generic-ia64
+- ;;
+- m68k)
+- $0 $opts generic-m68k
+- ;;
+- mips)
+- $0 $opts generic-mips
+- ;;
+- mipsel)
+- $0 $opts generic-mipsel
+- ;;
+- powerpc)
+- $0 $opts generic-powerpc
+- ;;
+- s390)
+- $0 $opts generic-s390
+- ;;
+- sparc)
+- $0 $opts generic-sparc
+- ;;
+- *)
+- echo "$0: no support for generic on this arch" >&2
+- exit 1
+- ;;
+- esac
++ if [ -n "`which dpkg 2> /dev/null`" ]
++ then
++ # pick the right generic-<arch> using dpkg's knowledge
++ case `dpkg --print-installation-architecture` in
++ alpha)
++ $0 $opts generic-alpha
++ ;;
++ arm)
++ $0 $opts generic-arm
++ ;;
++ hppa)
++ $0 $opts generic-hppa
++ ;;
++ i386)
++ $0 $opts generic-i386
++ ;;
++ ia64)
++ $0 $opts generic-ia64
++ ;;
++ m68k)
++ $0 $opts generic-m68k
++ ;;
++ mips)
++ $0 $opts generic-mips
++ ;;
++ mipsel)
++ $0 $opts generic-mipsel
++ ;;
++ powerpc)
++ $0 $opts generic-powerpc
++ ;;
++ s390)
++ $0 $opts generic-s390
++ ;;
++ sparc)
++ $0 $opts generic-sparc
++ ;;
++ *)
++ echo "$0: no support for generic on this arch" >&2
++ exit 1
++ ;;
++ esac
++ else
++ $0 $opts std
++ $0 $opts fd
++ $0 $opts fd0 fd1
++ $0 $opts hda hdb
++ $0 $opts xda xdb
++ $0 $opts sda sdb
++ $0 $opts pty
++ $0 $opts console
++ $0 $opts ttyS0 ttyS1 ttyS2 ttyS3
++ $0 $opts busmice
++ $0 $opts lp
++ $0 $opts par
++ fi
+ ;;
+ generic-alpha)
++ export MDARCH="alpha"
+ $0 $opts std
+ $0 $opts fd
+ $0 $opts fd0 fd1
+@@ -321,6 +338,7 @@
+ $0 $opts fb
+ ;;
+ generic-arm)
++ export MDARCH="arm"
+ $0 $opts std
+ $0 $opts fd
+ $0 $opts fd0 fd1
+@@ -340,6 +358,7 @@
+ $0 $opts fb
+ ;;
+ generic-hppa)
++ export MDARCH="hppa"
+ $0 $opts std
+ $0 $opts fd
+ $0 $opts fd0 fd1
+@@ -358,6 +377,7 @@
+ $0 $opts rtc
+ ;;
+ generic-i386)
++ export MDARCH="i386"
+ $0 $opts std
+ $0 $opts fd
+ $0 $opts fd0 fd1
+@@ -380,6 +400,7 @@
+ $0 $opts lmscd sbpcd aztcd bpcd dac960 ida ataraid cciss
+ ;;
+ generic-ia64)
++ export MDARCH="ia64"
+ $0 $opts std
+ $0 $opts fd
+ $0 $opts fd0 fd1
+@@ -400,6 +421,7 @@
+ $0 $opts efirtc
+ ;;
+ generic-m68k)
++ export MDARCH="m68k"
+ $0 $opts std
+ $0 $opts fd
+ $0 $opts fd0 fd1
+@@ -418,6 +440,7 @@
+ $0 $opts fb
+ ;;
+ generic-mips)
++ export MDARCH="mips"
+ $0 $opts std
+ $0 $opts fd
+ $0 $opts fd0 fd1
+@@ -436,6 +459,7 @@
+ $0 $opts busmice
+ ;;
+ generic-mipsel)
++ export MDARCH="mipsel"
+ $0 $opts std
+ $0 $opts fd
+ $0 $opts fd0 fd1
+@@ -454,6 +478,7 @@
+ $0 $opts rtc
+ ;;
+ generic-powerpc)
++ export MDARCH="powerpc"
+ $0 $opts std
+ $0 $opts fd
+ $0 $opts fd0 fd1
+@@ -478,6 +503,7 @@
+ $0 $opts isdn-io
+ ;;
+ generic-s390)
++ export MDARCH="s390"
+ $0 $opts std
+ $0 $opts fd
+ $0 $opts dasda dasdb dasdc dasdd dasde dasdf dasdg dasdh \
+@@ -489,6 +515,7 @@
+ $0 $opts rtc
+ ;;
+ generic-sparc)
++ export MDARCH="sparc"
+ $0 $opts std
+ $0 $opts fd0-bare fd1-bare
+ $0 $opts hda hdb hdc hdd
+@@ -601,8 +628,19 @@
+ done
+ ;;
+ adb)
+- # pick the right arch device using dpkg's knowledge
+- case `dpkg --print-installation-architecture` in
++ myarch=
++
++ if [ -n "`which dpkg 2> /dev/null`" ]
++ then
++ # pick the right arch device using dpkg's knowledge
++ myarch="`dpkg --print-installation-architecture`"
++
++ elif [ -n "${MDARCH}" ]
++ then
++ myarch="${MDARCH}"
++ fi
++
++ case $myarch in
+ powerpc)
+ # ADB bus devices (char)
+ makedev adb c 56 0 $mouse
diff --git a/sbin/depscan.sh b/sbin/depscan.sh
new file mode 100755
index 0000000..1fbf0ef
--- /dev/null
+++ b/sbin/depscan.sh
@@ -0,0 +1,93 @@
+#!/bin/bash
+# Copyright 1999-2004 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+source /sbin/functions.sh
+
+if [[ $1 == "--debug" ]] ; then
+ shift
+ set -x
+fi
+
+if [[ ! -d ${svcdir} ]]; then
+ if ! mkdir -p -m 0755 "${svcdir}" 2>/dev/null ; then
+ eerror "Could not create needed directory '${svcdir}'!"
+ fi
+fi
+
+for x in softscripts snapshot options daemons \
+ started starting inactive stopping failed \
+ exclusive exitcodes ; do
+ if [[ ! -d "${svcdir}/${x}" ]] ; then
+ if ! mkdir -p -m 0755 "${svcdir}/${x}" 2>/dev/null ; then
+ eerror "Could not create needed directory '${svcdir}/${x}'!"
+ fi
+ fi
+done
+
+# Only update if files have actually changed
+update=1
+
+if [[ $1 == "-u" ]] ; then
+ update=0
+ clock_screw=0
+ mtime_test="${svcdir}/mtime-test.$$"
+
+ # If its not there, we have to update, and make sure its present
+ # for next mtime testing
+ if [[ ! -e ${svcdir}/depcache ]] ; then
+ update=1
+ touch "${svcdir}/depcache"
+ fi
+
+ touch "${mtime_test}"
+ for config in /etc/conf.d /etc/init.d /etc/rc.conf
+ do
+ [[ ${update} == 0 ]] && \
+ is_older_than "${svcdir}/depcache" "${config}" && update=1
+
+ is_older_than "${mtime_test}" "${config}" && clock_screw=1
+ done
+ rm -f "${mtime_test}"
+
+ [[ ${clock_screw} == 1 ]] && \
+ ewarn "Some file in '/etc/{conf.d,init.d}' have Modification time in the future!"
+
+ shift
+fi
+
+[[ ${update} == 0 ]] && exit 0
+
+ebegin "Caching service dependencies"
+
+# Clean out the non volitile directories ...
+rm -rf "${svcdir}"/dep{cache,tree} "${svcdir}"/{broken,snapshot}/*
+
+retval=0
+SVCDIR="${svcdir}"
+DEPTYPES="${deptypes}"
+ORDTYPES="${ordtypes}"
+
+export SVCDIR DEPTYPES ORDTYPES
+
+cd /etc/init.d
+
+/bin/gawk \
+ -f /lib/rcscripts/awk/functions.awk \
+ -f /lib/rcscripts/awk/cachedepends.awk || \
+ retval=1
+
+bash "${svcdir}/depcache" | \
+/bin/gawk \
+ -f /lib/rcscripts/awk/functions.awk \
+ -f /lib/rcscripts/awk/gendepends.awk || \
+ retval=1
+
+touch "${svcdir}"/dep{cache,tree}
+chmod 0644 "${svcdir}"/dep{cache,tree}
+
+eend ${retval} "Failed to cache service dependencies"
+
+exit ${retval}
+
+# vim:ts=4
diff --git a/sbin/env-update.sh b/sbin/env-update.sh
new file mode 100755
index 0000000..533e989
--- /dev/null
+++ b/sbin/env-update.sh
@@ -0,0 +1,42 @@
+#!/bin/bash
+# Copyright 1999-2004 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+source /sbin/functions.sh || exit 1
+
+if [ "${EUID}" -ne 0 ]
+then
+ eerror "$0: must be root."
+ exit 1
+fi
+
+usage() {
+echo "usage: env-update.sh
+
+note:
+ This utility generates /etc/profile.env and /etc/csh.env
+ from the contents of /etc/env.d/
+"
+ exit 1
+}
+
+export SVCDIR="${svcdir}"
+
+# Only update if files have actually changed
+if [ "$1" == "-u" ]
+then
+ is_older_than "${svcdir}/envcache" /etc/env.d && exit 0
+ shift
+fi
+
+if [ "$#" -ne 0 ]
+then
+ usage
+else
+ /bin/gawk \
+ -f /lib/rcscripts/awk/functions.awk \
+ -f /lib/rcscripts/awk/genenviron.awk
+fi
+
+
+# vim:ts=4
diff --git a/sbin/functions.sh b/sbin/functions.sh
new file mode 100755
index 0000000..a210c4f
--- /dev/null
+++ b/sbin/functions.sh
@@ -0,0 +1,868 @@
+# Copyright 1999-2005 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+RC_GOT_FUNCTIONS="yes"
+
+# daemontools dir
+SVCDIR="/var/lib/supervise"
+
+# Check /etc/conf.d/rc for a description of these ...
+svcdir="/var/lib/init.d"
+svclib="/lib/rcscripts"
+svcmount="no"
+svcfstype="tmpfs"
+svcsize=1024
+
+# Different types of dependencies
+deptypes="need use"
+# Different types of order deps
+ordtypes="before after"
+
+#
+# Internal variables
+#
+
+# Dont output to stdout?
+RC_QUIET_STDOUT="no"
+RC_VERBOSE=${RC_VERBOSE:-no}
+
+# Should we use color?
+RC_NOCOLOR=${RC_NOCOLOR:-no}
+# Can the terminal handle endcols?
+RC_ENDCOL="yes"
+
+#
+# Default values for rc system
+#
+RC_TTY_NUMBER=11
+RC_NET_STRICT_CHECKING="no"
+RC_PARALLEL_STARTUP="no"
+RC_USE_CONFIG_PROFILE="yes"
+
+#
+# Default values for e-message indentation and dots
+#
+RC_INDENTATION=''
+RC_DEFAULT_INDENT=2
+#RC_DOT_PATTERN=' .'
+RC_DOT_PATTERN=''
+
+# Override defaults with user settings ...
+[ -f /etc/conf.d/rc ] && source /etc/conf.d/rc
+
+# void import_addon(char *addon)
+#
+# Import code from the specified addon if it exists
+#
+import_addon() {
+ local addon=${svclib}/addons/$1
+ if [[ -r ${addon} ]] ; then
+ source "${addon}"
+ return 0
+ fi
+ return 1
+}
+
+# void splash(...)
+#
+# Notify bootsplash/splashutils/gensplash/whatever about
+# important events.
+#
+splash() {
+ return 0
+}
+# This will override the splash() function...
+if ! import_addon splash-functions.sh ; then
+ [ -f /sbin/splash-functions.sh ] && source /sbin/splash-functions.sh
+fi
+
+# void profiling(...)
+#
+# Notify bootsplash/whatever about important events.
+#
+profiling() {
+ return 0
+}
+import_addon profiling-functions.sh
+
+# void bootlog(...)
+#
+# Notify bootlogger about important events.
+bootlog() {
+ return 0
+}
+[[ ${RC_BOOTLOG} == "yes" ]] && import_addon bootlogger.sh
+
+# void get_bootconfig()
+#
+# Get the BOOTLEVEL and SOFTLEVEL by setting
+# 'bootlevel' and 'softlevel' via kernel
+# parameters.
+#
+get_bootconfig() {
+ local copt=
+ local newbootlevel=
+ local newsoftlevel=
+
+ if [[ -r /proc/cmdline ]] ; then
+ for copt in $(</proc/cmdline) ; do
+ case "${copt%=*}" in
+ bootlevel)
+ newbootlevel=${copt##*=}
+ ;;
+ softlevel)
+ newsoftlevel=${copt##*=}
+ ;;
+ esac
+ done
+ fi
+
+ if [[ -n ${newbootlevel} ]] ; then
+ export BOOTLEVEL=${newbootlevel}
+ else
+ export BOOTLEVEL="boot"
+ fi
+
+ if [[ -n ${newsoftlevel} ]] ; then
+ export DEFAULTLEVEL=${newsoftlevel}
+ else
+ export DEFAULTLEVEL="default"
+ fi
+
+ return 0
+}
+
+setup_defaultlevels() {
+ get_bootconfig
+
+ if get_bootparam "noconfigprofile" ; then
+ export RC_USE_CONFIG_PROFILE="no"
+
+ elif get_bootparam "configprofile" ; then
+ export RC_USE_CONFIG_PROFILE="yes"
+ fi
+
+ if [ "${RC_USE_CONFIG_PROFILE}" = "yes" -a -n "${DEFAULTLEVEL}" ] && \
+ [ -d "/etc/runlevels/${BOOTLEVEL}.${DEFAULTLEVEL}" -o \
+ -L "/etc/runlevels/${BOOTLEVEL}.${DEFAULTLEVEL}" ]
+ then
+ export BOOTLEVEL="${BOOTLEVEL}.${DEFAULTLEVEL}"
+ fi
+
+ if [ -z "${SOFTLEVEL}" ] ; then
+ if [ -f "${svcdir}/softlevel" ] ; then
+ export SOFTLEVEL="$(< ${svcdir}/softlevel)"
+ else
+ export SOFTLEVEL="${BOOTLEVEL}"
+ fi
+ fi
+
+ return 0
+}
+
+# void get_libdir(void)
+#
+# prints the current libdir {lib,lib32,lib64}
+#
+get_libdir() {
+ if [ -n "${CONF_LIBDIR_OVERRIDE}" ] ; then
+ CONF_LIBDIR="${CONF_LIBDIR_OVERRIDE}"
+ elif [ -x "/usr/bin/portageq" ] ; then
+ CONF_LIBDIR="$(/usr/bin/portageq envvar CONF_LIBDIR)"
+ fi
+ echo ${CONF_LIBDIR:=lib}
+}
+
+# void esyslog(char* priority, char* tag, char* message)
+#
+# use the system logger to log a message
+#
+esyslog() {
+ local pri=
+ local 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
+}
+
+# void eindent(int num)
+#
+# increase the indent used for e-commands.
+#
+eindent() {
+ local i=$1
+ (( i > 0 )) || (( i = RC_DEFAULT_INDENT ))
+ esetdent $(( ${#RC_INDENTATION} + i ))
+}
+
+# void eoutdent(int num)
+#
+# decrease the indent used for e-commands.
+#
+eoutdent() {
+ local i=$1
+ (( i > 0 )) || (( i = RC_DEFAULT_INDENT ))
+ esetdent $(( ${#RC_INDENTATION} - i ))
+}
+
+# void esetdent(int num)
+#
+# hard set the indent used for e-commands.
+# num defaults to 0
+#
+esetdent() {
+ local i=$1
+ (( i < 0 )) && (( i = 0 ))
+ RC_INDENTATION=$(printf "%${i}s" '')
+}
+
+# void einfo(char* message)
+#
+# show an informative message (with a newline)
+#
+einfo() {
+ einfon "$*\n"
+ LAST_E_CMD=einfo
+ return 0
+}
+
+# void einfon(char* message)
+#
+# show an informative message (without a newline)
+#
+einfon() {
+ [[ ${RC_QUIET_STDOUT} == yes ]] && return 0
+ [[ ${RC_ENDCOL} != yes && ${LAST_E_CMD} == ebegin ]] && echo
+ echo -ne " ${GOOD}*${NORMAL} ${RC_INDENTATION}$*"
+ LAST_E_CMD=einfon
+ return 0
+}
+
+# void ewarn(char* message)
+#
+# show a warning message + log it
+#
+ewarn() {
+ if [[ ${RC_QUIET_STDOUT} == yes ]]; then
+ echo " $*"
+ else
+ [[ ${RC_ENDCOL} != yes && ${LAST_E_CMD} == ebegin ]] && echo
+ echo -e " ${WARN}*${NORMAL} ${RC_INDENTATION}$*"
+ fi
+
+ # Log warnings to system log
+ esyslog "daemon.warning" "rc-scripts" "$*"
+
+ LAST_E_CMD=ewarn
+ return 0
+}
+
+# void eerror(char* message)
+#
+# show an error message + log it
+#
+eerror() {
+ if [[ ${RC_QUIET_STDOUT} == yes ]]; then
+ echo " $*" >/dev/stderr
+ else
+ [[ ${RC_ENDCOL} != yes && ${LAST_E_CMD} == ebegin ]] && echo
+ echo -e " ${BAD}*${NORMAL} ${RC_INDENTATION}$*"
+ fi
+
+ # Log errors to system log
+ esyslog "daemon.err" "rc-scripts" "$*"
+
+ LAST_E_CMD=eerror
+ return 0
+}
+
+# void ebegin(char* message)
+#
+# show a message indicating the start of a process
+#
+ebegin() {
+ local msg="$*" dots spaces=${RC_DOT_PATTERN//?/ }
+ [[ ${RC_QUIET_STDOUT} == yes ]] && return 0
+
+ if [[ -n ${RC_DOT_PATTERN} ]]; then
+ dots=$(printf "%$(( COLS - 3 - ${#RC_INDENTATION} - ${#msg} - 7 ))s" '')
+ dots=${dots//${spaces}/${RC_DOT_PATTERN}}
+ msg="${msg}${dots}"
+ else
+ msg="${msg} ..."
+ fi
+ einfon "${msg}"
+ [[ ${RC_ENDCOL} == yes ]] && echo
+
+ LAST_E_LEN=$(( 3 + ${#RC_INDENTATION} + ${#msg} ))
+ LAST_E_CMD=ebegin
+ return 0
+}
+
+# void _eend(int error, char *efunc, char* errstr)
+#
+# indicate the completion of process, called from eend/ewend
+# if error, show errstr via efunc
+#
+# This function is private to functions.sh. Do not call it from a
+# script.
+#
+_eend() {
+ local retval=${1:-0} efunc=${2:-eerror} msg
+ shift 2
+
+ if [[ ${retval} == 0 ]]; then
+ [[ ${RC_QUIET_STDOUT} == yes ]] && return 0
+ msg="${BRACKET}[ ${GOOD}ok${BRACKET} ]${NORMAL}"
+ else
+ if [[ -c /dev/null ]]; then
+ rc_splash "stop" &>/dev/null &
+ else
+ rc_splash "stop" &
+ fi
+ if [[ -n "$*" ]]; then
+ ${efunc} "$*"
+ fi
+ msg="${BRACKET}[ ${BAD}!!${BRACKET} ]${NORMAL}"
+ fi
+
+ if [[ ${RC_ENDCOL} == yes ]]; then
+ echo -e "${ENDCOL} ${msg}"
+ else
+ [[ ${LAST_E_CMD} == ebegin ]] || LAST_E_LEN=0
+ printf "%$(( COLS - LAST_E_LEN - 6 ))s%b\n" '' "${msg}"
+ fi
+
+ return ${retval}
+}
+
+# void eend(int error, char* errstr)
+#
+# indicate the completion of process
+# if error, show errstr via eerror
+#
+eend() {
+ local retval=${1:-0}
+ shift
+
+ _eend ${retval} eerror "$*"
+
+ LAST_E_CMD=eend
+ return $retval
+}
+
+# void ewend(int error, char* errstr)
+#
+# indicate the completion of process
+# if error, show errstr via ewarn
+#
+ewend() {
+ local retval=${1:-0}
+ shift
+
+ _eend ${retval} ewarn "$*"
+
+ LAST_E_CMD=ewend
+ return $retval
+}
+
+# v-e-commands honor RC_VERBOSE which defaults to no.
+# The condition is negated so the return value will be zero.
+veinfo() { [[ "${RC_VERBOSE}" != yes ]] || einfo "$@"; }
+veinfon() { [[ "${RC_VERBOSE}" != yes ]] || einfon "$@"; }
+vewarn() { [[ "${RC_VERBOSE}" != yes ]] || ewarn "$@"; }
+veerror() { [[ "${RC_VERBOSE}" != yes ]] || eerror "$@"; }
+vebegin() { [[ "${RC_VERBOSE}" != yes ]] || ebegin "$@"; }
+veend() {
+ [[ "${RC_VERBOSE}" == yes ]] && { eend "$@"; return $?; }
+ return ${1:-0}
+}
+veend() {
+ [[ "${RC_VERBOSE}" == yes ]] && { ewend "$@"; return $?; }
+ return ${1:-0}
+}
+
+# char *KV_major(string)
+#
+# Return the Major (X of X.Y.Z) kernel version
+#
+KV_major() {
+ [[ -z $1 ]] && return 1
+
+ local KV=$@
+ echo ${KV%%.*}
+}
+
+# char *KV_minor(string)
+#
+# Return the Minor (Y of X.Y.Z) kernel version
+#
+KV_minor() {
+ [[ -z $1 ]] && return 1
+
+ local KV=$@
+ KV=${KV#*.}
+ echo ${KV%%.*}
+}
+
+# char *KV_micro(string)
+#
+# Return the Micro (Z of X.Y.Z) kernel version.
+#
+KV_micro() {
+ [[ -z $1 ]] && return 1
+
+ local KV=$@
+ KV=${KV#*.*.}
+ echo ${KV%%[^[:digit:]]*}
+}
+
+# int KV_to_int(string)
+#
+# Convert a string type kernel version (2.4.0) to an int (132096)
+# for easy compairing or versions ...
+#
+KV_to_int() {
+ [[ -z $1 ]] && return 1
+
+ local KV_MAJOR=$(KV_major "$1")
+ local KV_MINOR=$(KV_minor "$1")
+ local KV_MICRO=$(KV_micro "$1")
+ 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 ...
+ if [[ ${KV_int} -ge 131584 ]] ; then
+ echo "${KV_int}"
+ return 0
+ fi
+
+ return 1
+}
+
+# int get_KV()
+#
+# Return the kernel version (major, minor and micro concated) as an integer.
+# Assumes X and Y of X.Y.Z are numbers. Also assumes that some leading
+# portion of Z is a number.
+# e.g. 2.4.25, 2.6.10, 2.6.4-rc3, 2.2.40-poop, 2.0.15+foo
+#
+get_KV() {
+ local KV=$(uname -r)
+
+ echo $(KV_to_int "${KV}")
+
+ return $?
+}
+
+# bool get_bootparam(param)
+#
+# return 0 if gentoo=param was passed to the kernel
+#
+# EXAMPLE: if get_bootparam "nodevfs" ; then ....
+#
+get_bootparam() {
+ local x copt params retval=1
+
+ [ ! -r "/proc/cmdline" ] && return 1
+
+ for copt in $(< /proc/cmdline)
+ do
+ if [ "${copt%=*}" = "gentoo" ]
+ then
+ params="$(gawk -v PARAMS="${copt##*=}" '
+ BEGIN {
+ split(PARAMS, nodes, ",")
+ for (x in nodes)
+ print nodes[x]
+ }')"
+
+ # Parse gentoo option
+ for x in ${params}
+ do
+ if [ "${x}" = "$1" ]
+ then
+# echo "YES"
+ retval=0
+ fi
+ done
+ fi
+ done
+
+ return ${retval}
+}
+
+# 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=
+ local y=
+ local tmpstr=
+ local mylist=
+ local mypath="$*"
+
+ if [ "${mypath%/\*}" != "${mypath}" ]
+ then
+ mypath="${mypath%/\*}"
+ fi
+
+ for x in ${mypath}
+ do
+ [ ! -e "${x}" ] && continue
+
+ if [ ! -d "${x}" ] && ( [ -L "${x}" -o -f "${x}" ] )
+ then
+ mylist="${mylist} $(ls "${x}" 2> /dev/null)"
+ else
+ [ "${x%/}" != "${x}" ] && x="${x%/}"
+
+ cd "${x}"; tmpstr="$(ls)"
+
+ for y in ${tmpstr}
+ do
+ mylist="${mylist} ${x}/${y}"
+ done
+ fi
+ done
+
+ echo "${mylist}"
+}
+
+# void save_options(char *option, char *optstring)
+#
+# save the settings ("optstring") for "option"
+#
+save_options() {
+ local myopts="$1"
+
+ shift
+ if [ ! -d "${svcdir}/options/${myservice}" ]
+ then
+ mkdir -p -m 0755 "${svcdir}/options/${myservice}"
+ fi
+
+ echo "$*" > "${svcdir}/options/${myservice}/${myopts}"
+
+ return 0
+}
+
+# char *get_options(char *option)
+#
+# get the "optstring" for "option" that was saved
+# by calling the save_options function
+#
+get_options() {
+ if [ -f "${svcdir}/options/${myservice}/$1" ]
+ then
+ echo "$(< ${svcdir}/options/${myservice}/$1)"
+ fi
+
+ return 0
+}
+
+# char *add_suffix(char * configfile)
+#
+# Returns a config file name with the softlevel suffix
+# appended to it. For use with multi-config services.
+add_suffix() {
+ if [ "${RC_USE_CONFIG_PROFILE}" = "yes" -a -e "$1.${DEFAULTLEVEL}" ]
+ then
+ echo "$1.${DEFAULTLEVEL}"
+ else
+ echo "$1"
+ fi
+
+ return 0
+}
+
+# char *get_base_ver()
+#
+# get the version of baselayout that this system is running
+#
+get_base_ver() {
+ [[ ! -r /etc/gentoo-release ]] && return 0
+ local ver=$(</etc/gentoo-release)
+ echo ${ver##* }
+}
+
+# Network filesystems list for common use in rc-scripts.
+# This variable is used in is_net_fs and other places such as
+# localmount.
+NET_FS_LIST="afs cifs coda davfs gfs ncpfs nfs nfs4 ocfs2 shfs smbfs"
+
+# bool is_net_fs(path)
+#
+# return 0 if path is the mountpoint of a networked filesystem
+#
+# EXAMPLE: if is_net_fs / ; then ...
+#
+is_net_fs() {
+ local fstype
+ # /proc/mounts is always accurate but may not always be available
+ if [[ -e /proc/mounts ]]; then
+ fstype=$( sed -n -e '/^rootfs/!s:.* '"$1"' \([^ ]*\).*:\1:p' /proc/mounts )
+ else
+ fstype=$( mount | sed -n -e 's:.* on '"$1"' type \([^ ]*\).*:\1:p' )
+ fi
+ [[ " ${NET_FS_LIST} " == *" ${fstype} "* ]]
+ return $?
+}
+
+# bool is_uml_sys()
+#
+# return 0 if the currently running system is User Mode Linux
+#
+# EXAMPLE: if is_uml_sys ; then ...
+#
+is_uml_sys() {
+ grep -qs 'UML' /proc/cpuinfo
+ return $?
+}
+
+# bool is_vserver_sys()
+#
+# return 0 if the currently running system is a Linux VServer
+#
+# EXAMPLE: if is_vserver_sys ; then ...
+#
+is_vserver_sys() {
+ grep -qs '^s_context:[[:space:]]*[1-9]' /proc/self/status
+ return $?
+}
+
+# bool is_xenU_sys()
+#
+# return 0 if the currently running system is an unprivileged Xen domain
+#
+# EXAMPLE: if is_xenU_sys ; then ...
+#
+is_xenU_sys() {
+ [[ -d /proc/xen && ! -f /proc/xen/privcmd ]]
+}
+
+# bool get_mount_fstab(path)
+#
+# return the parameters to pass to the mount command generated from fstab
+#
+# EXAMPLE: cmd=$( get_mount_fstab /proc )
+# cmd=${cmd:--t proc none /proc}
+# mount -n ${cmd}
+#
+get_mount_fstab() {
+ awk '$1 ~ "^#" { next }
+ $2 == "'$*'" { stab="-t "$3" -o "$4" "$1" "$2; }
+ END { print stab; }
+ ' /etc/fstab
+}
+
+# char *reverse_list(list)
+#
+# Returns the reversed order of list
+#
+reverse_list() {
+ for (( i = $# ; i > 0 ; --i )); do
+ echo -n "${!i} "
+ done
+}
+
+# void start_addon(addon)
+#
+# Starts addon.
+#
+start_addon() {
+ local addon=$1
+ (import_addon ${addon}-start.sh)
+ return 0
+}
+
+# void start_volumes()
+#
+# Starts all volumes in RC_VOLUME_ORDER.
+#
+start_volumes() {
+ local x=
+
+ for x in ${RC_VOLUME_ORDER}; do
+ start_addon "${x}"
+ done
+
+ return 0
+}
+
+# void stop_addon(addon)
+#
+# Stops addon.
+#
+stop_addon() {
+ local addon=$1
+ (import_addon ${addon}-stop.sh)
+ return 0
+}
+
+# void stop_volumes()
+#
+# Stops all volumes in RC_VOLUME_ORDER (reverse order).
+#
+stop_volumes() {
+ local x=
+
+ for x in $(reverse_list ${RC_VOLUME_ORDER}); do
+ stop_addon "${x}"
+ done
+
+ return 0
+}
+
+# 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=
+ local ref="$1"
+ shift
+
+ for x in "$@" ; do
+ [[ ${x} -nt ${ref} ]] && return 0
+
+ if [[ -d ${x} ]] ; then
+ is_older_than "${ref}" "${x}"/* && return 0
+ fi
+ done
+
+ return 1
+}
+
+# char* bash_variable(char *variable)
+#
+# Turns the given variable into something that bash can use
+# Basically replaces anything not a-z,A-Z into a _
+#
+bash_variable() {
+ local args="$@"
+ LC_ALL=C echo "${args//[![:word:]]/_}"
+}
+
+# void requote()
+#
+# Requotes params so they're suitable to be eval'd, just like this would:
+# set -- 1 2 "3 4"
+# /usr/bin/getopt -- '' "$@" | sed 's/^ -- //'
+#
+requote() {
+ local q=\'
+ set -- "${@//\'/$q\'$q}" # quote inner instances of '
+ set -- "${@/#/$q}" # add ' to start of each param
+ set -- "${@/%/$q}" # add ' to end of each param
+ echo "$*"
+}
+
+##############################################################################
+# #
+# This should be the last code in here, please add all functions above!! #
+# #
+# *** START LAST CODE *** #
+# #
+##############################################################################
+
+if [ -z "${EBUILD}" ] ; then
+ # 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
+ PATH="/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/sbin:${PATH}"
+
+ # Cache the CONSOLETYPE - this is important as backgrounded shells don't
+ # have a TTY. rc unsets it at the end of running so it shouldn't hang
+ # around
+ if [[ -z ${CONSOLETYPE} ]]; then
+ export CONSOLETYPE=$( /sbin/consoletype 2>/dev/null )
+ fi
+ if [[ ${CONSOLETYPE} == "serial" ]] ; then
+ RC_NOCOLOR="yes"
+ RC_ENDCOL="no"
+ fi
+
+ for arg in "$@" ; do
+ case "${arg}" in
+ # Lastly check if the user disabled it with --nocolor argument
+ --nocolor|-nc)
+ RC_NOCOLOR="yes"
+ ;;
+ esac
+ done
+
+ if [ -r "/proc/cmdline" ] ; then
+ setup_defaultlevels
+ fi
+else
+ # Should we use colors ?
+ if [[ $* != *depend* ]]; then
+ # Check user pref in portage
+ RC_NOCOLOR="$(portageq envvar NOCOLOR 2>/dev/null)"
+ [ "${RC_NOCOLOR}" = "true" ] && RC_NOCOLOR="yes"
+ else
+ # We do not want colors during emerge depend
+ RC_NOCOLOR="yes"
+ # No output is seen during emerge depend, so this is not needed.
+ RC_ENDCOL="no"
+ fi
+fi
+
+if [[ -n ${EBUILD} && $* = *depend* ]]; then
+ # We do not want stty to run during emerge depend
+ COLS=80
+else
+ # Setup COLS and ENDCOL so eend can line up the [ ok ]
+ COLS=${COLUMNS:-0} # bash's internal COLUMNS variable
+ (( COLS == 0 )) && COLS=$(stty size 2>/dev/null | cut -d' ' -f2)
+ (( COLS > 0 )) || (( COLS = 80 )) # width of [ ok ] == 7
+fi
+
+if [[ ${RC_ENDCOL} == yes ]]; then
+ ENDCOL=$'\e[A\e['$(( COLS - 8 ))'C'
+else
+ ENDCOL=''
+fi
+
+# Setup the colors so our messages all look pretty
+if [[ ${RC_NOCOLOR} == yes ]]; then
+ unset GOOD WARN BAD NORMAL HILITE BRACKET
+else
+ GOOD=$'\e[32;01m'
+ WARN=$'\e[33;01m'
+ BAD=$'\e[31;01m'
+ NORMAL=$'\e[0m'
+ HILITE=$'\e[36;01m'
+ BRACKET=$'\e[34;01m'
+fi
+
+##############################################################################
+# #
+# *** END LAST CODE *** #
+# #
+# This should be the last code in here, please add all functions above!! #
+# #
+##############################################################################
+
+
+# vim:ts=4
diff --git a/sbin/modules-update b/sbin/modules-update
new file mode 100755
index 0000000..77c25be
--- /dev/null
+++ b/sbin/modules-update
@@ -0,0 +1,240 @@
+#!/bin/bash
+#
+# This is the modules-update script for Debian GNU/Linux.
+# Written by Wichert Akkerman <wakkerma@debian.org>
+# Copyright (C) 1998, 1999 Software in the Public Interest
+#
+# Modifications by Daniel Robbins <drobbins@gentoo.org>, Gentoo Foundation
+# 02 Sep 2001 -- Removed "arch" stuff since I see no reason to have
+# support for varying CPU architectures on a single system.
+#
+# Updated by Aron Griffis <agriffis@gentoo.org>
+# 05 May 2004 -- handle --assume-kernel argument for livecd building
+
+if [[ 0 -ne $(id -u) ]] ; then
+ echo "You have to be root to do this."
+ exit 2
+fi
+
+CFGFILE="/etc/modules.conf"
+TMPFILE="${CFGFILE}.$$"
+CFGFILE2="/etc/modprobe.conf"
+TMPFILE2="${CFGFILE2}.$$"
+TMPFILE2B="${CFGFILE2}B.$$"
+CFGFILE3="/etc/modules.devfs"
+TMPFILE3="${CFGFILE3}.$$"
+CFGFILE4="/etc/modprobe.devfs"
+TMPFILE4="${CFGFILE4}.$$"
+MODDIR="/etc/modules.d"
+ARCHDIR="${MODDIR}/arch"
+HEADER="### This file is automatically generated by modules-update"
+FULLHEADER="${HEADER}
+#
+# Please do not edit this file directly. If you want to change or add
+# anything please take a look at the files in ${MODDIR} and read
+# the manpage for modules-update(8).
+#
+"
+
+source /sbin/functions.sh
+
+# Parse command-line
+FORCE=false
+ASSUME_KV=
+while [[ -n $1 ]] ; do
+ case "$1" in
+ force)
+ FORCE=true ;;
+ --assume-kernel=*)
+ ASSUME_KV=${1#*=} ;;
+ *)
+ eerror "Error: I don't understand $1"
+ exit 1 ;;
+ esac
+ shift
+done
+
+# Set kernel version, either from --assume-kernel or uname -r
+KV=${ASSUME_KV:-$(uname -r)}
+if [[ $(KV_to_int ${KV}) -ge $(KV_to_int 2.5.48) ]]; then
+ KERNEL_2_6=true
+else
+ KERNEL_2_6=false
+fi
+
+# Check if $CONF is valid
+[[ ! -r ${CONF} ]] && CONF=
+
+set -e
+
+# Reset the sorting order since we depend on it
+export LC_COLLATE="C"
+
+depdir() {
+ local dep=$(sed -n -e '/[ \t]*depfile=/h;${x;s/[ \t]*depfile=//g;s,/[^/]*$,,p}' \
+ "${CFGFILE}")
+ [[ -z ${dep} ]] && dep="/lib/modules/${KV}"
+ echo "${dep}"
+}
+
+CFGFILES=${CFGFILE}
+if ${KERNEL_2_6} ; then
+ CFGFILES="${CFGFILES} ${CFGFILE2}"
+ [[ -d /etc/devfs.d ]] && CFGFILES="${CFGFILES} ${CFGFILE4}"
+fi
+
+for x in ${CFGFILES} ; do
+ if [[ -f ${x} ]] ; then
+ if ! sed -ne 1p "${x}" | egrep -q "^${HEADER}" ; then
+ # Do not bother if its modutils config file, and we
+ # have a 2.6 kernel without modprobe.old
+ [[ ${x} == "${CFGFILE}" ]] && ${KERNEL_2_6} && \
+ ! type -p modprobe.old > /dev/null && \
+ continue
+
+ ewarn "Error: the current ${x} is not automatically generated."
+
+ if $FORCE ; then
+ ewarn "force specified, (re)generating file anyway."
+ else
+ eerror "Use \"modules-update force\" to force (re)generation."
+ exit 1
+ fi
+ fi
+ fi
+done
+
+generate_config() {
+ local cfg=
+ local conf="$1"
+ local moddir="$2"
+ local tmpfile="$3"
+ local do_mprobe="$4"
+
+ for cfg in "${moddir}"/* "${conf}" ; do
+ [[ -d ${cfg} ]] && continue
+
+ [[ ! -r ${cfg} ]] && continue
+
+ # Skip backup and RCS files; fixes bug 20597 (07 May 2004 agriffis)
+ [[ ${cfg} == *~ || ${cfg} == *.bak || ${cfg} == *,v ]] && continue
+
+ [[ ${do_mprobe} -eq 1 && -e "/etc/modprobe.d/${cfg##*/}" ]] && continue
+
+ echo "### modules-update: start processing ${cfg}" >> "${tmpfile}"
+
+ if [[ -x ${cfg} ]] ; then
+ # $cfg can be executable; nice touch, Wichert! :)
+ "${cfg}" >> "${tmpfile}"
+ else
+ cat "${cfg}" >> "${tmpfile}"
+ fi
+
+ echo >> "${tmpfile}"
+ echo "### modules-update: end processing ${cfg}" >> "${tmpfile}"
+ echo >> "${tmpfile}"
+ done
+
+ return 0
+}
+
+if type -p modprobe.old > /dev/null ; then
+ if ${FORCE} || is_older_than ${CFGFILE} ${MODDIR} || \
+ [[ ! -e ${CFGFILE} ]] ; then
+ ebegin "Updating ${CFGFILE}"
+ echo "${FULLHEADER}" > "${TMPFILE}"
+ generate_config "${CONF}" "${MODDIR}" "${TMPFILE}" 0
+ [[ -e ${CFGFILE} ]] && mv -f "${CFGFILE}" "${CFGFILE}.old"
+ mv -f "${TMPFILE}" "${CFGFILE}"
+ eend 0
+ fi
+fi
+
+if ${FORCE} || is_older_than ${CFGFILE2} ${MODDIR} || [[ ! -e ${CFGFILE2} ]]; then
+ if [[ -x /sbin/generate-modprobe.conf ]] && ${KERNEL_2_6} ; then
+ # Make sure that generate-modprobe.conf can handle --assume-kernel
+ # if we were called with it.
+ if [[ -n ${ASSUME_KV} ]] && \
+ ! grep -qe -- --assume-kernel /sbin/generate-modprobe.conf
+ then
+ eerror "Error: modules-update called with --assume-kernel flag, but"
+ eerror "generate-modprobe.conf doesn't understand it. You need to"
+ eerror "install >=module-init-tools-3.0-r2"
+ exit 3
+ fi
+
+ ebegin "Updating ${CFGFILE2}"
+ echo "${FULLHEADER/modules.d/modprobe.d}" > "${TMPFILE2}"
+ if /sbin/generate-modprobe.conf ${ASSUME_KV:+--assume-kernel=${KV}} \
+ >> "${TMPFILE2}" 2>/dev/null
+ then
+ [[ -e ${CFGFILE2} ]] && mv -f "${CFGFILE2}" "${CFGFILE2}.old"
+ mv -f "${TMPFILE2}" "${CFGFILE2}"
+ eend 0
+ else
+ #
+ # If we made it here, it means either generate-modprobe.conf
+ # bombed on us, or the user doesn't have modutils installed.
+ # If the latter is true, then we should generate modprobe.conf
+ # ourselves with any old files laying around in /etc/modules.d.
+ #
+ rm -f "${TMPFILE2}"
+ if type -p modprobe.old > /dev/null ; then
+ eend 1 "Warning: could not generate ${CFGFILE2}!"
+ else
+ echo "${FULLHEADER/modules.d/modprobe.d}" > "${TMPFILE2B}"
+ generate_config "${CONF}" "${MODDIR}" "${TMPFILE2}" 1
+ export TESTING_MODPROBE_CONF="${TMPFILE2}"
+ if /sbin/generate-modprobe.conf ${ASSUME_KV:+--assume-kernel=${KV}} \
+ >> "${TMPFILE2B}" 2> /dev/null
+ then
+ [[ -e ${CFGFILE2} ]] && mv -f "${CFGFILE2}" "${CFGFILE2}.old"
+ mv -f "${TMPFILE2B}" "${CFGFILE2}"
+ eend 0
+ else
+ eend 1 "Warning: could not generate ${CFGFILE2}!"
+ rm -f "${TMPFILE2B}"
+ fi
+ rm -f "${TMPFILE2}"
+ fi
+ fi
+
+ if [[ -f ${CFGFILE3} ]] ; then
+ ebegin "Updating ${CFGFILE4}"
+ gawk '$0 !~ /^[[:space:]]*include/ { print $0 }' "${CFGFILE3}" \
+ > "${TMPFILE3}"
+
+ echo "${FULLHEADER/modules.d/modprobe.d}" > "${TMPFILE4}"
+ export TESTING_MODPROBE_CONF="${TMPFILE3}"
+ if /sbin/generate-modprobe.conf ${ASSUME_KV:+--assume-kernel=${KV}} \
+ >> "${TMPFILE4}" 2> /dev/null
+ then
+ [[ -e ${CFGFILE4} ]] && mv -f "${CFGFILE4}" "${CFGFILE4}.old"
+ mv -f "${TMPFILE4}" "${CFGFILE4}"
+
+ echo >> "${CFGFILE4}"
+ echo "include /etc/modprobe.conf" >> "${CFGFILE4}"
+ eend 0
+ else
+ eend 1 "Warning: could not generate ${CFGFILE4}!"
+ rm -f "${TMPFILE4}"
+ fi
+ rm -f "${TMPFILE3}"
+ fi
+ fi
+fi
+
+# We also call depmod here to stop insmod from complaining that modules.conf
+# is more recent then modules.dep
+if [[ ${CFGFILE2} -nt /lib/modules/${KV}/modules.dep ]] ; then
+ if [[ -d $(depdir) && -f /proc/modules ]] ; then
+ if [[ -f /usr/src/linux/System.map ]] ; then
+ depmod -a -F /usr/src/linux/System.map ${KV}
+ else
+ ewarn "System.map not found - unable to check symbols"
+ fi
+ fi
+fi
+
+
+# vim:ts=4
diff --git a/sbin/rc b/sbin/rc
new file mode 100755
index 0000000..bda2707
--- /dev/null
+++ b/sbin/rc
@@ -0,0 +1,975 @@
+#!/sbin/runscript
+# Copyright 1999-2005 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+trap ":" INT QUIT TSTP
+source /sbin/functions.sh
+# Only source this when this is a livecd booting ...
+[ -f /sbin/livecd-functions.sh ] && source /sbin/livecd-functions.sh
+umask 022
+
+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" &
+
+ echo -e "${ENDCOL}${NORMAL}[${BAD} oops ${NORMAL}]"
+ echo
+ eerror "The \"${1}\" command failed with error:"
+ echo
+ echo "${errstr#*: }"
+ echo
+ eerror "Since this is a critical task, startup cannot continue."
+ echo
+ /sbin/sulogin ${CONSOLE}
+ einfo "Unmounting filesystems"
+ if [ -c /dev/null ]; then
+ /bin/mount -a -o remount,ro &>/dev/null
+ else
+ /bin/mount -a -o remount,ro
+ fi
+ einfo "Rebooting"
+ /sbin/reboot -f
+ fi
+
+ return ${retval}
+}
+
+# Check that $1 exists ...
+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"
+ else
+ eerror "Please mount your root partition read/write, and execute:"
+ echo
+ eerror " # mkdir -p $1"
+ echo; echo
+ /sbin/sulogin ${CONSOLE}
+ fi
+ einfo "Unmounting filesystems"
+ /bin/mount -a -o remount,ro &>/dev/null
+ einfo "Rebooting"
+ /sbin/reboot -f
+ fi
+ fi
+
+ return 0
+}
+
+udev_version() {
+ local version=0
+
+ if [ -x "/sbin/udev" ]
+ then
+ version=$(/sbin/udev -V)
+ # We need it without a leading '0', else bash do the wrong thing
+ version="${version##0}"
+ # Older udev's will print nothing
+ [ -z "${version}" ] && version=0
+ fi
+
+ echo "${version}"
+}
+
+# void noblock_read(var)
+#
+# reads a line of input into var like regular read
+# but it does not block waiting for input
+#
+noblock_read() {
+ local old_tty_settings="$(stty -g)"
+ stty -icanon min 0 time 0
+ read "$@"
+ stty "${old_tty_settings}"
+}
+
+# bool user_want_interactive(void)
+#
+# return 0 if user wants interactive mode
+#
+user_want_interactive() {
+ local user_input
+ noblock_read user_input
+ [[ ${user_input} == *"I"* || ${user_input} == *"i"* ]]
+}
+
+# void do_interactive
+#
+# starts, skips, continues or drops to the shell
+# depending on user selection
+#
+do_interactive() {
+ local service="$1"
+ shift
+
+ local start_text="Start service"
+ local skip_text="Skip service"
+ local continue_text="Continue boot process"
+ local shell_text="Exit to shell"
+
+ echo
+ echo "About to start the service ${service}"
+ PS3="Enter your selection: "
+ select action in "${start_text}" "${skip_text}" "${continue_text}" \
+ "${shell_text}"
+ do
+ case ${action} in
+ "${start_text}")
+ "$@"
+ break
+ ;;
+ "${skip_text}")
+ break
+ ;;
+ "${continue_text}")
+ interactive="no"
+ "$@"
+ break
+ ;;
+ "${shell_text}")
+ echo
+ sulogin "${CONSOLE}"
+ ;;
+ esac
+ done
+}
+
+populate_udev() {
+ # Now populate /dev
+ /sbin/udevstart
+
+ # Not provided by sysfs but needed
+ ln -snf /proc/self/fd /dev/fd
+ ln -snf fd/0 /dev/stdin
+ ln -snf fd/1 /dev/stdout
+ ln -snf fd/2 /dev/stderr
+ [ -e /proc/kcore ] && ln -snf /proc/kcore /dev/core
+
+ # Create nodes that udev can't
+ [ -x /sbin/dmsetup ] && /sbin/dmsetup mknodes &>/dev/null
+ [ -x /sbin/lvm ] && /sbin/lvm vgscan -P --mknodes --ignorelockingfailure &>/dev/null
+ [ -x /sbin/evms_activate ] && /sbin/evms_activate -q &>/dev/null
+
+ # Create problematic directories
+ mkdir -p /dev/{pts,shm}
+
+ # Same thing as /dev/.devfsd
+ touch /dev/.udev
+
+ return 0
+}
+
+get_critical_services() {
+ local x=
+ CRITICAL_SERVICES=
+
+ if [ -f "/etc/runlevels/${BOOTLEVEL}/.critical" ]
+ then
+ for x in $(< /etc/runlevels/${BOOTLEVEL}/.critical)
+ do
+ CRITICAL_SERVICES="${CRITICAL_SERVICES} ${x##*/}"
+ done
+ else
+ CRITICAL_SERVICES="checkroot hostname modules checkfs localmount clock"
+ fi
+
+ export CRITICAL_SERVICES
+
+ return 0
+}
+
+# Save $1
+argv1="$1"
+
+# First time boot stuff goes here. Note that 'sysinit' is an internal runlevel
+# used to bring up local filesystems, and should not be started with /sbin/rc
+# directly ...
+if [[ ( ${RUNLEVEL} == "S" || ${RUNLEVEL} == "1" ) && ${argv1} = "sysinit" ]]
+then
+ # Setup initial $PATH just in case
+ PATH="/bin:/sbin:/usr/bin:/usr/sbin:${PATH}"
+
+ # Help users recover their systems incase these go missing
+ [ -c /dev/null ] && dev_null=1 || dev_null=0
+ [ -c /dev/console ] && dev_console=1 || dev_console=0
+
+ echo
+ echo -e "${GOOD}Gentoo Linux${GENTOO_VERS}; ${BRACKET}http://www.gentoo.org/${NORMAL}"
+ echo -e " Copyright 1999-2005 Gentoo Foundation; Distributed under the GPLv2"
+ echo
+ echo -e "Press ${GOOD}I${NORMAL} to enter interactive boot mode"
+ echo
+ check_statedir /proc
+
+ ebegin "Mounting proc at /proc"
+ if [[ ${RC_USE_FSTAB} = "yes" ]] ; then
+ mntcmd=$(get_mount_fstab /proc)
+ else
+ unset mntcmd
+ fi
+ try mount -n ${mntcmd:--t proc proc /proc}
+ eend $?
+
+ # 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
+ [ -f /sbin/livecd-functions.sh ] && livecd_read_commandline
+
+ if [ "$(get_KV)" -ge "$(KV_to_int '2.6.0')" ] ; then
+ if [[ -d /sys ]] ; then
+ ebegin "Mounting sysfs at /sys"
+ if [[ ${RC_USE_FSTAB} = "yes" ]] ; then
+ mntcmd=$(get_mount_fstab /sys)
+ else
+ unset mntcmd
+ fi
+ try mount -n ${mntcmd:--t sysfs sysfs /sys}
+ eend $?
+ else
+ ewarn "No /sys to mount sysfs needed in 2.6 and later kernels!"
+ fi
+ fi
+
+ check_statedir /dev
+
+ # Fix weird bug where there is a /dev/.devfsd in a unmounted /dev
+ devfs_automounted="no"
+ if [ -e "/dev/.devfsd" ]
+ then
+ mymounts="$(awk '($3 == "devfs") { print "yes"; exit 0 }' /proc/mounts)"
+ if [ "${mymounts}" != "yes" ]
+ then
+ rm -f /dev/.devfsd
+ else
+ devfs_automounted="yes"
+ fi
+ 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" ]
+ then
+ ebegin "Using existing device nodes 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" || \
+ [ ! -x /sbin/udev -o -e "/dev/.devfsd" ] || \
+ [ "$(get_KV)" -lt "$(KV_to_int '2.6.0')" ]
+ then
+ udev="no"
+ fi
+ fi
+
+ # Check devfs prerequisites and kernel params
+ if [ "${devfs}" = "yes" ]
+ then
+ if get_bootparam "nodevfs" || [ "${udev}" = "yes" ]
+ then
+ devfs="no"
+ fi
+ fi
+
+ # Actually start setting up /dev now
+ if [[ ${udev} = "yes" ]] ; then
+ # Setup temporary storage for /dev
+ ebegin "Mounting /dev for udev"
+ if [[ ${RC_USE_FSTAB} = "yes" ]] ; then
+ mntcmd=$(get_mount_fstab /dev)
+ else
+ unset mntcmd
+ fi
+ if [[ -n ${mntcmd} ]] ; then
+ try mount -n ${mntcmd}
+ else
+ if egrep -qs tmpfs /proc/filesystems ; then
+ mntcmd="tmpfs"
+ else
+ mntcmd="ramfs"
+ fi
+ # many video drivers require exec access in /dev #92921
+ try mount -n -t ${mntcmd} udev /dev -o exec,nosuid,mode=0755
+ fi
+ eend $?
+
+ # Selinux lovin; /selinux should be mounted by selinux-patched init
+ if [[ -x /sbin/restorecon ]] && [[ -c /selinux/null ]] ; then
+ restorecon /dev &> /selinux/null
+ fi
+
+ # Actually get udev rolling
+ ebegin "Configuring system to use udev"
+ if [[ ${RC_DEVICE_TARBALL} = "yes" ]] && [[ -s /lib/udev-state/devices.tar.bz2 ]]
+ then
+ einfo " Populating /dev with device nodes ..."
+ try tar -jxpf /lib/udev-state/devices.tar.bz2 -C /dev
+ fi
+ populate_udev
+
+ # Setup hotplugging (if possible)
+ if [ -e /proc/sys/kernel/hotplug ] ; then
+ if [ "$(udev_version)" -ge "48" ] ; then
+ einfo " Setting /sbin/udevsend as hotplug agent ..."
+ echo "/sbin/udevsend" > /proc/sys/kernel/hotplug
+ elif [ -x /sbin/hotplug ] ; then
+ einfo " Using /sbin/hotplug as hotplug agent ..."
+ else
+ einfo " Setting /sbin/udev as hotplug agent ..."
+ echo "/sbin/udev" > /proc/sys/kernel/hotplug
+ fi
+ fi
+ eend 0
+
+ # With devfs, /dev can be mounted by the kernel ...
+ elif [ "${devfs}" = "yes" ]
+ then
+ mymounts="$(awk '($2 == "devfs") { print "yes"; exit 0 }' /proc/filesystems)"
+ # Is devfs support compiled in?
+ if [ "${mymounts}" = "yes" ]
+ then
+ if [ "${devfs_automounted}" = "no" ]
+ then
+ ebegin "Mounting devfs at /dev"
+ try mount -n -t devfs devfs /dev
+ eend $?
+ else
+ ebegin "Kernel automatically mounted devfs at /dev"
+ eend 0
+ fi
+ ebegin "Starting devfsd"
+ /sbin/devfsd /dev >/dev/null
+ eend $? "Could not start /sbin/devfsd"
+ else
+ devfs="no"
+ fi
+
+ # 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" ] && [ "${udev}" = "no" ]
+ then
+ clear
+ echo
+ einfo "The Gentoo Linux system initialization scripts have detected that"
+ einfo "your system does not support DEVFS or UDEV. Since Gentoo Linux"
+ einfo "has been designed with these dynamic /dev managers in mind, it is"
+ einfo "highly suggested that you build support for it into your kernel."
+ einfo "Please read the Gentoo Handbook for more information!"
+ echo
+ einfo " http://www.gentoo.org/doc/en/handbook/"
+ echo
+ einfo "Thanks for using Gentoo! :)"
+ echo
+ read -t 15 -p "(hit Enter to continue or wait 15 seconds ...)"
+ fi
+ fi
+
+ # From linux-2.5.68 we need to mount /dev/pts again ...
+ if [ "$(get_KV)" -ge "$(KV_to_int '2.5.68')" ]
+ then
+ have_devpts="$(awk '($2 == "devpts") { print "yes"; exit 0 }' /proc/filesystems)"
+
+ if [ "${have_devpts}" = "yes" ]
+ then
+ # Only try to create /dev/pts if we have /dev mounted dynamically,
+ # else it might fail as / might be still mounted readonly.
+ if [ ! -d /dev/pts ] && \
+ [ "${devfs}" = "yes" -o "${udev}" = "yes" ]
+ then
+ # Make sure we have /dev/pts
+ mkdir -p /dev/pts &>/dev/null || \
+ ewarn "Could not create /dev/pts!"
+ fi
+
+ if [[ -d /dev/pts ]] ; then
+ ebegin "Mounting devpts at /dev/pts"
+ if [[ ${RC_USE_FSTAB} = "yes" ]] ; then
+ mntcmd=$(get_mount_fstab /dev/pts)
+ else
+ unset mntcmd
+ fi
+ try mount -n ${mntcmd:--t devpts -o gid=5,mode=0620 devpts /dev/pts}
+ eend $?
+ fi
+ fi
+ fi
+
+ # Start logging console output since we have all /dev stuff setup
+ bootlog start
+
+ # Swap needs to be activated *after* /dev has been fully setup so that
+ # the fstab can be properly parsed. This first pass we send to /dev/null
+ # in case the user has swap points setup on different partitions. We
+ # will run swapon again in localmount and that one will report errors.
+ ebegin "Activating (possible) swap"
+ /sbin/swapon -a >& /dev/null
+ eend 0
+
+ # 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
+ /bin/dmesg -n 1
+
+ # We set the forced softlevel from the kernel command line
+ # It needs to be run right after proc is mounted for the
+ # boot runlevel
+ setup_defaultlevels
+
+ # $BOOT can be used by rc-scripts to test if it is the first time
+ # the 'boot' runlevel is executed. Now also needed by some stuff in
+ # the 'sysinit' runlevel ...
+ export BOOT="yes"
+
+ start_critical_service() {
+ (
+ local retval=
+ local service=$1
+ # Needed for some addons like dm-crypt that starts in critical services
+ local myservice=$1
+
+ source "/etc/init.d/${service}" || eerror "Failed to source /etc/init.d/${service}"
+ retval=$?
+ [ "${retval}" -ne 0 ] && return "${retval}"
+ [ -e "/etc/conf.d/${service}" ] && source "/etc/conf.d/${service}"
+ source /etc/rc.conf
+
+ start || eerror "Failed to start /etc/init.d/${service}"
+ retval=$?
+
+ return "${retval}"
+ )
+ }
+
+ # We first try to find a locally defined list of critical services
+ # for a particular runlevel. If we cannot find it, we use the
+ # defaults.
+ get_critical_services
+
+ splash "rc_init" "${argv1}"
+
+ export START_CRITICAL="yes"
+
+ # We do not want to break compatibility, so we do not fully integrate
+ # these into /sbin/rc, but rather start them by hand ...
+ for x in ${CRITICAL_SERVICES}
+ do
+ splash "svc_start" "${x}"
+ user_want_interactive && interactive="yes"
+ if ! start_critical_service "${x}" ; then
+ splash "critical" &>/dev/null &
+
+ echo
+ eerror "One of more critical startup scripts failed to start!"
+ eerror "Please correct this, and reboot ..."
+ echo; echo
+ /sbin/sulogin ${CONSOLE}
+ einfo "Unmounting filesystems"
+ /bin/mount -a -o remount,ro &>/dev/null
+ einfo "Rebooting"
+ /sbin/reboot -f
+ fi
+
+ splash "svc_started" "${x}" "0"
+ done
+
+ unset START_CRITICAL
+
+ # /var/log should be writable now, so starting saving the boot output
+ bootlog sync
+
+ # have to run this after /var/run is mounted rw #85304
+ if [ -x /sbin/irqbalance -a "$(get_KV)" -ge "$(KV_to_int '2.5.0')" ]
+ then
+ ebegin "Starting irqbalance"
+ /sbin/irqbalance
+ eend $?
+ fi
+
+ # Check that $svcdir exists ...
+ check_statedir "${svcdir}"
+
+ # Should we use tmpfs/ramfs/ramdisk for caching dependency and
+ # general initscript data? Note that the 'gentoo=<fs>' kernel
+ # option should override any other setting ...
+ for fs in tmpfs ramfs ramdisk
+ do
+ if get_bootparam "${fs}"
+ then
+ svcmount="yes"
+ svcfstype="${fs}"
+ break
+ fi
+ done
+ if [ "${svcmount}" = "yes" ]
+ then
+ ebegin "Mounting ${svcfstype} at ${svcdir}"
+ case "${svcfstype}" in
+ ramfs)
+ try mount -n -t ramfs svcdir "${svcdir}" \
+ -o rw,mode=0755,size="${svcsize}"k
+ ;;
+ ramdisk)
+ try dd if=/dev/zero of=/dev/ram0 bs=1k count="${svcsize}"
+ try /sbin/mke2fs -i 1024 -vm0 /dev/ram0 "${svcsize}"
+ try mount -n -t ext2 /dev/ram0 "${svcdir}" -o rw
+ ;;
+ tmpfs|*)
+ try mount -n -t tmpfs svcdir "${svcdir}" \
+ -o rw,mode=0755,size="${svcsize}"k
+ ;;
+ esac
+ eend 0
+ 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
+
+ # Clear $svcdir from stale entries, but leave the caches around, as it
+ # should help speed things up a bit
+ rm -rf $(ls -d1 "${svcdir}/"* 2>/dev/null | \
+ grep -ve '\(depcache\|deptree\|envcache\)')
+
+ echo "sysinit" > "${svcdir}/softlevel"
+ echo "${interactive}" > "${svcdir}/interactive"
+
+ # Update the dependency cache
+ /sbin/depscan.sh -u
+
+ # Now that the dependency cache are up to date, make sure these
+ # are marked as started ...
+ (
+ # Needed for mark_service_started()
+ source "${svclib}/sh/rc-services.sh"
+
+ for x in ${CRITICAL_SERVICES}
+ do
+ mark_service_started "${x}"
+ done
+ )
+
+ # If the user's /dev/null or /dev/console are missing, we
+ # should help them out and explain how to rectify the situation
+ if [ ${dev_null} -eq 0 -o ${dev_console} -eq 0 ] \
+ && [ -e /usr/share/baselayout/issue.devfix ]
+ then
+ # Backup current /etc/issue
+ if [ -e /etc/issue -a ! -e /etc/issue.devfix ]
+ then
+ mv /etc/issue /etc/issue.devfix
+ fi
+
+ cp /usr/share/baselayout/issue.devfix /etc/issue
+ fi
+
+ # Setup login records ... this has to be done here because when
+ # we exit this runlevel, init will write a boot record to utmp
+ # If /var/run is readonly, then print a warning, not errors
+ if touch /var/run/utmp 2>/dev/null
+ then
+ > /var/run/utmp
+ touch /var/log/wtmp
+ chgrp utmp /var/run/utmp /var/log/wtmp
+ chmod 0664 /var/run/utmp /var/log/wtmp
+ # Remove /var/run/utmpx (bug from the past)
+ rm -f /var/run/utmpx
+ else
+ ewarn "Skipping /var/run/utmp initialization (ro root?)"
+ fi
+
+ # All done logging
+ bootlog quit
+
+ exit 0
+fi # Sysinit ends here
+
+if [[ ( ${RUNLEVEL} == "S" || ${RUNLEVEL} == "1" ) && ${argv1} == "boot" ]]
+then
+ setup_defaultlevels
+
+ if [ -n "${DEFAULTLEVEL}" -a "${DEFAULTLEVEL}" != "default" ]
+ then
+ # Setup our default runlevel runlevel that will be run
+ # the first time /sbin/rc is called with argv1 != sysinit|boot
+ echo "${DEFAULTLEVEL}" > "${svcdir}/ksoftlevel"
+ fi
+
+ # $BOOT can be used by rc-scripts to test if it is the first time
+ # the 'boot' runlevel is executed
+ export BOOT="yes"
+
+ # We reset argv1 to the bootlevel given on the kernel command line
+ # if there is one
+ argv1="${BOOTLEVEL}"
+
+elif [[ ${RUNLEVEL} != "S" && ${RUNLEVEL} != "1" && -e ${svcdir}/ksoftlevel ]]
+then
+ argv1="$(< ${svcdir}/ksoftlevel)"
+ rm -f "${svcdir}/ksoftlevel"
+elif [[ ${RUNLEVEL} != "S" && ${RUNLEVEL} != "1" && ${argv1} == "single" ]]
+then
+ /sbin/telinit S
+ exit 0
+elif [[ ( ${RUNLEVEL} == "S" || ${RUNLEVEL} == "1" ) && ${argv1} != "single" ]]
+then
+ level=$(awk -v level="${argv1}" '
+ $2 == level {
+ split($0, fields, ":")
+ print fields[2]
+ exit
+ }' /etc/inittab 2>/dev/null)
+ [[ -z ${level} ]] && level=3
+ /sbin/telinit "${level}"
+ exit 0
+fi
+
+source "${svclib}/sh/rc-services.sh"
+
+if [ -f "${svcdir}/softlevel" ]
+then
+ # Set OLDSOFTLEVEL if we had a valid SOFTLEVEL
+ export OLDSOFTLEVEL="$(< ${svcdir}/softlevel)"
+else
+ export OLDSOFTLEVEL=
+fi
+
+if [ -z "${argv1}" ]
+then
+ if [ -f "${svcdir}/softlevel" ]
+ then
+ export SOFTLEVEL="$(< ${svcdir}/softlevel)"
+ else
+ export SOFTLEVEL="${BOOTLEVEL}"
+ fi
+else
+ export SOFTLEVEL="${argv1}"
+fi
+
+if [ ! -f "${svcdir}/softlevel" ]
+then
+ echo "${SOFTLEVEL}" > "${svcdir}/softlevel"
+fi
+
+# For keeping a list of services that fails during boot/halt
+if [ ! -d "${svcdir}/failed" ]
+then
+ mkdir -p -m 0755 "${svcdir}/failed"
+else
+ rm -rf "${svcdir}"/failed/*
+fi
+
+splash "rc_init" "${argv1}"
+
+if [ "${SOFTLEVEL}" = "reboot" -o "${SOFTLEVEL}" = "shutdown" ]
+then
+ myscripts=
+
+elif [ "${SOFTLEVEL}" = "single" ]
+then
+ get_critical_services
+
+ myscripts="${CRITICAL_SERVICES}"
+
+elif [ ! -d "/etc/runlevels/${SOFTLEVEL}" ]
+then
+ eerror "ERROR: runlevel ${SOFTLEVEL} does not exist; exiting ..."
+ exit 1
+else
+ myscripts=
+ if [ "${SOFTLEVEL}" != "${BOOTLEVEL}" ]
+ then
+ # Normal runlevels *include* boot scripts
+ mylevels="$(dolisting "/etc/runlevels/${SOFTLEVEL}/")"
+ mylevels="${mylevels} $(dolisting /etc/runlevels/${BOOTLEVEL}/)"
+ else
+ # Non-normal runlevels don't include boot scripts as default
+ mylevels="$(dolisting "/etc/runlevels/${SOFTLEVEL}/")"
+ fi
+
+ [ "${OLDSOFTLEVEL}" = "${BOOTLEVEL}" -o "${OLDSOFTLEVEL}" = "single" ] \
+ && /bin/dmesg -n 1
+
+ for x in ${mylevels}
+ do
+ [ -L "${x}" ] && myscripts="${myscripts} ${x##*/}"
+ done
+fi
+
+# The softscripts dir contains all scripts that belong to the
+# runlevel specified in ${svcdir}/softlevel
+# It needs to be a new directory, else when stopping the services
+# and the old directory is not intact, things get broken
+
+mkdir -p -m 0755 "${svcdir}/softscripts.new"
+
+for x in ${myscripts} ; do
+ if [[ ! -e /etc/init.d/${x} ]] ; then
+ ewarn "WARNING: /etc/init.d/${x} missing; skipping ..."
+ continue
+ fi
+ # The -f eliminates a warning if the symlink already exists,
+ # which can happen if a service is in both the boot level and
+ # the current "normal" runlevel
+ ln -snf "/etc/init.d/${x}" "${svcdir}/softscripts.new/${x}"
+done
+
+get_stop_services() {
+ local x list
+
+ for x in $(dolisting "${svcdir}/inactive/") \
+ $(dolisting "${svcdir}/started/") ; do
+ list="${list} ${x##*/}"
+ done
+
+ reverse_list $(trace_dependencies ${list})
+}
+
+dep_stop() {
+ local x dep needsme depservice
+ local myservice=${1##*/}
+
+ service_stopped "${myservice}" && return 0
+
+ # Candidate for zapping ?
+ [[ ! -L ${svcdir}/softscripts.new/${myservice} ]] || \
+ return 0
+
+ # If this is a 'net' service, we do not want to stop it if it was
+ # not in the previous runlevel, and we are not shutting down,
+ # rebooting or going to single runlevel. This is because the user
+ # (or hotplut) might have started it (net.ppp?) ...
+ if net_service "${myservice}" && \
+ [[ ${SOFTLEVEL} != "reboot" && \
+ ${SOFTLEVEL} != "shutdown" && \
+ ${SOFTLEVEL} != "single" ]] ; then
+ if [[ -z ${OLDSOFTLEVEL} ]] || \
+ ! in_runlevel "${myservice}" "${OLDSOFTLEVEL}"
+ then
+ # This service is not in the previous runlevel, so
+ # do not stop it ...
+ return 0
+ fi
+ fi
+
+ # Should not work for 'use'
+ if [[ -z $(needsme "${myservice}") ]] ; then
+ # Nothing depends on me
+ stop_service "${myservice}"
+ else
+ # Something may depend on me
+ needsme=0
+
+ for dep in $(needsme "${myservice}") ; do
+ #if service_started "${dep}" && \
+ if [[ -L "${svcdir}/softscripts.new/${dep}" ]] ; then
+ # This dep is valid
+ needsme=1
+
+ break
+ fi
+ done
+
+ [[ ${needsme} -eq 0 ]] && stop_service "${myservice}"
+ fi
+}
+
+# Stop services
+if [[ ${SOFTLEVEL} != "single" && \
+ ${SOFTLEVEL} != "reboot" && \
+ ${SOFTLEVEL} != "shutdown" ]]
+then
+ for i in $(get_stop_services) ; do
+ dep_stop "${i}"
+ done
+
+ # Wait for any services that may still be stopping ...
+ [ "${RC_PARALLEL_STARTUP}" = "yes" ] && wait
+else
+ get_critical_services
+
+ is_critical_service() {
+ local x
+ local myservice=${1##*/}
+
+ for x in ${CRITICAL_SERVICES} ${LOGGER_SERVICE} ; do
+ [[ ${myservice} == "${x}" ]] && return 0
+ done
+
+ return 1
+ }
+
+ # First stop non critical services
+ for i in $(get_stop_services) ; do
+ is_critical_service "${i}" || dep_stop "${i}"
+ done
+
+ # Wait for any services that may still be stopping ...
+ [ "${RC_PARALLEL_STARTUP}" = "yes" ] && wait
+
+ export STOP_CRITICAL="yes"
+ # Now stop the rest
+ for i in $(get_stop_services) ; do
+ dep_stop "${i}"
+ done
+ unset STOP_CRITICAL
+fi
+
+# Only change softlevel AFTER all the services have been stopped,
+# else they will not get the depend's right (wrong SOFTLEVEL)
+
+echo "${SOFTLEVEL}" > "${svcdir}/softlevel"
+
+if [[ ${SOFTLEVEL} == "reboot" || ${SOFTLEVEL} == "shutdown" ]] ; then
+ source /sbin/functions.sh
+
+ # Clear $svcdir from stale entries, but leave the caches around, as it
+ # should help speed things up a bit
+ rm -rf $(ls -d1 "${svcdir}/"* 2>/dev/null | \
+ grep -ve '\(depcache\|deptree\|envcache\)')
+
+ source /etc/init.d/halt.sh
+
+ if [[ ${SOFTLEVEL} == "reboot" ]] ; then
+ source /etc/init.d/reboot.sh
+ else
+ source /etc/init.d/shutdown.sh
+ fi
+
+ # Should never get here
+ exit 0
+fi
+
+if [[ ${SOFTLEVEL} == "single" ]] ; then
+ /sbin/sulogin ${CONSOLE}
+ exit 0
+fi
+
+# Move the old softscritps directory to a different one
+# and make the new softscripts directory the current
+
+mv -f "${svcdir}/softscripts" "${svcdir}/softscripts.old"
+mv -f "${svcdir}/softscripts.new" "${svcdir}/softscripts"
+
+get_start_services() {
+ local x list
+
+ get_critical_services
+ list=${CRITICAL_SERVICES}
+
+ [[ -n ${LOGGER_SERVICE} && \
+ -L ${svcdir}/softscripts/${LOGGER_SERVICE} ]] && \
+ list="${list} ${LOGGER_SERVICE}"
+
+ for x in $(dolisting "${svcdir}/softscripts/") ; do
+ list="${list} ${x##*/}"
+ done
+
+ trace_dependencies ${list}
+}
+
+[[ -e "${svcdir}/interactive" ]] \
+ && interactive="$(<"${svcdir}/interactive")"
+
+# Start scripts
+for i in $(get_start_services) ; do
+ if service_stopped "${i}" ; then
+ user_want_interactive && interactive="yes"
+ if [[ ${interactive} == "yes" ]]; then
+ do_interactive "${i}" start_service "${i}"
+ else
+ start_service "${i}"
+ fi
+ fi
+done
+
+# Wait for any services that may still be running ...
+[ "${RC_PARALLEL_STARTUP}" = "yes" ] && wait
+
+# Clean the old runlevel
+rm -rf "${svcdir}/softscripts.old" &>/dev/null
+
+# Depends gets nuked, so update them
+# (this problem should be solved now, but i think it will be a good idea
+# to recreate the deps after a change in runlevel)
+
+#/sbin/depscan.sh &>/dev/null
+
+# We want devfsd running after a change of runlevel (this is mostly if we return
+# from runlevel 'single')
+if [ -z "`ps --no-heading -C 'devfsd'`" -a \
+ -n "`gawk '/\/dev devfs/ { print }' /proc/mounts 2>/dev/null`" ]
+then
+ if [ "${RC_DEVFSD_STARTUP}" != "no" ]
+ then
+ /sbin/devfsd /dev &>/dev/null
+ fi
+fi
+
+# Runlevel end, so clear stale fail list
+rm -rf "${svcdir}/failed" &>/dev/null
+
+# If we were in the boot runlevel, it is done now ...
+if [[ -n ${BOOT} ]]; then
+ unset BOOT
+ # Save our interactive mode into the default runlevel
+ echo "${interactive}" > "${svcdir}/interactive"
+else
+ # As we're not boot, we remove the interactive file
+ [[ -e "${svcdir}/interactive" ]] && rm -f "${svcdir}/interactive"
+fi
+
+# Remove the cached CONSOLETYPE
+unset CONSOLETYPE
+
+splash "rc_exit"
+
+# vim:ts=4
diff --git a/sbin/rc-daemon.sh b/sbin/rc-daemon.sh
new file mode 100755
index 0000000..fab3577
--- /dev/null
+++ b/sbin/rc-daemon.sh
@@ -0,0 +1,382 @@
+# Copyright 1999-2005 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+# RC functions to work with daemons
+# Basically we're a fancy wrapper for start-stop-daemon
+# and should be called as such. This means that our init scripts
+# should work as is with zero modification :)
+
+# Actually, the above is a small as lie we have some init scripts which try to
+# get start-stop-daemon to launch a shell script. While this does work with
+# the start-stop-daemon program in /sbin, it does cause a problem for us
+# when we're testing for the daemon to be running. I (Roy Marples) view this
+# as behaviour by design as start-stop-daemon should not be used to run shell
+# scripts!
+# At the time of writing, the only culprit I know of is courier-imap.
+# There may be others!
+
+RC_GOT_DAEMON="yes"
+
+[[ ${RC_GOT_FUNCTIONS} != "yes" ]] && source /sbin/functions.sh
+[[ ${RC_GOT_SERVICES} != "yes" ]] && source "${svclib}/sh/rc-services.sh"
+
+RC_RETRY_KILL="no"
+RC_RETRY_TIMEOUT=1
+RC_RETRY_COUNT=5
+RC_FAIL_ON_ZOMBIE="no"
+RC_KILL_CHILDREN="no"
+RC_WAIT_ON_START="0.1"
+
+# Override default settings with user settings ...
+[[ -f /etc/conf.d/rc ]] && source /etc/conf.d/rc
+
+# void rc_shift_args(void)
+#
+# Proccess vars - makes things easier by using the shift command
+# and indirect variables
+rc_shift_args() {
+ while [[ $# != "0" ]]; do
+ if [[ $1 != "-"* && -n ${addvar} ]]; then
+ if [[ -z ${!addvar} ]]; then
+ eval "${addvar}=\"$1\""
+ else
+ eval "${addvar}=\"${!addvar} $1\""
+ fi
+ shift
+ continue
+ fi
+ unset addvar
+ case "$1" in
+ -S|--start)
+ stopping=false
+ ;;
+ -K|--stop)
+ stopping=true
+ ;;
+ -n|--name)
+ addvar="name"
+ ;;
+ -x|--exec|-a|--startas)
+ addvar="cmd"
+ ;;
+ -p|--pidfile)
+ addvar="pidfile"
+ ;;
+ --pidfile=*)
+ pidfile="${1##--pidfile=}"
+ ;;
+ --pid=*)
+ pidfile="${1##--pid=}"
+ ;;
+ -s|--signal)
+ addvar="signal"
+ ;;
+ -t|--test|-o|--oknodo)
+ nothing=true
+ ;;
+ esac
+ shift
+ done
+}
+
+# void rc_setup_daemon_vars(void)
+#
+# Setup our vars based on the start-stop-daemon command
+rc_setup_daemon_vars() {
+ local name i
+ local -a sargs=( "${args%% \'--\' *}" )
+ local -a eargs
+ local x="${args// \'--\' /}"
+ [[ ${x} != "${args}" ]] && eargs=( "${args##* \'--\' }" )
+
+ rc_shift_args ${sargs[@]}
+
+ [[ -z ${cmd} ]] && cmd="${name}"
+
+ # We may want to launch the daemon with a custom command
+ # This is mainly useful for debugging with apps like valgrind, strace
+ local bash_service=$( bash_variable "${myservice}" )
+ eval x=\"\$\{RC_DAEMON_${bash_service}\}\"
+ if [[ -n ${x} ]]; then
+ local -a d=( ${x} )
+ if ${stopping}; then
+ args="--stop"
+ else
+ args="--start"
+ fi
+
+ # Add -- or - arguments as s-s-d options
+ j=${#d[@]}
+ for (( i=0; i<j; i++ )); do
+ [[ ${d[i]:0:1} != "-" ]] && break
+ args="${args} ${d[i]}"
+ unset d[i]
+ done
+ d=$( "${d[@]}" )
+
+ eval args=\"${args} --exec '${d[0]}' -- ${d[@]:1} '${cmd}' ${eargs[@]}\"
+ ! ${stopping} && cmd="${d[0]}"
+ fi
+
+ return 0
+}
+
+# bool rc_try_kill_pid(int pid, char* signal, bool session)
+#
+# Repeatedly kill the pid with the given signal until it dies
+# If session is true then we use tread pid as session and send it
+# via pkill
+# Returns 0 if successfuly otherwise 1
+rc_try_kill_pid() {
+ local pid="$1" signal="${2:-TERM}" session="${3:-false}" i s
+
+ # We split RC_RETRY_TIMEOUT into tenths of seconds
+ # So we return as fast as possible
+ (( s=${RC_RETRY_TIMEOUT}/10 ))
+
+ for (( i=0; i<RC_RETRY_COUNT*10; i++ )); do
+ if ${session} ; then
+ if [[ -x /usr/bin/pkill ]]; then
+ /usr/bin/pkill "-${signal}" -s "${pid}" || return 0
+ else
+ local pids=$(/bin/ps -eo pid,sid | /bin/sed -n 's/'${pid}'$//p')
+ [[ -z ${pids} ]] && return 0
+ /bin/kill -s "${signal}" ${pids} 2>/dev/null
+ fi
+ else
+ /bin/kill -s "${signal}" "${pid}" 2>/dev/null || return 0
+ fi
+ LC_ALL=C /bin/sleep "${s}"
+ done
+
+ return 1
+}
+
+# bool rc_kill_pid(int pid, bool session)
+#
+# Kills the given pid/session
+# Returns 1 if we fail to kill the pid (if it's valid) otherwise 0
+rc_kill_pid() {
+ local pid="$1" session="${2:-false}"
+
+ rc_try_kill_pid "${pid}" "${signal}" "${session}" && return 0
+
+ [[ ${RC_RETRY_KILL} == "yes" ]] \
+ && rc_try_kill_pid "${pid}" KILL "${session}" && return 0
+
+ return 1
+}
+
+# char* pidof(char* cmd, ...)
+#
+# Returns a space seperated list of pids associated with the command
+# This is to handle the rpc.nfsd program which acts weird
+pidof() {
+ local arg args
+
+ for arg in "$@"; do
+ [[ ${arg##*/} == "rpc.nfsd" ]] && arg="${arg%/*}/nfsd"
+ args="${args} '"${arg}"'"
+ done
+
+ eval /bin/pidof -x ${args}
+}
+
+# bool is_daemon_running(char* cmd, char* pidfile)
+#
+# Returns 0 if the given daemon is running, otherwise 1
+# If a pidfile is supplied, the pid inside it must match
+# a pid in the list of pidof ${cmd}
+is_daemon_running() {
+ local cmd pidfile pids pid
+
+ if [[ $# == "1" ]]; then
+ cmd="$1"
+ else
+ local i j="$#"
+ for (( i=0; i<j-1; i++ )); do
+ cmd="${cmd} $1"
+ shift
+ done
+ pidfile="$1"
+ fi
+
+ pids=$( pidof ${cmd} )
+ [[ -z ${pids} ]] && return 1
+
+ [[ -s ${pidfile} ]] || return 0
+
+ read pid < "${pidfile}"
+ pids=" ${pids} "
+ [[ ${pids// ${pid} } != "${pids}" ]]
+}
+
+# int rc_start_daemon(void)
+#
+# We don't do anyting fancy - just pass the given options
+# to start-stop-daemon and return the value
+rc_start_daemon() {
+ eval /sbin/start-stop-daemon "${args}"
+ local retval="$?"
+
+ [[ ${retval} != "0" ]] && return "${retval}"
+ [[ ${RC_WAIT_ON_START} == "0" ]] && return "${retval}"
+
+ # We pause for RC_WAIT_ON_START seconds and then
+ # check if the daemon is still running - this is mainly
+ # to handle daemons who launch and then fail due to invalid
+ # configuration files
+ LC_ALL=C /bin/sleep "${RC_WAIT_ON_START}"
+ is_daemon_running ${cmd} "${pidfile}"
+ retval="$?"
+ [[ ${retval} == "0" ]] && return 0
+
+ # Stop if we can to clean things up
+ if [[ $( type -t stop ) == "function" ]]; then
+ stop >/dev/null # We don't want to echo ebegin/eend
+ elif [[ -n ${pidfile} ]]; then
+ rc_stop_daemon
+ fi
+ return "${retval}"
+}
+
+# bool rc_stop_daemon(void)
+#
+# Instead of calling start-stop-daemon we instead try and
+# kill the process ourselves and any children left over
+# Returns 0 if everything was successful otherwise 1
+rc_stop_daemon() {
+ local pid pids retval="0"
+
+ if [[ -n ${cmd} ]]; then
+ if ! is_daemon_running ${cmd} "${pidfile}" ; then
+ [[ ${RC_FAIL_ON_ZOMBIE} == "yes" ]] && return 1
+ fi
+ pids=$( pidof ${cmd} )
+ fi
+
+ if [[ -s ${pidfile} ]]; then
+ read pid < "${pidfile}"
+ # Check that the given program is actually running the pid
+ if [[ -n ${pids} ]]; then
+ pids=" ${pids} "
+ [[ ${pids// ${pid} } == ${pids} ]] && return 1
+ fi
+ pids=${pid}
+ fi
+
+ for pid in ${pids}; do
+ if [[ ${RC_FAIL_ON_ZOMBIE} == "yes" ]]; then
+ /bin/ps -p "${pid}" &>/dev/null || return 1
+ fi
+
+ if rc_kill_pid "${pid}" false ; then
+ # Remove the pidfile if the process didn't
+ [[ -f ${pidfile} ]] && /bin/rm -f "${pidfile}"
+ else
+ retval=1
+ fi
+
+ if [[ ${RC_KILL_CHILDREN} == "yes" ]]; then
+ rc_kill_pid "${pid}" true || retval=1
+ fi
+ done
+
+ return "${retval}"
+}
+
+# void update_service_status(char *service)
+#
+# Loads the service state file and ensures that all listed daemons are still
+# running - hopefully on their correct pids too
+# If not, we stop the service
+update_service_status() {
+ local service="$1" daemonfile="${svcdir}/daemons/$1" i
+ local -a RC_DAEMONS=() RC_PIDFILES=()
+
+ # We only care about marking started services as stopped if the daemon(s)
+ # for it are no longer running
+ ! service_started "${service}" && return
+ [[ ! -f ${daemonfile} ]] && return
+
+ # OK, now check that every daemon launched is active
+ # If the --start command was any good a pidfile was specified too
+ source "${daemonfile}"
+ for (( i=0; i<${#RC_DAEMONS[@]}; i++ )); do
+ if ! is_daemon_running ${RC_DAEMONS[i]} "${RC_PIDFILES[i]}" ; then
+ if [[ -e "/etc/init.d/${service}" ]]; then
+ ( /etc/init.d/"${service}" stop &>/dev/null )
+ break
+ fi
+ fi
+ done
+}
+
+# int start-stop-daemon(...)
+#
+# Provide a wrapper to start-stop-daemon
+# Return the result of start_daemon or stop_daemon depending on
+# how we are called
+start-stop-daemon() {
+ local args=$( requote "$@" ) result i
+ local cmd pidfile pid stopping signal nothing=false
+ local daemonfile="${svcdir}/daemons/${myservice}"
+ local -a RC_DAEMONS=() RC_PIDFILES=()
+
+ [[ -e ${daemonfile} ]] && source "${daemonfile}"
+
+ rc_setup_daemon_vars
+
+ # We pass --oknodo and --test directly to start-stop-daemon and return
+ if ${nothing}; then
+ eval /sbin/start-stop-daemon "${args}"
+ return "$?"
+ fi
+
+ if ${stopping}; then
+ rc_stop_daemon
+ result="$?"
+ if [[ ${result} == "0" ]]; then
+ # We stopped the daemon successfully
+ # so we remove it from our state
+ for (( i=0; i<${#RC_DAEMONS[@]}; i++ )); do
+ # We should really check for valid cmd AND pidfile
+ # But most called to --stop only set the pidfile
+ if [[ ${RC_DAEMONS[i]} == "{cmd}" \
+ || ${RC_PIDFILES[i]}="${pidfile}" ]]; then
+ unset RC_DAEMONS[i] RC_PIDFILES[i]
+ RC_DAEMONS=( "${RC_DAEMONS[@]}" )
+ RC_PIDFILES=( "${RC_PIDFILES[@]}" )
+ break
+ fi
+ done
+ fi
+ else
+ rc_start_daemon
+ result="$?"
+ if [[ ${result} == "0" ]]; then
+ # We started the daemon sucessfully
+ # so we add it to our state
+ local max="${#RC_DAEMONS[@]}"
+ RC_DAEMONS[max]="${cmd}"
+ RC_PIDFILES[max]="${pidfile}"
+ fi
+ fi
+
+ # Write the new list of daemon states for this service
+ if [[ ${#RC_DAEMONS[@]} == "0" ]]; then
+ [[ -f ${daemonfile} ]] && rm -f "${daemonfile}"
+ else
+ echo "RC_DAEMONS[0]=\"${RC_DAEMONS[0]}\"" > "${daemonfile}"
+ echo "RC_PIDFILES[0]=\"${RC_PIDFILES[0]}\"" >> "${daemonfile}"
+
+ for (( i=1; i<${#RC_DAEMONS[@]}; i++ )); do
+ echo "RC_DAEMONS[${i}]=\"${RC_DAEMONS[i]}\"" >> "${daemonfile}"
+ echo "RC_PIDFILES[${i}]=\"${RC_PIDFILES[i]}\"" >> "${daemonfile}"
+ done
+ fi
+
+ return "${result}"
+}
+
+# vim:ts=4
diff --git a/sbin/rc-help.sh b/sbin/rc-help.sh
new file mode 100755
index 0000000..2a28859
--- /dev/null
+++ b/sbin/rc-help.sh
@@ -0,0 +1,186 @@
+#!/bin/bash
+# Copyright 1999-2004 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+source /sbin/functions.sh
+
+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 [ -L "${1}" ]
+then
+ myservice="$(readlink "${1}")"
+else
+ myservice=${1}
+fi
+
+myservice=${myservice##*/}
+
+echo -e "
+${GREEN}Gentoo Linux RC-Scripts; ${BLUE}http://www.gentoo.org/${OFF}
+ Copyright 1999-2004 Gentoo Foundation; Distributed under the GPL
+
+Usage: ${CYAN}${myservice}${OFF} < ${GREEN}flags${OFF} > [ ${GREEN}options${OFF} ]
+
+${CYAN}Options:${OFF}
+ ${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}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.
+
+${CYAN}Flags:${OFF}
+ ${GREEN}--quiet${OFF}
+ Suppress output to stdout, except if:
+
+ 1) It is a warning, then output to stdout
+ 2) It is an error, then output to stderr
+
+ ${GREEN}--nocolor${OFF}
+ Suppress the use of colors.
+
+${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' dependeny types can have '*'
+ as 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.
+
+${CYAN}Configuration files:${OFF}
+ There are two files which will be sourced for possible configuration by
+ the rc-scripts. They are (sourced from top to bottom):
+
+ /etc/conf.d/${myservice}
+ /etc/rc.conf
+
+${CYAN}Management:${OFF}
+ Services are added and removed via the 'rc-update' tool. Running it without
+ arguments should give sufficient help.
+"
diff --git a/sbin/rc-services.sh b/sbin/rc-services.sh
new file mode 100755
index 0000000..7ead024
--- /dev/null
+++ b/sbin/rc-services.sh
@@ -0,0 +1,883 @@
+# Copyright 1999-2004 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+# RC Dependency and misc service functions
+
+RC_GOT_SERVICES="yes"
+
+[[ ${RC_GOT_FUNCTIONS} != "yes" ]] && source /sbin/functions.sh
+
+if [[ ${RC_GOT_DEPTREE_INFO} != "yes" ]]; then
+ # Only try and update if we are root
+ if [[ ${EUID} == "0" ]] && ! /sbin/depscan.sh -u ; then
+ echo
+ eerror "Error running '/sbin/depscan.sh'!"
+ eerror "Please correct any problems above."
+ exit 1
+ fi
+
+ source "${svcdir}/deptree"
+ if [[ ${RC_GOT_DEPTREE_INFO} != "yes" ]]; then
+ echo
+ eerror "Dependency info is missing! Please run"
+ eerror " # /sbin/depscan.sh"
+ eerror "to fix this."
+ exit 1
+ fi
+fi
+
+#####################
+# Internal variables
+#####################
+
+# The name of the service whose dependency info we currently have
+rc_name=
+# The index of the service whose dependency info we currently have
+rc_index=0
+# Our dependency types ...
+rc_ineed=
+rc_needsme=
+rc_iuse=
+rc_usesme=
+rc_ibefore=
+rc_iafter=
+rc_broken=
+rc_mtime=
+
+############
+# Functions
+############
+
+# bool get_service_index(service, index)
+#
+# Print the index of 'service'. 'index' is the current index.
+#
+get_service_index() {
+ if [[ -z $1 || -z $2 ]]; then
+ echo "0"
+ return 1
+ fi
+
+ local x myservice="$1" index="$2"
+
+ # Do we already have the index?
+ if [[ -n ${index} && ${index} -gt 0 \
+ && ${myservice} == ${RC_DEPEND_TREE[${index}]} ]]; then
+ echo "${index}"
+ return 0
+ fi
+
+ for (( x=1; x<=${RC_DEPEND_TREE[0]}; x++ )); do
+ index=$(( ${x} * ${rc_index_scale} ))
+ if [[ ${myservice} == ${RC_DEPEND_TREE[${index}]} ]]; then
+ echo "${index}"
+ return 0
+ fi
+ done
+
+ echo "0"
+ return 1
+}
+
+# bool get_dep_info(service)
+#
+# Set the Dependency variables to contain data for 'service'
+#
+get_dep_info() {
+ [[ -z $1 ]] && return 1
+
+ local myservice="$1"
+
+ # We already have the right stuff ...
+ [[ ${myservice} == ${rc_name} && -n ${rc_mtime} ]] && return 0
+
+ rc_index="`get_service_index "${myservice}" "${rc_index}"`"
+ rc_mtime="${RC_DEPEND_TREE[$((${rc_index} + ${rc_type_mtime}))]}"
+
+ # Verify that we have the correct index (rc_index) ...
+ # [[ ${rc_index} == "0" ]] && return 1
+
+ rc_name="${RC_DEPEND_TREE[${rc_index}]}"
+ rc_ineed="${RC_DEPEND_TREE[$((${rc_index} + ${rc_type_ineed}))]}"
+ rc_needsme="${RC_DEPEND_TREE[$((${rc_index} + ${rc_type_needsme}))]}"
+ rc_iuse="${RC_DEPEND_TREE[$((${rc_index} + ${rc_type_iuse}))]}"
+ rc_usesme="${RC_DEPEND_TREE[$((${rc_index} + ${rc_type_usesme}))]}"
+ rc_ibefore="${RC_DEPEND_TREE[$((${rc_index} + ${rc_type_ibefore}))]}"
+ rc_iafter="${RC_DEPEND_TREE[$((${rc_index} + ${rc_type_iafter}))]}"
+ rc_broken="${RC_DEPEND_TREE[$((${rc_index} + ${rc_type_broken}))]}"
+ rc_mtime="${RC_DEPEND_TREE[$((${rc_index} + ${rc_type_mtime}))]}"
+ return 0
+}
+
+# string check_dependency(deptype, service1)
+#
+# List all the services that depend on 'service1' of dependency
+# type 'deptype'
+#
+# bool check_dependency(deptype, -t, service1, service2)
+#
+# Returns true if 'service2' is a dependency of type 'deptype'
+# of 'service1'
+#
+check_dependency() {
+ [[ -z $1 || -z $2 ]] && return 1
+
+ local x myservice deps
+
+ # Set the dependency variables to relate to 'service1'
+ if [[ $2 == "-t" ]]; then
+ [[ -z $3 || -z $4 ]] && return 1
+ myservice="$3"
+ else
+ myservice="$2"
+ fi
+
+ if ! get_dep_info "${myservice}" >/dev/null ; then
+ eerror "Could not get dependency info for \"${myservice}\"!" > /dev/stderr
+ eerror "Please run:" > /dev/stderr
+ eerror " # /sbin/depscan.sh" > /dev/stderr
+ eerror "to try and fix this." > /dev/stderr
+ return 1
+ fi
+
+ # Do we have valid info for 'deptype' ?
+ eval deps=\"\$\{rc_$1\}\"
+ [[ -z ${deps} ]] && return 1
+
+ if [[ $2 == "-t" && -n $4 ]]; then
+ # Check if 'service1' have 'deptype' dependency on 'service2'
+ for x in ${deps}; do
+ [[ ${x} == $4 ]] && return 0
+ done
+ return 1
+ else
+ # Just list all services that 'service1' have 'deptype' dependency on.
+ echo "${deps}"
+ return 0
+ fi
+}
+
+# Same as for check_dependency, except 'deptype' is set to
+# 'ineed'. It will return all the services 'service1' NEED's.
+ineed() {
+ check_dependency ineed "$@"
+}
+
+# Same as for check_dependency, except 'deptype' is set to
+# 'needsme'. It will return all the services that NEED 'service1'.
+needsme() {
+ check_dependency needsme "$@"
+}
+
+# Same as for check_dependency, except 'deptype' is set to
+# 'iuse'. It will return all the services 'service1' USE's.
+iuse() {
+ check_dependency iuse "$@"
+}
+
+# Same as for check_dependency, except 'deptype' is set to
+# 'usesme'. It will return all the services that USE 'service1'.
+usesme() {
+ check_dependency usesme "$@"
+}
+
+# Same as for check_dependency, except 'deptype' is set to
+# 'ibefore'. It will return all the services that are started
+# *after* 'service1' (iow, it will start 'service1' before the
+# list of services returned).
+ibefore() {
+ check_dependency ibefore "$@"
+}
+
+# Same as for check_dependency, except 'deptype' is set to
+# 'iafter'. It will return all the services that are started
+# *before* 'service1' (iow, it will start 'service1' after the
+# list of services returned).
+iafter() {
+ check_dependency iafter "$@"
+}
+
+# Same as for check_dependency, except 'deptype' is set to
+# 'broken'. It will return all the services that 'service1'
+# NEED, but are not present.
+broken() {
+ check_dependency broken "$@"
+}
+
+# bool is_fake_service(service, runlevel)
+#
+# Returns ture if 'service' is a fake service in 'runlevel'.
+#
+is_fake_service() {
+ local x fake_services
+
+ [[ -z $1 || -z $2 ]] && return 1
+
+ [[ $2 != ${BOOTLEVEL} && -e "/etc/runlevels/${BOOTLEVEL}/.fake" ]] \
+ && fake_services="$( < /etc/runlevels/${BOOTLEVEL}/.fake )"
+
+ [[ -e "/etc/runlevels/$2/.fake" ]] \
+ && fake_services="${fake_services} $( < /etc/runlevels/$2/.fake )"
+
+ for x in ${fake_services}; do
+ [[ $1 == ${x##*/} ]] && return 0
+ done
+
+ return 1
+}
+
+# bool in_runlevel(service, runlevel)
+#
+# Returns true if 'service' is in runlevel 'runlevel'.
+#
+in_runlevel() {
+ [[ -z $1 || -z $2 ]] && return 1
+
+ [[ -L "/etc/runlevels/$2/$1" ]] && return 0
+
+ return 1
+}
+
+# bool is_runlevel_start()
+#
+# Returns true if it is a runlevel change, and we are busy
+# starting services.
+#
+is_runlevel_start() {
+ [[ -d ${svcdir}/softscripts.old && \
+ ${SOFTLEVEL} != "${OLDSOFTLEVEL}" ]] && return 0
+
+ return 1
+}
+
+# bool is_runlevel_stop()
+#
+# Returns true if it is a runlevel change, and we are busy
+# stopping services.
+#
+is_runlevel_stop() {
+ [[ -d ${svcdir}/softscripts.new && \
+ ${SOFTLEVEL} != "${OLDSOFTLEVEL}" ]] && return 0
+
+ return 1
+}
+
+# void sevice_message([char *type] char *message)
+#
+# Print out a service message if we are on parallel
+service_message() {
+ [[ ${RC_PARALLEL_STARTUP} != "yes" ]] && return
+
+ local cmd="einfo"
+ if [[ $1 == 1 || $1 == "error" || $1 == "eerror" ]]; then
+ cmd="eerror"
+ shift
+ fi
+
+ local r="${RC_QUIET_STDOUT}"
+ RC_QUIET_STDOUT="no"
+ ${cmd} "$@"
+ RC_QUIET_STDOUT="${r}"
+}
+
+# bool begin_service( service )
+#
+# atomically marks the service as being executed
+# use like this:
+#
+# if begin_service service ; then
+# whatever is in here can only be executed by one process
+# end_service service
+# fi
+begin_service()
+{
+ [[ {$START_CRITICAL} == "yes" ]] && return 0
+
+ mkfifo "${svcdir}/exclusive/${service}" 2> /dev/null
+ return $?
+}
+
+# void end_service(service, exitcode)
+#
+# stops executing a exclusive region and
+# wakes up anybody who is waiting for the exclusive region
+#
+end_service()
+{
+ local service="$1" exitstatus="$2"
+
+ # if we are doing critical services, there is no fifo
+ [[ ${START_CRITICAL} == "yes" ]] && return
+
+ if [[ -n ${exitstatus} ]] ; then
+ echo "${exitstatus}" > "${svcdir}/exitcodes/${service}"
+ fi
+
+ # move the fifo to a unique name so no-one is waiting for it
+ local fifo="${svcdir}/exclusive/${service}"
+ if [[ -e "${fifo}" ]]; then
+ local tempname="${fifo}.$$"
+ mv -f "${fifo}" "${tempname}"
+
+ # wake up anybody that was waiting for the fifo
+ touch "${tempname}"
+
+ # We dont need the fifo anymore
+ rm -f "${tempname}"
+ fi
+}
+
+# int wait_service(service)
+#
+# If a service has started, or a fifo does not exist return 0
+# Otherwise, wait until we get an exit code via the fifo and return
+# that instead.
+wait_service()
+{
+ local service="$1"
+ local fifo="${svcdir}/exclusive/${service}"
+
+ [[ ${START_CRITICAL} == "yes" || ${STOP_CRITICAL} == "yes" ]] && return 0
+ [[ ! -e ${fifo} ]] && return 0
+
+ # This will block until the service fifo is touched
+ # Otheriwse we don't block
+ local tmp=$( < "${fifo}" &>/dev/null )
+ local exitstatus=$( < "${svcdir}/exitcodes/${service}" )
+
+ return "${exitstatus}"
+}
+
+# int start_service(service)
+#
+# Start 'service' if it is not already running.
+#
+start_service() {
+ local service="$1"
+ [[ -z ${service} ]] && return 1
+
+ if [[ ! -e "/etc/init.d/${service}" ]]; then
+ mark_service_stopped "${service}"
+ return 1
+ fi
+
+ service_starting "${service}" && return 0
+ service_started "${service}" && return 0
+ service_inactive "${service}" && return 1
+
+ if is_fake_service "${service}" "${SOFTLEVEL}" ; then
+ mark_service_started "${service}"
+ splash "svc_start" "${service}"
+ splash "svc_started" "${service}" "0"
+ return 0
+ fi
+
+ begin_service "${service}" || return 0
+ splash "svc_start" "${service}"
+ if [[ ${RC_PARALLEL_STARTUP} != "yes" \
+ || ${START_CRITICAL} == "yes" ]] ; then
+ # if we can not start the services in parallel
+ # then just start it and return the exit status
+ ( "/etc/init.d/${service}" start )
+ retval="$?"
+ splash "svc_started" "${service}" "${retval}"
+ end_service "${service}" "${retval}"
+ return "${retval}"
+ else
+ # if parallel startup is allowed, start it in background
+ (
+ "/etc/init.d/${service}" start
+ retval="$?"
+ splash "svc_started" "${service}" "${retval}"
+ end_service "${service}" "${retval}"
+ ) &
+ return 0
+ fi
+}
+
+# int stop_service(service)
+#
+# Stop 'service' if it is not already running.
+#
+stop_service() {
+ local service="$1"
+ [[ -z ${service} ]] && return 1
+
+ if [[ ! -e "/etc/init.d/${service}" ]]; then
+ mark_service_stopped "${service}"
+ return 0
+ fi
+
+ service_stopping "${service}" && return 0
+ service_stopped "${service}" && return 0
+
+ local level="${SOFTLEVEL}"
+ is_runlevel_stop && level="${OLDSOFTLEVEL}"
+
+ if is_fake_service "${service}" "${level}" ; then
+ splash "svc_stop" "${service}"
+ mark_service_stopped "${service}"
+ splash "svc_stopped" "${service}" "0"
+ return 0
+ fi
+
+ begin_service "${service}" || return 0
+
+ splash "svc_stop" "${service}"
+ if [[ ${RC_PARALLEL_STARTUP} != "yes" \
+ || ${STOP_CRITICAL} == "yes" ]] ; then
+ # if we can not start the services in parallel
+ # then just start it and return the exit status
+ ( "/etc/init.d/${service}" stop )
+ retval="$?"
+ splash "svc_stopped" "${service}" "${retval}"
+ end_service "${service}" "${retval}"
+ return "${retval}"
+ else
+ # if parallel startup is allowed, start it in background
+ (
+ ( "/etc/init.d/${service}" stop )
+ retval="$?"
+ splash "svc_stopped" "${service}" "${retval}"
+ end_service "${service}" "${retval}"
+ ) &
+ return 0
+ fi
+}
+
+# bool mark_service_starting(service)
+#
+# Mark 'service' as starting.
+#
+mark_service_starting() {
+ [[ -z $1 ]] && return 1
+
+ ln -snf "/etc/init.d/$1" "${svcdir}/starting/$1"
+ local retval=$?
+
+ [[ -f "${svcdir}/started/$1" ]] && rm -f "${svcdir}/started/$1"
+ [[ -f "${svcdir}/inactive/$1" ]] && rm -f "${svcdir}/inactive/$1"
+ [[ -f "${svcdir}/stopping/$1" ]] && rm -f "${svcdir}/stopping/$1"
+
+ return "${retval}"
+}
+
+# bool mark_service_started(service)
+#
+# Mark 'service' as started.
+#
+mark_service_started() {
+ [[ -z $1 ]] && return 1
+
+ ln -snf "/etc/init.d/$1" "${svcdir}/started/$1"
+ local retval="$?"
+
+ [[ -f "${svcdir}/starting/$1" ]] && rm -f "${svcdir}/starting/$1"
+ [[ -f "${svcdir}/inactive/$1" ]] && rm -f "${svcdir}/inactive/$1"
+ [[ -f "${svcdir}/stopping/$1" ]] && rm -f "${svcdir}/stopping/$1"
+
+ return "${retval}"
+}
+
+# bool mark_service_inactive(service)
+#
+# Mark service as inactive
+#
+mark_service_inactive() {
+ [[ -z $1 ]] && return 1
+
+ ln -snf "/etc/init.d/$1" "${svcdir}/inactive/$1"
+ local retval="$?"
+ [[ -f "${svcdir}/started/$1" ]] && rm -f "${svcdir}/started/$1"
+ [[ -f "${svcdir}/starting/$1" ]] && rm -f "${svcdir}/starting/$1"
+ [[ -f "${svcdir}/stopping/$1" ]] && rm -f "${svcdir}/stopping/$1"
+
+ return "${retval}"
+}
+
+# bool mark_service_stopping(service)
+#
+# Mark 'service' as stopping.
+#
+mark_service_stopping() {
+ [[ -z $1 ]] && return 1
+
+ ln -snf "/etc/init.d/$1" "${svcdir}/stopping/$1"
+ local retval="$?"
+
+ [ -f "${svcdir}/starting/$1" ] && rm -f "${svcdir}/starting/$1"
+ [ -f "${svcdir}/started/$1" ] && rm -f "${svcdir}/started/$1"
+ [ -f "${svcdir}/inactive/$1" ] && rm -f "${svcdir}/inactive/$1"
+
+ return "${retval}"
+}
+
+# bool mark_service_stopped(service)
+#
+# Mark 'service' as stopped.
+#
+mark_service_stopped() {
+ [[ -z $1 ]] && return 1
+
+ [[ -f "${svcdir}/starting/$1" ]] && rm -f "${svcdir}/starting/$1"
+ [[ -f "${svcdir}/started/$1" ]] && rm -f "${svcdir}/started/$1"
+ [[ -f "${svcdir}/inactive/$1" ]] && rm -f "${svcdir}/inactive/$1"
+ [[ -f "${svcdir}/stopping/$1" ]] && rm -f "${svcdir}/stopping/$1"
+
+ return $?
+}
+
+# bool test_service_state(char *service, char *state)
+#
+# Returns 0 if the service link exists and points to a file, otherwise 1
+# If 1 then the link is erased if it exists
+test_service_state() {
+ [[ -z $1 || -z $2 ]] && return 1
+
+ local f="${svcdir}/$2/$1"
+
+ # Service is in the state requested
+ [[ -L ${f} ]] && return 0
+
+ if [[ ! -e ${f} ]]; then
+ rm -f "${f}"
+ return 1
+ fi
+
+ return 0
+}
+
+# bool service_starting(service)
+#
+# Returns true if 'service' is starting
+#
+service_starting() {
+ test_service_state "$1" "starting"
+}
+
+# bool service_started(service)
+#
+# Returns true if 'service' is started
+#
+service_started() {
+ test_service_state "$1" "started"
+}
+
+# bool service_inactive(service)
+#
+# Returns true if 'service' is inactive
+#
+service_inactive() {
+ test_service_state "$1" "inactive"
+}
+
+# bool service_stopping(service)
+#
+# Returns true if 'service' is stopping
+#
+service_stopping() {
+ test_service_state "$1" "stopping"
+}
+
+# bool service_stopped(service)
+#
+# Returns true if 'service' is stopped
+#
+service_stopped() {
+ [[ -z $1 ]] && return 1
+
+ service_starting "$1" && return 1
+ service_started "$1" && return 1
+ service_stopping "$1" && return 1
+ service_inactive "$1" && return 1
+
+ return 0
+}
+
+# bool mark_service_failed(service)
+#
+# Mark service as failed for current runlevel. Note that
+# this is only valid on runlevel change ...
+#
+mark_service_failed() {
+ [[ -z $1 || ! -d "${svcdir}/failed" ]] && return 1
+
+ ln -snf "/etc/init.d/$1" "${svcdir}/failed/$1"
+}
+
+# bool service_failed(service)
+#
+# Return true if 'service' have failed during this runlevel.
+#
+service_failed() {
+ [[ -n $1 && -L "${svcdir}/failed/$1" ]]
+}
+
+# bool net_service(service)
+#
+# Returns true if 'service' is a service controlling a network interface
+#
+net_service() {
+ [[ -n $1 && ${1%%.*} == "net" && ${1##*.} != $1 ]]
+}
+
+# bool is_net_up()
+#
+# Return true if service 'net' is considered up, else false.
+#
+# Notes for RC_NET_STRICT_CHECKING values:
+# none net is up without checking anything - usefull for vservers
+# lo Interface 'lo' is counted and if only it is up, net is up.
+# no Interface 'lo' is not counted, and net is down even with it up,
+# so there have to be at least one other interface up.
+# yes All interfaces must be up.
+is_net_up() {
+ local netcount=0
+
+ case "${RC_NET_STRICT_CHECKING}" in
+ none)
+ return 0
+ ;;
+ lo)
+ netcount="$(ls -1 "${svcdir}"/started/net.* 2> /dev/null | \
+ egrep -c "\/net\..*$")"
+ ;;
+ *)
+ netcount="$(ls -1 "${svcdir}"/started/net.* 2> /dev/null | \
+ grep -v 'net\.lo' | egrep -c "\/net\..*$")"
+ ;;
+ esac
+
+ # Only worry about net.* services if this is the last one running,
+ # or if RC_NET_STRICT_CHECKING is set ...
+ if [ "${netcount}" -lt 1 -o "${RC_NET_STRICT_CHECKING}" = "yes" ]
+ then
+ return 1
+ fi
+
+ return 0
+}
+
+# bool dependon(service1, service2)
+#
+# Does service1 depend (NEED or USE) on service2 ?
+#
+dependon() {
+ ineed -t "$1" "$2" || iuse -t "$1" "$2"
+}
+
+# string validi(use/after, service)
+#
+# This is the main code for valid_after and valid_iuse
+# No point in writing it twice!
+valid_i() {
+ local x
+ # Just set to dummy for now (don't know if $svcdir/softlevel exists yet).
+ local mylevel=${BOOTLEVEL}
+
+ [[ $1 != "after" && $1 != "use" ]] && return 1
+
+ # Cannot be SOFTLEVEL, as we need to know current runlevel
+ [[ -f ${svcdir}/softlevel ]] && mylevel=$( < "${svcdir}/softlevel" )
+
+ for x in $( i$1 "$2" )
+ do
+ [[ -e "/etc/runlevels/${BOOTLEVEL}/${x}" \
+ || -e "/etc/runlevels/${mylevel}/${x}" \
+ || ${x} == "net" ]] \
+ && echo "${x}"
+ done
+
+ return 0
+}
+
+# string valid_iuse(service)
+#
+# This will only give the valid use's for the service
+# (they must be in the boot or current runlevel)
+#
+valid_iuse() {
+ valid_i "use" "$1"
+}
+
+#string valid_iafter(service)
+#
+# Valid services for current or boot rc level that should start
+# before 'service'
+#
+valid_iafter() {
+ valid_i "after" "$1"
+}
+
+# string trace_dependencies(service[s])
+#
+# Get and sort the dependencies of given service[s].
+#
+trace_dependencies() {
+ local -a services=( "$@" ) deps
+ local i j
+
+ if [[ $1 == -* ]]; then
+ deptype="${1/-}"
+ if net_service "${myservice}" ; then
+ services=( "net" "${myservice}" )
+ else
+ services=( "${myservice}" )
+ fi
+ fi
+
+ # If its a net service, just replace it with 'net'
+ if [[ -z ${deptype} ]] ; then
+ for (( i=0; i<${#services[@]} ; i++ )) ; do
+ net_service "${services[i]}" && services[i]="net"
+ done
+ fi
+
+ sort_unique() {
+ set -- " ${@/%/\n}"
+ echo -e "$@" | sort -u
+ }
+
+ local last=""
+ while [[ ${services[@]} != "${last}" ]]; do
+ last="${services[*]}"
+ for (( i=0; i<${#services[@]}; i++ )); do
+ if [[ -n ${deptype} ]] ; then
+ deps=( "${deps[@]}" $( "${deptype}" "${services[i]}" ) )
+ else
+ ndeps=(
+ $( ineed "${services[i]}" )
+ $( valid_iuse "${services[i]}" )
+ )
+
+ if is_runlevel_start || is_runlevel_stop ; then
+ ndeps=( "${ndeps[@]}" $( valid_iafter "${services[i]}" ) )
+ fi
+
+ #If its a net service, just replace it with 'net'
+ for (( j=0; j<${#ndeps[*]}; j++ )) ; do
+ net_service "${ndeps[j]}" && ndeps[j]="net"
+ done
+
+ deps=( "${deps[@]}" "${ndeps[@]}" )
+ fi
+ done
+ services=( $(sort_unique ${services[@]} ${deps[@]}) )
+ done
+
+ # Now, we sort our services
+ # When a service is first visited, we mark it dead and then
+ # revisit any dependencies. Finally we add ourselves to the sorted list.
+ # This should never get into an infinite loop, thanks to our dead array.
+ local -a dead=() deadname=() sorted=()
+ for (( i=0; i<${#services[@]}; i++ )); do
+ dead[i]=false;
+ deadname[i]="${services[i]}"
+ done
+
+ after_visit() {
+ local service="$1" i
+
+ for (( i=0; i<${#deadname[@]}; i++)); do
+ [[ ${service} == ${deadname[i]} ]] && break
+ done
+
+ ${dead[i]} && return
+ dead[i]=true
+
+ local x deps="$( ineed ${service} ) $( valid_iuse ${service} )"
+ if is_runlevel_start || is_runlevel_stop ; then
+ deps="${deps} $( valid_iafter ${service} )"
+ fi
+
+ if [[ -z ${deptype} ]] ; then
+ # If its a net service, just replace it with 'net'
+ for (( j=0; j<${#deps[@]}; j++ )) ; do
+ net_service "${deps[j]}" && deps[j]="net"
+ done
+ fi
+
+ for x in ${deps}; do
+ after_visit "${x}"
+ done
+
+ sorted=( "${sorted[@]}" "${service}" )
+ }
+
+ for (( i=0; i<${#services[*]}; i++ )); do
+ after_visit "${services[i]}"
+ done
+ services=( "${sorted[@]}" )
+
+ if [[ -n ${deptype} ]] ; then
+ # If deptype is set, we do not want the name of this service
+ x=" ${services[@]} "
+ services=( ${x// ${myservice} / } )
+
+ # If its a net service, do not include "net"
+ if net_service "${myservice}" ; then
+ x=" ${services[@]} "
+ sorted=( ${services// net / } )
+ fi
+ else
+ local netserv y
+
+ # XXX: I dont think RC_NET_STRICT_CHECKING should be considered
+ # here, but you never know ...
+ netserv=$( cd "${svcdir}"/started; ls net.* 2>/dev/null )
+
+ get_netservices() {
+ local runlevel="$1"
+
+ if [[ -d "/etc/runlevels/${runlevel}" ]] ; then
+ cd "/etc/runlevels/${runlevel}"
+ ls net.* 2>/dev/null
+ fi
+ }
+
+ # If no net services are running or we only have net.lo up, then
+ # assume we are in boot runlevel or starting a new runlevel
+ if [[ -z ${netserv} || ${netserv} == "net.lo" ]]; then
+ local mylevel="${BOOTLEVEL}"
+ local startnetserv=$( get_netservices "${mylevel}" )
+
+ [[ -f "${svcdir}/softlevel" ]] && mylevel=$( < "${svcdir}/softlevel" )
+ [[ ${BOOTLEVEL} != ${mylevel} ]] && \
+ startnetserv="${startnetserv} $( get_netservices "${mylevel}" )"
+ [[ -n ${startnetserv} ]] && netserv="${startnetserv}"
+ fi
+
+ # Replace 'net' with the actual net services
+ x=" ${services[@]} "
+ services=( ${x// net / ${netserv} } )
+ fi
+
+ echo "${services[@]}"
+}
+
+# bool query_before(service1, service2)
+#
+# Return true if 'service2' should be started *before*
+# service1.
+#
+query_before() {
+ local x list
+ local netservice="no"
+
+ [[ -z $1 || -z $2 ]] && return 1
+
+ list=$( trace_dependencies "$1" )
+
+ net_service "$2" && netservice="yes"
+
+ for x in ${list} ; do
+ [[ ${x} == "$2" ]] && return 0
+
+ # Also match "net" if this is a network service ...
+ [[ ${netservice} == "yes" && ${x} == "net" ]] && return 0
+ done
+
+ return 1
+}
+
+# vim:ts=4
diff --git a/sbin/rc-update b/sbin/rc-update
new file mode 100755
index 0000000..b13e406
--- /dev/null
+++ b/sbin/rc-update
@@ -0,0 +1,162 @@
+#!/bin/bash
+# Copyright 1999-2004 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+source /sbin/functions.sh
+if [[ ${EUID} -ne 0 ]] ; then
+ eerror "$0: must be root."
+ exit 1
+fi
+
+usage() {
+cat << FOO
+usage: rc-update -a|add script runlevel2 [runlevel2 ...]
+ rc-update -d|del script [runlevel1 ...]
+ rc-update -s|show [runlevel1 ...]
+
+examples:
+ # rc-update add net.eth0 default
+ Adds the net.eth0 script (in /etc/init.d) to the "default" runlevel.
+
+ # rc-update del sysklogd
+ Deletes the sysklogd script from all runlevels. The original script
+ is not deleted, just any symlinks to the script in /etc/runlevels/*.
+
+ # rc-update del net.eth2 default wumpus
+ Delete the net.eth2 script from the default and wumpus runlevels.
+ All other runlevels are unaffected. Again, the net.eth2 script
+ residing in /etc/init.d is not deleted, just any symlinks in
+ /etc/runlevels/default and /etc/runlevels/wumpus.
+
+ # rc-update show
+ Show all the available scripts and list at which runlevels they
+ will execute.
+FOO
+ exit 1
+}
+
+add() {
+ local x=
+ local myscript=
+
+ if [[ $# -lt 3 ]] ; then
+ eerror "${0}: at least two arguments expected after \"$1\"."
+ exit 1
+ fi
+ shift
+ myscript="$1"
+ if [[ ! -e /etc/init.d/${myscript} ]] ; then
+ eerror "$0: /etc/init.d/${myscript} not found; aborting."
+ exit 1
+ fi
+ shift
+ for x in $* ; do
+ if [[ ! -e /etc/runlevels/${x} ]] ; then
+ ewarn "runlevel ${x} not found; skipping"
+ continue
+ fi
+ if [[ -L /etc/runlevels/${x}/${myscript} ]] ; then
+ ewarn "${myscript} already installed in runlevel ${x}; skipping"
+ continue
+ fi
+ if [[ ! -x /etc/init.d/${myscript} ]] ; then
+ ewarn "${myscript} not executable; skipping"
+ continue
+ fi
+ ln -snf "/etc/init.d/${myscript}" "/etc/runlevels/${x}/${myscript}"
+ if [[ $? -ne 0 ]] ; then
+ eerror "$0: failed to add ${myscript} to ${x}."
+ exit 1
+ fi
+ regen=1
+ einfo "${myscript} added to runlevel ${x}"
+ done
+}
+
+del() {
+ local x=
+ local mylevels=
+ local myscript=
+ local remlevels=
+
+ if [[ $# -lt 2 ]] ; then
+ eerror "$0: at least one argument expected after \"$1\"."
+ exit 1
+ fi
+ shift
+ myscript=$1
+ shift
+ if [[ $# -eq 0 ]] ; then
+ mylevels=$(cd /etc/runlevels/; ls)
+ else
+ mylevels="$*"
+ fi
+ remlevels=""
+ for x in ${mylevels} ; do
+ if [[ -L /etc/runlevels/${x}/${myscript} ]] ; then
+ regen=1
+ rm -f "/etc/runlevels/${x}/${myscript}"
+ remlevels="${remlevels} ${x}"
+ fi
+ done
+ if [[ -z ${remlevels} ]] ; then
+ einfo "${myscript} not found in any of the specified runlevels."
+ else
+ einfo "${myscript} removed from the following runlevels:${remlevels}"
+ fi
+}
+
+show() {
+ local x=
+ local y=
+ local mylevels=
+ local myscripts=
+
+ shift
+ if [[ $# -eq 0 ]] ; then
+ mylevels=$(cd /etc/runlevels/; ls)
+ else
+ mylevels="$*"
+ fi
+ myscripts=$(cd /etc/init.d; ls)
+
+ for x in ${myscripts} ; do
+ if [[ ${x%%.sh} = "${x}" ]] ; then
+ printf "%20s | " ${x:0:19}
+ for y in ${mylevels} ; do
+ if [[ -L /etc/runlevels/${y}/${x} ]] ; then
+ echo -n "${y} "
+ else
+ printf "%${#y}s " " "
+ fi
+ done
+ echo ""
+ fi
+ done
+}
+
+if [[ $# -lt 1 ]] ; then
+ usage
+ exit 1
+fi
+
+regen=0
+
+case "$1" in
+ add|-a)
+ add "$@"
+ ;;
+ del|delete|-d)
+ del "$@"
+ ;;
+ show|-s)
+ show "$@"
+ ;;
+ *)
+ usage
+ exit 1
+ ;;
+esac
+
+
+# vim:ts=4
diff --git a/sbin/runscript.sh b/sbin/runscript.sh
new file mode 100755
index 0000000..0c13372
--- /dev/null
+++ b/sbin/runscript.sh
@@ -0,0 +1,581 @@
+#!/bin/bash
+# Copyright 1999-2005 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+# Common functions
+[[ ${RC_GOT_FUNCTIONS} != "yes" ]] && source /sbin/functions.sh
+# Functions to handle dependencies and services
+[[ ${RC_GOT_SERVICES} != "yes" ]] && source "${svclib}/sh/rc-services.sh"
+# Functions to control daemons
+[[ ${RC_GOT_DAEMON} != "yes" ]] && source "${svclib}/sh/rc-daemon.sh"
+
+# User must be root to run most script stuff (except status)
+if [[ ${EUID} != 0 ]] && ! [[ $2 == "status" && $# -eq 2 ]] ; then
+ eerror "$0: must be root to run init scripts"
+ exit 1
+fi
+
+# State variables
+svcpause="no"
+svcrestart="no"
+
+myscript=$1
+if [[ -L $1 ]] && [[ ! -L /etc/init.d/${1##*/} ]] ; then
+ myservice=$(readlink "$1")
+else
+ myservice=$1
+fi
+
+myservice=${myservice##*/}
+export SVCNAME=${myservice}
+mylevel=$(<"${svcdir}/softlevel")
+
+# Set $IFACE to the name of the network interface if it is a 'net.*' script
+if [[ ${myservice%%.*} == "net" ]] && [[ ${myservice##*.} != ${myservice} ]] ; then
+ IFACE=${myservice##*.}
+ NETSERVICE="yes"
+else
+ IFACE=
+ NETSERVICE=
+fi
+
+# Source configuration files.
+# (1) Source /etc/conf.d/${myservice} to get initscript-specific
+# configuration (if it exists).
+# (2) Source /etc/conf.d/net if it is a net.* service
+# (3) Source /etc/rc.conf to pick up potentially overriding
+# configuration, if the system administrator chose to put it
+# there (if it exists).
+
+[[ -e $(add_suffix /etc/conf.d/${myservice}) ]] && source "$(add_suffix /etc/conf.d/${myservice})"
+[[ -e $(add_suffix /etc/conf.d/net) ]] && \
+[[ ${NETSERVICE} == "yes" ]] && source "$(add_suffix /etc/conf.d/net)"
+[[ -e $(add_suffix /etc/rc.conf) ]] && source "$(add_suffix /etc/rc.conf)"
+
+usage() {
+ local IFS="|"
+ myline="Usage: ${myservice} { $* "
+ echo
+ eerror "${myline}}"
+ eerror " ${myservice} without arguments for full help"
+}
+
+stop() {
+ # Return success so the symlink gets removed
+ return 0
+}
+
+start() {
+ eerror "ERROR: \"${myservice}\" does not have a start function."
+ # Return failure so the symlink doesn't get created
+ return 1
+}
+
+restart() {
+ svc_restart || return $?
+}
+
+status() {
+ # Dummy function
+ return 0
+}
+
+svc_stop() {
+ local x=
+ local mydep=
+ local mydeps=
+ local retval=0
+ local ordservice=
+ local was_inactive=false
+
+ if service_stopping "${myservice}" ; then
+ eerror "ERROR: \"${myservice}\" is already stopping."
+ return 0
+ elif service_stopped "${myservice}" ; then
+ eerror "ERROR: \"${myservice}\" has not yet been started."
+ return 0
+ fi
+
+ # Do not try to stop if it had already failed to do so on runlevel change
+ if is_runlevel_stop && service_failed "${myservice}" ; then
+ return 1
+ fi
+
+ service_inactive "${myservice}" && was_inactive=true
+
+ # Remove symlink to prevent recursion
+ mark_service_stopping "${myservice}"
+
+ service_message "Stopping service ${myservice}"
+
+ if in_runlevel "${myservice}" "${BOOTLEVEL}" && \
+ [[ ${SOFTLEVEL} != "reboot" && ${SOFTLEVEL} != "shutdown" && \
+ ${SOFTLEVEL} != "single" ]]
+ then
+ ewarn "WARNING: you are stopping a boot service."
+ fi
+
+ if [[ ${svcpause} != "yes" ]] ; then
+ if [[ ${NETSERVICE} == "yes" ]] ; then
+ # A net.* service
+ if in_runlevel "${myservice}" "${BOOTLEVEL}" || \
+ in_runlevel "${myservice}" "${mylevel}"
+ then
+ # Only worry about net.* services if this is the last one running,
+ # or if RC_NET_STRICT_CHECKING is set ...
+ if ! is_net_up ; then
+ mydeps="net"
+ fi
+ fi
+
+ mydeps="${mydeps} ${myservice}"
+ else
+ mydeps=${myservice}
+ fi
+ fi
+
+ # Save the IN_BACKGROUND var as we need to clear it for stopping depends
+ local ib_save="${IN_BACKGROUND}"
+ unset IN_BACKGROUND
+ local -a servicelist=() index=0
+
+ for mydep in ${mydeps} ; do
+ # If some service 'need' $mydep, stop it first; or if it is a runlevel change,
+ # first stop all services that is started 'after' $mydep.
+ if needsme "${mydep}" >/dev/null || \
+ (is_runlevel_stop && ibefore "${mydep}" >/dev/null)
+ then
+ local -a sl=( $(needsme "${mydep}") )
+
+ # On runlevel change, stop all services "after $mydep" first ...
+ if is_runlevel_stop ; then
+ sl=( "${sl[@]}" $(ibefore "${mydep}") )
+ fi
+
+ local z="${#sl[@]}"
+ for (( x=0; x<z; x++ )); do
+ # Service not currently running, continue
+ if ! service_started "${sl[x]}" ; then
+ unset sl[x]
+ continue
+ fi
+
+ if ibefore -t "${mydep}" "${x}" >/dev/null && \
+ [[ -L ${svcdir}/softscripts.new/${x} ]]
+ then
+ # Service do not 'need' $mydep, and is still present in
+ # new runlevel ...
+ unset sl[x]
+ continue
+ fi
+
+ stop_service "${sl[x]}"
+ done
+ fi
+ servicelist[index]="${sl[index]}"
+ (( index++ ))
+ done
+
+ index=0
+ for mydep in ${mydeps} ; do
+ for x in ${servicelist[index]} ; do
+ service_stopped "${x}" && continue
+
+ if ibefore -t "${mydep}" "${x}" >/dev/null && \
+ [[ -L "${svcdir}/softscripts.new/${x}" ]]
+ then
+ # Service do not 'need' $mydep, and is still present in
+ # new runlevel ...
+ continue
+ fi
+
+ wait_service "${x}"
+
+ if ! service_stopped "${x}" ; then
+ # If we are halting the system, try and get it down as
+ # clean as possible, else do not stop our service if
+ # a dependent service did not stop.
+ if needsme -t "${mydep}" "${x}" >/dev/null && \
+ [[ ${SOFTLEVEL} != "reboot" && ${SOFTLEVEL} != "shutdown" ]]
+ then
+ retval=1
+ fi
+ break
+ fi
+ done
+ (( index++ ))
+ done
+
+ IN_BACKGROUND="${ib_save}"
+
+ if [[ ${retval} -ne 0 ]] ; then
+ eerror "ERROR: problems stopping dependent services."
+ eerror " \"${myservice}\" is still up."
+ else
+ # Stop einfo/ebegin/eend from working as parallel messes us up
+ [[ ${RC_PARALLEL_STARTUP} == "yes" ]] && RC_QUIET_STDOUT="yes"
+ # Now that deps are stopped, stop our service
+ ( stop )
+ retval=$?
+
+ # If a service has been marked inactive, exit now as something
+ # may attempt to start it again later
+ service_inactive "${myservice}" && return 0
+ fi
+
+ if [[ ${retval} -ne 0 ]] ; then
+ # Did we fail to stop? create symlink to stop multible attempts at
+ # runlevel change. Note this is only used at runlevel change ...
+ if is_runlevel_stop ; then
+ mark_service_failed "${myservice}"
+ fi
+
+ # If we are halting the system, do it as cleanly as possible
+ if [[ ${SOFTLEVEL} != "reboot" && ${SOFTLEVEL} != "shutdown" ]] ; then
+ if ${was_inactive} ; then
+ mark_service_inactive "${myservice}"
+ else
+ mark_service_started "${myservice}"
+ fi
+ fi
+
+ service_message "eerror" "FAILED to stop service ${myservice}!"
+ else
+ # If we're stopped from a daemon that sets ${IN_BACKGROUND} such as
+ # wpa_monitor when we mark as inactive instead of taking the down
+ if ${IN_BACKGROUND:-false} ; then
+ mark_service_inactive "${myservice}"
+ else
+ mark_service_stopped "${myservice}"
+ fi
+ service_message "Stopped service ${myservice}"
+ fi
+
+ return "${retval}"
+}
+
+svc_start() {
+ local retval=0
+ local startfail="no"
+ local x=
+ local y=
+ local myserv=
+ local ordservice=
+
+ if service_starting "${myservice}" ; then
+ ewarn "WARNING: \"${myservice}\" is already starting."
+ return 0
+ elif service_stopping "${myservice}" ; then
+ ewarn "WARNING: please wait for \"${myservice}\" to stop first."
+ return 0
+ elif service_inactive "${myservice}" ; then
+ if [[ ${IN_BACKGROUND} != "true" ]] ; then
+ ewarn "WARNING: \"${myservice}\" has already been started."
+ return 0
+ fi
+ elif service_started "${myservice}" ; then
+ ewarn "WARNING: \"${myservice}\" has already been started."
+ return 0
+ fi
+
+ # Do not try to start if i have done so already on runlevel change
+ if is_runlevel_start && service_failed "${myservice}" ; then
+ return 1
+ fi
+
+ mark_service_starting "${myservice}"
+ service_message "Starting service ${myservice}"
+
+ # On rc change, start all services "before $myservice" first
+ if is_runlevel_start ; then
+ startupservices="$(ineed "${myservice}") \
+ $(valid_iuse "${myservice}") \
+ $(valid_iafter "${myservice}")"
+ else
+ startupservices="$(ineed "${myservice}") \
+ $(valid_iuse "${myservice}")"
+ fi
+
+ # Start dependencies, if any
+ for x in ${startupservices} ; do
+ if [[ ${x} == "net" ]] && [[ ${NETSERVICE} != "yes" ]] && ! is_net_up ; then
+ local netservices="$(dolisting "/etc/runlevels/${BOOTLEVEL}/net.*") \
+ $(dolisting "/etc/runlevels/${mylevel}/net.*")"
+
+ for y in ${netservices} ; do
+ mynetservice=${y##*/}
+ if service_stopped "${mynetservice}" ; then
+ start_service "${mynetservice}"
+ fi
+ done
+ elif [[ ${x} != "net" ]] ; then
+ if service_stopped "${x}"; then
+ start_service "${x}"
+ fi
+ fi
+ done
+
+ # wait for dependencies to finish
+ for x in ${startupservices} ; do
+ if [ "${x}" = "net" -a "${NETSERVICE}" != "yes" ] ; then
+ local netservices="$(dolisting "/etc/runlevels/${BOOTLEVEL}/net.*") \
+ $(dolisting "/etc/runlevels/${mylevel}/net.*")"
+
+ for y in ${netservices} ; do
+ mynetservice="${y##*/}"
+
+ wait_service "${mynetservice}"
+
+ if ! service_started "${mynetservice}" ; then
+ # A 'need' dependency is critical for startup
+ if ineed -t "${myservice}" "${x}" >/dev/null ; then
+ # Only worry about a net.* service if we do not have one
+ # up and running already, or if RC_NET_STRICT_CHECKING
+ # is set ....
+ if ! is_net_up ; then
+ startfail="yes"
+ fi
+ fi
+ fi
+ done
+ elif [ "${x}" != "net" ] ; then
+ wait_service "${x}"
+ if ! service_started "${x}" ; then
+ # A 'need' dependacy is critical for startup
+ if ineed -t "${myservice}" "${x}" >/dev/null ; then
+ startfail="yes"
+ fi
+ fi
+ fi
+ done
+
+ if [[ ${startfail} == "yes" ]] ; then
+ eerror "ERROR: Problem starting needed services."
+ eerror " \"${myservice}\" was not started."
+ retval=1
+ elif broken "${myservice}" ; then
+ eerror "ERROR: Some services needed are missing. Run"
+ eerror " './${myservice} broken' for a list of those"
+ eerror " services. \"${myservice}\" was not started."
+ retval=1
+ else
+ (
+ exit() {
+ RC_QUIET_STDOUT="no"
+ eerror "DO NOT USE EXIT IN INIT.D SCRIPTS"
+ eerror "This IS a bug, please fix your broken init.d"
+ unset -f exit
+ exit $@
+ }
+ # Stop einfo/ebegin/eend from working as parallel messes us up
+ [[ ${RC_PARALLEL_STARTUP} == "yes" ]] && RC_QUIET_STDOUT="yes"
+ start
+ )
+ retval=$?
+
+ # If a service has been marked inactive, exit now as something
+ # may attempt to start it again later
+ service_inactive "${myservice}" && return 1
+ fi
+
+ if [[ ${retval} != 0 ]]; then
+ is_runlevel_start && mark_service_failed "${myservice}"
+
+ # Remove link if service didn't start; but only if we're not booting
+ # If we're booting, we need to continue and do our best to get the
+ # system up.
+ if [[ ${SOFTLEVEL} != "${BOOTLEVEL}" ]]; then
+ mark_service_stopped "${myservice}"
+ fi
+
+ service_message "eerror" "FAILED to start service ${myservice}!"
+ else
+ mark_service_started "${myservice}"
+
+ service_message "Service ${myservice} started OK"
+ fi
+
+ return "${retval}"
+}
+
+svc_restart() {
+ if ! service_stopped "${myservice}" ; then
+ svc_stop || return "$?"
+ fi
+ svc_start || return "$?"
+}
+
+svc_status() {
+ # The basic idea here is to have some sort of consistent
+ # output in the status() function which scripts can use
+ # as an generic means to detect status. Any other output
+ # should thus be formatted in the custom status() function
+ # to work with the printed " * status: foo".
+ local efunc="" state=""
+
+ # If we are effectively root, check to see if required daemons are running
+ # and update our status accordingly
+ [[ ${EUID} == 0 ]] && update_service_status "${myservice}"
+
+ if service_starting "${myservice}" ; then
+ efunc="einfo"
+ state="starting"
+ elif service_inactive "${myservice}" ; then
+ efunc="ewarn"
+ state="inactive"
+ elif service_started "${myservice}" ; then
+ efunc="einfo"
+ state="started"
+ elif service_stopping "${myservice}" ; then
+ efunc="eerror"
+ state="stopping"
+ else
+ efunc="eerror"
+ state="stopped"
+ fi
+ [[ ${RC_QUIET_STDOUT} != "yes" ]] \
+ && ${efunc} "status: ${state}"
+
+ status
+ [[ ${efunc} != "eerror" ]]
+}
+
+rcscript_errors=$(bash -n "${myscript}" 2>&1) || {
+ [[ -n ${rcscript_errors} ]] && echo "${rcscript_errors}" >&2
+ eerror "ERROR: \"${myscript}\" has syntax errors in it; aborting ..."
+ exit 1
+}
+
+# set *after* wrap_rcscript, else we get duplicates.
+opts="start stop restart"
+
+source "${myscript}"
+
+# make sure whe have valid $opts
+if [[ -z ${opts} ]] ; then
+ opts="start stop restart"
+fi
+
+svc_homegrown() {
+ local arg=$1
+ local x=
+
+ # Walk through the list of available options, looking for the
+ # requested one.
+ for x in ${opts} ; do
+ if [[ ${x} == ${arg} ]] ; then
+ if typeset -F "${x}" &>/dev/null ; then
+ # Run the homegrown function
+ "${x}"
+
+ return $?
+ fi
+ fi
+ done
+
+ # If we're here, then the function wasn't in $opts.
+ eerror "ERROR: wrong args. ( "${arg}" / $* )"
+ # Do not quote this either ...
+ usage ${opts}
+ exit 1
+}
+
+shift
+if [[ $# -lt 1 ]] ; then
+ eerror "ERROR: not enough args."
+ usage ${opts}
+ exit 1
+fi
+for arg in $* ; do
+ case "${arg}" in
+ --quiet)
+ RC_QUIET_STDOUT="yes"
+ ;;
+# We check this in functions.sh ...
+# --nocolor)
+# RC_NOCOLOR="yes"
+# ;;
+ --verbose)
+ RC_VERBOSE="yes"
+ ;;
+ esac
+done
+for arg in $* ; do
+ case "${arg}" in
+ stop)
+ svc_stop
+ ;;
+ start)
+ svc_start
+ ;;
+ needsme|ineed|usesme|iuse|broken)
+ trace_dependencies "-${arg}"
+ ;;
+ status)
+ svc_status
+ ;;
+ zap)
+ if ! service_stopped "${myservice}" ; then
+ einfo "Manually resetting ${myservice} to stopped state."
+ mark_service_stopped "${myservice}"
+ fi
+ ;;
+ restart)
+ svcrestart="yes"
+
+ # Create a snapshot of started services
+ rm -rf "${svcdir}/snapshot/$$"
+ mkdir -p "${svcdir}/snapshot/$$"
+ cp -a "${svcdir}"/started/* "${svcdir}/snapshot/$$/"
+
+ # Simple way to try and detect if the service use svc_{start,stop}
+ # to restart if it have a custom restart() funtion.
+ if [[ -n $(egrep '^[[:space:]]*restart[[:space:]]*()' "/etc/init.d/${myservice}") ]] ; then
+ if [[ -z $(egrep 'svc_stop' "/etc/init.d/${myservice}") ]] || \
+ [[ -z $(egrep 'svc_start' "/etc/init.d/${myservice}") ]]
+ then
+ echo
+ ewarn "Please use 'svc_stop; svc_start' and not 'stop; start' to"
+ ewarn "restart the service in its custom 'restart()' function."
+ ewarn "Run ${myservice} without arguments for more info."
+ echo
+ svc_restart
+ else
+ restart
+ fi
+ else
+ restart
+ fi
+
+ # Restart dependencies as well
+ if service_started "${myservice}" ; then
+ for x in $(trace_dependencies \
+ $(dolisting "${svcdir}/snapshot/$$/") ) ; do
+ if service_stopped "${x##*/}" ; then
+ start_service "${x##*/}"
+ fi
+ done
+ fi
+
+ # Wait for any services that may still be running ...
+ [[ ${RC_PARALLEL_STARTUP} == "yes" ]] && wait
+
+ rm -rf "${svcdir}/snapshot/$$"
+ svcrestart="no"
+ ;;
+ pause)
+ svcpause="yes"
+ svc_stop
+ svcpause="no"
+ ;;
+ --quiet|--nocolor)
+ ;;
+ *)
+ # Allow for homegrown functions
+ svc_homegrown ${arg}
+ ;;
+ esac
+done
+
+
+# vim:ts=4
diff --git a/src/.cvsignore b/src/.cvsignore
new file mode 100644
index 0000000..a26e40b
--- /dev/null
+++ b/src/.cvsignore
@@ -0,0 +1,5 @@
+.cvsignore
+*.o
+consoletype
+runscript
+start-stop-daemon
diff --git a/src/Makefile b/src/Makefile
new file mode 100644
index 0000000..252dea0
--- /dev/null
+++ b/src/Makefile
@@ -0,0 +1,49 @@
+# Copyright 1999-2005 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Header$
+
+CC = gcc
+LD = gcc
+
+CFLAGS = -Wall -O2
+DESTDIR =
+LIBDIR = lib
+
+BIN_TARGETS =
+SBIN_TARGETS = consoletype runscript start-stop-daemon
+SYS_WHITELIST = env_whitelist
+
+TARGET = $(BIN_TARGETS) $(SBIN_TARGETS)
+
+OS = Linux
+ifeq ($(OS),Linux)
+LDFLAGS_RS = -ldl
+endif
+ifeq ($(OS),BSD)
+LDFLAGS_SSD = -lkvm
+endif
+
+override CFLAGS += -DLIBDIR=\"$(LIBDIR)\"
+
+all: $(TARGET)
+
+rs-misc.o: core/misc.c
+ $(CC) $(CFLAGS) -c -o $@ $^
+
+runscript: runscript.o rs-misc.o
+ $(LD) $(LDFLAGS) -o $@ $^ $(LDFLAGS_RS)
+
+start-stop-daemon: start-stop-daemon.c
+ $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LDFLAGS_SSD)
+
+install: $(TARGET)
+ install -m 0755 -d $(DESTDIR)/bin
+ install -m 0755 -d $(DESTDIR)/sbin
+# install -m 0755 $(BIN_TARGETS) $(DESTDIR)/bin
+ install -m 0755 $(SBIN_TARGETS) $(DESTDIR)/sbin
+ install -m 0755 -d $(DESTDIR)/$(LIBDIR)/rcscripts/conf.d
+ install -m 0644 $(SYS_WHITELIST) $(DESTDIR)/$(LIBDIR)/rcscripts/conf.d
+
+clean:
+ rm -f $(TARGET)
+ rm -f *.o *~
diff --git a/src/awk/cachedepends.awk b/src/awk/cachedepends.awk
new file mode 100644
index 0000000..017e231
--- /dev/null
+++ b/src/awk/cachedepends.awk
@@ -0,0 +1,210 @@
+# Copyright 1999-2004 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Header$
+
+function print_start() {
+ print "source /sbin/functions.sh" >> TMPCACHE
+ print "" >> TMPCACHE
+ print "need() {" >> TMPCACHE
+ print " echo \"NEED $*\"; return 0" >> TMPCACHE
+ print "}" >> TMPCACHE
+ print "" >> TMPCACHE
+ print "use() {" >> TMPCACHE
+ print " echo \"USE $*\"; return 0" >> TMPCACHE
+ print "}" >> TMPCACHE
+ print "" >> TMPCACHE
+ print "before() {" >> TMPCACHE
+ print " echo \"BEFORE $*\"; return 0" >> TMPCACHE
+ print "}" >> TMPCACHE
+ print "" >> TMPCACHE
+ print "after() {" >> TMPCACHE
+ print " echo \"AFTER $*\"; return 0" >> TMPCACHE
+ print "}" >> TMPCACHE
+ print "" >> TMPCACHE
+ print "provide() {" >> TMPCACHE
+ print " echo \"PROVIDE $*\"; return 0" >> TMPCACHE
+ print "}" >> TMPCACHE
+ print "" >> TMPCACHE
+}
+
+function print_header1(mtime) {
+ print "#*** " MYFILENAME " ***" >> TMPCACHE
+ print "" >> TMPCACHE
+ print "myservice=\"" MYFILENAME "\"" >> TMPCACHE
+ print "myservice=\"${myservice##*/}\"" >> TMPCACHE
+ print "echo \"RCSCRIPT ${myservice}\"" >> TMPCACHE
+ print "" >> TMPCACHE
+ print "echo \"MTIME " mtime "\"" >> TMPCACHE
+ print "" >> TMPCACHE
+}
+
+function print_header2(mtime) {
+ print "(" >> TMPCACHE
+ print " # Get settings for rc-script ..." >> TMPCACHE
+ print "" >> TMPCACHE
+ print " [ -e \"/etc/conf.d/${myservice}\" ] && source \"/etc/conf.d/${myservice}\"" >> TMPCACHE
+ print "" >> TMPCACHE
+ print " [ -e /etc/conf.d/net ] && \\" >> TMPCACHE
+ print " [ \"${myservice%%.*}\" = \"net\" ] && \\" >> TMPCACHE
+ print " [ \"${myservice##*.}\" != \"${myservice}\" ] && source /etc/conf.d/net" >> TMPCACHE
+ print "" >> TMPCACHE
+ print " [ -e /etc/rc.conf ] && source /etc/rc.conf" >> TMPCACHE
+ print "" >> TMPCACHE
+ print " depend() {" >> TMPCACHE
+ print " return 0" >> TMPCACHE
+ print " }" >> TMPCACHE
+ print "" >> TMPCACHE
+}
+
+function print_end() {
+ print "" >> TMPCACHE
+ print " depend" >> TMPCACHE
+ print ")" >> TMPCACHE
+ print "" >> TMPCACHE
+}
+
+BEGIN {
+
+ extension("/lib/rcscripts/filefuncs.so", "dlload")
+
+ # Get our environment variables
+ SVCDIR = ENVIRON["SVCDIR"]
+ if (SVCDIR == "") {
+ eerror("Could not get SVCDIR!")
+ exit 1
+ }
+
+ # Since this could be called more than once simultaneously, use a
+ # temporary cache and rename when finished. See bug 47111
+ ("/bin/mktemp "SVCDIR"/depcache.XXXXXXX") | getline TMPCACHE
+ if (TMPCACHE == "") {
+ eerror("Failed to create temporary cache!")
+ exit 1
+ }
+
+ pipe = "ls /etc/init.d/*"
+ while ((pipe | getline tmpstring) > 0)
+ scripts = scripts " " tmpstring
+ close(pipe)
+
+ split(scripts, TMPRCSCRIPTS)
+
+ # Make sure that its a file we are working with,
+ # and do not process scripts, source or backup files.
+ for (x in TMPRCSCRIPTS)
+ if (((isfile(TMPRCSCRIPTS[x])) || (islink(TMPRCSCRIPTS[x]))) &&
+ (TMPRCSCRIPTS[x] !~ /((\.(c|bak))|\~)$/)) {
+
+ RCCOUNT++
+
+ RCSCRIPTS[RCCOUNT] = TMPRCSCRIPTS[x]
+ }
+
+ if (RCCOUNT == 0) {
+ eerror("No scripts to process!")
+ dosystem("rm -f "TMPCACHE)
+ exit 1
+ }
+
+ print_start()
+
+ for (count = 1;count <= RCCOUNT;count++) {
+
+ MYFNR = 1
+ MYFILENAME = RCSCRIPTS[count]
+ STAT_DATA[1] = 1
+
+ while (((getline < (RCSCRIPTS[count])) > 0) && (!NEXTFILE)) {
+
+ # If line start with a '#' and is the first line
+ if (($0 ~ /^[[:space:]]*#/) && (MYFNR == 1)) {
+
+ # Remove any spaces and tabs
+ gsub(/[[:space:]]+/, "")
+
+ if ($0 == "#!/sbin/runscript") {
+
+ if (RCSCRIPTS[count] ~ /\.sh$/) {
+
+ ewarn(RCSCRIPTS[count] " is invalid (should not end with '.sh')")
+ NEXTFILE = 1
+ continue
+ }
+
+ if (stat(MYFILENAME, STAT_DATA) != 0)
+ ewarn("Could not stat \"" MYFILENAME "\"")
+
+ ISRCSCRIPT = 1
+ print_header1(STAT_DATA["mtime"])
+ } else {
+
+ NEXTFILE = 1
+ continue
+ }
+ }
+
+ # Filter out comments and only process if its a rcscript
+ if (($0 !~ /^[[:space:]]*#/) && (ISRCSCRIPT)) {
+
+ # If line contain 'depend()', set GOTDEPEND to 1
+ if ($0 ~ /depend[[:space:]]*\(\)/) {
+
+ GOTDEPEND = 1
+
+ print_header2()
+ print " # Actual depend() function ..." >> TMPCACHE
+ }
+
+ # We have the depend function...
+ if (GOTDEPEND) {
+
+ # Basic theory is that COUNT will be 0 when we
+ # have matching '{' and '}'
+ COUNT += gsub(/{/, "{")
+ COUNT -= gsub(/}/, "}")
+
+ # This is just to verify that we have started with
+ # the body of depend()
+ SBCOUNT += gsub(/{/, "{")
+
+ # Make sure depend() contain something, else bash
+ # errors out (empty function).
+ if ((SBCOUNT > 0) && (COUNT == 0))
+ print " \treturn 0" >> TMPCACHE
+
+ # Print the depend() function
+ print " " $0 >> TMPCACHE
+
+ # If COUNT=0, and SBCOUNT>0, it means we have read
+ # all matching '{' and '}' for depend(), so stop.
+ if ((SBCOUNT > 0) && (COUNT == 0)) {
+
+ GOTDEPEND = 0
+ COUNT = 0
+ SBCOUNT = 0
+ ISRCSCRIPT = 0
+
+ print_end()
+
+ NEXTFILE = 1
+ continue
+ }
+ }
+ }
+
+ MYFNR++
+ }
+
+ close(RCSCRIPTS[count])
+
+ NEXTFILE = 0
+
+ }
+
+
+ assert(dosystem("rm -f "SVCDIR"/depcache"), "system(rm -f "SVCDIR"/depcache)")
+ assert(dosystem("mv "TMPCACHE" "SVCDIR"/depcache"), "system(mv "TMPCACHE" "SVCDIR"/depcache)")
+}
+
+
+# vim:ts=4
diff --git a/src/awk/functions.awk b/src/awk/functions.awk
new file mode 100644
index 0000000..825daed
--- /dev/null
+++ b/src/awk/functions.awk
@@ -0,0 +1,156 @@
+# Copyright 1999-2004 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Header$
+
+function einfo(string)
+{
+ printf(" %s %s%s", "\033[32;01m*\033[0m", string, "\n")
+}
+
+function ewarn(string)
+{
+ printf(" %s %s%s" , "\033[33;01m*\033[0m", string, "\n")
+}
+
+function eerror(string)
+{
+ printf(" %s %s%s" , "\033[31;01m*\033[0m", string, "\n")
+}
+
+function isfile(pathname, x, ret, data)
+{
+ ret = 0
+ data[1] = 1
+
+ if (pathname == "")
+ return 0
+
+ ret = stat(pathname, data)
+ if (ret < 0)
+ return 0
+
+ for (i in data) {
+ if (i == "type")
+ if (data[i] == "file")
+ ret = 1
+ }
+
+ return ret
+}
+
+function islink(pathname, x, ret, data)
+{
+ ret = 0
+ data[1] = 1
+
+ if (pathname == "")
+ return 0
+
+ ret = stat(pathname, data)
+ if (ret < 0)
+ return 0
+
+ for (i in data) {
+ if (i == "type")
+ if (data[i] == "symlink")
+ ret = 1
+ }
+
+ return ret
+}
+
+function isdir(pathname, x, ret, data)
+{
+ ret = 0
+ data[1] = 1
+
+ if (pathname == "")
+ return 0
+
+ ret = stat(pathname, data)
+ if (ret < 0)
+ return 0
+
+ for (i in data) {
+ if (i == "type")
+ if (data[i] == "directory")
+ ret = 1
+ }
+
+ return ret
+}
+
+function mktree(pathname, mode, x, max, ret, data, pathnodes, tmppath)
+{
+ ret = 0
+ data[1] = 1
+ pathnodes[1] = 1
+
+ if (pathname == "")
+ return 0
+
+ if (pathname ~ /^\//)
+ tmppath = ""
+ else
+ tmppath = "."
+
+ split(pathname, pathnodes, "/")
+
+ for (x in pathnodes)
+ max++
+
+ # We cannot use 'for (x in pathnodes)', as gawk likes to
+ # sort the order indexes are processed ...
+ for (x = 1;x <= max;x++) {
+ if (pathnodes[x] == "")
+ continue
+
+ tmppath = tmppath "/" pathnodes[x]
+
+ ret = stat(tmppath, data)
+ if (ret < 0)
+ if (mkdir(tmppath, mode) < 0)
+ return 0
+ }
+
+ return 1
+}
+
+# symlink() wrapper that normalize return codes ...
+function dosymlink(oldpath, newpath, ret)
+{
+ ret = 0
+
+ ret = symlink(oldpath, newpath)
+ if (ret < 0)
+ return 0
+ else
+ return 1
+}
+
+# system() wrapper that normalize return codes ...
+function dosystem(command, ret)
+{
+ ret = 0
+
+ ret = system(command)
+ if (ret == 0)
+ return 1
+ else
+ return 0
+}
+
+# assert --- assert that a condition is true. Otherwise exit.
+# This is from the gawk info manual.
+function assert(condition, string)
+{
+ if (! condition) {
+ printf("%s:%d: assertion failed: %s\n",
+ FILENAME, FNR, string) > "/dev/stderr"
+ _assert_exit = 1
+ exit 1
+ }
+}
+
+
+# vim:ts=4
diff --git a/src/awk/gendepends.awk b/src/awk/gendepends.awk
new file mode 100644
index 0000000..c4073b4
--- /dev/null
+++ b/src/awk/gendepends.awk
@@ -0,0 +1,562 @@
+# Copyright 1999-2004 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Header$
+
+# bool check_service(name)
+#
+# Returns true if the service exists
+#
+function check_service(name, x)
+{
+ for (x = 1; x <= RC_NUMBER; x++) {
+ if (DEPTREE[x,NAME] == name)
+ return 1
+ }
+
+ return 0
+}
+
+# int get_service_index(name)
+#
+# Return the index position in DEPTREE
+#
+function get_service_index(name, x)
+{
+ for (x = 1; x <= RC_NUMBER; x++) {
+ if (DEPTREE[x,NAME] == name)
+ return x
+ }
+
+ return 0
+}
+
+# bool check_depend(service1, type, service2)
+#
+# Returns true if 'service1' need/use/is_before/is_after 'service2'
+#
+function check_depend(service1, type, service2, tmpsplit, x)
+{
+ if (check_service(service1)) {
+ x = get_service_index(service1)
+
+ if ((x,type) in DEPTREE) {
+ split(DEPTREE[x,type], tmpsplit)
+
+ for (x in tmpsplit) {
+ if (tmpsplit[x] == service2)
+ return 1
+ }
+ }
+ }
+
+ return 0
+}
+
+# bool check_resolved_depend(service1, type, service2)
+#
+# Returns true if 'service1' need/use/is_before/is_after 'service2'
+# It should only be trusted if we do the BEFORE/AFTER loop
+#
+function check_resolved_depend(service1, type, service2, tmpsplit, x)
+{
+ if (check_service(service1)) {
+ x = get_service_index(service1)
+
+ if ((x,type) in RESOLVED_DEPTREE) {
+ split(RESOLVED_DEPTREE[x,type], tmpsplit)
+
+ for (x in tmpsplit) {
+ if (tmpsplit[x] == service2)
+ return 1
+ }
+ }
+ }
+
+ return 0
+}
+
+# string get_resolved_depends(service, type)
+#
+# Return the services that depend of type on service
+# It should only be trusted if we do the BEFORE/AFTER loop
+#
+function get_resolved_depends(service, type, x)
+{
+ if (check_service(service)) {
+ x = get_service_index(service)
+
+ if ((x,type) in RESOLVED_DEPTREE)
+ return RESOLVED_DEPTREE[x,type]
+ }
+
+ return ""
+}
+
+# bool check_recursive_depend(service1, service2, bool checkuse)
+#
+# Return true if service1 USE/NEED a service that NEEDS/USES
+# service2
+# It should only be trusted if we do the BEFORE/AFTER loop
+#
+function check_recursive_depend(service1, service2, checkuse, x, deps, deplist)
+{
+ deps = get_resolved_depends(service2, NEEDME)
+ if (deps != "") {
+ split(deps, deplist)
+ for (x in deplist)
+ if (check_resolved_depend(service1, NEED, deplist[x]))
+ return 1
+ if (checkuse && check_resolved_depend(service1, USE, deplist[x]))
+ return 1
+ }
+
+ if (!checkuse)
+ return 0
+
+ deps = get_resolved_depends(service2, USEME)
+ if (deps != "") {
+ split(deps, deplist)
+ for (x in deplist)
+ if (check_resolved_depend(service1, NEED, deplist[x]) ||
+ check_resolved_depend(service1, USE, deplist[x])) {
+ return 1
+ }
+ }
+
+ return 0
+}
+
+# bool add_deptree_item(rcnumber, type, item)
+#
+# Add an item(s) 'item' to the DEPTREE array at index [rcnumber,type]
+#
+function add_deptree_item(rcnumber, type, item)
+{
+ if (DEPTREE[rcnumber,type] != "")
+ DEPTREE[rcnumber,type] = DEPTREE[rcnumber,type] " " item
+ else
+ DEPTREE[rcnumber,type] = item
+
+ return 1
+}
+
+# bool add_provide(service, provide)
+#
+# Add a name of a virtual service ('provide') that 'service' Provides
+#
+function add_provide(service, provide)
+{
+ # We cannot have a service Provide a virtual service with the same name as
+ # an existing service ...
+ if (check_service(provide)) {
+ eerror(" Cannot add provide '" provide "', as a service with the same name exists!")
+ return 0
+ }
+
+ if (check_provide(provide)) {
+ # We cannot have more than one service Providing a virtual ...
+ ewarn(" Service '" get_provide(provide) "' already provided by '" provide "'!;")
+ ewarn(" Not adding service '" service "'...")
+ # Do not fail here as we do have a service that resolves the virtual
+ } else {
+ # Sanity check
+ if (check_service(service)) {
+ PROVIDE_LIST[provide] = service
+ } else {
+ eerror(" Cannot add provide '" provide "', as service '" service "' does not exist!")
+ return 0
+ }
+ }
+
+ return 1
+}
+
+# string get_provide(provide)
+#
+# Return the name of the service that Provides 'provide'
+#
+function get_provide(provide)
+{
+ if (provide in PROVIDE_LIST)
+ if (check_service(PROVIDE_LIST[provide]))
+ return PROVIDE_LIST[provide]
+
+ return ""
+}
+
+# bool check_provide(provide)
+#
+# Return true if any service Provides the virtual service with name 'provide'
+#
+function check_provide(provide)
+{
+ if (provide in PROVIDE_LIST)
+ return 1
+
+ return 0
+}
+
+# bool add_db_entry(service, type, item)
+#
+# Add a entry to RESOLVED_DEPTREE
+#
+function add_db_entry(service, type, item, x, sindex, tmpsplit)
+{
+ if (!check_service(service)) {
+ eerror(" Service '" service "' do not exist!")
+ return 0
+ }
+
+ sindex = get_service_index(service)
+
+ if ((sindex,type) in RESOLVED_DEPTREE) {
+ split(RESOLVED_DEPTREE[sindex,type], tmpsplit)
+
+ for (x in tmpsplit) {
+ if (tmpsplit[x] == item)
+ return 1
+ }
+
+ RESOLVED_DEPTREE[sindex,type] = RESOLVED_DEPTREE[sindex,type] " " item
+ } else {
+ RESOLVED_DEPTREE[sindex,type] = item
+ }
+
+ return 1
+}
+
+# void resolve_depend(type, service, deplist)
+#
+# Verify a depend entry(s) 'deplist' for service 'service' of type 'type',
+# and then add it to the DB.
+#
+function resolve_depend(type, service, deplist, x, deparray)
+{
+ if ((type == "") || (service == "") || (deplist == ""))
+ return
+
+ # If there are no existing service 'service', resolve possible
+ # provided services
+ if (!check_service(service)) {
+ if (check_provide(service))
+ service = get_provide(service)
+ else
+ return
+ }
+
+ split(deplist, deparray)
+
+ for (x in deparray) {
+
+ # If there are no existing service 'deparray[x]', resolve possible
+ # provided services
+ if (!check_service(deparray[x])) {
+ if (check_provide(deparray[x]))
+ deparray[x] = get_provide(deparray[x])
+ }
+
+ # Handle 'need', as it is the only dependency type that
+ # should handle invalid database entries currently.
+ if (!check_service(deparray[x])) {
+
+ if (((type == NEED) || (type == NEEDME)) && (deparray[x] != "net")) {
+
+ ewarn(" Can't find service '" deparray[x] "' needed by '" service "'; continuing...")
+
+ # service is broken due to missing 'need' dependencies
+ add_db_entry(service, BROKEN, deparray[x])
+
+ continue
+ }
+ else if (deparray[x] != "net")
+ continue
+ }
+
+ # Ugly bug ... if a service depends on itself, it creates
+ # a 'mini fork bomb' effect, and breaks things...
+ if (deparray[x] == service) {
+
+ # Dont work too well with the '*' use and need
+ if ((type != BEFORE) && (type != AFTER))
+ ewarn(" Service '" deparray[x] "' can't depend on itself; continuing...")
+
+ continue
+ }
+
+ # Currently only these depend/order types are supported
+ if ((type == NEED) || (type == USE) || (type == BEFORE) || (type == AFTER)) {
+
+ if (type == BEFORE) {
+ # NEED and USE override BEFORE (service BEFORE deparray[x])
+ if (check_resolved_depend(service, NEED, deparray[x]) ||
+ check_resolved_depend(service, USE, deparray[x]))
+ continue
+
+ if (check_recursive_depend(service, deparray[x], 1)) {
+ ewarn(" Service '" service "' should be BEFORE service '" deparray[x] "', but one of")
+ ewarn(" the services '" service "' depends on, depends on '" deparray[x] "'!")
+ continue
+ }
+ }
+
+ if (type == AFTER) {
+ # NEED and USE override AFTER (service AFTER deparray[x])
+ if (check_resolved_depend(deparray[x], NEED, service) ||
+ check_resolved_depend(deparray[x], USE, service))
+ continue
+
+ if (check_recursive_depend(deparray[x], service, 1)) {
+ ewarn(" Service '" service "' should be AFTER service '" deparray[x] "', but one of")
+ ewarn(" the services '" deparray[x] "' depends on, depends on '" service "'!")
+ continue
+ }
+ }
+
+ # NEED override USE (service USE deparray[x])
+ if (type == USE && (check_resolved_depend(deparray[x], NEED, service) ||
+ check_recursive_depend(deparray[x], service, 0))) {
+ ewarn(" Service '" deparray[x] "' NEED service '" service "', but service '" service "' wants")
+ ewarn(" to USE service '" deparray[x] "'!")
+ continue
+ }
+
+ # We do not want to add circular depends ...
+ if (check_depend(deparray[x], type, service) ||
+ check_resolved_depend(deparray[x], type, service)) {
+
+ if ((service,deparray[x],type) in CIRCULAR_DEPEND)
+ continue
+
+ if ((deparray[x],service,type) in CIRCULAR_DEPEND)
+ continue
+
+ ewarn(" Services '" service "' and '" deparray[x] "' have circular")
+ ewarn(" dependency of type '" TYPE_NAMES[type] "'; continuing...")
+
+ CIRCULAR_DEPEND[service,deparray[x],type] = "yes"
+
+ continue
+ }
+
+ add_db_entry(service, type, deparray[x])
+
+ # Reverse mapping
+ if (type == NEED)
+ add_db_entry(deparray[x], NEEDME, service)
+
+ # Reverse mapping
+ if (type == USE)
+ add_db_entry(deparray[x], USEME, service)
+
+ # Reverse mapping
+ if (type == BEFORE)
+ add_db_entry(deparray[x], AFTER, service)
+
+ # Reverse mapping
+ if (type == AFTER)
+ add_db_entry(deparray[x], BEFORE, service)
+ }
+ }
+}
+
+BEGIN {
+ NAME = 1
+ RC_NUMBER = 0
+
+ # Types ...
+ NEED = 2
+ NEEDME = 3
+ USE = 4
+ USEME = 5
+ BEFORE = 6
+ AFTER = 7
+ BROKEN = 8
+ MTIME = 9
+ PROVIDE = 10 # Not part of Types as when finally printed ...
+ TYPES_MIN = 2
+ TYPES_MAX = 9
+
+ TYPE_NAMES[NEED] = "ineed"
+ TYPE_NAMES[NEEDME] = "needsme"
+ TYPE_NAMES[USE] = "iuse"
+ TYPE_NAMES[USEME] = "usesme"
+ TYPE_NAMES[BEFORE] = "ibefore"
+ TYPE_NAMES[AFTER] = "iafter"
+ TYPE_NAMES[BROKEN] = "broken"
+ TYPE_NAMES[PROVIDE] = "provide"
+ TYPE_NAMES[MTIME] = "mtime"
+
+ # Get our environment variables
+ SVCDIR = ENVIRON["SVCDIR"]
+ if (SVCDIR == "") {
+ eerror("Could not get SVCDIR!")
+ exit 1
+ }
+
+ # There we do not really use yet
+ DEPTYPES = ENVIRON["DEPTYPES"]
+ ORDTYPES = ENVIRON["ORDTYPES"]
+
+ #CACHEDTREE = SVCDIR "/deptree"
+ ORIGCACHEDTREE = SVCDIR "/deptree"
+
+ # Since this could be called more than once simultaneously, use a
+ # temporary cache and rename when finished. See bug 48303
+ ("/bin/mktemp "SVCDIR"/treecache.XXXXXXX") | getline CACHEDTREE
+ if (CACHEDTREE == "") {
+ eerror("Failed to create temporary cache!")
+ exit 1
+ }
+
+ # We remove it below now only before moving the temp one over.
+ #assert(dosystem("rm -f " CACHEDTREE ), "system(rm -f " CACHEDTREE ")")
+}
+
+{
+ #
+ # Build our DEPTREE array
+ #
+
+ if ($1 == "RCSCRIPT") {
+ RC_NUMBER++
+
+ DEPTREE[RC_NUMBER,NAME] = $2
+ }
+
+ if ($1 == "NEED") {
+ sub(/NEED[[:space:]]*/, "")
+
+ if ($0 != "")
+ add_deptree_item(RC_NUMBER, NEED, $0)
+ }
+
+ if ($1 == "USE") {
+ sub(/USE[[:space:]]*/, "")
+
+ if ($0 != "")
+ add_deptree_item(RC_NUMBER, USE, $0)
+ }
+
+ if ($1 == "BEFORE") {
+ sub(/BEFORE[[:space:]]*/, "")
+
+ if ($0 != "")
+ add_deptree_item(RC_NUMBER, BEFORE, $0)
+ }
+
+ if ($1 == "AFTER") {
+ sub(/AFTER[[:space:]]*/, "")
+
+ if ($0 != "")
+ add_deptree_item(RC_NUMBER, AFTER, $0)
+ }
+
+ if ($1 == "PROVIDE") {
+ sub(/PROVIDE[[:space:]]*/, "")
+
+ if ($0 != "")
+ add_deptree_item(RC_NUMBER, PROVIDE, $0)
+ }
+
+ if ($1 == "MTIME") {
+ sub(/MTIME[[:space:]]*/, "")
+
+ if ($0 != "") {
+ # We add this directly to RESOLVED_DEPTREE
+ add_db_entry(DEPTREE[RC_NUMBER,NAME], MTIME, $0)
+ }
+ }
+}
+
+END {
+ # Add the 'net' service if it do not exist ...
+ if (!check_service("net")) {
+ RC_NUMBER++
+ DEPTREE[RC_NUMBER,NAME] = "net"
+ }
+
+ # Calculate all the provides ...
+ for (x = 1;x <= RC_NUMBER;x++) {
+ if ((x,PROVIDE) in DEPTREE)
+ add_provide(DEPTREE[x,NAME], DEPTREE[x,PROVIDE])
+ }
+
+ # Now do NEED
+ for (x = 1;x <= RC_NUMBER;x++) {
+ if ((x,NEED) in DEPTREE)
+ resolve_depend(NEED, DEPTREE[x,NAME], DEPTREE[x,NEED])
+ }
+
+ # Now do USE
+ for (x = 1;x <= RC_NUMBER;x++) {
+ if ((x,USE) in DEPTREE)
+ resolve_depend(USE, DEPTREE[x,NAME], DEPTREE[x,USE])
+ }
+
+ # Now do BEFORE and AFTER
+ for (x = 1;x <= RC_NUMBER;x++) {
+
+ if ((x,BEFORE) in DEPTREE)
+ resolve_depend(BEFORE, DEPTREE[x,NAME], DEPTREE[x,BEFORE])
+
+ if ((x,AFTER) in DEPTREE)
+ resolve_depend(AFTER, DEPTREE[x,NAME], DEPTREE[x,AFTER])
+ }
+
+ for (x = TYPES_MIN; x <= TYPES_MAX; x++)
+ print "rc_type_" TYPE_NAMES[x] "=" x >> (CACHEDTREE)
+ print "rc_index_scale=" (TYPES_MAX + 1) >> (CACHEDTREE)
+ print "" >> (CACHEDTREE)
+ print "declare -a RC_DEPEND_TREE" >> (CACHEDTREE)
+ print "" >> (CACHEDTREE)
+ print "RC_DEPEND_TREE[0]=" RC_NUMBER >> (CACHEDTREE)
+ print "" >> (CACHEDTREE)
+
+ # Generate the resolved CACHEDTREE
+ #
+ # NOTE: We used to use depinfo_<scriptname>() function to resolve our
+ # rc_<type> variables, but that do not scale when the names of
+ # the scripts include invalid bash variable characters (+,.,etc).
+ #
+ for (x = 1;x <= RC_NUMBER;x++) {
+
+ print "RC_DEPEND_TREE[" (x * (TYPES_MAX + 1)) "]=\"" DEPTREE[x,NAME] "\"" >> (CACHEDTREE)
+
+ for (y = TYPES_MIN; y <= TYPES_MAX; y++) {
+
+ tmpname = "RC_DEPEND_TREE[" (x * (TYPES_MAX + 1)) "+" y "]"
+
+ if ((x,y) in RESOLVED_DEPTREE) {
+
+ split(RESOLVED_DEPTREE[x,y], tmparray1)
+ count = asort(tmparray1, tmparray2)
+ tmpstr = tmparray2[1]
+
+ for (i = 2;i <= count;i++)
+ tmpstr = tmpstr " " tmparray2[i]
+
+ print tmpname "=\"" tmpstr "\"" >> (CACHEDTREE)
+ } else
+ print tmpname "=" >> (CACHEDTREE)
+ }
+
+ print "" >> (CACHEDTREE)
+ }
+
+ # Do not export these, as we want them local
+ print "RC_GOT_DEPTREE_INFO=\"yes\"" >> (CACHEDTREE)
+ print "" >> (CACHEDTREE)
+
+ if (check_provide("logger"))
+ print "LOGGER_SERVICE=\"" get_provide("logger") "\"" >> (CACHEDTREE)
+ else
+ print "LOGGER_SERVICE=" >> (CACHEDTREE)
+
+ close(CACHEDTREE)
+
+ assert(dosystem("rm -f "ORIGCACHEDTREE), "system(rm -f "ORIGCACHEDTREE")")
+ assert(dosystem("mv "CACHEDTREE" "ORIGCACHEDTREE), "system(mv "CACHEDTREE" "ORIGCACHEDTREE")")
+}
+
+
+# vim:ts=4
diff --git a/src/awk/genenviron.awk b/src/awk/genenviron.awk
new file mode 100644
index 0000000..087bed3
--- /dev/null
+++ b/src/awk/genenviron.awk
@@ -0,0 +1,179 @@
+# Copyright 1999-2004 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Header$
+
+BEGIN {
+
+ extension("/lib/rcscripts/filefuncs.so", "dlload")
+
+ # Get our environment variables
+ SVCDIR = ENVIRON["SVCDIR"]
+ if (SVCDIR == "") {
+ eerror("Could not get SVCDIR!")
+ exit 1
+ }
+
+ pipe = "ls -1 /etc/env.d/."
+ while ((pipe | getline tmpstring) > 0)
+ scripts = scripts " /etc/env.d/" tmpstring
+ close(pipe)
+
+ split(scripts, TMPENVFILES)
+
+ # Make sure that its a file we are working with,
+ # and do not process scripts, source or backup files.
+ # NOTE: do not use 'for (x in TMPENVFILES)', as gawk
+ # have this notion that it should mess with the
+ # order it list things then ....
+ for (x = 1;;x++) {
+
+ if (x in TMPENVFILES) {
+
+ if ((isfile(TMPENVFILES[x])) &&
+ (TMPENVFILES[x] !~ /((\.(sh|c|bak))|\~)$/)) {
+
+ ENVCOUNT++
+
+ ENVFILES[ENVCOUNT] = TMPENVFILES[x]
+ }
+ } else
+ break
+ }
+
+ if (ENVCOUNT == 0) {
+
+ eerror("No files to process!")
+ exit 1
+ }
+
+ ENVCACHE = SVCDIR "/envcache"
+ SHPROFILE = "/etc/profile.env"
+ CSHPROFILE = "/etc/csh.env"
+
+ # SPECIALS are treated differently. For each env.d file, the variables are
+ # appended seperated with a ':'. If not in specials, for each env.d file,
+ # the variable are just set to the new value.
+ tmpspecials="KDEDIRS:PATH:CLASSPATH:LDPATH:MANPATH:INFOPATH:ROOTPATH:CONFIG_PROTECT:CONFIG_PROTECT_MASK:PRELINK_PATH:PRELINK_PATH_MASK:PYTHONPATH:ADA_INCLUDE_PATH:ADA_OBJECTS_PATH"
+ split(tmpspecials, SPECIALS, ":")
+
+ unlink(ENVCACHE)
+
+ for (count = 1;count <= ENVCOUNT;count++) {
+
+ while ((getline < (ENVFILES[count])) > 0) {
+
+ # Filter out comments
+ if ($0 !~ /^[[:space:]]*#/) {
+
+ split($0, envnode, "=")
+
+ if (envnode[2] == "")
+ continue
+
+ if ($0 == "")
+ continue
+
+ # LDPATH should not be in environment
+ if (envnode[1] == "LDPATH")
+ continue
+
+ # In bash there should be no space between the variable name and
+ # the '=' ...
+ if (envnode[1] ~ /[^[:space:]]*[[:space:]]+$/)
+ continue
+
+ # strip variable name and '=' from data
+ sub("^[[:space:]]*" envnode[1] "[[:space:]]*=", "")
+ # strip all '"' and '\''
+ gsub(/\"/, "")
+ gsub(/\'/, "")
+ # strip leading and trailing spaces
+ gsub(/^[[:space:]]*/, "")
+ gsub(/[[:space:]]*$/, "")
+
+ if (envnode[1] in ENVTREE) {
+
+ DOSPECIAL = 0
+
+ for (x in SPECIALS) {
+
+ # Is this a special variable ?
+ if (envnode[1] == SPECIALS[x])
+ DOSPECIAL = 1
+ }
+
+ if (DOSPECIAL) {
+ split(ENVTREE[envnode[1]], tmpstr, ":")
+
+ # Check that we do not add dups ...
+ NODUPS = 1
+ for (x in tmpstr)
+ if (tmpstr[x] == $0)
+ NODUPS = 0
+
+ if (NODUPS)
+ # Once again, "CONFIG_PROTECT" and "CONFIG_PROTECT_MASK"
+ # are handled differently ...
+ if ((envnode[1] == "CONFIG_PROTECT") || (envnode[1] == "CONFIG_PROTECT_MASK"))
+ ENVTREE[envnode[1]] = ENVTREE[envnode[1]] " " $0
+ else
+ ENVTREE[envnode[1]] = ENVTREE[envnode[1]] ":" $0
+ } else
+ ENVTREE[envnode[1]] = $0
+ } else
+ ENVTREE[envnode[1]] = $0
+ }
+ }
+
+ close(ENVFILES[count])
+ }
+
+ for (x in ENVTREE)
+ print "export " x "=\"" ENVTREE[x] "\"" >> (ENVCACHE)
+
+ for (x in ENVTREE) {
+
+ # Print this a second time to make sure all variables
+ # are expanded ..
+ print "export " x "=\"" ENVTREE[x] "\"" >> (ENVCACHE)
+ print "echo \"" x "=${" x "}\"" >> (ENVCACHE)
+ }
+
+ close (ENVCACHE)
+
+ unlink(SHPROFILE)
+ unlink(CSHPROFILE)
+
+ # Add warning header for SHPROFILE
+ print "# THIS FILE IS AUTOMATICALLY GENERATED BY env-update." > (SHPROFILE)
+ print "# DO NOT EDIT THIS FILE. CHANGES TO STARTUP PROFILES" >> (SHPROFILE)
+ print "# GO INTO /etc/profile NOT /etc/profile.env" >> (SHPROFILE)
+ print "" >> (SHPROFILE)
+
+ # Add warning header for CSHPROFILE
+ print "# THIS FILE IS AUTOMATICALLY GENERATED BY env-update." > (CSHPROFILE)
+ print "# DO NOT EDIT THIS FILE. CHANGES TO STARTUP PROFILES" >> (CSHPROFILE)
+ print "# GO INTO /etc/csh.cshrc NOT /etc/csh.env" >> (CSHPROFILE)
+ print "" >> (CSHPROFILE)
+
+
+ pipe = "bash " ENVCACHE
+ while ((pipe | getline) > 0) {
+
+ sub(/=/, "='")
+ sub(/$/, "'")
+
+ print "export " $0 >> (SHPROFILE)
+
+ sub(/=/, " ")
+
+ print "setenv " $0 >> (CSHPROFILE)
+ }
+
+ close(pipe)
+ close(SHPROFILE)
+ close(CSHPROFILE)
+}
+
+
+# vim:ts=4
diff --git a/src/consoletype.c b/src/consoletype.c
new file mode 100644
index 0000000..5e5c45c
--- /dev/null
+++ b/src/consoletype.c
@@ -0,0 +1,38 @@
+/*
+ * consoletype.c
+ * simple app to figure out whether the current terminal
+ * is serial, console (vt), or remote (pty).
+ *
+ * Copyright 1999-2004 Gentoo Foundation
+ * Distributed under the terms of the GNU General Public License v2
+ * $Header$
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include "headers.h"
+
+int main(int argc, char *argv[])
+{
+ unsigned char twelve = 12;
+ int maj;
+ struct stat sb;
+
+ fstat(0, &sb);
+ maj = major(sb.st_rdev);
+ if (maj != 3 && (maj < 136 || maj > 143)) {
+#if defined(__linux__)
+ if (ioctl (0, TIOCLINUX, &twelve) < 0) {
+ printf("serial\n");
+ return 1;
+ }
+#endif
+ printf("vt\n");
+ return 0;
+ } else {
+ printf("pty\n");
+ return 2;
+ }
+}
diff --git a/src/core/.cvsignore b/src/core/.cvsignore
new file mode 100644
index 0000000..8ef5509
--- /dev/null
+++ b/src/core/.cvsignore
@@ -0,0 +1,3 @@
+*.o
+depscan
+test-regex
diff --git a/src/core/ChangeLog b/src/core/ChangeLog
new file mode 100644
index 0000000..0ac157a
--- /dev/null
+++ b/src/core/ChangeLog
@@ -0,0 +1,163 @@
+# ChangeLog for Gentoo System Intialization core utilities.
+# Copyright 1999-2005 Gentoo Foundation; Distributed under the GPLv2
+# $Header$
+
+26 Jul 2005 Martin Schlemmer <azarah@gentoo.org>
+
+ * depend.c
+ * depend.h
+ * parse.c
+ * parse.h: Remove the "parallel" stuff, as we do not use it anymore.
+
+15 Apr 2005 Martin Schlemmer <azarah@gentoo.org>
+
+ * parse.c: Do not source rc.conf for every script - once is enough.
+
+14 Apr 2005 Martin Schlemmer <azarah@gentoo.org>
+
+ * depscan.c: Update error comments for stage name changes some time
+ back.
+
+ * parse.c,
+ * parse.h: Do not try to extract the depend() function from the
+ scripts, but rather source the whole file. This way we can detect
+ syntax errors, etc. Little bit slower, but not much.
+
+07 Apr 2005 Martin Schlemmer <azarah@gentoo.org>
+
+ * test-regex.c: Add two more tests.
+
+ * depscan.c
+ * misc.c
+ * misc.h: Add basic klibc support. I need to add a mkstemp
+ implementation to get it done properly.
+
+12 Mar 2005 Martin Schlemmer <azarah@gentoo.org>
+
+ * Makefile: Also remove the tests in the clean target.
+
+11 Mar 2005 Martin Schlemmer <azarah@gentoo.org>
+
+ * test-regex.c: Add a few strings and patterns. Enable tests to
+ specify if they should fail or pass.
+
+10 Mar 2005 Martin Schlemmer <azarah@gentoo.org>
+
+ * test-regex.c: New file
+ * Makefile: Add check target to compile and run tests
+ * simple-regex.c (__match_wildcard): Get recursion right so that we
+ do not match a wildcard _and_ inc data_p if there are still other
+ wildcards (?, *) that could match.
+
+ * Makefile
+ * depend.c
+ * simple-regex.c: Override the debug/warning CFLAGS. Kill a few
+ warnings.
+
+23 Feb 2005 Martin Schlemmer <azarah@gentoo.org>
+
+ * misc.c: Fix memory leak in mktree().
+
+18 Feb 2005 Martin Schlemmer <azarah@gentoo.org>
+
+ * Makefile: Add -fbounds-checking support when DEBUG=1.
+
+ * misc.h: Scrap STRING_LIST_FOR_EACH_SAFE() and recode from scratch
+ fixing invalid pointer operations.
+
+ * misc.c: Remove the last strlen() from strndup() that caused an
+ overrun.
+
+17 Feb 2005 Martin Schlemmer <azarah@gentoo.org>:
+
+ * misc.c: Fix overrun in strndup(), thanks to report from
+ Ned Ludd <solar@gentoo.org>.
+
+ * debug.h
+ * misc.h
+ * simple-regex.c: Print debug/errors to stderr, patch from
+ Ned Ludd <solar@gentoo.org>.
+
+ * debug.h: Replace invalid EXIT_FAILSTATUS with EXIT_FAILURE.
+
+ * parse.c: Modify parse_print_body() to be more ash friendly.
+ Suggestions from Ned Ludd <solar@gentoo.org>.
+
+ * debug.h: Remove the 'errno = ESPIPE' in DBG_MSG() for now, as it
+ seems to be fixed by the select() changes.
+
+ * parse.c: Disable write select() for now, as it is not needed.
+
+ * depscan.c: Only print EINFO msg if we actually update the cache.
+
+ * parse.c: Rename write_output() macro to PRINT_TO_BUFFER().
+
+ * parse.c
+ * parse.h: Rewrote large parts of generate_stage[12]() and their
+ machanics to use select() when writing to the pipes. This fixes a
+ buffering issue where too much data would cause the write to be
+ truncated, and the read pipe would then wait forever.
+
+ * misc.c: Fix gbasename() to compile under gcc-2.95.3.
+
+ * parse.c: Switch to stdio based io for reading pipes in
+ generate_stage2().
+
+ * misc.c
+ * misc.h: Add gbasename() that is similar to GNU's basename().
+
+ * parse.c: Use gbasename() instead of POSIX version.
+
+ * parse.c: Fix write_legacy_stage3() to quote the mtime in its output.
+
+ * misc.c
+ * parse.c: Change type of length from int to size_t to avoid warnings
+ when compiled for darwin.
+
+ * misc.c
+ misc.h: Add strndup() instead of relying on glibc's implementation
+ (should fix some issues on bsd and darwin).
+
+ * depend.c
+ * simple-regex.c: Do not define _GNU_SOURCE, but rather use our
+ strndup() from misc.h.
+
+ * parse.c: Do not define _GNU_SOURCE, but rather use our strndup() from
+ misc.h. Also change all usage of basename() to conform to POSIX, and
+ do not use the GNU variants.
+
+16 Feb 2005; Martin Schlemmer <azarah@gentoo.org>:
+
+ * depscan.c: Add uid check and quit if user is not root.
+
+ * depend.c
+ * depend.h: Change service_type_names declaration in depend.h to extern
+ and move the definition to depend.c to avoid warnings.
+
+ * README: New file.
+
+ * depscan.c: Add delete_var_dirs() to delete volatile directories in
+ svcdir. Change 'char *' declarations for create_directory() and
+ create_var_dirs() to 'const char*'.
+
+ * misc.h
+ * misc.c: Add rmtree() function. Fix ls_dir() not to include '.' and
+ '..' in its listing. Fix segfault in ls_dir() if the file list is
+ empty.
+
+ Add Header tags to all source files and Makefile.
+
+ * debug.h: perror() set errno to ESPIPE for some reason - restore errno
+ after calling perror().
+
+ * depscan.c: Add code to create svcdir and co if missing.
+
+ * misc.c: Add missing '\n' to DBG_MSG in mktree().
+
+ * misc.h: Add a comment about strcatpaths() allocating the memory needed.
+
+ Initial checkin. Still rough in some parts, but should be 100% similar
+ in output to depscan.sh and co.
+
+
+# vim:expandtab
diff --git a/src/core/Makefile b/src/core/Makefile
new file mode 100644
index 0000000..1e9c050
--- /dev/null
+++ b/src/core/Makefile
@@ -0,0 +1,81 @@
+# Copyright (C) 2004,2005 Martin Schlemmer <azarah@nosferatu.za.org>
+#
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+# $Header$
+
+CC = gcc
+override CFLAGS += -Wall
+EXTRA_CFLAGS = -DLEGACY_DEPSCAN
+STRIP = strip
+
+DEPSCAN = depscan
+TEST_REGEX = test-regex
+
+TARGETS = $(DEPSCAN)
+CHECK_TARGETS = $(TEST_REGEX)
+
+all: $(TARGETS)
+
+.ALL: all
+
+OBJS = \
+ parse.o \
+ depend.o \
+ simple-regex.o \
+ misc.o
+
+HEADERS = \
+ parse.h \
+ depend.h \
+ simple-regex.h \
+ misc.h \
+ debug.h
+
+
+# cc-option (from linux kernel sources)
+# Usage: cflags-y += $(call gcc-option, -march=winchip-c6, -march=i586)
+
+cc-option = $(shell if $(CC) $(1) -S -o /dev/null -xc /dev/null \
+ > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi ;)
+
+
+ifeq ($(DEBUG),1)
+ override CFLAGS += -ggdb3
+ override CFLAGS += $(call cc-option, -fbounds-checking, -pipe)
+ EXTRA_CFLAGS += -DRC_DEBUG
+endif
+
+$(DEPSCAN): $(OBJS) $(DEPSCAN).o
+ $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -o $@ $^
+
+$(TEST_REGEX): $(TEST_REGEX).o simple-regex.o
+ $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -o $@ $^
+
+$(OBJS): $(HEADERS)
+
+.c.o:
+ $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<
+
+check: $(CHECK_TARGETS)
+ @for x in $^; do \
+ ./$${x} || exit 1; \
+ done
+
+strip: $(TARGETS)
+ $(STRIP) -s --remove-section=.note --remove-section=.comment $(TARGETS)
+
+clean:
+ rm -f *.o $(TARGETS) $(CHECK_TARGETS)
diff --git a/src/core/README b/src/core/README
new file mode 100644
index 0000000..31f4ef5
--- /dev/null
+++ b/src/core/README
@@ -0,0 +1,15 @@
+* Introduction
+==============
+
+This is still fairly alpha code, although I have tried to regression test it
+fairly extensively. After many requests, I have added it to CVS, so please
+do understand that it still is work in progress, although it should duplicate
+depscan.sh in functionality.
+
+To all those that might dabble with this, please send comments or fixes my
+way, and if I can ask very nicely, please do not commit before checking with
+me first, as I do have some large changes and additions still in the pipeline.
+
+
+Martin Schlemmer
+<azarah@gentoo.org>
diff --git a/src/core/debug.h b/src/core/debug.h
new file mode 100644
index 0000000..bc40038
--- /dev/null
+++ b/src/core/debug.h
@@ -0,0 +1,85 @@
+/*
+ * debug.h
+ *
+ * Simle debugging/logging macro's and functions.
+ *
+ * Copyright (C) 2004,2005 Martin Schlemmer <azarah@nosferatu.za.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Header$
+ */
+
+#ifndef _DEBUG_H
+#define _DEBUG_H
+
+#if defined(RC_DEBUG)
+# define DBG_MSG(_format, _arg...) \
+ do { \
+ int old_errno = errno; \
+ fprintf(stderr, "DEBUG(1): in %s, function %s(), line %i:\n", __FILE__, \
+ __FUNCTION__, __LINE__); \
+ fprintf(stderr, "DEBUG(2): " _format, ## _arg); \
+ errno = old_errno; \
+ if (0 != errno) { \
+ perror("DEBUG(3)"); \
+ /* perror() for some reason sets errno to ESPIPE */ \
+ errno = old_errno; \
+ } \
+ } while (0)
+#else
+# define DBG_MSG(_format, _arg...) \
+ do { \
+ int old_errno = errno; \
+ /* Bit of a hack, as how we do things tend to cause seek
+ * errors when reading the parent/child pipes */ \
+ /* if ((0 != errno) && (ESPIPE != errno)) { */ \
+ if (0 != errno) { \
+ fprintf(stderr, "DEBUG(1): in %s, function %s(), line %i:\n", \
+ __FILE__, __FUNCTION__, __LINE__); \
+ fprintf(stderr, "DEBUG(2): " _format, ## _arg); \
+ errno = old_errno; \
+ perror("DEBUG(3)"); \
+ /* perror() for some reason sets errno to ESPIPE */ \
+ errno = old_errno; \
+ } \
+ } while (0)
+#endif
+
+#define FATAL_ERROR() \
+ do { \
+ int old_errno = errno; \
+ fprintf(stderr, "ERROR: file '%s', function '%s', line %i.\n", \
+ __FILE__, __FUNCTION__, __LINE__); \
+ errno = old_errno; \
+ if (0 != errno) \
+ perror("ERROR"); \
+ exit(EXIT_FAILURE); \
+ } while (0)
+
+#define NEG_FATAL_ERROR(_x) \
+ do { \
+ if (-1 == _x) \
+ FATAL_ERROR(); \
+ } while (0)
+
+#define NULL_FATAL_ERROR(_x) \
+ do { \
+ if (NULL == _x) \
+ FATAL_ERROR(); \
+ } while (0)
+
+#endif /* _DEBUG_H */
+
diff --git a/src/core/depend.c b/src/core/depend.c
new file mode 100644
index 0000000..8fc6056
--- /dev/null
+++ b/src/core/depend.c
@@ -0,0 +1,532 @@
+/*
+ * depend.c
+ *
+ * Dependancy engine for Gentoo style rc-scripts.
+ *
+ * Copyright (C) 2004,2005 Martin Schlemmer <azarah@nosferatu.za.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Header$
+ */
+
+#include <errno.h>
+#include <string.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "debug.h"
+#include "depend.h"
+#include "list.h"
+#include "misc.h"
+
+LIST_HEAD(service_info_list);
+
+/* Names for service types (service_type_t) in depend.h.
+ * Note that this should sync with service_type_t */
+char *service_type_names[] = {
+ "NEED",
+ "NEED_ME",
+ "USE",
+ "USE_ME",
+ "BEFORE",
+ "AFTER",
+ "BROKEN",
+ "PROVIDE",
+ NULL
+};
+
+int __service_resolve_dependency(char *servicename, char *dependency, service_type_t type);
+
+service_info_t *service_get_info(char *servicename) {
+ service_info_t *info;
+
+ if ((NULL == servicename) || (0 == strlen(servicename))) {
+ DBG_MSG("Invalid argument passed!\n");
+ return NULL;
+ }
+
+ list_for_each_entry(info, &service_info_list, node) {
+ if (NULL != info->name)
+ if (0 == strcmp(info->name, servicename))
+ return info;
+ }
+
+ /* We use this to check if a service exists, so rather do not
+ * add debugging, otherwise it is very noisy! */
+ /* DBG_MSG("Invalid service name '%s'!\n", servicename); */
+
+ return NULL;
+}
+
+int service_add(char *servicename) {
+ service_info_t *info;
+ service_info_t *sorted;
+ int count;
+
+ if ((NULL == servicename) || (0 == strlen(servicename))) {
+ DBG_MSG("Invalid argument passed!\n");
+ return -1;
+ }
+
+ info = service_get_info(servicename);
+ if (NULL == info) {
+ DBG_MSG("Adding service '%s'.\n", servicename);
+
+ info = malloc(sizeof(service_info_t));
+ if (NULL == info) {
+ DBG_MSG("Failed to allocate service_info_t!\n");
+ return -1;
+ }
+
+ info->name = strndup(servicename, strlen(servicename));
+ if (NULL == info->name) {
+ DBG_MSG("Failed to allocate buffer!\n");
+ free(info);
+ return -1;
+ }
+
+ for (count = 0; count < ALL_SERVICE_TYPE_T; count++)
+ info->depend_info[count] = NULL;
+ info->provide = NULL;
+
+ /* We want to keep the list sorted */
+ list_for_each_entry(sorted, &service_info_list, node) {
+ if (strcmp(sorted->name, servicename) > 0) {
+ break;
+ }
+ }
+
+ list_add_tail(&info->node, &sorted->node);
+
+ return 0;
+ } else {
+ DBG_MSG("Tried to add duplicate service '%s'!\n", servicename);
+ }
+
+ return -1;
+}
+
+int service_is_dependency(char *servicename, char *dependency, service_type_t type) {
+ service_info_t *info;
+ char *service;
+ int count = 0;
+
+ if ((NULL == servicename) || (0 == strlen(servicename)) ||
+ (NULL == dependency) || (0 == strlen(dependency))) {
+ DBG_MSG("Invalid argument passed!\n");
+ return -1;
+ }
+
+ info = service_get_info(servicename);
+ if (NULL != info) {
+ STRING_LIST_FOR_EACH(info->depend_info[type], service, count) {
+ if (0 == strcmp(dependency, service))
+ return 0;
+ }
+ } else {
+ DBG_MSG("Invalid service name '%s'!\n", servicename);
+ }
+
+ return -1;
+}
+
+int service_add_dependency(char *servicename, char *dependency, service_type_t type) {
+ service_info_t *info;
+ char *tmp_buf;
+
+ if ((NULL == servicename) || (0 == strlen(servicename)) ||
+ (NULL == dependency) || (0 == strlen(dependency))) {
+ DBG_MSG("Invalid argument passed!\n");
+ return -1;
+ }
+
+ info = service_get_info(servicename);
+ if (NULL != info) {
+ /* Do not add duplicates */
+ if (-1 == service_is_dependency(servicename, dependency, type)) {
+ DBG_MSG("Adding dependency '%s' of service '%s', type '%s'.\n",
+ dependency, servicename, service_type_names[type]);
+
+ tmp_buf = strndup(dependency, strlen(dependency));
+ if (NULL == tmp_buf) {
+ DBG_MSG("Failed to allocate buffer!\n");
+ return -1;
+ }
+
+ STRING_LIST_ADD_SORT(info->depend_info[type], tmp_buf, error);
+ } else {
+ DBG_MSG("Duplicate dependency '%s' for service '%s', type '%s'!\n",
+ dependency, servicename,
+ service_type_names[type]);
+ /* Rather do not fail here, as we add a lot of doubles
+ * during resolving of dependencies */
+ }
+
+ return 0;
+ } else {
+ DBG_MSG("Invalid service name '%s'!\n", servicename);
+ }
+
+error:
+ return -1;
+}
+
+int service_del_dependency(char *servicename, char *dependency, service_type_t type) {
+ service_info_t *info;
+
+ if ((NULL == servicename) || (0 == strlen(servicename)) ||
+ (NULL == dependency) || (0 == strlen(dependency))) {
+ DBG_MSG("Invalid argument passed!\n");
+ return -1;
+ }
+
+ if (-1 == service_is_dependency(servicename, dependency, type)) {
+ DBG_MSG("Tried to remove invalid dependency '%s'!\n", dependency);
+ return -1;
+ }
+
+ info = service_get_info(servicename);
+ if (NULL != info) {
+ DBG_MSG("Removing dependency '%s' of service '%s', type '%s'.\n",
+ dependency , servicename, service_type_names[type]);
+
+ STRING_LIST_DEL(info->depend_info[type], dependency, error);
+ return 0;
+ } else {
+ DBG_MSG("Invalid service name '%s'!\n", servicename);
+ }
+
+error:
+ return -1;
+}
+
+service_info_t *service_get_virtual(char *virtual) {
+ service_info_t *info;
+
+ if ((NULL == virtual) || (0 == strlen(virtual))) {
+ DBG_MSG("Invalid argument passed!\n");
+ return NULL;
+ }
+
+ list_for_each_entry(info, &service_info_list, node) {
+ if (NULL != info->provide)
+ if (0 == strcmp(info->provide, virtual))
+ return info;
+ }
+
+ /* We use this to check if a virtual exists, so rather do not
+ * add debugging, otherwise it is very noisy! */
+ /* DBG_MSG("Invalid service name '%s'!\n", virtual); */
+
+ return NULL;
+}
+
+int service_add_virtual(char *servicename, char* virtual) {
+ service_info_t *info;
+
+ if ((NULL == servicename) || (0 == strlen(servicename)) ||
+ (NULL == virtual ) || (0 == strlen(virtual))) {
+ DBG_MSG("Invalid argument passed!\n");
+ return -1;
+ }
+
+ if (NULL != service_get_info(virtual)) {
+ EERROR(" Cannot add provide '%s', as a service with the same name exists!\n",
+ virtual);
+ /* Do not fail here as we do have a service that resolves
+ * the virtual */
+ }
+
+ info = service_get_virtual(virtual);
+ if (NULL != info) {
+ /* We cannot have more than one service Providing a virtual */
+ EWARN(" Service '%s' already provides '%s'!;\n",
+ info->name, virtual);
+ EWARN(" Not adding service '%s'...\n", servicename);
+ /* Do not fail here as we do have a service that resolves
+ * the virtual */
+ } else {
+ info = service_get_info(servicename);
+ if (NULL != info) {
+ DBG_MSG("Adding virtual '%s' of service '%s'.\n",
+ virtual, servicename);
+
+ info->provide = strndup(virtual, strlen(virtual));
+ if (NULL == info->provide) {
+ DBG_MSG("Failed to allocate buffer!\n");
+ return -1;
+ }
+ } else {
+ DBG_MSG("Invalid service name '%s'!\n", servicename);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+int service_set_mtime(char *servicename, time_t mtime) {
+ service_info_t *info;
+
+ if ((NULL == servicename) || (0 == strlen(servicename))) {
+ DBG_MSG("Invalid argument passed!\n");
+ return -1;
+ }
+
+ info = service_get_info(servicename);
+ if (NULL != info) {
+ DBG_MSG("Setting mtime '%li' of service '%s'.\n",
+ mtime, servicename);
+
+ info->mtime = mtime;
+
+ return 0;
+ } else {
+ DBG_MSG("Invalid service name '%s'!\n", servicename);
+ }
+
+ return -1;
+}
+
+int __service_resolve_dependency(char *servicename, char *dependency, service_type_t type) {
+ service_info_t *info;
+ int retval;
+
+ if ((NULL == servicename) || (0 == strlen(servicename)) ||
+ (NULL == dependency) || (0 == strlen(dependency))) {
+ DBG_MSG("Invalid argument passed!\n");
+ return -1;
+ }
+
+ info = service_get_info(servicename);
+ if (NULL == info) {
+ DBG_MSG("Invalid service name passed!\n");
+ return -1;
+ }
+
+ DBG_MSG("Checking dependency '%s' of service '%s', type '%s'.\n",
+ dependency, servicename, service_type_names[type]);
+
+ /* If there are no existing service 'dependency', try to resolve
+ * possible virtual services */
+ info = service_get_info(dependency);
+ if (NULL == info) {
+ info = service_get_virtual(dependency);
+ if (NULL != info) {
+ DBG_MSG("Virtual '%s' -> '%s' for service '%s', type '%s'.\n",
+ dependency, info->name, servicename,
+ service_type_names[type]);
+
+ retval = service_del_dependency(servicename, dependency, type);
+ if (-1 == retval) {
+ DBG_MSG("Failed to delete dependency!\n");
+ return -1;
+ }
+
+ /* Add the actual service name for the virtual */
+ dependency = info->name;
+ retval = service_add_dependency(servicename, dependency, type);
+ if (-1 == retval) {
+ DBG_MSG("Failed to add dependency!\n");
+ return -1;
+ }
+ }
+ }
+
+ /* Handle 'need', as it is the only dependency type that should
+ * handle invalid database entries currently. */
+ if (NULL == info) {
+ if ((type == NEED) || (type == NEED_ME)) {
+ EWARN(" Can't find service '%s' needed by '%s'; continuing...\n",
+ dependency, servicename);
+
+ retval = service_add_dependency(servicename, dependency, BROKEN);
+ if (-1 == retval) {
+ DBG_MSG("Failed to add dependency!\n");
+ return -1;
+ }
+
+ /* Delete invalid entry */
+ goto remove;
+ }
+
+ /* For the rest, if the dependency is not 'net', just silently
+ * die without error. Should not be needed as we add a 'net'
+ * service manually before we start, but you never know ... */
+ if (0 != strcmp(dependency, "net")) {
+ /* Delete invalid entry */
+ goto remove;
+ }
+ }
+
+ /* Ugly bug ... if a service depends on itself, it creates a
+ * 'mini fork bomb' effect, and breaks things horribly ... */
+ if (0 == strcmp(servicename, dependency)) {
+ /* Dont work too well with the '*' before and after */
+ if ((type != BEFORE) && (type != AFTER))
+ EWARN(" Service '%s' can't depend on itself; continuing...\n",
+ servicename);
+
+ /* Delete invalid entry */
+ goto remove;
+ }
+
+ /* Currently only these depend/order types are supported */
+ if ((type == NEED) || (type == USE) || (type == BEFORE) || (type == AFTER)) {
+ if (type == BEFORE) {
+ /* NEED and USE override BEFORE
+ * ('servicename' BEFORE 'dependency') */
+ if ((0 == service_is_dependency(servicename, dependency, NEED)) ||
+ (0 == service_is_dependency(servicename, dependency, USE))) {
+ /* Delete invalid entry */
+ goto remove;
+ }
+ }
+
+ if (type == AFTER) {
+ /* NEED and USE override AFTER
+ * ('servicename' AFTER 'dependency') */
+ if ((0 == service_is_dependency(dependency, servicename, NEED)) ||
+ (0 == service_is_dependency(dependency, servicename, USE))) {
+ /* Delete invalid entry */
+ goto remove;
+ }
+ }
+
+ /* We do not want to add circular dependencies ... */
+ if (0 == service_is_dependency(dependency, servicename, type)) {
+ EWARN(" Services '%s' and '%s' have circular\n",
+ servicename, dependency);
+ EWARN(" dependency of type '%s'; continuing...\n",
+ service_type_names[type]);
+
+ /* For now remove this dependency */
+ goto remove;
+ }
+
+ /* Reverse mapping */
+ if (type == NEED) {
+ retval = service_add_dependency(dependency, servicename, NEED_ME);
+ if (-1 == retval) {
+ DBG_MSG("Failed to add dependency!\n");
+ return -1;
+ }
+ }
+
+ /* Reverse mapping */
+ if (type == USE) {
+ retval = service_add_dependency(dependency, servicename, USE_ME);
+ if (-1 == retval) {
+ DBG_MSG("Failed to add dependency!\n");
+ return -1;
+ }
+ }
+
+ /* Reverse mapping */
+ if (type == BEFORE) {
+ retval = service_add_dependency(dependency, servicename, AFTER);
+ if (-1 == retval) {
+ DBG_MSG("Failed to add dependency!\n");
+ return -1;
+ }
+ }
+
+ /* Reverse mapping */
+ if (type == AFTER) {
+ retval = service_add_dependency(dependency, servicename, BEFORE);
+ if (-1 == retval) {
+ DBG_MSG("Failed to add dependency!\n");
+ return -1;
+ }
+ }
+ }
+
+ return 0;
+
+remove:
+ /* Delete invalid entry */
+ DBG_MSG("Removing invalid dependency '%s' of service '%s', type '%s'.\n",
+ dependency, servicename, service_type_names[type]);
+
+ retval = service_del_dependency(servicename, dependency, type);
+ if (-1 == retval) {
+ DBG_MSG("Failed to delete dependency!\n");
+ return -1;
+ }
+
+ /* Here we should not die with error */
+ return 0;
+}
+
+int service_resolve_dependencies(void) {
+ service_info_t *info;
+ char *service;
+ char *next = NULL;
+ int count;
+
+ /* Add our 'net' service */
+ if (NULL == service_get_info("net")) {
+ if (-1 == service_add("net"))
+ return -1;
+ }
+
+ /* Calculate all virtuals */
+ list_for_each_entry(info, &service_info_list, node) {
+ STRING_LIST_FOR_EACH_SAFE(info->depend_info[PROVIDE], service, next, count)
+ if (-1 == service_add_virtual(info->name, service)) {
+ DBG_MSG("Failed to add virtual!\n");
+ return -1;
+ }
+ }
+
+ /* Now do NEED, USE, BEFORE and AFTER */
+ list_for_each_entry(info, &service_info_list, node) {
+ STRING_LIST_FOR_EACH_SAFE(info->depend_info[NEED], service, next, count) {
+ if (-1 == __service_resolve_dependency(info->name, service, NEED)) {
+ DBG_MSG("Failed to resolve dependency!\n");
+ return -1;
+ }
+ }
+ }
+ list_for_each_entry(info, &service_info_list, node) {
+ STRING_LIST_FOR_EACH_SAFE(info->depend_info[USE], service, next, count) {
+ if (-1 == __service_resolve_dependency(info->name, service, USE)) {
+ DBG_MSG("Failed to resolve dependency!\n");
+ return -1;
+ }
+ }
+ }
+ list_for_each_entry(info, &service_info_list, node) {
+ STRING_LIST_FOR_EACH_SAFE(info->depend_info[BEFORE], service, next, count) {
+ if (-1 == __service_resolve_dependency(info->name, service, BEFORE)) {
+ DBG_MSG("Failed to resolve dependency!\n");
+ return -1;
+ }
+ }
+ }
+ list_for_each_entry(info, &service_info_list, node) {
+ STRING_LIST_FOR_EACH_SAFE(info->depend_info[AFTER], service, next, count) {
+ if (-1 == __service_resolve_dependency(info->name, service, AFTER)) {
+ DBG_MSG("Failed to resolve dependency!\n");
+ return -1;
+ }
+ }
+ }
+
+ return 0;
+}
+
diff --git a/src/core/depend.h b/src/core/depend.h
new file mode 100644
index 0000000..2a7ff77
--- /dev/null
+++ b/src/core/depend.h
@@ -0,0 +1,75 @@
+/*
+ * depend.h
+ *
+ * Dependancy engine for Gentoo style rc-scripts.
+ *
+ * Copyright (C) 2004,2005 Martin Schlemmer <azarah@nosferatu.za.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Header$
+ */
+
+#ifndef _DEPEND_H
+#define _DEPEND_H
+
+#include <sys/types.h>
+#include "list.h"
+
+/* Dependency types supported or still to be implemented */
+typedef enum {
+ NEED, /* All dependencies needed by specified service */
+ NEED_ME, /* All dependencies that need specified service */
+ USE, /* All dependencies used by specified service */
+ USE_ME, /* All dependencies that use specified service */
+ BEFORE, /* All services started before specified service */
+ AFTER, /* All services started after specified service */
+ BROKEN, /* All dependencies of type NEED missing for
+ specified service */
+ PROVIDE, /* All virtual services provided by specified service */
+ ALL_SERVICE_TYPE_T
+} service_type_t;
+
+/* Names for above service types (service_type_t).
+ * Note that this should sync with above service_type_t */
+extern char *service_type_names[];
+
+typedef struct {
+ struct list_head node;
+
+ char *name; /* Name of service */
+ char **depend_info[ALL_SERVICE_TYPE_T]; /* String lists for each service
+ type */
+ char *provide; /* Name of virtual service it
+ provides. This is only valid
+ after we resolving - thus after
+ service_resolve_dependencies() */
+ time_t mtime; /* Modification time of script */
+} service_info_t;
+
+struct list_head service_info_list;
+
+service_info_t *service_get_info(char *servicename);
+int service_add(char *servicename);
+int service_is_dependency(char *servicename, char *dependency, service_type_t type);
+int service_add_dependency(char *servicename, char *dependency, service_type_t type);
+int service_del_dependency(char *servicename, char *dependency, service_type_t type);
+service_info_t *service_get_virtual(char *virtual);
+int service_add_virtual(char *servicename, char* virtual);
+int service_set_mtime(char *servicename, time_t mtime);
+int service_resolve_dependencies(void);
+
+#endif /* _DEPEND_H */
+
diff --git a/src/core/depscan.c b/src/core/depscan.c
new file mode 100644
index 0000000..5030eb4
--- /dev/null
+++ b/src/core/depscan.c
@@ -0,0 +1,297 @@
+/*
+ * depscan.c
+ *
+ * Basic frontend for updating the dependency cache.
+ *
+ * Copyright (C) 2004,2005 Martin Schlemmer <azarah@nosferatu.za.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Header$
+ */
+
+#include <errno.h>
+#ifndef __KLIBC__
+# include <locale.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "debug.h"
+#include "depend.h"
+#include "misc.h"
+#include "parse.h"
+
+char* svcdir_subdirs[] = {
+ "softscripts",
+ "snapshot",
+ "options",
+ "started",
+ "starting",
+ "inactive",
+ "stopping",
+ NULL
+};
+
+char *svcdir_volatile_subdirs[] = {
+ "snapshot",
+ "broken",
+ NULL
+};
+
+int create_directory(const char *name);
+int create_var_dirs(const char *svcdir);
+int delete_var_dirs(const char *svcdir);
+
+int create_directory(const char *name) {
+ if ((NULL == name) || (0 == strlen(name))) {
+ DBG_MSG("Invalid argument passed!\n");
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Check if directory exist, and is not a symlink */
+ if (!is_dir(name, 0)) {
+ if (exists(name)) {
+ /* Remove it if not a directory */
+ if (-1 == unlink(name)) {
+ DBG_MSG("Failed to remove '%s'!\n", name);
+ return -1;
+ }
+ }
+ /* Now try to create the directory */
+ if (-1 == mktree(name, 0755)) {
+ DBG_MSG("Failed to create '%s'!\n", name);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+int create_var_dirs(const char *svcdir) {
+ char *tmp_path = NULL;
+ int i = 0;
+
+ if ((NULL == svcdir) || (0 == strlen(svcdir))) {
+ DBG_MSG("Invalid argument passed!\n");
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Check and create svcdir if needed */
+ if (-1 == create_directory(svcdir)) {
+ DBG_MSG("Failed to create '%s'!\n", svcdir);
+ return -1;
+ }
+
+ while (NULL != svcdir_subdirs[i]) {
+ tmp_path = strcatpaths(svcdir, svcdir_subdirs[i]);
+ if (NULL == tmp_path) {
+ DBG_MSG("Failed to allocate buffer!\n");
+ return -1;
+ }
+
+ /* Check and create all the subdirs if needed */
+ if (-1 == create_directory(tmp_path)) {
+ DBG_MSG("Failed to create '%s'!\n", tmp_path);
+ free(tmp_path);
+ return -1;
+ }
+
+ free(tmp_path);
+ i++;
+ }
+
+ return 0;
+}
+
+int delete_var_dirs(const char *svcdir) {
+ char *tmp_path = NULL;
+ int i = 0;
+
+ if ((NULL == svcdir) || (0 == strlen(svcdir))) {
+ DBG_MSG("Invalid argument passed!\n");
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Just quit if svcdir do not exist */
+ if (!exists(svcdir)) {
+ DBG_MSG("'%s' does not exist!\n", svcdir);
+ return 0;
+ }
+
+ while (NULL != svcdir_volatile_subdirs[i]) {
+ tmp_path = strcatpaths(svcdir, svcdir_volatile_subdirs[i]);
+ if (NULL == tmp_path) {
+ DBG_MSG("Failed to allocate buffer!\n");
+ return -1;
+ }
+
+ /* Skip the directory if it does not exist */
+ if (!exists(tmp_path))
+ goto _continue;
+
+ /* Check and delete all files and sub directories if needed */
+ if (-1 == rmtree(tmp_path)) {
+ DBG_MSG("Failed to delete '%s'!\n", tmp_path);
+ free(tmp_path);
+ return -1;
+ }
+
+_continue:
+ free(tmp_path);
+ i++;
+ }
+
+ return 0;
+}
+
+#if defined(LEGACY_DEPSCAN)
+
+int main() {
+ FILE *cachefile_fd = NULL;
+ char *data = NULL;
+ char *svcdir = NULL;
+ char *cachefile = NULL;
+ char *tmp_cachefile = NULL;
+ int tmp_cachefile_fd = 0;
+ int datasize = 0;
+
+ /* Make sure we do not run into locale issues */
+#ifndef __KLIBC__
+ setlocale (LC_ALL, "C");
+#endif
+
+ if (0 != getuid()) {
+ EERROR("Must be root!\n");
+ exit(EXIT_FAILURE);
+ }
+
+ svcdir = get_cnf_entry(RC_CONFD_FILE_NAME, SVCDIR_CONFIG_ENTRY);
+ if (NULL == svcdir) {
+ EERROR("Failed to get config entry '%s'!\n",
+ SVCDIR_CONFIG_ENTRY);
+ exit(EXIT_FAILURE);
+ }
+
+ /* Delete (if needed) volatile directories in svcdir */
+ if (-1 == delete_var_dirs(svcdir)) {
+ /* XXX: Not 100% accurate below message ... */
+ EERROR("Failed to delete '%s', %s", svcdir,
+ "or one of its sub directories!\n");
+ exit(EXIT_FAILURE);
+ }
+
+ /* Create all needed directories in svcdir */
+ if (-1 == create_var_dirs(svcdir)) {
+ EERROR("Failed to create '%s', %s", svcdir,
+ "or one of its sub directories!\n");
+ exit(EXIT_FAILURE);
+ }
+
+ cachefile = strcatpaths(svcdir, LEGACY_CACHE_FILE_NAME);
+ if (NULL == cachefile) {
+ DBG_MSG("Failed to allocate buffer!\n");
+ exit(EXIT_FAILURE);
+ }
+
+ tmp_cachefile = strcatpaths(cachefile, "XXXXXX");
+ if (NULL == tmp_cachefile) {
+ DBG_MSG("Failed to allocate buffer!\n");
+ exit(EXIT_FAILURE);
+ }
+ /* Replace the "/XXXXXX" with ".XXXXXX"
+ * Yes, I am lazy. */
+ tmp_cachefile[strlen(tmp_cachefile) - strlen(".XXXXXX")] = '.';
+
+ if (-1 == get_rcscripts()) {
+ EERROR("Failed to get rc-scripts list!\n");
+ exit(EXIT_FAILURE);
+ }
+
+ if (-1 == check_rcscripts_mtime(cachefile)) {
+ EINFO("Caching service dependencies ...\n");
+ DBG_MSG("Regenerating cache file '%s'.\n", cachefile);
+
+ datasize = generate_stage2(&data);
+ if (-1 == datasize) {
+ EERROR("Failed to generate stage2!\n");
+ exit(EXIT_FAILURE);
+ }
+
+ if (-1 == parse_cache(data, datasize)) {
+ EERROR("Failed to parse stage2 output!\n");
+ free(data);
+ exit(EXIT_FAILURE);
+ }
+
+#if 0
+ tmp_cachefile_fd = open("foo", O_CREAT | O_TRUNC | O_RDWR, 0600);
+ write(tmp_cachefile_fd, data, datasize);
+ close(tmp_cachefile_fd);
+#endif
+
+ free(data);
+
+ if (-1 == service_resolve_dependencies()) {
+ EERROR("Failed to resolve dependencies!\n");
+ exit(EXIT_FAILURE);
+ }
+
+#ifndef __KLIBC__
+ tmp_cachefile_fd = mkstemp(tmp_cachefile);
+#else
+ /* FIXME: Need to add a mkstemp implementation for klibc */
+ tmp_cachefile_fd = open(tmp_cachefile, O_CREAT | O_TRUNC | O_RDWR, 0600);
+#endif
+ if (-1 == tmp_cachefile_fd) {
+ EERROR("Could not open temporary file for writing!\n");
+ exit(EXIT_FAILURE);
+ }
+ cachefile_fd = fdopen(tmp_cachefile_fd, "w");
+ if (NULL == cachefile_fd) {
+ EERROR("Could not open temporary file for writing!\n");
+ exit(EXIT_FAILURE);
+ }
+
+ write_legacy_stage3(cachefile_fd);
+ fclose(cachefile_fd);
+
+ if ((-1 == unlink(cachefile)) && (exists(cachefile))) {
+ EERROR("Could not remove '%s'!\n", cachefile);
+ unlink(tmp_cachefile);
+ exit(EXIT_FAILURE);
+ }
+
+ if (-1 == rename(tmp_cachefile, cachefile)) {
+ EERROR("Could not move temporary file to '%s'!\n",
+ cachefile);
+ unlink(tmp_cachefile);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ exit(EXIT_SUCCESS);
+}
+
+#endif
+
diff --git a/src/core/list.h b/src/core/list.h
new file mode 100644
index 0000000..5c478bc
--- /dev/null
+++ b/src/core/list.h
@@ -0,0 +1,446 @@
+/*
+ * Copied from the Linux kernel source tree, version 2.6.0-test1.
+ *
+ * Licensed under the GPL v2 as per the whole kernel source tree.
+ *
+ * Ripped out the rcu stuff, as it's not needed.
+ *
+ * $Header$
+ */
+
+#ifndef _LINUX_LIST_H
+#define _LINUX_LIST_H
+
+//#include <linux/stddef.h>
+/**
+ * container_of - cast a member of a structure out to the containing structure
+ *
+ * @ptr: the pointer to the member.
+ * @type: the type of the container struct this is embedded in.
+ * @member: the name of the member within the struct.
+ *
+ */
+#define container_of(ptr, type, member) ({ \
+ const typeof( ((type *)0)->member ) *__mptr = (ptr); \
+ (type *)( (char *)__mptr - offsetof(type,member) );})
+
+//#include <linux/prefetch.h>
+static inline void prefetch(const void *x) {;}
+
+//#include <asm/system.h>
+
+/*
+ * These are non-NULL pointers that will result in page faults
+ * under normal circumstances, used to verify that nobody uses
+ * non-initialized list entries.
+ */
+#define LIST_POISON1 ((void *) 0x00100100)
+#define LIST_POISON2 ((void *) 0x00200200)
+
+/*
+ * Simple doubly linked list implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+struct list_head {
+ struct list_head *next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+ struct list_head name = LIST_HEAD_INIT(name)
+
+#define INIT_LIST_HEAD(ptr) do { \
+ (ptr)->next = (ptr); (ptr)->prev = (ptr); \
+} while (0)
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_add(struct list_head *new,
+ struct list_head *prev,
+ struct list_head *next)
+{
+ next->prev = new;
+ new->next = next;
+ new->prev = prev;
+ prev->next = new;
+}
+
+/**
+ * list_add - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+static inline void list_add(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head, head->next);
+}
+
+/**
+ * list_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static inline void list_add_tail(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head->prev, head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_del(struct list_head * prev, struct list_head * next)
+{
+ next->prev = prev;
+ prev->next = next;
+}
+
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty on entry does not return true after this, the entry is
+ * in an undefined state.
+ */
+static inline void list_del(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ entry->next = LIST_POISON1;
+ entry->prev = LIST_POISON2;
+}
+
+/**
+ * list_del_init - deletes entry from list and reinitialize it.
+ * @entry: the element to delete from the list.
+ */
+static inline void list_del_init(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ INIT_LIST_HEAD(entry);
+}
+
+/**
+ * list_move - delete from one list and add as another's head
+ * @list: the entry to move
+ * @head: the head that will precede our entry
+ */
+static inline void list_move(struct list_head *list, struct list_head *head)
+{
+ __list_del(list->prev, list->next);
+ list_add(list, head);
+}
+
+/**
+ * list_move_tail - delete from one list and add as another's tail
+ * @list: the entry to move
+ * @head: the head that will follow our entry
+ */
+static inline void list_move_tail(struct list_head *list,
+ struct list_head *head)
+{
+ __list_del(list->prev, list->next);
+ list_add_tail(list, head);
+}
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+static inline int list_empty(struct list_head *head)
+{
+ return head->next == head;
+}
+
+static inline void __list_splice(struct list_head *list,
+ struct list_head *head)
+{
+ struct list_head *first = list->next;
+ struct list_head *last = list->prev;
+ struct list_head *at = head->next;
+
+ first->prev = head;
+ head->next = first;
+
+ last->next = at;
+ at->prev = last;
+}
+
+/**
+ * list_splice - join two lists
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ */
+static inline void list_splice(struct list_head *list, struct list_head *head)
+{
+ if (!list_empty(list))
+ __list_splice(list, head);
+}
+
+/**
+ * list_splice_init - join two lists and reinitialise the emptied list.
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ *
+ * The list at @list is reinitialised
+ */
+static inline void list_splice_init(struct list_head *list,
+ struct list_head *head)
+{
+ if (!list_empty(list)) {
+ __list_splice(list, head);
+ INIT_LIST_HEAD(list);
+ }
+}
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr: the &struct list_head pointer.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) \
+ container_of(ptr, type, member)
+
+/**
+ * list_for_each - iterate over a list
+ * @pos: the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ */
+#define list_for_each(pos, head) \
+ for (pos = (head)->next, prefetch(pos->next); pos != (head); \
+ pos = pos->next, prefetch(pos->next))
+
+/**
+ * __list_for_each - iterate over a list
+ * @pos: the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ *
+ * This variant differs from list_for_each() in that it's the
+ * simplest possible list iteration code, no prefetching is done.
+ * Use this for code that knows the list to be very short (empty
+ * or 1 entry) most of the time.
+ */
+#define __list_for_each(pos, head) \
+ for (pos = (head)->next; pos != (head); pos = pos->next)
+
+/**
+ * list_for_each_prev - iterate over a list backwards
+ * @pos: the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ */
+#define list_for_each_prev(pos, head) \
+ for (pos = (head)->prev, prefetch(pos->prev); pos != (head); \
+ pos = pos->prev, prefetch(pos->prev))
+
+/**
+ * list_for_each_safe - iterate over a list safe against removal of list entry
+ * @pos: the &struct list_head to use as a loop counter.
+ * @n: another &struct list_head to use as temporary storage
+ * @head: the head for your list.
+ */
+#define list_for_each_safe(pos, n, head) \
+ for (pos = (head)->next, n = pos->next; pos != (head); \
+ pos = n, n = pos->next)
+
+/**
+ * list_for_each_entry - iterate over list of given type
+ * @pos: the type * to use as a loop counter.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry(pos, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member), \
+ prefetch(pos->member.next); \
+ &pos->member != (head); \
+ pos = list_entry(pos->member.next, typeof(*pos), member), \
+ prefetch(pos->member.next))
+
+/**
+ * list_for_each_entry_reverse - iterate backwards over list of given type.
+ * @pos: the type * to use as a loop counter.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_reverse(pos, head, member) \
+ for (pos = list_entry((head)->prev, typeof(*pos), member), \
+ prefetch(pos->member.prev); \
+ &pos->member != (head); \
+ pos = list_entry(pos->member.prev, typeof(*pos), member), \
+ prefetch(pos->member.prev))
+
+
+/**
+ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @pos: the type * to use as a loop counter.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_safe(pos, n, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member), \
+ n = list_entry(pos->member.next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/*
+ * Double linked lists with a single pointer list head.
+ * Mostly useful for hash tables where the two pointer list head is
+ * too wasteful.
+ * You lose the ability to access the tail in O(1).
+ */
+
+struct hlist_head {
+ struct hlist_node *first;
+};
+
+struct hlist_node {
+ struct hlist_node *next, **pprev;
+};
+
+#define HLIST_HEAD_INIT { .first = NULL }
+#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL }
+#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
+#define INIT_HLIST_NODE(ptr) ((ptr)->next = NULL, (ptr)->pprev = NULL)
+
+static __inline__ int hlist_unhashed(struct hlist_node *h)
+{
+ return !h->pprev;
+}
+
+static __inline__ int hlist_empty(struct hlist_head *h)
+{
+ return !h->first;
+}
+
+static __inline__ void __hlist_del(struct hlist_node *n)
+{
+ struct hlist_node *next = n->next;
+ struct hlist_node **pprev = n->pprev;
+ *pprev = next;
+ if (next)
+ next->pprev = pprev;
+}
+
+static __inline__ void hlist_del(struct hlist_node *n)
+{
+ __hlist_del(n);
+ n->next = LIST_POISON1;
+ n->pprev = LIST_POISON2;
+}
+
+static __inline__ void hlist_del_init(struct hlist_node *n)
+{
+ if (n->pprev) {
+ __hlist_del(n);
+ INIT_HLIST_NODE(n);
+ }
+}
+
+static __inline__ void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
+{
+ struct hlist_node *first = h->first;
+ n->next = first;
+ if (first)
+ first->pprev = &n->next;
+ h->first = n;
+ n->pprev = &h->first;
+}
+
+/* next must be != NULL */
+static __inline__ void hlist_add_before(struct hlist_node *n, struct hlist_node *next)
+{
+ n->pprev = next->pprev;
+ n->next = next;
+ next->pprev = &n->next;
+ *(n->pprev) = n;
+}
+
+static __inline__ void hlist_add_after(struct hlist_node *n,
+ struct hlist_node *next)
+{
+ next->next = n->next;
+ *(next->pprev) = n;
+ n->next = next;
+}
+
+#define hlist_entry(ptr, type, member) container_of(ptr,type,member)
+
+/* Cannot easily do prefetch unfortunately */
+#define hlist_for_each(pos, head) \
+ for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \
+ pos = pos->next)
+
+#define hlist_for_each_safe(pos, n, head) \
+ for (pos = (head)->first; n = pos ? pos->next : 0, pos; \
+ pos = n)
+
+/**
+ * hlist_for_each_entry - iterate over list of given type
+ * @tpos: the type * to use as a loop counter.
+ * @pos: the &struct hlist_node to use as a loop counter.
+ * @head: the head for your list.
+ * @member: the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry(tpos, pos, head, member) \
+ for (pos = (head)->first; \
+ pos && ({ prefetch(pos->next); 1;}) && \
+ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
+ pos = pos->next)
+
+/**
+ * hlist_for_each_entry_continue - iterate over a hlist continuing after existing point
+ * @tpos: the type * to use as a loop counter.
+ * @pos: the &struct hlist_node to use as a loop counter.
+ * @member: the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry_continue(tpos, pos, member) \
+ for (pos = (pos)->next; \
+ pos && ({ prefetch(pos->next); 1;}) && \
+ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
+ pos = pos->next)
+
+/**
+ * hlist_for_each_entry_from - iterate over a hlist continuing from existing point
+ * @tpos: the type * to use as a loop counter.
+ * @pos: the &struct hlist_node to use as a loop counter.
+ * @member: the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry_from(tpos, pos, member) \
+ for (; pos && ({ prefetch(pos->next); 1;}) && \
+ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
+ pos = pos->next)
+
+/**
+ * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @tpos: the type * to use as a loop counter.
+ * @pos: the &struct hlist_node to use as a loop counter.
+ * @n: another &struct hlist_node to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \
+ for (pos = (head)->first; \
+ pos && ({ n = pos->next; 1; }) && \
+ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
+ pos = n)
+
+#endif
diff --git a/src/core/misc.c b/src/core/misc.c
new file mode 100644
index 0000000..3f1035f
--- /dev/null
+++ b/src/core/misc.c
@@ -0,0 +1,649 @@
+/*
+ * misc.c
+ *
+ * Miscellaneous macro's and functions.
+ *
+ * Copyright (C) 2004,2005 Martin Schlemmer <azarah@nosferatu.za.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Header$
+ */
+
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "debug.h"
+#include "misc.h"
+
+char *memrepchr(char **str, char old, char new, size_t size) {
+ char *str_p;
+
+ if ((NULL == str) || (NULL == *str) || (0 == strlen(*str))) {
+ DBG_MSG("Invalid argument passed!\n");
+ errno = EINVAL;
+ return NULL;
+ }
+
+ str_p = memchr(*str, old, size);
+
+ while (NULL != str_p) {
+ str_p[0] = new;
+ str_p = memchr(&str_p[1], old, size - (str_p - *str) - 1);
+ }
+
+ return *str;
+}
+
+char *strcatpaths(const char *pathname1, const char *pathname2) {
+ char *new_path = NULL;
+ int lenght;
+
+ if ((NULL == pathname1) || (0 == strlen(pathname1)) ||
+ (NULL == pathname2) || (0 == strlen(pathname2))) {
+ DBG_MSG("Invalid argument passed!\n");
+ errno = EINVAL;
+ return NULL;
+ }
+
+ /* Lenght of pathname1 + lenght of pathname2 + '/' if needed */
+ lenght = strlen(pathname1) + strlen(pathname2) + 1;
+ /* lenght + '\0' */
+ new_path = malloc(lenght + 1);
+ if (NULL == new_path) {
+ DBG_MSG("Failed to allocate buffer!\n");
+ return NULL;
+ }
+
+ strncpy(new_path, pathname1, lenght);
+ /* Should we add a '/' ? */
+ if (new_path[strlen(new_path)-1] != '/')
+ strncat(new_path, "/", lenght - strlen(new_path));
+ strncat(new_path, pathname2, lenght - strlen(new_path));
+
+ return new_path;
+}
+
+char *strndup(const char *str, size_t size) {
+ char *new_str = NULL;
+ size_t len;
+
+ if (NULL == str) {
+ DBG_MSG("Invalid argument passed!\n");
+ errno = EINVAL;
+ return NULL;
+ }
+
+ /* Check lenght of str without breaching the size limit */
+ for (len = 0;(len < size) && ('\0' != str[len]);len++);
+
+ new_str = malloc(len + 1);
+ if (NULL == new_str) {
+ DBG_MSG("Failed to allocate buffer!\n");
+ return NULL;
+ }
+
+ /* Make sure our string is NULL terminated */
+ new_str[len] = '\0';
+
+ return (char *)memcpy(new_str, str, len);
+}
+
+char *gbasename(const char *path) {
+ char *new_path = NULL;
+
+ if ((NULL == path) || (0 == strlen(path))) {
+ DBG_MSG("Invalid argument passed!\n");
+ errno = EINVAL;
+ return NULL;
+ }
+
+ /* Copied from glibc */
+ new_path = strrchr (path, '/');
+ return new_path ? new_path + 1 : (char *)path;
+}
+
+
+int exists(const char *pathname) {
+ struct stat buf;
+ int retval;
+
+ if ((NULL == pathname) || (0 == strlen(pathname))) {
+ DBG_MSG("Invalid argument passed!\n");
+ return 0;
+ }
+
+ retval = lstat(pathname, &buf);
+ if (-1 != retval)
+ return 1;
+
+ /* Clear errno, as we do not want debugging to trigger */
+ errno = 0;
+
+ return 0;
+}
+
+int is_file(const char *pathname, int follow_link) {
+ struct stat buf;
+ int retval;
+
+ if ((NULL == pathname) || (0 == strlen(pathname))) {
+ DBG_MSG("Invalid argument passed!\n");
+ return 0;
+ }
+
+ retval = follow_link ? stat(pathname, &buf) : lstat(pathname, &buf);
+ if ((-1 != retval) && (S_ISREG(buf.st_mode)))
+ return 1;
+
+ /* Clear errno, as we do not want debugging to trigger */
+ errno = 0;
+
+ return 0;
+}
+
+int is_link(const char *pathname) {
+ struct stat buf;
+ int retval;
+
+ if ((NULL == pathname) || (0 == strlen(pathname))) {
+ DBG_MSG("Invalid argument passed!\n");
+ return 0;
+ }
+
+ retval = lstat(pathname, &buf);
+ if ((-1 != retval) && (S_ISLNK(buf.st_mode)))
+ return 1;
+
+ /* Clear errno, as we do not want debugging to trigger */
+ errno = 0;
+
+ return 0;
+}
+
+int is_dir(const char *pathname, int follow_link) {
+ struct stat buf;
+ int retval;
+
+ if ((NULL == pathname) || (0 == strlen(pathname))) {
+ DBG_MSG("Invalid argument passed!\n");
+ return 0;
+ }
+
+ retval = follow_link ? stat(pathname, &buf) : lstat(pathname, &buf);
+ if ((-1 != retval) && (S_ISDIR(buf.st_mode)))
+ return 1;
+
+ /* Clear errno, as we do not want debugging to trigger */
+ errno = 0;
+
+ return 0;
+}
+
+time_t get_mtime(const char *pathname, int follow_link) {
+ struct stat buf;
+ int retval;
+
+ if ((NULL == pathname) || (0 == strlen(pathname))) {
+ DBG_MSG("Invalid argument passed!\n");
+ return 0;
+ }
+
+ retval = follow_link ? stat(pathname, &buf) : lstat(pathname, &buf);
+ if (-1 != retval)
+ return buf.st_mtime;
+
+ /* Clear errno, as we do not want debugging to trigger */
+ errno = 0;
+
+ return 0;
+}
+
+#ifdef __KLIBC__
+int remove(const char *pathname) {
+ int retval;
+
+ if ((NULL == pathname) || (0 == strlen(pathname))) {
+ DBG_MSG("Invalid argument passed!\n");
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (is_dir(pathname, 0))
+ retval = rmdir(pathname);
+ else
+ retval = unlink(pathname);
+
+ return retval;
+}
+#endif
+
+int mktree(const char *pathname, mode_t mode) {
+ char *temp_name = NULL;
+ char *temp_token = NULL;
+ char *token_p;
+ char *token;
+ int retval;
+ int lenght;
+
+ if ((NULL == pathname) || (0 == strlen(pathname))) {
+ DBG_MSG("Invalid argument passed!\n");
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Lenght of 'pathname' + extra for "./" if needed */
+ lenght = strlen(pathname) + 2;
+ /* lenght + '\0' */
+ temp_name = malloc(lenght + 1);
+ if (NULL == temp_name) {
+ DBG_MSG("Failed to allocate temporary buffer!\n");
+ return -1;
+ }
+
+ temp_token = strndup(pathname, strlen(pathname));
+ if (NULL == temp_token) {
+ DBG_MSG("Failed to allocate temporary buffer!\n");
+ goto error;
+ }
+ token_p = temp_token;
+
+ if (pathname[0] == '/')
+ temp_name[0] = '\0';
+ else
+ /* If not an absolute path, make it local */
+ strncpy(temp_name, ".", lenght);
+
+ token = strsep(&token_p, "/");
+ /* First token might be "", but that is OK as it will be when the
+ * pathname starts with '/' */
+ while (NULL != token) {
+ strncat(temp_name, "/", lenght - strlen(temp_name));
+ strncat(temp_name, token, lenght - strlen(temp_name));
+
+ /* If it does not exist, create the dir. If it does exit,
+ * but is not a directory, we will catch it below. */
+ if (!exists(temp_name)) {
+ retval = mkdir(temp_name, mode);
+ if (-1 == retval) {
+ DBG_MSG("Failed to create directory!\n");
+ goto error;
+ }
+ /* Not a directory or symlink pointing to a directory */
+ } else if (!is_dir(temp_name, 1)) {
+ DBG_MSG("Component in pathname is not a directory!\n");
+ errno = ENOTDIR;
+ goto error;
+ }
+
+ do {
+ token = strsep(&token_p, "/");
+ /* The first "" was Ok, but rather skip double '/' after that */
+ } while ((NULL != token) && (0 == strlen(token)));
+ }
+
+ free(temp_name);
+ free(temp_token);
+
+ return 0;
+
+error:
+ free(temp_name);
+ free(temp_token);
+
+ return -1;
+}
+
+int rmtree(const char *pathname) {
+ char **dirlist = NULL;
+ int i = 0;
+
+ if ((NULL == pathname) || (0 == strlen(pathname))) {
+ DBG_MSG("Invalid argument passed!\n");
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!exists(pathname)) {
+ DBG_MSG("'%s' does not exists!\n", pathname);
+ errno = ENOENT;
+ return -1;
+ }
+
+ dirlist = ls_dir(pathname, 1);
+ if ((NULL == dirlist) && (0 != errno)) {
+ /* If errno = ENOENT and the directory exists, then it means
+ * it is empty, so we should not error out */
+ if (ENOENT != errno) {
+ DBG_MSG("Could not get listing for '%s'!\n", pathname);
+ return -1;
+ }
+ }
+
+ while ((NULL != dirlist) && (NULL != dirlist[i])) {
+ /* If it is a directory, call rmtree() again with
+ * it as argument */
+ if (is_dir(dirlist[i], 0)) {
+ if (-1 == rmtree(dirlist[i])) {
+ DBG_MSG("Failed to delete sub directory!\n");
+ goto error;
+ }
+ }
+
+ /* Now actually remove it. Note that if it was a directory,
+ * it should already be removed by above rmtree() call */
+ if ((exists(dirlist[i]) && (-1 == remove(dirlist[i])))) {
+ DBG_MSG("Failed to remove '%s'!\n", dirlist[i]);
+ goto error;
+ }
+ i++;
+ }
+
+ STRING_LIST_FREE(dirlist);
+
+ /* Now remove the parent */
+ if (-1 == remove(pathname)) {
+ DBG_MSG("Failed to remove '%s'!\n", pathname);
+ goto error;
+ }
+
+ return 0;
+error:
+ STRING_LIST_FREE(dirlist);
+
+ return -1;
+}
+
+char **ls_dir(const char *pathname, int hidden) {
+ DIR *dirfd;
+ struct dirent *dir_entry;
+ char **dirlist = NULL;
+
+ if ((NULL == pathname) || (0 == strlen(pathname))) {
+ DBG_MSG("Invalid argument passed!\n");
+ errno = EINVAL;
+ return NULL;
+ }
+
+ dirfd = opendir(pathname);
+ if (NULL == dirfd) {
+ DBG_MSG("Failed to call opendir()!\n");
+ /* errno will be set by opendir() */
+ goto error;
+ }
+
+ do {
+ /* Clear errno to distinguish between EOF and error */
+ errno = 0;
+ dir_entry = readdir(dirfd);
+ /* Only an error if 'errno' != 0, else EOF */
+ if ((NULL == dir_entry) && (0 != errno)) {
+ DBG_MSG("Failed to call readdir()!\n");
+ goto error;
+ }
+ if ((NULL != dir_entry) &&
+ /* Should we display hidden files? */
+ (hidden ? 1 : dir_entry->d_name[0] != '.'))
+ {
+ char *d_name = dir_entry->d_name;
+ char *tmp_p;
+
+ /* Do not list current or parent entries */
+ if ((0 == strcmp(d_name, ".")) ||
+ (0 == strcmp(d_name, "..")))
+ continue;
+
+ tmp_p = strcatpaths(pathname, d_name);
+ if (NULL == tmp_p) {
+ DBG_MSG("Failed to allocate buffer!\n");
+ /* errno = ENOMEM */
+ goto error;
+ }
+
+ STRING_LIST_ADD(dirlist, tmp_p, error);
+ }
+ } while (NULL != dir_entry);
+
+ if ((NULL == dirlist) || (NULL == dirlist[0])) {
+ DBG_MSG("Directory is empty.\n");
+ errno = ENOENT;
+ goto error;
+ }
+
+ closedir(dirfd);
+
+ return dirlist;
+
+error:
+ /* Free dirlist on error */
+ STRING_LIST_FREE(dirlist);
+
+ if (NULL != dirfd) {
+ int old_errno = errno;
+ closedir(dirfd);
+ /* closedir() might have changed it */
+ errno = old_errno;
+ }
+
+ return NULL;
+}
+
+/* This handles simple 'entry="bar"' type variables. If it is more complex
+ * ('entry="$(pwd)"' or such), it will obviously not work, but current behaviour
+ * should be fine for the type of variables we want. */
+char *get_cnf_entry(const char *pathname, const char *entry) {
+ char *buf = NULL;
+ char *tmp_buf = NULL;
+ char *tmp_p;
+ char *value = NULL;
+ char *token;
+ size_t lenght;
+ int count;
+ int current = 0;
+
+
+ if ((NULL == pathname) || (0 == strlen(pathname)) ||
+ (NULL == entry) || (0 == strlen(entry))) {
+ DBG_MSG("Invalid argument passed!\n");
+ errno = EINVAL;
+ return NULL;
+ }
+
+ /* If it is not a file or symlink pointing to a file, bail */
+ if (!is_file(pathname, 1)) {
+ DBG_MSG("Given pathname is not a file or do not exist!\n");
+ /* FIXME: Might need to set this to something better? */
+ errno = ENOENT;
+ return NULL;
+ }
+
+ if (-1 == file_map(pathname, &buf, &lenght)) {
+ DBG_MSG("Could not open config file for reading!\n");
+ return NULL;
+ }
+
+ while (current < lenght) {
+ count = buf_get_line(buf, lenght, current);
+
+ tmp_buf = strndup(&buf[current], count);
+ if (NULL == tmp_buf) {
+ DBG_MSG("Failed to allocate temporary buffer!\n");
+ goto error;
+ }
+ tmp_p = tmp_buf;
+
+ /* Strip leading spaces/tabs */
+ while ((tmp_p[0] == ' ') || (tmp_p[0] == '\t'))
+ tmp_p++;
+
+ /* Get entry and value */
+ token = strsep(&tmp_p, "=");
+ /* Bogus entry or value */
+ if (NULL == token)
+ goto _continue;
+
+ /* Make sure we have a string that is larger than 'entry', and
+ * the first part equals 'entry' */
+ if ((strlen(token) > 0) && (0 == strcmp(entry, token)))
+ {
+ do {
+ /* Bash variables are usually quoted */
+ token = strsep(&tmp_p, "\"\'");
+ /* If quoted, the first match will be "" */
+ } while ((NULL != token) && (0 == strlen(token)));
+
+ /* We have a 'entry='. We respect bash rules, so NULL
+ * value for now (if not already) */
+ if (NULL == token) {
+ /* We might have 'entry=' and later 'entry="bar"',
+ * so just continue for now ... we will handle
+ * it below when 'value == NULL' */
+ if (NULL != value) {
+ free(value);
+ value = NULL;
+ }
+ goto _continue;
+ }
+
+ /* If we have already allocated 'value', free it */
+ if (NULL != value)
+ free(value);
+
+ value = strndup(token, strlen(token));
+ if (NULL == value)
+ /* errno = ENOMEM */
+ goto error;
+
+ /* We do not break, as there might be more than one entry
+ * defined, and as bash uses the last, so should we */
+ /* break; */
+ }
+
+_continue:
+ current += count + 1;
+ free(tmp_buf);
+ /* Set to NULL in case we error out above and have
+ * to free below */
+ tmp_buf = NULL;
+ }
+
+
+ if (NULL == value) {
+ DBG_MSG("Failed to get value for config entry '%s'!\n", entry);
+ errno = ENOMSG;
+ goto error;
+ }
+
+ file_unmap(buf, lenght);
+
+ return value;
+
+error:
+ free(tmp_buf);
+ free(value);
+
+ if (NULL != buf) {
+ int old_errno = errno;
+ file_unmap(buf, lenght);
+ /* unmmap() might have changed it */
+ errno = old_errno;
+ }
+
+ return NULL;
+}
+
+
+/*
+ * Below three functions (file_map, file_unmap and buf_get_line) are
+ * from udev-050 (udev_utils.c).
+ * (Some are slightly modified, please check udev for originals.)
+ *
+ * Copyright (C) 2004 Kay Sievers <kay@vrfy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+int file_map(const char *filename, char **buf, size_t *bufsize)
+{
+ struct stat stats;
+ int fd;
+ int old_errno;
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0) {
+ DBG_MSG("Failed to open file!\n");
+ return -1;
+ }
+
+ if (fstat(fd, &stats) < 0) {
+ DBG_MSG("Failed to stat file!\n");
+ old_errno = errno;
+ close(fd);
+ /* close() might have changed it */
+ errno = old_errno;
+ return -1;
+ }
+
+ *buf = mmap(NULL, stats.st_size, PROT_READ, MAP_SHARED, fd, 0);
+ if (*buf == MAP_FAILED) {
+ DBG_MSG("Failed to mmap file!\n");
+ old_errno = errno;
+ close(fd);
+ /* close() might have changed it */
+ errno = old_errno;
+ return -1;
+ }
+ *bufsize = stats.st_size;
+
+ close(fd);
+
+ return 0;
+}
+
+void file_unmap(char *buf, size_t bufsize)
+{
+ munmap(buf, bufsize);
+}
+
+size_t buf_get_line(char *buf, size_t buflen, size_t cur)
+{
+ size_t count = 0;
+
+ for (count = cur; count < buflen && buf[count] != '\n'; count++);
+
+ return count - cur;
+}
+
diff --git a/src/core/misc.h b/src/core/misc.h
new file mode 100644
index 0000000..441a976
--- /dev/null
+++ b/src/core/misc.h
@@ -0,0 +1,288 @@
+/*
+ * misc.h
+ *
+ * Miscellaneous macro's and functions.
+ *
+ * Copyright (C) 2004,2005 Martin Schlemmer <azarah@nosferatu.za.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Header$
+ */
+
+#ifndef _MISC_H
+#define _MISC_H
+
+#include <sys/stat.h>
+#include <sys/types.h>
+
+/* Gentoo style e* printing macro's */
+#define EINFO(_args...) \
+ do { \
+ int old_errno = errno; \
+ printf(" \033[32;01m*\033[0m " _args); \
+ errno = old_errno; \
+ } while (0)
+
+#define EWARN(_args...) \
+ do { \
+ int old_errno = errno; \
+ printf(" \033[33;01m*\033[0m " _args); \
+ errno = old_errno; \
+ } while (0)
+
+#define EERROR(_args...) \
+ do { \
+ int old_errno = errno; \
+ fprintf(stderr, " \033[31;01m*\033[0m " _args); \
+ errno = old_errno; \
+ } while (0)
+
+/* Return true if filename '_name' ends in '_ext' */
+#define CHECK_FILE_EXTENSION(_name, _ext) \
+ (strlen(_name) > strlen(_ext) && \
+ 0 == strncmp(&_name[strlen(_name) - strlen(_ext)], \
+ _ext, strlen(_ext)))
+
+/* For each '_char' in '_string', inc '_count' */
+#define COUNT_CHAR_UP(_string, _char, _count) \
+ do { \
+ int _i; \
+ for (_i = 0;_i < strlen(_string);_i++) \
+ if (_string[_i] == _char) \
+ _count++; \
+ } while (0)
+
+/* For each '_char' in '_string', dec '_count' */
+#define COUNT_CHAR_DN(_string, _char, _count) \
+ do { \
+ int _i; \
+ for (_i = 0;_i < strlen(_string);_i++) \
+ if (_string[_i] == _char) \
+ _count--; \
+ } while (0)
+
+/* Add a new item to a string list. If the pointer to the list is NULL,
+ * allocate enough memory for the amount of entries needed. Ditto for
+ * when it already exists, but we add one more entry than it can
+ * contain. The list is NULL terminated.
+ * NOTE: _only_ memory for the list are allocated, and not for the items - that
+ * should be done by relevant code (unlike STRING_LIST_DEL that will
+ * free the memory) */
+#define STRING_LIST_ADD(_string_list, _item, _error) \
+ do { \
+ char **_tmp_p; \
+ int _i = 0; \
+ if ((NULL == _item) || (0 == strlen(_item))) { \
+ DBG_MSG("Invalid argument passed!\n"); \
+ errno = EINVAL; \
+ goto _error; \
+ } \
+ while ((NULL != _string_list) && (NULL != _string_list[_i])) { \
+ _i++; \
+ } \
+ /* Amount of entries + new + terminator */ \
+ _tmp_p = realloc(_string_list, sizeof(char *) * (_i + 2)); \
+ if (NULL == _tmp_p) { \
+ DBG_MSG("Failed to reallocate list!\n"); \
+ goto _error; \
+ } \
+ _string_list = _tmp_p; \
+ _string_list[_i] = _item; \
+ /* Terminator */ \
+ _string_list[_i+1] = NULL; \
+ } while (0)
+
+/* Add a new item to a string list (foundamental the same as above), but make
+ * sure we have all the items alphabetically sorted. */
+#define STRING_LIST_ADD_SORT(_string_list, _item, _error) \
+ do { \
+ char **_tmp_p; \
+ char *_str_p1; \
+ char *_str_p2; \
+ int _i = 0; \
+ if ((NULL == _item) || (0 == strlen(_item))) { \
+ DBG_MSG("Invalid argument passed!\n"); \
+ errno = EINVAL; \
+ goto _error; \
+ } \
+ while ((NULL != _string_list) && (NULL != _string_list[_i])) \
+ _i++; \
+ /* Amount of entries + new + terminator */ \
+ _tmp_p = realloc(_string_list, sizeof(char *) * (_i + 2)); \
+ if (NULL == _tmp_p) { \
+ DBG_MSG("Failed to reallocate list!\n"); \
+ goto _error; \
+ } \
+ _string_list = _tmp_p; \
+ if (0 == _i) \
+ /* Needed so that the end NULL will propagate
+ * (iow, make sure our 'NULL != _str_p1' test below
+ * do not fail) */ \
+ _string_list[_i] = NULL; \
+ /* Actual terminator that needs adding */ \
+ _string_list[_i+1] = NULL; \
+ _i = 0; \
+ /* See where we should insert the new item to have it all \
+ * alphabetically sorted */ \
+ while (NULL != _string_list[_i]) { \
+ if (strcmp(_string_list[_i], _item) > 0) { \
+ break; \
+ } \
+ _i++; \
+ } \
+ /* Now just insert the new item, and shift the rest one over.
+ * '_str_p2' is temporary storage to swap the indexes in a loop,
+ * and 'str_p1' is used to store the old value across the loop */ \
+ _str_p1 = _string_list[_i]; \
+ _string_list[_i] = _item; \
+ do { \
+ _i++;\
+ _str_p2 = _string_list[_i]; \
+ _string_list[_i] = _str_p1; \
+ _str_p1 = _str_p2; \
+ } while (NULL != _str_p1); \
+ } while (0)
+
+/* Delete one entry from the string list, and shift the rest down if the entry
+ * was not at the end. For now we do not resize the amount of entries the
+ * string list can contain, and free the memory for the matching item */
+#define STRING_LIST_DEL(_string_list, _item, _error) \
+ do { \
+ int _i = 0; \
+ if ((NULL == _item) || (0 == strlen(_item)) || \
+ (NULL == _string_list)) { \
+ DBG_MSG("Invalid argument passed!\n"); \
+ errno = EINVAL; \
+ goto _error; \
+ } \
+ while (NULL != _string_list[_i]) { \
+ if (0 == strcmp(_item, _string_list[_i])) \
+ break; \
+ else \
+ _i++; \
+ } \
+ if (NULL == _string_list[_i]) { \
+ DBG_MSG("Invalid argument passed!\n"); \
+ errno = EINVAL; \
+ goto _error; \
+ } \
+ free(_string_list[_i]); \
+ /* Shift all the following items one forward */ \
+ do { \
+ _string_list[_i] = _string_list[_i+1]; \
+ /* This stupidity is to shutup gcc */ \
+ _i++; \
+ } while (NULL != _string_list[_i]); \
+ } while (0)
+
+/* 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 STRING_LIST_FOR_EACH(_string_list, _pos, _counter) \
+ if ((NULL != _string_list) && (0 == (_counter = 0))) \
+ while (NULL != (_pos = _string_list[_counter++]))
+
+/* Same as above (with the same warning about '_counter'). Now we just
+ * have '_next' that are also used for indexing. Once again rather refrain
+ * from using it if not absolutely needed. The major difference to above,
+ * is that it should be safe from having the item removed from under you. */
+#define STRING_LIST_FOR_EACH_SAFE(_string_list, _pos, _next, _counter) \
+ if ((NULL != _string_list) && (0 == (_counter = 0))) \
+ /* First part of the while checks if this is the
+ * first loop, and if so setup _pos and _next
+ * and increment _counter */ \
+ while ((((0 == _counter) && \
+ (NULL != (_pos = _string_list[_counter])) && \
+ (_pos != (_next = _string_list[++_counter]))) || \
+ /* Second part is when it is not the first loop
+ * and _pos was not removed from under us. We
+ * just increment _counter, and setup _pos and
+ * _next */ \
+ ((0 != _counter) && \
+ (_pos == _string_list[_counter-1]) && \
+ (_next == _string_list[_counter]) && \
+ (NULL != (_pos = _string_list[_counter])) && \
+ (_pos != (_next = _string_list[++_counter]))) || \
+ /* Last part is when _pos was removed from under
+ * us. We basically just setup _pos and _next,
+ * but leave _counter alone */ \
+ ((0 != _counter) && \
+ (_pos != _string_list[_counter-1]) && \
+ (_next == _string_list[_counter-1]) && \
+ (NULL != (_pos = _string_list[_counter-1])) && \
+ (_pos != (_next = _string_list[_counter])))))
+
+/* Just free the whole string list */
+#define STRING_LIST_FREE(_string_list) \
+ do { \
+ if (NULL != _string_list) { \
+ int _i = 0; \
+ while (NULL != _string_list[_i]) \
+ free(_string_list[_i++]); \
+ free(_string_list); \
+ _string_list = NULL; \
+ } \
+ } while (0)
+
+/* String functions. Return a string on success, or NULL on error
+ * or no action taken. On error errno will be set.*/
+char *memrepchr(char **str, char old, char _new, size_t size);
+/* Concat two paths adding '/' if needed. Memory will be allocated
+ * with the malloc() call. */
+char *strcatpaths(const char *pathname1, const char *pathname2);
+
+/* Compat functions for GNU extensions */
+char *strndup(const char *str, size_t size);
+/* Same as basename(3), but do not modify path */
+char *gbasename(const char *path);
+
+/* The following functions do not care about errors - they only return
+ * 1 if 'pathname' exist, and is the type requested, or else 0.
+ * They also might clear errno */
+int exists(const char *pathname);
+int is_file(const char *pathname, int follow_link);
+int is_link(const char *pathname);
+int is_dir(const char *pathname, int follow_link);
+
+/* The following function do not care about errors - it only returns
+ * the mtime of 'pathname' if it exists, and is the type requested,
+ * or else 0. It also might clear errno */
+time_t get_mtime(const char *pathname, int follow_link);
+
+/* The following functions return 0 on success, or -1 with errno set on error. */
+#ifdef __KLIBC__
+int remove(const char *pathname);
+#endif
+int mktree(const char *pathname, mode_t mode);
+int rmtree(const char *pathname);
+
+/* The following return a pointer on success, or NULL with errno set on error.
+ * If it returned NULL, but errno is not set, then there was no error, but
+ * there is nothing to return. */
+char **ls_dir(const char *pathname, int hidden);
+char *get_cnf_entry(const char *pathname, const char *entry);
+
+/* Below three functions (file_map, file_unmap and buf_get_line) are from
+ * udev-050 (udev_utils.c). Please see misc.c for copyright info.
+ * (Some are slightly modified, please check udev for originals.) */
+int file_map(const char *filename, char **buf, size_t *bufsize);
+void file_unmap(char *buf, size_t bufsize);
+size_t buf_get_line(char *buf, size_t buflen, size_t cur);
+
+#endif /* _MISC_H */
+
diff --git a/src/core/parse.c b/src/core/parse.c
new file mode 100644
index 0000000..35926fc
--- /dev/null
+++ b/src/core/parse.c
@@ -0,0 +1,1033 @@
+/*
+ * parse.c
+ *
+ * Parser for Gentoo style rc-scripts.
+ *
+ * Copyright (C) 2004,2005 Martin Schlemmer <azarah@nosferatu.za.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Header$
+ */
+
+#include <errno.h>
+#include <string.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+
+#include "debug.h"
+#include "depend.h"
+#include "list.h"
+#include "misc.h"
+#include "parse.h"
+#include "simple-regex.h"
+
+#define READ_PIPE 0
+#define WRITE_PIPE 1
+
+#define PARSE_BUFFER_SIZE 256
+
+#define OUTPUT_MAX_LINE_LENGHT 256
+#define OUTPUT_BUFFER_SIZE (60 * 1024)
+
+/* void PRINT_TO_BUFFER(char **_buf, int _count, label _error, format) */
+#define PRINT_TO_BUFFER(_buf, _count, _error, _output...) \
+ do { \
+ int _i = 0; \
+ /* FIXME: Might do something more dynamic here */ \
+ if (OUTPUT_BUFFER_SIZE < (_count + OUTPUT_MAX_LINE_LENGHT)) { \
+ errno = ENOMEM; \
+ DBG_MSG("Output buffer size too small!\n"); \
+ goto _error; \
+ } \
+ _i = sprintf(&((*_buf)[_count]), _output); \
+ if (0 < _i) \
+ _count += _i + 1; \
+ } while (0)
+
+LIST_HEAD(rcscript_list);
+
+size_t parse_rcscript(char *scriptname, time_t mtime, char **data, size_t index);
+
+size_t parse_print_start(char **data, size_t index);
+size_t parse_print_header(char *scriptname, time_t mtime, char **data, size_t index);
+size_t parse_print_body(char *scriptname, char **data, size_t index);
+size_t parse_print_end(char **data, size_t index);
+
+int get_rcscripts(void) {
+ rcscript_info_t *info;
+ char **file_list = NULL;
+ char *rcscript;
+ char *confd_file = NULL;
+ int count;
+
+ file_list = ls_dir(INITD_DIR_NAME, 0);
+ if (NULL == file_list) {
+ DBG_MSG("'%s' is empty!\n", INITD_DIR_NAME);
+ return -1;
+ }
+
+ STRING_LIST_FOR_EACH(file_list, rcscript, count) {
+ /* Is it a file? */
+ if ((!is_file(rcscript, 1)) ||
+ /* Do not process scripts, source or backup files. */
+ (CHECK_FILE_EXTENSION(rcscript, ".c")) ||
+ (CHECK_FILE_EXTENSION(rcscript, ".bak")) ||
+ (CHECK_FILE_EXTENSION(rcscript, "~")))
+ {
+ DBG_MSG("'%s' is not a valid rc-script!\n",
+ gbasename(rcscript));
+ } else {
+ DBG_MSG("Adding rc-script '%s' to list.\n",
+ gbasename(rcscript));
+
+ info = malloc(sizeof(rcscript_info_t));
+ if (NULL == info) {
+ DBG_MSG("Failed to allocate rcscript_info_t!\n");
+ goto error;
+ }
+
+ /* Copy the name */
+ info->filename = strndup(rcscript, strlen(rcscript));
+ if (NULL == info->filename) {
+ DBG_MSG("Failed to allocate buffer!\n");
+ goto loop_error;
+ }
+
+ /* Get the modification time */
+ info->mtime = get_mtime(rcscript, 1);
+ if (0 == info->mtime) {
+ DBG_MSG("Failed to get modification time for '%s'!\n",
+ rcscript);
+ /* We do not care if it fails - we will pick up
+ * later if there is a problem with the file */
+ }
+
+ /* File name for the conf.d config file (if any) */
+ confd_file = strcatpaths(CONFD_DIR_NAME,
+ gbasename(rcscript));
+ if (NULL == confd_file) {
+ DBG_MSG("Failed to allocate temporary buffer!\n");
+ goto loop_error;
+ }
+
+ /* Get the modification time of the conf.d file
+ * (if any exists) */
+ info->confd_mtime = get_mtime(confd_file, 1);
+ if (0 == info->confd_mtime) {
+ DBG_MSG("Failed to get modification time for '%s'!\n",
+ confd_file);
+ /* We do not care that it fails, as not all
+ * rc-scripts will have conf.d config files */
+ }
+
+ free(confd_file);
+
+ list_add_tail(&info->node, &rcscript_list);
+
+ continue;
+
+loop_error:
+ if (NULL != info)
+ free(info->filename);
+ free(info);
+
+ goto error;
+ }
+ }
+
+ /* Final check if we have some entries */
+ if (NULL == file_list[0]) {
+ DBG_MSG("No rc-scripts to parse!\n");
+ errno = ENOENT;
+ goto error;
+ }
+
+ STRING_LIST_FREE(file_list);
+
+ return 0;
+
+error:
+ STRING_LIST_FREE(file_list);
+
+ return -1;
+}
+
+/* Returns 0 if we do not need to regen the cache file, else -1 with
+ * errno set if something went wrong */
+int check_rcscripts_mtime(char *cachefile) {
+ rcscript_info_t *info;
+ time_t cache_mtime;
+ time_t rc_conf_mtime;
+ time_t rc_confd_mtime;
+
+ if ((NULL == cachefile) || (0 == strlen(cachefile))) {
+ DBG_MSG("Invalid argument passed!\n");
+ errno = EINVAL;
+ return -1;
+ }
+
+ cache_mtime = get_mtime(cachefile, 1);
+ if (0 == cache_mtime) {
+ DBG_MSG("Could not get modification time for cache file '%s'!\n",
+ cachefile);
+ return -1;
+ }
+
+ /* Get and compare mtime for RC_CONF_FILE_NAME with that of cachefile */
+ rc_conf_mtime = get_mtime(RC_CONF_FILE_NAME, 1);
+ if (rc_conf_mtime > cache_mtime) {
+ DBG_MSG("'%s' have a later modification time than '%s'.\n",
+ RC_CONF_FILE_NAME, cachefile);
+ return -1;
+ }
+ /* Get and compare mtime for RC_CONFD_FILE_NAME with that of cachefile */
+ rc_confd_mtime = get_mtime(RC_CONFD_FILE_NAME, 1);
+ if (rc_confd_mtime > cache_mtime) {
+ DBG_MSG("'%s' have a later modification time than '%s'.\n",
+ RC_CONFD_FILE_NAME, cachefile);
+ return -1;
+ }
+
+ /* Get and compare mtime for each rc-script and its conf.d config file
+ * with that of cachefile */
+ list_for_each_entry(info, &rcscript_list, node) {
+ if ((info->mtime > cache_mtime) ||
+ (info->confd_mtime > cache_mtime)) {
+ DBG_MSG("'%s' have a later modification time than '%s'.\n",
+ info->filename, cachefile);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/* Return count on success, -1 on error. If it was critical, errno will be set. */
+size_t parse_rcscript(char *scriptname, time_t mtime, char **data, size_t index) {
+ regex_data_t tmp_data;
+ char *buf = NULL;
+ char *tmp_buf = NULL;
+ size_t write_count = index;
+ size_t lenght;
+ int count;
+ int current = 0;
+
+ if ((NULL == scriptname) || (0 == strlen(scriptname))) {
+ DBG_MSG("Invalid argument passed!\n");
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (-1 == file_map(scriptname, &buf, &lenght)) {
+ DBG_MSG("Could not open '%s' for reading!\n",
+ gbasename(scriptname));
+ return -1;
+ }
+
+ while (current < lenght) {
+ count = buf_get_line(buf, lenght, current);
+
+ tmp_buf = strndup(&buf[current], count);
+ if (NULL == tmp_buf) {
+ DBG_MSG("Failed to allocate temporary buffer!\n");
+ goto error;
+ }
+
+ if (0 == current) {
+ /* Check if it starts with '#!/sbin/runscript' */
+ DO_REGEX(tmp_data, tmp_buf,
+ "[ \t]*#![ \t]*/sbin/runscript[ \t]*.*", error);
+ if (REGEX_FULL_MATCH != tmp_data.match) {
+ DBG_MSG("'%s' is not a valid rc-script!\n",
+ gbasename(scriptname));
+ errno = 0;
+ goto error;
+ }
+
+ /* We do not want rc-scripts ending in '.sh' */
+ if (CHECK_FILE_EXTENSION(scriptname, ".sh")) {
+ EWARN("'%s' is invalid (should not end with '.sh')!\n",
+ gbasename(scriptname));
+ errno = 0;
+ goto error;
+ }
+ DBG_MSG("Parsing '%s'.\n", gbasename(scriptname));
+
+ write_count = parse_print_header(gbasename(scriptname),
+ mtime, data, write_count);
+ if (-1 == write_count) {
+ DBG_MSG("Failed to call parse_print_header()!\n");
+ goto error;
+ }
+
+ goto _continue;
+ }
+
+ /* Check for lines with comments, and skip them */
+ DO_REGEX(tmp_data, tmp_buf, "^[ \t]*#", error);
+ if (REGEX_MATCH(tmp_data))
+ goto _continue;
+
+ /* If the line contains 'depend()', set 'got_depend' */
+ DO_REGEX(tmp_data, tmp_buf, "depend[ \t]*()[ \t]*{?", error);
+ if (REGEX_MATCH(tmp_data)) {
+ DBG_MSG("Got 'depend()' function.\n");
+
+ write_count = parse_print_body(gbasename(scriptname),
+ data, write_count);
+ if (-1 == write_count) {
+ DBG_MSG("Failed to call parse_print_body()!\n");
+ goto error;
+ }
+
+ /* Need to have the 'source', as parse_cache() checks for
+ * second arg */
+ PRINT_TO_BUFFER(data, write_count, error,
+ " . \"%s\" >/dev/null 2>&1 || echo \"FAILED source\"\n",
+ scriptname);
+
+ write_count = parse_print_end(data, write_count);
+ if (-1 == write_count) {
+ DBG_MSG("Failed to call parse_print_end()!\n");
+ goto error;
+ }
+
+ /* Make sure this is the last loop */
+ current += lenght;
+ goto _continue;
+ }
+
+_continue:
+ current += count + 1;
+ free(tmp_buf);
+ }
+
+ file_unmap(buf, lenght);
+
+ return write_count;
+
+error:
+ free(tmp_buf);
+ if (NULL != buf) {
+ int old_errno = errno;
+ file_unmap(buf, lenght);
+ /* file_unmap() might have changed it */
+ errno = old_errno;
+ }
+
+ return -1;
+}
+
+
+size_t generate_stage1(char **data) {
+ rcscript_info_t *info;
+ size_t write_count = 0;
+ size_t tmp_count;
+
+ write_count = parse_print_start(data, write_count);
+ if (-1 == write_count) {
+ DBG_MSG("Failed to call parse_print_start()!\n");
+ return -1;
+ }
+
+ list_for_each_entry(info, &rcscript_list, node) {
+ tmp_count = parse_rcscript(info->filename, info->mtime, data, write_count);
+ if (-1 == tmp_count) {
+ DBG_MSG("Failed to parse '%s'!\n",
+ gbasename(info->filename));
+
+ /* If 'errno' is set, it is critical (hopefully) */
+ if (0 != errno)
+ return -1;
+ } else {
+ write_count = tmp_count;
+ }
+ }
+
+ return write_count;
+}
+
+/* Empty signal handler for SIGPIPE */
+static void sig_handler(int signum) {
+ return;
+}
+
+/* Returns data's lenght on success, else -1 on error. */
+size_t generate_stage2(char **data) {
+ /* parent_pfds is used to send data to the parent
+ * (thus the parent only use the read pipe, and the
+ * child uses the write pipe)
+ */
+ int parent_pfds[2];
+ /* child_pfds is used to send data to the child
+ * (thus the child only use the read pipe, and the
+ * parent uses the write pipe)
+ */
+ int child_pfds[2];
+ pid_t child_pid;
+ size_t write_count = 0;
+ int old_errno = 0;
+
+ /* Pipe to send data to parent */
+ if (-1 == pipe(parent_pfds)) {
+ DBG_MSG("Failed to open 'parent_pfds' pipe!\n");
+ goto error;
+ }
+ /* Pipe to send data to childd */
+ if (-1 == pipe(child_pfds)) {
+ DBG_MSG("Failed to open 'child_pfds' pipe!\n");
+ /* Close parent_pfds */
+ goto error_c_parent;
+ }
+
+ /* Zero data */
+ *data = NULL;
+
+ child_pid = fork();
+ if (-1 == child_pid) {
+ DBG_MSG("Failed to fork()!\n");
+ /* Close all pipes */
+ goto error_c_all;
+ }
+ if (0 == child_pid) {
+ /***
+ *** In child
+ ***/
+
+ char *const argv[] = {
+ "bash",
+ "--noprofile",
+ "--norc",
+ "--",
+ NULL
+ };
+
+ /* Close the sides of the pipes we do not use */
+ close(child_pfds[WRITE_PIPE]); /* Only used for reading */
+ close(parent_pfds[READ_PIPE]); /* Only used for writing */
+
+ /* dup2 child side read pipe to STDIN */
+ dup2(child_pfds[READ_PIPE], STDIN_FILENO);
+ /* dup2 child side write pipe to STDOUT */
+ dup2(parent_pfds[WRITE_PIPE], STDOUT_FILENO);
+
+ /* We need to be in INITD_DIR_NAME for 'before'/'after' '*' to work */
+ if (-1 == chdir(INITD_DIR_NAME)) {
+ DBG_MSG("Failed to chdir to '%s'!\n", INITD_DIR_NAME);
+ exit(1);
+ }
+
+ if (-1 == execv(SHELL_PARSER, argv)) {
+ DBG_MSG("Failed to execv %s!\n", SHELL_PARSER);
+ exit(1);
+ }
+ } else {
+ /***
+ *** In parent
+ ***/
+
+ struct sigaction act_new;
+ struct sigaction act_old;
+ struct timeval tv;
+#if defined(USE_WRITE_SELECT)
+ fd_set write_fds;
+#endif
+ fd_set read_fds;
+ char buf[PARSE_BUFFER_SIZE+1];
+ char *stage1_data = NULL;
+ size_t stage1_write_count = 0;
+ size_t stage1_written = 0;
+#if defined(USE_WRITE_SELECT)
+ int max_write_fds = child_pfds[WRITE_PIPE] + 1;
+#endif
+ int max_read_fds = parent_pfds[READ_PIPE] + 1;
+ int status = 0;
+ int read_count;
+ int closed_write_pipe = 0;
+ int tmp_pid = 0;
+
+ DBG_MSG("Child pid = %i\n", child_pid);
+
+ /* Set signal handler for SIGPIPE to empty in case bash errors
+ * out. It will then close the write pipe, and instead of us
+ * getting SIGPIPE, we can handle the write error like normal.
+ */
+ memset(&act_new, 0x00, sizeof(act_new));
+ act_new.sa_handler = (void (*) (int))sig_handler;
+ sigemptyset (&act_new.sa_mask);
+ act_new.sa_flags = 0;
+ sigaction(SIGPIPE, &act_new, &act_old);
+
+ /* Close the sides of the pipes we do not use */
+ close(parent_pfds[WRITE_PIPE]); /* Only used for reading */
+ close(child_pfds[READ_PIPE]); /* Only used for writing */
+
+ stage1_data = malloc(OUTPUT_BUFFER_SIZE + 1);
+ if (NULL == stage1_data) {
+ DBG_MSG("Failed to allocate buffer!\n");
+ goto error_c_p_side;
+ }
+
+ /* Pipe parse_rcscripts() to bash */
+ stage1_write_count = generate_stage1(&stage1_data);
+ if (-1 == stage1_write_count) {
+ DBG_MSG("Failed to generate stage1!\n");
+ goto error_c_p_side;
+ }
+
+#if 0
+ int tmp_fd = open("bar", O_CREAT | O_TRUNC | O_RDWR, 0600);
+ write(tmp_fd, stage1_data, stage1_write_count);
+ close(tmp_fd);
+#endif
+
+ /* Do setup for select() */
+ tv.tv_sec = 0; /* We do not want to wait for select() */
+ tv.tv_usec = 0; /* Same thing here */
+#if defined(USE_WRITE_SELECT)
+ FD_ZERO(&write_fds);
+ FD_SET(child_pfds[WRITE_PIPE], &write_fds);
+#endif
+ FD_ZERO(&read_fds);
+ FD_SET(parent_pfds[READ_PIPE], &read_fds);
+
+ do {
+#if defined(USE_WRITE_SELECT)
+ fd_set wwrite_fds = write_fds;
+#endif
+ fd_set wread_fds = read_fds;
+ int tmp_count = 0;
+#if defined(USE_WRITE_SELECT)
+ int do_write = 0;
+#endif
+ int do_read = 0;
+
+ /* Check if we can read from parent_pfds[READ_PIPE] */
+ select(max_read_fds, &wread_fds, NULL, NULL, &tv);
+ do_read = FD_ISSET(parent_pfds[READ_PIPE], &wread_fds);
+
+ /* While there is data to be written */
+ if (stage1_written < stage1_write_count) {
+#if defined(USE_WRITE_SELECT)
+ /* Check if we can write */
+ select(max_write_fds, NULL, &wwrite_fds,
+ NULL, &tv);
+ do_write = FD_ISSET(child_pfds[WRITE_PIPE],
+ &wwrite_fds);
+
+ /* If we can write, or there is nothing to
+ * read, keep feeding the write pipe */
+ if (do_write || !do_read) {
+#else
+ if (!do_read) {
+#endif
+ tmp_count = write(child_pfds[WRITE_PIPE],
+ &stage1_data[stage1_written],
+ strlen(&stage1_data[stage1_written]));
+ if (-1 == tmp_count) {
+ DBG_MSG("Error writing to child_pfds[WRITE_PIPE]!\n");
+ goto failed;
+ }
+ /* What was written before, plus what
+ * we wrote now as well as the ending
+ * '\0' of the line */
+ stage1_written += tmp_count + 1;
+
+ /* Close the write pipe if we done
+ * writing to get a EOF signaled to
+ * bash */
+ if (stage1_written >= stage1_write_count) {
+ closed_write_pipe = 1;
+ close(child_pfds[WRITE_PIPE]);
+ }
+ }
+ }
+
+ if (do_read) {
+ read_count = read(parent_pfds[READ_PIPE], buf,
+ PARSE_BUFFER_SIZE);
+ if (-1 == read_count) {
+ DBG_MSG("Error reading parent_pfds[READ_PIPE]!\n");
+ goto failed;
+ }
+ if (read_count > 0) {
+ char *tmp_p;
+
+ tmp_p = realloc(*data, write_count +
+ read_count);
+ if (NULL == tmp_p) {
+ DBG_MSG("Failed to allocate buffer!\n");
+ goto failed;
+ }
+
+ memcpy(&tmp_p[write_count], buf,
+ read_count);
+
+ *data = tmp_p;
+ write_count += read_count;
+ }
+ }
+ tmp_pid = waitpid(child_pid, &status, WNOHANG);
+ } while (0 == tmp_pid);
+
+failed:
+ /* Set old_errno to disable child exit code checking below */
+ if (0 != errno)
+ old_errno = errno;
+
+ free(stage1_data);
+
+ if (0 == closed_write_pipe)
+ close(child_pfds[WRITE_PIPE]);
+ close(parent_pfds[READ_PIPE]);
+
+ /* Restore the old signal handler for SIGPIPE */
+ sigaction(SIGPIPE, &act_old, NULL);
+
+ if (tmp_pid != child_pid)
+ /* Wait for bash to finish */
+ waitpid(child_pid, &status, 0);
+ /* If old_errno is set, we had an error in the read loop, so do
+ * not worry about the child's exit code */
+ if (0 == old_errno) {
+ if ((!WIFEXITED(status)) || (0 != WEXITSTATUS(status))) {
+ DBG_MSG("Bash failed with status 0x%x!\n", status);
+ goto error;
+ }
+ } else {
+ /* Right, we had an error, so set errno, and exit */
+ errno = old_errno;
+ goto error;
+ }
+ }
+
+ return write_count;
+
+ /* Close parent side pipes */
+error_c_p_side:
+ old_errno = errno;
+ close(child_pfds[WRITE_PIPE]);
+ close(parent_pfds[READ_PIPE]);
+ /* close() might have changed it */
+ errno = old_errno;
+ goto error;
+
+ /* Close all pipes */
+error_c_all:
+ old_errno = errno;
+ close(child_pfds[READ_PIPE]);
+ close(child_pfds[WRITE_PIPE]);
+ /* close() might have changed it */
+ errno = old_errno;
+
+ /* Only close parent's pipes */
+error_c_parent:
+ old_errno = errno;
+ close(parent_pfds[READ_PIPE]);
+ close(parent_pfds[WRITE_PIPE]);
+ /* close() might have changed it */
+ errno = old_errno;
+
+error:
+ return -1;
+}
+
+int write_legacy_stage3(FILE *output) {
+ service_info_t *info;
+ char *service;
+ int count;
+ int index = 0;
+ int dep_count;
+ int i;
+
+ if (-1 == fileno(output)) {
+ DBG_MSG("Bad output stream!\n");
+ return -1;
+ }
+
+ fprintf(output, "rc_type_ineed=2\n");
+ fprintf(output, "rc_type_needsme=3\n");
+ fprintf(output, "rc_type_iuse=4\n");
+ fprintf(output, "rc_type_usesme=5\n");
+ fprintf(output, "rc_type_ibefore=6\n");
+ fprintf(output, "rc_type_iafter=7\n");
+ fprintf(output, "rc_type_broken=8\n");
+ fprintf(output, "rc_type_mtime=9\n");
+ fprintf(output, "rc_index_scale=10\n\n");
+ fprintf(output, "declare -a RC_DEPEND_TREE\n\n");
+
+ list_for_each_entry(info, &service_info_list, node) {
+ index++;
+ }
+ if (0 == index) {
+ EERROR("No services to generate dependency tree for!\n");
+ return -1;
+ }
+
+ fprintf(output, "RC_DEPEND_TREE[0]=%i\n\n", index);
+
+ index = 1;
+
+ list_for_each_entry(info, &service_info_list, node) {
+#if 0
+ /* Make it easier to compare old depscan.sh output and this
+ * output as it puts 'net' right in the middle */
+ if (0 == strcmp("net", info->name))
+ continue;
+#endif
+ fprintf(output, "RC_DEPEND_TREE[%i]=\"%s\"\n", index*11, info->name);
+
+ for (i = 0;i <= BROKEN;i++) {
+ dep_count = 0;
+
+ fprintf(output, "RC_DEPEND_TREE[%i+%i]=", (index * 11), (i + 2));
+
+ STRING_LIST_FOR_EACH(info->depend_info[i], service, count) {
+ if (0 == dep_count)
+ fprintf(output, "\"%s", service);
+ else
+ fprintf(output, " %s", service);
+
+ dep_count++;
+ }
+
+ if (dep_count > 0)
+ fprintf(output, "\"\n");
+ else
+ fprintf(output, "\n");
+ }
+
+ fprintf(output, "RC_DEPEND_TREE[%i+9]=", index*11);
+ fprintf(output, "\n");
+
+ fprintf(output, "RC_DEPEND_TREE[%i+10]=\"%li\"\n\n", index*11,
+ info->mtime);
+ index++;
+ }
+
+ fprintf(output, "RC_GOT_DEPTREE_INFO=\"yes\"\n");
+
+ info = service_get_virtual("logger");
+ if (NULL == info) {
+ DBG_MSG("No service provides the 'logger' logger virtual!\n");
+ fprintf(output, "\nLOGGER_SERVICE=\n");
+ } else {
+ fprintf(output, "\nLOGGER_SERVICE=\"%s\"\n", info->name);
+ }
+
+
+ return 0;
+}
+
+int parse_cache(const char *data, size_t lenght) {
+ service_info_t *info;
+ service_type_t type = ALL_SERVICE_TYPE_T;
+ char *tmp_buf = NULL;
+ char *rc_name = NULL;
+ char *tmp_p;
+ char *token;
+ char *field;
+ int count;
+ int current = 0;
+ int retval;
+
+ if ((NULL == data) || (lenght <= 0)) {
+ DBG_MSG("Invalid argument passed!\n");
+ errno = EINVAL;
+ goto error;
+ }
+
+ while (current < lenght) {
+ count = buf_get_line((char *)data, lenght, current);
+
+ tmp_buf = strndup(&data[current], count);
+ if (NULL == tmp_buf) {
+ DBG_MSG("Failed to allocate temporary buffer!\n");
+ goto error;
+ }
+ tmp_p = tmp_buf;
+
+ /* Strip leading spaces/tabs */
+ while ((tmp_p[0] == ' ') || (tmp_p[0] == '\t'))
+ tmp_p++;
+
+ /* Get FIELD name and FIELD value */
+ token = strsep(&tmp_p, " ");
+
+ /* FIELD name empty/bogus? */
+ if ((NULL == token) || (0 == strlen(token)) ||
+ /* We got an empty FIELD value */
+ (NULL == tmp_p) || (0 == strlen(tmp_p))) {
+ DBG_MSG("Parsing stopped due to short read!\n");
+ errno = EMSGSIZE;
+ goto error;
+ }
+
+ if (0 == strcmp(token, FIELD_RCSCRIPT)) {
+ DBG_MSG("Field = '%s', value = '%s'\n", token, tmp_p);
+
+ /* Add the service to the list, and initialize all data */
+ retval = service_add(tmp_p);
+ if (-1 == retval) {
+ DBG_MSG("Failed to add %s to service list!\n",
+ tmp_p);
+ goto error;
+ }
+
+ info = service_get_info(tmp_p);
+ if (NULL == info) {
+ DBG_MSG("Failed to get info for '%s'!\n", tmp_p);
+ goto error;
+ }
+ /* Save the rc-script name for next passes of loop */
+ rc_name = info->name;
+
+ goto _continue;
+ }
+
+ if (NULL == rc_name) {
+ DBG_MSG("Other fields should come after '%s'!\n", FIELD_RCSCRIPT);
+ goto error;
+ }
+
+ if (0 == strcmp(token, FIELD_FAILED)) {
+ EWARN("'%s' has syntax errors, please correct!\n", rc_name);
+ /* FIXME: Need to think about what to do syntax BROKEN
+ * services */
+ retval = service_add_dependency(rc_name, rc_name, BROKEN);
+ if (-1 == retval) {
+ DBG_MSG("Failed to add dependency '%s' to service '%s', type '%s'!\n",
+ token, rc_name, field);
+ goto error;
+ }
+ goto _continue;
+ }
+
+ if (0 == strcmp(token, FIELD_NEED)) {
+ type = NEED;
+ goto have_dep_field;
+ }
+
+ if (0 == strcmp(token, FIELD_USE)) {
+ type = USE;
+ goto have_dep_field;
+ }
+
+ if (0 == strcmp(token, FIELD_BEFORE)) {
+ type = BEFORE;
+ goto have_dep_field;
+ }
+
+ if (0 == strcmp(token, FIELD_AFTER)) {
+ type = AFTER;
+ goto have_dep_field;
+ }
+
+ if (0 == strcmp(token, FIELD_PROVIDE)) {
+ type = PROVIDE;
+ goto have_dep_field;
+ }
+
+ if (type < ALL_SERVICE_TYPE_T) {
+have_dep_field:
+ /* Get the first value *
+ * As the values are passed to a bash function, and we
+ * then use 'echo $*' to parse them, they should only
+ * have one space between each value ... */
+ token = strsep(&tmp_p, " ");
+
+ /* Get the correct type name */
+ field = service_type_names[type];
+
+ while (NULL != token) {
+ DBG_MSG("Field = '%s', service = '%s', value = '%s'\n",
+ field, rc_name, token);
+
+ retval = service_add_dependency(rc_name, token, type);
+ if (-1 == retval) {
+ DBG_MSG("Failed to add dependency '%s' to service '%s', type '%s'!\n",
+ token, rc_name, field);
+ goto error;
+ }
+
+ /* Get the next value (if any) */
+ token = strsep(&tmp_p, " ");
+ }
+
+ goto _continue;
+ }
+
+ if (0 == strcmp(token, FIELD_MTIME)) {
+ time_t mtime = 0;
+
+ /* Just use the first value, and ignore the rest */
+ token = strsep(&tmp_p, " ");
+
+ if (NULL != token)
+ mtime = atoi(token);
+
+ retval = service_set_mtime(rc_name, mtime);
+ if (-1 == retval) {
+ DBG_MSG("Failed to set mtime for service '%s'!\n",
+ rc_name);
+ goto error;
+ }
+
+ /* Some debugging in case we have some corruption or
+ * other issues */
+ token = strsep(&tmp_p, " ");
+ if (NULL != token)
+ DBG_MSG("Too many falues for field '%s'!\n",
+ FIELD_MTIME);
+
+ goto _continue;
+ }
+
+ /* Fall through */
+ DBG_MSG("Unknown FIELD in data!\n");
+
+_continue:
+ type = ALL_SERVICE_TYPE_T;
+ current += count + 1;
+ free(tmp_buf);
+ /* Do not free 'rc_name', as it should be consistant
+ * across loops */
+ }
+
+ return 0;
+
+error:
+ free(tmp_buf);
+
+ return -1;
+}
+
+size_t parse_print_start(char **data, size_t index) {
+ size_t write_count = index;
+
+ PRINT_TO_BUFFER(data, write_count, error, ". /sbin/functions.sh\n");
+ PRINT_TO_BUFFER(data, write_count, error, "[ -e /etc/rc.conf ] && . /etc/rc.conf\n\n");
+// PRINT_TO_BUFFER(data, write_count, error, "set -e\n\n");
+ PRINT_TO_BUFFER(data, write_count, error, "need() {\n");
+ PRINT_TO_BUFFER(data, write_count, error, " [ -n \"$*\" ] && echo \"NEED $*\"; return 0\n");
+ PRINT_TO_BUFFER(data, write_count, error, "}\n\n");
+ PRINT_TO_BUFFER(data, write_count, error, "use() {\n");
+ PRINT_TO_BUFFER(data, write_count, error, " [ -n \"$*\" ] && echo \"USE $*\"; return 0\n");
+ PRINT_TO_BUFFER(data, write_count, error, "}\n\n");
+ PRINT_TO_BUFFER(data, write_count, error, "before() {\n");
+ PRINT_TO_BUFFER(data, write_count, error, " [ -n \"$*\" ] && echo \"BEFORE $*\"; return 0\n");
+ PRINT_TO_BUFFER(data, write_count, error, "}\n\n");
+ PRINT_TO_BUFFER(data, write_count, error, "after() {\n");
+ PRINT_TO_BUFFER(data, write_count, error, " [ -n \"$*\" ] && echo \"AFTER $*\"; return 0\n");
+ PRINT_TO_BUFFER(data, write_count, error, "}\n\n");
+ PRINT_TO_BUFFER(data, write_count, error, "provide() {\n");
+ PRINT_TO_BUFFER(data, write_count, error, " [ -n \"$*\" ] && echo \"PROVIDE $*\"; return 0\n");
+ PRINT_TO_BUFFER(data, write_count, error, "}\n\n");
+
+ return write_count;
+
+error:
+ return -1;
+}
+
+size_t parse_print_header(char *scriptname, time_t mtime, char **data, size_t index) {
+ size_t write_count = index;
+
+ PRINT_TO_BUFFER(data, write_count, error, "#*** %s ***\n\n", scriptname);
+ PRINT_TO_BUFFER(data, write_count, error, "myservice=\"%s\"\n", scriptname);
+ PRINT_TO_BUFFER(data, write_count, error, "echo \"RCSCRIPT ${myservice}\"\n\n");
+ PRINT_TO_BUFFER(data, write_count, error, "echo \"MTIME %li\"\n\n", mtime);
+
+ return write_count;
+
+error:
+ return -1;
+}
+
+size_t parse_print_body(char *scriptname, char **data, size_t index) {
+ size_t write_count = index;
+ char *tmp_buf = NULL;
+ char *tmp_ptr;
+ char *base;
+ char *ext;
+
+ tmp_buf = strndup(scriptname, strlen(scriptname));
+ if (NULL == tmp_buf) {
+ DBG_MSG("Failed to allocate temporary buffer!\n");
+ goto error;
+ }
+
+ /*
+ * Rather do the next block in C than bash, in case we want to
+ * use ash or another shell in the place of bash
+ */
+
+ /* bash: base="${myservice%%.*}" */
+ base = tmp_buf;
+ tmp_ptr = strchr(tmp_buf, '.');
+ if (NULL != tmp_ptr) {
+ tmp_ptr[0] = '\0';
+ tmp_ptr++;
+ } else {
+ tmp_ptr = tmp_buf;
+ }
+ /* bash: ext="${myservice##*.}" */
+ ext = strrchr(tmp_ptr, '.');
+ if (NULL == ext)
+ ext = tmp_ptr;
+
+ PRINT_TO_BUFFER(data, write_count, error, "\n");
+ PRINT_TO_BUFFER(data, write_count, error, " # Get settings for rc-script ...\n");
+ PRINT_TO_BUFFER(data, write_count, error, " [ -e \"/etc/conf.d/${myservice}\" ] && \\\n");
+ PRINT_TO_BUFFER(data, write_count, error, " . \"/etc/conf.d/${myservice}\"\n");
+ PRINT_TO_BUFFER(data, write_count, error, " [ -e /etc/conf.d/net ] && \\\n");
+ PRINT_TO_BUFFER(data, write_count, error, " [ \"%s\" = \"net\" ] && \\\n", base);
+ PRINT_TO_BUFFER(data, write_count, error, " [ \"%s\" != \"${myservice}\" ] && \\\n", ext);
+ PRINT_TO_BUFFER(data, write_count, error, " . /etc/conf.d/net\n");
+ PRINT_TO_BUFFER(data, write_count, error, " depend() {\n");
+ PRINT_TO_BUFFER(data, write_count, error, " return 0\n");
+ PRINT_TO_BUFFER(data, write_count, error, " }\n\n");
+ PRINT_TO_BUFFER(data, write_count, error, " # Actual depend() function ...\n");
+
+ free(tmp_buf);
+
+ return write_count;
+
+error:
+ return -1;
+}
+
+size_t parse_print_end(char **data, size_t index) {
+ size_t write_count = index;
+
+ PRINT_TO_BUFFER(data, write_count, error, "\n");
+ PRINT_TO_BUFFER(data, write_count, error, " depend\n");
+ PRINT_TO_BUFFER(data, write_count, error, "\n\n");
+
+ return write_count;
+
+error:
+ return -1;
+}
+
diff --git a/src/core/parse.h b/src/core/parse.h
new file mode 100644
index 0000000..895fc6b
--- /dev/null
+++ b/src/core/parse.h
@@ -0,0 +1,110 @@
+/*
+ * parse.h
+ *
+ * Parser for Gentoo style rc-scripts.
+ *
+ * Copyright (C) 2004,2005 Martin Schlemmer <azarah@nosferatu.za.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Header$
+ */
+
+#ifndef _PARSE_H
+#define _PARSE_H
+
+#include <sys/types.h>
+#include "list.h"
+
+#define RC_CONF_FILE_NAME "/etc/rc.conf"
+#define RC_CONFD_FILE_NAME "/etc/conf.d/rc"
+#define INITD_DIR_NAME "/etc/init.d/"
+#define CONFD_DIR_NAME "/etc/conf.d/"
+
+#define SVCDIR_CONFIG_ENTRY "svcdir"
+
+#define SHELL_PARSER "/bin/bash"
+
+#define LEGACY_CACHE_FILE_NAME "deptree"
+
+#define FIELD_RCSCRIPT "RCSCRIPT"
+#define FIELD_NEED "NEED"
+#define FIELD_USE "USE"
+#define FIELD_BEFORE "BEFORE"
+#define FIELD_AFTER "AFTER"
+#define FIELD_PROVIDE "PROVIDE"
+#define FIELD_MTIME "MTIME"
+#define FIELD_FAILED "FAILED"
+
+typedef struct {
+ struct list_head node;
+
+ char *filename;
+ time_t mtime;
+ time_t confd_mtime;
+} rcscript_info_t;
+
+struct list_head rcscript_list;
+
+int get_rcscripts(void);
+int check_rcscripts_mtime(char *cachefile);
+size_t generate_stage1(char **data);
+size_t generate_stage2(char **data);
+size_t read_stage2(char **data);
+int write_stage2(FILE *outfile);
+size_t generate_stage3(char **data);
+size_t read_stage3(char **data);
+int write_stage3(FILE *outfile);
+int write_legacy_stage3(FILE *output);
+int parse_cache(const char *data, size_t lenght);
+
+/*
+ * get_rcscripts()
+ * |
+ * V
+ * check_rcscripts_mtime() ------------------------------> read_stage3()
+ * | |
+ * | |
+ * V V
+ * generate_stage1() (Called by generate_stage2()) parse_cache()
+ * | |
+ * | |
+ * V |
+ * generate_stage2() ----> write_stage2() (Debugging) |
+ * | |
+ * | |
+ * | === parse_cache() |
+ * V | | |
+ * generate_stage3() ==| | |
+ * | | | |
+ * | | V |
+ * | === service_resolve_dependencies() |
+ * | |
+ * | |
+ * |-------> write_legacy_stage3() (Proof of Concept |
+ * | or Debugging) |
+ * | |
+ * V |
+ * write_stage3() |
+ * | |
+ * | V
+ * |<-------------------------------------------------------
+ * |
+ * V
+ *
+ */
+
+#endif /* _PARSE_H */
+
diff --git a/src/core/simple-regex.c b/src/core/simple-regex.c
new file mode 100644
index 0000000..385f1f4
--- /dev/null
+++ b/src/core/simple-regex.c
@@ -0,0 +1,854 @@
+/*
+ * simple_regex.c
+ *
+ * Simle regex library.
+ *
+ * Copyright (C) 2004,2005 Martin Schlemmer <azarah@nosferatu.za.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Header$
+ */
+
+/*
+ * Some notes:
+ *
+ * - This is a very simple regex library (read: return a match if some string
+ * matches some regex). It is probably not POSIX (if there are a POSIX or
+ * other standard) compatible.
+ *
+ * - I primarily wrote it to _not_ use glibc type regex functions, in case we
+ * might want to use it in code that have to be linked agaist klibc, etc.
+ *
+ * - It really is not optimized in any way yet.
+ *
+ * - Supported operators are:
+ *
+ * '.', '?', '*', '+' - So called 'wildcards'
+ * '[a-z]', '[^a-z]' - Basic 'lists'. Note that 'a-z' just specify that
+ * it supports basic lists as well as sequences ..
+ * The '^' is for an inverted list of course.
+ * '^', '$' - The 'from start' and 'to end' operators. If these
+ * are not used at the start ('^') or end ('$') of the
+ * regex, they will be treated as normal characters
+ * (this of course exclude the use of '^' in a 'list').
+ *
+ * - If an invalid argument was passed, the functions returns 0 with
+ * 'regex_data-match == 0' (no error with no match) rather than -1. It may
+ * not be consistant with other practices, but I personally do not feel it is
+ * a critical error for these types of functions, and there are debugging you
+ * can enable to verify that there are no such issues.
+ *
+ * - __somefunction() is usually a helper function for somefunction(). I guess
+ * recursion might be an alternative, but I try to avoid it.
+ *
+ * - In general if we are matching a 'wildcard' ('*', '+' or '?'), a 'word'
+ * (read: some part of the regex that do not contain a 'wildcard' or 'list')
+ * will have a greater 'weight' than the 'wildcard'. This means that we
+ * will only continue to evaluate the 'wildcard' until the following 'word'
+ * (if any) matches. Currently this do not hold true for a 'list' not
+ * followed by a 'wildcard' - I might fix this in future.
+ *
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "debug.h"
+#include "misc.h"
+#include "simple-regex.h"
+
+/* Macro to check if a regex_data_t pointer is valid */
+#define CHECK_REGEX_DATA_P(_regex_data, _on_error) \
+ do { \
+ if ((NULL == _regex_data) || \
+ (NULL == _regex_data->data) || \
+ /* We do not check for this, as it might still \
+ * provide a match ('*' or '?' wildcard) */ \
+ /* (0 == strlen(_regex_data->data)) || */ \
+ (NULL == _regex_data->regex) || \
+ (0 == strlen(_regex_data->regex))) {\
+ DBG_MSG("Invalid argument passed!\n"); \
+ goto _on_error; \
+ } \
+ } while (0)
+
+size_t get_word(const char *regex, char **r_word);
+int match_word(regex_data_t *regex_data);
+size_t get_list_size(const char *regex);
+size_t get_list(const char *regex, char **r_list);
+int __match_list(regex_data_t *regex_data);
+int match_list(regex_data_t *regex_data);
+size_t get_wildcard(const char *regex, char *r_wildcard);
+int __match_wildcard(regex_data_t *regex_data,
+int (*match_func)(regex_data_t *regex_data), const char *regex);
+int match_wildcard(regex_data_t *regex_data);
+int __match(regex_data_t *regex_data);
+
+/*
+ * Return values for match_* functions
+ *
+ * 0 - There was no error. If there was a match, regex_data->match
+ * - will be > 0 (this is the definitive check - if not true, the
+ * - other values of the struct may be bogus), regex_data->count
+ * - will be the amount of data that was matched (might be 0 for
+ * - some wildcards), and regex_data->r_count will be > 0.
+ *
+ * -1 - An error occured. Check errno for more info.
+ *
+ */
+
+size_t get_word(const char *regex, char **r_word) {
+ char *r_list;
+ char *tmp_p;
+ size_t count = 0;
+ size_t tmp_count;
+
+ /* NULL string means we do not have a word */
+ if ((NULL == regex) || (0 == strlen(regex))) {
+ DBG_MSG("Invalid argument passed!\n");
+ return 0;
+ }
+
+ *r_word = malloc(strlen(regex) + 1);
+ if (NULL == r_word) {
+ DBG_MSG("Failed to allocate buffer!\n");
+ return 0;
+ }
+ tmp_p = *r_word;
+
+ while (strlen(regex) > 0) {
+ switch (regex[0]) {
+ case '*':
+ case '+':
+ case '?':
+ /* If its a wildcard, backup one step */
+ *--tmp_p = '\0';
+ count--;
+ return count;
+ case '[':
+ tmp_count = get_list(regex, &r_list);
+ free(r_list);
+ /* In theory should not happen, but you never know
+ * what may happen in future ... */
+ if (-1 == tmp_count)
+ goto error;
+
+ /* Bail if we have a list */
+ if (tmp_count > 0) {
+ tmp_p[0] = '\0';
+ return count;
+ }
+ default:
+ *tmp_p++ = *regex++;
+ count++;
+ break;
+ }
+ }
+
+ tmp_p[0] = '\0';
+
+ return count;
+
+error:
+ free(*r_word);
+
+ return -1;
+}
+
+int match_word(regex_data_t *regex_data) {
+ char *data_p = regex_data->data;
+ char *r_word = NULL, *r_word_p;
+ size_t count = 0;
+
+ CHECK_REGEX_DATA_P(regex_data, exit);
+
+ count = get_word(regex_data->regex, &r_word);
+ if (-1 == count)
+ goto error;
+ if (0 == count)
+ goto exit;
+ r_word_p = r_word;
+
+ while ((strlen(data_p) > 0) && (strlen(r_word_p) > 0 )) {
+ /* If 'r_word' is not 100% part of 'string', we do not have
+ * a match. If its a '.', it matches no matter what. */
+ if ((data_p[0] != r_word_p[0]) && (r_word_p[0] != '.')) {
+ count = 0;
+ goto exit;
+ }
+
+ data_p++;
+ r_word_p++;
+ }
+
+ /* If 'string' is shorter than 'r_word', we do not have a match */
+ if ((0 == strlen(data_p)) && (0 < strlen(r_word_p))) {
+ count = 0;
+ goto exit;
+ }
+
+exit:
+ /* Fill in our structure */
+ if (0 == count)
+ regex_data->match = REGEX_NO_MATCH;
+ else if (strlen(regex_data->data) == count)
+ regex_data->match = REGEX_FULL_MATCH;
+ else
+ regex_data->match = REGEX_PARTIAL_MATCH;
+ if (regex_data->match != REGEX_NO_MATCH)
+ regex_data->where = regex_data->data;
+ else
+ regex_data->where = NULL;
+ regex_data->count = count;
+ regex_data->r_count = count;
+
+ free(r_word);
+ return 0;
+
+error:
+ regex_data->match = REGEX_NO_MATCH;
+
+ free(r_word);
+ return -1;
+}
+
+size_t get_list_size(const char *regex) {
+ size_t count = 0;
+
+ /* NULL string means we do not have a list */
+ if ((NULL == regex) || (0 == strlen(regex)) || (regex[0] != '[')) {
+ DBG_MSG("Invalid argument passed!\n");
+ return 0;
+ }
+
+ regex++;
+
+ while ((strlen(regex) > 0) && (regex[0] != ']')) {
+ /* We have a sequence (x-y) */
+ if ((regex[0] == '-') && (regex[1] != ']') &&
+ (strlen(regex) >= 2) && (regex[-1] < regex[1]))
+ {
+ /* Add current + diff in sequence */
+ count += regex[1] - regex[-1];
+ /* Take care of '-' and next char */
+ regex += 2;
+ } else {
+ regex++;
+ count++;
+ }
+ }
+
+ return count;
+}
+
+size_t get_list(const char *regex, char **r_list) {
+ char *tmp_buf = NULL;
+ size_t count = 0;
+ size_t size;
+
+ /* NULL string means we do not have a list */
+ if ((NULL == regex) || (0 == strlen(regex))) {
+ DBG_MSG("Invalid argument passed!\n");
+ return 0;
+ }
+
+ /* Bail if we do not have a list. Do not add debugging, as
+ * it is very noisy (used a lot when we call match_list() in
+ * __match() and match() to test for list matching) */
+ if (regex[0] != '[')
+ return 0;
+
+ size = get_list_size(regex);
+ if (0 == size) {
+ /* Should not be an issue, but just in case */
+ DBG_MSG("0 returned by get_list_size.\n");
+ return 0;
+ }
+
+ *r_list = malloc(size + 1);
+ if (NULL == *r_list) {
+ DBG_MSG("Failed to allocate buffer!\n");
+ return -1;
+ }
+ tmp_buf = *r_list;
+
+ /* Take care of '[' */
+ regex++;
+ count++;
+
+ while ((strlen(regex) > 0) && (regex[0] != ']')) {
+ /* We have a sequence (x-y) */
+ if ((regex[0] == '-') && (regex[1] != ']') &&
+ (strlen(regex) >= 2) && (regex[-1] < regex[1]))
+ {
+
+ /* Fill in missing chars in sequence */
+ while (tmp_buf[-1] < regex[1]) {
+ tmp_buf[0] = (char)(tmp_buf[-1] + 1);
+ tmp_buf++;
+ /* We do not increase count */
+ }
+ /* Take care of '-' and next char */
+ count += 2;
+ regex += 2;
+ } else {
+ *tmp_buf++ = *regex++;
+ count++;
+ }
+ }
+
+ tmp_buf[0] = '\0';
+ /* Take care of ']' */
+ count++;
+
+ /* We do not have a list as it does not end in ']' */
+ if (regex[0] != ']') {
+ count = 0;
+ free(*r_list);
+ }
+
+ return count;
+}
+
+/* If the first is the '^' character, everything but the list is matched
+ * NOTE: We only evaluate _ONE_ data character at a time!! */
+int __match_list(regex_data_t *regex_data) {
+ regex_data_t tmp_data;
+ char *data_p = regex_data->data;
+ char *list_p = regex_data->regex;
+ char test_regex[2] = { '\0', '\0' };
+ int invert = 0;
+ int match;
+ int retval;
+
+ CHECK_REGEX_DATA_P(regex_data, failed);
+
+ if (list_p[0] == '^') {
+ /* We need to invert the match */
+ invert = 1;
+ /* Make sure '^' is not part of our list */
+ list_p++;
+ }
+
+ if (invert)
+ /* All should be a match if not in the list */
+ match = 1;
+ else
+ /* We only have a match if in the list */
+ match = 0;
+
+ while (strlen(list_p) > 0) {
+ test_regex[0] = list_p[0];
+
+ FILL_REGEX_DATA(tmp_data, data_p, test_regex);
+ retval = match_word(&tmp_data);
+ if (-1 == retval)
+ goto error;
+
+ if (REGEX_MATCH(tmp_data)) {
+ if (invert)
+ /* If we exclude the list from
+ * characters we try to match, we
+ * have a match until one of the
+ * list is found. */
+ match = 0;
+ else
+ /* If not, we have to keep looking
+ * until one from the list match
+ * before we have a match */
+ match = 1;
+ break;
+ }
+ list_p++;
+ }
+
+ /* Fill in our structure */
+ if (match) {
+ regex_data->match = REGEX_PARTIAL_MATCH;
+ regex_data->where = regex_data->data;
+ regex_data->count = 1;
+ /* This one is more cosmetic, as match_list() will
+ * do the right thing */
+ regex_data->r_count = 0; /* strlen(regex_data->regex); */
+ } else {
+failed:
+ regex_data->match = REGEX_NO_MATCH;
+ regex_data->where = NULL;
+ regex_data->count = 0;
+ regex_data->r_count = 0;
+ }
+
+ return 0;
+
+error:
+ regex_data->match = REGEX_NO_MATCH;
+
+ return -1;
+}
+
+int match_list(regex_data_t *regex_data) {
+ regex_data_t tmp_data;
+ char *data_p = regex_data->data;
+ char *list_p = regex_data->regex;
+ char *r_list = NULL;
+ size_t r_count = 0;
+ int retval;
+
+ CHECK_REGEX_DATA_P(regex_data, failed);
+
+ r_count = get_list(list_p, &r_list);
+ if (-1 == r_count)
+ goto error;
+ if (0 == r_count)
+ goto failed;
+
+ FILL_REGEX_DATA(tmp_data, data_p, &list_p[r_count-1]);
+ retval = __match_wildcard(&tmp_data, __match_list, r_list);
+ if (-1 == retval)
+ goto error;
+ if (REGEX_MATCH(tmp_data)) {
+ /* This should be 2 ('word' + 'wildcard'), so just remove
+ * the wildcard */
+ tmp_data.r_count--;
+ goto exit;
+ }
+
+ FILL_REGEX_DATA(tmp_data, data_p, r_list);
+ retval = __match_list(&tmp_data);
+ if (-1 == retval)
+ goto error;
+ if (REGEX_MATCH(tmp_data))
+ goto exit;
+
+failed:
+ /* We will fill in regex_data below */
+ tmp_data.match = REGEX_NO_MATCH;
+ tmp_data.where = NULL;
+ tmp_data.count = 0;
+ tmp_data.r_count = 0;
+
+exit:
+ /* Fill in our structure */
+ regex_data->match = tmp_data.match;
+ regex_data->where = tmp_data.where;
+ regex_data->count = tmp_data.count;
+ if (regex_data->match != REGEX_NO_MATCH)
+ /* tmp_data.r_count for __match_wildcard will take care of the
+ * wildcard, and tmp_data.r_count for __match_list will be 0 */
+ regex_data->r_count = r_count + tmp_data.r_count;
+ else
+ regex_data->r_count = 0;
+
+ free(r_list);
+ return 0;
+
+error:
+ regex_data->match = REGEX_NO_MATCH;
+
+ free(r_list);
+ return -1;
+}
+
+size_t get_wildcard(const char *regex, char *r_wildcard) {
+ /* NULL regex means we do not have a wildcard */
+ if ((NULL == regex) || (0 == strlen(regex))) {
+ DBG_MSG("Invalid argument passed!\n");
+ return 0;
+ }
+
+ r_wildcard[0] = regex[0];
+ r_wildcard[2] = '\0';
+
+ switch (regex[1]) {
+ case '*':
+ case '+':
+ case '?':
+ r_wildcard[1] = regex[1];
+ break;
+ default:
+ r_wildcard[0] = '\0';
+ return 0;
+ }
+
+ return strlen(r_wildcard);
+}
+
+int __match_wildcard(regex_data_t *regex_data, int (*match_func)(regex_data_t *regex_data), const char *regex) {
+ regex_data_t tmp_data;
+ char *data_p = regex_data->data;
+ char *wildcard_p = regex_data->regex;
+ char r_wildcard[3];
+ size_t count = 0;
+ size_t r_count = 0;
+ int is_match = 0;
+ int retval;
+
+ CHECK_REGEX_DATA_P(regex_data, exit);
+
+ if (NULL == match_func) {
+ DBG_MSG("NULL match_func was passed!\n");
+ goto exit;
+ }
+
+ r_count = get_wildcard(wildcard_p, r_wildcard);
+ if (0 == r_count)
+ goto exit;
+
+ FILL_REGEX_DATA(tmp_data, data_p, (char *)regex);
+ retval = match_func(&tmp_data);
+ if (-1 == retval)
+ goto error;
+
+ switch (r_wildcard[1]) {
+ case '*':
+ case '?':
+ /* '*' and '?' always matches */
+ is_match = 1;
+ case '+':
+ /* We need to match all of them */
+ do {
+ /* If we have at least one match for '+', or none
+ * for '*' or '?', check if we have a word or list match.
+ * We do this because a word weights more than a wildcard */
+ if ((strlen(wildcard_p) > 2) && ((count > 0) ||
+ (r_wildcard[1] == '*') || (r_wildcard[1] == '?')))
+ {
+ regex_data_t tmp_data2;
+#if 0
+ printf("data_p = %s, wildcard_p = %s\n", data_p, wildcard_p);
+#endif
+
+ FILL_REGEX_DATA(tmp_data2, data_p, &wildcard_p[2]);
+ retval = match(&tmp_data2);
+ if (-1 == retval)
+ goto error;
+
+ if (/* '.' might be a special case ... */
+ /* (wildcard_p[2] != '.') && */
+ (REGEX_MATCH(tmp_data2) &&
+ (REGEX_FULL_MATCH == tmp_data2.match))) {
+ goto exit;
+ }
+ }
+
+ if (REGEX_MATCH(tmp_data)) {
+ data_p += tmp_data.count;
+ count += tmp_data.count;
+ is_match = 1;
+
+ FILL_REGEX_DATA(tmp_data, data_p, (char *)regex);
+ retval = match_func(&tmp_data);
+ if (-1 == retval)
+ goto error;
+ }
+ /* Only once for '?' */
+ } while ((REGEX_MATCH(tmp_data)) && (r_wildcard[1] != '?'));
+
+ break;
+ default:
+ /* No wildcard */
+ break;
+ }
+
+exit:
+ /* Fill in our structure */
+ /* We can still have a match ('*' and '?'), although count == 0 */
+ if ((0 == count) && (0 == is_match))
+ regex_data->match = REGEX_NO_MATCH;
+ else if (strlen(regex_data->data) == count)
+ regex_data->match = REGEX_FULL_MATCH;
+ else
+ regex_data->match = REGEX_PARTIAL_MATCH;
+ if (regex_data->match != REGEX_NO_MATCH)
+ regex_data->where = regex_data->data;
+ else
+ regex_data->where = NULL;
+ regex_data->count = count;
+ regex_data->r_count = r_count;
+
+ return 0;
+
+error:
+ regex_data->match = REGEX_NO_MATCH;
+
+ return -1;
+}
+
+int match_wildcard(regex_data_t *regex_data) {
+ regex_data_t tmp_data;
+ char *data_p = regex_data->data;
+ char *wildcard_p = regex_data->regex;
+ char r_wildcard[3];
+ size_t r_count;
+ int retval;
+
+ CHECK_REGEX_DATA_P(regex_data, failed);
+
+ /* Invalid wildcard - we need a character + a regex operator */
+ if (strlen(wildcard_p) < 2)
+ goto failed;
+
+ r_count = get_wildcard(wildcard_p, r_wildcard);
+ if (0 == r_count)
+ goto failed;
+
+ /* Needed so that match_word() will not bail if it sees the wildcard */
+ r_wildcard[1] = '\0';
+
+ FILL_REGEX_DATA(tmp_data, data_p, wildcard_p);
+ retval = __match_wildcard(&tmp_data, match_word, r_wildcard);
+ if (-1 == retval)
+ goto error;
+ if (REGEX_MATCH(tmp_data))
+ goto exit;
+
+failed:
+ /* We will fill in regex_data below */
+ tmp_data.match = REGEX_NO_MATCH;
+ tmp_data.where = NULL;
+ tmp_data.count = 0;
+ tmp_data.r_count = 0;
+
+exit:
+ /* Fill in our structure */
+ regex_data->match = tmp_data.match;
+ regex_data->where = tmp_data.where;
+ regex_data->count = tmp_data.count;
+ regex_data->r_count = tmp_data.r_count;
+
+ return 0;
+
+error:
+ regex_data->match = REGEX_NO_MATCH;
+
+ return -1;
+}
+
+int __match(regex_data_t *regex_data) {
+ regex_data_t tmp_data;
+ char *data_p = regex_data->data;
+ char *regex_p = regex_data->regex;
+ size_t count = 0;
+ size_t r_count = 0;
+ int match = 0;
+ int retval;
+
+ CHECK_REGEX_DATA_P(regex_data, failed);
+
+ while (strlen(regex_p) > 0) {
+#if 0
+ printf("data_p = '%s', regex_p = '%s'\n", data_p, regex_p);
+#endif
+
+ FILL_REGEX_DATA(tmp_data, data_p, regex_p);
+ retval = match_list(&tmp_data);
+ if (-1 == retval)
+ goto error;
+ if (REGEX_MATCH(tmp_data))
+ goto match;
+
+ FILL_REGEX_DATA(tmp_data, data_p, regex_p);
+ retval = match_wildcard(&tmp_data);
+ if (-1 == retval)
+ goto error;
+ if (REGEX_MATCH(tmp_data))
+ goto match;
+
+ FILL_REGEX_DATA(tmp_data, data_p, regex_p);
+ retval = match_word(&tmp_data);
+ if (-1 == retval)
+ goto error;
+ if (REGEX_MATCH(tmp_data))
+ goto match;
+
+ break;
+
+match:
+ data_p += tmp_data.count;
+ count += tmp_data.count;
+ regex_p += tmp_data.r_count;
+ r_count += tmp_data.r_count;
+ match = 1;
+
+ /* Check that we do not go out of bounds */
+ if (((data_p - regex_data->data) > strlen(regex_data->data)) ||
+ ((regex_p - regex_data->regex) > strlen(regex_data->regex)))
+ goto failed;
+ }
+
+ /* We could not match the whole regex (data too short?) */
+ if (0 != strlen(regex_p))
+ goto failed;
+
+ goto exit;
+
+failed:
+ /* We will fill in regex_data below */
+ count = 0;
+ r_count = 0;
+ match = 0;
+
+exit:
+ /* Fill in our structure */
+ /* We can still have a match ('*' and '?'), although count == 0 */
+ if ((0 == count) && (0 == match))
+ regex_data->match = REGEX_NO_MATCH;
+ else if (strlen(regex_data->data) == count)
+ regex_data->match = REGEX_FULL_MATCH;
+ else
+ regex_data->match = REGEX_PARTIAL_MATCH;
+ if (regex_data->match != REGEX_NO_MATCH)
+ regex_data->where = regex_data->data;
+ else
+ regex_data->where = NULL;
+ regex_data->count = count;
+ regex_data->r_count = r_count;
+
+ return 0;
+
+error:
+ regex_data->match = REGEX_NO_MATCH;
+
+ return -1;
+}
+
+int match(regex_data_t *regex_data) {
+ regex_data_t tmp_data;
+ char *data_p = regex_data->data;
+ char *regex_p;
+ char *tmp_buf = NULL;
+ int from_start = 0;
+ int to_end = 0;
+ int retval;
+
+ CHECK_REGEX_DATA_P(regex_data, failed);
+
+ /* We might be modifying regex_p, so make a copy */
+ tmp_buf = strndup(regex_data->regex, strlen(regex_data->regex));
+ if (NULL == tmp_buf) {
+ DBG_MSG("Failed to allocate temporary buffer!\n");
+ goto error;
+ }
+ regex_p = tmp_buf;
+
+ /* Should we only match from the start? */
+ if (regex_p[0] == '^') {
+ regex_p++;
+ from_start = 1;
+ }
+
+ /* Should we match up to the end? */
+ if (regex_p[strlen(regex_p) - 1] == '$') {
+ regex_p[strlen(regex_p) - 1] = '\0';
+ to_end = 1;
+ }
+
+ do {
+ FILL_REGEX_DATA(tmp_data, data_p, regex_p);
+ retval = __match(&tmp_data);
+ if (-1 == retval)
+ goto error;
+ } while ((strlen(data_p++) > 0) &&
+ (!REGEX_MATCH(tmp_data)) && (0 == from_start));
+
+ /* Compensate for above extra inc */
+ data_p--;
+
+ /* Fill in our structure */
+ if (REGEX_MATCH(tmp_data)) {
+ /* Check if we had an '$' at the end of the regex, and
+ * verify that we still have a match */
+ if ((1 == to_end) && (tmp_data.count != strlen(data_p))) {
+ goto failed;
+ }
+
+ if ((data_p == regex_data->data) &&
+ (tmp_data.match == REGEX_FULL_MATCH))
+ regex_data->match = REGEX_FULL_MATCH;
+ else
+ regex_data->match = REGEX_PARTIAL_MATCH;
+ regex_data->where = data_p;
+ regex_data->count = tmp_data.count;
+ regex_data->r_count = tmp_data.r_count;
+ if (1 == from_start)
+ regex_data->r_count++;
+ if (1 == to_end)
+ regex_data->r_count++;
+ } else {
+failed:
+ regex_data->match = REGEX_NO_MATCH;
+ regex_data->where = NULL;
+ regex_data->count = 0;
+ regex_data->r_count = 0;
+ }
+
+ free(tmp_buf);
+
+ return 0;
+
+error:
+ regex_data->match = REGEX_NO_MATCH;
+ free(tmp_buf);
+
+ return -1;
+}
+
+#if 0
+int main() {
+ regex_data_t tmp_data;
+ FILE *rcscript;
+ char regex[] = "^[ \t]*[d-p]+d[ \t]*(+)[ \t]*{$";
+ char tempstr[255];
+ int retval;
+
+ rcscript = fopen("acpid", "r");
+ if (NULL == rcscript) {
+ printf("%s", "Error opening file!");
+ return 1;
+ }
+
+ while (0 != fgets(tempstr, 254, rcscript)) {
+ if (tempstr[strlen(tempstr) - 1] == '\n')
+ tempstr[strlen(tempstr) - 1] = '\0';
+
+ FILL_REGEX_DATA(tmp_data, tempstr, regex);
+ retval = match(&tmp_data);
+ if (-1 != retval) {
+ if (REGEX_MATCH(tmp_data)) {
+ printf("*** string = '%s' ***\n", tempstr);
+ printf("*** regex = '%s' ***\n", regex);
+
+ if (REGEX_FULL_MATCH == tmp_data.match)
+ printf("match (full): '%s', %i\n", tmp_data.where, tmp_data.count);
+ else
+ printf("match: '%s', %i\n", tmp_data.where, tmp_data.count);
+
+ } else {
+ printf("%s", "No match\n");
+ }
+ } else {
+ printf("%s", "Error during match\n");
+ }
+ }
+
+ fclose(rcscript);
+
+ return 0;
+}
+#endif
+
diff --git a/src/core/simple-regex.h b/src/core/simple-regex.h
new file mode 100644
index 0000000..affa312
--- /dev/null
+++ b/src/core/simple-regex.h
@@ -0,0 +1,86 @@
+/*
+ * simple_regex.h
+ *
+ * Simle regex library.
+ *
+ * Copyright (C) 2004,2005 Martin Schlemmer <azarah@nosferatu.za.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Header$
+ */
+
+#ifndef _SIMPLE_REGEX_H
+#define _SIMPLE_REGEX_H
+
+#define REGEX_NO_MATCH 0 /* We have no match */
+#define REGEX_PARTIAL_MATCH 1 /* Some of the string matches the regex */
+#define REGEX_FULL_MATCH 2 /* The whole string matches the regex */
+
+/* Macro to fill in .data and .regex */
+#define FILL_REGEX_DATA(_regex_data, _string, _regex) \
+ do { \
+ _regex_data.data = _string; \
+ _regex_data.regex = _regex; \
+ } while (0)
+
+/* Fill in _regex_data with _data and _regex, on failure goto _error */
+#define DO_REGEX(_regex_data, _data, _regex, _error) \
+ do { \
+ FILL_REGEX_DATA(_regex_data, _data, _regex); \
+ if (-1 == match(&_regex_data)) { \
+ DBG_MSG("Could not do regex match!\n"); \
+ goto _error; \
+ } \
+ } while (0)
+
+/* Evaluate to true if we have some kind of match */
+#define REGEX_MATCH(_regex_data) \
+ ((REGEX_FULL_MATCH == _regex_data.match) || \
+ (REGEX_PARTIAL_MATCH == _regex_data.match))
+
+/* Same as above, but for use when _regex_data is a pointer */
+#define REGEX_MATCH_P(_regex_data) \
+ ((REGEX_FULL_MATCH == _regex_data->match) || \
+ (REGEX_PARTIAL_MATCH == _regex_data->match))
+
+typedef struct {
+ char *data; /* String to perform regex operation on */
+ char *regex; /* String containing regex to use */
+ int match; /* Will be set if there was a match. Check
+ * REGEX_*_MATCH above for possible values */
+ char *where; /* Pointer to where match starts in data */
+ size_t count; /* Count characters from data matched by regex */
+ size_t r_count; /* Count characters of regex used for match. This
+ * should normally be the lenght of regex, but might
+ * not be for some internal functions ... */
+} regex_data_t;
+
+/*
+ * Return:
+ *
+ * 0 - There was no error. If there was a match, regex_data->match
+ * - will be > 0 (this is the definitive check - if not true, the
+ * - other values of the struct may be bogus), regex_data->count
+ * - will be the amount of data that was matched (might be 0 for
+ * - some wildcards), and regex_data->r_count will be > 0.
+ *
+ * -1 - An error occured. Check errno for more info.
+ *
+ */
+int match(regex_data_t *regex_data);
+
+#endif /* _SIMPLE_REGEX_H */
+
diff --git a/src/core/test-regex.c b/src/core/test-regex.c
new file mode 100644
index 0000000..610a490
--- /dev/null
+++ b/src/core/test-regex.c
@@ -0,0 +1,80 @@
+/*
+ * test-regex.c
+ *
+ * Test for the simple-regex module.
+ *
+ * Copyright (C) 2004,2005 Martin Schlemmer <azarah@nosferatu.za.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Header$
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "debug.h"
+#include "simple-regex.h"
+
+char *test_data[] = {
+ /* string, pattern, match (1 = yes, 0 = no) */
+ "ab", "a?[ab]b", "1",
+ "abb", "a?[ab]b", "1",
+ "aab", "a?[ab]b", "1",
+ "a", "a?a?a?a", "1",
+ "aa", "a?a?a?a", "1",
+ "aa", "a?a?a?aa", "1",
+ "aaa", "a?a?a?aa", "1",
+ "ab", "[ab]*", "1",
+ "abc", "[ab]*.", "1",
+ "ab", "[ab]*b+", "1",
+ "ab", "a?[ab]*b+", "1",
+ "aaaaaaaaaaaaaaaaaaaaaaa", "a*b", "0",
+ "aaaaaaaaabaaabbaaaaaa", "a*b+a*b*ba+", "1",
+ "ababababab", "a.*", "1",
+ "baaaaaaaab", "a*", "0",
+ NULL
+};
+
+int main() {
+ regex_data_t tmp_data;
+ char buf[256], string[100], regex[100];
+ int i;
+
+ for (i = 0; NULL != test_data[i]; i += 3) {
+ snprintf(string, 99, "'%s'", test_data[i]);
+ snprintf(regex, 99, "'%s'", test_data[i + 1]);
+ snprintf(buf, 255, "string = %s, pattern = %s", string, regex);
+ printf("%-60s", buf);
+ DO_REGEX(tmp_data, test_data[i], test_data[i + 1], error);
+ if (REGEX_MATCH(tmp_data) && (REGEX_FULL_MATCH == tmp_data.match)) {
+ if (0 != strncmp(test_data[i + 2], "1", 1))
+ goto error;
+ } else {
+ if (0 != strncmp(test_data[i + 2], "0", 1))
+ goto error;
+ }
+
+ printf("%s\n", "[ \033[32;01mOK\033[0m ]");
+ }
+
+ return 0;
+error:
+ printf("%s\n", "[ \033[31;01m!!\033[0m ]");
+
+ return 1;
+}
diff --git a/src/env_whitelist b/src/env_whitelist
new file mode 100644
index 0000000..00ea17a
--- /dev/null
+++ b/src/env_whitelist
@@ -0,0 +1,26 @@
+# /lib/rcscripts/conf.d/env_whitelist: 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_BACKGROUND
+IN_HOTPLUG
+
+# Default shell stuff
+SHELL
+USER
+HOME
+
+# From /sbin/init
+PATH
+INIT_VERSION
+RUNLEVEL
+PREVLEVEL
+CONSOLE
+
diff --git a/src/filefuncs/Makefile b/src/filefuncs/Makefile
new file mode 100644
index 0000000..4d35197
--- /dev/null
+++ b/src/filefuncs/Makefile
@@ -0,0 +1,17 @@
+CC = gcc
+LD = gcc
+
+TARGETS = filefuncs.so
+
+all: $(TARGETS)
+
+filefuncs.o: filefuncs.c
+ $(CC) -shared -Wall -DHAVE_CONFIG_H -c -O -fPIC -I/usr/include/awk $^
+
+filefuncs.so: filefuncs.o
+ $(LD) -o $@ -shared $^
+
+clean:
+ rm -f $(TARGETS)
+ rm -f *.o *~ core
+
diff --git a/src/filefuncs/filefuncs.c b/src/filefuncs/filefuncs.c
new file mode 100644
index 0000000..8f3cc34
--- /dev/null
+++ b/src/filefuncs/filefuncs.c
@@ -0,0 +1,486 @@
+/*
+ * filefuncs.c - Builtin functions that provide initial minimal iterface
+ * to the file system.
+ *
+ * Arnold Robbins, update for 3.1, Mon Nov 23 12:53:39 EST 1998
+ */
+
+/*
+ * Copyright (C) 2001 the Free Software Foundation, Inc.
+ *
+ * This file is part of GAWK, the GNU implementation of the
+ * AWK Programming Language.
+ *
+ * GAWK is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GAWK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+/*
+ * Copyright 1999-2004 Gentoo Foundation
+ * Distributed under the terms of the GNU General Public License v2
+ * Author: Martin Schlemmer <azarah@gentoo.org>, Nov 2002
+ * $Header$
+ *
+ * Extended with: do_symlink()
+ * do_unlink()
+ * do_mkdir()
+ * do_rmdir()
+ *
+ * for use in the Gentoo rcscripts
+ *
+ */
+
+#include "awk.h"
+
+#include <unistd.h>
+#include <sys/sysmacros.h>
+
+/* do_chdir --- provide dynamically loaded chdir() builtin for gawk */
+
+static NODE *
+do_chdir(tree)
+NODE *tree;
+{
+ NODE *newdir;
+ int ret = -1;
+
+ if (do_lint && tree->param_cnt > 1)
+ lintwarn("chdir: called with too many arguments");
+
+ newdir = get_argument(tree, 0);
+ if (newdir != NULL) {
+ (void) force_string(newdir);
+ ret = chdir(newdir->stptr);
+ if (ret < 0)
+ update_ERRNO();
+
+ free_temp(newdir);
+ } else if (do_lint)
+ lintwarn("chdir: called with no arguments");
+
+
+ /* Set the return value */
+ set_value(tmp_number((AWKNUM) ret));
+
+ /* Just to make the interpreter happy */
+ return tmp_number((AWKNUM) 0);
+}
+
+/* do_symlink --- provide dynamically loaded symlink() builtin for gawk */
+
+static NODE *
+do_symlink(tree)
+NODE *tree;
+{
+ NODE *oldpath, *newpath;
+ int ret = -1;
+
+ if (do_lint && tree->param_cnt > 2)
+ lintwarn("symlink: called with too many arguments");
+
+ oldpath = get_argument(tree, 0);
+ newpath = get_argument(tree, 1);
+ if ((oldpath != NULL) && (newpath)) {
+ (void) force_string(oldpath);
+ (void) force_string(newpath);
+ ret = symlink(oldpath->stptr, newpath->stptr);
+ if (ret < 0)
+ update_ERRNO();
+
+ free_temp(oldpath);
+ free_temp(newpath);
+ } else if (do_lint)
+ lintwarn("symlink: called with not enough arguments");
+
+ /* Set the return value */
+ set_value(tmp_number((AWKNUM) ret));
+
+ /* Just to make the interpreter happy */
+ return tmp_number((AWKNUM) 0);
+}
+
+/* do_unlink --- provide dynamically loaded unlink() builtin for gawk */
+
+static NODE *
+do_unlink(tree)
+NODE *tree;
+{
+ NODE *pathname;
+ int ret = -1;
+
+ if (do_lint && tree->param_cnt > 1)
+ lintwarn("unlink: called with too many arguments");
+
+ pathname = get_argument(tree, 0);
+ if (pathname != NULL) {
+ (void) force_string(pathname);
+ ret = unlink(pathname->stptr);
+ if (ret < 0)
+ update_ERRNO();
+
+ free_temp(pathname);
+ } else if (do_lint)
+ lintwarn("unlink: called with no arguments");
+
+ /* Set the return value */
+ set_value(tmp_number((AWKNUM) ret));
+
+ /* Just to make the interpreter happy */
+ return tmp_number((AWKNUM) 0);
+}
+
+/* do_mkdir --- provide dynamically loaded mkdir() builtin for gawk */
+
+static NODE *
+do_mkdir(tree)
+NODE *tree;
+{
+ NODE *pathname, *mode;
+ int ret = -1;
+
+ if (do_lint && tree->param_cnt > 2)
+ lintwarn("mkdir: called with too many arguments");
+
+ pathname = get_argument(tree, 0);
+ mode = get_argument(tree, 1);
+ if ((pathname != NULL) && (mode != NULL)) {
+ (void) force_string(pathname);
+ (void) force_number(mode);
+ ret = mkdir(pathname->stptr, mode->numbr);
+ if (ret < 0)
+ update_ERRNO();
+
+ free_temp(pathname);
+ free_temp(mode);
+ } else if (do_lint)
+ lintwarn("mkdir: called with not enough arguments");
+
+ /* Set the return value */
+ set_value(tmp_number((AWKNUM) ret));
+
+ /* Just to make the interpreter happy */
+ return tmp_number((AWKNUM) 0);
+}
+
+/* do_rmdir --- provide dynamically loaded rmdir() builtin for gawk */
+
+static NODE *
+do_rmdir(tree)
+NODE *tree;
+{
+ NODE *pathname;
+ int ret = -1;
+
+ if (do_lint && tree->param_cnt > 1)
+ lintwarn("rmdir: called with too many arguments");
+
+ pathname = get_argument(tree, 0);
+ if (pathname != NULL) {
+ (void) force_string(pathname);
+ ret = rmdir(pathname->stptr);
+ if (ret < 0)
+ update_ERRNO();
+
+ free_temp(pathname);
+ } else if (do_lint)
+ lintwarn("rmdir: called with no arguments");
+
+ /* Set the return value */
+ set_value(tmp_number((AWKNUM) ret));
+
+ /* Just to make the interpreter happy */
+ return tmp_number((AWKNUM) 0);
+}
+
+/* format_mode --- turn a stat mode field into something readable */
+
+static char *
+format_mode(fmode)
+unsigned long fmode;
+{
+ static char outbuf[12];
+ int i;
+
+ strcpy(outbuf, "----------");
+ /* first, get the file type */
+ i = 0;
+ switch (fmode & S_IFMT) {
+#ifdef S_IFSOCK
+ case S_IFSOCK:
+ outbuf[i] = 's';
+ break;
+#endif
+#ifdef S_IFLNK
+ case S_IFLNK:
+ outbuf[i] = 'l';
+ break;
+#endif
+ case S_IFREG:
+ outbuf[i] = '-'; /* redundant */
+ break;
+ case S_IFBLK:
+ outbuf[i] = 'b';
+ break;
+ case S_IFDIR:
+ outbuf[i] = 'd';
+ break;
+#ifdef S_IFDOOR /* Solaris weirdness */
+ case S_IFDOOR:
+ outbuf[i] = 'D';
+ break;
+#endif /* S_IFDOOR */
+ case S_IFCHR:
+ outbuf[i] = 'c';
+ break;
+#ifdef S_IFIFO
+ case S_IFIFO:
+ outbuf[i] = 'p';
+ break;
+#endif
+ }
+
+ i++;
+ if ((fmode & S_IRUSR) != 0)
+ outbuf[i] = 'r';
+ i++;
+ if ((fmode & S_IWUSR) != 0)
+ outbuf[i] = 'w';
+ i++;
+ if ((fmode & S_IXUSR) != 0)
+ outbuf[i] = 'x';
+ i++;
+
+ if ((fmode & S_IRGRP) != 0)
+ outbuf[i] = 'r';
+ i++;
+ if ((fmode & S_IWGRP) != 0)
+ outbuf[i] = 'w';
+ i++;
+ if ((fmode & S_IXGRP) != 0)
+ outbuf[i] = 'x';
+ i++;
+
+ if ((fmode & S_IROTH) != 0)
+ outbuf[i] = 'r';
+ i++;
+ if ((fmode & S_IWOTH) != 0)
+ outbuf[i] = 'w';
+ i++;
+ if ((fmode & S_IXOTH) != 0)
+ outbuf[i] = 'x';
+ i++;
+
+ outbuf[i] = '\0';
+
+ if ((fmode & S_ISUID) != 0) {
+ if (outbuf[3] == 'x')
+ outbuf[3] = 's';
+ else
+ outbuf[3] = 'S';
+ }
+
+ /* setgid without execute == locking */
+ if ((fmode & S_ISGID) != 0) {
+ if (outbuf[6] == 'x')
+ outbuf[6] = 's';
+ else
+ outbuf[6] = 'l';
+ }
+
+ if ((fmode & S_ISVTX) != 0) {
+ if (outbuf[9] == 'x')
+ outbuf[9] = 't';
+ else
+ outbuf[9] = 'T';
+ }
+
+ return outbuf;
+}
+
+/* do_stat --- provide a stat() function for gawk */
+
+static NODE *
+do_stat(tree)
+NODE *tree;
+{
+ NODE *file, *array;
+ struct stat sbuf;
+ int ret;
+ NODE **aptr;
+ char *pmode; /* printable mode */
+ char *type = "unknown";
+
+ /* check arg count */
+ if (tree->param_cnt != 2)
+ fatal(
+ "stat: called with incorrect number of arguments (%d), should be 2",
+ tree->param_cnt);
+
+ /* directory is first arg, array to hold results is second */
+ file = get_argument(tree, 0);
+ array = get_argument(tree, 1);
+
+ /* empty out the array */
+ assoc_clear(array);
+
+ /* lstat the file, if error, set ERRNO and return */
+ (void) force_string(file);
+ ret = lstat(file->stptr, & sbuf);
+ if (ret < 0) {
+ update_ERRNO();
+
+ set_value(tmp_number((AWKNUM) ret));
+
+ free_temp(file);
+ return tmp_number((AWKNUM) 0);
+ }
+
+ /* fill in the array */
+ aptr = assoc_lookup(array, tmp_string("name", 4), FALSE);
+ *aptr = dupnode(file);
+
+ aptr = assoc_lookup(array, tmp_string("dev", 3), FALSE);
+ *aptr = make_number((AWKNUM) sbuf.st_dev);
+
+ aptr = assoc_lookup(array, tmp_string("ino", 3), FALSE);
+ *aptr = make_number((AWKNUM) sbuf.st_ino);
+
+ aptr = assoc_lookup(array, tmp_string("mode", 4), FALSE);
+ *aptr = make_number((AWKNUM) sbuf.st_mode);
+
+ aptr = assoc_lookup(array, tmp_string("nlink", 5), FALSE);
+ *aptr = make_number((AWKNUM) sbuf.st_nlink);
+
+ aptr = assoc_lookup(array, tmp_string("uid", 3), FALSE);
+ *aptr = make_number((AWKNUM) sbuf.st_uid);
+
+ aptr = assoc_lookup(array, tmp_string("gid", 3), FALSE);
+ *aptr = make_number((AWKNUM) sbuf.st_gid);
+
+ aptr = assoc_lookup(array, tmp_string("size", 4), FALSE);
+ *aptr = make_number((AWKNUM) sbuf.st_size);
+
+ aptr = assoc_lookup(array, tmp_string("blocks", 6), FALSE);
+ *aptr = make_number((AWKNUM) sbuf.st_blocks);
+
+ aptr = assoc_lookup(array, tmp_string("atime", 5), FALSE);
+ *aptr = make_number((AWKNUM) sbuf.st_atime);
+
+ aptr = assoc_lookup(array, tmp_string("mtime", 5), FALSE);
+ *aptr = make_number((AWKNUM) sbuf.st_mtime);
+
+ aptr = assoc_lookup(array, tmp_string("ctime", 5), FALSE);
+ *aptr = make_number((AWKNUM) sbuf.st_ctime);
+
+ /* for block and character devices, add rdev, major and minor numbers */
+ if (S_ISBLK(sbuf.st_mode) || S_ISCHR(sbuf.st_mode)) {
+ aptr = assoc_lookup(array, tmp_string("rdev", 4), FALSE);
+ *aptr = make_number((AWKNUM) sbuf.st_rdev);
+
+ aptr = assoc_lookup(array, tmp_string("major", 5), FALSE);
+ *aptr = make_number((AWKNUM) major(sbuf.st_rdev));
+
+ aptr = assoc_lookup(array, tmp_string("minor", 5), FALSE);
+ *aptr = make_number((AWKNUM) minor(sbuf.st_rdev));
+ }
+
+#ifdef HAVE_ST_BLKSIZE
+ aptr = assoc_lookup(array, tmp_string("blksize", 7), FALSE);
+ *aptr = make_number((AWKNUM) sbuf.st_blksize);
+#endif /* HAVE_ST_BLKSIZE */
+
+ aptr = assoc_lookup(array, tmp_string("pmode", 5), FALSE);
+ pmode = format_mode(sbuf.st_mode);
+ *aptr = make_string(pmode, strlen(pmode));
+
+ /* for symbolic links, add a linkval field */
+ if (S_ISLNK(sbuf.st_mode)) {
+ char buf[BUFSIZ*2];
+ int linksize;
+
+ linksize = readlink(file->stptr, buf, sizeof buf);
+ /* should make this smarter */
+ if (linksize == sizeof(buf))
+ fatal("size of symbolic link too big");
+ buf[linksize] = '\0';
+
+ aptr = assoc_lookup(array, tmp_string("linkval", 7), FALSE);
+ *aptr = make_string(buf, linksize);
+ }
+
+ /* add a type field */
+ switch (sbuf.st_mode & S_IFMT) {
+#ifdef S_IFSOCK
+ case S_IFSOCK:
+ type = "socket";
+ break;
+#endif
+#ifdef S_IFLNK
+ case S_IFLNK:
+ type = "symlink";
+ break;
+#endif
+ case S_IFREG:
+ type = "file";
+ break;
+ case S_IFBLK:
+ type = "blockdev";
+ break;
+ case S_IFDIR:
+ type = "directory";
+ break;
+#ifdef S_IFDOOR
+ case S_IFDOOR:
+ type = "door";
+ break;
+#endif
+ case S_IFCHR:
+ type = "chardev";
+ break;
+#ifdef S_IFIFO
+ case S_IFIFO:
+ type = "fifo";
+ break;
+#endif
+ }
+
+ aptr = assoc_lookup(array, tmp_string("type", 4), FALSE);
+ *aptr = make_string(type, strlen(type));
+
+ free_temp(file);
+
+ /* Set the return value */
+ set_value(tmp_number((AWKNUM) ret));
+
+ /* Just to make the interpreter happy */
+ return tmp_number((AWKNUM) 0);
+}
+
+/* dlload --- load new builtins in this library */
+
+NODE *
+dlload(tree, dl)
+NODE *tree;
+void *dl;
+{
+ make_builtin("chdir", do_chdir, 1);
+ make_builtin("symlink", do_symlink, 2);
+ make_builtin("unlink", do_unlink, 1);
+ make_builtin("mkdir", do_mkdir, 2);
+ make_builtin("rmdir", do_rmdir, 1);
+ make_builtin("stat", do_stat, 2);
+
+ return tmp_number((AWKNUM) 0);
+}
+
diff --git a/src/headers.h b/src/headers.h
new file mode 100644
index 0000000..09f07a1
--- /dev/null
+++ b/src/headers.h
@@ -0,0 +1,26 @@
+/*
+ * header.h
+ * Dirty little file to include header files w/out autotools.
+ *
+ * Copyright 1999-2004 Gentoo Foundation
+ * Distributed under the terms of the GNU General Public License v2
+ * $Header$
+ */
+
+/* Common includes */
+#define HAVE_TIOCNOTTY
+#define HAVE_SETSID
+
+/* OS-specific includes */
+#if defined(__GLIBC__)
+# define HAVE_SYS_SYSMACROS_H
+# define HAVE_ERROR_H
+#endif
+
+/* Now we actually include crap ;) */
+#ifdef HAVE_ERROR_H
+# include <error.h>
+#endif
+#ifdef HAVE_SYS_SYSMACROS_H
+# include <sys/sysmacros.h>
+#endif
diff --git a/src/runscript.c b/src/runscript.c
new file mode 100644
index 0000000..61b43bf
--- /dev/null
+++ b/src/runscript.c
@@ -0,0 +1,250 @@
+/*
+ * runscript.c
+ * Handle launching of Gentoo init scripts.
+ *
+ * Copyright 1999-2004 Gentoo Foundation
+ * Distributed under the terms of the GNU General Public License v2
+ * $Header$
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <dlfcn.h>
+
+#include "core/debug.h"
+#include "core/misc.h"
+
+#ifndef LIBDIR
+# define LIBDIR "lib"
+#endif
+
+#define SBIN_RC "/sbin/rc"
+#define PROFILE_ENV "/etc/profile.env"
+#define RCSCRIPTS_LIB "/" LIBDIR "/rcscripts"
+#define SYS_WHITELIST RCSCRIPTS_LIB "/conf.d/env_whitelist"
+#define USR_WHITELIST "/etc/conf.d/env_whitelist"
+#define RCSCRIPT_HELP RCSCRIPTS_LIB "/sh/rc-help.sh"
+#define SELINUX_LIB RCSCRIPTS_LIB "/runscript_selinux.so"
+#define SOFTLEVEL "SOFTLEVEL"
+
+#define DEFAULT_PATH "PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/sbin"
+
+#define IS_SBIN_RC() (0 == strcmp(caller, SBIN_RC))
+
+static void (*selinux_run_init_old) (void);
+static void (*selinux_run_init_new) (int argc, char **argv);
+
+extern char **environ;
+
+void setup_selinux(int argc, char **argv) {
+ void *lib_handle = NULL;
+
+ lib_handle = dlopen(SELINUX_LIB, RTLD_NOW | RTLD_GLOBAL);
+ if (NULL != lib_handle) {
+ selinux_run_init_old = dlsym(lib_handle, "selinux_runscript");
+ selinux_run_init_new = dlsym(lib_handle, "selinux_runscript2");
+
+ /* Use new run_init if it exists, else fall back to old */
+ if (NULL != selinux_run_init_new)
+ selinux_run_init_new(argc, argv);
+ else if (NULL != selinux_run_init_old)
+ selinux_run_init_old();
+ else {
+ /* This shouldnt happen... probably corrupt lib */
+ fprintf(stderr, "Run_init is missing from runscript_selinux.so!\n");
+ exit(127);
+ }
+ }
+}
+
+char **get_whitelist(char **whitelist, char *filename) {
+ char *buf = NULL;
+ char *tmp_buf = NULL;
+ char *tmp_p = NULL;
+ char *token = NULL;
+ size_t lenght = 0;
+ int count = 0;
+ int current = 0;
+
+ if (-1 == file_map(filename, &buf, &lenght))
+ return NULL;
+
+ while (current < lenght) {
+ count = buf_get_line(buf, lenght, current);
+
+ tmp_buf = strndup(&buf[current], count);
+ if (NULL == tmp_buf) {
+ DBG_MSG("Failed to allocate temporary buffer!\n");
+ goto error;
+ }
+ tmp_p = tmp_buf;
+
+ /* Strip leading spaces/tabs */
+ while ((tmp_p[0] == ' ') || (tmp_p[0] == '\t'))
+ tmp_p++;
+
+ /* Get entry - we do not want comments, and only the first word
+ * on a line is valid */
+ token = strsep(&tmp_p, "# \t");
+ if (NULL != token && '\0' != token[0]) {
+ tmp_p = strndup(token, strlen(token));
+ STRING_LIST_ADD(whitelist, tmp_p, error);
+ }
+
+ current += count + 1;
+ free(tmp_buf);
+ /* Set to NULL in case we error out above and have
+ * to free below */
+ tmp_buf = NULL;
+ }
+
+
+ file_unmap(buf, lenght);
+
+ return whitelist;
+
+error:
+ if (NULL != tmp_buf)
+ free(tmp_buf);
+ file_unmap(buf, lenght);
+ STRING_LIST_FREE(whitelist);
+
+ return NULL;
+}
+
+char **filter_environ(char *caller) {
+ char **myenv = NULL;
+ char **whitelist = NULL;
+ char *env_name = NULL;
+ int check_profile = 1;
+ int count = 0;
+
+ if (NULL != getenv(SOFTLEVEL) && !IS_SBIN_RC())
+ /* Called from /sbin/rc, but not /sbin/rc itself, so current
+ * environment should be fine */
+ return environ;
+
+ if (1 == is_file(SYS_WHITELIST, 1))
+ whitelist = get_whitelist(whitelist, SYS_WHITELIST);
+ else
+ EWARN("System environment whitelist missing!\n");
+
+ if (1 == is_file(USR_WHITELIST, 1))
+ whitelist = get_whitelist(whitelist, USR_WHITELIST);
+
+ if (NULL == whitelist)
+ /* If no whitelist is present, revert to old behaviour */
+ return environ;
+
+ if (1 != is_file(PROFILE_ENV, 1))
+ /* XXX: Maybe warn here? */
+ check_profile = 0;
+
+ STRING_LIST_FOR_EACH(whitelist, env_name, count) {
+ char *env_var = NULL;
+ char *tmp_p = NULL;
+ int env_len = 0;
+
+ env_var = getenv(env_name);
+ if (NULL != env_var)
+ goto add_entry;
+
+ if (1 == check_profile) {
+ char *tmp_env_name = NULL;
+ int tmp_len = 0;
+
+ /* The entries in PROFILE_ENV is of the form:
+ * export VAR_NAME=value */
+ tmp_len = strlen(env_name) + strlen("export ") + 1;
+ tmp_env_name = calloc(tmp_len, sizeof(char *));
+ if (NULL == tmp_env_name) {
+ DBG_MSG("Failed to allocate temporary buffer!\n");
+ goto error;
+ }
+ snprintf(tmp_env_name, tmp_len, "export %s", env_name);
+
+ /* Clear errno so that subsequent calls do not trigger
+ * DBG_MSG */
+ errno = 0;
+ env_var = get_cnf_entry(PROFILE_ENV, tmp_env_name);
+ free(tmp_env_name);
+ if (NULL == env_var && ENOMSG != errno)
+ goto error;
+ else if (NULL != env_var)
+ goto add_entry;
+ }
+
+ continue;
+
+add_entry:
+ env_len = strlen(env_name) + strlen(env_var) + 2;
+ tmp_p = calloc(env_len, sizeof(char *));
+ if (NULL == tmp_p) {
+ DBG_MSG("Failed to allocate temporary buffer!\n");
+ goto error;
+ }
+ snprintf(tmp_p, env_len, "%s=%s", env_name, env_var);
+ STRING_LIST_ADD(myenv, tmp_p, error);
+ }
+
+ STRING_LIST_FREE(whitelist);
+
+ if (NULL == myenv)
+ /* If all else fails, just add a default PATH */
+ STRING_LIST_ADD(myenv, strdup(DEFAULT_PATH), error);
+
+ return myenv;
+
+error:
+ STRING_LIST_FREE(myenv);
+ STRING_LIST_FREE(whitelist);
+
+ return NULL;
+}
+
+int main(int argc, char *argv[]) {
+ char *myargs[32];
+ char **myenv = NULL;
+ char *caller = argv[1];
+ int new = 1;
+
+ myargs[0] = "runscript";
+ while (argv[new] != 0) {
+ myargs[new] = argv[new];
+ new++;
+ }
+ myargs[new] = NULL;
+
+ /* Do not do help for /sbin/rc */
+ if (argc < 3 && !IS_SBIN_RC()) {
+ execv(RCSCRIPT_HELP, myargs);
+ exit(1);
+ }
+
+ /* Setup a filtered environment according to the whitelist */
+ myenv = filter_environ(caller);
+ if (NULL == myenv) {
+ EWARN("%s: Failed to filter the environment!\n", caller);
+ /* XXX: Might think to bail here, but it could mean the system
+ * is rendered unbootable, so rather not */
+ myenv = environ;
+ }
+
+ /* Ok, we are ready to go, so setup selinux if applicable */
+ setup_selinux(argc, argv);
+
+ if (!IS_SBIN_RC()) {
+ if (execve("/sbin/runscript.sh", myargs, myenv) < 0)
+ exit(1);
+ } else {
+ if (execve("/bin/bash", myargs, myenv) < 0)
+ exit(1);
+ }
+
+ return 0;
+}
diff --git a/src/start-stop-daemon.c b/src/start-stop-daemon.c
new file mode 100644
index 0000000..315164f
--- /dev/null
+++ b/src/start-stop-daemon.c
@@ -0,0 +1,1375 @@
+/*
+ * A rewrite of the original Debian's start-stop-daemon Perl script
+ * in C (faster - it is executed many times during system startup).
+ *
+ * Written by Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl>,
+ * public domain. Based conceptually on start-stop-daemon.pl, by Ian
+ * Jackson <ijackson@gnu.ai.mit.edu>. May be used and distributed
+ * freely for any purpose. Changes by Christian Schwarz
+ * <schwarz@monet.m.isar.de>, to make output conform to the Debian
+ * Console Message Standard, also placed in public domain. Minor
+ * changes by Klee Dienes <klee@debian.org>, also placed in the Public
+ * Domain.
+ *
+ * Changes by Ben Collins <bcollins@debian.org>, added --chuid, --background
+ * and --make-pidfile options, placed in public domain aswell.
+ *
+ * Port to OpenBSD by Sontri Tomo Huynh <huynh.29@osu.edu>
+ * and Andreas Schuldei <andreas@schuldei.org>
+ *
+ * Changes by Ian Jackson: added --retry (and associated rearrangements).
+ *
+ * Modified for Gentoo rc-scripts by Donny Davies <woodchip@gentoo.org>:
+ * I removed the BSD/Hurd/OtherOS stuff, added #include <stddef.h>
+ * and stuck in a #define VERSION "1.9.18". Now it compiles without
+ * the whole automake/config.h dance.
+ *
+ * Updated by Aron Griffis <agriffis@gentoo.org>:
+ * Fetched updates from Debian's dpkg-1.10.20, including fix for
+ * Gentoo bug 22686 (start-stop-daemon in baselayout doesn't allow
+ * altered nicelevel).
+ * Updated by Kito <kito@gentoo.org>:
+ * Add support for Darwin, additional patches from opendarwin.org
+ * fix for Gentoo bug 72145 from eldad@gentoo.org
+ */
+
+#define VERSION "1.10.20"
+#include <stddef.h>
+
+#define NONRETURNPRINTFFORMAT(x, y) \
+ __attribute__((noreturn, format(printf, x, y)))
+#define NONRETURNING \
+ __attribute__((noreturn))
+
+#if defined(linux) || (defined(__FreeBSD_kernel__) && defined(__GLIBC__))
+# define OSLinux
+#elif defined(__GNU__)
+# define OSHURD
+#elif defined(__sparc__)
+# define OSsunos
+#elif defined(OPENBSD) || defined(__OpenBSD__)
+# define OSOpenBSD
+#elif defined(hpux)
+# define OShpux
+#elif defined(__FreeBSD__)
+# define OSFreeBSD
+#elif defined(__NetBSD__)
+# define OSNetBSD
+#elif defined(__APPLE__)
+# define OSDarwin
+#else
+# error Unknown architecture - cannot build start-stop-daemon
+#endif
+
+#define MIN_POLL_INTERVAL 20000 /*us*/
+
+#if defined(OSHURD)
+# include <hurd.h>
+# include <ps.h>
+#endif
+
+#if defined(OSOpenBSD) || defined(OSFreeBSD) || defined(OSNetBSD) || defined(OSDarwin)
+#include <sys/param.h>
+#include <sys/user.h>
+#include <sys/proc.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <sys/types.h>
+
+#include <err.h>
+#include <kvm.h>
+#include <limits.h>
+#endif
+
+#if defined(OShpux)
+#include <sys/param.h>
+#include <sys/pstat.h>
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <pwd.h>
+#include <grp.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/termios.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <assert.h>
+#include <ctype.h>
+
+#include "headers.h"
+
+#ifdef HURD_IHASH_H
+# include <hurd/ihash.h>
+#endif
+
+static int testmode = 0;
+static int quietmode = 0;
+static int exitnodo = 1;
+static int start = 0;
+static int stop = 0;
+static int background = 0;
+static int mpidfile = 0;
+static int signal_nr = 15;
+static const char *signal_str = NULL;
+static int user_id = -1;
+static int runas_uid = -1;
+static int runas_gid = -1;
+static const char *userspec = NULL;
+static char *changeuser = NULL;
+static const char *changegroup = NULL;
+static char *changeroot = NULL;
+static const char *changedir = NULL;
+static const char *cmdname = NULL;
+static char *execname = NULL;
+static char *startas = NULL;
+static const char *pidfile = NULL;
+static char what_stop[1024];
+static const char *schedule_str = NULL;
+static const char *progname = "";
+static int nicelevel = 0;
+
+static struct stat exec_stat;
+#if defined(OSHURD)
+static struct proc_stat_list *procset;
+#endif
+
+
+struct pid_list {
+ struct pid_list *next;
+ pid_t pid;
+};
+
+static struct pid_list *found = NULL;
+static struct pid_list *killed = NULL;
+
+struct schedule_item {
+ enum { sched_timeout, sched_signal, sched_goto, sched_forever } type;
+ int value; /* seconds, signal no., or index into array */
+ /* sched_forever is only seen within parse_schedule and callees */
+};
+
+static int schedule_length;
+static struct schedule_item *schedule = NULL;
+
+static void *xmalloc(int size);
+static void push(struct pid_list **list, pid_t pid);
+static void do_help(void);
+static void parse_options(int argc, char * const *argv);
+static int pid_is_user(pid_t pid, uid_t uid);
+static int pid_is_cmd(pid_t pid, const char *name);
+static void check(pid_t pid);
+static void do_pidfile(const char *name);
+static void do_stop(int signal_nr, int quietmode,
+ int *n_killed, int *n_notkilled, int retry_nr);
+#if defined(OSLinux) || defined(OShpux)
+static int pid_is_exec(pid_t pid, const struct stat *esb);
+#endif
+
+#ifdef __GNUC__
+static void fatal(const char *format, ...)
+ NONRETURNPRINTFFORMAT(1, 2);
+static void badusage(const char *msg)
+ NONRETURNING;
+#else
+static void fatal(const char *format, ...);
+static void badusage(const char *msg);
+#endif
+
+/* This next part serves only to construct the TVCALC macro, which
+ * is used for doing arithmetic on struct timeval's. It works like this:
+ * TVCALC(result, expression);
+ * where result is a struct timeval (and must be an lvalue) and
+ * expression is the single expression for both components. In this
+ * expression you can use the special values TVELEM, which when fed a
+ * const struct timeval* gives you the relevant component, and
+ * TVADJUST. TVADJUST is necessary when subtracting timevals, to make
+ * it easier to renormalise. Whenver you subtract timeval elements,
+ * you must make sure that TVADJUST is added to the result of the
+ * subtraction (before any resulting multiplication or what have you).
+ * TVELEM must be linear in TVADJUST.
+ */
+typedef long tvselector(const struct timeval*);
+static long tvselector_sec(const struct timeval *tv) { return tv->tv_sec; }
+static long tvselector_usec(const struct timeval *tv) { return tv->tv_usec; }
+#define TVCALC_ELEM(result, expr, sec, adj) \
+{ \
+ const long TVADJUST = adj; \
+ long (*const TVELEM)(const struct timeval*) = tvselector_##sec; \
+ (result).tv_##sec = (expr); \
+}
+#define TVCALC(result,expr) \
+do { \
+ TVCALC_ELEM(result, expr, sec, (-1)); \
+ TVCALC_ELEM(result, expr, usec, (+1000000)); \
+ (result).tv_sec += (result).tv_usec / 1000000; \
+ (result).tv_usec %= 1000000; \
+} while(0)
+
+
+static void
+fatal(const char *format, ...)
+{
+ va_list arglist;
+
+ fprintf(stderr, "%s: ", progname);
+ va_start(arglist, format);
+ vfprintf(stderr, format, arglist);
+ va_end(arglist);
+ putc('\n', stderr);
+ exit(2);
+}
+
+
+static void *
+xmalloc(int size)
+{
+ void *ptr;
+
+ ptr = malloc(size);
+ if (ptr)
+ return ptr;
+ fatal("malloc(%d) failed", size);
+}
+
+
+static void
+xgettimeofday(struct timeval *tv)
+{
+ if (gettimeofday(tv,0) != 0)
+ fatal("gettimeofday failed: %s", strerror(errno));
+}
+
+
+static void
+push(struct pid_list **list, pid_t pid)
+{
+ struct pid_list *p;
+
+ p = xmalloc(sizeof(*p));
+ p->next = *list;
+ p->pid = pid;
+ *list = p;
+}
+
+static void
+clear(struct pid_list **list)
+{
+ struct pid_list *here, *next;
+
+ for (here = *list; here != NULL; here = next) {
+ next = here->next;
+ free(here);
+ }
+
+ *list = NULL;
+}
+
+static void
+do_help(void)
+{
+ printf(
+"start-stop-daemon " VERSION " for Debian - small and fast C version written by\n"
+"Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl>, public domain.\n"
+"\n"
+"Usage:\n"
+" start-stop-daemon -S|--start options ... -- arguments ...\n"
+" start-stop-daemon -K|--stop options ...\n"
+" start-stop-daemon -H|--help\n"
+" start-stop-daemon -V|--version\n"
+"\n"
+"Options (at least one of --exec|--pidfile|--user is required):\n"
+" -x|--exec <executable> program to start/check if it is running\n"
+" -p|--pidfile <pid-file> pid file to check\n"
+" -c|--chuid <name|uid[:group|gid]>\n"
+" change to this user/group before starting process\n"
+" -u|--user <username>|<uid> stop processes owned by this user\n"
+" -g|--group <group|gid> run process as this group\n"
+" -n|--name <process-name> stop processes with this name\n"
+" -s|--signal <signal> signal to send (default TERM)\n"
+" -a|--startas <pathname> program to start (default is <executable>)\n"
+" -C|--chdir <directory> Change to <directory>(default is /)\n"
+" -N|--nicelevel <incr> add incr to the process's nice level\n"
+" -b|--background force the process to detach\n"
+" -m|--make-pidfile create the pidfile before starting\n"
+" -R|--retry <schedule> check whether processes die, and retry\n"
+" -t|--test test mode, don't do anything\n"
+" -o|--oknodo exit status 0 (not 1) if nothing done\n"
+" -q|--quiet be more quiet\n"
+" -v|--verbose be more verbose\n"
+"Retry <schedule> is <item>|/<item>/... where <item> is one of\n"
+" -<signal-num>|[-]<signal-name> send that signal\n"
+" <timeout> wait that many seconds\n"
+" forever repeat remainder forever\n"
+"or <schedule> may be just <timeout>, meaning <signal>/<timeout>/KILL/<timeout>\n"
+"\n"
+"Exit status: 0 = done 1 = nothing done (=> 0 if --oknodo)\n"
+" 3 = trouble 2 = with --retry, processes wouldn't die\n");
+}
+
+
+static void
+badusage(const char *msg)
+{
+ if (msg)
+ fprintf(stderr, "%s: %s\n", progname, msg);
+ fprintf(stderr, "Try `%s --help' for more information.\n", progname);
+ exit(3);
+}
+
+struct sigpair {
+ const char *name;
+ int signal;
+};
+
+const struct sigpair siglist[] = {
+ { "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 }
+};
+
+static int parse_integer(const char *string, int *value_r) {
+ unsigned long ul;
+ char *ep;
+
+ if (!string[0])
+ return -1;
+
+ ul= strtoul(string,&ep,10);
+ if (ul > INT_MAX || *ep != '\0')
+ return -1;
+
+ *value_r= ul;
+ return 0;
+}
+
+static int parse_signal(const char *signal_str, int *signal_nr)
+{
+ unsigned int i;
+
+ if (parse_integer(signal_str, signal_nr) == 0)
+ return 0;
+
+ for (i = 0; i < sizeof (siglist) / sizeof (siglist[0]); i++) {
+ if (strcmp (signal_str, siglist[i].name) == 0) {
+ *signal_nr = siglist[i].signal;
+ return 0;
+ }
+ }
+ return -1;
+}
+
+static void
+parse_schedule_item(const char *string, struct schedule_item *item) {
+ const char *after_hyph;
+
+ if (!strcmp(string,"forever")) {
+ item->type = sched_forever;
+ } else if (isdigit(string[0])) {
+ item->type = sched_timeout;
+ if (parse_integer(string, &item->value) != 0)
+ badusage("invalid timeout value in schedule");
+ } else if ((after_hyph = string + (string[0] == '-')) &&
+ parse_signal(after_hyph, &item->value) == 0) {
+ item->type = sched_signal;
+ } else {
+ badusage("invalid schedule item (must be [-]<signal-name>, "
+ "-<signal-number>, <timeout> or `forever'");
+ }
+}
+
+static void
+parse_schedule(const char *schedule_str) {
+ char item_buf[20];
+ const char *slash;
+ int count, repeatat;
+ ptrdiff_t str_len;
+
+ count = 0;
+ for (slash = schedule_str; *slash; slash++)
+ if (*slash == '/')
+ count++;
+
+ schedule_length = (count == 0) ? 4 : count+1;
+ schedule = xmalloc(sizeof(*schedule) * schedule_length);
+
+ if (count == 0) {
+ schedule[0].type = sched_signal;
+ schedule[0].value = signal_nr;
+ parse_schedule_item(schedule_str, &schedule[1]);
+ if (schedule[1].type != sched_timeout) {
+ badusage ("--retry takes timeout, or schedule list"
+ " of at least two items");
+ }
+ schedule[2].type = sched_signal;
+ schedule[2].value = SIGKILL;
+ schedule[3]= schedule[1];
+ } else {
+ count = 0;
+ repeatat = -1;
+ while (schedule_str != NULL) {
+ slash = strchr(schedule_str,'/');
+ str_len = slash ? slash - schedule_str : strlen(schedule_str);
+ if (str_len >= (ptrdiff_t)sizeof(item_buf))
+ badusage("invalid schedule item: far too long"
+ " (you must delimit items with slashes)");
+ memcpy(item_buf, schedule_str, str_len);
+ item_buf[str_len] = 0;
+ schedule_str = slash ? slash+1 : NULL;
+
+ parse_schedule_item(item_buf, &schedule[count]);
+ if (schedule[count].type == sched_forever) {
+ if (repeatat >= 0)
+ badusage("invalid schedule: `forever'"
+ " appears more than once");
+ repeatat = count;
+ continue;
+ }
+ count++;
+ }
+ if (repeatat >= 0) {
+ schedule[count].type = sched_goto;
+ schedule[count].value = repeatat;
+ count++;
+ }
+ assert(count == schedule_length);
+ }
+}
+
+static void
+parse_options(int argc, char * const *argv)
+{
+ static struct option longopts[] = {
+ { "help", 0, NULL, 'H'},
+ { "stop", 0, NULL, 'K'},
+ { "start", 0, NULL, 'S'},
+ { "version", 0, NULL, 'V'},
+ { "startas", 1, NULL, 'a'},
+ { "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'},
+ { "group", 1, NULL, 'g'},
+ { "chroot", 1, NULL, 'r'},
+ { "verbose", 0, NULL, 'v'},
+ { "exec", 1, NULL, 'x'},
+ { "chuid", 1, NULL, 'c'},
+ { "nicelevel", 1, NULL, 'N'},
+ { "background", 0, NULL, 'b'},
+ { "make-pidfile", 0, NULL, 'm'},
+ { "retry", 1, NULL, 'R'},
+ { "chdir", 1, NULL, 'd'},
+ { NULL, 0, NULL, 0}
+ };
+ int c;
+
+ for (;;) {
+ c = getopt_long(argc, argv, "HKSV:a:n:op:qr:s:tu:vx:c:N:bmR:g:d:",
+ longopts, (int *) 0);
+ if (c == -1)
+ break;
+ switch (c) {
+ case 'H': /* --help */
+ do_help();
+ exit(0);
+ case 'K': /* --stop */
+ stop = 1;
+ break;
+ case 'S': /* --start */
+ start = 1;
+ break;
+ case 'V': /* --version */
+ printf("start-stop-daemon " VERSION "\n");
+ exit(0);
+ case 'a': /* --startas <pathname> */
+ startas = optarg;
+ break;
+ case 'n': /* --name <process-name> */
+ cmdname = optarg;
+ break;
+ case 'o': /* --oknodo */
+ exitnodo = 0;
+ break;
+ case 'p': /* --pidfile <pid-file> */
+ pidfile = optarg;
+ break;
+ case 'q': /* --quiet */
+ quietmode = 1;
+ break;
+ case 's': /* --signal <signal> */
+ signal_str = optarg;
+ break;
+ case 't': /* --test */
+ testmode = 1;
+ break;
+ case 'u': /* --user <username>|<uid> */
+ userspec = optarg;
+ break;
+ case 'v': /* --verbose */
+ quietmode = -1;
+ break;
+ case 'x': /* --exec <executable> */
+ execname = optarg;
+ break;
+ case 'c': /* --chuid <username>|<uid> */
+ /* we copy the string just in case we need the
+ * argument later. */
+ changeuser = strdup(optarg);
+ changeuser = strtok(changeuser, ":");
+ changegroup = strtok(NULL, ":");
+ break;
+ case 'g': /* --group <group>|<gid> */
+ changegroup = optarg;
+ break;
+ case 'r': /* --chroot /new/root */
+ changeroot = optarg;
+ break;
+ case 'N': /* --nice */
+ nicelevel = atoi(optarg);
+ break;
+ case 'b': /* --background */
+ background = 1;
+ break;
+ case 'm': /* --make-pidfile */
+ mpidfile = 1;
+ break;
+ case 'R': /* --retry <schedule>|<timeout> */
+ schedule_str = optarg;
+ break;
+ case 'd': /* --chdir /new/dir */
+ changedir = optarg;
+ break;
+ default:
+ badusage(NULL); /* message printed by getopt */
+ }
+ }
+
+ if (signal_str != NULL) {
+ if (parse_signal (signal_str, &signal_nr) != 0)
+ badusage("signal value must be numeric or name"
+ " of signal (KILL, INT, ...)");
+ }
+
+ if (schedule_str != NULL) {
+ parse_schedule(schedule_str);
+ }
+
+ if (start == stop)
+ badusage("need one of --start or --stop");
+
+ if (!execname && !pidfile && !userspec && !cmdname)
+ badusage("need at least one of --exec, --pidfile, --user or --name");
+
+ if (!startas)
+ startas = execname;
+
+ if (start && !startas)
+ badusage("--start needs --exec or --startas");
+
+ if (mpidfile && pidfile == NULL)
+ badusage("--make-pidfile is only relevant with --pidfile");
+
+ if (background && !start)
+ badusage("--background is only relevant with --start");
+
+}
+
+#if defined(OSLinux)
+static int
+pid_is_exec(pid_t pid, const struct stat *esb)
+{
+ struct stat sb;
+ char buf[32];
+
+ sprintf(buf, "/proc/%d/exe", pid);
+ if (stat(buf, &sb) != 0)
+ return 0;
+ return (sb.st_dev == esb->st_dev && sb.st_ino == esb->st_ino);
+}
+
+
+static int
+pid_is_user(pid_t pid, uid_t uid)
+{
+ struct stat sb;
+ char buf[32];
+
+ sprintf(buf, "/proc/%d", pid);
+ if (stat(buf, &sb) != 0)
+ return 0;
+ return (sb.st_uid == uid);
+}
+
+
+static int
+pid_is_cmd(pid_t pid, const char *name)
+{
+ char buf[32];
+ FILE *f;
+ int c;
+
+ sprintf(buf, "/proc/%d/stat", pid);
+ f = fopen(buf, "r");
+ if (!f)
+ return 0;
+ while ((c = getc(f)) != EOF && c != '(')
+ ;
+ if (c != '(') {
+ fclose(f);
+ return 0;
+ }
+ /* this hopefully handles command names containing ')' */
+ while ((c = getc(f)) != EOF && c == *name)
+ name++;
+ fclose(f);
+ return (c == ')' && *name == '\0');
+}
+#endif /* OSLinux */
+
+
+#if defined(OSHURD)
+static int
+pid_is_user(pid_t pid, uid_t uid)
+{
+ struct stat sb;
+ char buf[32];
+ struct proc_stat *pstat;
+
+ sprintf(buf, "/proc/%d", pid);
+ if (stat(buf, &sb) != 0)
+ return 0;
+ return (sb.st_uid == uid);
+ pstat = proc_stat_list_pid_proc_stat (procset, pid);
+ if (pstat == NULL)
+ fatal ("Error getting process information: NULL proc_stat struct");
+ proc_stat_set_flags (pstat, PSTAT_PID | PSTAT_OWNER_UID);
+ return (pstat->owner_uid == uid);
+}
+
+static int
+pid_is_cmd(pid_t pid, const char *name)
+{
+ struct proc_stat *pstat;
+ pstat = proc_stat_list_pid_proc_stat (procset, pid);
+ if (pstat == NULL)
+ fatal ("Error getting process information: NULL proc_stat struct");
+ proc_stat_set_flags (pstat, PSTAT_PID | PSTAT_ARGS);
+ return (!strcmp (name, pstat->args));
+}
+#endif /* OSHURD */
+
+
+static int
+pid_is_running(pid_t pid)
+{
+ struct stat sb;
+ char buf[32];
+
+ sprintf(buf, "/proc/%d", pid);
+ if (stat(buf, &sb) != 0) {
+ if (errno!=ENOENT)
+ fatal("Error stating %s: %s", buf, strerror(errno));
+ return 0;
+ }
+
+ return 1;
+}
+
+static void
+check(pid_t pid)
+{
+#if defined(OSLinux) || defined(OShpux)
+ if (execname && !pid_is_exec(pid, &exec_stat))
+ return;
+#elif defined(OSHURD) || defined(OSFreeBSD) || defined(OSNetBSD) || defined(OSDarwin)
+ /* I will try this to see if it works */
+ if (execname && !pid_is_cmd(pid, execname))
+ return;
+#endif
+ if (userspec && !pid_is_user(pid, user_id))
+ return;
+ if (cmdname && !pid_is_cmd(pid, cmdname))
+ return;
+ if (start && !pid_is_running(pid))
+ return;
+ push(&found, pid);
+}
+
+static void
+do_pidfile(const char *name)
+{
+ FILE *f;
+ pid_t pid;
+
+ f = fopen(name, "r");
+ if (f) {
+ if (fscanf(f, "%d", &pid) == 1)
+ check(pid);
+ fclose(f);
+ } else if (errno != ENOENT)
+ fatal("open pidfile %s: %s", name, strerror(errno));
+
+}
+
+/* WTA: this needs to be an autoconf check for /proc/pid existance.
+ */
+
+#if defined(OSLinux) || defined (OSsunos) || defined(OSfreebsd)
+static void
+do_procinit(void)
+{
+ DIR *procdir;
+ struct dirent *entry;
+ int foundany;
+ pid_t pid;
+
+ procdir = opendir("/proc");
+ if (!procdir)
+ fatal("opendir /proc: %s", strerror(errno));
+
+ foundany = 0;
+ while ((entry = readdir(procdir)) != NULL) {
+ if (sscanf(entry->d_name, "%d", &pid) != 1)
+ continue;
+ foundany++;
+ check(pid);
+ }
+ closedir(procdir);
+ if (!foundany)
+ fatal("nothing in /proc - not mounted?");
+}
+#endif /* OSLinux */
+
+
+#if defined(OSHURD)
+error_t
+check_all(void *ptr)
+{
+ struct proc_stat *pstat = ptr;
+
+ check(pstat->pid);
+ return 0;
+}
+
+static void
+do_procinit(void)
+{
+ struct ps_context *context;
+ error_t err;
+
+ err = ps_context_create(getproc(), &context);
+ if (err)
+ error(1, err, "ps_context_create");
+
+ err = proc_stat_list_create(context, &procset);
+ if (err)
+ error(1, err, "proc_stat_list_create");
+
+ err = proc_stat_list_add_all(procset, 0, 0);
+ if (err)
+ error(1, err, "proc_stat_list_add_all");
+
+ /* Check all pids */
+ ihash_iterate(context->procs, check_all);
+}
+#endif /* OSHURD */
+
+
+#if defined(OSOpenBSD) || defined(OSFreeBSD) || defined(OSNetBSD)
+static int
+pid_is_cmd(pid_t pid, const char *name)
+{
+ kvm_t *kd;
+ int nentries, argv_len=0;
+ struct kinfo_proc *kp;
+ char errbuf[_POSIX2_LINE_MAX], buf[_POSIX2_LINE_MAX];
+ char **pid_argv_p;
+ char *start_argv_0_p, *end_argv_0_p;
+
+
+ kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf);
+ if (kd == 0)
+ errx(1, "%s", errbuf);
+ if ((kp = kvm_getprocs(kd, KERN_PROC_PID, pid, &nentries)) == 0)
+ errx(1, "%s", kvm_geterr(kd));
+ if ((pid_argv_p = kvm_getargv(kd, kp, argv_len)) == 0)
+ errx(1, "%s", kvm_geterr(kd));
+
+ start_argv_0_p = *pid_argv_p;
+ /* find and compare string */
+
+ /* find end of argv[0] then copy and cut of str there. */
+ if ((end_argv_0_p = strchr(*pid_argv_p, ' ')) == 0 )
+ /* There seems to be no space, so we have the command
+ * allready in its desired form. */
+ start_argv_0_p = *pid_argv_p;
+ else {
+ /* Tests indicate that this never happens, since
+ * kvm_getargv itselfe cuts of tailing stuff. This is
+ * not what the manpage says, however. */
+ strncpy(buf, *pid_argv_p, (end_argv_0_p - start_argv_0_p));
+ buf[(end_argv_0_p - start_argv_0_p) + 1] = '\0';
+ start_argv_0_p = buf;
+ }
+
+ if (strlen(name) != strlen(start_argv_0_p))
+ return 0;
+ return (strcmp(name, start_argv_0_p) == 0) ? 1 : 0;
+}
+
+static int
+pid_is_user(pid_t pid, uid_t uid)
+{
+ kvm_t *kd;
+ int nentries; /* Value not used */
+ uid_t proc_uid;
+ struct kinfo_proc *kp;
+ char errbuf[_POSIX2_LINE_MAX];
+
+
+ kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf);
+ if (kd == 0)
+ errx(1, "%s", errbuf);
+ if ((kp = kvm_getprocs(kd, KERN_PROC_PID, pid, &nentries)) == 0)
+ errx(1, "%s", kvm_geterr(kd));
+ if (kp->ki_ruid )
+ kvm_read(kd, (u_long)&(kp->ki_ruid),
+ &proc_uid, sizeof(uid_t));
+ else
+ return 0;
+ return (proc_uid == (uid_t)uid);
+}
+
+static int
+pid_is_exec(pid_t pid, const char *name)
+{
+ kvm_t *kd;
+ int nentries;
+ struct kinfo_proc *kp;
+ char errbuf[_POSIX2_LINE_MAX], *pidexec;
+
+ kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf);
+ if (kd == 0)
+ errx(1, "%s", errbuf);
+ if ((kp = kvm_getprocs(kd, KERN_PROC_PID, pid, &nentries)) == 0)
+ errx(1, "%s", kvm_geterr(kd));
+ pidexec = kp->ki_comm;
+ if (strlen(name) != strlen(pidexec))
+ return 0;
+ return (strcmp(name, pidexec) == 0) ? 1 : 0;
+}
+
+
+static void
+do_procinit(void)
+{
+ /* Nothing to do */
+}
+
+#endif /* OSOpenBSD */
+
+#if defined(OSDarwin)
+int
+pid_is_user(pid_t pid, uid_t uid)
+{
+ int mib[4];
+ size_t size;
+ struct kinfo_proc ki;
+
+ size = sizeof(ki);
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_PID;
+ mib[3] = pid;
+ if (sysctl(mib, 4, &ki, &size, NULL, 0) < 0)
+ errx(1, "%s", "Failure calling sysctl");
+ return (uid == ki.kp_eproc.e_pcred.p_ruid);
+}
+
+static int
+pid_is_cmd(pid_t pid, const char *name)
+{
+ int mib[4];
+ size_t size;
+ struct kinfo_proc ki;
+
+ size = sizeof(ki);
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_PID;
+ mib[3] = pid;
+ if (sysctl(mib, 4, &ki, &size, NULL, 0) < 0)
+ errx(1, "%s", "Failure calling sysctl");
+ return (!strncmp(name, ki.kp_proc.p_comm, MAXCOMLEN));
+}
+
+static void
+do_procinit(void)
+{
+ int mib[3];
+ size_t size;
+ int nprocs, ret, i;
+ struct kinfo_proc *procs = NULL, *newprocs;
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_ALL;
+ ret = sysctl(mib, 3, NULL, &size, NULL, 0);
+ /* Allocate enough memory for entire process table */
+ do {
+ size += size / 10;
+ newprocs = realloc(procs, size);
+ if (newprocs == NULL) {
+ if (procs)
+ free(procs);
+ errx(1, "%s", "Could not reallocate memory");
+ }
+ procs = newprocs;
+ ret = sysctl(mib, 3, procs, &size, NULL, 0);
+ } while (ret >= 0 && errno == ENOMEM);
+
+ if (ret < 0)
+ errx(1, "%s", "Failure calling sysctl");
+
+ /* Verify size of proc structure */
+ if (size % sizeof(struct kinfo_proc) != 0)
+ errx(1, "%s", "proc size mismatch, userland out of sync with kernel");
+ nprocs = size / sizeof(struct kinfo_proc);
+ for (i = 0; i < nprocs; i++) {
+ check(procs[i].kp_proc.p_pid);
+ }
+}
+#endif /* OSDarwin */
+#if defined(OShpux)
+static int
+pid_is_user(pid_t pid, uid_t uid)
+{
+ struct pst_status pst;
+
+ if (pstat_getproc(&pst, sizeof(pst), (size_t) 0, (int) pid) < 0)
+ return 0;
+ return ((uid_t) pst.pst_uid == uid);
+}
+
+static int
+pid_is_cmd(pid_t pid, const char *name)
+{
+ struct pst_status pst;
+
+ if (pstat_getproc(&pst, sizeof(pst), (size_t) 0, (int) pid) < 0)
+ return 0;
+ return (strcmp(pst.pst_ucomm, name) == 0);
+}
+
+static int
+pid_is_exec(pid_t pid, const struct stat *esb)
+{
+ struct pst_status pst;
+
+ if (pstat_getproc(&pst, sizeof(pst), (size_t) 0, (int) pid) < 0)
+ return 0;
+ return ((dev_t) pst.pst_text.psf_fsid.psfs_id == esb->st_dev
+ && (ino_t) pst.pst_text.psf_fileid == esb->st_ino);
+}
+
+static void
+do_procinit(void)
+{
+ struct pst_status pst[10];
+ int i, count;
+ int idx = 0;
+
+ while ((count = pstat_getproc(pst, sizeof(pst[0]), 10, idx)) > 0) {
+ for (i = 0; i < count; i++)
+ check(pst[i].pst_pid);
+ idx = pst[count - 1].pst_idx + 1;
+ }
+}
+#endif /* OShpux */
+
+
+static void
+do_findprocs(void)
+{
+ clear(&found);
+
+ if (pidfile)
+ do_pidfile(pidfile);
+ else
+ do_procinit();
+}
+
+/* return 1 on failure */
+static void
+do_stop(int signal_nr, int quietmode, int *n_killed, int *n_notkilled, int retry_nr)
+{
+ struct pid_list *p;
+
+ do_findprocs();
+
+ *n_killed = 0;
+ *n_notkilled = 0;
+
+ if (!found)
+ return;
+
+ clear(&killed);
+
+ for (p = found; p; p = p->next) {
+ if (testmode) {
+ printf("Would send signal %d to %d.\n",
+ signal_nr, p->pid);
+ (*n_killed)++;
+ } else if (kill(p->pid, signal_nr) == 0) {
+ push(&killed, p->pid);
+ (*n_killed)++;
+ } else {
+ printf("%s: warning: failed to kill %d: %s\n",
+ progname, p->pid, strerror(errno));
+ (*n_notkilled)++;
+ }
+ }
+ if (quietmode < 0 && killed) {
+ printf("Stopped %s (pid", what_stop);
+ for (p = killed; p; p = p->next)
+ printf(" %d", p->pid);
+ putchar(')');
+ if (retry_nr > 0)
+ printf(", retry #%d", retry_nr);
+ printf(".\n");
+ }
+}
+
+
+static void
+set_what_stop(const char *str)
+{
+ strncpy(what_stop, str, sizeof(what_stop));
+ what_stop[sizeof(what_stop)-1] = '\0';
+}
+
+static int
+run_stop_schedule(void)
+{
+ int r, position, n_killed, n_notkilled, value, ratio, anykilled, retry_nr;
+ struct timeval stopat, before, after, interval, maxinterval;
+
+ if (testmode) {
+ if (schedule != NULL) {
+ printf("Ignoring --retry in test mode\n");
+ schedule = NULL;
+ }
+ }
+
+ if (cmdname)
+ set_what_stop(cmdname);
+ else if (execname)
+ set_what_stop(execname);
+ else if (pidfile)
+ sprintf(what_stop, "process in pidfile `%.200s'", pidfile);
+ else if (userspec)
+ sprintf(what_stop, "process(es) owned by `%.200s'", userspec);
+ else
+ fatal("internal error, please report");
+
+ anykilled = 0;
+ retry_nr = 0;
+
+ if (schedule == NULL) {
+ do_stop(signal_nr, quietmode, &n_killed, &n_notkilled, 0);
+ if (n_notkilled > 0 && quietmode <= 0)
+ printf("%d pids were not killed\n", n_notkilled);
+ if (n_killed)
+ anykilled = 1;
+ goto x_finished;
+ }
+
+ for (position = 0; position < schedule_length; ) {
+ value= schedule[position].value;
+ n_notkilled = 0;
+
+ switch (schedule[position].type) {
+
+ case sched_goto:
+ position = value;
+ continue;
+
+ case sched_signal:
+ do_stop(value, quietmode, &n_killed, &n_notkilled, retry_nr++);
+ if (!n_killed)
+ goto x_finished;
+ else
+ anykilled = 1;
+ goto next_item;
+
+ case sched_timeout:
+ /* We want to keep polling for the processes, to see if they've exited,
+ * or until the timeout expires.
+ *
+ * This is a somewhat complicated algorithm to try to ensure that we
+ * notice reasonably quickly when all the processes have exited, but
+ * don't spend too much CPU time polling. In particular, on a fast
+ * machine with quick-exiting daemons we don't want to delay system
+ * shutdown too much, whereas on a slow one, or where processes are
+ * taking some time to exit, we want to increase the polling
+ * interval.
+ *
+ * The algorithm is as follows: we measure the elapsed time it takes
+ * to do one poll(), and wait a multiple of this time for the next
+ * poll. However, if that would put us past the end of the timeout
+ * period we wait only as long as the timeout period, but in any case
+ * we always wait at least MIN_POLL_INTERVAL (20ms). The multiple
+ * (`ratio') starts out as 2, and increases by 1 for each poll to a
+ * maximum of 10; so we use up to between 30% and 10% of the
+ * machine's resources (assuming a few reasonable things about system
+ * performance).
+ */
+ xgettimeofday(&stopat);
+ stopat.tv_sec += value;
+ ratio = 1;
+ for (;;) {
+ xgettimeofday(&before);
+ if (timercmp(&before,&stopat,>))
+ goto next_item;
+
+ do_stop(0, 1, &n_killed, &n_notkilled, 0);
+ if (!n_killed)
+ goto x_finished;
+
+ xgettimeofday(&after);
+
+ if (!timercmp(&after,&stopat,<))
+ goto next_item;
+
+ if (ratio < 10)
+ ratio++;
+
+ TVCALC(interval, ratio * (TVELEM(&after) - TVELEM(&before) + TVADJUST));
+ TVCALC(maxinterval, TVELEM(&stopat) - TVELEM(&after) + TVADJUST);
+
+ if (timercmp(&interval,&maxinterval,>))
+ interval = maxinterval;
+
+ if (interval.tv_sec == 0 &&
+ interval.tv_usec <= MIN_POLL_INTERVAL)
+ interval.tv_usec = MIN_POLL_INTERVAL;
+
+ r = select(0,0,0,0,&interval);
+ if (r < 0 && errno != EINTR)
+ fatal("select() failed for pause: %s",
+ strerror(errno));
+ }
+
+ default:
+ assert(!"schedule[].type value must be valid");
+
+ }
+
+ next_item:
+ position++;
+ }
+
+ if (quietmode <= 0)
+ printf("Program %s, %d process(es), refused to die.\n",
+ what_stop, n_killed);
+
+ return 2;
+
+x_finished:
+ if (!anykilled) {
+ if (quietmode <= 0)
+ printf("No %s found running; none killed.\n", what_stop);
+ return exitnodo;
+ } else {
+ return 0;
+ }
+}
+
+
+int main(int argc, char **argv) NONRETURNING;
+int
+main(int argc, char **argv)
+{
+ int devnull_fd = -1;
+#ifdef HAVE_TIOCNOTTY
+ int tty_fd = -1;
+#endif
+ progname = argv[0];
+
+ parse_options(argc, argv);
+ argc -= optind;
+ argv += optind;
+
+ if (execname && stat(execname, &exec_stat))
+ fatal("stat %s: %s", execname, strerror(errno));
+
+ if (userspec && sscanf(userspec, "%d", &user_id) != 1) {
+ struct passwd *pw;
+
+ pw = getpwnam(userspec);
+ if (!pw)
+ fatal("user `%s' not found\n", userspec);
+
+ user_id = pw->pw_uid;
+ }
+
+ if (changegroup && sscanf(changegroup, "%d", &runas_gid) != 1) {
+ struct group *gr = getgrnam(changegroup);
+ if (!gr)
+ fatal("group `%s' not found\n", changegroup);
+ runas_gid = gr->gr_gid;
+ }
+ if (changeuser && sscanf(changeuser, "%d", &runas_uid) != 1) {
+ struct passwd *pw = getpwnam(changeuser);
+ if (!pw)
+ fatal("user `%s' not found\n", changeuser);
+ runas_uid = pw->pw_uid;
+ if (changegroup == NULL) { /* pass the default group of this user */
+ changegroup = ""; /* just empty */
+ runas_gid = pw->pw_gid;
+ }
+ }
+
+ if (stop) {
+ int i = run_stop_schedule();
+ exit(i);
+ }
+
+ do_findprocs();
+
+ if (found) {
+ if (quietmode <= 0)
+ printf("%s already running.\n", execname ? execname : "process");
+ exit(exitnodo);
+ }
+ if (testmode) {
+ printf("Would start %s ", startas);
+ while (argc-- > 0)
+ printf("%s ", *argv++);
+ if (changeuser != NULL) {
+ printf(" (as user %s[%d]", changeuser, runas_uid);
+ if (changegroup != NULL)
+ printf(", and group %s[%d])", changegroup, runas_gid);
+ else
+ printf(")");
+ }
+ if (changeroot != NULL)
+ printf(" in directory %s", changeroot);
+ if (nicelevel)
+ printf(", and add %i to the priority", nicelevel);
+ printf(".\n");
+ exit(0);
+ }
+ if (quietmode < 0)
+ printf("Starting %s...\n", startas);
+ *--argv = startas;
+ if (background) { /* ok, we need to detach this process */
+ int i;
+ if (quietmode < 0)
+ printf("Detatching to start %s...", startas);
+ i = fork();
+ if (i<0) {
+ fatal("Unable to fork.\n");
+ }
+ if (i) { /* parent */
+ if (quietmode < 0)
+ printf("done.\n");
+ exit(0);
+ }
+ /* child continues here */
+
+#ifdef HAVE_TIOCNOTTY
+ tty_fd=open("/dev/tty", O_RDWR);
+#endif
+ devnull_fd=open("/dev/null", O_RDWR);
+ }
+ if (nicelevel) {
+ errno=0;
+ if ((nice(nicelevel)==-1) && (errno!=0))
+ fatal("Unable to alter nice level by %i: %s", nicelevel,
+ strerror(errno));
+ }
+ if (mpidfile && pidfile != NULL) { /* user wants _us_ to make the pidfile :) */
+ FILE *pidf = fopen(pidfile, "w");
+ pid_t pidt = getpid();
+ if (pidf == NULL)
+ fatal("Unable to open pidfile `%s' for writing: %s", pidfile,
+ strerror(errno));
+ fprintf(pidf, "%d\n", pidt);
+ fclose(pidf);
+ }
+ if (changeroot != NULL) {
+ if (chdir(changeroot) < 0)
+ fatal("Unable to chdir() to %s", changeroot);
+ if (chroot(changeroot) < 0)
+ fatal("Unable to chroot() to %s", changeroot);
+ }
+ if (changedir != NULL && chdir(changedir) < 0)
+ fatal("Unable to chdir() to %s", changedir);
+ if (changeuser != NULL) {
+ if (setgid(runas_gid))
+ fatal("Unable to set gid to %d", runas_gid);
+ if (initgroups(changeuser, runas_gid))
+ fatal("Unable to set initgroups() with gid %d", runas_gid);
+ if (setuid(runas_uid))
+ fatal("Unable to set uid to %s", changeuser);
+ }
+ if (background) { /* continue background setup */
+ int i;
+#ifdef HAVE_TIOCNOTTY
+ /* change tty */
+ ioctl(tty_fd, TIOCNOTTY, 0);
+ close(tty_fd);
+#endif
+ umask(022); /* set a default for dumb programs */
+ dup2(devnull_fd,0); /* stdin */
+ dup2(devnull_fd,1); /* stdout */
+ dup2(devnull_fd,2); /* stderr */
+#if defined(OShpux)
+ /* now close all extra fds */
+ for (i=sysconf(_SC_OPEN_MAX)-1; i>=3; --i) close(i);
+#else
+ /* now close all extra fds */
+ for (i=getdtablesize()-1; i>=3; --i) close(i);
+#endif
+
+ /* create a new session */
+#ifdef HAVE_SETSID
+ setsid();
+#else
+ setpgid(0,0);
+#endif
+ }
+ execv(startas, argv);
+ fatal("Unable to start %s: %s", startas, strerror(errno));
+}
+