diff options
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 @@ +[0;35;40m . +[0;35;40m .vir. d$b +[0;35;40m .d$$$$$$b. .cd$$b. .d$$b. d$$$$$$$$$$$b .d$$b. .d$$b. +[0;35;40m $$$$( )$$$b d$$$()$$$. d$$$$$$$b Q$$$$$$$P$$$P.$$$$$$$b. .$$$$$$$b. +[0;35;40m Q$$$$$$$$$$B$$$$$$$$P" d$$$PQ$$$$b. $$$$. .$$$P' `$$$ .$$$P' `$$$ +[0;35;40m "$$$$$$$P Q$$$$$$$b d$$$P Q$$$$b $$$$b $$$$b..d$$$ $$$$b..d$$$ +[0;35;40m d$$$$$$P" "$$$$$$$$ Q$$$ Q$$$$ $$$$$ `Q$$$$$$$P `Q$$$$$$$P +[0;35;40m $$$$$$$P `""""" "" "" Q$$$P "Q$$$P" "Q$$$P" +[0;35;40m `Q$$P" """ +[0;37;40m + +This is \n.\O (\s \m \r) \t + diff --git a/etc/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 @@ -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)); +} + |