Git init 2.0alpha master 2.0_alpha
authorKibum Kim <kb0929.kim@samsung.com>
Fri, 6 Jan 2012 15:47:29 +0000 (00:47 +0900)
committerKibum Kim <kb0929.kim@samsung.com>
Fri, 6 Jan 2012 15:47:29 +0000 (00:47 +0900)
197 files changed:
BUGS [new file with mode: 0644]
COPYING [new file with mode: 0644]
ChangeLog [new file with mode: 0644]
Makefile [new file with mode: 0644]
README [new file with mode: 0644]
TODO.scripts [new file with mode: 0644]
_darcs/current/BUGS [new file with mode: 0644]
_darcs/current/COPYING [new file with mode: 0644]
_darcs/current/ChangeLog [new file with mode: 0644]
_darcs/current/Makefile [new file with mode: 0644]
_darcs/current/README [new file with mode: 0644]
_darcs/current/TODO.scripts [new file with mode: 0644]
_darcs/current/biblio.bib [new file with mode: 0644]
_darcs/current/contrib/ensureifup [new file with mode: 0644]
_darcs/current/contrib/ifstate [new file with mode: 0644]
_darcs/current/contrib/ifstate-check [new file with mode: 0644]
_darcs/current/debian/TODO [new file with mode: 0644]
_darcs/current/debian/changelog [new file with mode: 0644]
_darcs/current/debian/conffiles [new file with mode: 0644]
_darcs/current/debian/config [new file with mode: 0644]
_darcs/current/debian/control [new file with mode: 0644]
_darcs/current/debian/copyright [new file with mode: 0644]
_darcs/current/debian/dirs [new file with mode: 0644]
_darcs/current/debian/ifupdown-clean.init [new file with mode: 0644]
_darcs/current/debian/ifupdown.default [new file with mode: 0644]
_darcs/current/debian/ifupdown.init [new file with mode: 0644]
_darcs/current/debian/po/POTFILES.in [new file with mode: 0644]
_darcs/current/debian/po/ca.po [new file with mode: 0644]
_darcs/current/debian/po/cs.po [new file with mode: 0644]
_darcs/current/debian/po/da.po [new file with mode: 0644]
_darcs/current/debian/po/de.po [new file with mode: 0644]
_darcs/current/debian/po/el.po [new file with mode: 0644]
_darcs/current/debian/po/es.po [new file with mode: 0644]
_darcs/current/debian/po/fr.po [new file with mode: 0644]
_darcs/current/debian/po/it.po [new file with mode: 0644]
_darcs/current/debian/po/ja.po [new file with mode: 0644]
_darcs/current/debian/po/lt.po [new file with mode: 0644]
_darcs/current/debian/po/nl.po [new file with mode: 0644]
_darcs/current/debian/po/pl.po [new file with mode: 0644]
_darcs/current/debian/po/pt_BR.po [new file with mode: 0644]
_darcs/current/debian/po/ru.po [new file with mode: 0644]
_darcs/current/debian/po/sv.po [new file with mode: 0644]
_darcs/current/debian/po/templates.pot [new file with mode: 0644]
_darcs/current/debian/po/tr.po [new file with mode: 0644]
_darcs/current/debian/po/zh_CN.po [new file with mode: 0644]
_darcs/current/debian/postinst [new file with mode: 0644]
_darcs/current/debian/postrm [new file with mode: 0644]
_darcs/current/debian/preinst [new file with mode: 0644]
_darcs/current/debian/rules [new file with mode: 0644]
_darcs/current/debian/templates.master [new file with mode: 0644]
_darcs/current/debian/testbuild [new file with mode: 0644]
_darcs/current/debian/upgrade-from-0.5.x.pl [new file with mode: 0644]
_darcs/current/examples/bridge [new file with mode: 0644]
_darcs/current/examples/check-mac-address.sh [new file with mode: 0644]
_darcs/current/examples/generate-interfaces.pl [new file with mode: 0644]
_darcs/current/examples/get-mac-address.sh [new file with mode: 0644]
_darcs/current/examples/network-interfaces [new file with mode: 0644]
_darcs/current/examples/pcmcia-compat.sh [new file with mode: 0644]
_darcs/current/examples/ping-places.sh [new file with mode: 0644]
_darcs/current/execution.dia [new file with mode: 0644]
_darcs/current/ifup.8 [new file with mode: 0644]
_darcs/current/ifupdown.nw [new file with mode: 0644]
_darcs/current/interfaces.5.pre [new file with mode: 0644]
_darcs/current/makecdep.sh [new file with mode: 0644]
_darcs/current/makenwdep.sh [new file with mode: 0644]
_darcs/current/modules.dia [new file with mode: 0644]
_darcs/inventory [new file with mode: 0644]
_darcs/patches/20050322184259-48b0a-3d7d00a0c38d726902f24ae37090ed7af95dc35b.gz [new file with mode: 0644]
_darcs/patches/20050322185711-48b0a-265b47864d2d5eb1b5e40dcae77f4234e83e1e09.gz [new file with mode: 0644]
_darcs/patches/20050322185930-48b0a-899f2c66d03fccd88c81a91a27ad918e83df8241.gz [new file with mode: 0644]
_darcs/patches/20050322190943-48b0a-e970d73397730c0825bb9d37e0ac15607857ce11.gz [new file with mode: 0644]
_darcs/patches/20050322191425-48b0a-338ca9e6e811ee13e25fcac84c499fa6ee5b81f6.gz [new file with mode: 0644]
_darcs/patches/20050325172759-48b0a-b001b9856880f508cee8ff667615da2c16df3158.gz [new file with mode: 0644]
_darcs/patches/20050325172831-48b0a-6d40f49e987c5c8dbf4ad2f0f6285d84fb51e3fb.gz [new file with mode: 0644]
_darcs/patches/20050325173048-48b0a-f17b1c4e81302f32ea5341c165c72335487c4e0d.gz [new file with mode: 0644]
_darcs/patches/20050325173537-48b0a-404f6e17843f4e0292bf258e5542e9802a159b14.gz [new file with mode: 0644]
_darcs/patches/20050325174738-48b0a-508807aae413654455d5d3c00c7717af85ee4c17.gz [new file with mode: 0644]
_darcs/patches/20050325174749-48b0a-61da41cded8e77e4347a964ee2111d9b21a2ceea.gz [new file with mode: 0644]
_darcs/patches/20050325174926-48b0a-935743f08e999b2ddb6041e3fbd29ec1298555d8.gz [new file with mode: 0644]
_darcs/patches/20050326151125-48b0a-c2ed89301d3a7a42fed7174513023f9067a1a347.gz [new file with mode: 0644]
_darcs/patches/20050326151130-48b0a-e655ac6f135e14c6f088be1a687c07774c58e96d.gz [new file with mode: 0644]
_darcs/patches/20050331140306-48b0a-192b390dc5d22de8e61d5e3c21370d44bca6726e.gz [new file with mode: 0644]
_darcs/patches/20050403071601-48b0a-277064f82b402d73dd3e9f4dc18edec161e592f8.gz [new file with mode: 0644]
_darcs/patches/20050403130722-48b0a-cc5a3bf9eb540a9ba9e130626912237e96a9609d.gz [new file with mode: 0644]
_darcs/patches/20050403133706-48b0a-ac0145fc85e019fecf12356618aa3ecc6aef73ff.gz [new file with mode: 0644]
_darcs/patches/20050403142603-48b0a-ea9f259b5bc7061a3cfcb23e791d27dcaffbb898.gz [new file with mode: 0644]
_darcs/patches/20050403150334-48b0a-1bec190d7c5130a0de8b79579a1e664bdfe6303f.gz [new file with mode: 0644]
_darcs/patches/20050403150343-48b0a-02e148db83abd6cd9f9e6ec53a2a1916a38a61cb.gz [new file with mode: 0644]
_darcs/patches/20050403150657-48b0a-15ca5d98146a5b255dd993de9e8ccb07ce586b20.gz [new file with mode: 0644]
_darcs/patches/20050403150711-48b0a-b7a219596d7793c014e937d477b07e8cf5cf9033.gz [new file with mode: 0644]
_darcs/patches/20050403150728-48b0a-ad57c1b54ea04699dd8454be692cf0ac25c599de.gz [new file with mode: 0644]
_darcs/patches/20050403154821-48b0a-c05c4823816cc11771bd66a8eef9baa14ff29e1e.gz [new file with mode: 0644]
_darcs/patches/20050403155657-48b0a-a78731fa7b94026a1bce3d86ec14703e4595ad21.gz [new file with mode: 0644]
_darcs/patches/20050403160939-48b0a-69fa8a1fcabd5f848efb68b6efb17d88ea9846e2.gz [new file with mode: 0644]
_darcs/patches/20050403160952-48b0a-858bcd92fe2ecda0dff3f0f2d6f4bb88791dd336.gz [new file with mode: 0644]
_darcs/patches/20050403161110-48b0a-710fb33717b518175348f16756bc6248934ae15a.gz [new file with mode: 0644]
_darcs/patches/20050403161538-48b0a-75ab76ed9925211a1b83efde1cc4a213f429a7be.gz [new file with mode: 0644]
_darcs/patches/20050403161611-48b0a-5dc34a325877de7548d9f4636b75e75d71f8344c.gz [new file with mode: 0644]
_darcs/patches/20050403161634-48b0a-9010b91cdccf9ad2cffd13e848384692469232bd.gz [new file with mode: 0644]
_darcs/patches/20050403161830-48b0a-4cbfbff1753740cb4e4e72b6309621f170caeaae.gz [new file with mode: 0644]
_darcs/patches/20050403164423-48b0a-f4c3920fcf3caefba1297b1ade7338990f1c859f.gz [new file with mode: 0644]
_darcs/patches/20050403164757-48b0a-8ad09d3f62ee0d157e4648a67ef16f680abe8933.gz [new file with mode: 0644]
_darcs/patches/20050403164804-48b0a-e909e1e9ed995134a316a22ebc1ffa8d5b3f633a.gz [new file with mode: 0644]
_darcs/patches/20050403170911-48b0a-1b052d27df2f8d7764bd5aa71c832aa5f73aa122.gz [new file with mode: 0644]
_darcs/patches/20050403170919-48b0a-40bc9c8afdf3b2ec6cfb9cc84222991be5495c23.gz [new file with mode: 0644]
_darcs/patches/20050404011259-48b0a-db60e8597853894dc22ff0226ecf8ea7dfb2bd0f.gz [new file with mode: 0644]
_darcs/patches/20050404030039-48b0a-993cd391cfa3d828a35b52da39abed02d69d4d50.gz [new file with mode: 0644]
_darcs/patches/20050404030209-48b0a-3d326cb89210df162b267bc2120ca20066deb39e.gz [new file with mode: 0644]
_darcs/patches/20050404030334-48b0a-49ae19612c6b7d8211c6b89239397064c53f7cdf.gz [new file with mode: 0644]
_darcs/patches/20050404111917-48b0a-3666132d54f974fa92dd5402d4570d505724c04e.gz [new file with mode: 0644]
_darcs/patches/20050404111950-48b0a-360b54b858475ae4e78e2ef4c6e0d84b2dd6a56c.gz [new file with mode: 0644]
_darcs/patches/20050404153209-48b0a-169d4444f3c27466a8d7a3d56ddb15f41d1bb5f1.gz [new file with mode: 0644]
_darcs/patches/20050405164755-48b0a-e33319257ad5608206f0abf53c6adf7eb9a3764b.gz [new file with mode: 0644]
_darcs/patches/20050405164913-48b0a-6cb47dfd47e9259a9c588c9a61fc8cf4086d61cd.gz [new file with mode: 0644]
_darcs/patches/20050405164921-48b0a-31ba4f33e19477ff10a68ddb24c6bbd7aad63d0d.gz [new file with mode: 0644]
_darcs/patches/20050405164951-48b0a-c06ed2064f300df62ea7b8b18994d3a314e3b6b3.gz [new file with mode: 0644]
_darcs/patches/20050405173454-48b0a-7dd75d1a00e8a35a038628a6fceae4eca9e31fd3.gz [new file with mode: 0644]
_darcs/patches/20050405173752-48b0a-3437c72ae180a5c8357dca7a79f16976dd904b10.gz [new file with mode: 0644]
_darcs/patches/20050416142311-48b0a-2cc01e8f4873f2281ecea741c173d52e64b2f6ba.gz [new file with mode: 0644]
_darcs/patches/20050423030949-48b0a-07da52fd9e90c570754aff473397bbad371dd748.gz [new file with mode: 0644]
_darcs/patches/20050502135743-bb3ee-eec9c722232316e0040f3ee2baa9df3f4ecd1514.gz [new file with mode: 0644]
_darcs/patches/pending [new file with mode: 0644]
_darcs/patches/unrevert [new file with mode: 0644]
_darcs/prefs/author [new file with mode: 0644]
_darcs/prefs/binaries [new file with mode: 0644]
_darcs/prefs/boring [new file with mode: 0644]
_darcs/prefs/defaultrepo [new file with mode: 0644]
_darcs/prefs/motd [new file with mode: 0644]
_darcs/prefs/repos [new file with mode: 0644]
addrfam.c [new file with mode: 0644]
archlinux.c [new file with mode: 0644]
archlinux.h [new file with mode: 0644]
biblio.bib [new file with mode: 0644]
config.c [new file with mode: 0644]
contrib/ensureifup [new file with mode: 0644]
contrib/ifstate [new file with mode: 0644]
contrib/ifstate-check [new file with mode: 0644]
debian/TODO [new file with mode: 0644]
debian/changelog [new file with mode: 0644]
debian/conffiles [new file with mode: 0644]
debian/config [new file with mode: 0644]
debian/control [new file with mode: 0644]
debian/copyright [new file with mode: 0644]
debian/dirs [new file with mode: 0644]
debian/ifupdown-clean.init [new file with mode: 0644]
debian/ifupdown.default [new file with mode: 0644]
debian/ifupdown.init [new file with mode: 0644]
debian/interfaces [new file with mode: 0644]
debian/po/POTFILES.in [new file with mode: 0644]
debian/po/ca.po [new file with mode: 0644]
debian/po/cs.po [new file with mode: 0644]
debian/po/da.po [new file with mode: 0644]
debian/po/de.po [new file with mode: 0644]
debian/po/el.po [new file with mode: 0644]
debian/po/es.po [new file with mode: 0644]
debian/po/fr.po [new file with mode: 0644]
debian/po/it.po [new file with mode: 0644]
debian/po/ja.po [new file with mode: 0644]
debian/po/lt.po [new file with mode: 0644]
debian/po/nl.po [new file with mode: 0644]
debian/po/pl.po [new file with mode: 0644]
debian/po/pt_BR.po [new file with mode: 0644]
debian/po/ru.po [new file with mode: 0644]
debian/po/sv.po [new file with mode: 0644]
debian/po/templates.pot [new file with mode: 0644]
debian/po/tr.po [new file with mode: 0644]
debian/po/zh_CN.po [new file with mode: 0644]
debian/postinst [new file with mode: 0644]
debian/postrm [new file with mode: 0644]
debian/preinst [new file with mode: 0644]
debian/rules [new file with mode: 0755]
debian/templates [new file with mode: 0644]
debian/templates.master [new file with mode: 0644]
debian/testbuild [new file with mode: 0755]
debian/upgrade-from-0.5.x.pl [new file with mode: 0644]
defn2c.pl [new file with mode: 0755]
defn2man.pl [new file with mode: 0755]
examples/bridge [new file with mode: 0644]
examples/check-mac-address.sh [new file with mode: 0644]
examples/generate-interfaces.pl [new file with mode: 0644]
examples/get-mac-address.sh [new file with mode: 0644]
examples/network-interfaces [new file with mode: 0644]
examples/pcmcia-compat.sh [new file with mode: 0644]
examples/ping-places.sh [new file with mode: 0644]
execute.c [new file with mode: 0644]
execution.dia [new file with mode: 0644]
header.h [new file with mode: 0644]
ifup.8 [new file with mode: 0644]
ifupdown.nw [new file with mode: 0644]
inet.defn [new file with mode: 0644]
inet6.defn [new file with mode: 0644]
interfaces.5.pre [new file with mode: 0644]
ipx.defn [new file with mode: 0644]
main.c [new file with mode: 0644]
makecdep.sh [new file with mode: 0755]
makenwdep.sh [new file with mode: 0755]
modules.dia [new file with mode: 0644]

diff --git a/BUGS b/BUGS
new file mode 100644 (file)
index 0000000..ca8c82b
--- /dev/null
+++ b/BUGS
@@ -0,0 +1,310 @@
+
+---- should be okay for 0.6.5 [even sarge] ----
+
+Easy/standalone:
+     . #84697: ifupdown tarball unnecessarily large
+     . #296273: ifupdown: [patch] Improve debian/rules targets to not
+       build unnecessarily
+     . #294970: ifupdown: makenwdep.sh output is garbled if /bin/sh is a
+       POSIX sh like /bin/dash
+     . #283649: ifupdown: [PATCH] cross build
+
+     * #255222: wvdial pidfiles have non-FHS names
+     * #84074: ifupdown: --force should work even when ifstate is not
+       writable
+     * #282740: ifupdown: Please keep dhclient's leases file in /var/lib/
+       [unmerge from 246621]
+     * #127786: ifup should wait for ppp interface to appear [also 287173]
+
+Vars for scripts:
+     . #88946: please add --verbose for if.d scripts
+     . #286155: please export hook name to environment
+
+Syntax:
+     . #62633: netbase: Suggestion - rules for creating & destroying
+       interfaces
+    ** #300987: Please allow passing of values via dhclient3's -e option
+
+Interface dependencies: [see 170030 log!]
+     * #87862: Please handle virtual network devices
+     * #101317: ifupdown: support for ifenslave bond0
+     * #113230: please consider adding dependencies to interfaces
+     * #193679: ifupdown: ifdown should bring down virtual interfaces
+       before their "parent" interface
+     * #265650: Wishlist: a "shared" kind of interface
+     * #290406: ifupdown problem whith vlan devices
+     * #112992: Please allow user cmds for "ifup A" to call "ifup B"
+     * #170030: Please allow user cmds for "ifup A" to call "ifup B" 
+     * #244101: Please provide logical interface name to up/down commands
+       [not really about its title at all]
+
+Hotplug issues:
+     . #300937: Please add features for "first class" handling of hot
+       plugged interfaces
+     * #231197: Please prevent ifup A -> hotplug -> ifup A deadlock
+     * #245028: /etc/init.d/ifupdown should run earlier in /etc/rcS.d/
+
+Other script enhancements:
+     * #149395: Please add 'include' directive [also 159884]
+
+     * #139383: ifupdown: No way to pass commandline options to mapping
+       script [aslo 239150, 286332]
+     * #154442: Provide intermediate interface name to nested mapper
+       (or, in general, environment variables)
+
+---- 0.7 features ----
+
+Ifconfig-ish:
+     * #111006: Support for pump's --win-client-ident feature
+     * #143053: pptp interface support (patch)
+     * #152479: Please add support for CIPE interfaces
+     * #158089: GRE and IPIP tunnel support
+     * #160571: slattach and ifup problem
+     * #168776: ifupdown: Should accept more than one IPv6 address in
+       /etc/network/interfaces
+     * #176903: ifupdown doesn't support supersedes properly on DHCP
+       interfaces
+     * #181988: Bringing up arp-less interfaces
+     * #196877: ifupdown: Please support passing additional arguments to
+       pon
+     * #204641: ifupdown: Please include zeroconf support
+     * #205583: ifupdown: option to define an inet6 interface without
+       address [also 266021]
+     * #235993: New option "metric" for gateway routing metric
+     * #246621: ifupdown: Please (optionally) stop DHCP clients in such a
+       way that they do not relinquish leases
+     * #247050: no txqueuelen setting
+     * #256240: Please include standard way to set speed and duplex
+    ** #253472: ifupdown: dhclient stops running after cable modem
+       connection outage
+    ** #263749: manual "ifdown" needed after DHCP_NAK brings down
+       interface
+
+Include options in ifstate:
+     * #81219: `ifdown -a' doesn't work if default route changed
+     * #153222: Wish for ifstate documentation or a status command
+     * #253628: Please allow /e/n/i to be modified while ifaces are up
+     * #266175: Changing from dhcp to static IP: dhclient still running
+
+Update options/interface from "up" commands:
+     * #83922: Pls furnish DHCP-client-assigned IPaddress to "up" scripts
+     * #245642: ifupdown 0.7: Implement callback mechanism for ppp, dhcp,
+       etc
+     * #256233: ifupdown: Using environment variables in /e/n/i [well, related]
+
+Allow mapping to go from logical -> physical as well as reverse
+     * #101728: Automatic detection of hardware interface
+     * #182012: ifupdown 0.7: Implement detection of physical iface
+     * #227283: Please implement a nameif(8)-like feature
+
+Selection of ifconfig/ip/pump/dhcpd:
+     * #228380: ifupdown: Should be able to specify favoured DHCP client
+
+Unwind on Failure:
+     * #246771: ifupdown: Failure to execute mapping script not reported
+     * #286148: properly unwind ifup when up hook fails
+     * #88945: please consider adding a possibility to abort
+       initialization from an if.d script
+
+Hurd:
+     * #296115: ifupdown: [patch] Port to non-linux
+
+Crazy:
+     . #79683: /etc/network/interfaces hash '#' doesn't work at end of
+       line
+     * #119401: default gateway network route should be default to a host
+       route
+     * #150876: ifupdown: defn2c generalization
+     * #154816: Please warn about unrecognized options
+     * #170278: Suggestion: a configuration parsing utility
+     * #255217: Please provide a way to override default configuration
+       behavior
+     * #275326: Please add a "fail" interface type, that aborts
+       configuration. [crazy, but intriguing...]
+
+Reassign me:
+     * #251559: ifupdown: Wrong broadcast address is calculated for
+       aliased ifaces (but works correctly for physical iface)
+
+Example scripts:
+     * #96727: [PATCH] default route should not be set when %gateway is
+       specified [also, 152895]
+     * #106798: ifupdown: More support for ip-package  [unmerge with 87862]
+     * #120382: ifupdown: ifup should (optionally) check for link before
+       configuring the interface. [also 237155]
+     * #191644: ifupdown: please add support for user-definable static
+       routes
+     * #192235: ifupdown: What goes up must be put down, so I wrote this
+       little script.
+     * #294044: ifupdown: Would be nice to set MTU even with DHCP
+       interfaces
+     * #296071: ifupdown: feature request: for inet interfaces, support
+       config for diald / dial-on-demand
+     * #300214: Wifi map script.
+
+NMU miscellania:
+     * #150773: ifupdown: patches from NMU (0.6.4-4.1)
+     * #151465: ifupdown: patches from NMU (0.6.4-4.2, 0.6.4-4.3)
+     * #152893: ifupdown: patches from NMU (0.6.4-4.4)
+     * #208726: ifupdown: patches from NMU (0.6.4-4.5)
+     * #209006: patches from NMU (0.6.4-4.6)
+     * #242314: Ifupdown: patches for NMU (0.6.4-4.7)
+     * #263913: ifupdown: patches for NMU (0.6.4-4.9)
+     * #266282: ifupdown: NMU patch from 0.6.4-4.9 to 0.6.4-4.10
+     * #297762: ifupdown: NMU patch from 0.6.4-4.10 to 0.6.4-4.11
+
+-----
+NMU craziness...
+
+Critical bugs - fixed in NMU
+     * #264134: Removes ifstate during boot, then fails to bring
+       interfaces up because ifstate doesn't exist
+Grave bugs - fixed in NMU
+     * #208811: ifupdown: Preinst fails if /etc/network absent
+Serious policy violations - fixed in NMU
+     * #265165: ifupdown: postinst fails with: /etc/network/run/ifstate:
+       No such file or directory
+Important bugs - fixed in NMU
+     * #88947: please pass down method to if.d scripts
+     * #105342: upgrade from potato makes unuseable interfaces file.
+     * #297898: ifupdown: postinst fails: /etc/network/ifstate: no such
+       file or directory
+     * #299845: Typo in ifupdown.postinst may let the package in
+       experimental unusable !
+Normal bugs - fixed in NMU
+     * #82339: ifup: Don't mark eth1 "up" on failure
+     * #83496: [patch] Swedish translation of ifupdown template file
+     * #83542: german templates file [patch]
+     * #83804: debconf french template file for ifupdown [patch]
+     * #86895: [PATCH] ifupdown: mapping protocol not really documented
+     * #94656: ifdown -a not deconfiguring all dhcp interfaces
+     * #97782: ifupdown: inconsistency in if. state in case of error
+     * #98448: Portuguese (pt_BR) templates file [patch]
+     * #101204: ifupdown.dvi should depend on *.eps [patch]
+     * #106878: ifupdown: modprobe 3c59x and network is brought up
+       according to interfaces w/o auto
+     * #107701: Polish template file for ifupdown package
+     * #108876: [PATCH] add locking to ifup/down
+     * #112652: russian templates file [ifipdown]
+     * #113338: ifupdown: ifup marks an interface as configured even if
+       pre-up commands fail
+     * #122422: Debconf question asked at wrong time
+     * #134006: [Marc.Herbert@ens-lyon.fr: interfaces.5.pre enhancement]
+     * #138694: obscure description of "mapping" in interfaces(5)
+     * #148666: ifup: Don't mark eth0 "up" on failure
+     * #151932: ifupdown: ifdown -a; ifup -a
+     * #152853: "[" gets too many arguments in preinst
+     * #169194: ifupdown: ifup has bogus exit status when failing
+     * #175679: Documentation doesn't match implementation of mappings
+     * #178226: ifupdown: if*.d are not in the list of files
+     * #196366: ifupdown: Can't use dhclient on more than one interface
+     * #196865: Please stop dhclient3 such that it runs its hook script
+     * #198841: ifupdown: ifdown brings down all pump enabled devices
+     * #204468: ifupdown: ifup(8) should describe how to set mapping
+     * #207388: ifupdown: dh_suidregister-is-obsolete
+     * #224468: ifupdown: hw option not implemented correctly
+     * #255228: postrm doesn't delete configuration files on purge
+     * #258965: ifupdown: FTBFS with gcc-3.4: label at end of compound
+       statement
+     * #259609: ifupdown: ifdown -a does not turn off all interfaces in
+       ifstate
+     * #266479: postinst fails in pbuilder with : /etc/network/ifstate:
+       Permission denied
+Minor bugs - fixed in NMU (29 bugs)
+     * #81150: ifupdown: man page title
+     * #86410: does hostname lookup when no service is running
+     * #112012: please document initialization order for ifupdown -a
+     * #114429: ifupdown: pump works also with 2.4.x kernels
+     * #138403: interfaces(5): 'auto' takes physical iface names as args
+     * #141634: ifupdown: missing documentation for /etc/network/if-up.d
+       and friends
+     * #150720: netbase: interfaces file should support all ifconfig
+       options, including MTU
+     * #156789: ifupdown: Document precedence of dhcp clients in
+       interfaces(5)
+     * #157698: ifupdown: man missing if-up.d, etc.
+     * #160918: Typo in interfaces(5) : s/three/four/
+     * #172147: ifupdown: How to use multiple IPs per NIC is not
+       documented
+     * #173101: minor: get-mac-address.sh missing a ")"
+     * #177896: ifupdown: typo in network-interfaces
+     * #178630: Should Suggest dhcp-client
+     * #180000: ifupdown: if(up|down) --help output for -a slightly
+       misleading
+     * #186316: ifupdown: interfaces(5) man page needs s/three/four/ in
+       'IFACE OPTIONS'
+     * #193488: Syntax error in examples/get-mac-address.sh
+     * #213068: ifupdown: ifup(8) should document "IFACE=LIFACE" syntax
+     * #216716: ifupdown: interfaces(5) gives slightly incorrect
+       description of mapping
+     * #231404: ifupdown: -s option undocumented
+     * #232347: ifupdown: interfaces(5) manpage misleading
+     * #242527: ifupdown-0.6.4-4.7 does not work with the (experimental)
+       dhcp-client (3.0.1betaRC4-1) package
+     * #242537: ifupdown: does not bring up eth0 via dhclient anymore
+     * #247772: /usr/share/man/man8/ifup.8.gz: add usage examples
+     * #255053: /usr/share/doc/ifupdown/examples/check-mac-address.sh:
+       [PATCH] syntax error 
+     * #255218: interfaces(5) should mention wireless(7)
+     * #255574: Fixes for XSI:isms
+     * #286166: inconsistency with manpage: pre-up hook failures prevent
+       config
+     * #287172: typo in manpage
+Wishlist items - fixed in NMU (43 bugs)
+     * #36073: Please write an app to generate /e/n/interfaces
+     * #57731: netbase: MTU option with ifup and ifdown
+     * #57830: Please use /e/init.d/network to generate /e/n/interfaces
+     * #67743: interfaces should configure local end of ipv6 over ipv4
+       tunnel
+     * #76142: Please add a new 'noip' method for unconfigured interfaces
+     * #79999: ifupdown: Need ability to specify media type
+     * #84602: ifup needs ability to specify hardware address
+     * #86902: ifupdown: contributed scripts to keep iface up
+     * #88948: Add "manual" method to ifupdown
+     * #92993: ifupdown: How do I configure eth0 to have no address?
+     * #96265: ifupdown: Why are address and netmask required for
+       v4tunnel method?
+     * #100397: should support MTU
+     * #106533: MTU from interfaces file
+     * #110198: ifupdown: fixing some small typos in pt_BR debconf
+       template translation [PATCH]
+     * #113620: udhcpc: is it possible to integrate udhcpc with Debian's
+       /etc/network
+     * #116646: udhcpc: No init.d scripts
+     * #121755: Please warn on upgrade if /e/n/i lacks "auto lo"
+     * #129003: /etc/network/interfaces: Please allow for no IP address
+     * #135502: ifupdown: set hardware address
+     * #141885: ifupdown: Patch to provide 6to4 support (adds local
+       option) and new null address family
+     * #154517: ifupdown: please consider adding distclean target
+     * #164823: bridge-utils: /etc/network/interfaces does not permit the
+       configuration of a bridge without an IP address
+     * #171981: ifupdown: ifup requires netmask for an interface with ip
+       0.0.0.0
+     * #174764: ifupdown: Danish template translation
+     * #190698: Please add 'custom' method for iface stanzas
+     * #200786: ifupdown: Please switch to gettext-based debconf
+       templates
+     * #203636: Please mention extended iface options in interfaces(5)
+     * #207727: ifupdown: spanish debconf templates
+     * #210436: ifupdown: Japanese debconf messages
+     * #213619: ifupdown: Please document ifdown -a behaviour correctly
+       in the manpage
+     * #213723: [INTL:nl] new po-debconf template translation in Dutch.
+     * #229503: Please add Greek debconf translation (attached)
+     * #229527: Please add Greek debconf translation (attached)
+     * #231910: ifupdown: [INTL:zh_CN] Simplified Chinese translation to
+       debconf templates
+     * #231995: Czech translation of ifupdown debconf templates
+     * #239142: [INTL:tr] Turkish po-debconf translation
+     * #241248: Updated Danish po-debconf translation
+     * #242607: /etc/init.d/ifupdown: Please create run directory if not
+       present
+     * #245067: Please delete ifstate file on shutdown
+     * #248717: [l10:ca] ifupdown catalan debconf templates
+     * #249233: ifupdown: Lithuanian translation of debconf templates
+     * #250713: Should be Suggests: iproute, dhcp3-client, ppp
+     * #284123: [INTL:it] Italian debconf templates translation for
+       ifupdown
+Normal bugs - resolved (1 bug)
+     * #298232: ifupdown: a few files are not cleanup at upgrade
diff --git a/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..d60c31a
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+                   GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                           NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+           How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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; either version 2 of the License, or
+    (at your option) any later version.
+
+    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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year  name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/ChangeLog b/ChangeLog
new file mode 100644 (file)
index 0000000..ed3ed29
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,131 @@
+
+ChangeLog for ifupdown
+======================
+
+2000-11-18   0.6.4  Anthony Towns <aj@azure.humbug.org.au>
+
+       * Shouldn't use errno, apparently. Should use ferror() instead.
+         What a completely stupid API. Thanks to Roderich Schupp for
+         pointing this out.
+
+       * Use $(( .. )) in a shell for math, not $[..] which is bash only.
+         Thanks to Kalle Olavi Niemitalo for this one.
+
+2000-10-20   0.6.3  Anthony Towns <aj@azure.humbug.org.au>
+
+       * Fixed horrible bugs where to get n structures I realloc n
+         bytes, instead of n * sizeof(..) bytes. Shame on me.
+
+       * Don't commit the new networking state to the statefile when
+         --no-act is happening (after all, there *aren't* any changes...)
+
+       * Bring forward some changes from the .deb:
+               - /var/run/ifupdown.state -> /etc/network/ifstate
+                 (/var may be NFS mounted...)
+               - Add /e/n/ifstate to manpage.
+               - Add pointopoint support for inet/static.
+               - dhcpcd works with all kernels, not "2.0 and 2.2" :)
+               - Add provider support for ppp. It's still a kludge.
+               - Update ipx address family.
+               - Remove noauto from the interfaces manpage.
+
+2000-09-22   0.6.2  Anthony Towns <aj@azure.humbug.org.au>
+
+       * Aieee. cardmgr (pcmcia utility) starts with stdin *closed*,
+         rather than redirected from /dev/null. So when I open pipes
+         and stuff, it can come up as fd 0. Not good. Fake fd 0,1,2 as
+         /dev/null if they're not already existant.
+
+       * Fixed silly bug about not properly downing interfaces too.
+
+2000-09-15   0.6.1  Anthony Towns <aj@azure.humbug.org.au>
+
+       * Fixed up defn2man.pl so that /usr/share/doc (eg) isn't italicised.
+
+       * Cleaned up execute.c and updated literate comments to match new
+         behaviour.
+       * Update literate comments for main.c too.
+
+       * Fixed --no-act and --verbose to actually work, rather than just
+         be faked. Both are now program-wide variables declared in
+         main.c.
+
+       * Included some explanatory diagrams (.dia's), and some build code
+         to actually include them in the woven output. They're done as .eps
+         files which pdflatex can't handle. Bummer.
+
+       * Largely updated manpage to reflect changes in 0.6
+
+       * Changed behaviour of --no-act to still run any mappings. (Use
+         --no-mappings as well to disable those)
+       * Add a --version option.
+       * Only update the state file if the interface was found.
+
+2000-06-09   0.6.0  Anthony Towns <aj@azure.humbug.org.au>
+
+       * STILL TO DO: update manpage, tidy up the changed literate source.
+
+       * run-parts /etc/network/if-{up,down,pre-up,post-down}.d is called
+         after running any iface-specific scripts.
+       * Environment of called programs contains exactly:
+               IF_<option>=<value>
+               IFACE=<physical iface name>
+               MODE=<start or stop>
+         and whatever /bin/sh defaults to initialising.
+
+       * Each option may only be specified once.
+       * Added `auto lo eth0', remove `noauto'.
+       * Added mapping support. Thanks to Marc Haber for the inspiration.
+       * Removed scheme support.
+       * Report line-number as well as file name, when read_interfaces()
+         fails.
+
+       * Added /var/run/ifupdown.state
+       * Made ifdown -a use the statefile rather than the config file.
+
+       * Added inet6 methods static and v4tunnel. (Thanks to Bastian
+         Blank for a patch for the former)
+       * Made "pre-up", "down", "post-down" manpage descriptions
+         match the "up" description. Yay for redundancy.
+
+2000-03-23   0.5.5  Anthony Towns <aj@azure.humbug.org.au>
+
+       * Added "pre-up" and "post-down" options.
+
+2000-02-29   0.5.4  Anthony Towns <aj@azure.humbug.org.au>
+
+       * Some more minor cleanups.
+
+2000-02-29   0.5.3  Anthony Towns <aj@azure.humbug.org.au>
+
+       * Minor cleanups; added ifup.8.ps.gz and interfaces.5.ps.gz
+         to the default target.
+
+2000-02-28   0.5.2  Anthony Towns <aj@azure.humbug.org.au>
+
+       * Change the dhcpcd/dhcpcd-sv stuff to refer to just
+         /sbin/dhcpcd, instead of checking for dhcpcd-sv
+         specifically.
+
+       * Add a manpage for /etc/network/interfaces, thanks
+         to Joey Hess. Rearranged ifup(8) a bit, and
+         added some stuff to it. Also actually wrote the
+         *bold* and /italic/ handling.
+
+       * Finally got sick of lines longer than 80 chars in
+         .defn files and added \ escaping of newlines.
+
+2000-02-13   0.5.1  Anthony Towns <aj@azure.humbug.org.au>
+
+       * Cleaned up some of the source.
+
+       * Redefined .defn files a bit: added a description tag for
+         methods, and made the options list be documentation
+         for the options rather than something useful for C.
+
+       * Added defn2man.pl, and made a manpage (generated from
+         ifupdown.8.pre and defn2man.pl).
+
+2000-02-07   0.5.0  Anthony Towns <aj@azure.humbug.org.au>
+
+       * Initial release, from netbase.deb, 3.16-9
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..35007c5
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,102 @@
+CFLAGS := -Wall -W -g -O2 -D'IFUPDOWN_VERSION="0.6.5"'
+CC := gcc
+
+CFILES := addrfam.c execute.c config.c main.c archlinux.c
+HFILES := header.h archlinux.h
+PERLFILES := defn2c.pl defn2man.pl
+DEFNFILES := inet.defn ipx.defn inet6.defn
+
+OBJ := main.o addrfam.o execute.o config.o \
+       $(patsubst %.defn,%.o,$(DEFNFILES)) archlinux.o
+
+MAN := $(patsubst %.defn,%.man,$(DEFNFILES))
+
+default : executables
+all : executables docs
+
+executables : ifup ifdown ifup.8 ifdown.8 interfaces.5
+docs : ifupdown.ps.gz ifup.8.ps.gz interfaces.5.ps.gz ifupdown.pdf
+
+.PHONY : executables 
+.PHONY : clean clobber
+
+install :
+       install -m 0755 -d     ${BASEDIR}/sbin
+       install -m 0755 ifup   ${BASEDIR}/sbin
+       ln ${BASEDIR}/sbin/ifup ${BASEDIR}/sbin/ifdown  
+
+clean :
+       rm -f *.aux *.toc *.log *.bbl *.blg *.ps *.eps *.pdf
+       rm -f *.o *.d $(patsubst %.defn,%.c,$(DEFNFILES)) *~
+       rm -f $(patsubst %.defn,%.man,$(DEFNFILES))
+       rm -f ifup ifdown interfaces.5 ifdown.8
+       rm -f ifupdown.dvi *.ps{,.gz}
+
+clobber : clean
+       rm -f ifupdown.tex $(PERLFILES) $(CFILES) $(HFILES) $(DEFNFILES)
+
+distclean : clobber
+       rm -f makecdep.sh makenwdep.sh Makefile
+ifup: $(OBJ)
+       $(CC) $(CFLAGS) $^ $(LDFLAGS) $(OUTPUT_OPTION)
+
+ifdown: ifup
+       ln -sf ifup ifdown
+interfaces.5: interfaces.5.pre $(MAN)
+       sed $(foreach man,$(MAN),-e '/^##ADDRESSFAM##$$/r $(man)') \
+            -e '/^##ADDRESSFAM##$$/d' < $< > $@        
+
+ifdown.8: ifup.8
+       ln -sf $< $@
+
+%.5.ps: %.5
+       groff -mandoc -Tps $< > $@
+%.8.ps: %.8
+       groff -mandoc -Tps $< > $@
+ifupdown.dvi: modules.eps execution.eps
+ifupdown.ps: modules.eps execution.eps
+ifupdown.pdf: modules.pdf execution.pdf
+%.tex : %.nw
+       noweave -delay -index -latex $< >$@
+
+%.bbl : %.tex biblio.bib
+       latex $<
+       bibtex $(basename $<)
+
+%.dvi : %.tex %.bbl
+       latex $<
+       latex $<
+
+%.pdf : %.tex %.bbl
+       pdflatex $<
+       pdflatex $<
+
+%.ps : %.dvi
+       dvips -o $@ $<
+
+%.gz : %
+       gzip --best --stdout $< >$@
+%.eps : %.dia
+       dia --nosplash -e $@ $<
+
+%.pdf : %.eps
+       gs -q -sDEVICE=pdfwrite -dNOPAUSE -sOutputFile=$@ - < $<
+%.d: %.nw makenwdep.sh
+       ./makenwdep.sh $< > $@
+%.d: %.c makecdep.sh
+       ./makecdep.sh $< > $@
+%.c : %.defn defn2c.pl
+       ./defn2c.pl $< > $@
+%.man: %.defn defn2man.pl
+       ./defn2man.pl $< > $@
+
+include-deps := YES
+ifneq "" "$(filter %clean,$(MAKECMDGOALS))"
+include-deps := NO
+endif
+ifeq "clobber" "$(MAKECMDGOALS)"
+include-deps := NO
+endif
+ifeq "$(strip $(include-deps))" "YES"
+include ifupdown.d
+endif
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..570068c
--- /dev/null
+++ b/README
@@ -0,0 +1,35 @@
+
+ifupdown
+========
+
+ifup and ifdown are two utilities to assist with basic interface
+manipulation.
+
+
+Building
+--------
+
+To build from CVS, you need to generate the tangled sources from the
+literate source. To do this, you'll need Norman Ramsey's noweb program
+(nowebm.deb for Debian users). The following instructions should be enough
+to build from nothing but ifupdown.nw.
+
+       notangle -t8 -RMakefile ifupdown.nw >Makefile
+       notangle -Rmakenwdep.sh ifupdown.nw >makenwdep.sh
+       chmod 755 makenwdep.sh
+       make
+
+After that, you should just need some standard tools like gcc and perl.
+
+
+Literate Source
+---------------
+
+To view the pretty-printed literate source code, you can make any of
+the targets:
+
+       ifupdown.ps
+       ifupdown.dvi
+or     ifupdown.pdf
+
+You'll need a LaTeX distribution to do this, as well as noweb.
diff --git a/TODO.scripts b/TODO.scripts
new file mode 100644 (file)
index 0000000..110bd14
--- /dev/null
@@ -0,0 +1,27 @@
+
+       bridging
+iface brg0 inet static
+    bridge eth0 eth1
+    address 1.2.3.4
+    netmask 255.255.255.0
+
+       bonding
+(same as bonding, except both cards go to the same place)
+(i think it's that simple)
+
+       multiple-addresses (can be on varied subnets) [87862]
+iface brg0 inet static
+    address 1.2.3.4
+    netmask 255.255.255.0
+    gateway 1.2.3.1
+    extra-addresses 1.2.3.5 192.168.1.16   
+
+       set-mac [84602]
+       set-mtu [57731]
+
+       pppoe? [92993]
+iface ppp1 inet ppp
+
+
+       NFS mounts?
+       DNS
diff --git a/_darcs/current/BUGS b/_darcs/current/BUGS
new file mode 100644 (file)
index 0000000..ca8c82b
--- /dev/null
@@ -0,0 +1,310 @@
+
+---- should be okay for 0.6.5 [even sarge] ----
+
+Easy/standalone:
+     . #84697: ifupdown tarball unnecessarily large
+     . #296273: ifupdown: [patch] Improve debian/rules targets to not
+       build unnecessarily
+     . #294970: ifupdown: makenwdep.sh output is garbled if /bin/sh is a
+       POSIX sh like /bin/dash
+     . #283649: ifupdown: [PATCH] cross build
+
+     * #255222: wvdial pidfiles have non-FHS names
+     * #84074: ifupdown: --force should work even when ifstate is not
+       writable
+     * #282740: ifupdown: Please keep dhclient's leases file in /var/lib/
+       [unmerge from 246621]
+     * #127786: ifup should wait for ppp interface to appear [also 287173]
+
+Vars for scripts:
+     . #88946: please add --verbose for if.d scripts
+     . #286155: please export hook name to environment
+
+Syntax:
+     . #62633: netbase: Suggestion - rules for creating & destroying
+       interfaces
+    ** #300987: Please allow passing of values via dhclient3's -e option
+
+Interface dependencies: [see 170030 log!]
+     * #87862: Please handle virtual network devices
+     * #101317: ifupdown: support for ifenslave bond0
+     * #113230: please consider adding dependencies to interfaces
+     * #193679: ifupdown: ifdown should bring down virtual interfaces
+       before their "parent" interface
+     * #265650: Wishlist: a "shared" kind of interface
+     * #290406: ifupdown problem whith vlan devices
+     * #112992: Please allow user cmds for "ifup A" to call "ifup B"
+     * #170030: Please allow user cmds for "ifup A" to call "ifup B" 
+     * #244101: Please provide logical interface name to up/down commands
+       [not really about its title at all]
+
+Hotplug issues:
+     . #300937: Please add features for "first class" handling of hot
+       plugged interfaces
+     * #231197: Please prevent ifup A -> hotplug -> ifup A deadlock
+     * #245028: /etc/init.d/ifupdown should run earlier in /etc/rcS.d/
+
+Other script enhancements:
+     * #149395: Please add 'include' directive [also 159884]
+
+     * #139383: ifupdown: No way to pass commandline options to mapping
+       script [aslo 239150, 286332]
+     * #154442: Provide intermediate interface name to nested mapper
+       (or, in general, environment variables)
+
+---- 0.7 features ----
+
+Ifconfig-ish:
+     * #111006: Support for pump's --win-client-ident feature
+     * #143053: pptp interface support (patch)
+     * #152479: Please add support for CIPE interfaces
+     * #158089: GRE and IPIP tunnel support
+     * #160571: slattach and ifup problem
+     * #168776: ifupdown: Should accept more than one IPv6 address in
+       /etc/network/interfaces
+     * #176903: ifupdown doesn't support supersedes properly on DHCP
+       interfaces
+     * #181988: Bringing up arp-less interfaces
+     * #196877: ifupdown: Please support passing additional arguments to
+       pon
+     * #204641: ifupdown: Please include zeroconf support
+     * #205583: ifupdown: option to define an inet6 interface without
+       address [also 266021]
+     * #235993: New option "metric" for gateway routing metric
+     * #246621: ifupdown: Please (optionally) stop DHCP clients in such a
+       way that they do not relinquish leases
+     * #247050: no txqueuelen setting
+     * #256240: Please include standard way to set speed and duplex
+    ** #253472: ifupdown: dhclient stops running after cable modem
+       connection outage
+    ** #263749: manual "ifdown" needed after DHCP_NAK brings down
+       interface
+
+Include options in ifstate:
+     * #81219: `ifdown -a' doesn't work if default route changed
+     * #153222: Wish for ifstate documentation or a status command
+     * #253628: Please allow /e/n/i to be modified while ifaces are up
+     * #266175: Changing from dhcp to static IP: dhclient still running
+
+Update options/interface from "up" commands:
+     * #83922: Pls furnish DHCP-client-assigned IPaddress to "up" scripts
+     * #245642: ifupdown 0.7: Implement callback mechanism for ppp, dhcp,
+       etc
+     * #256233: ifupdown: Using environment variables in /e/n/i [well, related]
+
+Allow mapping to go from logical -> physical as well as reverse
+     * #101728: Automatic detection of hardware interface
+     * #182012: ifupdown 0.7: Implement detection of physical iface
+     * #227283: Please implement a nameif(8)-like feature
+
+Selection of ifconfig/ip/pump/dhcpd:
+     * #228380: ifupdown: Should be able to specify favoured DHCP client
+
+Unwind on Failure:
+     * #246771: ifupdown: Failure to execute mapping script not reported
+     * #286148: properly unwind ifup when up hook fails
+     * #88945: please consider adding a possibility to abort
+       initialization from an if.d script
+
+Hurd:
+     * #296115: ifupdown: [patch] Port to non-linux
+
+Crazy:
+     . #79683: /etc/network/interfaces hash '#' doesn't work at end of
+       line
+     * #119401: default gateway network route should be default to a host
+       route
+     * #150876: ifupdown: defn2c generalization
+     * #154816: Please warn about unrecognized options
+     * #170278: Suggestion: a configuration parsing utility
+     * #255217: Please provide a way to override default configuration
+       behavior
+     * #275326: Please add a "fail" interface type, that aborts
+       configuration. [crazy, but intriguing...]
+
+Reassign me:
+     * #251559: ifupdown: Wrong broadcast address is calculated for
+       aliased ifaces (but works correctly for physical iface)
+
+Example scripts:
+     * #96727: [PATCH] default route should not be set when %gateway is
+       specified [also, 152895]
+     * #106798: ifupdown: More support for ip-package  [unmerge with 87862]
+     * #120382: ifupdown: ifup should (optionally) check for link before
+       configuring the interface. [also 237155]
+     * #191644: ifupdown: please add support for user-definable static
+       routes
+     * #192235: ifupdown: What goes up must be put down, so I wrote this
+       little script.
+     * #294044: ifupdown: Would be nice to set MTU even with DHCP
+       interfaces
+     * #296071: ifupdown: feature request: for inet interfaces, support
+       config for diald / dial-on-demand
+     * #300214: Wifi map script.
+
+NMU miscellania:
+     * #150773: ifupdown: patches from NMU (0.6.4-4.1)
+     * #151465: ifupdown: patches from NMU (0.6.4-4.2, 0.6.4-4.3)
+     * #152893: ifupdown: patches from NMU (0.6.4-4.4)
+     * #208726: ifupdown: patches from NMU (0.6.4-4.5)
+     * #209006: patches from NMU (0.6.4-4.6)
+     * #242314: Ifupdown: patches for NMU (0.6.4-4.7)
+     * #263913: ifupdown: patches for NMU (0.6.4-4.9)
+     * #266282: ifupdown: NMU patch from 0.6.4-4.9 to 0.6.4-4.10
+     * #297762: ifupdown: NMU patch from 0.6.4-4.10 to 0.6.4-4.11
+
+-----
+NMU craziness...
+
+Critical bugs - fixed in NMU
+     * #264134: Removes ifstate during boot, then fails to bring
+       interfaces up because ifstate doesn't exist
+Grave bugs - fixed in NMU
+     * #208811: ifupdown: Preinst fails if /etc/network absent
+Serious policy violations - fixed in NMU
+     * #265165: ifupdown: postinst fails with: /etc/network/run/ifstate:
+       No such file or directory
+Important bugs - fixed in NMU
+     * #88947: please pass down method to if.d scripts
+     * #105342: upgrade from potato makes unuseable interfaces file.
+     * #297898: ifupdown: postinst fails: /etc/network/ifstate: no such
+       file or directory
+     * #299845: Typo in ifupdown.postinst may let the package in
+       experimental unusable !
+Normal bugs - fixed in NMU
+     * #82339: ifup: Don't mark eth1 "up" on failure
+     * #83496: [patch] Swedish translation of ifupdown template file
+     * #83542: german templates file [patch]
+     * #83804: debconf french template file for ifupdown [patch]
+     * #86895: [PATCH] ifupdown: mapping protocol not really documented
+     * #94656: ifdown -a not deconfiguring all dhcp interfaces
+     * #97782: ifupdown: inconsistency in if. state in case of error
+     * #98448: Portuguese (pt_BR) templates file [patch]
+     * #101204: ifupdown.dvi should depend on *.eps [patch]
+     * #106878: ifupdown: modprobe 3c59x and network is brought up
+       according to interfaces w/o auto
+     * #107701: Polish template file for ifupdown package
+     * #108876: [PATCH] add locking to ifup/down
+     * #112652: russian templates file [ifipdown]
+     * #113338: ifupdown: ifup marks an interface as configured even if
+       pre-up commands fail
+     * #122422: Debconf question asked at wrong time
+     * #134006: [Marc.Herbert@ens-lyon.fr: interfaces.5.pre enhancement]
+     * #138694: obscure description of "mapping" in interfaces(5)
+     * #148666: ifup: Don't mark eth0 "up" on failure
+     * #151932: ifupdown: ifdown -a; ifup -a
+     * #152853: "[" gets too many arguments in preinst
+     * #169194: ifupdown: ifup has bogus exit status when failing
+     * #175679: Documentation doesn't match implementation of mappings
+     * #178226: ifupdown: if*.d are not in the list of files
+     * #196366: ifupdown: Can't use dhclient on more than one interface
+     * #196865: Please stop dhclient3 such that it runs its hook script
+     * #198841: ifupdown: ifdown brings down all pump enabled devices
+     * #204468: ifupdown: ifup(8) should describe how to set mapping
+     * #207388: ifupdown: dh_suidregister-is-obsolete
+     * #224468: ifupdown: hw option not implemented correctly
+     * #255228: postrm doesn't delete configuration files on purge
+     * #258965: ifupdown: FTBFS with gcc-3.4: label at end of compound
+       statement
+     * #259609: ifupdown: ifdown -a does not turn off all interfaces in
+       ifstate
+     * #266479: postinst fails in pbuilder with : /etc/network/ifstate:
+       Permission denied
+Minor bugs - fixed in NMU (29 bugs)
+     * #81150: ifupdown: man page title
+     * #86410: does hostname lookup when no service is running
+     * #112012: please document initialization order for ifupdown -a
+     * #114429: ifupdown: pump works also with 2.4.x kernels
+     * #138403: interfaces(5): 'auto' takes physical iface names as args
+     * #141634: ifupdown: missing documentation for /etc/network/if-up.d
+       and friends
+     * #150720: netbase: interfaces file should support all ifconfig
+       options, including MTU
+     * #156789: ifupdown: Document precedence of dhcp clients in
+       interfaces(5)
+     * #157698: ifupdown: man missing if-up.d, etc.
+     * #160918: Typo in interfaces(5) : s/three/four/
+     * #172147: ifupdown: How to use multiple IPs per NIC is not
+       documented
+     * #173101: minor: get-mac-address.sh missing a ")"
+     * #177896: ifupdown: typo in network-interfaces
+     * #178630: Should Suggest dhcp-client
+     * #180000: ifupdown: if(up|down) --help output for -a slightly
+       misleading
+     * #186316: ifupdown: interfaces(5) man page needs s/three/four/ in
+       'IFACE OPTIONS'
+     * #193488: Syntax error in examples/get-mac-address.sh
+     * #213068: ifupdown: ifup(8) should document "IFACE=LIFACE" syntax
+     * #216716: ifupdown: interfaces(5) gives slightly incorrect
+       description of mapping
+     * #231404: ifupdown: -s option undocumented
+     * #232347: ifupdown: interfaces(5) manpage misleading
+     * #242527: ifupdown-0.6.4-4.7 does not work with the (experimental)
+       dhcp-client (3.0.1betaRC4-1) package
+     * #242537: ifupdown: does not bring up eth0 via dhclient anymore
+     * #247772: /usr/share/man/man8/ifup.8.gz: add usage examples
+     * #255053: /usr/share/doc/ifupdown/examples/check-mac-address.sh:
+       [PATCH] syntax error 
+     * #255218: interfaces(5) should mention wireless(7)
+     * #255574: Fixes for XSI:isms
+     * #286166: inconsistency with manpage: pre-up hook failures prevent
+       config
+     * #287172: typo in manpage
+Wishlist items - fixed in NMU (43 bugs)
+     * #36073: Please write an app to generate /e/n/interfaces
+     * #57731: netbase: MTU option with ifup and ifdown
+     * #57830: Please use /e/init.d/network to generate /e/n/interfaces
+     * #67743: interfaces should configure local end of ipv6 over ipv4
+       tunnel
+     * #76142: Please add a new 'noip' method for unconfigured interfaces
+     * #79999: ifupdown: Need ability to specify media type
+     * #84602: ifup needs ability to specify hardware address
+     * #86902: ifupdown: contributed scripts to keep iface up
+     * #88948: Add "manual" method to ifupdown
+     * #92993: ifupdown: How do I configure eth0 to have no address?
+     * #96265: ifupdown: Why are address and netmask required for
+       v4tunnel method?
+     * #100397: should support MTU
+     * #106533: MTU from interfaces file
+     * #110198: ifupdown: fixing some small typos in pt_BR debconf
+       template translation [PATCH]
+     * #113620: udhcpc: is it possible to integrate udhcpc with Debian's
+       /etc/network
+     * #116646: udhcpc: No init.d scripts
+     * #121755: Please warn on upgrade if /e/n/i lacks "auto lo"
+     * #129003: /etc/network/interfaces: Please allow for no IP address
+     * #135502: ifupdown: set hardware address
+     * #141885: ifupdown: Patch to provide 6to4 support (adds local
+       option) and new null address family
+     * #154517: ifupdown: please consider adding distclean target
+     * #164823: bridge-utils: /etc/network/interfaces does not permit the
+       configuration of a bridge without an IP address
+     * #171981: ifupdown: ifup requires netmask for an interface with ip
+       0.0.0.0
+     * #174764: ifupdown: Danish template translation
+     * #190698: Please add 'custom' method for iface stanzas
+     * #200786: ifupdown: Please switch to gettext-based debconf
+       templates
+     * #203636: Please mention extended iface options in interfaces(5)
+     * #207727: ifupdown: spanish debconf templates
+     * #210436: ifupdown: Japanese debconf messages
+     * #213619: ifupdown: Please document ifdown -a behaviour correctly
+       in the manpage
+     * #213723: [INTL:nl] new po-debconf template translation in Dutch.
+     * #229503: Please add Greek debconf translation (attached)
+     * #229527: Please add Greek debconf translation (attached)
+     * #231910: ifupdown: [INTL:zh_CN] Simplified Chinese translation to
+       debconf templates
+     * #231995: Czech translation of ifupdown debconf templates
+     * #239142: [INTL:tr] Turkish po-debconf translation
+     * #241248: Updated Danish po-debconf translation
+     * #242607: /etc/init.d/ifupdown: Please create run directory if not
+       present
+     * #245067: Please delete ifstate file on shutdown
+     * #248717: [l10:ca] ifupdown catalan debconf templates
+     * #249233: ifupdown: Lithuanian translation of debconf templates
+     * #250713: Should be Suggests: iproute, dhcp3-client, ppp
+     * #284123: [INTL:it] Italian debconf templates translation for
+       ifupdown
+Normal bugs - resolved (1 bug)
+     * #298232: ifupdown: a few files are not cleanup at upgrade
diff --git a/_darcs/current/COPYING b/_darcs/current/COPYING
new file mode 100644 (file)
index 0000000..d60c31a
--- /dev/null
@@ -0,0 +1,340 @@
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+                   GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                           NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+           How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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; either version 2 of the License, or
+    (at your option) any later version.
+
+    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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year  name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/_darcs/current/ChangeLog b/_darcs/current/ChangeLog
new file mode 100644 (file)
index 0000000..ed3ed29
--- /dev/null
@@ -0,0 +1,131 @@
+
+ChangeLog for ifupdown
+======================
+
+2000-11-18   0.6.4  Anthony Towns <aj@azure.humbug.org.au>
+
+       * Shouldn't use errno, apparently. Should use ferror() instead.
+         What a completely stupid API. Thanks to Roderich Schupp for
+         pointing this out.
+
+       * Use $(( .. )) in a shell for math, not $[..] which is bash only.
+         Thanks to Kalle Olavi Niemitalo for this one.
+
+2000-10-20   0.6.3  Anthony Towns <aj@azure.humbug.org.au>
+
+       * Fixed horrible bugs where to get n structures I realloc n
+         bytes, instead of n * sizeof(..) bytes. Shame on me.
+
+       * Don't commit the new networking state to the statefile when
+         --no-act is happening (after all, there *aren't* any changes...)
+
+       * Bring forward some changes from the .deb:
+               - /var/run/ifupdown.state -> /etc/network/ifstate
+                 (/var may be NFS mounted...)
+               - Add /e/n/ifstate to manpage.
+               - Add pointopoint support for inet/static.
+               - dhcpcd works with all kernels, not "2.0 and 2.2" :)
+               - Add provider support for ppp. It's still a kludge.
+               - Update ipx address family.
+               - Remove noauto from the interfaces manpage.
+
+2000-09-22   0.6.2  Anthony Towns <aj@azure.humbug.org.au>
+
+       * Aieee. cardmgr (pcmcia utility) starts with stdin *closed*,
+         rather than redirected from /dev/null. So when I open pipes
+         and stuff, it can come up as fd 0. Not good. Fake fd 0,1,2 as
+         /dev/null if they're not already existant.
+
+       * Fixed silly bug about not properly downing interfaces too.
+
+2000-09-15   0.6.1  Anthony Towns <aj@azure.humbug.org.au>
+
+       * Fixed up defn2man.pl so that /usr/share/doc (eg) isn't italicised.
+
+       * Cleaned up execute.c and updated literate comments to match new
+         behaviour.
+       * Update literate comments for main.c too.
+
+       * Fixed --no-act and --verbose to actually work, rather than just
+         be faked. Both are now program-wide variables declared in
+         main.c.
+
+       * Included some explanatory diagrams (.dia's), and some build code
+         to actually include them in the woven output. They're done as .eps
+         files which pdflatex can't handle. Bummer.
+
+       * Largely updated manpage to reflect changes in 0.6
+
+       * Changed behaviour of --no-act to still run any mappings. (Use
+         --no-mappings as well to disable those)
+       * Add a --version option.
+       * Only update the state file if the interface was found.
+
+2000-06-09   0.6.0  Anthony Towns <aj@azure.humbug.org.au>
+
+       * STILL TO DO: update manpage, tidy up the changed literate source.
+
+       * run-parts /etc/network/if-{up,down,pre-up,post-down}.d is called
+         after running any iface-specific scripts.
+       * Environment of called programs contains exactly:
+               IF_<option>=<value>
+               IFACE=<physical iface name>
+               MODE=<start or stop>
+         and whatever /bin/sh defaults to initialising.
+
+       * Each option may only be specified once.
+       * Added `auto lo eth0', remove `noauto'.
+       * Added mapping support. Thanks to Marc Haber for the inspiration.
+       * Removed scheme support.
+       * Report line-number as well as file name, when read_interfaces()
+         fails.
+
+       * Added /var/run/ifupdown.state
+       * Made ifdown -a use the statefile rather than the config file.
+
+       * Added inet6 methods static and v4tunnel. (Thanks to Bastian
+         Blank for a patch for the former)
+       * Made "pre-up", "down", "post-down" manpage descriptions
+         match the "up" description. Yay for redundancy.
+
+2000-03-23   0.5.5  Anthony Towns <aj@azure.humbug.org.au>
+
+       * Added "pre-up" and "post-down" options.
+
+2000-02-29   0.5.4  Anthony Towns <aj@azure.humbug.org.au>
+
+       * Some more minor cleanups.
+
+2000-02-29   0.5.3  Anthony Towns <aj@azure.humbug.org.au>
+
+       * Minor cleanups; added ifup.8.ps.gz and interfaces.5.ps.gz
+         to the default target.
+
+2000-02-28   0.5.2  Anthony Towns <aj@azure.humbug.org.au>
+
+       * Change the dhcpcd/dhcpcd-sv stuff to refer to just
+         /sbin/dhcpcd, instead of checking for dhcpcd-sv
+         specifically.
+
+       * Add a manpage for /etc/network/interfaces, thanks
+         to Joey Hess. Rearranged ifup(8) a bit, and
+         added some stuff to it. Also actually wrote the
+         *bold* and /italic/ handling.
+
+       * Finally got sick of lines longer than 80 chars in
+         .defn files and added \ escaping of newlines.
+
+2000-02-13   0.5.1  Anthony Towns <aj@azure.humbug.org.au>
+
+       * Cleaned up some of the source.
+
+       * Redefined .defn files a bit: added a description tag for
+         methods, and made the options list be documentation
+         for the options rather than something useful for C.
+
+       * Added defn2man.pl, and made a manpage (generated from
+         ifupdown.8.pre and defn2man.pl).
+
+2000-02-07   0.5.0  Anthony Towns <aj@azure.humbug.org.au>
+
+       * Initial release, from netbase.deb, 3.16-9
diff --git a/_darcs/current/Makefile b/_darcs/current/Makefile
new file mode 100644 (file)
index 0000000..35007c5
--- /dev/null
@@ -0,0 +1,102 @@
+CFLAGS := -Wall -W -g -O2 -D'IFUPDOWN_VERSION="0.6.5"'
+CC := gcc
+
+CFILES := addrfam.c execute.c config.c main.c archlinux.c
+HFILES := header.h archlinux.h
+PERLFILES := defn2c.pl defn2man.pl
+DEFNFILES := inet.defn ipx.defn inet6.defn
+
+OBJ := main.o addrfam.o execute.o config.o \
+       $(patsubst %.defn,%.o,$(DEFNFILES)) archlinux.o
+
+MAN := $(patsubst %.defn,%.man,$(DEFNFILES))
+
+default : executables
+all : executables docs
+
+executables : ifup ifdown ifup.8 ifdown.8 interfaces.5
+docs : ifupdown.ps.gz ifup.8.ps.gz interfaces.5.ps.gz ifupdown.pdf
+
+.PHONY : executables 
+.PHONY : clean clobber
+
+install :
+       install -m 0755 -d     ${BASEDIR}/sbin
+       install -m 0755 ifup   ${BASEDIR}/sbin
+       ln ${BASEDIR}/sbin/ifup ${BASEDIR}/sbin/ifdown  
+
+clean :
+       rm -f *.aux *.toc *.log *.bbl *.blg *.ps *.eps *.pdf
+       rm -f *.o *.d $(patsubst %.defn,%.c,$(DEFNFILES)) *~
+       rm -f $(patsubst %.defn,%.man,$(DEFNFILES))
+       rm -f ifup ifdown interfaces.5 ifdown.8
+       rm -f ifupdown.dvi *.ps{,.gz}
+
+clobber : clean
+       rm -f ifupdown.tex $(PERLFILES) $(CFILES) $(HFILES) $(DEFNFILES)
+
+distclean : clobber
+       rm -f makecdep.sh makenwdep.sh Makefile
+ifup: $(OBJ)
+       $(CC) $(CFLAGS) $^ $(LDFLAGS) $(OUTPUT_OPTION)
+
+ifdown: ifup
+       ln -sf ifup ifdown
+interfaces.5: interfaces.5.pre $(MAN)
+       sed $(foreach man,$(MAN),-e '/^##ADDRESSFAM##$$/r $(man)') \
+            -e '/^##ADDRESSFAM##$$/d' < $< > $@        
+
+ifdown.8: ifup.8
+       ln -sf $< $@
+
+%.5.ps: %.5
+       groff -mandoc -Tps $< > $@
+%.8.ps: %.8
+       groff -mandoc -Tps $< > $@
+ifupdown.dvi: modules.eps execution.eps
+ifupdown.ps: modules.eps execution.eps
+ifupdown.pdf: modules.pdf execution.pdf
+%.tex : %.nw
+       noweave -delay -index -latex $< >$@
+
+%.bbl : %.tex biblio.bib
+       latex $<
+       bibtex $(basename $<)
+
+%.dvi : %.tex %.bbl
+       latex $<
+       latex $<
+
+%.pdf : %.tex %.bbl
+       pdflatex $<
+       pdflatex $<
+
+%.ps : %.dvi
+       dvips -o $@ $<
+
+%.gz : %
+       gzip --best --stdout $< >$@
+%.eps : %.dia
+       dia --nosplash -e $@ $<
+
+%.pdf : %.eps
+       gs -q -sDEVICE=pdfwrite -dNOPAUSE -sOutputFile=$@ - < $<
+%.d: %.nw makenwdep.sh
+       ./makenwdep.sh $< > $@
+%.d: %.c makecdep.sh
+       ./makecdep.sh $< > $@
+%.c : %.defn defn2c.pl
+       ./defn2c.pl $< > $@
+%.man: %.defn defn2man.pl
+       ./defn2man.pl $< > $@
+
+include-deps := YES
+ifneq "" "$(filter %clean,$(MAKECMDGOALS))"
+include-deps := NO
+endif
+ifeq "clobber" "$(MAKECMDGOALS)"
+include-deps := NO
+endif
+ifeq "$(strip $(include-deps))" "YES"
+include ifupdown.d
+endif
diff --git a/_darcs/current/README b/_darcs/current/README
new file mode 100644 (file)
index 0000000..570068c
--- /dev/null
@@ -0,0 +1,35 @@
+
+ifupdown
+========
+
+ifup and ifdown are two utilities to assist with basic interface
+manipulation.
+
+
+Building
+--------
+
+To build from CVS, you need to generate the tangled sources from the
+literate source. To do this, you'll need Norman Ramsey's noweb program
+(nowebm.deb for Debian users). The following instructions should be enough
+to build from nothing but ifupdown.nw.
+
+       notangle -t8 -RMakefile ifupdown.nw >Makefile
+       notangle -Rmakenwdep.sh ifupdown.nw >makenwdep.sh
+       chmod 755 makenwdep.sh
+       make
+
+After that, you should just need some standard tools like gcc and perl.
+
+
+Literate Source
+---------------
+
+To view the pretty-printed literate source code, you can make any of
+the targets:
+
+       ifupdown.ps
+       ifupdown.dvi
+or     ifupdown.pdf
+
+You'll need a LaTeX distribution to do this, as well as noweb.
diff --git a/_darcs/current/TODO.scripts b/_darcs/current/TODO.scripts
new file mode 100644 (file)
index 0000000..110bd14
--- /dev/null
@@ -0,0 +1,27 @@
+
+       bridging
+iface brg0 inet static
+    bridge eth0 eth1
+    address 1.2.3.4
+    netmask 255.255.255.0
+
+       bonding
+(same as bonding, except both cards go to the same place)
+(i think it's that simple)
+
+       multiple-addresses (can be on varied subnets) [87862]
+iface brg0 inet static
+    address 1.2.3.4
+    netmask 255.255.255.0
+    gateway 1.2.3.1
+    extra-addresses 1.2.3.5 192.168.1.16   
+
+       set-mac [84602]
+       set-mtu [57731]
+
+       pppoe? [92993]
+iface ppp1 inet ppp
+
+
+       NFS mounts?
+       DNS
diff --git a/_darcs/current/biblio.bib b/_darcs/current/biblio.bib
new file mode 100644 (file)
index 0000000..134498f
--- /dev/null
@@ -0,0 +1,42 @@
+@Book{K&R,
+  author =      {Brian Kernighan and Dennis Ritchie},
+  title =       {The C Programming Language},
+  publisher =   {Prentice Hall},
+  year =        {1988},
+  edition =     {Second},
+}
+
+@Book{camel,
+  author =      {Larry Wall and Tom Christiansen and Randal Schwartz},
+  title =       {Programming Perl},
+  publisher =   {O'Reilley and Associates},
+  year =        {1996},
+}
+
+@Book{StevensUnix,
+  author =      {W. Richard Stevens},
+  title =       {Advanced Programming in the UNIX Environment},
+  publisher =   {Addison-Wesley},
+  year =        {1997},
+}
+
+@Book{latex,
+  author =      {Leslie Lamport},
+  title =       {\LaTeX --- A Document Preparation System},
+  publisher =   {Addison Wesley},
+  year =        {1994},
+}
+
+@Misc{recursivemake,
+  author =      {Peter Miller {\tt <millerp@canb.auug.org.au>}},
+  title =       {Recursive Make Considered Harmful},
+  year =        {1997},
+}
+
+@Misc{wwwnoweb,
+  author =       {Norman Ramsey},
+  title =        {{\tt noweb} home page},
+  howpublished = {{\tt http://www.cs.virginia.edu/\~{}nr/noweb/}},
+}
+
+
diff --git a/_darcs/current/contrib/ensureifup b/_darcs/current/contrib/ensureifup
new file mode 100644 (file)
index 0000000..b949648
--- /dev/null
@@ -0,0 +1,30 @@
+#!/bin/sh
+# This script is useful to check wether an interface is up and,
+# if not, it attempts to bring it back. This can be necessary
+# if your ISP provider causes occasional outages.
+# Some ISPs are known to termine connections when they reach
+# 24 hours to "prevent abuse".
+# Run this script through cron (every 5 minutes? your call)
+# and ensure that ifstate is located where it is defined below.
+#
+# NOTE: This script is just provided as an example. If you want this
+# feature you might be better off installing ifplugd which provides
+# similar functionality (but more featureful) out of the box.
+
+# TODO:
+# Improve it so it can find out (eg from /etc/network/run/ifstate)
+# whether an interface was brought down
+# unexpectedly, or if a clean "ifdown" was issued.
+
+iface="$1"
+ifstate=/usr/local/sbin/ifstate
+
+if [ `$ifstate "$iface"` = DOWN ]
+then
+    logger -s "Trying to bring $iface back up..."
+    ifdown "$iface"
+    ifup "$iface"
+    [ `$ifstate "$iface"` = UP ] && logger -s "$iface now up again"
+fi
+
+exit 0
diff --git a/_darcs/current/contrib/ifstate b/_darcs/current/contrib/ifstate
new file mode 100644 (file)
index 0000000..cd79e19
--- /dev/null
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+iface="$1"
+if [ -z "$iface" ] ; then
+       echo "Usage: $0 IFACE"
+       exit 1
+fi
+
+if ifconfig "$iface" | grep -Fw UP >/dev/null
+then
+       echo UP
+else
+       echo DOWN
+fi
diff --git a/_darcs/current/contrib/ifstate-check b/_darcs/current/contrib/ifstate-check
new file mode 100644 (file)
index 0000000..4f99d8a
--- /dev/null
@@ -0,0 +1,86 @@
+#!/usr/bin/perl
+#
+# Generate a report of the status of interfaces configured
+# by 'ifupdown'
+# (c) 2004 Javier Fernandez-Sanguino <jfs@debian.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; either version 2 of the License, or
+#    (at your option) any later version.
+#
+#    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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+
+$statefile="/etc/network/run/ifstate";
+$configfile="/etc/network/interfaces";
+
+open (IFACE,"<$configfile") || die ("Could not open $configfile: $!\n");
+while (<IFACE>) {
+       chomp;
+       if ( /^iface\s+(\w+)\s+/ ) {
+               $configured{$1}=$_; 
+       }
+}
+
+close IFACE;
+
+open (IPLINK,"ip link show|") || die ("Could not execute ip: $!\n");
+while (<IPLINK>) {
+       chomp;
+# FORMAT
+# #: AAAA: <XXXXX,UP> mtu 16436 qdisc noqueue
+       if ( /^\d+: (\w+):.*?\<.*?,UP.*?\>/ ) {
+               $iplink{$1}=$_;
+       }
+}
+close IPLINK;
+
+
+open (STATE,"<$statefile") || die ("Could not open $statefile: $!\n");
+$line = 0;
+while (<STATE>) {
+       chomp;
+       $line++;
+# Format is IFACE=IFACE
+       if ( /^(\w+)=(\w+)$/ ) {
+               $iface = $1;
+               $ifaces = $2;
+               if ( $iface ne $ifaces ) {
+                       print STDERR "Error in $statefile (line $line), interface names do not match ('$iface' and '$ifaces')\n";
+               } else {
+                       check_status($iface);
+               }
+       } else {
+               print STDERR "Error in $statefile (line $line), unknown content\n";
+       }
+
+}
+close STATE;
+
+exit 0;
+
+sub check_status {
+       my ($int) = @_;
+       print "$int: ";
+       my $status = "UP";
+# Check if it's really up, this is done basicly because ifupdown
+# might not have configured it properly even if it thinks he has
+# (sample: ifconfig croaks when wrong parameters are used and 
+# ifupdown does not detect that the system call went awry)
+       $status = "ERROR_NOT_REALLY_UP" if ! defined ($iplink{$int}) ;
+       if ( defined ( $configured{$int} ) ) {
+               $status .= ",CONFIGURED";
+       } else {
+               $status .= ",MANUALLY_CONFIGURED";
+       }
+       print "$status\n";
+       return 0;
+}
diff --git a/_darcs/current/debian/TODO b/_darcs/current/debian/TODO
new file mode 100644 (file)
index 0000000..8532938
--- /dev/null
@@ -0,0 +1,19 @@
+
+- The documentation in pdf generated by the .dia files does not show
+  up properly (it is bigger than the PDF itself)
+
+- There is currently no way to build an ifudown-doc package. Since dia
+  cannot be used without a $DISPLAY the only alternatives are to 
+  either build the dia stuff manually (for autobuilders) and build the
+  docs with the package or build all the docs manually and use a 
+  a 'clean-everything-but-docs' target to clean the package when building.
+
+- More documentation on how to configure ifupdown for different goals
+  is needed. A lot of content is already available in
+  the Debian Reference, but more detailed examples would be useful
+  (and should be included in a separate ifupdown-doc package)
+  See: http://www.debian.org/doc/manuals/reference/ch-gateway.en.html#s-net-high)
+
+- When compiling the package there are errors related to po files not being
+  correct. This is because of the current hack for woody compatibility in
+  debian/rules. Remove when sarge is released?
diff --git a/_darcs/current/debian/changelog b/_darcs/current/debian/changelog
new file mode 100644 (file)
index 0000000..bb7395e
--- /dev/null
@@ -0,0 +1,596 @@
+ifupdown (0.6.7) unstable; urgency=low
+
+  * Don't use dirname/basename in ifupdown init script; they're in /usr/bin.
+    (Closes: Bug#304188)
+
+  * Check for free space on /dev/shm when working out where to link
+    /e/n/run. Thanks to Jose Manuel Delgado Mendinueta. (Closes:
+    Bug#303656)
+
+ -- Anthony Towns <ajt@debian.org>  Mon,  2 May 2005 23:57:25 +1000
+
+ifupdown (0.6.6) unstable; urgency=low
+
+  * The "what does wine come in" release
+
+  * Fix brown paper bag bug where %iface% maps to the logical interface
+    name rather than the hardware one. Thanks to Paul Hampson for being
+    the first to spot it once the BTS was working again. Also add a test
+    case. (Closes: Bug#303148)
+
+  * Fix brown paper bag bug where "test -e" doesn't actually identify a
+    dangling /etc/network/run symlink on upgrade. (Closes: Bug#303225)
+
+  * Fix brown paper bag bug where we only consider pointing
+    /etc/network/run at /dev/shm if /dev/shm *isn't* in /proc/mounts. (No
+    bug filed yet, though...)
+
+ -- Anthony Towns <ajt@debian.org>  Tue,  5 Apr 2005 14:19:21 +1000
+
+ifupdown (0.6.5) unstable; urgency=low
+
+  * The Gernot Heiser release -- aged like a fine South Australian wine.
+
+  * Switch to Debian-native versioning / source packaging for the time being.
+    (Closes: Bug#84697)
+  * Change Section: to base, to match overrides.
+
+  * Thanks to Michael Weber, Javier Fernandez-Sanguino Pena, Marc
+    Haber, and Thomas Hood for NMUs. (Closes: Bug#150773, Bug#151465,
+    Bug#152893, Bug#208726, Bug#209006, Bug#242314, Bug#263913,
+    Bug#266282, Bug#297762)
+
+  * debian/rules: Don't re-build unnecessarily. Thanks to Michael Banck
+    (Closes: Bug#296273)
+
+  * Add post-up, pre-down as aliases for "up" and "down". (Closes: Bug#62633)
+
+  * Deprecate (undocument) "--exclude" option.
+
+  * Add support for "allow-*" lines for systems such as hotplug or ifplugd.
+    Usage is "ifup --allow=hotplug <interfaces>"; only the allowed interfaces
+    whill actually be tried. (Closes: Bug#300937)
+
+  * Satiate the POSIX sh monkeys, makenwdep.sh now uses printf for \t's,
+    not echo -e. (Closes: Bug#294970)
+
+  * Switch to using "/etc/network/run/ifstate" instead of
+    "/etc/network/ifstate". Simplify all the complicated hackery dealing
+    with that. Use myreadlink function instead of /lib/init/readlink.
+    (Closes: Bug#302519)
+
+  * Make debian/rules test always succeed when cross-building. Thanks
+    to NIIBE Yutaka. (Closes: Bug#283649)
+
+  * Add VERBOSITY variable for scripts, invoke run-parts with --verbose.
+    Thanks to Michael Weber. (Closes: Bug#88946)
+  * Add LOGICAL variable for scripts. (Doesn't work for mapping scripts yet
+    though)
+  * Add PHASE variable for scripts, same as MODE but more detailed;
+    pre-up, post-down, etc. (Closes: Bug#286155)
+
+  * Document lack of support for end-of-line comments in interfaces(5).
+    (Closes: Bug#79683)
+
+  * Remove conflict with old, experimental-only version of dhcp-client.
+
+ -- Anthony Towns <ajt@debian.org>  Mon,  4 Apr 2005 23:41:06 +1000
+
+ifupdown (0.6.4-4.12) unstable; urgency=low
+
+  * Non-maintainer upload
+  * Begin description synopsis with lower case letter
+  * postinst:
+    + Create run dir at the target of /etc/network/run if it is absent
+      (Closes: #297898)
+
+ -- Thomas Hood <jdthood@yahoo.co.uk>  Thu,  3 Mar 2005 19:05:05 +0100
+
+ifupdown (0.6.4-4.11) unstable; urgency=low
+
+  * Non-maintainer upload
+  * postinst:
+    + Do not make /etc/network/run a symlink to /dev/shm/network/
+      if devfs is in use.  (Closes: #266479)
+  * /etc/init.d/ifupdown:
+    + Don't accept arguments to "start" method
+    + Fix initscript output
+  * ifup.8:
+    + Correct typo (Closes: #287172)
+  * interfaces.5:
+    + Correct description of what happens when user commands fail
+      (Closes: #286166)
+    + Remove reference to VERBOSE which isn't implemented in this
+      version  (Reported in #88946)
+  * Add it.po thanks to Luca Monducci  (Closes: #284123)
+
+ -- Thomas Hood <jdthood@yahoo.co.uk>  Sun, 12 Sep 2004 14:46:29 +0200
+
+ifupdown (0.6.4-4.10) unstable; urgency=low
+
+  * Non-maintainer upload. Fix critical bugs.
+  * fix ifstate cleaning in init script. (Closes: #264134).
+  * fix /etc/network/run creation in postinst (Closes: #265165).
+
+ -- Marc Haber <mh+debian-packages@zugschlus.de>  Tue, 17 Aug 2004 06:38:16 +0200
+
+ifupdown (0.6.4-4.9) unstable; urgency=low
+
+  * Non-maintainer upload: bug fixes and some improvements, unfortunately
+    they will not make it to sarge...
+   [Javier Fernandez-Sanguino]
+    - Added a generic --exclude option (modified ifupdown.nw and ifup.8)
+      This way other scripts (such as /e/i/networking in netbase)
+      can avoid bringing down 'lo' on shutdown doing: 'ifdown -e lo -a'
+      This will help close #254705, #256680 and #208700.
+    - Make it conflict with the dch-client version from experimental 
+      (Closes: #242537, #242527)
+    - Added usage examples provided by Thomas Hood (Closes: #247772)
+    - L10n:
+       + Updated catalan debconf templates provided by Aleix Badia i Bosch 
+        (Closes: #248717)
+        + Included Lithuanian translation of debconf templates provided
+        by Gintautas Miliauskas (Closes: #249233)
+    - /etc/init.d/ifupdown: Exit with error if called with unknown arguments
+    - ifupdown.nw: fix FTBFS with gcc-3.4 (Closes: #258965)
+    - ifup.8: ammended manpage describing how ifdown really works 
+      (Closes: #259609)
+    - Remove XSI:isms in several scripts (Closes: #255574)
+    - debian/po/POTFILES.in:  point to templates.master instead of templates
+   [Thomas Hood]
+    - debian/control:
+       + Build-Depend on version of debhelper with dh_installinit --name
+       + Put dhcp3-client before dhcp-client in disjunctive dependency
+         (Closes: #250713)
+     - Add /etc/default/ifupdown (currently not used, will be in the
+       future)
+     - /etc/init.d/ifupdown:
+        + Creates target of /etc/network/run if the latter is a dangling
+         symlink.  Thanks to AJT for good discussion.  (Closes: #242607)
+        + Delete ifstate on stop  (Closes: #245067)
+    - /etc/init.d/ifupdown-clean
+        + Delete ifstate on stop  (Closes: #245067)
+    - debian/rules:
+        + Now use dh_installdebconf to install debconf stuff
+        + Install new ifupdown-clean initscript.  It runs at S:S18.
+        + ifupdown initscript now runs at 0,6:S36 as well as S:S39.
+        Note: this will only apply to new installations (not to upgrades)
+     - examples/*
+        + Move the contributed scripts to contrib/
+        + Clean up and add comments
+     - examples/check-mac-address.sh:
+        + Fix argument check  (Closes: #254388)
+     - debian/postrm:
+        + Delete configuration files on purge  (Closes: #255228)
+     - ifup.8
+        + Clean up
+        + Add EXAMPLES section  (Closes #247772)
+     - interfaces.5
+        + Mention wireless(7)  (Closes: #255218)
+        + Reorder content and do some other minor changes.
+     - debian/postinst:
+        + Create /etc/network/run symlink to /dev/shm/network/ if 
+         it does not exist
+        + Warn if "auto lo" or "iface lo" stanza absent from /e/n/i
+        (Closes: #121755)
+       
+ -- Javier Fernandez-Sanguino Pen~a <jfs@computer.org>  Wed, 28 Jul 2004 17:04:19 +0200
+
+
+ifupdown (0.6.4-4.8) unstable; urgency=low
+
+  * Fix configuration of interfaces with multiple address families.
+    (Closes: Bug#242867) 
+  * Add testcase 3 to check for such errors.
+
+ -- Anthony Towns <aj@azure.humbug.org.au>  Sat, 10 Apr 2004 16:47:57 +1000
+
+ifupdown (0.6.4-4.7) unstable; urgency=low
+
+  * Non-maintainer upload. This is mostly a bug-fix release, no new
+    features have been added and the behaviour of ifupdown has only changed
+    slightly. Content has been reviewed by both the maintainer and several
+    other maintainers (who have NMUed this package previously)
+    - Ifupdown.dvi now depends on *eps files (Closes: #101204)
+    - Added missing Build-Dep to noweb since the Makefile calls makenwdep.sh
+      (and it calls 'noroots') on build.
+    - Remove the undocumented (and unused) -s option from the manpage and the
+      main.c code. (Closes: #231404)
+    - inet6.defn
+      + Make it possible to run an v4tunnel without an address (Closes: #96265)
+    - inet.defn
+      + Included different handling of dhclient3 versus dhclient.
+      + Avoids inconsistency in interface state if the command run
+       by ifup fails, also added -e option to dhclient in order to 
+       have it return an error if it cannot get an address. 
+       Notice that this is not yet done with dhclient3 (-1) since that would
+       mean not running dhclient3 as a daemon and renews not being done.
+       (Closes: #97782, #82339, #113338, #148666, #169194)
+      + An independent lease file is created per interface so that dhclient
+       can be used in more than one interface (Closes: #196366)
+      + If dhcp3-client is installed (the binary /sbin/dhclient3 is available)
+       then use the -r option instead of with a KILL signal, this enables
+       it to release the DHCP release an execute the hook script before
+       exiting. Also, the package now suggests 'dhcp-client | dhcp3-client'
+       (since dhcp3-client does not provide dhcp-client as pump does)
+       (Closes: #196865)
+      + Added a metric option for routes, notice, however, the dhclient's
+       -e (undocumented) option is not included from the provided patch.
+       (Closes: #235993)
+      + Use -r instead of -k when DHCP interfaces using pump are downed in 
+       order to avoid killing all interfaces (only release the one asked for)
+       (Closes: #198841)
+      + Properly implement the 'hw' option in interfaces by defining the 
+       hardware address before upping the interface. 
+       (Closes: #224468, #84602)
+      + Allow setting of the hw address in the dhcp method as suggested.
+       (Closes: #135502)
+    - examples:
+      + Added an example in the interfaces file on how to setup an interface
+       with multiple IP addresses. I've added a warning, though, since this
+       is expected not to work in some cases and might generate inconsistencies
+       between the real state and the one noted down in the interfaces state
+       file. It is worth documenting this option (with known caveats) rather
+       than have users figure it out for themselves.
+       (Closes: #172147)
+      + Added sample scripts ('ensureifup' and 'ifstate') to ensure that
+       interfaces are always up (might be useful for crappy ISP providers)
+       as provided by Yann Dirson (Closes: #86902)
+      + Provide a 'generate-interfaces.pl' script under the examples dir
+       in order to facilitate migration of network configuration in 
+       pre-woody systems. This script might also be useful to migrate other
+       Linux systems to Debian.
+       (Closes: #57830)
+      + Added a sample 'ifstate-complex' command. Since it is not documented
+        I'm adding it to the examples and not closing #153222 with it (yet)
+      + Fixed a syntax error in the 'check-mac-address.sh' script and added
+        both a little bit of comment code and proper usage.
+      + Provided an example on how to setup an interface without IP address
+        using the 'manual' method. This is suitable for some cases where we 
+        only want to have the interface to be up. This example can be used
+        to setup PPPOE interfaces or network IDS listening on a network. 
+        This might not be as good as providing a specific method but the
+        maintainer considers that this is the way it should be handled.
+        (Closes: #76142, #92993, #129003, #164823, #171981)
+      + Also, provided an example bridge configuration script that can
+        be setup in /e/n/if-{pre-up,down}.d/ in order to setup bridges.
+    - Interfaces(5).pre:
+      + Slight improvement in to better describe mapping and point to 
+       the examples available. (Closes: #232594)
+      + Minor changes in the manpage to avoid people being misled .
+        (Closes: #232347)
+      + Better description of mappings (Closes: #216716)
+      + Document IFACE=LIFACE syntax (Closes: #213068)
+      + Documented known bugs or limitations.
+      + Reference the location of the network examples.
+      + Reference also the "Debian Reference" manual since it is more
+        verbose in how /e/n/interfaces and ifupdown works.
+    - Ifup(8):
+      + Document that the -a option will take down all interfaces.
+       (Closes: #208607)
+      + Also describe in which order are interfaces started/stopped when
+        using -a which might avoid confusion, see  #208700 for example.
+      + Changed manpage name to ifup (instead of ifupdown).
+       (Closes: #81150)
+      + Document known bugs in the manpage: state maintained is sometimes
+       lost, the ifstate needs to be writable and there is a known deadlock
+       issue.
+      + Document known "limitations" and refer readers to alternatives to
+        monitor interface changes such as ifupd and hotplug.
+      + Minor formatting changes and rewrites for better comprehension.
+    - Translations:
+      + Added Spanish debconf translation provided by Carlos Valdivia.
+       (Closes: #207727)
+      + Added Japanese debconf translation provided by Kenshi Muto.
+       (Closes: #210436)
+      + Added Dutch debconf translation provided by Tim Dijkstra.
+       (Closes: #213723)
+      + Added Greek debconf translation provided by Konstantinos Margaritis.
+       (Closes: #229503, #229527)
+      + Added simplified Chinese debconf translation provided by Hiei Xu.
+       (Closes: #231910)
+      + Added Czech debconf translation provided by Miroslav Kure.
+       (Closes: #231995)
+      + Added Turkish debconf translation provided by Recai Oktas.
+       (Closes: #239142)
+      + Added Danish debconf translation provided by Morten Brix Pedersen.
+       (Closes: #241248)
+
+ -- Javier Fernandez-Sanguino Pen~a <jfs@computer.org>  Mon,  5 Apr 2004 21:12:05 +0200
+
+ifupdown (0.6.4-4.6) unstable; urgency=low
+
+  * Non-maintainer upload
+  * reinstate code creating non-existent /etc/network in preinst. Moving
+    that code to postinst is currently problematic since other packages
+    pre-depend on ifupdown and dpkg doesn't guarantee that pre-depended
+    packages are configured before unpacking the depending package.
+                                                             (Closes: #208811)
+  * don't call dpkg --compare-version on initial install in postinst
+
+ -- Marc Haber <mh+debian-packages@zugschlus.de>  Sat,  6 Sep 2003 10:49:48 +0000
+
+ifupdown (0.6.4-4.5) unstable; urgency=low
+
+  * Non-maintainer upload
+  * ifupdown.nw:
+    + Clarify description of --all option                    (Closes: #180000)
+    + Add manual interface method                            (Closes:  #88948)
+    + Document order of precedence of DHCP clients           (Closes: #156789)
+  * debian/prepostinstrm:
+    + Use "set -e" consistently
+  * debian/rules, debian/postinst, debian/preinst
+    + Add /etc/network/if*.d/ directories to the package     (Closes: #178226)
+    + Use dh_installinit with --no-start option
+  * debian/config: fix compare-versions so that debconf question
+    is asked when updating from < 0.6                        (Closes: #122422)
+  * debian/rules:
+    + documented {clobber,distclean} targets                 (Closes: #154517)
+    + removed obsolete call of dh_suidregister
+  * added Danish convert-interfaces template.  Thanks to morten@wtk.dk
+    for translation.                                         (Closes: #174764)
+  * Switch to gettext-based debconf templates and update French
+    translation. Thanks to Christian Perrier for this work.  (Closes: #200786)
+  * use Colin Watson's backporting helper for po-debconf'ed packages.
+  * interfaces(5):
+    + Format improvements
+    + Describe how mapping works                             (Closes: #86895)
+                                                             (Closes: #138694)
+                                                             (Closes: #175679)
+                                                             (Closes: #204468)
+    + Document order of processing of auto ifaces            (Closes: #112012)
+    + Say that "auto" takes physical interface names as arguments
+                                                             (Closes: #138403)
+    + Document function of /etc/network/if-*.d/ directories  (Closes: #141634)
+                                                             (Closes: #157698)
+    + There are more than three universal options            (Closes: #160918)
+                                                             (Closes: #186316)
+    + Mention extended options                               (Closes: #203636)
+  * ifup(8)
+    + Indicate in synopsis that -i option takes an argument       
+    + minor phrasing changes aiming at greater clarity  
+    + formatting corrections                   
+  * examples/*: fix typos                                    (Closes: #173101)
+  * debian/control:
+    + Suggest dhcp-client and ppp                            (Closes: #178630)
+    + Standards-Version: 3.6.1
+    + Priority: important to agree with override file
+    + Clarify wording of long description
+  * debian/copyright:
+    + Clean up and make lintian happy
+  * Thanks to Thomas Hood and Michael Weber for helping to prepare
+    these patches and the NMU.
+
+ -- Marc Haber <mh+debian-packages@zugschlus.de>  Wed, 27 Aug 2003 14:00:59 +0000
+
+ifupdown (0.6.4-4.4) unstable; urgency=low
+
+  * Non-maintainer upload
+  * adjustment to changed md5sum output format (as of dpkg 1.10)
+    (Closes: Bug#152853)
+
+ -- Michael Weber <michaelw@debian.org>  Sun, 14 Jul 2002 02:12:15 +0200
+
+ifupdown (0.6.4-4.3) unstable; urgency=low
+
+  * Non-maintainer upload
+  * flush stream buffers before forking and after writing the
+    statefile
+    (Closes: Bug#151932)
+         
+ -- Michael Weber <michaelw@debian.org>  Thu,  4 Jul 2002 21:02:10 +0200
+
+ifupdown (0.6.4-4.2) unstable; urgency=low
+
+  * Non-maintainer upload
+  * added locking support, parallel executions of if{up,down} will be
+    serialized (modified patch from bod@debian.org).
+    (Closes: Bug#108876, Bug#108857)
+
+ -- Michael Weber <michaelw@debian.org>  Mon, 24 Jun 2002 21:42:50 +0200
+
+ifupdown (0.6.4-4.1) unstable; urgency=low
+
+  * Non-maintainer upload
+  * added convert-interfaces template for:
+    + de (Closes: Bug#83542)
+    + fr (Closes: Bug#83804)
+    + pt_BR (Closes: Bug#98448, Bug#110198)
+    + pl (Closes: Bug#107701)
+    + ru (Closes: Bug#112652)
+    + sv (Closes: Bug#83496)
+    (thanks to all translators)
+  * fixed some typos in source documentation
+  * pass METHOD and ADDRFAM environment variables to if.d scripts
+    and {pre-,}{up,down} lines
+    (Closes: Bug#88947)
+  * upgrade-from-0.5.x.pl emits auto statements only once
+    (patch from weasel@debian.org)
+    (Closes: Bug#105342)
+  * added "mtu" option to inet and inet6 static stanzas
+    (Closes: Bug#57731)
+  * added options "local" and "ttl" to inet6 static stanza
+    (Closes: Bug#67743)
+  * added and documented option "media" to specify the medium type
+    (Closed: Bug#79999)
+  * added and documented option hwaddress
+    (Closes: Bug#82604)
+  * reject options with empty values
+    (Closes: #86410)
+  * added more documentation to the IPX stanza
+  * improved usenet2man conversion (handles punctuation 
+    before/after //,**
+  * added support for udhcpc (slightly modified patch from kraai@debian.org)
+    (Closes: Bug#113620)
+  * added support for multiple executions of dhclient (uses
+    /var/run/dhclient.%iface%.pid now)
+    (Closes: Bug#94656)
+  * man page update [pump works for kernels (> 2.2.x)]
+    (Closes: Bug#114429)
+  * configurable user/group for install (0/0 as default, since
+    NetBSD uses group "wheel" instead of "root")
+  * examples/{check,get}-mac-address.sh:
+    + mapping script now compares given MAC addresses case-insensitive.
+    + added LANG=C to make ifupdown output reliably parseable
+      (thanks to blade@debian.org)
+
+ -- Michael Weber <michaelw@debian.org>  Sun, 23 Jun 2002 11:56:25 +0200
+
+ifupdown (0.6.4-4) unstable; urgency=low
+
+  * Don't delete /etc/network/ifstate every boot, just empty the file. This
+    way people can symlink it to /var/run/ifstate if they so desire (ie, if
+    /var is local and /etc is read-only). (Closes: Bug#103868, Bug#85206)
+  * Explicitly set PATH in the environment, because pdksh is broken, broken
+    I say. (Closes: Bug#83557, Bug#99444)
+
+ -- Anthony Towns <aj@azure.humbug.org.au>  Tue, 19 Jun 2001 00:04:30 +1000
+
+ifupdown (0.6.4-3) unstable; urgency=low
+
+  * Add some test cases to hopefully catch miscompiles on silly
+    architectures like alpha. Weirdly, I can't duplicate this bug on
+    lully anymore, so I didn't add a -O0 workaround at this time. We'll
+    see what happens. (Closes: Bug#81143)
+
+  * Correct old /e/n/i check from -2 so it might even work. (Closes:
+    Bug#81611)
+
+ -- Anthony Towns <aj@azure.humbug.org.au>  Tue,  9 Jan 2001 10:48:18 +1000
+
+ifupdown (0.6.4-2) unstable; urgency=low
+
+  * Check for old /etc/network/interfaces conffile (all comments, same
+    md5, same size), and replace it with new conffile so as not to mislead
+    people into forgetting the "auto" lines. (Closes: Bug#79822) 
+
+  * Added wvdial support, theoretically. If it doesn't work, someone'll have
+    to file a new bug and tell me. (Closes: Bug#76985)
+
+ -- Anthony Towns <ajt@debian.org>  Thu, 28 Dec 2000 21:28:47 +1000
+
+ifupdown (0.6.4-1) unstable; urgency=low
+
+  * New upstream release. Removes a bashism from the makefile, and uses
+    ferror() correctly (hopefully) (Closes: Bug#75279, Bug#76086)
+
+  * Add example that checks a MAC address is what it should be. (Closes:
+    Bug#76198)
+
+ -- Anthony Towns <ajt@debian.org>  Sun, 19 Nov 2000 15:33:22 +1000
+
+ifupdown (0.6.3-1) unstable; urgency=low
+
+  * New upstream release. Debian patches incorporated upstream, and a
+    big fix wrt memory allocation.
+
+ -- Anthony Towns <ajt@debian.org>  Fri, 20 Oct 2000 18:38:10 -0700
+
+ifupdown (0.6.2pr-7) unstable; urgency=low
+
+  * Rename to ifupdown. Let's see what breaks.
+
+  * Add pointopoint option for static inet interfaces. (Closes: Bug#74563)
+
+  * Updating to 0.6.x fixes some problems:
+        --scheme no longer exists (Closes: Bug#54814)
+        line numbers are reported (Closes: Bug#62542)
+        you can use $IFACE in /e/n/interfaces (Closes: Bug#71779)
+
+ -- Anthony Towns <ajt@debian.org>  Mon, 16 Oct 2000 19:30:54 -0700
+
+ifupdown0.6 (0.6.2pr-6) unstable; urgency=low
+
+  * Cleanup /etc/network/ifstate when booting (it will be wrong
+    if the system crashed).
+
+  * This should be enough for ifupdown.deb to be updated, hopefully.
+
+ -- Anthony Towns <ajt@debian.org>  Fri, 13 Oct 2000 19:41:34 -0700
+
+ifupdown0.6 (0.6.2pr-5) unstable; urgency=low
+
+  * The previous few uploads should've fixed most of the bugs
+    described in 72872. (Closes: Bug#72872)
+
+  * Add .sh suffixes to the example mapping scripts.
+  * Fix a typo in postinst (interface *file* not files)
+  * Add a "press enter to continue" if the /e/n/i update fails. 
+
+  * Moved /var/run/ifupdown.state to /etc/network/ifstate. Gross.
+    (Closes: Bug#74312)
+
+ -- Anthony Towns <ajt@debian.org>  Sat,  7 Oct 2000 23:52:02 -0700
+
+ifupdown0.6 (0.6.2pr-4) unstable; urgency=low
+
+  * Automatically update /etc/network/interfaces, hopefully. 
+
+ -- Anthony Towns <ajt@debian.org>  Sat,  7 Oct 2000 21:53:21 -0700
+
+ifupdown0.6 (0.6.2pr-3) unstable; urgency=low
+
+  * Started work on automatically converting from 0.5.x config format to
+    0.6.x.
+  * Move the example from /usr/share/doc/ifupdown to ifupdown0.6.
+  * Add some example mapping scripts. 
+
+ -- Anthony Towns <ajt@debian.org>  Sat,  7 Oct 2000 18:15:10 -0700
+
+ifupdown0.6 (0.6.2pr-2) unstable; urgency=low
+
+  * Note that dhcpcd works with any kernel, not just 2.0 and 2.2.
+  * Remove the "noauto" keyword from the manpage. Ooopsy.
+  * Create /etc/network/if-*.d directories in preinst.
+  * Update the example-etc-network-interfaces to use the auto keyword.
+
+ -- Anthony Towns <ajt@debian.org>  Sun, 24 Sep 2000 17:05:21 -0700
+
+ifupdown0.6 (0.6.2pr-1) unstable; urgency=low
+
+  * New upstream release.
+  * Forward port some fixes from the last .deb that I hadn't put in the
+    upstream source. Whoops.
+
+  * This is a beta package that doesn't upgrade cleanly from ifupdown. It's
+    for testing purposes only.
+
+ -- Anthony Towns <ajt@debian.org>  Sun, 24 Sep 2000 16:05:25 -0700
+
+ifupdown (0.5.5pr-3) unstable; urgency=low
+
+  * debian/rules: Adjusted to *always* build from scratch if noweb is
+    installed, to ensure that the various .c and .defn files are updated
+    wherever possible. This should fix the problem where the updated
+    inet6.defn wasn't being included, even after -2, amongst others.
+
+ -- Anthony Towns <ajt@debian.org>  Mon, 28 Aug 2000 12:40:28 +1000
+
+ifupdown (0.5.5pr-2) unstable; urgency=low
+
+  * debian/rules: chmod +x any scripts that are created when the diff is
+    applied. (Closes: Bug#70030)
+
+  * ifupdown.nw: Forward port lost changes from netbase 3.18-4.
+    (Closes: Bug#69723)
+  * ifupdown.nw: Specify interface explicitly when adding default routes,
+    and explicitly remove the route when deconfiguring an interface.
+    (Closes: Bug#63071, Bug#67796)
+
+  * debian/control: Add dependency on net-tools.
+
+ -- Anthony Towns <ajt@debian.org>  Sun, 27 Aug 2000 17:47:01 +1000
+
+ifupdown (0.5.5pr-1) unstable; urgency=low
+
+  * Thought through and removed build-dependency on noweb. This involves
+    changing what I put in the .orig.tar.gz. (Closes: Bug#68869)
+
+ -- Anthony Towns <ajt@debian.org>  Sat, 19 Aug 2000 18:09:09 +1000
+
+ifupdown (0.5.5-1) unstable; urgency=low
+
+  * Split from netbase.
+
+ -- Anthony Towns <ajt@debian.org>  Mon, 17 Jul 2000 08:24:56 +1000
+
diff --git a/_darcs/current/debian/conffiles b/_darcs/current/debian/conffiles
new file mode 100644 (file)
index 0000000..20e3e16
--- /dev/null
@@ -0,0 +1,3 @@
+/etc/init.d/ifupdown
+/etc/init.d/ifupdown-clean
+/etc/default/ifupdown
diff --git a/_darcs/current/debian/config b/_darcs/current/debian/config
new file mode 100644 (file)
index 0000000..adf37c0
--- /dev/null
@@ -0,0 +1,15 @@
+#!/bin/sh
+set -e
+
+# Source debconf library
+[ -e /usr/share/debconf/confmodule ] || exit 0
+. /usr/share/debconf/confmodule
+
+if [ "$1" = "configure" ] && [ "$2" != "" ]; then
+       if dpkg --compare-versions "$2" lt "0.6"; then
+               db_input low ifupdown/convert-interfaces || true
+               db_go
+       fi
+fi
+
+db_stop
diff --git a/_darcs/current/debian/control b/_darcs/current/debian/control
new file mode 100644 (file)
index 0000000..993bfb1
--- /dev/null
@@ -0,0 +1,16 @@
+Source: ifupdown
+Section: base
+Priority: important
+Maintainer: Anthony Towns <ajt@debian.org>
+Standards-Version: 3.6.1.0
+Build-Depends: debhelper (>= 4.1.68), nowebm
+
+Package: ifupdown
+Architecture: any
+Depends: net-tools, ${shlibs:Depends}, ${debconf-depends}
+Suggests: iproute, dhcp3-client | dhcp-client, ppp
+Replaces: netbase (<< 4.00)
+Description: high level tools to configure network interfaces
+ This package provides the tools ifup and ifdown which may be used to
+ configure (or, respectively, deconfigure) network interfaces based on
+ interface definitions in the file /etc/network/interfaces.
diff --git a/_darcs/current/debian/copyright b/_darcs/current/debian/copyright
new file mode 100644 (file)
index 0000000..e3839a1
--- /dev/null
@@ -0,0 +1,21 @@
+This package was created and debianized by Anthony Towns
+<ajt@debian.org>. He is also the upstream author of ifupdown.
+
+Copyright (c) 1999, Anthony Towns.  All rights reserved.
+
+   This package 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 dated June, 1991.
+
+   This package 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 package; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+   02111-1307, USA.
+
+On Debian GNU/Linux systems, the complete text of the GNU General
+Public License can be found in /usr/share/common-licenses/GPL .
diff --git a/_darcs/current/debian/dirs b/_darcs/current/debian/dirs
new file mode 100644 (file)
index 0000000..323cb0c
--- /dev/null
@@ -0,0 +1,8 @@
+usr/bin
+usr/sbin
+usr/share/doc/ifupdown/examples
+usr/share/ifupdown
+usr/share/man/man5
+usr/share/man/man8
+etc/network
+etc/init.d
diff --git a/_darcs/current/debian/ifupdown-clean.init b/_darcs/current/debian/ifupdown-clean.init
new file mode 100644 (file)
index 0000000..77bcb6b
--- /dev/null
@@ -0,0 +1,40 @@
+#!/bin/sh
+#
+# ifupdown-clean
+#
+
+set -e
+
+MYNAME="${0##*/}"
+PATH=/sbin:/bin
+[ -r /etc/default/ifupdown ] && . /etc/default/ifupdown
+
+# Note: The state file location is hardcoded in ifup|ifdown
+# it is used as a variable in this script order to ease transitions
+# to other locations by the package (not by the sysadmin), if you want
+# to setup an alternate location please use a symlink
+IFSTATE=/etc/network/run/ifstate
+
+case "$1" in
+  start)
+    echo -n "Cleaning up ifupdown..."
+    if [ -f $IFSTATE -a ! -L $IFSTATE ]; then
+      rm -f "$IFSTATE"
+    elif [ -f $IFSTATE ]; then
+      # This is kinda bad :(
+      >$IFSTATE
+    fi
+    echo "done."
+    exit 0
+    ;;
+
+  stop|restart|force-reload)
+    exit 0
+    ;;
+
+  *)
+    echo "Usage: $0 {start|stop|restart|force-reload}" >&2
+    exit 3
+    ;;
+esac
+
diff --git a/_darcs/current/debian/ifupdown.default b/_darcs/current/debian/ifupdown.default
new file mode 100644 (file)
index 0000000..04715b1
--- /dev/null
@@ -0,0 +1,6 @@
+# Set to "yes" to turn on debugging messages in scripts
+# DEBUG=""
+
+# Time to wait for ifupdown to become ready at boot
+# (Currently not used)
+# IFUPDOWN_TIMEOUT=60
diff --git a/_darcs/current/debian/ifupdown.init b/_darcs/current/debian/ifupdown.init
new file mode 100644 (file)
index 0000000..d261bda
--- /dev/null
@@ -0,0 +1,105 @@
+#!/bin/sh -e
+
+[ -x /sbin/ifup ] || exit 0
+[ -x /sbin/ifdown ] || exit 0
+
+MYNAME="${0##*/}"
+report() { echo "${MYNAME}: $*" ; }
+report_err() { report "Error: $*" >&2 ; }
+RUN_DIR=/etc/network/run
+[ -r /etc/default/ifupdown ] && . /etc/default/ifupdown
+
+# Note: The state file location is hardcoded in ifup|ifdown
+IFSTATE=/etc/network/run/ifstate
+
+myreadlink () {
+  dest="${1%/}"
+  extras=""
+
+  while [ "$dest" != "" ]; do
+    if [ -d "$dest" ]; then
+      cd "$dest"
+      dest=$(/bin/pwd)
+      break
+    fi
+
+    if [ -L "$dest" ]; then
+      d2=$(readlink "$dest")
+      if [ "${d2#/}" = "$d2" ]; then
+        dest="${dest%/*}/$d2"
+      else
+        dest="$d2"
+      fi
+    fi
+
+    while [ ! -e "$dest" ]; do
+      extras="${dest##*/}/$extras"
+      if [ "${extras%%/*}" = ".." ]; then return 1; fi
+      destx="${dest%/*}"
+      if [ "$destx" = "$dest" ]; then destx=""; fi
+      dest="$destx"
+    done
+  done
+  dest="$dest/$extras"
+  echo "${dest%/}"
+}
+
+case "$1" in
+  start|restart)
+    if [ "$2" ]; then
+      report_err "Arguments to '$1' command not accepted"
+      exit 3
+    fi
+    echo -n "Setting up networking..."
+
+    # if /etc/network/run is a symlink to a directory that doesn't exist,
+    # create it.
+
+    if [ -L "$RUN_DIR" ] && [ ! -d "$RUN_DIR" ] ; then
+      runmkdir="$(myreadlink "$RUN_DIR")"
+      if [ ! "$runmkdir" ] ; then
+        echo "failed."
+        report_err "Cannot create target of /etc/network/run"
+        exit 1
+      fi
+      if ! mkdir -p "$runmkdir"; then
+        echo "failed."
+        report_err "Failure creating directory $runmkdir"
+        exit 1
+      fi
+    fi
+
+    # Create the state file
+    # Doing this also signals that ifupdown is available for use
+    if [ ! -r "$IFSTATE" ]; then
+      if ! : > "$IFSTATE" ; then
+        echo "failed."
+        report_err "Failure initializing $IFSTATE"
+        exit 1
+      fi 
+    fi
+
+    echo "done."
+    exit 0
+    ;;
+
+  stop)
+    if [ "$2" ]; then
+      report_err "Arguments to '$1' command not accepted"
+      exit 3
+    fi
+    if [ -x /etc/init.d/ifupdown-clean ]; then
+      /etc/init.d/ifupdown-clean start
+    fi
+    ;;
+
+  force-reload)
+    ;;
+
+  *)
+    echo "Usage: $0 {start|stop|restart|force-reload}" >&2
+    exit 3
+    ;;
+esac
+
+exit 0
diff --git a/_darcs/current/debian/po/POTFILES.in b/_darcs/current/debian/po/POTFILES.in
new file mode 100644 (file)
index 0000000..302e553
--- /dev/null
@@ -0,0 +1 @@
+[type: gettext/rfc822deb] templates.master
diff --git a/_darcs/current/debian/po/ca.po b/_darcs/current/debian/po/ca.po
new file mode 100644 (file)
index 0000000..5238927
--- /dev/null
@@ -0,0 +1,36 @@
+# ifupdown (debconf) translation to Catalan.
+# Copyright (C) 2004 Free Software Foundation, Inc.
+# Aleix Badia i Bosch <abadia@ica.es>, 2004
+# Matt Bonner <mateubonet@yahoo.com>, 2004
+# Jordi Mallach <jordi@debian.org>, 2004
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ifupdown-0.6.4-4.6_templates\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2004-08-04 17:16+0200\n"
+"PO-Revision-Date: 2004-02-28 19:46GMT\n"
+"Last-Translator: Aleix Badia i Bosch <abadia@ica.es>\n"
+"Language-Team: Debian L10n Catalan <debian-l10n-catalan@lists.debian.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid "Update /etc/network/interfaces?"
+msgstr "Voleu actualitzar el fitxer /etc/network/interfaces?"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid ""
+"The format of /etc/network/interfaces has had a minor but incompatible "
+"change made between version 0.5.x and 0.6.x of ifupdown. It is however "
+"possible to automatically convert from the old format to the new in almost "
+"all cases."
+msgstr ""
+"El format del fitxer /etc/network/interfaces de l'ifupdown s'ha modificat "
+"entre les versions 0.5.x i 0.6.x. Tot i això, en la majoria dels casos es "
+"pot actualitzar automàticament del format vell al nou."
diff --git a/_darcs/current/debian/po/cs.po b/_darcs/current/debian/po/cs.po
new file mode 100644 (file)
index 0000000..dac701e
--- /dev/null
@@ -0,0 +1,43 @@
+#
+#    Translators, if you are not familiar with the PO format, gettext
+#    documentation is worth reading, especially sections dedicated to
+#    this format, e.g. by running:
+#         info -n '(gettext)PO Files'
+#         info -n '(gettext)Header Entry'
+#
+#    Some information specific to po-debconf are available at
+#            /usr/share/doc/po-debconf/README-trans
+#         or http://www.debian.org/intl/l10n/po-debconf/README-trans
+#
+#    Developers do not need to manually edit POT or PO files.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ifupdown\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2004-08-04 17:16+0200\n"
+"PO-Revision-Date: 2004-02-09 20:09+0100\n"
+"Last-Translator: Miroslav Kure <kurem@debian.cz>\n"
+"Language-Team: Czech <provoz@debian.cz>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO-8859-2\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid "Update /etc/network/interfaces?"
+msgstr "Aktualizovat /etc/network/interfaces?"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid ""
+"The format of /etc/network/interfaces has had a minor but incompatible "
+"change made between version 0.5.x and 0.6.x of ifupdown. It is however "
+"possible to automatically convert from the old format to the new in almost "
+"all cases."
+msgstr ""
+"Mezi verzemi 0.5.x a 0.6 programu ifupdown do¹lo k malé, ale nekompatibilní "
+"zmìnì formátu souboru /etc/network/interfaces. V témìø v¹ech pøípadech lze "
+"pøevést data ze starého formátu do nového zcela automaticky."
diff --git a/_darcs/current/debian/po/da.po b/_darcs/current/debian/po/da.po
new file mode 100644 (file)
index 0000000..396570e
--- /dev/null
@@ -0,0 +1,44 @@
+#
+#    Translators, if you are not familiar with the PO format, gettext
+#    documentation is worth reading, especially sections dedicated to
+#    this format, e.g. by running:
+#         info -n '(gettext)PO Files'
+#         info -n '(gettext)Header Entry'
+#
+#    Some information specific to po-debconf are available at
+#            /usr/share/doc/po-debconf/README-trans
+#         or http://www.debian.org/intl/l10n/po-debconf/README-trans
+#
+#    Developers do not need to manually edit POT or PO files.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ifupdown 0.6.4\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2004-08-04 17:16+0200\n"
+"PO-Revision-Date: 2004-03-31 14:37+0200\n"
+"Last-Translator: Morten Brix Pedersen <morten@wtf.dk>\n"
+"Language-Team: Danish <dansk@klid.dk>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid "Update /etc/network/interfaces?"
+msgstr "Opdatér /etc/network/interfaces?"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid ""
+"The format of /etc/network/interfaces has had a minor but incompatible "
+"change made between version 0.5.x and 0.6.x of ifupdown. It is however "
+"possible to automatically convert from the old format to the new in almost "
+"all cases."
+msgstr ""
+"Formatet i filen /etc/network/interfaces har fået lavet en mindre men "
+"inkompatibel ændring mellem version 0.5.x og 0.6.x af ifupdown. Det er dog "
+"muligt at automatisk konvertere fra det gamle format til det nye i næsten "
+"alle tilfælde."
diff --git a/_darcs/current/debian/po/de.po b/_darcs/current/debian/po/de.po
new file mode 100644 (file)
index 0000000..bacb4ac
--- /dev/null
@@ -0,0 +1,45 @@
+#
+#    Translators, if you are not familiar with the PO format, gettext
+#    documentation is worth reading, especially sections dedicated to
+#    this format, e.g. by running:
+#         info -n '(gettext)PO Files'
+#         info -n '(gettext)Header Entry'
+#
+#    Some information specific to po-debconf are available at
+#            /usr/share/doc/po-debconf/README-trans
+#         or http://www.debian.org/intl/l10n/po-debconf/README-trans
+#
+#    Developers do not need to manually edit POT or PO files.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2004-08-04 17:16+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO-8859-15\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid "Update /etc/network/interfaces?"
+msgstr "Soll /etc/network/interfaces erneuert werden?"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid ""
+"The format of /etc/network/interfaces has had a minor but incompatible "
+"change made between version 0.5.x and 0.6.x of ifupdown. It is however "
+"possible to automatically convert from the old format to the new in almost "
+"all cases."
+msgstr ""
+"Das Format von /etc/network/interfaces hat eine kleinere aber inkompatible "
+"Änderung zwischen Version 0.5.x und 0.6.x von ifupdown erfahren. Es ist "
+"jedoch in fast allen Fällen möglich, automatisch vom alten in das neue "
+"Format zu konvertieren."
diff --git a/_darcs/current/debian/po/el.po b/_darcs/current/debian/po/el.po
new file mode 100644 (file)
index 0000000..3f96181
--- /dev/null
@@ -0,0 +1,45 @@
+# translation of el.po to Greek
+# translation of templates.po to Greek
+#
+#    Translators, if you are not familiar with the PO format, gettext
+#    documentation is worth reading, especially sections dedicated to
+#    this format, e.g. by running:
+#         info -n '(gettext)PO Files'
+#         info -n '(gettext)Header Entry'
+#    Some information specific to po-debconf are available at
+#            /usr/share/doc/po-debconf/README-trans
+#         or http://www.debian.org/intl/l10n/po-debconf/README-trans#
+#    Developers do not need to manually edit POT or PO files.
+# Konstantinos Margaritis <markos@debian.org>, 2004.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: el\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2004-08-04 17:16+0200\n"
+"PO-Revision-Date: 2004-01-15 22:04EEST\n"
+"Last-Translator: Konstantinos Margaritis <markos@debian.org>\n"
+"Language-Team: Greek <debian-l10n-greek@lists.debian.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.0.2\n"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid "Update /etc/network/interfaces?"
+msgstr "Να γίνει διόρθωση του /etc/network/interfaces;"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid ""
+"The format of /etc/network/interfaces has had a minor but incompatible "
+"change made between version 0.5.x and 0.6.x of ifupdown. It is however "
+"possible to automatically convert from the old format to the new in almost "
+"all cases."
+msgstr ""
+"Η δομή του /etc/network/interfaces άλλαξε με ένα μικρό αλλά ασύμβατο τρόπο "
+"από την έκδοση του πακέτου ifupdown 0.5.x και 0.6.x.  Ωστόσο, είναι δυνατή η "
+"αυτόματη μετατροπή της παλιάς δομής στη νέα για σχεδόν όλες τις περιπτώσεις."
diff --git a/_darcs/current/debian/po/es.po b/_darcs/current/debian/po/es.po
new file mode 100644 (file)
index 0000000..f3d133c
--- /dev/null
@@ -0,0 +1,46 @@
+#
+#    Translators, if you are not familiar with the PO format, gettext
+#    documentation is worth reading, especially sections dedicated to
+#    this format, e.g. by running:
+#         info -n '(gettext)PO Files'
+#         info -n '(gettext)Header Entry'
+#
+#    Some information specific to po-debconf are available at
+#            /usr/share/doc/po-debconf/README-trans
+#         or http://www.debian.org/intl/l10n/po-debconf/README-trans
+#
+#    Developers do not need to manually edit POT or PO files.
+#
+# Carlos Valdivia Yagüe <valyag@dat.etsit.upm.es>, 2003
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ifupdown 0.6.4\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2004-08-04 17:16+0200\n"
+"PO-Revision-Date: 2003-08-29 01:00+0200\n"
+"Last-Translator: Carlos Valdivia Yagüe <valyag@dat.etsit.upm.es>\n"
+"Language-Team: Debian L10n Spanish <debian-l10n-spanish@lists.debian.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO-8859-15\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid "Update /etc/network/interfaces?"
+msgstr "¿Actualizar /etc/network/interfaces"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid ""
+"The format of /etc/network/interfaces has had a minor but incompatible "
+"change made between version 0.5.x and 0.6.x of ifupdown. It is however "
+"possible to automatically convert from the old format to the new in almost "
+"all cases."
+msgstr ""
+"El formato de /etc/network/interfaces ha sufrido un cambio pequeño pero "
+"incompatible entre las versiones 0.5.x y 0.6.x de ifupdown. No obstante, en "
+"casi todos los casos es posible realizar la conversión automáticamente entre "
+"el formato antiguo y el nuevo."
diff --git a/_darcs/current/debian/po/fr.po b/_darcs/current/debian/po/fr.po
new file mode 100644 (file)
index 0000000..2b5ec5f
--- /dev/null
@@ -0,0 +1,44 @@
+#
+#    Translators, if you are not familiar with the PO format, gettext
+#    documentation is worth reading, especially sections dedicated to
+#    this format, e.g. by running:
+#         info -n '(gettext)PO Files'
+#         info -n '(gettext)Header Entry'
+#
+#    Some information specific to po-debconf are available at
+#            /usr/share/doc/po-debconf/README-trans
+#         or http://www.debian.org/intl/l10n/po-debconf/README-trans
+#
+#    Developers do not need to manually edit POT or PO files.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ifupdown 0.6.4\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2004-08-04 17:16+0200\n"
+"PO-Revision-Date: 2003-07-10 19:52+0100\n"
+"Last-Translator: Thomas Morin <thomas.morin@webmotion.com>\n"
+"Language-Team: French <debian-l10n-french@lists.debian.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO-8859-15\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid "Update /etc/network/interfaces?"
+msgstr "Mettre à jour /etc/network/interfaces ?"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid ""
+"The format of /etc/network/interfaces has had a minor but incompatible "
+"change made between version 0.5.x and 0.6.x of ifupdown. It is however "
+"possible to automatically convert from the old format to the new in almost "
+"all cases."
+msgstr ""
+"Le format du fichier /etc/network/interfaces a subi un changement mineur "
+"mais incompatible entre les versions 0.5.x et 0.6.x d'ifupdown. Il est "
+"néanmoins possible de convertir automatiquement ce fichier de l'ancien "
+"format au nouveau, dans la plupart des cas."
diff --git a/_darcs/current/debian/po/it.po b/_darcs/current/debian/po/it.po
new file mode 100644 (file)
index 0000000..730dda8
--- /dev/null
@@ -0,0 +1,36 @@
+# ifupdown po-debconf translation to italian\r
+# Copyright (C) 2004 Software in the Public Interest\r
+# This file is distributed under the same license as the ifupdown package.\r
+# Luca Monducci, 2004.\r
+# \r
+msgid ""
+msgstr ""
+"Project-Id-Version: ifupdown 0.6.4-4.10\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2004-08-04 17:16+0200\n"
+"PO-Revision-Date: 2004-11-21 16:02+0100\n"
+"Last-Translator: Luca Monducci <luca.mo@tiscali.it>\n"
+"Language-Team: Italian <debian-l10n-italian@lists.debian.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid "Update /etc/network/interfaces?"
+msgstr "Aggiornare /etc/network/interfaces?"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid ""
+"The format of /etc/network/interfaces has had a minor but incompatible "
+"change made between version 0.5.x and 0.6.x of ifupdown. It is however "
+"possible to automatically convert from the old format to the new in almost "
+"all cases."
+msgstr ""
+"Il formato del file /etc/network/interfaces ha subito un piccolo cambiamento "
+"che lo rende incompatibile fra le versioni 0.5.x e 0.6.x di ifupdown. "
+"Comunque, nella maggior parte dei casi, è possibile convertire "
+"automaticamente il file dal vecchio formato al nuovo."
diff --git a/_darcs/current/debian/po/ja.po b/_darcs/current/debian/po/ja.po
new file mode 100644 (file)
index 0000000..984a761
--- /dev/null
@@ -0,0 +1,43 @@
+#
+#    Translators, if you are not familiar with the PO format, gettext
+#    documentation is worth reading, especially sections dedicated to
+#    this format, e.g. by running:
+#         info -n '(gettext)PO Files'
+#         info -n '(gettext)Header Entry'
+#
+#    Some information specific to po-debconf are available at
+#            /usr/share/doc/po-debconf/README-trans
+#         or http://www.debian.org/intl/l10n/po-debconf/README-trans
+#
+#    Developers do not need to manually edit POT or PO files.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2004-08-04 17:16+0200\n"
+"PO-Revision-Date: 2003-09-11 23:13+0900\n"
+"Last-Translator: Kenshi Muto <kmuto@debian.org>\n"
+"Language-Team: Japanese <debian-japanese@lists.debian.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=EUC-JP\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid "Update /etc/network/interfaces?"
+msgstr "/etc/network/interfaces ¤ò¹¹¿·¤·¤Þ¤¹¤«?"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid ""
+"The format of /etc/network/interfaces has had a minor but incompatible "
+"change made between version 0.5.x and 0.6.x of ifupdown. It is however "
+"possible to automatically convert from the old format to the new in almost "
+"all cases."
+msgstr ""
+"/etc/network/interfaces ¤Î·Á¼°¤Ï¡¢ifupdown ¤Î 0.5.x ¤È 0.6.x ¤Î¤¢¤¤¤À¤ÇºÙ¤«"
+"¤Ê¡¢¤·¤«¤·Èó¸ß´¹¤ÎÊѹ¹¤¬¹Ô¤ï¤ì¤Þ¤·¤¿¡£¤Û¤Ü¤¹¤Ù¤Æ¤Î¾ì¹ç¡¢¸Å¤¤·Á¼°¤«¤é¿·¤·¤¤·Á"
+"¼°¤Ø¼«Æ°Åª¤ËÊÑ´¹¤Ç¤­¤Þ¤¹¡£"
diff --git a/_darcs/current/debian/po/lt.po b/_darcs/current/debian/po/lt.po
new file mode 100644 (file)
index 0000000..43e31e9
--- /dev/null
@@ -0,0 +1,33 @@
+# translation of ifupdown debconf templates to Lithuanian
+# Copyright (C) 2004 Free Software Foundation, Inc.
+# Gintautas Miliauskas <gintas@akl.lt>, 2004.
+msgid ""
+msgstr ""
+"Project-Id-Version: pcmcia-cs\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2004-08-04 17:16+0200\n"
+"PO-Revision-Date: 2004-05-16 11:05+0300\n"
+"Last-Translator: Gintautas Miliauskas <gintas@akl.lt>\n"
+"Language-Team: Lithuanian <komp_lt@konferencijos.lt>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid "Update /etc/network/interfaces?"
+msgstr "Atnaujinti /etc/network/interfaces?"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid ""
+"The format of /etc/network/interfaces has had a minor but incompatible "
+"change made between version 0.5.x and 0.6.x of ifupdown. It is however "
+"possible to automatically convert from the old format to the new in almost "
+"all cases."
+msgstr ""
+"Failo /etc/network/interfaces formatas nežymiai, bet nesuderinamai skiriasi "
+"tarp ifupdown versijų 0.5.x ir 0.6.x, tačiau beveik visais atvejais galima "
+"automatiškai konvertuoti iš seno formato į naują."
diff --git a/_darcs/current/debian/po/nl.po b/_darcs/current/debian/po/nl.po
new file mode 100644 (file)
index 0000000..21eb670
--- /dev/null
@@ -0,0 +1,44 @@
+#
+#    Translators, if you are not familiar with the PO format, gettext
+#    documentation is worth reading, especially sections dedicated to
+#    this format, e.g. by running:
+#         info -n '(gettext)PO Files'
+#         info -n '(gettext)Header Entry'
+#
+#    Some information specific to po-debconf are available at
+#            /usr/share/doc/po-debconf/README-trans
+#         or http://www.debian.org/intl/l10n/po-debconf/README-trans
+#
+#    Developers do not need to manually edit POT or PO files.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ifupdown 0.6.4-4.6\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2004-08-04 17:16+0200\n"
+"PO-Revision-Date: 2003-09-20 00:44+0100\n"
+"Last-Translator: Tim Dijkstra <tim@famdijkstra.org>\n"
+"Language-Team: Dutch <debian-l10n-dutch@lists.debian.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=iso-8859-15\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid "Update /etc/network/interfaces?"
+msgstr "/etc/network/interfaces bijwerken?"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid ""
+"The format of /etc/network/interfaces has had a minor but incompatible "
+"change made between version 0.5.x and 0.6.x of ifupdown. It is however "
+"possible to automatically convert from the old format to the new in almost "
+"all cases."
+msgstr ""
+"De indeling van /etc/network/interfaces heeft tussen versie 0.5.x en 0.6.x "
+"van ifupdown een kleine, maar incompatibele verandering ondergaan. In bijna "
+"alle gevallen is het echter mogelijk om automatisch het oude format naar het "
+"nieuwe om te zetten."
diff --git a/_darcs/current/debian/po/pl.po b/_darcs/current/debian/po/pl.po
new file mode 100644 (file)
index 0000000..cbf6cdb
--- /dev/null
@@ -0,0 +1,46 @@
+#
+#    Translators, if you are not familiar with the PO format, gettext
+#    documentation is worth reading, especially sections dedicated to
+#    this format, e.g. by running:
+#         info -n '(gettext)PO Files'
+#         info -n '(gettext)Header Entry'
+#
+#    Some information specific to po-debconf are available at
+#            /usr/share/doc/po-debconf/README-trans
+#         or http://www.debian.org/intl/l10n/po-debconf/README-trans
+#
+#    Developers do not need to manually edit POT or PO files.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2004-08-04 17:16+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO-8859-2\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid "Update /etc/network/interfaces?"
+msgstr "Uaktualniæ /etc/network/interfaces?"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid ""
+"The format of /etc/network/interfaces has had a minor but incompatible "
+"change made between version 0.5.x and 0.6.x of ifupdown. It is however "
+"possible to automatically convert from the old format to the new in almost "
+"all cases."
+msgstr ""
+"W porównaniu z wersj± 0.5.x, wersja 0.6.x programu ifupdown wprowadza drobne "
+"zmiany, które jednak powoduj±, ¿e stara wersja pliku /etc/network/interfaces "
+"mo¿e nie pasowaæ do nowej konfiguracji. Istnieje jednak mo¿liwo¶æ "
+"automatycznej konwersji (w praktycznie wszystkich przypadkach) ze starego "
+"formatu do nowego."
diff --git a/_darcs/current/debian/po/pt_BR.po b/_darcs/current/debian/po/pt_BR.po
new file mode 100644 (file)
index 0000000..e557a7a
--- /dev/null
@@ -0,0 +1,45 @@
+#
+#    Translators, if you are not familiar with the PO format, gettext
+#    documentation is worth reading, especially sections dedicated to
+#    this format, e.g. by running:
+#         info -n '(gettext)PO Files'
+#         info -n '(gettext)Header Entry'
+#
+#    Some information specific to po-debconf are available at
+#            /usr/share/doc/po-debconf/README-trans
+#         or http://www.debian.org/intl/l10n/po-debconf/README-trans
+#
+#    Developers do not need to manually edit POT or PO files.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2004-08-04 17:16+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO-8859-1\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid "Update /etc/network/interfaces?"
+msgstr "Atualizar /etc/network/interfaces?"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid ""
+"The format of /etc/network/interfaces has had a minor but incompatible "
+"change made between version 0.5.x and 0.6.x of ifupdown. It is however "
+"possible to automatically convert from the old format to the new in almost "
+"all cases."
+msgstr ""
+"O formato do arquivo /etc/network/interfaces sofreu uma mudança menor mas "
+"incompatível entre as versões 0.5.x e 0.6.x do pacote ifupdown. Porém é "
+"possível converter a partir do formato antigo para o novo formato na maioria "
+"dos casos."
diff --git a/_darcs/current/debian/po/ru.po b/_darcs/current/debian/po/ru.po
new file mode 100644 (file)
index 0000000..7ccca68
--- /dev/null
@@ -0,0 +1,44 @@
+#
+#    Translators, if you are not familiar with the PO format, gettext
+#    documentation is worth reading, especially sections dedicated to
+#    this format, e.g. by running:
+#         info -n '(gettext)PO Files'
+#         info -n '(gettext)Header Entry'
+#
+#    Some information specific to po-debconf are available at
+#            /usr/share/doc/po-debconf/README-trans
+#         or http://www.debian.org/intl/l10n/po-debconf/README-trans
+#
+#    Developers do not need to manually edit POT or PO files.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2004-08-04 17:16+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=KOI8-R\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid "Update /etc/network/interfaces?"
+msgstr "ïÂÎÏ×ÉÔØ /etc/network/interfaces?"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid ""
+"The format of /etc/network/interfaces has had a minor but incompatible "
+"change made between version 0.5.x and 0.6.x of ifupdown. It is however "
+"possible to automatically convert from the old format to the new in almost "
+"all cases."
+msgstr ""
+"æÏÒÍÁÔ /etc/network/interfaces ÉÍÅÅÔ ÎÅÂÏÌØÛÉÅ, ÎÏ ÎÅÓÏ×ÍÅÓÔÉÍÙÅ ÉÚÍÅÎÅÎÉÑ "
+"ÍÅÖÄÕ ×ÅÒÓÉÑÍÉ 0.5.x É 0.6.x ifupdown. ïÄÎÁËÏ ×ÏÚÍÏÖÎÏ Á×ÔÏÍÁÔÉÞÅÓËÉ "
+"ÐÒÅÏÂÒÁÚÏ×ÁÔØ ÓÔÁÒÙÊ ÆÏÒÍÁÔ Ó ÎÏ×ÙÊ ÐÏÞÔÉ ×Ï ×ÓÅÈ ÓÌÕÞÁÑÈ."
diff --git a/_darcs/current/debian/po/sv.po b/_darcs/current/debian/po/sv.po
new file mode 100644 (file)
index 0000000..4c2ab42
--- /dev/null
@@ -0,0 +1,44 @@
+#
+#    Translators, if you are not familiar with the PO format, gettext
+#    documentation is worth reading, especially sections dedicated to
+#    this format, e.g. by running:
+#         info -n '(gettext)PO Files'
+#         info -n '(gettext)Header Entry'
+#
+#    Some information specific to po-debconf are available at
+#            /usr/share/doc/po-debconf/README-trans
+#         or http://www.debian.org/intl/l10n/po-debconf/README-trans
+#
+#    Developers do not need to manually edit POT or PO files.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2004-08-04 17:16+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO-8859-1\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid "Update /etc/network/interfaces?"
+msgstr "Uppdatera /etc/network/interfaces?"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid ""
+"The format of /etc/network/interfaces has had a minor but incompatible "
+"change made between version 0.5.x and 0.6.x of ifupdown. It is however "
+"possible to automatically convert from the old format to the new in almost "
+"all cases."
+msgstr ""
+"Formatet på /etc/network/interfaces genomgick en liten men inkompatibel "
+"ändring mellan version 0.5.x och 0.6.x av ifupdown. Det är dock möjligt att "
+"nästan alltid automatiskt konvertera från det gamla formatet till det nya."
diff --git a/_darcs/current/debian/po/templates.pot b/_darcs/current/debian/po/templates.pot
new file mode 100644 (file)
index 0000000..2edbd95
--- /dev/null
@@ -0,0 +1,41 @@
+#
+#    Translators, if you are not familiar with the PO format, gettext
+#    documentation is worth reading, especially sections dedicated to
+#    this format, e.g. by running:
+#         info -n '(gettext)PO Files'
+#         info -n '(gettext)Header Entry'
+#
+#    Some information specific to po-debconf are available at
+#            /usr/share/doc/po-debconf/README-trans
+#         or http://www.debian.org/intl/l10n/po-debconf/README-trans
+#
+#    Developers do not need to manually edit POT or PO files.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2004-08-04 17:16+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid "Update /etc/network/interfaces?"
+msgstr ""
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid ""
+"The format of /etc/network/interfaces has had a minor but incompatible "
+"change made between version 0.5.x and 0.6.x of ifupdown. It is however "
+"possible to automatically convert from the old format to the new in almost "
+"all cases."
+msgstr ""
diff --git a/_darcs/current/debian/po/tr.po b/_darcs/current/debian/po/tr.po
new file mode 100644 (file)
index 0000000..3c3a118
--- /dev/null
@@ -0,0 +1,37 @@
+# Turkish translation of ifupdown.
+# This file is distributed under the same license as the ifupdown package.
+# Mehmet Turker <mturker@innova.com.tr>, 2004.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ifupdown\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2004-08-04 17:16+0200\n"
+"PO-Revision-Date: 2004-03-21 03:22+0200\n"
+"Last-Translator: Mehmet Turker <mturker@innova.com.tr>\n"
+"Language-Team: Turkish <debian-l10n-turkish@lists.debian.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.3.1\n"
+"Plural-Forms:  nplurals=1; plural=0;\n"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid "Update /etc/network/interfaces?"
+msgstr "/etc/network/interfaces güncellensin mi?"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid ""
+"The format of /etc/network/interfaces has had a minor but incompatible "
+"change made between version 0.5.x and 0.6.x of ifupdown. It is however "
+"possible to automatically convert from the old format to the new in almost "
+"all cases."
+msgstr ""
+"/etc/network/interfaces dosya biçeminde 0.5.x'den 0.6.x sürümüne geçişte "
+"küçük fakat uyumsuzluk yaratan bir değişiklik oldu. Bununla birlikte eski "
+"biçemin otomatik olarak yenisine dönüştürülmesi neredeyse her durumda "
+"mümkündür."
diff --git a/_darcs/current/debian/po/zh_CN.po b/_darcs/current/debian/po/zh_CN.po
new file mode 100644 (file)
index 0000000..c9140f8
--- /dev/null
@@ -0,0 +1,42 @@
+#
+#    Translators, if you are not familiar with the PO format, gettext
+#    documentation is worth reading, especially sections dedicated to
+#    this format, e.g. by running:
+#         info -n '(gettext)PO Files'
+#         info -n '(gettext)Header Entry'
+#
+#    Some information specific to po-debconf are available at
+#            /usr/share/doc/po-debconf/README-trans
+#         or http://www.debian.org/intl/l10n/po-debconf/README-trans
+#
+#    Developers do not need to manually edit POT or PO files.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ifupdown 0.6.4\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2004-08-04 17:16+0200\n"
+"PO-Revision-Date: 2004-02-06 17:45+0800\n"
+"Last-Translator: Hiei Xu <nicky@mail.edu.cn>\n"
+"Language-Team: Chinese/Simplified <i18n-translation@lists.linux.net.cn>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid "Update /etc/network/interfaces?"
+msgstr "更新 /etc/network/interfaces 吗?"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid ""
+"The format of /etc/network/interfaces has had a minor but incompatible "
+"change made between version 0.5.x and 0.6.x of ifupdown. It is however "
+"possible to automatically convert from the old format to the new in almost "
+"all cases."
+msgstr ""
+"ifupdown 0.5.x 与 0.6.x 所使用的 /etc/network/interfaces 的文件格式之间有一个"
+"较小但互不兼容的改变,然而在绝大多数情况下程序都能自动将旧格式转换到新格式。"
diff --git a/_darcs/current/debian/postinst b/_darcs/current/debian/postinst
new file mode 100644 (file)
index 0000000..953fed8
--- /dev/null
@@ -0,0 +1,156 @@
+#!/bin/sh
+set -e
+
+. /usr/share/debconf/confmodule
+
+MYNAME="${0##*/}"
+
+report() { echo "${MYNAME}: $*" ; }
+report_warn() { report "Warning: $*" >&2 ; }
+report_err() { report "Error: $*" >&2 ; }
+
+ATTEMPT_CONVERSION=false
+if [ "$1" = "configure" ] && [ "$2" != "" ] &&
+        dpkg --compare-versions "$2" le "0.6.2pr-3"
+then
+  # Get answers to questions
+  db_get ifupdown/convert-interfaces;    ATTEMPT_CONVERSION="$RET"
+fi
+
+# Update /etc/network/interfaces from "noauto" to "auto"
+if [ "$ATTEMPT_CONVERSION" = "true" ]; then
+  echo
+  echo -n "Automatically converting /etc/network/interfaces"
+  (
+    cd /etc/network;
+    if /usr/share/ifupdown/upgrade-from-0.5.x.pl \
+      < interfaces > interfaces.dpkg-new 2>/dev/null
+    then
+      echo " succeeded."
+      mv interfaces interfaces.dpkg-old
+      mv interfaces.dpkg-new interfaces
+      echo "Old interfaces file saved as interfaces.dpkg-old."
+    else
+      echo " failed."
+      echo
+      echo "If you wish to reattempt the conversion you may run"
+      echo "    cat /etc/network/interfaces |"
+      echo "         /usr/share/ifupdown/upgrade-from-0.5.x.pl"
+      echo
+    fi
+  )
+fi
+
+# Create /etc/network/run 
+if [ "$1" = configure -a ! -d /etc/network/run ]; then
+  if [ -e /etc/network/run -o -L /etc/network/run ]; then
+    echo "Renaming non-directory /etc/network/run to run.dpkg-old..."
+    mv /etc/network/run /etc/network/run.dpkg-old
+  fi
+
+  # The best choice is to use /dev/shm/network
+  #
+  # If we can't use that, we'll just make /etc/network/run a directory,
+  # unless we're upgrading, in which case we'll just keep ifstate where it
+  # is, by making /etc/network/run a symlink to /etc/network.
+
+  WHAT_TO_USE=devshm
+
+  if [ ! -d /dev/shm -o ! -w /dev/shm -o ! -r /proc/mounts ]; then
+    WHAT_TO_USE=owndir
+  elif ! grep -qs "^tmpfs[[:space:]]\+/dev/shm[[:space:]]\+tmpfs[[:space:]]\+\([^[:space:]]\+,\)\?rw" /proc/mounts
+  then
+    WHAT_TO_USE=owndir
+  elif grep -qs '[[:space:]]/dev[[:space:]]devfs[[:space:]]' /proc/mounts; then
+    WHAT_TO_USE=owndir
+  fi
+
+  # Check for available space if we are using devshm
+  if [ "$WHAT_TO_USE" = devshm ]; then
+    SPACE=`df -k /dev/shm | tail -1 | awk '{if ($4 ~ /%/) { print $3 } else { print $4 } }'`
+    if [ "$SPACE" -le 0 ]; then
+      WHAT_TO_USE=owndir
+    fi
+  fi
+
+  if [ "$WHAT_TO_USE" = owndir -a -e /etc/network/ifstate ]; then
+    WHAT_TO_USE=etcnetwork
+  fi
+
+  if [ "$WHAT_TO_USE" = devshm ]
+  then
+    [ -d /dev/shm/network ] || mkdir /dev/shm/network
+    ln -s /dev/shm/network /etc/network/run
+  elif [ "$WHAT_TO_USE" = "owndir" ]; then
+    mkdir /etc/network/run
+  else
+    ln -s . /etc/network/run
+  fi
+fi 
+
+# Move /etc/network/ifstate to /etc/network/run/ifstate
+if [ "$1" = configure -a "$2" != "" -a -e /etc/network/ifstate ] &&
+     dpkg --compare-versions "$2" lt "0.6.5"
+then
+  if [ ! -e /etc/network/run/ifstate ] || ! diff /etc/network/ifstate /etc/network/run/ifstate >/dev/null
+  then
+    echo "Moving /etc/network/ifstate to /etc/network/run/ifstate"
+    if [ ! -L /etc/network/ifstate ]; then
+      mv /etc/network/ifstate /etc/network/run/ifstate
+    else
+      cat /etc/network/ifstate >/etc/network/run/ifstate
+      mv /etc/network/ifstate /etc/network/ifstate.dpkg-old
+    fi
+  fi
+fi
+   
+if [ "$1" = "configure" -a "$2" != "" ] &&
+     dpkg --compare-versions "$2" le "0.6.4-4.1" &&
+     [ -f /etc/network/run/ifstate -a -x /sbin/dhclient ]
+then
+  # for every active ifupdown-controlled dhclient interface, copy
+  # /var/run/dhclient.pid, so that the new ifdown is able to kill
+  # dhclient.
+  #
+  # the old version had a bug with more than one DHCP iface anyway,
+  # so we don't know which one the PID file actually belongs to.
+
+  sed -e 's/^.*=//' /etc/network/run/ifstate |
+    while read iface; do
+      # handle \<newline>-continued lines
+      if sed -e '/^[[:space:]]*#/b;:g /\\$/{N;s/\\\n//;bg;}' /etc/network/interfaces | grep -qe "^[[:space:]]*iface[[:space:]]*\\b${iface}\\b[[:space:]]*.*\\bdhcp\\b.*" &&
+          [ -f "/var/run/dhclient.pid" ] &&
+          [ ! -f "/var/run/dhclient.${iface}.pid" ]
+      then
+        # copy original file.  If dhclient was started
+        # manually, one can still use dhclient.pid, if started
+        # by ifupdown, the new ifupdown can take it down with 
+        # dhclient.${iface}.pid.  Obsolete files are removed during
+        # next boot (bootmisc.sh).
+        cp /var/run/dhclient.pid "/var/run/dhclient.${iface}.pid"
+      fi
+    done
+fi
+
+# Generic stuff done on all configurations
+if [ "$1" = "configure" ] ; then
+  if [ -f /etc/network/interfaces ] ; then
+    # TODO: This should be handled with debconf and the script
+    # could introduce the line there directly
+    if ! grep -q "^[[:space:]]*iface[[:space:]]\+lo[[:space:]]\+inet[[:space:]]\+loopback\>" /etc/network/interfaces ; then
+      report_warn "No 'iface lo' definition found in /etc/network/interfaces"
+    fi
+    if ! grep -q "^[[:space:]]*auto[[:space:]].*\<lo\>" /etc/network/interfaces ; then
+      report_warn "No 'auto lo' statement found in /etc/network/interfaces"
+    fi
+  else  # ! -f /etc/network/interfaces
+    echo "Creating /etc/network/interfaces."
+    echo "# interfaces(5) file used by ifup(8) and ifdown(8)" > /etc/network/interfaces
+    echo "auto lo" >> /etc/network/interfaces
+    echo "iface lo inet loopback" >> /etc/network/interfaces
+  fi
+fi
+
+db_stop
+
+#DEBHELPER#
diff --git a/_darcs/current/debian/postrm b/_darcs/current/debian/postrm
new file mode 100644 (file)
index 0000000..883ffcd
--- /dev/null
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+case "$1" in
+  purge)
+    # Note: We don't remove /etc/network/interfaces
+    rm -f /etc/network/run/ifstate
+
+    if [ -L /etc/network/run ] ; then
+      rm -f /etc/network/run
+    elif [ -d /etc/network/run ] ; then
+      rmdir --ignore-fail-on-non-empty /etc/network/run
+    fi
+    ;;
+esac
+
+#DEBHELPER#
+
diff --git a/_darcs/current/debian/preinst b/_darcs/current/debian/preinst
new file mode 100644 (file)
index 0000000..eb5523f
--- /dev/null
@@ -0,0 +1,27 @@
+#!/bin/sh
+set -e
+
+if [ ! -d /etc/network ]; then
+  mkdir -p /etc/network
+fi
+
+if [ -f /etc/network/interfaces ] && ! grep -q '^[^#]' /etc/network/interfaces
+then
+  f=/etc/network/interfaces
+  if [ `md5sum < $f | cut -f1 -d ' '` = "4ed352919f69a77ad302ad1593204405" ]; then
+    if [ `wc -c < /etc/network/interfaces` -eq 2466 ]; then
+      echo -n "Removing old dummy /etc/network/interfaces: "
+      rm /etc/network/interfaces
+      echo "done."
+    fi
+  fi
+fi
+
+if [ ! -f /etc/network/interfaces ]; then
+  cat <<EOF >/etc/network/interfaces
+# Used by ifup(8) and ifdown(8). See the interfaces(5) manpage or
+# /usr/share/doc/ifupdown/examples for more information.
+EOF
+fi
+
+#DEBHELPER#
diff --git a/_darcs/current/debian/rules b/_darcs/current/debian/rules
new file mode 100644 (file)
index 0000000..698a1c2
--- /dev/null
@@ -0,0 +1,174 @@
+#!/usr/bin/make -f
+
+######################################################################
+# BUILD NOTES
+#
+# ifupdown's written in litprog using noweb. noweb is written in icon.
+# icon isn't as portable as one might hope (it needs to have bits recoded
+# for each arch and OS it's ported to. ugh).
+#
+# So. The "upstream" source is made to not include any of the generated
+# files. That's neat and tidy. If you want to modify anything, you edit
+# the .nw file.
+#
+# Once you've done all the Debian changes, you run debian/rules binary,
+# and get all the .c files and such updated. Once you're done, you
+# run debian/rules clean, which leaves the generated .c files around
+# for porters. You then generate a .diff.gz, and all should be well.
+#
+# Useful targets of the toplevel makefile:
+# clobber:
+#   * gets rid of all the generated files except Makefile,
+#     make{c,nw}dep.sh, which are needed to bootstrap
+#
+# distclean:
+#   * removes ALL generated files.  Use with care.
+#
+# docs: 
+#   * builds the documentation. Note that this is not done per
+#     default (only executables are built). If this is added to
+#     the default build process (which will not be done in the near
+#     future since dia requires an X display even if using the -e option) 
+#     the 'tetex-base' and 'dia' packages would need to be added to the
+#     Build-Dep
+#
+######################################################################
+
+# Uncomment this to turn on verbose mode.
+#export DH_VERBOSE=1
+
+# This is the debhelper compatability version to use.
+export DH_COMPAT=1
+
+# For working out whether we're cross-building
+DEB_BUILD_GNU_TYPE     := $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)
+DEB_HOST_GNU_TYPE      := $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
+
+# user/group of to-be-installed files
+ROOT_USER  := 0
+ROOT_GROUP := 0
+
+ifeq (,$(wildcard /usr/bin/po2debconf))
+PO2DEBCONF := no
+MINDEBCONFVER := 0.5
+else
+PO2DEBCONF := yes
+MINDEBCONFVER := 1.2.0
+endif
+
+configure:
+       dh_testdir
+
+build: build-stamp
+build-stamp: # configure
+       dh_testdir
+
+       if [ -x /usr/bin/noweb ]; then \
+         $(MAKE) clobber; \
+       else \
+         chmod a+rx defn2c.pl defn2man.pl makecdep.sh makenwdep.sh; \
+       fi
+       $(MAKE)
+       touch build-stamp
+
+test: build
+       dh_testdir
+
+ifeq ($(DEB_BUILD_GNU_TYPE),$(DEB_HOST_GNU_TYPE))
+       chmod a+rx debian/testbuild
+       @echo running debian/testbuild
+       @if ! debian/testbuild; then \
+            echo '=================================================='; \
+            echo 'AUTOMATIC TESTS FAILED -- Something built wrong or'; \
+            echo 'there is a bug in the code!!! Either way something'; \
+            echo 'is completely screwed up!!! File a bug!'; \
+            echo ''; \
+            echo 'Aborting build.'; \
+            echo '=================================================='; \
+            exit 1; \
+       fi
+endif
+
+clean:
+       dh_testdir
+       dh_testroot
+
+       # Add here commands to clean up after the build process
+       rm -rf tests/
+       rm -f build-stamp install-stamp
+       -$(MAKE) clean
+
+       dh_clean
+ifeq ($(PO2DEBCONF),yes)
+       # Hack for woody compatibility. This makes sure that the
+       # debian/templates file shipped in the source package doesn't
+       # specify encodings, which woody's debconf can't handle. If building
+       # on a system with po-debconf installed (conveniently debhelper (>=
+       # 4.1.16) depends on it), the binary-arch target will generate a
+       # better version for sarge.
+       echo 1 > debian/po/output
+       po2debconf debian/templates.master > debian/templates
+       rm -f debian/po/output
+endif
+
+install-stamp: install
+install: build test
+       dh_testdir
+       dh_testroot
+       dh_clean -k
+       dh_installdirs etc/network/if-pre-up.d etc/network/if-up.d etc/network/if-down.d etc/network/if-post-down.d
+
+       # Add here commands to install the package into debian/tmp.
+       $(MAKE) install BASEDIR=`pwd`/debian/tmp
+
+       install -o $(ROOT_USER) -g $(ROOT_GROUP) -m 755 debian/upgrade-from-0.5.x.pl \
+               debian/tmp/usr/share/ifupdown/
+       touch install-stamp
+
+# Build architecture-independent files here.
+binary-indep: build-stamp install-stamp
+# We have nothing to do by default.
+
+# Build architecture-dependent files here.
+binary-arch: build install
+#      dh_testversion
+       dh_testdir
+       dh_testroot
+       dh_installdebconf       
+       dh_installdocs
+       dh_installexamples contrib/*
+       mv debian/tmp/usr/share/doc/ifupdown/examples debian/tmp/usr/share/doc/ifupdown/contrib
+       dh_installexamples examples/*
+       dh_installmenu
+#      dh_installemacsen
+#      dh_installpam
+       dh_installinit --name=ifupdown --no-start -- start 39 S .  start 36 0 6 .
+       dh_installinit --name=ifupdown-clean --no-start -- start 18 S .
+       dh_installcron
+#      dh_installmanpages
+#         ^-- can't do our symlink trick
+       install -o $(ROOT_USER) -g $(ROOT_GROUP) -m 644 interfaces.5 debian/tmp/usr/share/man/man5/interfaces.5
+       install -o $(ROOT_USER) -g $(ROOT_GROUP) -m 644 ifup.8 debian/tmp/usr/share/man/man8/ifup.8
+       ln -s ifup.8 debian/tmp/usr/share/man/man8/ifdown.8
+       dh_installinfo
+#      dh_undocumented
+       dh_installchangelogs ChangeLog
+       dh_link
+       dh_strip
+       dh_compress
+       dh_fixperms
+       # You may want to make some executables suid here.
+#      dh_suidregister
+#      dh_makeshlibs
+       dh_installdeb
+#      dh_perl
+       dh_shlibdeps
+ifeq ($(PO2DEBCONF),yes)
+       po2debconf -e utf8 debian/templates.master > debian/templates
+endif
+       dh_gencontrol -- -V'debconf-depends=debconf (>= $(MINDEBCONFVER)) | debconf-2.0'
+       dh_md5sums
+       dh_builddeb
+
+binary: binary-indep binary-arch
+.PHONY: build clean binary-indep binary-arch binary install configure test
diff --git a/_darcs/current/debian/templates.master b/_darcs/current/debian/templates.master
new file mode 100644 (file)
index 0000000..e3c5229
--- /dev/null
@@ -0,0 +1,8 @@
+Template: ifupdown/convert-interfaces
+Type: boolean
+Default: true
+_Description: Update /etc/network/interfaces?
+ The format of /etc/network/interfaces has had a minor but incompatible
+ change made between version 0.5.x and 0.6.x of ifupdown. It is however
+ possible to automatically convert from the old format to the new in almost
+ all cases.
diff --git a/_darcs/current/debian/testbuild b/_darcs/current/debian/testbuild
new file mode 100644 (file)
index 0000000..bc7f4e5
--- /dev/null
@@ -0,0 +1,175 @@
+#!/bin/sh -e
+
+rm -rf tests/
+mkdir tests
+
+cat >tests/testcase.1 <<EOF
+# RUN: -a
+auto eth0
+iface eth0 inet static
+  address 1.2.3.4
+  netmask 255.255.255.0
+  up echo hi
+  post-up echo hello
+EOF
+cat >tests/up.1 <<EOF
+====stdout====
+====stderr====
+Configuring interface eth0=eth0 (inet)
+run-parts --verbose /etc/network/if-pre-up.d
+
+ifconfig eth0 1.2.3.4 netmask 255.255.255.0     up
+
+echo hi
+echo hello
+run-parts --verbose /etc/network/if-up.d
+EOF
+
+cat >tests/testcase.2 <<EOF
+# RUN: -a
+auto eth0 eth1 eth2
+auto eth3 eth4 eth5
+allow-hotplug eth6
+iface eth0 inet static
+  address 1.2.3.4
+  netmask 255.255.255.0
+iface eth1 inet static
+  address 1.3.4.5
+  netmask 255.255.255.0
+iface eth2 inet static
+  address 1.4.5.6
+  netmask 255.255.255.0
+iface eth3 inet static
+  address 1.5.6.7
+  netmask 255.255.255.0
+iface eth4 inet static
+  address 1.7.8.9
+  netmask 255.255.255.0
+iface eth5 inet static
+  address 1.8.9.10
+  netmask 255.255.255.0
+iface eth6 inet static
+  address 1.11.12.13
+  netmask 255.255.255.0
+iface eth7 inet static
+  address 1.14.15.16
+  netmask 255.255.255.0
+EOF
+cat >tests/up.2 <<EOF
+====stdout====
+====stderr====
+Configuring interface eth0=eth0 (inet)
+run-parts --verbose /etc/network/if-pre-up.d
+
+ifconfig eth0 1.2.3.4 netmask 255.255.255.0     up
+
+run-parts --verbose /etc/network/if-up.d
+Configuring interface eth1=eth1 (inet)
+run-parts --verbose /etc/network/if-pre-up.d
+
+ifconfig eth1 1.3.4.5 netmask 255.255.255.0     up
+
+run-parts --verbose /etc/network/if-up.d
+Configuring interface eth2=eth2 (inet)
+run-parts --verbose /etc/network/if-pre-up.d
+
+ifconfig eth2 1.4.5.6 netmask 255.255.255.0     up
+
+run-parts --verbose /etc/network/if-up.d
+Configuring interface eth3=eth3 (inet)
+run-parts --verbose /etc/network/if-pre-up.d
+
+ifconfig eth3 1.5.6.7 netmask 255.255.255.0     up
+
+run-parts --verbose /etc/network/if-up.d
+Configuring interface eth4=eth4 (inet)
+run-parts --verbose /etc/network/if-pre-up.d
+
+ifconfig eth4 1.7.8.9 netmask 255.255.255.0     up
+
+run-parts --verbose /etc/network/if-up.d
+Configuring interface eth5=eth5 (inet)
+run-parts --verbose /etc/network/if-pre-up.d
+
+ifconfig eth5 1.8.9.10 netmask 255.255.255.0    up
+
+run-parts --verbose /etc/network/if-up.d
+EOF
+cat >tests/testcase.3 <<EOF
+# RUN: -a
+auto eth0
+iface eth0 inet static
+  address 1.2.3.4
+  netmask 255.255.255.0
+iface eth0 inet6 static
+  address 3ffe:ffff:100:f101::1
+  netmask 64
+EOF
+cat >tests/up.3 <<EOF
+====stdout====
+====stderr====
+Configuring interface eth0=eth0 (inet)
+run-parts --verbose /etc/network/if-pre-up.d
+
+ifconfig eth0 1.2.3.4 netmask 255.255.255.0             up
+
+run-parts --verbose /etc/network/if-up.d
+Configuring interface eth0=eth0 (inet6)
+run-parts --verbose /etc/network/if-pre-up.d
+ifconfig eth0    up
+ifconfig eth0 add 3ffe:ffff:100:f101::1/64
+
+run-parts --verbose /etc/network/if-up.d
+EOF
+
+cat >tests/testcase.4 <<EOF
+# RUN: eth0=work
+mapping eth0
+  script tests/map.eth0.work
+iface work inet static
+  address 1.2.3.4
+  netmask 255.255.255.0
+  up echo hi
+  post-up echo hello
+EOF
+cat >tests/up.4 <<EOF
+====stdout====
+====stderr====
+Configuring interface eth0=work (inet)
+run-parts --verbose /etc/network/if-pre-up.d
+
+ifconfig eth0 1.2.3.4 netmask 255.255.255.0     up
+
+echo hi
+echo hello
+run-parts --verbose /etc/network/if-up.d
+EOF
+
+
+result=true
+for test in 1 2 3 4; do
+       args="$(cat tests/testcase.$test | sed -n 's/^# RUN: //p')"
+       ./ifup -nv --force -i tests/testcase.$test $args \
+               >tests/up-res-out.$test 2>tests/up-res-err.$test || 
+               true
+       (echo "====stdout===="; cat tests/up-res-out.$test
+        echo "====stderr===="; cat tests/up-res-err.$test) > tests/up-res.$test
+
+       echo "Testcase $test: $args"
+       
+       if diff -ub tests/up.$test tests/up-res.$test; then
+               echo "(okay)"
+       else
+               echo "(failed)"
+               result=false
+       fi
+       echo "=========="
+done
+
+if $result; then
+       echo "(okay overall)"
+       exit 0
+else
+       echo "(failed overall)"
+       exit 1
+fi
diff --git a/_darcs/current/debian/upgrade-from-0.5.x.pl b/_darcs/current/debian/upgrade-from-0.5.x.pl
new file mode 100644 (file)
index 0000000..2734d28
--- /dev/null
@@ -0,0 +1,65 @@
+#!/usr/bin/perl -w
+
+use strict;
+
+my %doneifaces = ();
+my @orig = ();   # original interfaces file
+my $line;
+
+while($line = <STDIN>) {
+       if ($line =~ m/^\s*#/) {
+               push @orig, $line;
+               next;
+       }
+
+       my $tmp;
+       while ($line =~ m/\\\n$/ and $tmp = <>) {
+               $line .= $tmp;
+       }
+       push @orig, $line;
+}
+
+my $out = "";
+my $block = "";
+my $auto = "";
+for my $x (@orig) {
+       my $y = $x;
+       $y =~ s/^\s*//s;
+       $y =~ s/\\\n//sg;
+       $y =~ s/\s*$//s;
+
+       if ($y =~ m/^scheme\b/) {
+               print STDERR "Schemes cannot be automatically converted\n";
+               exit(1);
+       }
+       if ($y =~ m/^auto\b/) {
+               print STDERR "File seems to already be converted\n";
+               exit(1);
+       }
+
+       if ($y =~ m/^iface\b/s) {
+               $out .= $auto . $block;
+               $block = $x;
+               if ($y =~ m/^iface\s+(\S+)/s && ! $doneifaces{$1}++ ) {
+                       $auto = "# automatically added when upgrading\n";
+                       $auto .= "auto $1\n";
+               } else {
+                       $auto = "";
+               }
+               next;
+       }
+
+       if ($y =~ m/^noauto/) {
+               $auto = "";
+               my $spaces = $x;
+               $spaces =~ s/\S.*$//s;
+               $block .= $spaces . "# noauto (removed on upgrade)\n";
+               next;
+       }
+
+       $block .= $x;
+}
+
+$out .= $auto . $block;
+
+print $out;
diff --git a/_darcs/current/examples/bridge b/_darcs/current/examples/bridge
new file mode 100644 (file)
index 0000000..97fe3f5
--- /dev/null
@@ -0,0 +1,69 @@
+#!/bin/sh 
+# The following script example, if dropped in /etc/network/if-pre-up.d/
+# and under /etc/network/if-down.d/, will manage to configure a bridge 
+# if defined in the /etc/network/interfaces file as either:
+#
+# Note: The bridge-utils package already provide a similar (more
+# powerful) script this is just provided here for convenience and to
+# show how the /etc/network/if-*.d/ methods can be defined.
+# 
+# [ a bridge with an associated IP address ]
+#  iface br0 inet static
+#       bridge-ifaces eth0 eth1
+#       address 192.168.1.1
+#       netmask 255.255.255.0
+# [ a bridge which acts as an anonymous bridge ]
+#  iface br0 inet manual
+#       bridge-ifaces eth0 eth1
+#       up ifconfig $IFACE up
+#
+# For more information read:
+#  http://bridge.sourceforge.net/howto.html
+
+brctl=`which brctl`
+
+# Notice that the bridge-utils package must be installed and 
+# we need to have the BRIDGE_IFACES in order to work
+[ "$IF_BRIDGE_IFACES" = "" ] && exit 0
+if [ -z "$brctl" ] ; then
+       # ? Somebody is trying to use us without having bridge-utils?
+       echo "Cannot find the 'brctl' program to setup the bridge"
+       echo "Hint: Have you installed the bridge-utils package?"
+       exit 1
+fi 
+
+# Check all interfaces before proceeding
+for i in $IF_BRIDGE_IFACES; do
+       ip link show $i >/dev/null 2>&1
+       if [ $? -ne 0 ] ; then
+               echo "Interface $i is not available, aborting"
+               exit 1
+       fi
+done
+
+if [ "$MODE" = "start" ] ; then
+       # We are being called by ifup:
+       # Bring up all the bridge interfaces
+       for i in $IF_BRIDGE_IFACES; do
+               ifconfig $i 0.0.0.0 up
+       done
+       # And now add the bridge itself and the interfaces which are part
+       # of the bridge
+       brctl addbr $IFACE
+       for i in $IF_BRIDGE_IFACES; do
+               brctl addif $IFACE $i
+       done
+elif [ "$MODE" = "stop" ];  then
+       # We are being called by ifdown:
+       # Remove the bridge itself and the bridge association
+       for i in $IF_BRIDGE_IFACES; do
+               brctl delif $IFACE $i
+       done
+       brctl delbr $IFACE
+       # Bring down all the bridge interfaces
+       for i in $IF_BRIDGE_IFACES; do
+               ifconfig $i down
+       done
+fi
+
+exit 0
diff --git a/_darcs/current/examples/check-mac-address.sh b/_darcs/current/examples/check-mac-address.sh
new file mode 100644 (file)
index 0000000..f5eaa92
--- /dev/null
@@ -0,0 +1,19 @@
+#!/bin/sh
+#
+# Checks if the given interface matches the given ethernet MAC.
+# If it does it exits with 0 (success) status;
+# if it doesn't then it exists with 1 (error) status.
+
+set -e
+
+export LANG=C
+
+if [ ! "$2" ] ; then
+       echo "Usage: $0 IFACE targetMAC"
+       exit 1
+fi
+iface="$1"
+targetmac=`echo "$2" | sed -e 'y/ABCDEF/abcdef/'`
+mac=$(/sbin/ifconfig "$iface" | sed -n -e '/^.*HWaddr \([:[:xdigit:]]*\).*/{s//\1/;y/ABCDEF/abcdef/;p;q;}')
+
+if [ "$targetmac" = "$mac" ]; then exit 0; else exit 1; fi
diff --git a/_darcs/current/examples/generate-interfaces.pl b/_darcs/current/examples/generate-interfaces.pl
new file mode 100644 (file)
index 0000000..b2d41d9
--- /dev/null
@@ -0,0 +1,133 @@
+#!/usr/bin/perl -w
+# Generate an /etc/network/interfaces script based on the
+# current interface and network status.
+# Useful to migrate the configuration of old Debian versions (i.e. pre-woody)
+# or non-Debian systems to the ifup/down scheme used in Debian.
+#
+# (c) 2000 Anthony Towns 
+# slight improvements (route parsing and direct command
+# execution) done by Javier Fernandez-Sanguino 
+# 
+# TODO:
+# [aj] It'd be good if it also grabbed the default gateway from route,
+# and worked out the network based on the netmask and the address
+# (the network is needed for ifup under 2.0.x kernels).
+#
+# [jfs] Some (optional) information is not parsed, like: route metrics
+# and hw addresses of interfaces
+
+
+use strict;
+
+my %iface = ();  # name -> iface info hash
+my $ciface;  # current iface name
+
+# First, read interfaces from ifconfig
+#
+open (IFC,"ifconfig -a | ") || die ("Could not execute ifconfig: $!\n");
+
+while(my $line = <IFC>) {
+    chomp $line;
+    if ($line =~ m/^(\S+)\s+(\S.*)$/) {
+        $ciface = $1;
+       $iface{$ciface} = { };
+        $line = $2;
+    } elsif ($line =~ m/^\s+(\S.*)$/) {
+        $line = $1;
+    } else {
+        $ciface = undef;
+        next;
+    }
+    next unless(defined $ciface);
+
+    if ($line =~ s/Link encap:(.*)$//) {
+        $iface{$ciface}->{"type"} = $1;
+    }
+    if ($line =~ s/^inet //) {
+        $iface{$ciface}->{"ipv4"} = "yes";
+        if ($line =~ s/addr:(\S*)//) {
+            $iface{$ciface}->{"ipv4_addr"} = $1;
+        }
+        if ($line =~ s/Bcast:(\S*)//) {
+            $iface{$ciface}->{"ipv4_bcast"} = $1;
+        }
+        if ($line =~ s/Mask:(\S*)//) {
+            $iface{$ciface}->{"ipv4_mask"} = $1;
+        }
+    }
+}
+
+close IFC;
+
+# Now, read route information from netstat
+#
+open (ROU,"route -n | ") || die ("Could not execute route: $!\n");
+while(my $line = <ROU>) {
+    chomp $line;
+    if ( $line =~ m/^([\d\.]+)\s+([\d\.]+)\s+([\d\.]+)\s+(\S+)\s+(\d+).*?\s+(\S+)$/) {
+       my $dest = $1; my $gw = $2; my $mask = $3; my $flags = $4;
+       my $metric = $5; my $if = $6;
+       if ( defined ( $iface{$if} ) ) {
+               if ( $dest eq "0.0.0.0" && $mask eq "0.0.0.0" ) {
+               # Default gateway
+                       $iface{$if}->{"gateway"} = $gw;
+               } elsif ( $gw ne "0.0.0.0" )  {
+               # Specific (static) route
+                       push @{$iface{$if}->{"up"}} , "route add -net $dest netmask $mask gw $gw dev $if";
+                       push @{$iface{$if}->{"down"}} , "route del -net $dest netmask $mask gw $gw dev $if";
+               }
+       }
+    }
+
+}
+
+close ROU;
+
+foreach my $if (keys %iface) {
+    if ($iface{$if}->{"type"} =~ m/loopback/i) {
+        if ($iface{$if}->{"ipv4"} eq "yes") {
+            print "iface $if inet loopback\n";
+        }
+    }
+
+    if ($iface{$if}->{"type"} =~ m/ethernet/i) {
+        if ($iface{$if}->{"ipv4"} eq "yes") {
+            print "iface $if inet static\n";
+            if (defined $iface{$if}->{"ipv4_addr"}) {
+                print "    address " . $iface{$if}->{"ipv4_addr"} . "\n";
+            }
+            if (defined $iface{$if}->{"ipv4_mask"}) {
+                print "    netmask " . $iface{$if}->{"ipv4_mask"} . "\n";
+            }
+            if (defined $iface{$if}->{"ipv4_addr"}) {
+                print "    broadcast " . $iface{$if}->{"ipv4_bcast"} . "\n";
+            }
+            if (defined $iface{$if}->{"gateway"}) {
+                print "    gateway " . $iface{$if}->{"gateway"} . "\n";
+            }
+            if (defined $iface{$if}->{"pre-up"}) {
+               while ( my $upcmd = pop @{$iface{$if}->{"pre-up"}} ) {
+                       print "    pre-up " . $upcmd . "\n";
+               }
+            }
+            if (defined $iface{$if}->{"up"}) {
+               while ( my $upcmd = pop @{$iface{$if}->{"up"}} ) {
+                       print "    up " . $upcmd . "\n";
+               }
+            }
+            if (defined $iface{$if}->{"down"}) {
+               while ( my $downcmd = pop @{$iface{$if}->{"down"}} ) {
+                       print "    down " . $downcmd . "\n";
+               }
+            }
+            if (defined $iface{$if}->{"post-down"}) {
+               while ( my $downcmd = pop @{$iface{$if}->{"pre-down"}} ) {
+                       print "    pre-down " . $downcmd . "\n";
+               }
+            }
+        }
+    }
+    print "\n";
+}
+
+exit 0;
diff --git a/_darcs/current/examples/get-mac-address.sh b/_darcs/current/examples/get-mac-address.sh
new file mode 100644 (file)
index 0000000..6f73d5a
--- /dev/null
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+set -e
+
+export LANG=C
+
+iface="$1"
+mac=$(/sbin/ifconfig "$iface" | sed -n -e '/^.*HWaddr \([:[:xdigit:]]*\).*/{s//\1/;y/ABCDEF/abcdef/;p;q;}')
+which=""
+
+while read testmac scheme; do
+       if [ "$which" ]; then continue; fi
+       if [ "$mac" = "$(echo "$testmac" | sed -e 'y/ABCDEF/abcdef/')" ]; then which="$scheme"; fi
+done
+
+if [ "$which" ]; then echo $which; exit 0; fi
+exit 1
diff --git a/_darcs/current/examples/network-interfaces b/_darcs/current/examples/network-interfaces
new file mode 100644 (file)
index 0000000..50a7eb3
--- /dev/null
@@ -0,0 +1,193 @@
+######################################################################
+# /etc/network/interfaces -- configuration file for ifup(8), ifdown(8)
+#
+# A "#" character in the very first column makes the rest of the line
+# be ignored. Blank lines are ignored. Lines may be indented freely.
+# A "\" character at the very end of the line indicates the next line
+# should be treated as a continuation of the current one.
+#
+# The "pre-up", "up", "down" and "post-down" options are valid for all 
+# interfaces, and may be specified multiple times. All other options
+# may only be specified once.
+#
+# See the interfaces(5) manpage for information on what options are 
+# available.
+######################################################################
+
+# We always want the loopback interface.
+#
+# auto lo
+# iface lo inet loopback
+
+# An example ethernet card setup: (broadcast and gateway are optional)
+#
+# auto eth0
+# iface eth0 inet static
+#     address 192.168.0.42
+#     network 192.168.0.0
+#     netmask 255.255.255.0
+#     broadcast 192.168.0.255
+#     gateway 192.168.0.1
+
+# A more complicated ethernet setup, with a less common netmask, and a downright
+# weird broadcast address: (the "up" lines are executed verbatim when the 
+# interface is brought up, the "down" lines when it's brought down)
+#
+# auto eth0
+# iface eth0 inet static
+#     address 192.168.1.42
+#     network 192.168.1.0
+#     netmask 255.255.255.128
+#     broadcast 192.168.1.0
+#     up route add -net 192.168.1.128 netmask 255.255.255.128 gw 192.168.1.2
+#     up route add default gw 192.168.1.200
+#     down route del default gw 192.168.1.200
+#     down route del -net 192.168.1.128 netmask 255.255.255.128 gw 192.168.1.2
+
+# A more complicated ethernet setup with a single ethernet card with
+# two interfaces.
+# Note: This happens to work since ifconfig handles it that way, not because
+# ifup/down handles the ':' any differently.
+# Warning: There is a known bug if you do this, since the state will not
+# be properly defined if you try to 'ifdown eth0' when both interfaces
+# are up. The ifconfig program will not remove eth0 but it will be
+# removed from the interfaces state so you will see it up until you execute:
+# 'ifdown eth0:1 ; ifup eth0; ifdown eth0'
+# BTW, this is "bug" #193679 (it's not really a bug, it's more of a 
+# limitation)
+#
+# auto eth0 eth0:1
+# iface eth0 inet static
+#     address 192.168.0.100
+#     network 192.168.0.0
+#     netmask 255.255.255.0
+#     broadcast 192.168.0.255
+#     gateway 192.168.0.1
+# iface eth0:1 inet static
+#     address 192.168.0.200
+#     network 192.168.0.0
+#     netmask 255.255.255.0
+
+# "pre-up" and "post-down" commands are also available. In addition, the
+# exit status of these commands are checked, and if any fail, configuration
+# (or deconfiguration) is aborted. So:
+#
+# auto eth0
+# iface eth0 inet dhcp
+#     pre-up [ -f /etc/network/local-network-ok ]
+#
+# will allow you to only have eth0 brought up when the file 
+# /etc/network/local-network-ok exists.
+
+# Two ethernet interfaces, one connected to a trusted LAN, the other to
+# the untrusted Internet. If their MAC addresses get swapped (because an
+# updated kernel uses a different order when probing for network cards,
+# say), then they don't get brought up at all.
+#
+# auto eth0 eth1
+# iface eth0 inet static
+#     address 192.168.42.1
+#     netmask 255.255.255.0
+#     pre-up /path/to/check-mac-address.sh eth0 11:22:33:44:55:66
+#     pre-up /usr/local/sbin/enable-masq
+# iface eth1 inet dhcp
+#     pre-up /path/to/check-mac-address.sh eth1 AA:BB:CC:DD:EE:FF
+#     pre-up /usr/local/sbin/firewall
+
+# Two ethernet interfaces, one connected to a trusted LAN, the other to
+# the untrusted Internet, identified by MAC address rather than interface
+# name:
+#
+# auto eth0 eth1
+# mapping eth0 eth1
+#     script /path/to/get-mac-address.sh
+#     map 11:22:33:44:55:66 lan
+#     map AA:BB:CC:DD:EE:FF internet
+# iface lan inet static
+#     address 192.168.42.1
+#     netmask 255.255.255.0
+#     pre-up /usr/local/sbin/enable-masq $IFACE
+# iface internet inet dhcp
+#     pre-up /usr/local/sbin/firewall $IFACE
+
+# A PCMCIA interface for a laptop that is used in different locations:
+# (note the lack of an "auto" line for any of these)
+#
+# mapping eth0
+#    script /path/to/pcmcia-compat.sh
+#    map home,*,*,*                  home
+#    map work,*,*,00:11:22:33:44:55  work-wireless
+#    map work,*,*,01:12:23:34:45:50  work-static
+#
+# iface home inet dhcp
+# iface work-wireless bootp
+# iface work-static static
+#     address 10.15.43.23
+#     netmask 255.255.255.0
+#     gateway 10.15.43.1
+#
+# Note, this won't work unless you specifically change the file
+# /etc/pcmcia/network to look more like:
+#
+#     if [ -r ./shared ] ; then . ./shared ; else . /etc/pcmcia/shared ; fi
+#     get_info $DEVICE
+#     case "$ACTION" in
+#         'start')
+#             /sbin/ifup $DEVICE
+#             ;;
+#         'stop')
+#             /sbin/ifdown $DEVICE
+#             ;;
+#     esac
+#     exit 0
+
+# An alternate way of doing the same thing: (in this case identifying
+# where the laptop is is done by configuring the interface as various
+# options, and seeing if a computer that is known to be on each particular
+# network will respond to pings. The various numbers here need to be chosen
+# with a great deal of care.)
+#
+# mapping eth0
+#    script /path/to/ping-places.sh
+#    map 192.168.42.254/24 192.168.42.1 home
+#    map 10.15.43.254/24 10.15.43.1 work-wireless
+#    map 10.15.43.23/24 10.15.43.1 work-static
+#
+# iface home inet dhcp
+# iface work-wireless bootp
+# iface work-static static
+#     address 10.15.43.23
+#     netmask 255.255.255.0
+#     gateway 10.15.43.1
+#
+# Note that the ping-places script requires the iproute package installed,
+# and the same changes to /etc/pcmcia/network are required for this as for
+# the previous example.
+
+
+# Set up an interface to read all the traffic on the network. This 
+# configuration can be useful to setup Network Intrusion Detection
+# sensors in 'stealth'-type configuration. This prevents the NIDS
+# system to be a direct target in a hostile network since they have
+# no IP address on the network. Notice, however, that there have been
+# known bugs over time in sensors part of NIDS (for example see 
+# DSA-297 related to Snort) and remote buffer overflows might even be
+# triggered by network packet processing.
+# 
+# auto eth0
+# iface eth0 inet manual
+#      up ifconfig $IFACE 0.0.0.0 up
+#       up ip link set $IFACE promisc on
+#       down ip link set $IFACE promisc off
+#       down ifconfig $IFACE down
+
+# Set up an interface which will not be allocated an IP address by
+# ifupdown but will be configured through external programs. This
+# can be useful to setup interfaces configured through other programs,
+# like, for example, PPPOE scripts.
+#
+# auto eth0
+# iface eth0 inet manual
+#       up ifconfig $IFACE 0.0.0.0 up
+#       up /usr/local/bin/myconfigscript
+#       down ifconfig $IFACE down
diff --git a/_darcs/current/examples/pcmcia-compat.sh b/_darcs/current/examples/pcmcia-compat.sh
new file mode 100644 (file)
index 0000000..4b31fdb
--- /dev/null
@@ -0,0 +1,29 @@
+#!/bin/sh
+
+if [ ! -e /etc/pcmcia/shared ]; then exit 1; fi
+
+pcmcia_shared () {
+       . /etc/pcmcia/shared
+}
+
+iface="$1"
+
+# /etc/pcmcia/shared sucks
+pcmcia_shared "start" $iface
+usage () {
+       exit 1
+}
+
+get_info $iface
+HWADDR=`/sbin/ifconfig $DEVICE | sed -n -e 's/.*addr \([^ ]*\) */\1/p'`
+
+which=""
+while read glob scheme; do
+       if [ "$which" ]; then continue; fi
+       case "$SCHEME,$SOCKET,$INSTANCE,$HWADDR" in
+               $glob) which=$scheme ;;
+       esac
+done
+
+if [ "$which" ]; then echo $which; exit 0; fi
+exit 1
diff --git a/_darcs/current/examples/ping-places.sh b/_darcs/current/examples/ping-places.sh
new file mode 100644 (file)
index 0000000..6f6f2e1
--- /dev/null
@@ -0,0 +1,30 @@
+#!/bin/sh
+
+if [ `id -u` -ne 0 ] || [ "$1" = "" ]; then exit 1; fi
+
+if [ -x /usr/bin/fping ]; then
+       PING="/usr/bin/fping"
+else
+       PING="/bin/ping -c 2"
+fi
+
+iface="$1"
+which=""
+
+while read addr pingme scheme; do
+       if [ "$which" ]; then continue; fi
+
+       #echo "  Trying $addr & $pingme ($scheme)" >&2
+
+       ip addr add $addr dev $iface  >/dev/null 2>&1
+       ip link set $iface up         >/dev/null 2>&1
+
+       if $PING $pingme >/dev/null 2>&1; then
+               which="$scheme" 
+       fi
+       ip link set $iface down       >/dev/null 2>&1
+       ip addr del $addr dev $iface  >/dev/null 2>&1
+done
+
+if [ "$which" ]; then echo $which; exit 0; fi
+exit 1
diff --git a/_darcs/current/execution.dia b/_darcs/current/execution.dia
new file mode 100644 (file)
index 0000000..70cd9c3
Binary files /dev/null and b/_darcs/current/execution.dia differ
diff --git a/_darcs/current/ifup.8 b/_darcs/current/ifup.8
new file mode 100644 (file)
index 0000000..4b29edd
--- /dev/null
@@ -0,0 +1,165 @@
+.TH ifup 8 "22 May 2004" IFUPDOWN ""
+.SH NAME
+ifup \- bring a network interface up
+.PP
+ifdown \- take a network interface down
+.SH SYNOPSIS
+.B ifup 
+[\fB\-nv\fR]
+[\fB\-\-no\-act\fR]
+[\fB\-\-verbose\fR]
+[\fB\-i\fR \fIFILE\fR|\fB\-\-interfaces=\fR\fIFILE\fR]
+[\fB\-\-allow\fR \fICLASS\fR]
+\fB\-a\fR|\fIIFACE\fR...
+.br
+.B ifup 
+\fB\-h\fR|\fB\-\-help\fR
+.br
+.B ifup 
+\fB\-V\fR|\fB\-\-version\fR
+.PP
+.B ifdown
+[\fB\-nv\fR]
+[\fB\-\-no\-act\fR]
+[\fB\-\-verbose\fR]
+[\fB\-i\fR \fIFILE\fR|\fB\-\-interfaces=\fR\fIFILE\fR]
+[\fB\-\-allow\fR \fICLASS\fR]
+\fB\-a\fR|\fIIFACE\fR...
+.SH DESCRIPTION
+The
+.BR ifup " and " ifdown
+commands may be used to configure (or, respectively, deconfigure) network
+interfaces based on interface definitions in the file
+.IR /etc/network/interfaces .
+.SH OPTIONS
+A summary of options is included below.
+.TP
+.BR \-a ", " \-\-all
+If given to \fBifup\fP, affect all interfaces marked \fBauto\fP.
+Interfaces are brought up in the order in which they are defined
+in /etc/network/interfaces.
+If given to \fBifdown\fP, affect all defined interfaces.
+Interfaces are brought down in the order in which they are
+currently listed in the state file. Only interfaces defined
+in /etc/network/interfaces will be brought down.
+.TP
+.B \-\-force
+Force configuration or deconfiguration of the interface.
+.TP
+.BR \-h ", " \-\-help
+Show summary of options.
+.TP
+\fB\-\-allow=\fR\fICLASS\fR
+Only allow interfaces listed in an
+.I allow\-CLASS
+line in /etc/network/interfaces to be acted upon.
+.TP
+\fB\-i\fR \fIFILE\fR, \fB\-\-interfaces=\fR\fIFILE\fR
+Read interface definitions from 
+.I FILE
+instead of from /etc/network/interfaces.
+.TP
+.BR \-n ", " \-\-no\-act
+Don't configure any interfaces or run any "up" or "down" commands.
+.TP
+.B \-\-no\-mappings
+Don't run any mappings.  See
+.BR interfaces (5)
+for more information about the mapping feature.
+.TP
+.BR \-V ", " \-\-version
+Show copyright and version information.
+.TP
+.BR \-v ", " \-\-verbose
+Show commands as they are executed.
+.SH EXAMPLES
+.TP
+.B ifup -a
+Bring up all the interfaces defined with
+.I auto
+in 
+.I /etc/network/interfaces
+.TP
+.B ifup eth0
+Bring up interface
+.B eth0
+.TP
+.B ifup eth0=home
+Bring up interface
+.B eth0
+as logical interface
+.B home
+.TP
+.B ifdown -a
+Bring down all interfaces that are currently up.
+.SH NOTES
+.BR ifup " and " ifdown
+are actually the same program called by different names.
+.P
+The program does not configure network interfaces directly;
+it runs low level utilities such as
+.BR ifconfig " and " route
+to do its dirty work.
+.SH FILES
+.TP
+.I /etc/network/interfaces
+definitions of network interfaces
+See
+.BR interfaces (5)
+for more information.
+.TP
+.I /etc/network/run/ifstate
+current state of network interfaces
+.SH KNOWN BUGS/LIMITATIONS
+The program keeps records of whether network interfaces are up or down.
+Under exceptional circumstances these records can become
+inconsistent with the real states of the interfaces.
+For example, an interface that was brought up using
+.B ifup
+and later deconfigured using
+.B ifconfig
+will still be recorded as up.
+To fix this you can use the
+.B \-\-force
+option to force
+.B ifup
+or
+.B ifdown
+to run configuration or deconfiguration commands despite what
+it considers the current state of the interface to be.
+.P
+The file
+.I /etc/network/run/ifstate
+must be writable for
+.B ifup
+or
+.B ifdown
+to work properly.
+If that location is not writable
+(for example, because the root filesystem is mounted read-only
+for system recovery)
+then
+.I /etc/network/run/ifstate
+should be made a symbolic link to a writable location.
+If that is not possible then you can use the
+.B \-\-force
+option to run configuration or deconfiguration commands
+without updating the file.
+.P
+Note that the program does not run automatically:
+.B ifup
+alone does not bring up interfaces
+that appear as a result of hardware being installed and 
+.B ifdown
+alone does not bring down interfaces
+that disappear as a result of hardware being removed.
+To automate the configuration of network interfaces you need to
+install other packages such as
+.BR hotplug (8)
+or
+.BR ifplugd (8).
+.SH AUTHOR
+The ifupdown suite was written by Anthony Towns <aj@azure.humbug.org.au>.
+.SH SEE ALSO
+.BR interfaces (5),
+.BR ifconfig (8).
diff --git a/_darcs/current/ifupdown.nw b/_darcs/current/ifupdown.nw
new file mode 100644 (file)
index 0000000..e0f774e
--- /dev/null
@@ -0,0 +1,4121 @@
+%
+\documentclass{article}
+\usepackage{graphicx}
+\usepackage{noweb}
+\pagestyle{noweb}
+\noweboptions{smallcode,hideunuseddefs}
+\begin{document}
+@
+
+\def\nwendcode{\endtrivlist\endgroup}
+\let\nwdocspar=\relax
+
+\title{ Interface Tools\thanks{
+Copyright \copyright\ 1999--2005 Anthony Towns. 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; either version 2 of the License, or (at your option) any
+later version.  
+}}
+
+\author{ Anthony Towns \\ { \tt aj@azure.humbug.org.au } }
+
+\pagenumbering{roman}
+
+\maketitle
+\tableofcontents
+
+\vfill
+\pagebreak
+\pagenumbering{arabic}
+
+\section{Introduction}
+
+This source defines the commands [[ifup]] and [[ifdown]], used to
+manipulate interfaces in an easily controllable manner.
+
+\subsection{Assumed Knowledge}
+
+The reader is assumed to have knowledge of the C \cite{K&R} and Perl
+\cite{camel} programming languages in a Unix environment \cite{StevensUnix}.
+A cursory understanding of network administration on the appropriate
+platform is also assumed, along with access to the relevant manual
+pages as necessary.
+
+This source has been written as a literate program using the [[noweb]]
+\cite{wwwnoweb} tool suite, and typeset using \LaTeX\ \cite{latex}.
+
+\subsection{Program Structure}
+
+We shall decompose this program into four main areas of functionality:
+compile-time configuration, run-time configuration, execution, and the
+overall driver.
+
+Compile-time configuration will deal with differing available address
+families (IP vs IPX vs IPv6, and so on), and the differing methods of
+enabling and disabling interfaces configured for each family. This will
+be implemented using the [[addrfam]] module, and various [[.defn]] files,
+for the address family definitions.
+
+Run-time configuration will deal with determining the local setup
+based on the file [[/etc/network/interfaces]], and producing a data
+structure encapsulating these details. This will be implemented in the
+[[config]] module.
+
+Execution will deal with issues relating to working out exactly which
+commands to run based on a somewhat abstract description from the
+compile-time configuration and the details determined at
+run-time. This will be dealt with in the [[execute]] module.
+
+The remaining work --- argument parsing, error reporting, and,
+essentially, putting all the pieces together --- is done by the
+[[main]] module.
+
+The following diagram gives a brief idea of the information and control
+flow amongst the modules.
+
+\begin{center}
+\includegraphics[height=45mm]{modules}
+\end{center}
+
+Much of the information sharing will be done by defining and filling
+in some data structures and allowing the other modules to just access
+that information directly. Rather than hiding the information itself,
+most of our modules simply attempt to hide how that information was
+originally written. Because of this, we shall find that these modules are
+too closely linked to be completely separated in a convenient manner,
+so they will all make use of a single header file for each other's
+structure definitions, exported interfaces and so on.
+
+<<header.h>>=
+#ifndef HEADER_H
+#define HEADER_H
+
+<<type definitions>>
+<<function type definitions>>
+<<structure definitions>>
+<<constant definitions>>
+<<exported symbols>>
+
+#endif /* HEADER_H */
+@ 
+
+\section{The Build System}
+
+We shall begin with the template for the Makefile we shall use.
+
+<<Makefile>>=
+<<make options>>
+
+CFILES := addrfam.c execute.c config.c main.c archlinux.c
+HFILES := header.h archlinux.h
+PERLFILES := defn2c.pl defn2man.pl
+DEFNFILES := inet.defn ipx.defn inet6.defn
+
+OBJ := main.o addrfam.o execute.o config.o \
+       $(patsubst %.defn,%.o,$(DEFNFILES)) archlinux.o
+
+MAN := $(patsubst %.defn,%.man,$(DEFNFILES))
+
+default : executables
+all : executables docs
+
+executables : ifup ifdown ifup.8 ifdown.8 interfaces.5
+docs : ifupdown.ps.gz ifup.8.ps.gz interfaces.5.ps.gz ifupdown.pdf
+
+.PHONY : executables 
+<<phony targets>>
+<<executable targets>>
+<<manpage targets>>
+<<extra dependencies>>
+<<implicit rules>>
+
+<<generated dependency inclusion>>
+@ 
+
+We shall build exactly two executables, [[ifup]] and [[ifdown]], which
+will in truth simply be two names for a single binary, albeit with
+different functionality.
+
+<<executable targets>>=
+ifup: $(OBJ)
+       $(CC) $(CFLAGS) $^ $(LDFLAGS) $(OUTPUT_OPTION)
+
+ifdown: ifup
+       ln -sf ifup ifdown
+@ 
+
+Both of these executables have a manpage. Since they're actually the
+same executable, what could be more appropriate than them having the
+same manpage too?
+
+<<manpage targets>>=
+interfaces.5: interfaces.5.pre $(MAN)
+       sed $(foreach man,$(MAN),-e '/^##ADDRESSFAM##$$/r $(man)') \
+            -e '/^##ADDRESSFAM##$$/d' < $< > $@        
+
+ifdown.8: ifup.8
+       ln -sf $< $@
+
+%.5.ps: %.5
+       groff -mandoc -Tps $< > $@
+%.8.ps: %.8
+       groff -mandoc -Tps $< > $@
+@ 
+
+Further, for convenience, we'll make use of two phony targets, [[clean]],
+[[clobber]] and [[distclean]], which will delete working files, everything
+that can be rebuilt with a [[make]] command, and everything that can be
+rebuilt at all, respectively.
+
+<<phony targets>>=
+.PHONY : clean clobber
+
+install :
+       install -m 0755 -d     ${BASEDIR}/sbin
+       install -m 0755 ifup   ${BASEDIR}/sbin
+       ln ${BASEDIR}/sbin/ifup ${BASEDIR}/sbin/ifdown  
+
+clean :
+       rm -f *.aux *.toc *.log *.bbl *.blg *.ps *.eps *.pdf
+       rm -f *.o *.d $(patsubst %.defn,%.c,$(DEFNFILES)) *~
+       rm -f $(patsubst %.defn,%.man,$(DEFNFILES))
+       rm -f ifup ifdown interfaces.5 ifdown.8
+       rm -f ifupdown.dvi *.ps{,.gz}
+
+clobber : clean
+       rm -f ifupdown.tex $(PERLFILES) $(CFILES) $(HFILES) $(DEFNFILES)
+
+distclean : clobber
+       rm -f makecdep.sh makenwdep.sh Makefile
+@ 
+
+We have some fairly standard rules to build the printed version of the
+source code using \LaTeX\ that are, unfortunately, not included in
+[[make(1)]]'s builtin rules, so we'll note them here.
+
+<<implicit rules>>=
+%.tex : %.nw
+       noweave -delay -index -latex $< >$@
+
+%.bbl : %.tex biblio.bib
+       latex $<
+       bibtex $(basename $<)
+
+%.dvi : %.tex %.bbl
+       latex $<
+       latex $<
+
+%.pdf : %.tex %.bbl
+       pdflatex $<
+       pdflatex $<
+
+%.ps : %.dvi
+       dvips -o $@ $<
+
+%.gz : %
+       gzip --best --stdout $< >$@
+@ 
+
+Additionally, some of [[make]]'s builtin rules are fairly
+conservative, so we'll encourage it to use a more entertaining method
+of compiling source code.
+
+<<make options>>=
+CFLAGS := -Wall -W -g -O2 -D'IFUPDOWN_VERSION="0.6.5"'
+CC := gcc
+@ 
+
+\subsection{Graphics}
+
+We include a few graphics (made using dia) in this document. We have to
+express these fairly explicitly, unfortunately.
+
+<<implicit rules>>=
+%.eps : %.dia
+       dia --nosplash -e $@ $<
+
+%.pdf : %.eps
+       gs -q -sDEVICE=pdfwrite -dNOPAUSE -sOutputFile=$@ - < $<
+@
+
+<<extra dependencies>>=
+ifupdown.dvi: modules.eps execution.eps
+ifupdown.ps: modules.eps execution.eps
+ifupdown.pdf: modules.pdf execution.pdf
+@
+
+\subsection{Automatic Dependencies}
+
+To build the system, we'll make use of some techniques discussed in
+\cite{recursivemake} for determining dependencies. Namely, a number
+of files will have an associated [[.d]] file containing dynamically
+determined dependency information. The first such file we will construct
+is the dependency information for [[noweb]] source files, which can be
+identified by the [[.nw]] extension.
+
+<<implicit rules>>=
+%.d: %.nw makenwdep.sh
+       ./makenwdep.sh $< > $@
+@
+
+To construct the dependency information, we may use the [[noroots(1)]]
+command to determine the \emph{root chunks} in the [[noweb]] source
+(stripping the unwanted [[<<]] and [[>>]] markers as we go, and
+denoting that in such a way that [[noweb]] doesn't mistakenly think
+the [[sed]] command is a chunk reference itself), and then noting down
+appropriate commands to construct the target.
+
+<<makenwdep.sh>>=
+<<parse makenwdep arguments>>
+
+noroots $FILE | sed 's/^<''<\(.*\)>>$/\1/' |
+       while read chunk; do
+               <<output dependency info for [[$chunk]]>>
+       done
+@ 
+
+Our dependency information is straightforward. To construct a file from
+[[noweb]] source, we simply need to run [[notangle(1)]] over it. We add
+a couple of extra tweaks in order to only update files that were actually
+changed (the [[cpif(1)]] call), and to handle tabs properly.
+
+We also need some extra things to take care of particular types of files.
+In particular its important to have our scripts marked executable, so we
+can use them as part of the build process itself, and it's also important
+to have the dependency information for our C files (which are dealt with
+next) included at some point.
+
+<<output dependency info for [[$chunk]]>>=
+printf "%s : %s\n" "$chunk" "$FILE"
+case $chunk in
+       *.pl|*.sh)
+               printf "\tnotangle -R\$@ \$< >\$@\n"
+               printf "\tchmod 755 %s\n" "$chunk"
+               ;;
+       *.c)
+               printf "\tnotangle -L -R\$@ \$< | cpif \$@\n"
+               printf "include ${chunk%.c}.d\n"
+               ;;
+       *.h)
+               printf "\tnotangle -L -R\$@ \$< | cpif \$@\n"
+               ;;
+       *)
+               printf "\tnotangle -t8 -R\$@ $< >\$@\n"
+               ;;
+esac
+@ 
+
+Finally, our fairly primitive argument parsing is simply:
+
+<<parse makenwdep arguments>>=
+FILE=$1
+
+if [ "$FILE" = "" -o ! -f "$FILE" ]; then
+       echo "Please specify a .nw file"
+       exit 1
+fi
+@ 
+
+We have a related system for object files generated from C source
+code. Since each object file depends not only on its source, but also
+the headers included in that source, we generate a [[.d]] file indicating
+exactly which headers need to be checked.
+
+<<implicit rules>>=
+%.d: %.c makecdep.sh
+       ./makecdep.sh $< > $@
+@ 
+
+We can do this using [[gcc(1)]]'s convenient [[-MM -MG]] options,
+which do exactly this, with the added proviso that the [[.d]] file
+itself can possibly depend on any of the header files being modified
+(and, in particular, [[#include]] lines being added or deleted).
+
+<<makecdep.sh>>=
+#!/bin/sh
+<<parse makecdep arguments>>
+
+gcc -MM -MG $FILE |
+  sed -e 's@^\(.*\)\.o:@\1.o \1.d:@'
+@ 
+
+\emph{Deja vu}, anyone?
+
+<<parse makecdep arguments>>= 
+FILE=$1
+if [ "$FILE" = "" -o ! -f "$FILE" ]; then
+       echo "Please specify a .c file"
+       exit 1
+fi
+@
+
+To include the generated dependencies in [[Makefile]], we have to
+be a bit careful.  The problem here is that they should not be rebuild
+when merely the cleaning of the source tree is asked for.  Any targets
+ending in [[clean]], plus the [[clobber]] target prevent the inclusion
+of the generated dependencies.
+
+Unfortunately, [[make]] doesn't allow logical combinations within
+[[ifeq]] and friends, so we have to simulate this.
+
+<<generated dependency inclusion>>=
+include-deps := YES
+ifneq "" "$(filter %clean,$(MAKECMDGOALS))"
+include-deps := NO
+endif
+ifeq "clobber" "$(MAKECMDGOALS)"
+include-deps := NO
+endif
+@
+
+Finally, include the dependency information:
+
+<<generated dependency inclusion>>=
+ifeq "$(strip $(include-deps))" "YES"
+include ifupdown.d
+endif
+@
+
+\section{Compile Time Configuration}
+
+At compile time we need to determine all the possible address families
+that may be used, and all the methods of setting up interfaces for
+those address families, along with the various possible options
+affecting each method.
+
+Our key definition at this point is that of the [[address_family]]
+structure, which encapsulates all the compile time information about
+each address family.
+
+<<type definitions>>=
+typedef struct address_family address_family;
+@ 
+
+<<structure definitions>>=
+struct address_family {
+       char *name;
+       int n_methods;
+       method *method;
+};
+@ 
+
+Each defined address family will be included in the [[addr_fams]]
+array, which becomes the \emph{raison d'\^etre} of the [[addrfam]]
+module.
+
+<<exported symbols>>=
+extern address_family *addr_fams[];
+@ 
+
+Each address family incorporates a number of methods, which
+encapsulate various ways of configuring an interface for a particular
+address family. There are two definining components of a method: two
+sets of commands to bring an interface up and down, and a number of
+options for the commands.
+
+\emph{NB: I expect this will be extended sooner or later to make the
+options more flexible. Probably introducing some form of typing (for
+example to convert netmasks from CIDR specs to dotted-quads, ie
+/24~$\rightarrow$~255.255.255.0), and some form of matching to allow
+multiple options to be deduced from a single configuration
+statement. --- aj}
+
+<<type definitions>>=
+typedef struct method method;
+@ 
+
+<<structure definitions>>=
+struct method {
+       char *name;
+       command_set *up, *down;
+};
+@ 
+
+Each command set is implemented as a single function, accepting two
+parameters: the definitions of the interface the commands should deal
+with, and the function that should be used to execute them. See the
+[[execute]] module for more details.
+
+<<function type definitions>>=
+typedef int (execfn)(char *command);
+typedef int (command_set)(interface_defn *ifd, execfn *e);
+@ 
+
+As our compile-time configuration is done at, well, compile-time, there
+is little need for functions in the actual module, and we can make do with
+a single exported array.
+
+<<addrfam.c>>=
+#include <stdlib.h>
+#include "header.h"
+
+<<address family declarations>>
+
+address_family *addr_fams[] = {
+       <<address family references>>
+       NULL
+};
+@ 
+
+\subsection{Generating C Code}
+
+Unfortunately, while the [[.defn]] representation is reasonably
+convenient for human use, it's less convenient for a compiler. As
+such, at build time, we will build a single structure of type
+[[address_family]] in a separate module, and reference that from
+[[addrfam.c]].
+
+Naturally, we'll use a [[perl]] script to convert [[.defn]] files to C
+code.
+
+<<implicit rules>>=
+%.c : %.defn defn2c.pl
+       ./defn2c.pl $< > $@
+@ 
+
+The functionality of our program is pretty basic: read from the file
+specified as the argument, output to [[stdout]]; and correspondingly
+the structure of the program is similarly simple. We make use of a
+couple of global variables, a few helpful subroutines, and then build
+our C program.
+
+<<defn2c.pl>>=
+#!/usr/bin/perl -w
+
+use strict;
+
+# declarations
+<<defn2c variables>>
+
+# subroutines
+<<defn2c subroutines>>
+
+# main code
+<<output headers for address family>>
+<<parse [[.defn]] file and output intermediate structures>>
+<<output address family data structure>>
+@ 
+
+Clearly we need to reference some of the data structures we defined
+above, so we can begin with the rather trivial:
+
+<<output headers for address family>>=
+print "#include \"header.h\"\n\n\n";
+@ 
+
+The overall purpose of the C code we're trying to construct is to
+define a structure of type [[address_family]], and have it externally
+visible. So we'd like to declare a statically-initialized structure of
+this type, and be done with it.
+
+To do this, however, we need to have some way of uniquely identifying
+the structure to avoid naming conflicts. We'll do this by assuming we
+have a previously initialized variable, [[$address_family]], and that
+names of the form [[addr_foo]] won't be used elsewhere.
+
+<<defn2c variables>>=
+my $address_family = "";
+@
+
+We also need to reference an array of pointers to this address
+family's [[method]]s, which will have to be initialized separately.
+We'll assume that previous code will create such a structure, and call
+it (imaginatively) [[methods]].
+
+<<output address family data structure>>=
+<<output [[methods]] data structure>>
+
+print <<EOF;
+address_family addr_${address_family} = {
+       "$address_family",
+       sizeof(methods)/sizeof(struct method),
+       methods
+};
+EOF
+@ 
+
+Our [[methods]] array will be a little more complicated to
+construct. The first difficulty is that it will actually require some
+state from having read the [[.defn]] file. To handle this, we'll
+introduce a hash [[%methods]] that has the value [[1]] for each method
+from the [[.defn]] file. We use a hash instead of a list because it
+makes some error checking more convenient later, and since order
+doesn't particularly matter.
+
+<<defn2c variables>>=
+my %methods = ();
+@
+
+We'll use standard names, such as [[foo_up]], [[foo_down]], and
+[[foo_options]] for the various elements of each method which cannot
+be defined inline. The two functions and the array will be declared
+static to avoid name conflicts.
+
+<<output [[methods]] data structure>>=
+print "static method methods[] = {\n";
+my $method;
+foreach $method (keys %methods) {
+       print <<EOF;
+       {
+               "$method",
+               ${method}_up, ${method}_down,
+       },
+EOF
+}
+print "};\n\n";
+@ 
+
+In a reasonably obvious manner we can then proceed to process the
+[[.defn]] file to initialize the aforementioned variables, and to
+output the method-specific functions and array. We'll begin by
+defining a variable to keep track of the current line.
+
+<<defn2c variables>>=
+my $line = "";
+@ 
+
+Our semantics for this variable will be basically that it contains a
+valid, meaningful input line. It won't be blank, or contain comments,
+and if there aren't any more lines to be read, it will evaluate to
+[[false]]. In order to keep these semantics, we'll use the subroutine
+[[nextline]] to update it. (Since we'll later find we'll want to reuse
+this subroutine, we'll keep it in a chunk of its own)
+
+<<defn2c subroutines>>=
+<<[[nextline]] subroutine>>
+@ 
+
+<<[[nextline]] subroutine>>=
+sub nextline {
+       $line = <>;
+       while($line and ($line =~ /^#/ or $line =~ /^\s*$/)) {
+               $line = <>;
+       }
+       if (!$line) { return 0; }
+       chomp $line;
+       while ($line =~ m/^(.*)\\$/) {
+               my $addon = <>;
+               chomp $addon;
+               $line = $1 . $addon;
+       }
+       return 1;
+}
+@ 
+
+Our high-level logic then looks basically like:
+
+<<parse [[.defn]] file and output intermediate structures>>=
+nextline;
+while($line) {
+       <<parse a top-level section and output intermediate structures>>
+
+       # ...otherwise
+       die("Unknown command \"$line\"");
+}
+@
+
+To make all this stuff easier, we'll use a `matching' function to help
+with parsing lines: basically, given a line, a command, and possibly
+an indentation prefix (eg [["    "]]). (As with [[nextline]], this will
+also be useful to reuse, hence it has its own pair of chunks, too)
+
+<<defn2c variables>>=
+my $match = "";
+@ 
+
+<<defn2c subroutines>>=
+<<[[match]] subroutine>>
+@ 
+
+<<[[match]] subroutine>>=
+sub match {
+       my $line = $_[0];
+       my $cmd = "$_[1]" ? "$_[1]\\b\\s*" : "";;
+       my $indentexp = (@_ == 3) ? "$_[2]\\s+" : "";
+
+       if ($line =~ /^${indentexp}${cmd}(([^\s](.*[^\s])?)?)\s*$/) {
+               $match = $1;
+               return 1;
+       } else {
+               return 0;
+       } 
+}
+@ 
+
+Okay. So, the first line we expect to see is the name of the address
+family we're defining.
+
+<<parse a top-level section and output intermediate structures>>=
+if (match($line, "address_family")) {
+       get_address_family $match;
+       next;
+}
+@ 
+
+This is, as you'd imagine, pretty simple to deal with. We just need to
+store the address family's name, and move on to the next line.
+
+<<defn2c subroutines>>=
+sub get_address_family {
+       $address_family = $_[0] if ($address_family eq "");
+       nextline;
+}
+@ 
+
+Which brings us to determining the architecture.
+
+<<parse a top-level section and output intermediate structures>>=
+if (match($line, "architecture")) {
+       get_architecture $match;
+       next;
+}
+@ 
+
+You'd never guess what, but it's just as easy as the address family thing
+was.
+
+<<defn2c subroutines>>=
+sub get_architecture {
+       my $arch = $_[0];
+       die("architecture declaration appears too late") if (keys %methods);
+       print "#include \"arch${arch}.h\"\n\n\n";
+       nextline;
+}
+@ 
+
+Which leaves us with the hard bit, actually creating the functions and
+array for each method.
+
+<<parse a top-level section and output intermediate structures>>=
+if (match($line, "method")) {
+       get_method $match;
+       next;
+}
+@
+
+The basic premise is to check for each of our options in a given
+order: if they don't match, then we can presume they don't exist ---
+any errors will be reported when the main function finds something
+weird going on. All we really have to take care of so far is ensuring
+an appropriate level of indentation, and that we're not defining the
+same method twice.
+
+<<defn2c subroutines>>=
+sub get_method {
+       my $method = $_[0];
+       my $indent = ($line =~ /(\s*)[^\s]/) ? $1 : "";
+
+       die "Duplicate method $method\n" if ($methods{$method}++);
+
+       nextline;
+       <<output code for description>>
+       <<output code for options list>>
+       <<output code for up commands>>
+       <<output code for down commands>>
+}
+@ 
+
+The description and options sections are just documentation chunks,
+and hence aren't at all relevant for the C code.
+
+<<output code for description>>=
+if (match($line, "description", $indent)) {
+       skip_section();
+}
+@ 
+
+<<output code for options list>>=
+if (match($line, "options", $indent)) {
+       skip_section();
+}
+@ 
+
+Skipping a section is fairly easy: we just need to check alignments. This is
+yet another subroutine that'll come in handy elsewhere.
+
+<<defn2c subroutines>>=
+<<[[skip_section]] subroutine>>
+@ 
+
+<<[[skip_section]] subroutine>>=
+sub skip_section {
+       my $struct = $_[0];
+       my $indent = ($line =~ /(\s*)[^\s]/) ? $1 : "";
+
+       1 while (nextline && match($line, "", $indent));
+}
+@ 
+
+Checking the various relevant components of each method is fairly
+simple: we need to see if it exists, and if it does, parse and output
+it, while if it doesn't, we need to output a place holder.
+
+<<output code for up commands>>=
+if (match($line, "up", $indent)) {
+       get_commands(${method}, "up");
+} else {
+       print "static int ${method}_up(interface_defn ifd) { return 0; }\n"
+}
+@ 
+
+<<output code for down commands>>=
+if (match($line, "down", $indent)) {
+       get_commands(${method}, "down");
+} else {
+       print "static int ${method}_down(interface_defn ifd) { return 0; }\n"
+}
+@
+
+<<defn2c subroutines>>=
+sub get_commands {
+       my $method = $_[0];
+       my $mode = $_[1];
+       my $function = "${method}_${mode}";
+       my $indent = ($line =~ /(\s*)[^\s]/) ? $1 : "";
+
+       print "static int ${function}(interface_defn *ifd, execfn *exec) {\n";
+
+       while (nextline && match($line, "", $indent)) {
+               if ( $match =~ /^(.*[^\s])\s+if\s*\((.*)\)\s*$/ ) {
+                       print "if ( $2 ) {\n";
+                       print "  if (!execute(\"$1\", ifd, exec)) return 0;\n";
+                       print "}\n";
+               } elsif ( $match =~ /^(.*[^\s])\s+elsif\s*\((.*)\)\s*$/ ) {
+                       print "else if ( $2 ) {\n";
+                       print "  if (!execute(\"$1\", ifd, exec)) return 0;\n";
+                       print "}\n";
+               } elsif ( $match =~ /^(.*[^\s])\s*$/ ) {
+                       print "{\n";
+                       print "  if (!execute(\"$1\", ifd, exec)) return 0;\n";
+                       print "}\n";
+               }
+       }
+
+       print "return 1;\n";
+       print "}\n";
+}
+@ 
+
+\subsection{Building Manual Pages}
+
+So having C code is all very well, but if you want to ignore all user
+problems with a casual ``RTFM!'' there has to be some semblance of an
+M for them to R. So we need a script to generate some useful
+descriptions of the various methods.
+
+We'll achieve this by making another Perl script, [[defn2man.pl]],
+which will generate fragments of [[troff]] that can be catted together
+with a general overview of [[ifupdown]] to produce real manpages.
+
+<<implicit rules>>=
+%.man: %.defn defn2man.pl
+       ./defn2man.pl $< > $@
+@ 
+
+So we'll use a similar structure to [[defn2c.pl]].
+
+<<defn2man.pl>>=
+#!/usr/bin/perl -w
+
+use strict;
+
+# declarations
+<<defn2man variables>>
+
+# subroutines
+<<defn2man subroutines>>
+
+# main code
+<<parse [[.defn]] file and output manpage fragment>>
+@ 
+
+As predicted, we'll also incorporate [[nextline]], [[match]] and
+[[skip_section]]:
+
+<<defn2man variables>>=
+my $line;
+my $match;
+@ 
+
+<<defn2man subroutines>>=
+<<[[nextline]] subroutine>>
+<<[[match]] subroutine>>
+<<[[skip_section]] subroutine>>
+@ 
+
+Now we'll have a slightly different structure to the program itself
+this time, since we need to do things pretty much in order for
+outputting the manpage. This imposes stricter ordering requirements on
+the [[.defn]] files than [[defn2c]] did.
+
+<<parse [[.defn]] file and output manpage fragment>>=
+nextline;
+if ($line and match($line, "address_family")) {
+       get_address_family $match;
+} else {
+       die "address_family must be listed first\n";
+}
+if ($line and match($line, "architecture")) {
+       get_architecture $match;
+}
+while ($line and match($line, "method")) {
+       get_method $match;
+}
+@ 
+
+Okay, so it wasn't \emph{that} different from what we had before. Sue
+me.
+
+The [[get_address_family]] and [[get_architecture]] subroutines are
+fairly straight forward:
+
+<<defn2man subroutines>>=
+sub get_address_family {
+       print ".SH " . uc($match) . " ADDRESS FAMILY\n";
+       print "This section documents the methods available in the\n";
+       print "$match address family.\n";
+       nextline;
+}
+@ 
+
+<<defn2man subroutines>>=
+sub get_architecture {
+       # no op
+       nextline;
+}
+@ 
+
+Which only leaves extracting the description and options for each
+method. And, of course, this imposes less restrictions of the
+[[.defn]] file than [[defn2c.pl]] did. It's a crazy old world.
+
+<<defn2man subroutines>>=
+sub get_method {
+       my $method = shift;
+       my $indent = ($line =~ /(\s*)\S/) ? $1 : "";
+       my $description = "";
+       my @options = ();
+
+       nextline;
+       while ($line and match($line, "", $indent)) {
+               if (match($line, "description", $indent)) {
+                       $description = get_description();
+               } elsif (match($line, "options", $indent)) {
+                       @options = get_options();
+               } else {
+                       skip_section;
+               }
+       }
+
+       <<output [[$method]] introduction man fragment>>
+       <<output [[$description]] man fragment>>
+       <<output [[@options]] man fragment>>
+}
+@
+
+<<output [[$method]] introduction man fragment>>=
+print ".SS The $method Method\n";
+@ 
+
+Okay. Now our [[$description]] is just the description with any [['\n']]
+characters it may've had, but without the leading spaces.
+
+<<defn2man subroutines>>=
+sub get_description {
+       my $desc = "";
+       my $indent = ($line =~ /(\s*)\S/) ? $1 : "";
+       while(nextline && match($line, "", $indent)) {
+               $desc .= "$match\n";
+       }
+       return $desc;
+}
+@ 
+
+We're actually going to be a little tricky here, and allow some formatting
+in our descriptions. Basically, we'll allow bold and italic encoding
+to be denoted by [[*bold*]] and [[/italics/]] in the wonderful Usenet
+tradition. As such, we'll use a cute little function to convert the
+Usenet style to \emph{roff}. We'll also take care not to do this conversion
+within words (for things like [[/etc/hosts]], eg). Voila:
+
+<<defn2man subroutines>>=
+sub usenet2man {
+       my $in = shift;
+       my $out = "";
+
+       $in =~ s/\s+/ /g;
+       while ($in =~ m%^([^*/]*)([*/])([^*/]*)([*/])(.*)$%s) {
+               my ($pre, $l, $mid, $r, $post) = ($1, $2, $3, $4, $5);
+               if ($l eq $r && " $pre"  =~ m/[[:punct:][:space:]]$/ 
+                            && "$post " =~ m/^[[:punct:][:space:]]/) {
+                       $out .= $pre;
+                       $out .= ($l eq "*" ? '\fB' : '\fI') . $mid . '\fP';
+                       ($in = $post) =~ s/^\s+/ /;
+               } else {
+                       $out .= $pre . $l;
+                       $in = $mid . $r . $post;
+               }
+       } 
+       return $out . $in;
+}
+@
+
+The only further thing to note about this is that we're being careless
+and ignoring the possibility of \emph{roff} escape sequences in the input. But
+since this is for internal use only, well, too bad. So here we go:
+
+<<output [[$description]] man fragment>>=
+if ($description ne "") {
+       print usenet2man($description) . "\n";
+} else {
+       print "(No description)\n";
+}
+@ 
+
+Damn that was fun.
+
+Reading the options is almost exactly the same as the description,
+except we want a list instead of just a string.
+
+<<defn2man subroutines>>=
+sub get_options {
+       my @opts = ();
+       my $indent = ($line =~ /(\s*)\S/) ? $1 : "";
+       while(nextline && match($line, "", $indent)) {
+               push @opts, $match;
+       }
+       return @opts;
+}
+@ 
+
+Output is slightly more complicated, but not too much so.
+
+<<output [[@options]] man fragment>>=
+print ".PP\n";
+print ".B Options\n";
+print ".RS\n";
+if (@options) {
+       foreach my $o (@options) {
+               if ($o =~ m/^\s*(\S*)\s*(.*)\s+--\s+(\S.*)$/) {
+                       my $opt = $1;
+                       my $optargs = $2;
+                       my $dsc = $3;
+                       print ".TP\n";
+                       print ".BI $opt";
+                       print " \" $optargs\"" unless($optargs =~ m/^\s*$/);
+                       print "\n";
+                       print usenet2man($dsc) . "\n";
+               } else {
+                       print ".TP\n";
+                       print ".B $o\n";
+               }
+       }
+} else {
+       print ".TP\n";
+       print "(No options)\n";
+}
+print ".RE\n";
+@ 
+
+\section{Run-time Configuration}
+
+Our module is of the usual form, and we'll make use of a few fairly standard
+headers. Please move along, there's nothing to see here.
+
+<<config.c>>=
+<<config headers>>
+<<config function declarations>>
+<<config functions>>
+@ 
+
+<<config headers>>=
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+@ 
+
+We'll also make use of some of our other modules. This is, after all,
+why we had a single header in the first place.
+
+<<config headers>>=
+#include "header.h"
+@ 
+
+The key function we're interested in defining here is
+[[read_interfaces()]], which will (wait for it) read an interfaces
+file. The intention is to make it really easy to deal with the
+vagaries of [[/etc/network/interfaces]] anywhere else.
+
+So the first question we need to deal with is ``What's a convenient
+form for other functions which deal with interfaces?'' Well, our
+answer to that is basically:
+
+\begin{enumerate}
+       \item an array of interface names that should be brought up at
+       bootup.
+
+       \item a singly linked list to represent the various mappings.
+
+       \item another singly linked list to represent the interface
+       definitions themselves.
+\end{enumerate}
+
+ These are almost in exact correspondence with the original file.
+
+<<type definitions>>=
+typedef struct interfaces_file interfaces_file;
+@ 
+
+<<structure definitions>>=
+struct interfaces_file {
+       allowup_defn *allowups;
+       interface_defn *ifaces;
+       mapping_defn *mappings;
+};
+@
+
+So, at run-time, we first need a way of dealing with the [[auto]] and
+[[allow-*]] lines. We'll treat [[allow-auto]] and [[auto]] as equivalent,
+making that pretty straightforward:
+
+<<type definitions>>=
+typedef struct allowup_defn allowup_defn;
+@
+
+<<structure definitions>>=
+struct allowup_defn {
+       allowup_defn *next;
+
+       char *when;
+       int max_interfaces;
+       int n_interfaces;
+       char **interfaces;
+};
+@ 
+
+We also require a way of representing each interface listed in the
+configuration file. This naturally needs to reference an address family
+and method, and all the options a user may specify about an interface.
+
+<<type definitions>>=
+typedef struct interface_defn interface_defn;
+@ 
+
+<<structure definitions>>=
+struct interface_defn {
+       interface_defn *next;
+
+       char *logical_iface;
+       char *real_iface;
+
+       address_family *address_family;
+       method *method;
+
+       int automatic;
+
+       int max_options;
+       int n_options;
+       variable *option;
+};
+@
+
+The last component in the above, the options, is represented by a
+series of name/value pairs, as follows:
+
+<<type definitions>>=
+typedef struct variable variable;
+@ 
+
+<<structure definitions>>=
+struct variable {
+       char *name;
+       char *value;
+};
+@ 
+
+In addition, we want to represent each mapping in the configuration
+file. This is somewhat simpler, since each mapping is entirely self
+contained, and doesn't need to reference previously determined address
+families or methods or anything.
+
+<<type definitions>>=
+typedef struct mapping_defn mapping_defn;
+@ 
+
+<<structure definitions>>=
+struct mapping_defn {
+       mapping_defn *next;
+
+       int max_matches;
+       int n_matches;
+       char **match;
+
+       char *script;
+
+       int max_mappings;
+       int n_mappings;
+       char **mapping;
+};
+@ 
+
+We can thus begin to instantiate our actual function. What we want is
+something that, given the name of a file, will produce the appropriate
+linked list of interfaces defined in it, or possibly give some sort of
+helpful error message. Pretty simple, hey?
+
+<<exported symbols>>=
+interfaces_file *read_interfaces(char *filename);
+@ 
+
+<<config functions>>=
+interfaces_file *read_interfaces(char *filename) {
+       <<variables local to read interfaces>>
+       interfaces_file *defn;
+
+       <<allocate defn or [[return NULL]]>>
+       <<open file or [[return NULL]]>>
+
+       while (<<we've gotten a line from the file>>) {
+               <<process the line>>
+       }
+       if (<<an error occurred getting the line>>) {
+               <<report internal error and die>>
+       }
+
+       <<close file>>
+
+       return defn;
+}
+@ 
+
+<<allocate defn or [[return NULL]]>>=
+defn = malloc(sizeof(interfaces_file));
+if (defn == NULL) {
+       return NULL;
+}
+defn->allowups = NULL;
+defn->mappings = NULL;
+defn->ifaces = NULL;
+@ 
+
+\subsection{File Handling}
+
+So, the first and most obvious thing to deal with is the file
+handling. Nothing particularly imaginative here.
+
+<<variables local to read interfaces>>=
+FILE *f;
+int line;
+@ 
+
+<<open file or [[return NULL]]>>=
+f = fopen(filename, "r");
+if ( f == NULL ) return NULL;
+line = 0;
+@
+
+<<close file>>=
+fclose(f);
+line = -1;
+@
+
+\subsection{Line Parsing}
+
+Our next problem is to work out how to read a single line from our
+input file. While this is nominally easy, we also want to deal nicely
+with things like continued lines, comments, and very long lines.
+
+So we're going to have to write and make use of a complicated little
+function, which we'll imaginatively call [[get_line()]]. It will need
+a pointer to the file it's reading from, as well as a buffer to store
+the line it finds. Since this buffer's size can't be known in advance
+we'll need to make it [[realloc()]]-able, which means we need to pass
+around references to both the buffer's location (which may change),
+and it's size (which probably will). Our function declaration is thus:
+
+<<config function declarations>>=
+static int get_line(char **result, size_t *result_len, FILE *f, int *line);
+@ 
+
+To use it, we'll need a couple of variables to stores the buffer's
+location, and it's current length.
+
+<<variables local to read interfaces>>=
+char *buf = NULL;
+size_t buf_len = 0;
+@ 
+
+Given these, and presuming we can actually implement the function, our
+key chunk can thus be implemented simply as:
+
+<<we've gotten a line from the file>>=
+get_line(&buf,&buf_len,f,&line)
+@ 
+
+We'll also add the requirement that errors are indicated by the
+[[errno]] variable being non-zero, which is usual and reasonable for
+all the circumstances where [[get_line()]] might have problems.
+
+<<config headers>>=
+#include <errno.h>
+@ 
+
+<<an error occurred getting the line>>=
+ferror(f) != 0
+@ 
+
+Actually defining the function is, as you'd probably imagine, a little
+more complicated. We begin by reading a line from the file. If it was
+a comment (that is, it has a [[#]] character at the first non-blank
+position) then we try again. Otherwise, if the line is continued
+(indicated by a [[\]] character at the very end of the line) we append
+the next line to the buffer. We go to a little bit of effort to trim
+whitespace, and finally return a boolean result indicating whether we
+got a line or not.
+
+<<config functions>>=
+static int get_line(char **result, size_t *result_len, FILE *f, int *line) {
+       <<variables local to get line>>
+
+       do {
+               <<clear buffer>>
+               <<append next line to buffer, or [[return 0]]>>
+               <<trim leading whitespace>>
+       } while (<<line is a comment>>);
+
+       while (<<buffer is continued>>) {
+               <<remove continuation mark>>
+               <<append next line to buffer, or [[return 0]]>>
+       }
+
+       <<trim trailing whitespace>>
+
+       return 1;
+}
+@ 
+
+In order to do string concatenation efficiently, we'll keep track of
+where the end of the line so far is --- this is thus where the
+terminating [[NUL]] will be by the end of the function.
+
+<<variables local to get line>>=
+size_t pos;
+@ 
+
+We can thus clear the buffer by simply resetting where we append new
+text to the beginning of the buffer. What could be simpler?
+
+<<clear buffer>>=
+pos = 0;
+@ 
+
+We'll be making use of the [[fgets()]] function to read the line
+(rather than, say, [[fgetc()]]) so to get an entire line we may have
+to make multiple attempts (if the line is bigger than our
+buffer). Realising this, and the fact that we may not have any
+allocated space for our buffer initially, we need a loop something
+like:
+
+<<append next line to buffer, or [[return 0]]>>=
+do {
+       <<reallocate buffer as necessary, or [[return 0]]>>
+       <<get some more of the line, or [[return 0]]>>
+} while(<<the line isn't complete>>);
+
+<<remove trailing newline>>
+
+(*line)++;
+
+assert( (*result)[pos] == '\0' );
+@ 
+
+When reallocating the buffer, we need to make sure it increases in
+chunks large enough that we don't have to do this too often, but not
+so huge that we run out of memory just to read an 81 character line.
+We'll use two fairly simple heuristics for this: if we've got room to
+add no more than 10 characters, we may as well reallocate the buffer,
+and when reallocating, we want to more or less double the buffer, but
+we want to at least add 80 characters. So we do both.
+
+<<reallocate buffer as necessary, or [[return 0]]>>=
+if (*result_len - pos < 10) {
+       char *newstr = realloc(*result, *result_len * 2 + 80);
+       if (newstr == NULL) {
+               return 0;
+       }
+       *result = newstr;
+       *result_len = *result_len * 2 + 80;
+}
+@ 
+
+The only time we need to keep reading is when the buffer wasn't big
+enough for the entire line. This is indicated by a full buffer, with
+no newline at the end. There is, actually, one case where this can
+happen legitimately --- where the last line of the file is
+\emph{exactly} the length of the buffer. We need to detect this
+because [[fgets()]] will return [[NULL]] and indicate that it's hit
+the end of the file, but we won't want to indicate that until the
+\emph{next} time we try to get a line. Complicated, isn't it?
+
+<<the line isn't complete>>=
+pos == *result_len - 1 && (*result)[pos-1] != '\n'
+@ 
+
+So having thought through all that, actually working with [[fgets()]]
+is fairly simple, especially since we deal with the actual errors
+elsewhere. All we need to do is make the call, update [[pos]] and
+check that the problems [[fgets()]] may have actually bother us.
+
+<<get some more of the line, or [[return 0]]>>=
+if (!fgets(*result + pos, *result_len - pos, f)) {
+       if (ferror(f) == 0 && pos == 0) return 0;
+       if (ferror(f) != 0) return 0;
+}
+pos += strlen(*result + pos);
+@ 
+
+[[fgets()]] leaves a [[\n]] in our buffer in some cases. We're never
+actually interested in it, however, so it's a good move to get rid of
+it.
+
+<<remove trailing newline>>=
+if (pos != 0 && (*result)[pos-1] == '\n') {
+       (*result)[--pos] = '\0';
+}
+@ 
+
+
+Pretty simple, hey? Now the next thing we want to do is get rid of
+some of the whitespace lying about. This is all pretty basic, and just
+involves finding where the whitespace begins and ends, and, well,
+getting rid of it.
+
+<<config headers>>=
+#include <ctype.h>
+@ 
+
+<<trim leading whitespace>>=
+{ 
+       int first = 0; 
+       while (isspace((*result)[first]) && (*result)[first]) {
+               first++;
+       }
+
+       memmove(*result, *result + first, pos - first + 1);
+       pos -= first;
+}
+@ 
+
+<<trim trailing whitespace>>=
+while (isspace((*result)[pos-1])) { /* remove trailing whitespace */
+       pos--;
+}
+(*result)[pos] = '\0';
+@ 
+
+As we mentioned earlier, a line is a comment iff it's first character
+is a [[#]] symbol. Similarly, it's continued iff it's very last
+character is a [[\]]. And, rather obviously, if we want to remove a
+single trailing [[\]], we can do so by changing it to a [[NUL]].
+
+<<line is a comment>>=
+(*result)[0] == '#'
+@ 
+
+<<buffer is continued>>=
+(*result)[pos-1] == '\\'
+@ 
+
+<<remove continuation mark>>=
+(*result)[--pos] = '\0';
+@ 
+
+\subsection{Line Processing}
+
+So. We've gone to a lot of trouble to get a line that we can parse
+with a snap of our fingers, so we probably better jump to it, to mix
+some \emph{clich\'e's}.
+
+We have two alternative bits of state to maintain between lines: either
+what interface we're currently defining, or what mapping we're currently
+defining.
+
+<<variables local to read interfaces>>=
+interface_defn *currif = NULL;
+mapping_defn *currmap = NULL;
+enum { NONE, IFACE, MAPPING } currently_processing = NONE;
+@ 
+
+Since our configuration files are pretty basic, we can work out what
+any particular line means based on the first word in it. To cope with
+this, we'll thus make use of a couple of variables, one to store the
+first word, and the other to store the rest of the line.
+
+<<variables local to read interfaces>>=
+char firstword[80];
+char *rest;
+@ 
+
+To initialize these variables we'll make use of a function I'm overly
+fond of called [[next_word()]]. It copies the first word in a string
+to a given buffer, and returns a pointer to the rest of the buffer.
+
+<<config function declarations>>=
+static char *next_word(char *buf, char *word, int maxlen);
+@
+
+<<config functions>>=
+static char *next_word(char *buf, char *word, int maxlen) {
+       if (!buf) return NULL;
+       if (!*buf) return NULL;
+
+       while(!isspace(*buf) && *buf) {
+               if (maxlen-- > 1) *word++ = *buf;
+               buf++;
+       }
+       if (maxlen > 0) *word = '\0';
+
+       while(isspace(*buf) && *buf) buf++;
+
+       return buf;
+}
+@ 
+
+So after all this, there are basically three different sorts of line
+we can get: the start of a new interface, the start of a new mapping,
+or an option for whatever interface we're currently working with.
+Note that we check for blank lines, but \emph{not} for options with
+empty values.  This has to be done on a case-by-case basis.
+
+<<process the line>>=
+rest = next_word(buf, firstword, 80);
+if (rest == NULL) continue; /* blank line */
+
+if (strcmp(firstword, "mapping") == 0) {
+       <<process [[mapping]] line>>
+       currently_processing = MAPPING;
+} else if (strcmp(firstword, "iface") == 0) {
+       <<process [[iface]] line>>
+       currently_processing = IFACE;
+} else if (strcmp(firstword, "auto") == 0) {
+       <<process [[auto]] line>>
+       currently_processing = NONE;
+} else if (strncmp(firstword, "allow-", 6) == 0 && strlen(firstword) > 6) {
+       <<process [[allow-]] line>>
+       currently_processing = NONE;
+} else {
+       <<process option line>>
+}
+@ 
+
+<<process option line>>=
+switch(currently_processing) {
+       case IFACE:
+               <<process iface option line>>
+               break;
+       case MAPPING:
+               <<process mapping option line>>
+               break;
+       case NONE:
+       default:
+               <<report bad option and die>>
+}
+@ 
+
+\subsubsection{Mapping Line}
+
+Declaring a new mapping is reasonably copewithable --- we need to process
+a few things, but they're reasonably easy to handle.
+
+The main weirdness is that we're processing the [[mapping]] line itself
+and the rest of the stanza in separate blocks of code. So this first
+chunk just needs to do the basics of initialising the data structure,
+but can't really fill in all that much of it.
+
+<<process [[mapping]] line>>=
+<<allocate new mapping>>
+<<parse mapping interfaces>>
+<<set other mapping options to defaults>>
+<<add to list of mappings>>
+@ 
+
+<<allocate new mapping>>=
+currmap = malloc(sizeof(mapping_defn));
+if (currmap == NULL) {
+       <<report internal error and die>>
+}
+@ 
+
+<<parse mapping interfaces>>=
+currmap->max_matches = 0;
+currmap->n_matches = 0;
+currmap->match = NULL;
+
+while((rest = next_word(rest, firstword, 80))) {
+       if (currmap->max_matches == currmap->n_matches) {
+               char **tmp;
+               currmap->max_matches = currmap->max_matches * 2 + 1;
+               tmp = realloc(currmap->match, 
+                       sizeof(*tmp) * currmap->max_matches);
+               if (tmp == NULL) {
+                       currmap->max_matches = (currmap->max_matches - 1) / 2;
+                       <<report internal error and die>>
+               }
+               currmap->match = tmp;
+       }
+
+       currmap->match[currmap->n_matches++] = strdup(firstword);
+}
+@ 
+
+<<set other mapping options to defaults>>=
+currmap->script = NULL;
+
+currmap->max_mappings = 0;
+currmap->n_mappings = 0;
+currmap->mapping = NULL;
+@ 
+
+<<add to list of mappings>>=
+{
+       mapping_defn **where = &defn->mappings;
+       while(*where != NULL) {
+               where = &(*where)->next;
+       }
+       *where = currmap;
+       currmap->next = NULL;
+}
+@ 
+
+So that's that. But as mentioned, we also need to cope with the options
+within the stanza, as well as the lead in. As before, it's not really
+complicated, and we do it thusly:
+
+<<process mapping option line>>=
+if (strcmp(firstword, "script") == 0) {
+       <<handle [[script]] line>>
+} else if (strcmp(firstword, "map") == 0) {
+       <<handle [[map]] line>>
+} else {
+       <<report bad option and die>>
+}
+@ 
+
+<<handle [[script]] line>>=
+if (currmap->script != NULL) {
+       <<report duplicate script in mapping and die>>
+} else {
+       currmap->script = strdup(rest);
+}
+@ 
+
+<<handle [[map]] line>>=
+if (currmap->max_mappings == currmap->n_mappings) {
+       char **opt;
+       currmap->max_mappings = currmap->max_mappings * 2 + 1;
+       opt = realloc(currmap->mapping, sizeof(*opt) * currmap->max_mappings);
+       if (opt == NULL) {
+               <<report internal error and die>>
+       }
+       currmap->mapping = opt;
+}
+currmap->mapping[currmap->n_mappings] = strdup(rest);
+currmap->n_mappings++;
+@ 
+
+\subsubsection{Interface line}
+
+Declaring a new interface follows the same pattern, but is somewhat more
+interesting and some more complicated data structures are involved.
+
+<<process [[iface]] line>>=
+{
+       <<variables local to process [[iface]] line>>
+
+       <<allocate new interface>>
+
+       <<parse interface settings>>
+
+       <<set iface name>>
+       <<set address family>>
+       <<set method>>
+       <<set other interface options to defaults>>
+
+       <<add to list of interfaces>>
+}
+@ 
+
+We'll deal with each of these phases one by one and pretty much in
+order, so prepare yourself for the intense excitement of memory
+allocation!
+
+<<allocate new interface>>=
+currif = malloc(sizeof(interface_defn));
+if (!currif) {
+       <<report internal error and die>>
+}
+@ 
+
+When we introduce a new interface, we simultaneously name the
+interface, the address family, and the method. We cope with this by,
+well, getting somewhere to store each of them, and then, well, storing
+them.
+
+<<variables local to process [[iface]] line>>=
+char iface_name[80];
+char address_family_name[80];
+char method_name[80];
+@ 
+
+<<parse interface settings>>=
+rest = next_word(rest, iface_name, 80);
+rest = next_word(rest, address_family_name, 80);
+rest = next_word(rest, method_name, 80);
+
+if (rest == NULL) {
+       <<report too few parameters for iface line and die>>
+}
+
+if (rest[0] != '\0') {
+       <<report too many parameters for iface line and die>>
+}
+@ 
+
+We then want to store the interface name.
+
+<<set iface name>>=
+currif->logical_iface = strdup(iface_name);
+if (!currif->logical_iface) {
+       <<report internal error and die>>
+}
+@ 
+
+Setting the address family is a little more involved, because it's not
+very useful to know what the name of the address family is, you really
+want to know all the details recorded in the appropriate
+[[address_family]] structure. So we'll make use of a little helper
+function, called [[get_address_family()]] to convert the useless
+string, to the hopefully less useless structure.
+
+<<config function declarations>>=
+static address_family *get_address_family(address_family *af[], char *name);
+@ 
+
+<<set address family>>=
+currif->address_family = get_address_family(addr_fams, address_family_name);
+if (!currif->address_family) {
+       <<report unknown address family and die>>
+}
+@ 
+
+Of course, we probably need to actually implement the function too. We
+won't do anything particularly fancy here, just a simple linear
+search. \emph{Should this really be here, or an exported symbol from
+[[addrfam.c]]? --- aj}
+
+<<config functions>>=
+static address_family *get_address_family(address_family *af[], char *name) {
+       int i;
+       for (i = 0; af[i]; i++) {
+               if (strcmp(af[i]->name, name) == 0) {
+                       return af[i];
+               }
+       }
+       return NULL;
+}
+@
+
+We do something incredibly similar when dealing with the method the
+user wishes to use, and we do it for incredibly similar reasons. Again
+we declare a cute little helper function, this time imaginatively
+called [[get_method()]], and then go and use it and implement in
+almost exactly the same way as before. I told you this was going to be
+a thrill. \emph{The same note applies here, too --- aj}
+
+<<config function declarations>>=
+static method *get_method(address_family *af, char *name);
+@ 
+
+<<set method>>=
+currif->method = get_method(currif->address_family, method_name);
+if (!currif->method) {
+       <<report unknown method and die>>
+       return NULL; /* FIXME */
+}
+@
+
+<<config functions>>=
+static method *get_method(address_family *af, char *name) {
+       int i;
+       for (i = 0; i < af->n_methods; i++) {
+               if (strcmp(af->method[i].name, name) == 0) {
+                       return &af->method[i];
+               }
+       }
+       return NULL;
+}
+@
+
+You'll continue to be enthralled as we set the remaining options to
+some default values.
+
+<<set other interface options to defaults>>=
+currif->automatic = 1;
+currif->max_options = 0;
+currif->n_options = 0;
+currif->option = NULL;
+@ 
+
+Since we want to keep the interfaces in order, we have to go all the
+way to the end of the list of interfaces to add the new interface, and
+we can hence set the [[next]] pointer to NULL in all cases. Gee. Whiz.
+
+Actually, I'm selling this a little short. We also want to make sure
+we don't try instantiating the same interface twice or anything. So we
+take care of that too. There now. Didn't that just get the adrenalin
+pumping?
+
+<<add to list of interfaces>>=
+{
+       interface_defn **where = &defn->ifaces; 
+       while(*where != NULL) {
+               if (duplicate_if(*where, currif)) {
+                       <<report duplicate interface and die>>
+               }
+               where = &(*where)->next;
+       }
+
+       *where = currif;
+       currif->next = NULL;
+}
+@ 
+
+Duplicate interfaces are interfaces that have the same name and the
+same address family. Nothing more complicated than that.
+
+<<config function declarations>>=
+static int duplicate_if(interface_defn *ifa, interface_defn *ifb);
+@ 
+
+<<config functions>>=
+static int duplicate_if(interface_defn *ifa, interface_defn *ifb) {
+       if (strcmp(ifa->logical_iface, ifb->logical_iface) != 0) return 0;
+       if (ifa->address_family != ifb->address_family) return 0;
+       return 1;
+}
+@ 
+
+Dealing with the per-interface options is the next thing to deal
+with. 
+
+<<process iface option line>>=
+<<convert [[post-up]] and [[pre-down]] aliases to [[up]] and [[down]]>>
+<<check for duplicate options>>
+<<add option>>
+@
+
+<<convert [[post-up]] and [[pre-down]] aliases to [[up]] and [[down]]>>=
+if (strcmp(firstword, "post-up") == 0) {
+       strcpy(firstword, "up");
+}
+if (strcmp(firstword, "pre-down") == 0) {
+       strcpy(firstword, "down");
+} 
+@
+
+<<check for duplicate options>>=
+{
+       int i;
+
+       if (strlen (rest) == 0) {
+               <<report empty option and die>>
+       }
+
+       if (strcmp(firstword, "pre-up") != 0 
+           && strcmp(firstword, "up") != 0
+           && strcmp(firstword, "down") != 0
+           && strcmp(firstword, "post-down") != 0)
+        {
+               for (i = 0; i < currif->n_options; i++) {
+                       if (strcmp(currif->option[i].name, firstword) == 0) {
+                               <<report duplicate option and die>>
+                       }
+               }
+       }
+}
+@ 
+
+Adding an option is fairly straightforward: we simply construct
+a new variable and add it at the end of our array of variables,
+increasing the size of the array first if necessary.  Options with 
+empty values are rejected.
+
+<<add option>>=
+if (currif->n_options >= currif->max_options) {
+       <<increase max number of options>>
+}
+
+currif->option[currif->n_options].name = strdup(firstword);
+currif->option[currif->n_options].value = strdup(rest);
+
+if (!currif->option[currif->n_options].name) {
+       <<report internal error and die>>
+}
+
+if (!currif->option[currif->n_options].value) {
+       <<report internal error and die>>
+}
+
+currif->n_options++;   
+@
+
+We'll increase the space for variables by a constant amount each time,
+rather than doubling or anything smart like that.
+
+<<increase max number of options>>=
+{
+       variable *opt;
+       currif->max_options = currif->max_options + 10;
+       opt = realloc(currif->option, sizeof(*opt) * currif->max_options);
+       if (opt == NULL) {
+               <<report internal error and die>>
+       }
+       currif->option = opt;
+}
+@ 
+
+\subsubsection{Auto and Allow Lines}
+
+Processing the [[auto]] and [[allow-]] lines is pretty straightforward
+after the above, we just need to add each parameter to the list and
+check for duplicates. Since we're doing essentially the same thing twice,
+we'll break the common part out into a function.
+
+<<process [[auto]] line>>=
+allowup_defn *auto_ups = get_allowup(&defn->allowups, "auto");
+if (!auto_ups) {
+       <<report internal error and die>>
+}
+while((rest = next_word(rest, firstword, 80))) {
+       if (!add_allow_up(filename, line, auto_ups, firstword))
+               return NULL;
+}
+@ 
+<<process [[allow-]] line>>=
+allowup_defn *allow_ups = get_allowup(&defn->allowups, firstword + 6);
+if (!allow_ups) {
+       <<report internal error and die>>
+}
+while((rest = next_word(rest, firstword, 80))) {
+       if (!add_allow_up(filename, line, allow_ups, firstword))
+               return NULL;
+}
+@ 
+
+<<config function declarations>>=
+allowup_defn *get_allowup(allowup_defn **allowups, char *name);
+
+<<config functions>>=
+allowup_defn *get_allowup(allowup_defn **allowups, char *name) {
+       for (; *allowups; allowups = &(*allowups)->next) {
+               if (strcmp((*allowups)->when, name) == 0) break;
+       }
+       if (*allowups == NULL) {
+               *allowups = malloc(sizeof(allowup_defn));
+               if (*allowups == NULL) return NULL;
+               (*allowups)->when = strdup(name);
+               (*allowups)->next = NULL;
+               (*allowups)->max_interfaces = 0;
+               (*allowups)->n_interfaces = 0;
+               (*allowups)->interfaces = NULL;
+       }
+       return *allowups;
+}
+@
+
+We'll want to export a little helper function to make finding the appropriate
+allowup easier too:
+
+<<exported symbols>>=
+allowup_defn *find_allowup(interfaces_file *defn, char *name);
+@
+
+<<config functions>>=
+allowup_defn *find_allowup(interfaces_file *defn, char *name) {
+       allowup_defn *allowups = defn->allowups;
+       for (; allowups; allowups = allowups->next) {
+               if (strcmp(allowups->when, name) == 0) break;
+       }
+       return allowups;
+}
+@
+
+<<config function declarations>>=
+allowup_defn *add_allow_up(char *filename, int line,
+        allowup_defn *allow_up, char *iface_name);
+@
+
+<<config functions>>=
+allowup_defn *add_allow_up(char *filename, int line,
+       allowup_defn *allow_up, char *iface_name)
+{
+       <<check [[iface_name]] isn't already an [[allow_up]] interface or die>>
+       <<add [[iface_name]] as an [[allow_up]] interface or die>>
+       return allow_up;
+}
+@
+
+<<check [[iface_name]] isn't already an [[allow_up]] interface or die>>=
+{
+       int i;
+
+       for (i = 0; i < allow_up->n_interfaces; i++) {
+               if (strcmp(iface_name, allow_up->interfaces[i]) == 0) {
+                       <<report [[iface_name]] as [[allow_up]] duplicate, die>>
+               }
+       }
+}
+@
+
+<<add [[iface_name]] as an [[allow_up]] interface or die>>=
+if (allow_up->n_interfaces == allow_up->max_interfaces) {
+       char **tmp;
+       allow_up->max_interfaces *= 2;
+       allow_up->max_interfaces++;
+       tmp = realloc(allow_up->interfaces, 
+               sizeof(*tmp) * allow_up->max_interfaces);
+       if (tmp == NULL) {
+               <<report internal error and die>>
+       }
+       allow_up->interfaces = tmp;
+}
+
+allow_up->interfaces[allow_up->n_interfaces] = strdup(iface_name);
+allow_up->n_interfaces++;
+@
+
+\subsection{Error Handling}
+
+We don't do anything too fancy about handling errors that occur, we
+just print out a hopefully helpful error message, and return from the
+function. \emph{We probably should also go to some effort to close files,
+and free memory, but well, you know. Maybe version $n+1$. --- aj}
+
+<<report internal error and die>>=
+perror(filename);
+return NULL;
+@ 
+
+<<report too few parameters for iface line and die>>=
+fprintf(stderr, "%s:%d: too few parameters for iface line\n", filename, line);
+return NULL;
+@
+
+<<report too many parameters for iface line and die>>=
+fprintf(stderr, "%s:%d: too many parameters for iface line\n", filename, line);
+return NULL;
+@
+
+<<report unknown address family and die>>=
+fprintf(stderr, "%s:%d: unknown address type\n", filename, line);
+return NULL;
+@
+
+<<report unknown method and die>>=
+fprintf(stderr, "%s:%d: unknown method\n", filename, line);
+return NULL;
+@
+
+<<report duplicate interface and die>>=
+fprintf(stderr, "%s:%d: duplicate interface\n", filename, line);
+return NULL;
+@
+
+<<report [[iface_name]] as [[allow_up]] duplicate, die>>=
+fprintf(stderr, "%s:%d: interface %s declared allow-%s twice\n", 
+       filename, line, iface_name, allow_up->when);
+return NULL;
+@
+
+<<report duplicate option and die>>=
+fprintf(stderr, "%s:%d: duplicate option\n", filename, line);
+return NULL;
+@
+
+<<report duplicate script in mapping and die>>=
+fprintf(stderr, "%s:%d: duplicate script in mapping\n", filename, line);
+return NULL;
+@ 
+
+<<report bad option and die>>=
+fprintf(stderr, "%s:%d: misplaced option\n", filename, line);
+return NULL;
+@
+
+<<report empty option and die>>=
+fprintf(stderr, "%s:%d: option with empty value\n", filename, line);
+return NULL;
+@ 
+
+\section{Execution}
+
+The [[execute]] module will be laid out in the standard manner, and
+will make use of the usual header files.
+
+<<execute.c>>=
+<<execute headers>>
+<<execute global variables>>
+<<execute function declarations>>
+<<execute functions>>
+@ 
+
+<<execute headers>>=
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "header.h"
+@
+
+The key functions we export from here are all the functions that as a
+fairly direct result run some executable.
+
+\begin{itemize}
+       \item [[iface_up()]] and [[iface_down()]] which will actually
+       configure or deconfigure an interface.
+
+       \item [[execute()]] which will take an interface definition and
+       a command and fill in the details from the first into the
+       second, and the execute the result. This is basically just a
+       callback for the address family module.
+
+       \item [[run_mapping()]] which will run a mapping script and
+       determine if a new logical interface should be selected.
+\end{itemize}
+
+We'll discuss each of these in order.
+
+\subsection{Interface Configuration and Deconfiguration}
+
+Most of the complexity is involved in implementing the [[iface_up()]] and
+[[iface_down()]] functions. These are complicated enough that an explanatory
+diagram is probably useful:
+
+\begin{center}
+\includegraphics[height=60mm]{execution}
+\end{center}
+
+At a conceptual level, [[iface_up()]] and [[iface_down()]] have a
+reasonably straightforward job: they have to run one set of scripts,
+the configure or deconfigure the interface, then run another set of
+scripts.
+
+This is complicated slightly in that they also have to handle the
+possibility that some of an interface's required arguments may be missing
+(in which case none of the commands should be attempted), and that some
+of the commands may fail (in which case none of the following commands
+should be attempted). We've already encoded most of the early-abort
+logic for the latter case into the address family definitions; so the way
+we'll handle the the former case is simply to call the address family's
+method [[up()]] or [[down()]] twice: once to ensure all the variables are
+appropriately filled out, and once to actually configure the interface.
+
+\subsubsection{Command checking}
+
+As such, we'll make use of two execution functions, each of which take
+one parameter, a shell command. We'll uninventively call these [[doit()]]
+and [[check()]]. They'll return 0 on failure, non-zero on success.
+
+[[check()]] is thus fairly trivial:
+
+<<execute function declarations>>=
+static int check(char *str);
+@
+
+<<execute functions>>=
+static int check(char *str) {
+       return str != NULL;
+}
+@ 
+
+\subsubsection{Environment handling}
+
+[[doit()]] is much more complicated, mainly by the fact that we
+don't simply want to just run the programs, but because we also want
+to setup a sanitized environment. In particular, we want to make the
+environment variables [[IFACE]], and [[MODE]] available (eg, [[eth0]] and
+[[start]] respectively), and we want to export all the given options as
+[[IF_OPTION]], with some sanitisation.
+
+We'll do this just once per interface rather than once per command,
+and so we'll use a global variable to store our new environment, and a
+special function which will initialise it for us.
+
+<<execute global variables>>=
+static char **environ = NULL;
+@ 
+
+[[environ]] will be in the format used by the [[execle()]] function call,
+that is, a [[NULL]]-terminated array of strings of the form [[foo=bar]].
+
+<<execute function declarations>>=
+static void set_environ(interface_defn *iface, char *mode, char *phase);
+@
+
+Our function then will be:
+
+<<execute functions>>=
+static void set_environ(interface_defn *iface, char *mode, char *phase) {
+       <<variables local to set environ>>
+       int i;
+       const int n_env_entries = iface->n_options + 8;
+
+       <<initialise environ [[n_env_entries]]>>
+
+       for (i = 0; i < iface->n_options; i++) {
+               <<[[continue]] if option is a command>>
+
+               <<add [[IF_]]option to environment>>
+       }
+
+       <<add [[IFACE]] to environment>>
+       <<add [[LOGICAL]] to environment>>
+       <<add [[ADDRFAM]] to environment>>
+       <<add [[METHOD]] to environment>>
+
+       <<add [[MODE]] to environment>>
+       <<add [[PHASE]] to environment>>
+       <<add [[VERBOSITY]] to environment>>
+       <<add [[PATH]] to environment>>
+}
+@
+
+Since we keep adding at the end, we'll make use of a pointer to keep track
+of where the end actually is, namely:
+
+<<variables local to set environ>>=
+char **environend;
+@
+
+Initialising thus becomes:
+
+<<initialise environ [[n_env_entries]]>>=
+<<clear environ if necessary>>
+environ = malloc(sizeof(char*) * (n_env_entries + 1 /* for final NULL */));
+environend = environ; 
+*environend = NULL;
+@
+
+<<clear environ if necessary>>=
+if (environ != NULL) {
+       char **ppch;
+       for (ppch = environ; *ppch; ppch++) {
+               free(*ppch);
+               *ppch = NULL;
+       }
+       free(environ);
+       environ = NULL;
+}
+@
+
+Our continue chunk is also fairly straight forward:
+
+<<[[continue]] if option is a command>>=
+if (strcmp(iface->option[i].name, "pre-up") == 0
+    || strcmp(iface->option[i].name, "up") == 0
+    || strcmp(iface->option[i].name, "down") == 0
+    || strcmp(iface->option[i].name, "post-down") == 0)
+{
+       continue;
+}
+@
+
+We'll make use of a small helper function for actually setting the
+environment. This function will handle [[malloc]]ing enough memory, and
+ensuring the environment variable name is reasonably sensible. It'll
+take three parameters: a [[printf]]-style format string presumed to
+contain two [[%s]]s, and the two parameters to that format string.
+
+<<execute function declarations>>=
+static char *setlocalenv(char *format, char *name, char *value);
+@
+
+We can then go ahead and fill in the environment.
+
+<<add [[IF_]]option to environment>>=
+*(environend++) = setlocalenv("IF_%s=%s", iface->option[i].name,
+                              iface->option[i].value);
+*environend = NULL;
+@
+
+<<add [[IFACE]] to environment>>=
+*(environend++) = setlocalenv("%s=%s", "IFACE", iface->real_iface);
+*environend = NULL;
+@
+
+<<add [[LOGICAL]] to environment>>=
+*(environend++) = setlocalenv("%s=%s", "LOGICAL", iface->logical_iface);
+*environend = NULL;
+@
+
+<<add [[MODE]] to environment>>=
+*(environend++) = setlocalenv("%s=%s", "MODE", mode);
+*environend = NULL;
+@
+
+<<add [[PHASE]] to environment>>=
+*(environend++) = setlocalenv("%s=%s", "PHASE", phase); 
+*environend = NULL;
+@
+
+<<add [[PATH]] to environment>>=
+*(environend++) = setlocalenv("%s=%s", "PATH", "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin");
+*environend = NULL;
+@
+
+<<add [[VERBOSITY]] to environment>>=
+*(environend++) = setlocalenv("%s=%s", "VERBOSITY", verbose ? "1" : "0");
+*environend = NULL;
+@
+
+<<add [[ADDRFAM]] to environment>>=
+*(environend++) = setlocalenv("%s=%s", "ADDRFAM", iface->address_family->name);
+*environend = NULL;
+@
+
+<<add [[METHOD]] to environment>>=
+*(environend++) = setlocalenv("%s=%s", "METHOD", iface->method->name);
+*environend = NULL;
+@
+
+Our helper function then will then be something like:
+
+<<execute functions>>=
+static char *setlocalenv(char *format, char *name, char *value) {
+       char *result;
+
+       <<allocate memory for [[result]]>>
+
+       sprintf(result, format, name, value);
+
+       <<tidy [[result]]>>
+
+       return result;
+}
+@
+
+Allocating the memory is fairly straightforward (although working out
+exactly how much memory involves a little guesswork, and assuming the
+caller passes in a reasonable [[format]]).
+
+<<allocate memory for [[result]]>>=
+result = malloc(strlen(format)   /* -4 for the two %s's */
+                + strlen(name) 
+                + strlen(value) 
+                + 1);
+if (!result) {
+       perror("malloc");
+       exit(1);
+}
+@
+
+And finally, tidying the result is a fairly simple matter of eliding all
+the characters we don't like, or translating them to ones we do like. We
+do like upper case letters, digits and underscores; and we're willing
+to translate hyphens and lower case letters. So here we go.
+
+<<tidy [[result]]>>=
+{
+       char *here, *there;
+
+       for(here = there = result; *there != '=' && *there; there++) {
+               if (*there == '-') *there = '_';
+               if (isalpha(*there)) *there = toupper(*there);
+
+               if (isalnum(*there) || *there == '_') {
+                       *here = *there;
+                       here++;
+               }
+       }
+       memmove(here, there, strlen(there) + 1);
+}
+@
+
+\subsubsection{Command Execution}
+
+Our [[doit()]] function is then essentially a rewrite of the standard
+[[system()]] function call. The only additions are that we setup our
+child's environment as discussed previously, and we make use of two
+external globals, [[no_act]] and [[verbose]] and modify our behaviour
+based on those.
+
+<<execute function declarations>>=
+static int doit(char *str);
+@
+
+<<execute functions>>=
+static int doit(char *str) {
+       assert(str);
+
+       if (verbose || no_act) {
+               fprintf(stderr, "%s\n", str);
+       }
+       if (!no_act) {
+               pid_t child;
+               int status;
+
+               fflush(NULL);
+               switch(child = fork()) {
+                   case -1: /* failure */
+                       return 0;
+                   case 0: /* child */
+                       execle("/bin/sh", "/bin/sh", "-c", str, NULL, environ);
+                       exit(127);
+                   default: /* parent */
+                       break;
+               }
+               waitpid(child, &status, 0);
+               if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
+                       return 0;
+       }
+       return 1;
+}
+@
+
+\subsubsection{Executing a list of commands}
+
+In addition to the above, we also need a function to cope with running
+all the [[pre-up]] commands and so forth.
+
+<<exported symbols>>=
+int execute_all(interface_defn *ifd, execfn *exec, char *opt);
+@ 
+
+All we need to do for this is to iterate through the options in the
+interface definition, and execute whichever ones are the right type,
+and call the [[run-parts]] command on the appropriate directory of
+scripts. That doesn't make for thrilling code.
+
+This function will generally have [[doit]] passed in as the [[exec]]
+parameter.
+
+<<execute functions>>=
+int execute_all(interface_defn *ifd, execfn *exec, char *opt) {
+       int i;
+       char buf[100];
+       for (i = 0; i < ifd->n_options; i++) {
+               if (strcmp(ifd->option[i].name, opt) == 0) {
+                       if (!(*exec)(ifd->option[i].value)) {
+                               return 0;
+                       }
+               }
+       }
+
+       snprintf(buf, sizeof(buf), "run-parts %s /etc/network/if-%s.d",
+               verbose ? "--verbose" : "", opt);
+
+       (*exec)(buf); 
+
+       return 1;
+}
+@ 
+
+\subsubsection{[[iface_up()]] and [[iface_down()]]}
+
+Our functions, then are:
+
+<<exported symbols>>=
+int iface_up(interface_defn *iface);
+int iface_down(interface_defn *iface);
+@ 
+
+<<execute functions>>=
+int iface_up(interface_defn *iface) {
+       if (!iface->method->up(iface,check)) return -1;
+
+       set_environ(iface, "start", "pre-up");
+       if (!execute_all(iface,doit,"pre-up")) return 0;
+
+       if (!iface->method->up(iface,doit)) return 0;
+
+       set_environ(iface, "start", "post-up");
+       if (!execute_all(iface,doit,"up")) return 0;
+
+       return 1;
+}
+@ 
+
+<<execute functions>>=
+int iface_down(interface_defn *iface) {
+       if (!iface->method->down(iface,check)) return -1;
+
+       set_environ(iface, "stop", "pre-down");
+       if (!execute_all(iface,doit,"down")) return 0;
+
+       if (!iface->method->down(iface,doit)) return 0;
+
+       set_environ(iface, "stop", "post-down");
+       if (!execute_all(iface,doit,"post-down")) return 0;
+
+       return 1;
+}
+@ 
+
+\subsection{Command Parsing}
+
+All the above just leave one thing out: how the address family method's
+configuration function gets back to calling [[doit()]]. This function
+answers that question:
+
+<<exported symbols>>=
+int execute(char *command, interface_defn *ifd, execfn *exec);
+@ 
+
+At the somewhat abstract level, this is fairly trivial. The devil is
+in the details of the parsing, which makes up the rest of the module.
+
+<<execute functions>>=
+int execute(char *command, interface_defn *ifd, execfn *exec) { 
+       char *out;
+       int ret;
+
+       out = parse(command, ifd);
+       if (!out) { return 0; }
+
+       ret = (*exec)(out);
+
+       free(out);
+       return ret;
+}
+@ 
+
+We'll need a basic parser function, which we'll call [[parse()]], to
+make the appropriate substitutions into a command. It's probably worth
+a note as to exactly what substitutions may be made:
+
+\begin{itemize}
+
+       \item Special characters can be escaped with a backslash. eg
+       [[ls MoreThan80\%]].
+
+       \item Variables can be substituted by including their name
+       delimeted by percents. eg [[ls %directory%]].
+
+       \item Optional components may be enclosed in double square
+       brackets. Optional components will be included exactly when
+       every variable referenced within exists. eg
+       [[ls [[--color=%color%]]][[] %directory%]]. Optional components
+       may be nested.
+
+\end{itemize}
+
+Most of the parsing is fairly straightforward -- basically, we keep an
+output buffer, and add things to it as we stroll through the input
+buffer: either the actual character we want, or whatever the value of
+the variable we're looking at is, or whatever. The only particularly
+complicated bit is how we deal with the optional sections, which will
+be explained when we get to them.
+
+<<execute function declarations>>=
+static char *parse(char *command, interface_defn *ifd);
+@ 
+
+<<execute functions>>=
+static char *parse(char *command, interface_defn *ifd) {
+       <<variables local to parse>>
+
+       while(*command) {
+               switch(*command) {
+                       <<handle a token>>
+               }
+       }
+
+       <<deal with error conditions>>
+
+       <<return result>>
+}
+@
+
+\subsubsection{Maintain output buffer}
+
+So the first thing we need to do is actually write some code to deal
+with the output buffer, which will need to be dynamically resized and
+so on to take care of possibly long strings and what-not. It is the
+caller's responsibility to [[free()]] this buffer. We'll maintain two
+extra variables for convenience: who much memory we've allocated
+[[len]], and where the next character should be stuck [[pos]].
+
+<<variables local to parse>>=
+char *result = NULL;
+size_t pos = 0, len = 0;
+@ 
+
+This makes it pretty easy to return the result to the caller, too.
+
+<<return result>>=
+return result;
+@
+
+The main thing to be done to this buffer is to add characters or
+strings to it. To deal with this, we'll make use of an [[addstr()]]
+function that resizes the buffer as necessary, and appends a string to
+it. So we can deal with single characters, and substrings in general,
+we'll specify the string to be added as a pointer-length combination,
+rather than as a [[NUL]] terminated string.
+
+<<execute function declarations>>=
+void addstr(char **buf, size_t *len, size_t *pos, char *str, size_t strlen);
+@ 
+
+<<execute functions>>=
+void addstr(char **buf, size_t *len, size_t *pos, char *str, size_t strlen) {
+       assert(*len >= *pos);
+       assert(*len == 0 || (*buf)[*pos] == '\0');
+
+       if (*pos + strlen >= *len) {
+               char *newbuf;
+               newbuf = realloc(*buf, *len * 2 + strlen + 1);
+               if (!newbuf) {
+                       perror("realloc");
+                       exit(1); /* a little ugly */
+               }
+               *buf = newbuf;
+               *len = *len * 2 + strlen + 1;
+       }
+
+       while (strlen-- >= 1) {
+               (*buf)[(*pos)++] = *str;
+               str++;
+       }
+       (*buf)[*pos] = '\0';
+}
+@ 
+
+Given this, we can define our default behaviour for a character:
+
+<<handle a token>>=
+default:
+       addstr(&result, &len, &pos, command, 1);
+       command++;
+       break;
+@ 
+
+\subsubsection{Escaped characters}
+
+We can also deal pretty simply with escaped tokens. The only special
+circumstance is if the [[\]] is at the very end of string. We don't
+want buffer overflows afterall.
+
+<<handle a token>>=
+case '\\':
+       if (command[1]) {
+               addstr(&result, &len, &pos, command+1, 1);
+               command += 2;
+       } else {
+               addstr(&result, &len, &pos, command, 1);
+               command++;
+       }
+       break;
+@ 
+
+\subsubsection{Optional components}
+
+Basically we keep track of each optional section we're in, whether
+we've been unable to fill in any variables, and where we started
+it. When we reach the end of an optional section, we check to see if
+we were unable to fill in any variables, and, if so, we discard any
+text we'd added within that block. This also allows us to neatly check
+for any errors trying to fill in variables that aren't in optional
+sections.
+
+Basically what we'll do here is keep one stack to represent where the
+various thingos started, and another to represent whether any
+variables didn't exist. We'll use the bottom-most entry in the stack
+to represent the entire command, and thus keep track of whether or not
+we have to return an error because an undefined variable was used in a
+non-optional part of the command.
+
+<<constant definitions>>=
+#define MAX_OPT_DEPTH 10
+@ 
+
+<<variables local to parse>>=
+size_t old_pos[MAX_OPT_DEPTH] = {0};
+int okay[MAX_OPT_DEPTH] = {1};
+int opt_depth = 1;
+@ 
+
+Given this, when we encounter a double open bracket, we need to just
+add the appropriate values to our stacks, and, similarly, when we
+encounter a double close bracket, we simply need to pop the stack, and
+see whether we need to move back or not, as well as taking care of an
+possible errors, naturally. \emph{We probably could actually give
+error messages here instead of just treating the brackets literally
+when they might cause problems. But there doesn't seem much point,
+really. --- aj}
+
+<<handle a token>>=
+case '[':
+       if (command[1] == '[' && opt_depth < MAX_OPT_DEPTH) {
+               old_pos[opt_depth] = pos;
+               okay[opt_depth] = 1;
+               opt_depth++;
+               command += 2;
+       } else {
+               addstr(&result, &len, &pos, "[", 1);
+               command++;
+       }
+       break;
+@ 
+
+<<handle a token>>=
+case ']':
+       if (command[1] == ']' && opt_depth > 1) {
+               opt_depth--;
+               if (!okay[opt_depth]) {
+                       pos = old_pos[opt_depth];
+                       result[pos] = '\0';
+               }
+               command += 2;
+       } else {
+               addstr(&result, &len, &pos, "]", 1);
+               command++;
+       }
+       break;
+@
+
+Finally, at the end of the function, the stacks can be left in an
+unacceptable state --- either one of the optional blocks was never
+closed, or an undefined variable was used elsewhere. We'll note these
+circumstances by returning [[NULL]] and setting [[errno]].
+
+<<execute headers>>=
+#include <errno.h>
+@
+
+<<constant definitions>>=
+#define EUNBALBRACK 10001
+#define EUNDEFVAR   10002
+@ 
+
+<<deal with error conditions>>=
+if (opt_depth > 1) {
+       errno = EUNBALBRACK;
+       free(result);
+       return NULL;
+}
+
+if (!okay[0]) {
+       errno = EUNDEFVAR;
+       free(result);
+       return NULL;
+}
+@ 
+
+\subsubsection{Variables}
+
+Dealing with variables is comparatively fairly simple. We just need to
+find the next percent, and see if whatever's in-between is a variable,
+and, if so, get it's value.
+
+<<constant definitions>>=
+#define MAX_VARNAME    32
+#define EUNBALPER   10000
+@ 
+
+<<handle a token>>=
+case '%':
+{
+       <<variables local to handle percent token>>
+       char *varvalue;
+
+       <<determine variable name>>
+
+       <<get [[varvalue]]>>
+
+       if (varvalue) {
+               addstr(&result, &len, &pos, varvalue, strlen(varvalue));
+       } else {
+               okay[opt_depth - 1] = 0;
+       }
+
+       <<move to token after closing percent>>
+
+       break;
+}
+@ 
+
+We don't do anything particularly clever dealing with the next percent
+--- just a pointer to the appropriate character.
+
+<<variables local to handle percent token>>=
+char *nextpercent;
+@ 
+
+<<determine variable name>>=
+command++;
+nextpercent = strchr(command, '%');
+if (!nextpercent) {
+       errno = EUNBALPER;
+       free(result);
+       return NULL;
+}
+@ 
+
+<<move to token after closing percent>>=
+command = nextpercent + 1;
+@
+
+The slightly tricky thing we do here is use a [[strncmpz]] function,
+which allows us to check that a string represented by a [[char*]] and
+a length is the same as a [[NUL]] terminated string.
+
+<<execute function declarations>>=
+int strncmpz(char *l, char *r, size_t llen);
+@ 
+
+<<execute functions>>=
+int strncmpz(char *l, char *r, size_t llen) {
+       int i = strncmp(l, r, llen);
+       if (i == 0)
+               return -r[llen];
+       else
+               return i;
+}
+@ 
+
+Given the above, the implementation of the [[get_var()]] function to
+lookup the value of a variable, is reasonably straight forward.
+
+<<execute function declarations>>=
+char *get_var(char *id, size_t idlen, interface_defn *ifd);
+@ 
+
+<<execute functions>>=
+char *get_var(char *id, size_t idlen, interface_defn *ifd) {
+       int i;
+
+       if (strncmpz(id, "iface", idlen) == 0) {
+               return ifd->real_iface;
+       } else {
+               for (i = 0; i < ifd->n_options; i++) {
+                       if (strncmpz(id, ifd->option[i].name, idlen) == 0) {
+                               return ifd->option[i].value;
+                       }
+               }
+       }
+
+       return NULL;
+}
+@ 
+
+Which means we can finish of the chunk, thus:
+
+<<get [[varvalue]]>>=
+varvalue = get_var(command, nextpercent - command, ifd);
+@ 
+
+\subsection{Mapping Scripts}
+
+Doing a mapping is moderately complicated, since we need to pass a
+fair bit of stuff to the script. The way we'll do this is via a
+mixture of command line arguments, and [[stdin]]: basically, we'll
+pass all the mapping variables from the interfaces file via [[stdin]],
+and anything else necessary will be a command line argument. The
+script will be expected to exit successfully with the appropriate
+logical interface as the first line of [[stdout]] if it made a match,
+or exit unsuccessfully (error code [[1]], eg) otherwise.
+
+<<exported symbols>>=
+int run_mapping(char *physical, char *logical, int len, mapping_defn *map);
+@ 
+
+<<execute functions>>=
+int run_mapping(char *physical, char *logical, int len, mapping_defn *map) {
+       FILE *in, *out;
+       int i, status;
+       pid_t pid;
+
+       <<execute the mapping script>>
+       <<send input to mapping script>>
+       <<wait for mapping script to finish>>
+       <<check output from mapping script>>
+
+       return 1;
+}
+@ 
+
+The latter options here are fairly straightforward, given some Unix
+knowledge.
+
+<<send input to mapping script>>=
+for (i = 0; i < map->n_mappings; i++) {
+       fprintf(in, "%s\n", map->mapping[i]);
+}
+fclose(in);
+@ 
+
+<<wait for mapping script to finish>>=
+waitpid(pid, &status, 0);
+@ 
+
+<<check output from mapping script>>=
+if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
+       if (fgets(logical, len, out)) {
+               char *pch = logical + strlen(logical) - 1;
+               while (pch >= logical && isspace(*pch)) 
+                       *(pch--) = '\0';
+       }
+}
+fclose(out);   
+@ 
+
+Slightly more complicated is setting up the child process and grabbing
+its [[stdin]] and [[stdout]]. Unfortunately we can't just use
+[[popen()]] for this, since it'll only allow us to go one way. So,
+instead we'll write our own [[popen()]]. It'll look like:
+
+<<execute headers>>=
+#include <stdarg.h>
+@ 
+
+<<execute function declarations>>=
+static int popen2(FILE **in, FILE **out, char *command, ...);
+@ 
+
+The varargs component will be the arguments, as per [[execl()]], and
+the return value will be the [[PID]] if the call was successful, or 0
+otherwise.
+
+As such, we will be able to execute the script thusly:
+
+<<execute the mapping script>>=
+pid = popen2(&in, &out, map->script, physical, NULL);
+if (pid == 0) {
+       return 0;
+}
+@ 
+
+Writing [[popen2()]] is an exercise in Unix arcana.
+
+<<execute headers>>=
+#include <unistd.h>
+#include <sys/wait.h>
+@ 
+
+<<execute functions>>=
+static int popen2(FILE **in, FILE **out, char *command, ...) {
+       va_list ap;
+       char *argv[11] = {command};
+       int argc;
+       int infd[2], outfd[2];
+       pid_t pid;
+
+       argc = 1;
+       va_start(ap, command);
+       while((argc < 10) && (argv[argc] = va_arg(ap, char*))) {
+               argc++;
+       }
+       argv[argc] = NULL; /* make sure */
+       va_end(ap);
+
+       if (pipe(infd) != 0) return 0;
+       if (pipe(outfd) != 0) {
+               close(infd[0]); close(infd[1]);
+               return 0;
+       }
+
+       fflush(NULL);
+       switch(pid = fork()) {
+               case -1: /* failure */
+                       close(infd[0]); close(infd[1]);
+                       close(outfd[0]); close(outfd[1]);
+                       return 0;
+               case 0: /* child */
+                       dup2(infd[0], 0);
+                       dup2(outfd[1], 1);
+                       close(infd[0]); close(infd[1]);
+                       close(outfd[0]); close(outfd[1]);
+                       execvp(command, argv);
+                       exit(127);
+               default: /* parent */
+                       *in = fdopen(infd[1], "w");
+                       *out = fdopen(outfd[0], "r");
+                       close(infd[0]); close(outfd[1]);
+                       return pid;
+       }
+       /* unreached */
+}
+@
+
+\section{The Driver}
+
+The final C module we'll have is the one with the [[main()]]
+function. It's put together in a fairly straightforward way.
+
+<<main.c>>=
+<<main headers>>
+<<main global variables>>
+<<main function declarations>>
+<<main functions>>
+<<main>>
+@ 
+
+Equally, there's nothing particularly special about our headers.
+
+<<main headers>>=
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "header.h"
+@
+
+Now, after all the above modules, our main program doesn't have too
+much to do: it just has to interpret arguments and coordinate the
+intervening modules. Since we're being ``smart'', as well as parsing
+arguments, we'll decide whether the interface is going up or down
+depending on whether we were called as [[ifup]] or [[ifdown]].
+
+<<main>>=
+int main(int argc, char **argv) {
+       <<variables local to main>>
+
+       <<ensure environment is sane>>
+
+       <<parse command name or die>>
+       <<parse arguments>>
+
+       <<read interfaces files or die>>
+
+       <<run commands for appropriate interfaces>>
+
+       return 0;
+}
+@
+
+\subsection{Check the Environment}
+
+In the earlier code we assume that we have stdin, stdout and stderr all
+available. We need to assure that, just in case:
+
+<<main headers>>=
+#include <unistd.h>
+#include <fcntl.h>
+@
+
+<<ensure environment is sane>>=
+{
+       int i;
+       for (i = 0; i <= 2; i++) {
+               if (fcntl(i, F_GETFD) == -1) {
+                       if (errno == EBADF && open("/dev/null", 0) == -1) {
+                               fprintf(stderr,
+                                       "%s: fd %d not available; aborting\n",
+                                       argv[0], i);
+                               exit(2);
+                       } else if (errno == EBADF) {
+                               errno = 0; /* no more problems */
+                       } else {
+                               /* some other problem -- eeek */
+                               perror(argv[0]);
+                               exit(2);
+                       }
+               }
+       }
+}
+@
+
+\subsection{Configuring or Deconfiguring?}
+
+So the very first real thing we need to do is parse the command name. To
+do this, we'll obviously need to work out somewhere to store the result. A
+reasonable thing to do here is just to keep a function pointer about,
+which will point to one of the previously defined [[iface_up]] or
+[[iface_down]] functions, depending on which should be used on the
+specified interfaces.
+
+<<variables local to main>>=
+int (*cmds)(interface_defn *) = NULL;
+@
+
+So given this, we can just:
+
+<<parse command name or die>>=
+{
+       char *command;
+
+       <<set [[command]] to the base of the command name>>
+       <<set [[cmds]] based on [[command]] or die>>
+}
+@
+
+And fill out each component in the reasonably obvious manner of:
+
+<<set [[command]] to the base of the command name>>=
+if ((command = strrchr(argv[0],'/'))) {
+       command++; /* first char after / */
+} else {
+       command = argv[0]; /* no /'s in argv[0] */
+}
+@
+
+<<set [[cmds]] based on [[command]] or die>>=
+if (strcmp(command, "ifup")==0) {
+       cmds = iface_up;
+} else if (strcmp(command, "ifdown")==0) {
+       cmds = iface_down;
+} else {
+       fprintf(stderr,"This command should be called as ifup or ifdown\n");
+       exit(1);
+}
+@ 
+
+In addition, since our later behaviour varies depending on whether we're
+bringing interfaces up or taking them down we'll define two chunks to assist
+with this, namely:
+
+<<we're bringing interfaces up>>=
+(cmds == iface_up)
+@
+
+<<we're taking interfaces down>>=
+(cmds == iface_down)
+@
+
+The [[--allow]] option lets us limit the interfaces ifupdown will act on.
+It's implemented by having an [[allow_class]] that tells us which class
+of interfaces we're working with, and skipping interfaces that aren't
+in that class, like so:
+
+<<we're limiting to [[--allow]]ed interfaces>>=
+(allow_class != NULL)
+
+<<find [[iface]] in [[allow_class]] or [[continue]]>>=
+{
+       int i;
+       allowup_defn *allowup = find_allowup(defn, allow_class);
+       if (allowup == NULL)
+               continue;
+
+       for (i = 0; i < allowup->n_interfaces; i++) {
+               if (strcmp(allowup->interfaces[i], iface) == 0)
+                       break;
+       }
+       if (i >= allowup->n_interfaces)
+               continue;
+}
+@
+
+Finally, the behaviour might vary depending on whether we are 
+excluding this interface or not. Notice that
+the exclude option can use a full interface name or substrings that
+match interfaces. A user could easily have unexpected behaviour
+if he uses a small string to do the match:
+
+<<we're [[--exclude]]ing this interface>>=
+(excludeint != NULL && strstr(iface,excludeint) != NULL)
+@
+
+\subsection{Argument Handling}
+
+Okay, so next on our agenda is argument handling.
+
+We'll do argument handling via the GNU [[getopt]] function, which
+means we have to include the appropriate header, and define a cute
+little structure to represent out long options:
+
+<<main headers>>=
+#include <getopt.h>
+@
+
+<<variables local to main>>=
+struct option long_opts[] = {
+       {"help",        no_argument,       NULL, 'h'},
+       {"version",     no_argument,       NULL, 'V'},
+       {"verbose",     no_argument,       NULL, 'v'},
+       {"all",         no_argument,       NULL, 'a'},
+       {"allow",       required_argument, NULL,  3 },
+       {"interfaces",  required_argument, NULL, 'i'},
+       {"exclude",     required_argument, NULL, 'e'},
+       {"no-act",      no_argument,       NULL, 'n'},
+       {"no-mappings", no_argument,       NULL,  1 },
+       {"force",       no_argument,       NULL,  2 },
+       {0,0,0,0}
+};
+@ 
+
+The usual way of dealing with options then is to have a variable to store
+the various things. The only special note here is that we need to export
+[[no_act]] and [[verbose]] to the [[execute]] module.
+
+<<exported symbols>>=
+extern int no_act;
+extern int verbose;
+@
+
+<<main global variables>>=
+int no_act = 0;
+int verbose = 0;
+@
+
+<<variables local to main>>=
+int do_all = 0;
+int run_mappings = 1;
+int force = 0;
+char *allow_class = NULL;
+char *interfaces = "/etc/network/interfaces";
+char *statefile = "/etc/network/run/ifstate";
+char *excludeint = NULL ;
+@ 
+
+We'll also have two helper functions to display usage information,
+like so:
+
+<<main function declarations>>=
+static void usage(char *execname);
+static void help(char *execname);
+static void version(char *execname);
+@ 
+
+<<main functions>>=
+static void usage(char *execname) {
+       fprintf(stderr, "%s: Use --help for help\n", execname);
+       exit(1);
+}
+@ 
+
+<<main functions>>=
+static void version(char *execname) {
+       printf("%s version " IFUPDOWN_VERSION "\n", execname);
+       printf("Copyright (c) 1999-2005 Anthony Towns\n\n");
+       printf(
+
+"This program is free software; you can redistribute it and/or modify\n"
+"it under the terms of the GNU General Public License as published by\n"
+"the Free Software Foundation; either version 2 of the License, or (at\n"
+"your option) any later version.\n"
+
+       );
+       exit(0);
+}
+@ 
+
+<<main functions>>=
+static void help(char *execname) {
+       printf("Usage: %s <options> <ifaces...>\n\n", execname);
+       printf("Options:\n");
+       printf("\t-h, --help\t\tthis help\n");
+       printf("\t-V, --version\t\tcopyright and version information\n");
+       printf("\t-a, --all\t\tde/configure all interfaces marked \"auto\"\n");
+       printf("\t--allow CLASS\t\tignore non-\"allow-CLASS\" interfaces\n");
+       printf("\t-i, --interfaces FILE\tuse FILE for interface definitions\n");
+       printf("\t-n, --no-act\t\tprint out what would happen, but don't do it\n");
+       printf("\t\t\t\t(note that this option doesn't disable mappings)\n");
+       printf("\t-v, --verbose\t\tprint out what would happen before doing it\n");
+       printf("\t--no-mappings\t\tdon't run any mappings\n");
+       printf("\t--force\t\t\tforce de/configuration\n");
+       exit(0);
+}
+@ 
+
+Now, the meat of argument parsing is done with [[getopt()]] and a
+[[switch]], like so:
+
+<<parse arguments>>=
+for(;;) {
+       int c;
+       c = getopt_long(argc, argv, "e:s:i:hVvna", long_opts, NULL);
+       if (c == EOF) break;
+
+       switch(c) {
+               <<[[getopt]] possibilities>>
+       }
+}
+
+<<check unreasonable arguments>>
+@ 
+
+Now, our [[getopt]] possibilities are basically each option, or something
+really bad. Actual interface names are automagically collected at the end
+by [[getopt()]].So first, the legitimate cases get handled:
+
+<<[[getopt]] possibilities>>=
+case 'i':
+       interfaces = strdup(optarg);
+       break;
+@ 
+<<[[getopt]] possibilities>>=
+case 'v':
+       verbose = 1;
+       break;
+@ 
+<<[[getopt]] possibilities>>=
+case 'a':
+       do_all = 1;
+       break;
+@ 
+<<[[getopt]] possibilities>>=
+case 3:
+       allow_class = strdup(optarg);
+       break;
+@ 
+<<[[getopt]] possibilities>>=
+case 'n':
+       no_act = 1;
+       break;
+@ 
+<<[[getopt]] possibilities>>=
+case 1:
+       run_mappings = 0;
+       break;
+@ 
+<<[[getopt]] possibilities>>=
+case 2:
+       force = 1;
+       break;
+@
+<<[[getopt]] possibilities>>=
+case 'e':
+       excludeint = strdup(optarg);
+       break;
+@ 
+
+And we also have a help option and a version option:
+
+<<[[getopt]] possibilities>>=
+case 'h':
+       help(argv[0]);
+       break;
+@ 
+<<[[getopt]] possibilities>>=
+case 'V':
+       version(argv[0]);
+       break;
+@ 
+
+And we also have the possibility that the user is just making up
+options:
+
+<<[[getopt]] possibilities>>=
+default:
+       usage(argv[0]);
+       break;
+@
+
+After all that there are still some things that can be a bit weird. We
+can be told either to act on all interfaces (except the noauto ones),
+or we can be told to act on specific interface. We won't accept been
+told to do both, and we won't accept not being told to do one or the
+other. We can test these two cases as follows:
+
+<<check unreasonable arguments>>=
+if (argc - optind > 0 && do_all) {
+       usage(argv[0]);
+}
+@ 
+
+<<check unreasonable arguments>>=
+if (argc - optind == 0 && !do_all) {
+       usage(argv[0]);
+}
+@ 
+
+\subsection{Reading the Interfaces File}
+
+Since this has all been covered in a previous section, this is pretty
+trivial.
+
+<<variables local to main>>=
+interfaces_file *defn;
+@ 
+
+<<read interfaces files or die>>=
+defn = read_interfaces(interfaces);
+if ( !defn ) {
+       fprintf(stderr, "%s: couldn't read interfaces file \"%s\"\n",
+               argv[0], interfaces);
+       exit(1);
+}
+@
+
+\subsection{Execution}
+
+A broad overview of what we'll actually be doing is as follows:
+
+<<run commands for appropriate interfaces>>=
+<<lock 'n load ifupdown state>>
+<<determine target interfaces>>
+{
+       int i;
+       for (<<each target interface, [[i]]>>) {
+               char iface[80], liface[80];
+
+               <<initialize [[iface]] to [[i]]th target interface>>
+               if (!force) {
+                       <<check ifupdown state (possibly [[continue]])>>
+               }
+
+               if (<<we're limiting to [[--allow]]ed interfaces>>) {
+                       <<find [[iface]] in [[allow_class]] or [[continue]]>>
+               }
+
+               if (<<we're [[--exclude]]ing this interface>>)  
+                       continue;
+
+               if (<<we're bringing interfaces up>> && run_mappings) {
+                       <<run mappings>>
+               }
+
+               <<bring interface up/down and update ifupdown state>>
+               <<commit ifupdown state>>
+       }
+}
+<<close ifupdown state>>
+@
+
+We'll leave determining the appropriate target interfaces and dealing
+with the state until a little later. That leaves us with covering running
+the mappings and bringing the interface up or taking it down.
+
+Mappings are dealt with like so:
+
+<<run mappings>>=
+{
+       mapping_defn *currmap;
+       for (currmap = defn->mappings; currmap; currmap = currmap->next) {
+               int i;
+               for (i = 0; i < currmap->n_matches; i++) {
+                       <<[[continue]] unless mapping matches>>
+                       <<run mapping>>
+                       break;
+               }
+       }
+}
+@
+
+We check if mappings match by using shell globs, so we'll need a new header
+to take care of that.
+
+<<main headers>>=
+#include <fnmatch.h>
+@ 
+
+<<[[continue]] unless mapping matches>>=
+if (fnmatch(currmap->match[i], liface, 0) != 0)
+       continue;
+@
+
+Actually running a mapping is fairly straightforward, thanks to our
+previous handywork.
+
+<<run mapping>>=
+if (verbose) {
+       fprintf(stderr, "Running mapping script %s on %s\n",
+               currmap->script, liface);
+}
+run_mapping(iface, liface, sizeof(liface), currmap);
+@
+
+Bringing an interface up or taking it down can be done thusly:
+
+<<bring interface up/down and update ifupdown state>>=
+{
+       interface_defn *currif;
+       int okay = 0;
+       int failed = 0; 
+       for (currif = defn->ifaces; currif; currif = currif->next) {
+               if (strcmp(liface, currif->logical_iface) == 0) {
+                       okay = 1;
+
+                       <<run commands for [[currif]]; set [[failed]] on error>>
+
+                       if (failed) break;
+                       /* Otherwise keep going: this interface may have
+                        * match with other address families */
+               }
+       }
+
+       if (!okay && !force) {
+               fprintf(stderr, "Ignoring unknown interface %s=%s.\n", 
+                       iface, liface);
+       } else {
+               <<update ifupdown state>>
+       }
+}
+@
+
+<<run commands for [[currif]]; set [[failed]] on error>>=
+{
+       currif->real_iface = iface;
+
+       if (verbose) {
+               fprintf(stderr, "Configuring interface %s=%s (%s)\n", 
+                       iface, liface, currif->address_family->name);
+       }
+
+       switch(cmds(currif)) {
+           case -1:
+               printf("Don't seem to be have all the variables for %s/%s.\n", 
+                       liface, currif->address_family->name);
+               failed = 1;
+               break;
+           case 0:
+               failed = 1;
+               break;
+               /* not entirely successful */
+           case 1:
+               failed = 0;
+               break;
+               /* successful */
+           default:
+               printf("Internal error while configuring interface %s/%s (assuming it failed)\n", 
+                       liface, currif->address_family->name);
+               failed = 1;
+               /* what happened here? */
+       }
+       currif->real_iface = NULL;
+}
+@ 
+
+\subsection{Target Interfaces}
+
+So, if we're going to actually do something, we should probably figure
+out exactly what we're going to do it to. So, we need to know the set
+of interfaces we're going to hax0r. This is just an array of interfaces,
+either [[physical_iface]] or [[physical_iface=logical_iface]].
+
+<<variables local to main>>=
+int n_target_ifaces;
+char **target_iface;
+@ 
+
+<<each target interface, [[i]]>>=
+i = 0; i < n_target_ifaces; i++
+@
+
+We initialise this based on our command line arguments.
+
+<<determine target interfaces>>=
+if (do_all) {
+       if (<<we're bringing interfaces up>>) {
+               allowup_defn *autos = find_allowup(defn, "auto");
+               target_iface = autos ? autos->interfaces : NULL;
+               n_target_ifaces = autos ? autos->n_interfaces : 0;
+       } else if (<<we're taking interfaces down>>) {
+               target_iface = state;
+               n_target_ifaces = n_state;
+       } else {
+               assert(0);
+       }       
+} else {
+       target_iface = argv + optind;
+       n_target_ifaces = argc - optind;
+}
+@ 
+
+<<initialize [[iface]] to [[i]]th target interface>>=
+strncpy(iface, target_iface[i], sizeof(iface));
+iface[sizeof(iface)-1] = '\0';
+
+{
+       char *pch;
+       if ((pch = strchr(iface, '='))) {
+               *pch = '\0';
+               strncpy(liface, pch+1, sizeof(liface));
+               liface[sizeof(liface)-1] = '\0';
+       } else {
+               strncpy(liface, iface, sizeof(liface));
+               liface[sizeof(liface)-1] = '\0';
+       }
+}
+@ 
+
+\subsection{State}
+
+Since it's generally not feasible to rerun a mapping script after an
+interface is configured (since a mapping script may well bring the
+interface down while it's investigating matters), we need to maintain a
+statefile between invocations to keep track of which physical interfaces
+were mapped to which logical ones. We ought to use 
+[[/var/run/ifupdown.state]] or something similar for this, but [[/var]]
+isn't guaranteed to be available until the network's up, so we'll use
+[[/etc/network/run/ifstate]] instead.
+
+<<variables local to main>>=
+char **state = NULL; /* list of iface=liface */
+int n_state = 0;
+int max_state = 0;
+@ 
+
+We'll also use two helper functions: one to lookup an interface, and one to
+add an interface.
+
+<<main function declarations>>=
+static int lookfor_iface(char **ifaces, int n_ifaces, char *iface);
+@ 
+
+<<main functions>>=
+static int lookfor_iface(char **ifaces, int n_ifaces, char *iface) {
+       int i;
+       for (i = 0; i < n_ifaces; i++) {
+               if (strncmp(iface, ifaces[i], strlen(iface)) == 0) {
+                       if (ifaces[i][strlen(iface)] == '=') {
+                               return i;
+                       }
+               }
+       }
+       return -1;
+}
+@ 
+
+<<main function declarations>>=
+static void add_to_state(char ***ifaces, int *n_ifaces, int *max_ifaces, 
+                         char *new_iface);
+@ 
+
+<<main functions>>=
+static void add_to_state(char ***ifaces, int *n_ifaces, int *max_ifaces, 
+                         char *new_iface)
+{
+       assert(*max_ifaces >= *n_ifaces);
+       if (*max_ifaces == *n_ifaces) {
+               *max_ifaces = (*max_ifaces * 2) + 1;
+               *ifaces = realloc(*ifaces, sizeof(**ifaces) * *max_ifaces);
+               if (*ifaces == NULL) {
+                       perror("realloc");
+                       exit(1);
+               }
+       }
+
+       (*ifaces)[(*n_ifaces)++] = new_iface;
+}
+@ 
+
+The state file is opened and locked, blocking parallel updates:
+
+<<main function declarations>>=
+static int lock_fd (int fd);
+@ 
+
+<<main functions>>=
+static int lock_fd (int fd) {
+       struct flock lock;
+
+       lock.l_type = F_WRLCK;
+       lock.l_whence = SEEK_SET;
+       lock.l_start = 0;
+       lock.l_len = 0;
+
+       if  (fcntl(fd, F_SETLKW, &lock) < 0) {
+               return -1;
+       }
+
+       return 0;
+}
+@ 
+
+
+<<variables local to main>>=
+static FILE *state_fp = NULL;
+@
+
+<<lock 'n load ifupdown state>>=
+{
+       state_fp = fopen(statefile, no_act ? "r" : "a+");
+       if (state_fp == NULL && !no_act) {
+               fprintf(stderr, 
+                       "%s: failed to open statefile %s: %s\n",
+                       argv[0], statefile, strerror(errno));
+               exit (1);
+       }
+
+       if (state_fp != NULL) {
+               char buf[80];
+               char *p;
+
+               if (!no_act) {
+                       int flags;
+
+                       if ((flags = fcntl(fileno(state_fp), F_GETFD)) < 0
+                           || fcntl(fileno(state_fp), F_SETFD, flags | FD_CLOEXEC) < 0) {
+                               fprintf(stderr, 
+                                       "%s: failed to set FD_CLOEXEC on statefile %s: %s\n",
+                                       argv[0], statefile, strerror(errno));
+                               exit(1);
+                       }
+
+                       if (lock_fd (fileno(state_fp)) < 0) {
+                               fprintf(stderr, 
+                                       "%s: failed to lock statefile %s: %s\n",
+                                       argv[0], statefile, strerror(errno));
+                               exit(1);
+                       }
+
+               }
+
+               rewind (state_fp);
+               while((p = fgets(buf, sizeof buf, state_fp)) != NULL) {
+                       char *pch;
+
+                       pch = buf + strlen(buf) - 1;
+                       while(pch > buf && isspace(*pch)) pch--;
+                       *(pch+1) = '\0';
+
+                       pch = buf;
+                       while(isspace(*pch)) pch++;
+
+                       add_to_state(&state, &n_state, &max_state, strdup(pch));
+               }
+       }
+}
+@
+
+<<close ifupdown state>>=
+if (state_fp != NULL) {
+       fclose(state_fp);
+       state_fp = NULL;
+}
+@
+
+
+<<commit ifupdown state>>=
+if (state_fp != NULL && !no_act) {
+       int i;
+
+       if (ftruncate(fileno(state_fp), 0) < 0)
+       {
+               fprintf(stderr, 
+                       "%s: failed to truncate statefile %s: %s\n",
+                       argv[0], statefile, strerror(errno));
+               exit(1);
+       }
+
+       rewind(state_fp);
+       for (i = 0; i < n_state; i++) {
+               fprintf(state_fp, "%s\n", state[i]);
+       }
+       fflush(state_fp);
+}
+@
+
+This leaves our two useful chunks. The first checks to ensure what we're
+proposing to do is reasonable (ie, we're not downing an interface that's
+not up, or uping one that's not down).
+
+<<check ifupdown state (possibly [[continue]])>>=
+{
+       int already_up = lookfor_iface(state, n_state, iface);;
+
+       if (<<we're bringing interfaces up>>) {
+               if (already_up != -1) {
+                       fprintf(stderr, 
+                               "%s: interface %s already configured\n",
+                               argv[0], iface);
+                       continue;
+               }
+       } else if (<<we're taking interfaces down>>) {
+               if (already_up == -1) {
+                       fprintf(stderr, "%s: interface %s not configured\n",
+                               argv[0], iface);
+                       continue;
+               }
+               strncpy(liface, strchr(state[already_up], '=') + 1, 80);
+               liface[79] = 0;
+       } else {
+               assert(0);
+       }
+}
+@ 
+
+And finally, we also need to be able to update the state as we bring
+interfaces up and down.
+
+<<update ifupdown state>>=
+{
+       int already_up = lookfor_iface(state, n_state, iface);
+
+       if (<<we're bringing interfaces up>>) {
+               char *newiface = 
+                       malloc(strlen(iface) + 1 + strlen(liface) + 1);
+               sprintf(newiface, "%s=%s", iface, liface);
+
+               if (already_up == -1) {
+                       if (failed == 1) {
+                               printf("Failed to bring up %s.\n", liface);
+                       } else {
+                               add_to_state(&state, &n_state, &max_state, newiface);
+                       }
+               } else {
+                       free(state[already_up]);
+                       state[already_up] = newiface;
+               }
+       } else if (<<we're taking interfaces down>>) {
+               if (already_up != -1) {
+                       state[already_up] = state[--n_state];
+               }
+       } else {
+               assert(0);
+       }
+}
+@ 
+
+\appendix
+
+\section{Linux Address Families}
+
+<<archlinux.h>>=
+unsigned int mylinuxver();
+unsigned int mylinux(int,int,int);
+int execable(char *);
+@
+
+<<archlinux.c>>=
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/utsname.h>
+#include <sys/stat.h>
+
+#include "archlinux.h"
+
+unsigned int mylinuxver() {
+       static int maj = -1, rev, min;
+
+       if (maj == -1) {
+               struct utsname u;
+               char *pch;
+               uname(&u);
+               maj = atoi(u.release);
+               pch = strchr(u.release, '.');
+               rev = atoi(pch+1);
+               pch = strchr(pch+1, '.');
+               min = atoi(pch+1);
+       }
+
+       return mylinux(maj,rev,min);
+}
+
+unsigned int mylinux(int maj, int rev, int min) { 
+       return min | rev << 10 | maj << 13;
+}
+
+int execable(char *program) {
+       struct stat buf;
+
+       if (0 == stat(program, &buf)) {
+               if (S_ISREG(buf.st_mode) && (S_IXUSR & buf.st_mode)) return 1;
+       }
+       return 0;
+}
+@ 
+
+\subsection{IPv4 Address Family}
+
+<<address family declarations>>=
+extern address_family addr_inet;
+@ 
+
+<<address family references>>=
+&addr_inet, 
+@ 
+
+<<inet.defn>>=
+address_family inet
+architecture linux
+
+<<inet methods>>
+@ 
+
+<<inet methods>>=
+method loopback
+  description
+    This method may be used to define the IPv4 loopback interface.
+
+  up
+    ifconfig %iface% 127.0.0.1 up
+    route add -net 127.0.0.0       if ( mylinuxver() < mylinux(2,1,100) )
+
+  down
+    ifconfig %iface% down
+@ 
+
+<<inet methods>>=
+method static
+  description
+    This method may be used to define ethernet interfaces with statically
+    allocated IPv4 addresses.
+      
+  options
+    address address             -- Address (dotted quad) *required*
+    netmask netmask             -- Netmask (dotted quad) *required*
+    broadcast broadcast_address -- Broadcast address (dotted quad)
+    network network_address     -- Network address (dotted quad) *required \
+                                     for 2.0.x kernels*
+    metric metric               -- Routing metric for default gateway (integer)
+    gateway address             -- Default gateway (dotted quad)
+    pointopoint address                -- Address of other end point (dotted quad). \
+                                  Note the spelling of "point-to".
+    media type                  -- Medium type, driver dependent
+    hwaddress class address     -- Hardware Address. /class/ is one of \
+                                     *ether*, *ax25*, *ARCnet* or *netrom*. \
+                                     /address/ is dependent on the above \
+                                     choice.
+    mtu size                    -- MTU size
+
+  up
+    [[ ifconfig %iface% hw %hwaddress%]]
+    ifconfig %iface% %address% netmask %netmask% [[broadcast %broadcast%]] \
+       [[pointopoint %pointopoint%]] [[media %media%]] [[mtu %mtu%]] \
+       up
+    route add -net %network%  \
+        if ( mylinuxver() < mylinux(2,1,100) )
+    [[ route add default gw %gateway% [[metric %metric%]] %iface% ]]
+
+  down
+    [[ route del default gw %gateway% [[metric %metric%]] %iface% ]]
+    ifconfig %iface% down
+@
+
+<<inet methods>>=
+method manual
+  description
+    This method may be used to define interfaces for which no configuration
+    is done by default.  Such interfaces can be configured manually by
+    means of *up* and *down* commands or /etc/network/if-*.d scripts.
+
+  up
+
+  down
+@ 
+
+<<inet methods>>=
+method dhcp
+  description
+    This method may be used to obtain an address via DHCP with any of
+    the tools: dhclient, pump, udhcpc, dhcpcd.
+    (They have been listed in their order of precedence.)
+    If you have a complicated DHCP setup you should
+    note that some of these clients use their own configuration files
+    and do not obtain their configuration information via *ifup*.
+
+  options
+    hostname hostname       -- Hostname to be requested (pump, dhcpcd, udhcpc)
+    leasehours leastime     -- Preferred lease time in hours (pump)
+    leasetime leasetime     -- Preferred lease time in seconds (dhcpcd)
+    vendor vendor           -- Vendor class identifier (dhcpcd)
+    client client_id        -- Client identifier (dhcpcd, udhcpc)
+    hwaddress class address -- Hardware Address. /class/ is one of \
+                                *ether*, *ax25*, *ARCnet* or *netrom*. \
+                                /address/ is dependent on this choice.
+
+  up
+    [[ifconfig %iface% hw %hwaddress%]]
+    dhclient3 -pf /var/run/dhclient.%iface%.pid -lf /var/run/dhclient.%iface%.leases %iface% \
+        if (execable("/sbin/dhclient3"))
+    dhclient -e -pf /var/run/dhclient.%iface%.pid -lf /var/run/dhclient.%iface%.leases %iface% \
+        elsif (execable("/sbin/dhclient"))
+    pump -i %iface% [[-h %hostname%]] [[-l %leasehours%]] \
+        elsif (execable("/sbin/pump") && mylinuxver() >= mylinux(2,1,100))
+    udhcpc -n -p /var/run/udhcpc.%iface%.pid -i %iface% [[-H %hostname%]] \
+           [[-c %clientid%]] \
+        elsif (execable("/sbin/udhcpc") && mylinuxver() >= mylinux(2,2,0))
+    dhcpcd [[-h %hostname%]] [[-i %vendor%]] [[-I %clientid%]] \
+           [[-l %leasetime%]] %iface% \
+        elsif (execable("/sbin/dhcpcd"))
+
+  down
+    dhclient3 -r -pf /var/run/dhclient.%iface%.pid -lf /var/run/dhclient.%iface%.leases %iface% \
+        if (execable("/sbin/dhclient3"))
+    cat /var/run/dhclient.%iface%.pid | xargs -i kill -TERM {} \
+        elsif (execable("/sbin/dhclient"))
+    pump -i %iface% -r \
+        elsif (execable("/sbin/pump") && mylinuxver() >= mylinux(2,1,100))
+    cat /var/run/udhcpc.%iface%.pid | xargs -i kill -TERM {} \
+        elsif (execable("/sbin/udhcpc"))
+    dhcpcd -k %iface% \
+        elsif (execable("/sbin/dhcpcd"))
+
+    ifconfig %iface% down
+@ 
+
+<<inet methods>>=
+method bootp
+  description
+    This method may be used to obtain an address via bootp.
+
+  options
+    bootfile file  -- Tell the server to use /file/ as the bootfile.
+    server address -- Use the IP address /address/ to communicate with \
+                      the server.
+    hwaddr addr    -- Use /addr/ as the hardware address instead of \
+                      whatever it really is.
+
+  up
+    bootpc [[--bootfile %bootfile%]] --dev %iface% [[--server %server%]] \
+           [[--hwaddr %hwaddr%]] --returniffail --serverbcast
+
+  down
+    ifconfig down %iface%
+@ 
+
+<<inet methods>>=
+method ppp
+  description
+    This method uses pon/poff to configure a PPP interface. See those
+    commands for details.
+  options
+    provider name  -- Use /name/ as the provider (from /etc/ppp/peers).
+  up
+    pon [[%provider%]]
+  down
+    poff [[%provider%]]
+@ 
+
+<<inet methods>>=
+method wvdial
+  description
+    This method uses wvdial to configure a PPP interface. See that command
+    for more details.
+  options
+    provider name  -- Use /name/ as the provider (from /etc/ppp/peers).
+  up
+    /sbin/start-stop-daemon --start -x /usr/bin/wvdial \
+                      -p /var/run/wvdial.%iface% -b -m -- [[ %provider% ]]
+  down
+    /sbin/start-stop-daemon --stop -x /usr/bin/wvdial \
+                      -p /var/run/wvdial.%iface% -s 2
+@
+
+
+
+
+\subsection{IPv6 Address Family}
+
+<<address family declarations>>=
+extern address_family addr_inet6;
+@ 
+
+<<address family references>>=
+&addr_inet6,
+@ 
+
+<<inet6.defn>>=
+address_family inet6
+architecture linux
+
+method loopback
+  description
+    This method may be used to define the IPv6 loopback interface.
+  up
+    ifconfig %iface% add ::1
+  down
+    ifconfig %iface% del ::1
+
+method static
+  description
+    This method may be used to define interfaces with statically assigned
+    IPv6 addresses.
+
+  options
+    address address        -- Address (colon delimited) *required*
+    netmask mask           -- Netmask (number of bits, eg 64) *required*
+    gateway address        -- Default gateway (colon delimited)
+    media type             -- Medium type, driver dependent
+    hwaddress class address -- Hardware Address. /class/ is one of \
+                                 *ether*, *ax25*, *ARCnet* or *netrom*. \
+                                 /address/ is dependent on this choice.
+    mtu size               -- MTU size
+  up
+    ifconfig %iface% [[media %media%]] [[hw %hwaddress%]] [[mtu %mtu%]] up
+    ifconfig %iface% add %address%/%netmask%
+    [[ route -A inet6 add ::/0 gw %gateway% ]] 
+
+  down
+    ifconfig %iface% down
+
+method v4tunnel
+  description
+    This method may be used to setup an IPv6-over-IPv4 tunnel. It requires
+    the *ip* command from the *iproute* package.
+
+  options
+    address address       -- Address (colon delimited)
+    netmask mask          -- Netmask (number of bits, eg 64) 
+    endpoint address      -- Address of other tunnel endpoint (IPv4 \
+                             dotted quad) *required*
+    local address         -- Address of the local endpoint (IPv4 \
+                             dotted quad)
+    gateway address       -- Default gateway (colon delimited)
+    ttl time              -- TTL setting
+
+  up
+    ip tunnel add %iface% mode sit remote %endpoint% [[local %local%]] \
+       [[ttl %ttl%]]
+    ip link set %iface% up
+    [[ ip addr add %address%/%netmask% dev %iface% ]]
+    [[ ip route add %gateway% dev %iface% ]]
+    [[ ip route add ::/0 via %gateway% dev %iface% ]]
+
+  down
+    ip tunnel del %iface%
+@ 
+
+\subsection{IPX Address Family}
+
+<<address family declarations>>=
+extern address_family addr_ipx;
+@ 
+
+<<address family references>>=
+&addr_ipx,
+@ 
+
+<<ipx.defn>>=
+address_family ipx
+architecture linux
+
+method static
+  description
+    This method may be used to setup an IPX interface.  It requires the
+    /ipx_interface/ command.
+
+  options
+    frame type             -- /type/ of ethernet frames to use (e.g. *802.2*)
+    netnum id              -- Network number
+
+  up
+    ipx_interface add %iface% %frame% %netnum%
+
+  down
+    ipx_interface del %iface% %frame%
+
+method dynamic
+  description
+    This method may be used to setup an IPX interface dynamically.
+
+  options
+    frame type             -- /type/ of ethernet frames to use (e.g. *802.2*)
+
+  up
+    ipx_interface add %iface% %frame%
+
+  down
+    ipx_interface del %iface% %frame%
+@ 
+
+\begin{flushleft}
+\bibliography{biblio}
+\bibliographystyle{unsrt}
+\end{flushleft}
+
+\end{document}
diff --git a/_darcs/current/interfaces.5.pre b/_darcs/current/interfaces.5.pre
new file mode 100644 (file)
index 0000000..c550e51
--- /dev/null
@@ -0,0 +1,271 @@
+.\" -*- nroff -*-
+.\" macros
+.de EX \" Begin Example
+.  IP
+.  ft CW
+.  nf
+.  ne \\$1
+..
+.de EE \" End Example
+.  ft P
+.  fi
+.  PP
+..
+.TH INTERFACES 5 "5 April 2004" "ifupdown" "File formats"
+.SH NAME
+/etc/network/interfaces \- network interface configuration for ifup and ifdown 
+.SH DESCRIPTION
+/etc/network/interfaces contains network interface configuration
+information for the
+.BR ifup (8)
+and
+.BR ifdown (8)
+commands.
+This is where you configure how your system is connected to the network.
+.P
+Lines starting with `#' are ignored. Note that end-of-line comments are
+NOT supported, comments must be on a line of their own.
+.P
+A line may be extended across multiple lines by making the last character
+a backslash.
+.P
+The file consists of zero or more "iface", "mapping", "auto" and "allow-"
+stanzas. Here is an example.
+.EX
+auto lo eth0
+allow-hotplug eth1
+
+iface lo inet loopback
+
+mapping eth0 
+       script /usr/local/sbin/map\-scheme
+       map HOME eth0\-home
+       map WORK eth0\-work
+
+iface eth0\-home inet static
+       address 192.168.1.1
+       netmask 255.255.255.0
+       up flush\-mail
+
+iface eth0\-work inet dhcp
+
+iface eth1 inet dhcp
+.EE
+Lines beginning with the word "auto" are used to identify the physical
+interfaces to be brought up when
+.B ifup
+is run with the
+.B \-a
+option.  (This option is used by the system boot scripts.)
+Physical interface names should follow the word "auto" on the same line.
+There can be multiple "auto" stanzas.
+.B ifup
+brings the named interfaces up in the order listed.
+.P
+Lines beginning with "allow-" are used to identify interfaces that should
+be brought up automatically by various subsytems. This may be done using
+a command such as "ifup --allow=hotplug eth0 eth1", which will only bring
+up eth0 or eth1 if it is listed in an "allow-hotplug" line. Note that
+"allow-auto" and "auto" are synonyms.
+.P
+Stanzas beginning with the word "mapping" are used to determine how a
+logical interface name is chosen for a physical interface that is to be
+brought up.  The first line of a mapping stanza consists of the word
+"mapping" followed by a pattern in shell glob syntax.  Each mapping stanza
+must contain a
+.BR script
+definition.  The named script is run with the physical interface name as
+its argument and with the contents of all following "map" lines 
+(\fBwithout\fR the leading "map") in the
+stanza provided to it on its standard input. The script must print a
+string on its standard output before exiting. See 
+.IR /usr/share/doc/ifupdown/examples
+for examples of what the script must print.
+.P
+Mapping a name consists of searching the remaining mapping
+patterns and running the script corresponding to the first match;
+the script outputs the name to which the original is mapped.
+.P
+.B ifup
+is normally given a physical interface name as its first non\-option argument.
+.B ifup
+also uses this name as the initial logical name for the interface unless
+it is accompanied by a  suffix of the form \fI=LOGICAL\fR, in which case
+ifup chooses \fILOGICAL\fR as the initial logical name for the interface.
+It then maps this name, possibly more than once according to successive
+mapping specifications,  until no further mappings are possible.  If the
+resulting name is the name of some defined logical interface then
+.B ifup 
+attempts to bring up the physical interface
+as that logical interface.  Otherwise
+.B ifup
+exits with an error.
+.P
+Stanzas defining logical interfaces start with a line consisting of the
+word "iface" followed by the name of the logical interface.
+In simple configurations without mapping stanzas this name should simply
+be the name of the physical interface to which it is to be applied.
+(The default mapping script is, in effect, the
+.B echo
+command.)
+The interface name is followed by the name of the address family that the
+interface uses.  This will be "inet" for TCP/IP networking, but there is
+also some support for IPX networking ("ipx"), and IPv6 networking ("inet6").
+Following that is the name of the method used to configure the interface.
+.P
+Additional options can be given on subsequent lines in the stanza.
+Which options are available depends on the family and method,
+as described below.
+Additional options can be made available by other Debian packages.
+For example, the wireless\-tools package makes available a number of
+options prefixed with "wireless\-" which can be used to configure the
+interface using
+.BR iwconfig (8) .
+(See
+.BR wireless (7)
+for details.)
+.P
+Options are usually indented for clarity (as in the example above)
+but are not required to be.
+.SH IFACE OPTIONS
+The following "command" options are available for every family and method.
+Each of these options can be given multiple times in a single stanza,
+in which case the commands are executed in the order in which they appear
+in the stanza.
+(You can ensure a command never fails by suffixing "|| true".)
+.TP
+.BI pre\-up " command"
+Run
+.I command
+before bringing the interface up.
+If this command fails then
+.B ifup
+aborts,
+refraining from marking the interface as configured,
+prints an error message,
+and exits with status 0.
+This behavior may change in the future.
+.TP
+.BI up " command" 
+.TP
+.BI post\-up " command"
+Run
+.I command
+after bringing the interface up.
+If this command fails then
+.B ifup
+aborts,
+refraining from marking the interface as configured
+(even though it has really been configured),
+prints an error message,
+and exits with status 0.
+This behavior may change in the future.
+.TP
+.BI down " command"
+.TP
+.BI pre\-down " command"
+Run
+.I command
+before taking the interface down.
+If this command fails then
+.B ifdown
+aborts,
+marks the interface as deconfigured
+(even though it has not really been deconfigured),
+and exits with status 0.
+This behavior may change in the future.
+.TP
+.BI post\-down " command"
+Run
+.I command
+after taking the interface down.
+If this command fails then
+.B ifdown
+aborts,
+marks the interface as deconfigured,
+and exits with status 0.
+This behavior may change in the future.
+.P
+There exists for each of the above mentioned options a directory
+.IR /etc/network/if\-\fB<option>\fI.d/ 
+the scripts in which are run (with no arguments) using
+.BR run\-parts (8)
+after the option itself has been processed.
+.P
+All of these commands have access to the following environment variables.
+.TP
+.B IFACE
+physical name of the interface being processed
+.TP
+.B LOGICAL
+logical name of the interface being processed
+.TP
+.B ADDRFAM
+address family of the interface
+.TP
+.B METHOD
+method of the interface (e.g.,
+.IR static )
+.TP
+.B MODE
+.IR start " if run from ifup, " stop " if run from ifdown"
+.TP
+.B PHASE 
+as per MODE, but with finer granularity, distinguishing the
+\fIpre-up\fR, \fIpost-up\fR, \fIpre-down\fR and \fIpost-down\fR phases.
+.TP
+.B VERBOSITY
+indicates whether \fB--verbose\fR was used; set to 1 if so, 0 if not.
+.TP
+.B PATH
+the command search path:
+.I /usr/local/sbin:\%/usr/local/bin:\%/usr/sbin:\%/usr/bin:\%/sbin:\%/bin
+.P
+Additionally, all options given in an interface definition stanza are
+exported to the environment in upper case with "IF_" prepended and with
+hyphens converted to underscores and non\-alphanumeric characters discarded.
+##ADDRESSFAM##
+.SH KNOWN BUGS/LIMITATIONS
+The
+.B ifup
+and
+.B ifdown
+programs work with so-called "physical" interface names.
+These names are assigned to hardware by the kernel.
+Unfortunately it can happen that the kernel assigns different
+physical interface names to the same hardware at different
+times; for example, what was called "eth0" last time you booted
+is now called "eth1" and vice versa.
+This creates a problem if you want to configure the interfaces
+appropriately.
+A way to deal with this problem is to use mapping scripts that
+choose logical interface names according to the properties of
+the interface hardware.
+See the
+.B get-mac-address.sh
+script in the examples directory for an example of such a mapping
+script.  See also Debian bug #101728.
+.P
+It is not currently possible to divide up
+.B /etc/network/interfaces 
+into multiple files.  A feature that would make this possible is
+some sort of inclusion directive.  No such feature exists in the
+current ifupdown program.  For more information see Debian
+bug #159884.
+.SH AUTHOR
+The ifupdown suite was written by Anthony Towns <aj@azure.humbug.org.au>.
+This manpage was contributed by Joey Hess <joey@kitenet.net>.
+.SH "SEE ALSO"
+.BR ifup (8),
+.BR iwconfig (8),
+.BR run\-parts (8).
+.P
+For advice on configuring this package read the
+.B Network Configuration
+chapter of the \fIDebian Reference\fR manual,
+available at
+\fIhttp://www.debian.org/doc/manuals/reference/ch-gateway.en.html\fR
+or in the \fBdebian-reference-en\fR package.
+.P
+Examples of how to set up interfaces can be found in
+.BR /usr/share/doc/ifupdown/examples/network-interfaces .
diff --git a/_darcs/current/makecdep.sh b/_darcs/current/makecdep.sh
new file mode 100644 (file)
index 0000000..e39dadf
--- /dev/null
@@ -0,0 +1,9 @@
+#!/bin/sh
+FILE=$1
+if [ "$FILE" = "" -o ! -f "$FILE" ]; then
+        echo "Please specify a .c file"
+        exit 1
+fi
+
+gcc -MM -MG $FILE |
+  sed -e 's@^\(.*\)\.o:@\1.o \1.d:@'
diff --git a/_darcs/current/makenwdep.sh b/_darcs/current/makenwdep.sh
new file mode 100644 (file)
index 0000000..4360528
--- /dev/null
@@ -0,0 +1,27 @@
+FILE=$1
+
+if [ "$FILE" = "" -o ! -f "$FILE" ]; then
+        echo "Please specify a .nw file"
+        exit 1
+fi
+
+noroots $FILE | sed 's/^<''<\(.*\)>>$/\1/' |
+        while read chunk; do
+                printf "%s : %s\n" "$chunk" "$FILE"
+                case $chunk in
+                        *.pl|*.sh)
+                                printf "\tnotangle -R\$@ \$< >\$@\n"
+                                printf "\tchmod 755 %s\n" "$chunk"
+                                ;;
+                        *.c)
+                                printf "\tnotangle -L -R\$@ \$< | cpif \$@\n"
+                                printf "include ${chunk%.c}.d\n"
+                                ;;
+                        *.h)
+                                printf "\tnotangle -L -R\$@ \$< | cpif \$@\n"
+                                ;;
+                        *)
+                                printf "\tnotangle -t8 -R\$@ $< >\$@\n"
+                                ;;
+                esac
+        done
diff --git a/_darcs/current/modules.dia b/_darcs/current/modules.dia
new file mode 100644 (file)
index 0000000..ebe8afd
Binary files /dev/null and b/_darcs/current/modules.dia differ
diff --git a/_darcs/inventory b/_darcs/inventory
new file mode 100644 (file)
index 0000000..36610d9
--- /dev/null
@@ -0,0 +1,107 @@
+[ifupdown 0.6.4-4.12
+Anthony Towns <aj@azure.humbug.org.au>**20050322184259] 
+[MU, version bump
+Anthony Towns <aj@azure.humbug.org.au>**20050322185711] 
+[don't re-build unnecessarily in debian/rules
+Anthony Towns <aj@azure.humbug.org.au>**20050322185930] 
+[remove generated files
+Anthony Towns <aj@azure.humbug.org.au>**20050322190943] 
+[add post-up / pre-down aliases for up / down in interfaces file
+Anthony Towns <aj@azure.humbug.org.au>**20050322191425] 
+[update copyright, bump version
+Anthony Towns <aj@azure.humbug.org.au>**20050325172759] 
+[undocument --exclude option
+Anthony Towns <aj@azure.humbug.org.au>**20050325172831] 
+[fix grammar for exclude interfaces chunk
+Anthony Towns <aj@azure.humbug.org.au>**20050325173048] 
+[support for --allow=hotplug, etc
+Anthony Towns <aj@azure.humbug.org.au>**20050325173537] 
+[satiate POSIX sh monkeys
+Anthony Towns <aj@azure.humbug.org.au>**20050325174738] 
+[update generated files
+Anthony Towns <aj@azure.humbug.org.au>**20050325174749] 
+[add BUGS file to categoris bugs in the BTS
+Anthony Towns <aj@azure.humbug.org.au>**20050325174926] 
+[add version notes
+Anthony Towns <aj@azure.humbug.org.au>**20050326151125] 
+[note debian-native in changelog
+Anthony Towns <aj@azure.humbug.org.au>**20050326151130] 
+[fix grammar in changelog a bit
+Anthony Towns <aj@azure.humbug.org.au>**20050331140306] 
+[annotate BUGS some more
+Anthony Towns <aj@azure.humbug.org.au>**20050403071601] 
+[mv ifstate into /etc/network/run, simplify handling
+Anthony Towns <aj@azure.humbug.org.au>**20050403130722] 
+[indent postinst to two space tabs
+Anthony Towns <aj@azure.humbug.org.au>**20050403133706] 
+[handle /e/n/run and /e/n/run/ifstate creation/transition a little more carefully
+Anthony Towns <aj@azure.humbug.org.au>**20050403142603] 
+[add some more informative comments i/o
+Anthony Towns <aj@azure.humbug.org.au>**20050403150334] 
+[cope with /etc/network/ifstate being a symlink
+Anthony Towns <aj@azure.humbug.org.au>**20050403150343] 
+[debian/rules test is a no-op when cross building
+Anthony Towns <aj@azure.humbug.org.au>**20050403150657] 
+[tidy up debian/rules a little more
+Anthony Towns <aj@azure.humbug.org.au>**20050403150711] 
+[reprioritise the /e/n/i enhancements
+Anthony Towns <aj@azure.humbug.org.au>**20050403150728] 
+[remove unused chunk, gah
+Anthony Towns <aj@azure.humbug.org.au>**20050403154821] 
+[add VERBOSITY, invoke run-parts with --verbose
+Anthony Towns <aj@azure.humbug.org.au>**20050403155657] 
+[add LOGICAL to variables for scripts
+Anthony Towns <aj@azure.humbug.org.au>**20050403160939] 
+[fix up error message
+Anthony Towns <aj@azure.humbug.org.au>**20050403160952] 
+[reprioritise LOGICAL for mapping scripts
+Anthony Towns <aj@azure.humbug.org.au>**20050403161110] 
+[add PHASE var
+Anthony Towns <aj@azure.humbug.org.au>**20050403161538] 
+[tidy up <<clear environ..>> chunk
+Anthony Towns <aj@azure.humbug.org.au>**20050403161611] 
+[ifstate docs are waiting on restructuring ifstate
+Anthony Towns <aj@azure.humbug.org.au>**20050403161634] 
+[document lack of end-of-line comments
+Anthony Towns <aj@azure.humbug.org.au>**20050403161830] 
+[reprioritise BUGS some more
+Anthony Towns <aj@azure.humbug.org.au>**20050403164423] 
+[remove parenthetical note that dash can't cope with
+Anthony Towns <aj@azure.humbug.org.au>**20050403164757] 
+[remove second dh_gencontrol invocation
+Anthony Towns <aj@azure.humbug.org.au>**20050403164804] 
+[ignore templates, gar
+Anthony Towns <aj@azure.humbug.org.au>**20050403170911] 
+[simplify debconf dependencies
+Anthony Towns <aj@azure.humbug.org.au>**20050403170919] 
+[rearrange BUGS some more
+Anthony Towns <aj@azure.humbug.org.au>**20050404011259] 
+[fix syntax error in ifupdown.init
+Anthony Towns <aj@azure.humbug.org.au>**20050404030039] 
+[document --allow implementation in the code
+Anthony Towns <aj@azure.humbug.org.au>**20050404030209] 
+[fix up documentation for changes so far
+Anthony Towns <aj@azure.humbug.org.au>**20050404030334] 
+[remove conflict with old dhcp-client version
+Anthony Towns <aj@azure.humbug.org.au>**20050404111917] 
+[fix wrong variable name in ifupdown.init
+Anthony Towns <aj@azure.humbug.org.au>**20050404111950] [change section to base
+Anthony Towns <aj@azure.humbug.org.au>**20050404153209] 
+[fix handling when logical and physical iface names don't match
+Anthony Towns <aj@azure.humbug.org.au>**20050405164755] 
+[deal with dangling /etc/network/run symlink on upgrade
+Anthony Towns <aj@azure.humbug.org.au>**20050405164913] 
+[name the release
+Anthony Towns <aj@azure.humbug.org.au>**20050405164921] 
+[update dateline for 0.6.5 to match what was uploaded
+Anthony Towns <aj@azure.humbug.org.au>**20050405164951] 
+[use ajt@d.o address
+Anthony Towns <aj@azure.humbug.org.au>**20050405173454] 
+[correct test for /dev/shm in /proc/mounts
+Anthony Towns <aj@azure.humbug.org.au>**20050405173752] 
+[drop basename, dirname
+Anthony Towns <aj@azure.humbug.org.au>**20050416142311] 
+[check for space on /dev/shm
+Anthony Towns <aj@azure.humbug.org.au>**20050423030949] 
+[bump changelog date
+aj@azure.humbug.org.au**20050502135743] 
diff --git a/_darcs/patches/20050322184259-48b0a-3d7d00a0c38d726902f24ae37090ed7af95dc35b.gz b/_darcs/patches/20050322184259-48b0a-3d7d00a0c38d726902f24ae37090ed7af95dc35b.gz
new file mode 100644 (file)
index 0000000..1ebe2fa
Binary files /dev/null and b/_darcs/patches/20050322184259-48b0a-3d7d00a0c38d726902f24ae37090ed7af95dc35b.gz differ
diff --git a/_darcs/patches/20050322185711-48b0a-265b47864d2d5eb1b5e40dcae77f4234e83e1e09.gz b/_darcs/patches/20050322185711-48b0a-265b47864d2d5eb1b5e40dcae77f4234e83e1e09.gz
new file mode 100644 (file)
index 0000000..aa6c1ab
Binary files /dev/null and b/_darcs/patches/20050322185711-48b0a-265b47864d2d5eb1b5e40dcae77f4234e83e1e09.gz differ
diff --git a/_darcs/patches/20050322185930-48b0a-899f2c66d03fccd88c81a91a27ad918e83df8241.gz b/_darcs/patches/20050322185930-48b0a-899f2c66d03fccd88c81a91a27ad918e83df8241.gz
new file mode 100644 (file)
index 0000000..dcd09af
Binary files /dev/null and b/_darcs/patches/20050322185930-48b0a-899f2c66d03fccd88c81a91a27ad918e83df8241.gz differ
diff --git a/_darcs/patches/20050322190943-48b0a-e970d73397730c0825bb9d37e0ac15607857ce11.gz b/_darcs/patches/20050322190943-48b0a-e970d73397730c0825bb9d37e0ac15607857ce11.gz
new file mode 100644 (file)
index 0000000..ef20e02
Binary files /dev/null and b/_darcs/patches/20050322190943-48b0a-e970d73397730c0825bb9d37e0ac15607857ce11.gz differ
diff --git a/_darcs/patches/20050322191425-48b0a-338ca9e6e811ee13e25fcac84c499fa6ee5b81f6.gz b/_darcs/patches/20050322191425-48b0a-338ca9e6e811ee13e25fcac84c499fa6ee5b81f6.gz
new file mode 100644 (file)
index 0000000..5e8cfc3
Binary files /dev/null and b/_darcs/patches/20050322191425-48b0a-338ca9e6e811ee13e25fcac84c499fa6ee5b81f6.gz differ
diff --git a/_darcs/patches/20050325172759-48b0a-b001b9856880f508cee8ff667615da2c16df3158.gz b/_darcs/patches/20050325172759-48b0a-b001b9856880f508cee8ff667615da2c16df3158.gz
new file mode 100644 (file)
index 0000000..7aae2f2
Binary files /dev/null and b/_darcs/patches/20050325172759-48b0a-b001b9856880f508cee8ff667615da2c16df3158.gz differ
diff --git a/_darcs/patches/20050325172831-48b0a-6d40f49e987c5c8dbf4ad2f0f6285d84fb51e3fb.gz b/_darcs/patches/20050325172831-48b0a-6d40f49e987c5c8dbf4ad2f0f6285d84fb51e3fb.gz
new file mode 100644 (file)
index 0000000..2fa8f98
Binary files /dev/null and b/_darcs/patches/20050325172831-48b0a-6d40f49e987c5c8dbf4ad2f0f6285d84fb51e3fb.gz differ
diff --git a/_darcs/patches/20050325173048-48b0a-f17b1c4e81302f32ea5341c165c72335487c4e0d.gz b/_darcs/patches/20050325173048-48b0a-f17b1c4e81302f32ea5341c165c72335487c4e0d.gz
new file mode 100644 (file)
index 0000000..8b927a2
Binary files /dev/null and b/_darcs/patches/20050325173048-48b0a-f17b1c4e81302f32ea5341c165c72335487c4e0d.gz differ
diff --git a/_darcs/patches/20050325173537-48b0a-404f6e17843f4e0292bf258e5542e9802a159b14.gz b/_darcs/patches/20050325173537-48b0a-404f6e17843f4e0292bf258e5542e9802a159b14.gz
new file mode 100644 (file)
index 0000000..ce625ba
Binary files /dev/null and b/_darcs/patches/20050325173537-48b0a-404f6e17843f4e0292bf258e5542e9802a159b14.gz differ
diff --git a/_darcs/patches/20050325174738-48b0a-508807aae413654455d5d3c00c7717af85ee4c17.gz b/_darcs/patches/20050325174738-48b0a-508807aae413654455d5d3c00c7717af85ee4c17.gz
new file mode 100644 (file)
index 0000000..f98e9f0
Binary files /dev/null and b/_darcs/patches/20050325174738-48b0a-508807aae413654455d5d3c00c7717af85ee4c17.gz differ
diff --git a/_darcs/patches/20050325174749-48b0a-61da41cded8e77e4347a964ee2111d9b21a2ceea.gz b/_darcs/patches/20050325174749-48b0a-61da41cded8e77e4347a964ee2111d9b21a2ceea.gz
new file mode 100644 (file)
index 0000000..8ed0ef8
Binary files /dev/null and b/_darcs/patches/20050325174749-48b0a-61da41cded8e77e4347a964ee2111d9b21a2ceea.gz differ
diff --git a/_darcs/patches/20050325174926-48b0a-935743f08e999b2ddb6041e3fbd29ec1298555d8.gz b/_darcs/patches/20050325174926-48b0a-935743f08e999b2ddb6041e3fbd29ec1298555d8.gz
new file mode 100644 (file)
index 0000000..3c32b95
Binary files /dev/null and b/_darcs/patches/20050325174926-48b0a-935743f08e999b2ddb6041e3fbd29ec1298555d8.gz differ
diff --git a/_darcs/patches/20050326151125-48b0a-c2ed89301d3a7a42fed7174513023f9067a1a347.gz b/_darcs/patches/20050326151125-48b0a-c2ed89301d3a7a42fed7174513023f9067a1a347.gz
new file mode 100644 (file)
index 0000000..10b301f
Binary files /dev/null and b/_darcs/patches/20050326151125-48b0a-c2ed89301d3a7a42fed7174513023f9067a1a347.gz differ
diff --git a/_darcs/patches/20050326151130-48b0a-e655ac6f135e14c6f088be1a687c07774c58e96d.gz b/_darcs/patches/20050326151130-48b0a-e655ac6f135e14c6f088be1a687c07774c58e96d.gz
new file mode 100644 (file)
index 0000000..e8c52c3
Binary files /dev/null and b/_darcs/patches/20050326151130-48b0a-e655ac6f135e14c6f088be1a687c07774c58e96d.gz differ
diff --git a/_darcs/patches/20050331140306-48b0a-192b390dc5d22de8e61d5e3c21370d44bca6726e.gz b/_darcs/patches/20050331140306-48b0a-192b390dc5d22de8e61d5e3c21370d44bca6726e.gz
new file mode 100644 (file)
index 0000000..4033c41
Binary files /dev/null and b/_darcs/patches/20050331140306-48b0a-192b390dc5d22de8e61d5e3c21370d44bca6726e.gz differ
diff --git a/_darcs/patches/20050403071601-48b0a-277064f82b402d73dd3e9f4dc18edec161e592f8.gz b/_darcs/patches/20050403071601-48b0a-277064f82b402d73dd3e9f4dc18edec161e592f8.gz
new file mode 100644 (file)
index 0000000..5d91eab
Binary files /dev/null and b/_darcs/patches/20050403071601-48b0a-277064f82b402d73dd3e9f4dc18edec161e592f8.gz differ
diff --git a/_darcs/patches/20050403130722-48b0a-cc5a3bf9eb540a9ba9e130626912237e96a9609d.gz b/_darcs/patches/20050403130722-48b0a-cc5a3bf9eb540a9ba9e130626912237e96a9609d.gz
new file mode 100644 (file)
index 0000000..c276f29
Binary files /dev/null and b/_darcs/patches/20050403130722-48b0a-cc5a3bf9eb540a9ba9e130626912237e96a9609d.gz differ
diff --git a/_darcs/patches/20050403133706-48b0a-ac0145fc85e019fecf12356618aa3ecc6aef73ff.gz b/_darcs/patches/20050403133706-48b0a-ac0145fc85e019fecf12356618aa3ecc6aef73ff.gz
new file mode 100644 (file)
index 0000000..0b211ea
Binary files /dev/null and b/_darcs/patches/20050403133706-48b0a-ac0145fc85e019fecf12356618aa3ecc6aef73ff.gz differ
diff --git a/_darcs/patches/20050403142603-48b0a-ea9f259b5bc7061a3cfcb23e791d27dcaffbb898.gz b/_darcs/patches/20050403142603-48b0a-ea9f259b5bc7061a3cfcb23e791d27dcaffbb898.gz
new file mode 100644 (file)
index 0000000..7edfb2b
Binary files /dev/null and b/_darcs/patches/20050403142603-48b0a-ea9f259b5bc7061a3cfcb23e791d27dcaffbb898.gz differ
diff --git a/_darcs/patches/20050403150334-48b0a-1bec190d7c5130a0de8b79579a1e664bdfe6303f.gz b/_darcs/patches/20050403150334-48b0a-1bec190d7c5130a0de8b79579a1e664bdfe6303f.gz
new file mode 100644 (file)
index 0000000..f9d8129
Binary files /dev/null and b/_darcs/patches/20050403150334-48b0a-1bec190d7c5130a0de8b79579a1e664bdfe6303f.gz differ
diff --git a/_darcs/patches/20050403150343-48b0a-02e148db83abd6cd9f9e6ec53a2a1916a38a61cb.gz b/_darcs/patches/20050403150343-48b0a-02e148db83abd6cd9f9e6ec53a2a1916a38a61cb.gz
new file mode 100644 (file)
index 0000000..2768700
Binary files /dev/null and b/_darcs/patches/20050403150343-48b0a-02e148db83abd6cd9f9e6ec53a2a1916a38a61cb.gz differ
diff --git a/_darcs/patches/20050403150657-48b0a-15ca5d98146a5b255dd993de9e8ccb07ce586b20.gz b/_darcs/patches/20050403150657-48b0a-15ca5d98146a5b255dd993de9e8ccb07ce586b20.gz
new file mode 100644 (file)
index 0000000..e318308
Binary files /dev/null and b/_darcs/patches/20050403150657-48b0a-15ca5d98146a5b255dd993de9e8ccb07ce586b20.gz differ
diff --git a/_darcs/patches/20050403150711-48b0a-b7a219596d7793c014e937d477b07e8cf5cf9033.gz b/_darcs/patches/20050403150711-48b0a-b7a219596d7793c014e937d477b07e8cf5cf9033.gz
new file mode 100644 (file)
index 0000000..2305fe2
Binary files /dev/null and b/_darcs/patches/20050403150711-48b0a-b7a219596d7793c014e937d477b07e8cf5cf9033.gz differ
diff --git a/_darcs/patches/20050403150728-48b0a-ad57c1b54ea04699dd8454be692cf0ac25c599de.gz b/_darcs/patches/20050403150728-48b0a-ad57c1b54ea04699dd8454be692cf0ac25c599de.gz
new file mode 100644 (file)
index 0000000..4d31868
Binary files /dev/null and b/_darcs/patches/20050403150728-48b0a-ad57c1b54ea04699dd8454be692cf0ac25c599de.gz differ
diff --git a/_darcs/patches/20050403154821-48b0a-c05c4823816cc11771bd66a8eef9baa14ff29e1e.gz b/_darcs/patches/20050403154821-48b0a-c05c4823816cc11771bd66a8eef9baa14ff29e1e.gz
new file mode 100644 (file)
index 0000000..ba8e0cb
Binary files /dev/null and b/_darcs/patches/20050403154821-48b0a-c05c4823816cc11771bd66a8eef9baa14ff29e1e.gz differ
diff --git a/_darcs/patches/20050403155657-48b0a-a78731fa7b94026a1bce3d86ec14703e4595ad21.gz b/_darcs/patches/20050403155657-48b0a-a78731fa7b94026a1bce3d86ec14703e4595ad21.gz
new file mode 100644 (file)
index 0000000..90ac74f
Binary files /dev/null and b/_darcs/patches/20050403155657-48b0a-a78731fa7b94026a1bce3d86ec14703e4595ad21.gz differ
diff --git a/_darcs/patches/20050403160939-48b0a-69fa8a1fcabd5f848efb68b6efb17d88ea9846e2.gz b/_darcs/patches/20050403160939-48b0a-69fa8a1fcabd5f848efb68b6efb17d88ea9846e2.gz
new file mode 100644 (file)
index 0000000..1251a55
Binary files /dev/null and b/_darcs/patches/20050403160939-48b0a-69fa8a1fcabd5f848efb68b6efb17d88ea9846e2.gz differ
diff --git a/_darcs/patches/20050403160952-48b0a-858bcd92fe2ecda0dff3f0f2d6f4bb88791dd336.gz b/_darcs/patches/20050403160952-48b0a-858bcd92fe2ecda0dff3f0f2d6f4bb88791dd336.gz
new file mode 100644 (file)
index 0000000..acddc39
Binary files /dev/null and b/_darcs/patches/20050403160952-48b0a-858bcd92fe2ecda0dff3f0f2d6f4bb88791dd336.gz differ
diff --git a/_darcs/patches/20050403161110-48b0a-710fb33717b518175348f16756bc6248934ae15a.gz b/_darcs/patches/20050403161110-48b0a-710fb33717b518175348f16756bc6248934ae15a.gz
new file mode 100644 (file)
index 0000000..13ef184
Binary files /dev/null and b/_darcs/patches/20050403161110-48b0a-710fb33717b518175348f16756bc6248934ae15a.gz differ
diff --git a/_darcs/patches/20050403161538-48b0a-75ab76ed9925211a1b83efde1cc4a213f429a7be.gz b/_darcs/patches/20050403161538-48b0a-75ab76ed9925211a1b83efde1cc4a213f429a7be.gz
new file mode 100644 (file)
index 0000000..9444ca0
Binary files /dev/null and b/_darcs/patches/20050403161538-48b0a-75ab76ed9925211a1b83efde1cc4a213f429a7be.gz differ
diff --git a/_darcs/patches/20050403161611-48b0a-5dc34a325877de7548d9f4636b75e75d71f8344c.gz b/_darcs/patches/20050403161611-48b0a-5dc34a325877de7548d9f4636b75e75d71f8344c.gz
new file mode 100644 (file)
index 0000000..1f22264
Binary files /dev/null and b/_darcs/patches/20050403161611-48b0a-5dc34a325877de7548d9f4636b75e75d71f8344c.gz differ
diff --git a/_darcs/patches/20050403161634-48b0a-9010b91cdccf9ad2cffd13e848384692469232bd.gz b/_darcs/patches/20050403161634-48b0a-9010b91cdccf9ad2cffd13e848384692469232bd.gz
new file mode 100644 (file)
index 0000000..bab884c
Binary files /dev/null and b/_darcs/patches/20050403161634-48b0a-9010b91cdccf9ad2cffd13e848384692469232bd.gz differ
diff --git a/_darcs/patches/20050403161830-48b0a-4cbfbff1753740cb4e4e72b6309621f170caeaae.gz b/_darcs/patches/20050403161830-48b0a-4cbfbff1753740cb4e4e72b6309621f170caeaae.gz
new file mode 100644 (file)
index 0000000..83aa689
Binary files /dev/null and b/_darcs/patches/20050403161830-48b0a-4cbfbff1753740cb4e4e72b6309621f170caeaae.gz differ
diff --git a/_darcs/patches/20050403164423-48b0a-f4c3920fcf3caefba1297b1ade7338990f1c859f.gz b/_darcs/patches/20050403164423-48b0a-f4c3920fcf3caefba1297b1ade7338990f1c859f.gz
new file mode 100644 (file)
index 0000000..be3757d
Binary files /dev/null and b/_darcs/patches/20050403164423-48b0a-f4c3920fcf3caefba1297b1ade7338990f1c859f.gz differ
diff --git a/_darcs/patches/20050403164757-48b0a-8ad09d3f62ee0d157e4648a67ef16f680abe8933.gz b/_darcs/patches/20050403164757-48b0a-8ad09d3f62ee0d157e4648a67ef16f680abe8933.gz
new file mode 100644 (file)
index 0000000..60340c9
Binary files /dev/null and b/_darcs/patches/20050403164757-48b0a-8ad09d3f62ee0d157e4648a67ef16f680abe8933.gz differ
diff --git a/_darcs/patches/20050403164804-48b0a-e909e1e9ed995134a316a22ebc1ffa8d5b3f633a.gz b/_darcs/patches/20050403164804-48b0a-e909e1e9ed995134a316a22ebc1ffa8d5b3f633a.gz
new file mode 100644 (file)
index 0000000..9fc459f
Binary files /dev/null and b/_darcs/patches/20050403164804-48b0a-e909e1e9ed995134a316a22ebc1ffa8d5b3f633a.gz differ
diff --git a/_darcs/patches/20050403170911-48b0a-1b052d27df2f8d7764bd5aa71c832aa5f73aa122.gz b/_darcs/patches/20050403170911-48b0a-1b052d27df2f8d7764bd5aa71c832aa5f73aa122.gz
new file mode 100644 (file)
index 0000000..dc2fe13
Binary files /dev/null and b/_darcs/patches/20050403170911-48b0a-1b052d27df2f8d7764bd5aa71c832aa5f73aa122.gz differ
diff --git a/_darcs/patches/20050403170919-48b0a-40bc9c8afdf3b2ec6cfb9cc84222991be5495c23.gz b/_darcs/patches/20050403170919-48b0a-40bc9c8afdf3b2ec6cfb9cc84222991be5495c23.gz
new file mode 100644 (file)
index 0000000..6075396
Binary files /dev/null and b/_darcs/patches/20050403170919-48b0a-40bc9c8afdf3b2ec6cfb9cc84222991be5495c23.gz differ
diff --git a/_darcs/patches/20050404011259-48b0a-db60e8597853894dc22ff0226ecf8ea7dfb2bd0f.gz b/_darcs/patches/20050404011259-48b0a-db60e8597853894dc22ff0226ecf8ea7dfb2bd0f.gz
new file mode 100644 (file)
index 0000000..dd0717c
Binary files /dev/null and b/_darcs/patches/20050404011259-48b0a-db60e8597853894dc22ff0226ecf8ea7dfb2bd0f.gz differ
diff --git a/_darcs/patches/20050404030039-48b0a-993cd391cfa3d828a35b52da39abed02d69d4d50.gz b/_darcs/patches/20050404030039-48b0a-993cd391cfa3d828a35b52da39abed02d69d4d50.gz
new file mode 100644 (file)
index 0000000..837dcac
Binary files /dev/null and b/_darcs/patches/20050404030039-48b0a-993cd391cfa3d828a35b52da39abed02d69d4d50.gz differ
diff --git a/_darcs/patches/20050404030209-48b0a-3d326cb89210df162b267bc2120ca20066deb39e.gz b/_darcs/patches/20050404030209-48b0a-3d326cb89210df162b267bc2120ca20066deb39e.gz
new file mode 100644 (file)
index 0000000..d8e1827
Binary files /dev/null and b/_darcs/patches/20050404030209-48b0a-3d326cb89210df162b267bc2120ca20066deb39e.gz differ
diff --git a/_darcs/patches/20050404030334-48b0a-49ae19612c6b7d8211c6b89239397064c53f7cdf.gz b/_darcs/patches/20050404030334-48b0a-49ae19612c6b7d8211c6b89239397064c53f7cdf.gz
new file mode 100644 (file)
index 0000000..1ff7eca
Binary files /dev/null and b/_darcs/patches/20050404030334-48b0a-49ae19612c6b7d8211c6b89239397064c53f7cdf.gz differ
diff --git a/_darcs/patches/20050404111917-48b0a-3666132d54f974fa92dd5402d4570d505724c04e.gz b/_darcs/patches/20050404111917-48b0a-3666132d54f974fa92dd5402d4570d505724c04e.gz
new file mode 100644 (file)
index 0000000..86af352
Binary files /dev/null and b/_darcs/patches/20050404111917-48b0a-3666132d54f974fa92dd5402d4570d505724c04e.gz differ
diff --git a/_darcs/patches/20050404111950-48b0a-360b54b858475ae4e78e2ef4c6e0d84b2dd6a56c.gz b/_darcs/patches/20050404111950-48b0a-360b54b858475ae4e78e2ef4c6e0d84b2dd6a56c.gz
new file mode 100644 (file)
index 0000000..38b2fa2
Binary files /dev/null and b/_darcs/patches/20050404111950-48b0a-360b54b858475ae4e78e2ef4c6e0d84b2dd6a56c.gz differ
diff --git a/_darcs/patches/20050404153209-48b0a-169d4444f3c27466a8d7a3d56ddb15f41d1bb5f1.gz b/_darcs/patches/20050404153209-48b0a-169d4444f3c27466a8d7a3d56ddb15f41d1bb5f1.gz
new file mode 100644 (file)
index 0000000..d4710af
Binary files /dev/null and b/_darcs/patches/20050404153209-48b0a-169d4444f3c27466a8d7a3d56ddb15f41d1bb5f1.gz differ
diff --git a/_darcs/patches/20050405164755-48b0a-e33319257ad5608206f0abf53c6adf7eb9a3764b.gz b/_darcs/patches/20050405164755-48b0a-e33319257ad5608206f0abf53c6adf7eb9a3764b.gz
new file mode 100644 (file)
index 0000000..5879827
Binary files /dev/null and b/_darcs/patches/20050405164755-48b0a-e33319257ad5608206f0abf53c6adf7eb9a3764b.gz differ
diff --git a/_darcs/patches/20050405164913-48b0a-6cb47dfd47e9259a9c588c9a61fc8cf4086d61cd.gz b/_darcs/patches/20050405164913-48b0a-6cb47dfd47e9259a9c588c9a61fc8cf4086d61cd.gz
new file mode 100644 (file)
index 0000000..9298610
Binary files /dev/null and b/_darcs/patches/20050405164913-48b0a-6cb47dfd47e9259a9c588c9a61fc8cf4086d61cd.gz differ
diff --git a/_darcs/patches/20050405164921-48b0a-31ba4f33e19477ff10a68ddb24c6bbd7aad63d0d.gz b/_darcs/patches/20050405164921-48b0a-31ba4f33e19477ff10a68ddb24c6bbd7aad63d0d.gz
new file mode 100644 (file)
index 0000000..642a68d
Binary files /dev/null and b/_darcs/patches/20050405164921-48b0a-31ba4f33e19477ff10a68ddb24c6bbd7aad63d0d.gz differ
diff --git a/_darcs/patches/20050405164951-48b0a-c06ed2064f300df62ea7b8b18994d3a314e3b6b3.gz b/_darcs/patches/20050405164951-48b0a-c06ed2064f300df62ea7b8b18994d3a314e3b6b3.gz
new file mode 100644 (file)
index 0000000..8c4e783
Binary files /dev/null and b/_darcs/patches/20050405164951-48b0a-c06ed2064f300df62ea7b8b18994d3a314e3b6b3.gz differ
diff --git a/_darcs/patches/20050405173454-48b0a-7dd75d1a00e8a35a038628a6fceae4eca9e31fd3.gz b/_darcs/patches/20050405173454-48b0a-7dd75d1a00e8a35a038628a6fceae4eca9e31fd3.gz
new file mode 100644 (file)
index 0000000..8192055
Binary files /dev/null and b/_darcs/patches/20050405173454-48b0a-7dd75d1a00e8a35a038628a6fceae4eca9e31fd3.gz differ
diff --git a/_darcs/patches/20050405173752-48b0a-3437c72ae180a5c8357dca7a79f16976dd904b10.gz b/_darcs/patches/20050405173752-48b0a-3437c72ae180a5c8357dca7a79f16976dd904b10.gz
new file mode 100644 (file)
index 0000000..f152313
Binary files /dev/null and b/_darcs/patches/20050405173752-48b0a-3437c72ae180a5c8357dca7a79f16976dd904b10.gz differ
diff --git a/_darcs/patches/20050416142311-48b0a-2cc01e8f4873f2281ecea741c173d52e64b2f6ba.gz b/_darcs/patches/20050416142311-48b0a-2cc01e8f4873f2281ecea741c173d52e64b2f6ba.gz
new file mode 100644 (file)
index 0000000..c49631f
Binary files /dev/null and b/_darcs/patches/20050416142311-48b0a-2cc01e8f4873f2281ecea741c173d52e64b2f6ba.gz differ
diff --git a/_darcs/patches/20050423030949-48b0a-07da52fd9e90c570754aff473397bbad371dd748.gz b/_darcs/patches/20050423030949-48b0a-07da52fd9e90c570754aff473397bbad371dd748.gz
new file mode 100644 (file)
index 0000000..b04fe64
Binary files /dev/null and b/_darcs/patches/20050423030949-48b0a-07da52fd9e90c570754aff473397bbad371dd748.gz differ
diff --git a/_darcs/patches/20050502135743-bb3ee-eec9c722232316e0040f3ee2baa9df3f4ecd1514.gz b/_darcs/patches/20050502135743-bb3ee-eec9c722232316e0040f3ee2baa9df3f4ecd1514.gz
new file mode 100644 (file)
index 0000000..985b1bf
Binary files /dev/null and b/_darcs/patches/20050502135743-bb3ee-eec9c722232316e0040f3ee2baa9df3f4ecd1514.gz differ
diff --git a/_darcs/patches/pending b/_darcs/patches/pending
new file mode 100644 (file)
index 0000000..2c63c08
--- /dev/null
@@ -0,0 +1,2 @@
+{
+}
diff --git a/_darcs/patches/unrevert b/_darcs/patches/unrevert
new file mode 100644 (file)
index 0000000..80c2ddb
--- /dev/null
@@ -0,0 +1,124 @@
+
+New patches:
+
+[unrevert
+anonymous**20050405173436] 
+<
+> {
+hunk ./debian/changelog 62
+   * Remove conflict with old, experimental-only version of dhcp-client.
++v v v v v v v
+  -- Anthony Towns <ajt@debian.org>  Mon,  4 Apr 2005 23:41:06 +1000
+hunk ./debian/changelog 64
++^ ^ ^ ^ ^ ^ ^
+ ifupdown (0.6.4-4.12) unstable; urgency=low
+}
+
+Context:
+
+[use ajt@d.o address
+Anthony Towns <aj@azure.humbug.org.au>**20050405173454] 
+[update dateline for 0.6.5 to match what was uploaded
+Anthony Towns <aj@azure.humbug.org.au>**20050405164951] 
+[name the release
+Anthony Towns <aj@azure.humbug.org.au>**20050405164921] 
+[deal with dangling /etc/network/run symlink on upgrade
+Anthony Towns <aj@azure.humbug.org.au>**20050405164913] 
+[fix handling when logical and physical iface names don't match
+Anthony Towns <aj@azure.humbug.org.au>**20050405164755] 
+[change section to base
+Anthony Towns <aj@azure.humbug.org.au>**20050404153209] 
+[fix wrong variable name in ifupdown.init
+Anthony Towns <aj@azure.humbug.org.au>**20050404111950] 
+[remove conflict with old dhcp-client version
+Anthony Towns <aj@azure.humbug.org.au>**20050404111917] 
+[fix up documentation for changes so far
+Anthony Towns <aj@azure.humbug.org.au>**20050404030334] 
+[document --allow implementation in the code
+Anthony Towns <aj@azure.humbug.org.au>**20050404030209] 
+[fix syntax error in ifupdown.init
+Anthony Towns <aj@azure.humbug.org.au>**20050404030039] 
+[rearrange BUGS some more
+Anthony Towns <aj@azure.humbug.org.au>**20050404011259] 
+[simplify debconf dependencies
+Anthony Towns <aj@azure.humbug.org.au>**20050403170919] 
+[ignore templates, gar
+Anthony Towns <aj@azure.humbug.org.au>**20050403170911] 
+[remove second dh_gencontrol invocation
+Anthony Towns <aj@azure.humbug.org.au>**20050403164804] 
+[remove parenthetical note that dash can't cope with
+Anthony Towns <aj@azure.humbug.org.au>**20050403164757] 
+[reprioritise BUGS some more
+Anthony Towns <aj@azure.humbug.org.au>**20050403164423] 
+[document lack of end-of-line comments
+Anthony Towns <aj@azure.humbug.org.au>**20050403161830] 
+[ifstate docs are waiting on restructuring ifstate
+Anthony Towns <aj@azure.humbug.org.au>**20050403161634] 
+[tidy up <<clear environ..>> chunk
+Anthony Towns <aj@azure.humbug.org.au>**20050403161611] 
+[add PHASE var
+Anthony Towns <aj@azure.humbug.org.au>**20050403161538] 
+[reprioritise LOGICAL for mapping scripts
+Anthony Towns <aj@azure.humbug.org.au>**20050403161110] 
+[fix up error message
+Anthony Towns <aj@azure.humbug.org.au>**20050403160952] 
+[add LOGICAL to variables for scripts
+Anthony Towns <aj@azure.humbug.org.au>**20050403160939] 
+[add VERBOSITY, invoke run-parts with --verbose
+Anthony Towns <aj@azure.humbug.org.au>**20050403155657] 
+[remove unused chunk, gah
+Anthony Towns <aj@azure.humbug.org.au>**20050403154821] 
+[reprioritise the /e/n/i enhancements
+Anthony Towns <aj@azure.humbug.org.au>**20050403150728] 
+[tidy up debian/rules a little more
+Anthony Towns <aj@azure.humbug.org.au>**20050403150711] 
+[debian/rules test is a no-op when cross building
+Anthony Towns <aj@azure.humbug.org.au>**20050403150657] 
+[cope with /etc/network/ifstate being a symlink
+Anthony Towns <aj@azure.humbug.org.au>**20050403150343] 
+[add some more informative comments i/o
+Anthony Towns <aj@azure.humbug.org.au>**20050403150334] 
+[handle /e/n/run and /e/n/run/ifstate creation/transition a little more carefully
+Anthony Towns <aj@azure.humbug.org.au>**20050403142603] 
+[indent postinst to two space tabs
+Anthony Towns <aj@azure.humbug.org.au>**20050403133706] 
+[mv ifstate into /etc/network/run, simplify handling
+Anthony Towns <aj@azure.humbug.org.au>**20050403130722] 
+[annotate BUGS some more
+Anthony Towns <aj@azure.humbug.org.au>**20050403071601] 
+[fix grammar in changelog a bit
+Anthony Towns <aj@azure.humbug.org.au>**20050331140306] 
+[note debian-native in changelog
+Anthony Towns <aj@azure.humbug.org.au>**20050326151130] 
+[add version notes
+Anthony Towns <aj@azure.humbug.org.au>**20050326151125] 
+[add BUGS file to categoris bugs in the BTS
+Anthony Towns <aj@azure.humbug.org.au>**20050325174926] 
+[update generated files
+Anthony Towns <aj@azure.humbug.org.au>**20050325174749] 
+[satiate POSIX sh monkeys
+Anthony Towns <aj@azure.humbug.org.au>**20050325174738] 
+[support for --allow=hotplug, etc
+Anthony Towns <aj@azure.humbug.org.au>**20050325173537] 
+[fix grammar for exclude interfaces chunk
+Anthony Towns <aj@azure.humbug.org.au>**20050325173048] 
+[undocument --exclude option
+Anthony Towns <aj@azure.humbug.org.au>**20050325172831] 
+[update copyright, bump version
+Anthony Towns <aj@azure.humbug.org.au>**20050325172759] 
+[add post-up / pre-down aliases for up / down in interfaces file
+Anthony Towns <aj@azure.humbug.org.au>**20050322191425] 
+[remove generated files
+Anthony Towns <aj@azure.humbug.org.au>**20050322190943] 
+[don't re-build unnecessarily in debian/rules
+Anthony Towns <aj@azure.humbug.org.au>**20050322185930] 
+[MU, version bump
+Anthony Towns <aj@azure.humbug.org.au>**20050322185711] 
+[ifupdown 0.6.4-4.12
+Anthony Towns <aj@azure.humbug.org.au>**20050322184259] 
+Patch bundle hash:
+4ed746e15cf9bfd8ef8d8d58101c2ef301b5f6b4
diff --git a/_darcs/prefs/author b/_darcs/prefs/author
new file mode 100644 (file)
index 0000000..f77b644
--- /dev/null
@@ -0,0 +1 @@
+aj@azure.humbug.org.au
\ No newline at end of file
diff --git a/_darcs/prefs/binaries b/_darcs/prefs/binaries
new file mode 100644 (file)
index 0000000..8cbe077
--- /dev/null
@@ -0,0 +1,39 @@
+# Binary file regexps:
+\.png$
+\.PNG$
+\.gz$
+\.GZ$
+\.pdf$
+\.PDF$
+\.jpg$
+\.JPG$
+\.gif$
+\.GIF$
+\.tar$
+\.TAR$
+\.bz2$
+\.BZ2$
+\.z$
+\.Z$
+\.zip$
+\.ZIP$
+\.jar$
+\.JAR$
+\.so$
+\.SO$
+\.a$
+\.A$
+\.tgz$
+\.TGZ$
+\.jpeg$
+\.JPEG$
+\.mpg$
+\.MPG$
+\.mpeg$
+\.MPEG$
+\.iso$
+\.ISO$
+\.exe$
+\.EXE$
+\.doc$
+\.DOC$
diff --git a/_darcs/prefs/boring b/_darcs/prefs/boring
new file mode 100644 (file)
index 0000000..4318648
--- /dev/null
@@ -0,0 +1,26 @@
+# Boring file regexps:
+\.hi$
+\.o$
+(^|/)CVS($|/)
+(^|/)RCS($|/)
+~$
+#(^|/)\.[^/]
+(^|/)_darcs($|/)
+\.bak$
+\.BAK$
+\.orig$
+(^|/)vssver\.scc$
+\.swp$
+(^|/)MT($|/)
+(^|/)\{arch\}($|/)
+(^|/).arch-ids($|/)
+(^|/),
+\.class$
+\.prof$
+(^|/)\.DS_Store$
+(^|/)BitKeeper($|/)
+(^|/)ChangeSet($|/)
+(^|/)\.svn($|/)
+\.py[co]$
+\#
+\.cvsignore$
diff --git a/_darcs/prefs/defaultrepo b/_darcs/prefs/defaultrepo
new file mode 100644 (file)
index 0000000..6a71e76
--- /dev/null
@@ -0,0 +1 @@
+http://www.erisian.com.au/darcs/ifupdown/hacking/0.7
diff --git a/_darcs/prefs/motd b/_darcs/prefs/motd
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/_darcs/prefs/repos b/_darcs/prefs/repos
new file mode 100644 (file)
index 0000000..6a71e76
--- /dev/null
@@ -0,0 +1 @@
+http://www.erisian.com.au/darcs/ifupdown/hacking/0.7
diff --git a/addrfam.c b/addrfam.c
new file mode 100644 (file)
index 0000000..ddfc906
--- /dev/null
+++ b/addrfam.c
@@ -0,0 +1,23 @@
+#line 450 "ifupdown.nw"
+#include <stdlib.h>
+#include "header.h"
+
+#line 3825 "ifupdown.nw"
+extern address_family addr_inet;
+#line 4005 "ifupdown.nw"
+extern address_family addr_inet6;
+#line 4076 "ifupdown.nw"
+extern address_family addr_ipx;
+
+#line 455 "ifupdown.nw"
+address_family *addr_fams[] = {
+       
+#line 3829 "ifupdown.nw"
+&addr_inet, 
+#line 4009 "ifupdown.nw"
+&addr_inet6,
+#line 4080 "ifupdown.nw"
+&addr_ipx,
+#line 457 "ifupdown.nw"
+       NULL
+};
diff --git a/archlinux.c b/archlinux.c
new file mode 100644 (file)
index 0000000..057a103
--- /dev/null
@@ -0,0 +1,39 @@
+#line 3782 "ifupdown.nw"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/utsname.h>
+#include <sys/stat.h>
+
+#include "archlinux.h"
+
+unsigned int mylinuxver() {
+       static int maj = -1, rev, min;
+
+       if (maj == -1) {
+               struct utsname u;
+               char *pch;
+               uname(&u);
+               maj = atoi(u.release);
+               pch = strchr(u.release, '.');
+               rev = atoi(pch+1);
+               pch = strchr(pch+1, '.');
+               min = atoi(pch+1);
+       }
+
+       return mylinux(maj,rev,min);
+}
+
+unsigned int mylinux(int maj, int rev, int min) { 
+       return min | rev << 10 | maj << 13;
+}
+
+int execable(char *program) {
+       struct stat buf;
+
+       if (0 == stat(program, &buf)) {
+               if (S_ISREG(buf.st_mode) && (S_IXUSR & buf.st_mode)) return 1;
+       }
+       return 0;
+}
diff --git a/archlinux.h b/archlinux.h
new file mode 100644 (file)
index 0000000..4973e33
--- /dev/null
@@ -0,0 +1,4 @@
+#line 3776 "ifupdown.nw"
+unsigned int mylinuxver();
+unsigned int mylinux(int,int,int);
+int execable(char *);
diff --git a/biblio.bib b/biblio.bib
new file mode 100644 (file)
index 0000000..134498f
--- /dev/null
@@ -0,0 +1,42 @@
+@Book{K&R,
+  author =      {Brian Kernighan and Dennis Ritchie},
+  title =       {The C Programming Language},
+  publisher =   {Prentice Hall},
+  year =        {1988},
+  edition =     {Second},
+}
+
+@Book{camel,
+  author =      {Larry Wall and Tom Christiansen and Randal Schwartz},
+  title =       {Programming Perl},
+  publisher =   {O'Reilley and Associates},
+  year =        {1996},
+}
+
+@Book{StevensUnix,
+  author =      {W. Richard Stevens},
+  title =       {Advanced Programming in the UNIX Environment},
+  publisher =   {Addison-Wesley},
+  year =        {1997},
+}
+
+@Book{latex,
+  author =      {Leslie Lamport},
+  title =       {\LaTeX --- A Document Preparation System},
+  publisher =   {Addison Wesley},
+  year =        {1994},
+}
+
+@Misc{recursivemake,
+  author =      {Peter Miller {\tt <millerp@canb.auug.org.au>}},
+  title =       {Recursive Make Considered Harmful},
+  year =        {1997},
+}
+
+@Misc{wwwnoweb,
+  author =       {Norman Ramsey},
+  title =        {{\tt noweb} home page},
+  howpublished = {{\tt http://www.cs.virginia.edu/\~{}nr/noweb/}},
+}
+
+
diff --git a/config.c b/config.c
new file mode 100644 (file)
index 0000000..1ec0a99
--- /dev/null
+++ b/config.c
@@ -0,0 +1,665 @@
+#line 1033 "ifupdown.nw"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#line 1044 "ifupdown.nw"
+#include "header.h"
+#line 1263 "ifupdown.nw"
+#include <errno.h>
+#line 1397 "ifupdown.nw"
+#include <ctype.h>
+#line 1240 "ifupdown.nw"
+static int get_line(char **result, size_t *result_len, FILE *f, int *line);
+#line 1467 "ifupdown.nw"
+static char *next_word(char *buf, char *word, int maxlen);
+#line 1704 "ifupdown.nw"
+static address_family *get_address_family(address_family *af[], char *name);
+#line 1739 "ifupdown.nw"
+static method *get_method(address_family *af, char *name);
+#line 1800 "ifupdown.nw"
+static int duplicate_if(interface_defn *ifa, interface_defn *ifb);
+#line 1919 "ifupdown.nw"
+allowup_defn *get_allowup(allowup_defn **allowups, char *name);
+
+#line 1957 "ifupdown.nw"
+allowup_defn *add_allow_up(char *filename, int line,
+        allowup_defn *allow_up, char *iface_name);
+#line 1174 "ifupdown.nw"
+interfaces_file *read_interfaces(char *filename) {
+       
+#line 1210 "ifupdown.nw"
+FILE *f;
+int line;
+#line 1247 "ifupdown.nw"
+char *buf = NULL;
+size_t buf_len = 0;
+#line 1447 "ifupdown.nw"
+interface_defn *currif = NULL;
+mapping_defn *currmap = NULL;
+enum { NONE, IFACE, MAPPING } currently_processing = NONE;
+#line 1458 "ifupdown.nw"
+char firstword[80];
+char *rest;
+#line 1176 "ifupdown.nw"
+       interfaces_file *defn;
+
+       
+#line 1195 "ifupdown.nw"
+defn = malloc(sizeof(interfaces_file));
+if (defn == NULL) {
+       return NULL;
+}
+defn->allowups = NULL;
+defn->mappings = NULL;
+defn->ifaces = NULL;
+#line 1179 "ifupdown.nw"
+       
+#line 1215 "ifupdown.nw"
+f = fopen(filename, "r");
+if ( f == NULL ) return NULL;
+line = 0;
+
+#line 1181 "ifupdown.nw"
+       while (
+#line 1255 "ifupdown.nw"
+get_line(&buf,&buf_len,f,&line)
+#line 1181 "ifupdown.nw"
+                                             ) {
+               
+#line 1494 "ifupdown.nw"
+rest = next_word(buf, firstword, 80);
+if (rest == NULL) continue; /* blank line */
+
+if (strcmp(firstword, "mapping") == 0) {
+       
+#line 1546 "ifupdown.nw"
+currmap = malloc(sizeof(mapping_defn));
+if (currmap == NULL) {
+       
+#line 2008 "ifupdown.nw"
+perror(filename);
+return NULL;
+#line 1549 "ifupdown.nw"
+}
+#line 1553 "ifupdown.nw"
+currmap->max_matches = 0;
+currmap->n_matches = 0;
+currmap->match = NULL;
+
+while((rest = next_word(rest, firstword, 80))) {
+       if (currmap->max_matches == currmap->n_matches) {
+               char **tmp;
+               currmap->max_matches = currmap->max_matches * 2 + 1;
+               tmp = realloc(currmap->match, 
+                       sizeof(*tmp) * currmap->max_matches);
+               if (tmp == NULL) {
+                       currmap->max_matches = (currmap->max_matches - 1) / 2;
+                       
+#line 2008 "ifupdown.nw"
+perror(filename);
+return NULL;
+#line 1566 "ifupdown.nw"
+               }
+               currmap->match = tmp;
+       }
+
+       currmap->match[currmap->n_matches++] = strdup(firstword);
+}
+#line 1575 "ifupdown.nw"
+currmap->script = NULL;
+
+currmap->max_mappings = 0;
+currmap->n_mappings = 0;
+currmap->mapping = NULL;
+#line 1583 "ifupdown.nw"
+{
+       mapping_defn **where = &defn->mappings;
+       while(*where != NULL) {
+               where = &(*where)->next;
+       }
+       *where = currmap;
+       currmap->next = NULL;
+}
+#line 1499 "ifupdown.nw"
+       currently_processing = MAPPING;
+} else if (strcmp(firstword, "iface") == 0) {
+       
+#line 1635 "ifupdown.nw"
+{
+       
+#line 1668 "ifupdown.nw"
+char iface_name[80];
+char address_family_name[80];
+char method_name[80];
+
+#line 1638 "ifupdown.nw"
+       
+#line 1656 "ifupdown.nw"
+currif = malloc(sizeof(interface_defn));
+if (!currif) {
+       
+#line 2008 "ifupdown.nw"
+perror(filename);
+return NULL;
+#line 1659 "ifupdown.nw"
+}
+
+#line 1640 "ifupdown.nw"
+       
+#line 1674 "ifupdown.nw"
+rest = next_word(rest, iface_name, 80);
+rest = next_word(rest, address_family_name, 80);
+rest = next_word(rest, method_name, 80);
+
+if (rest == NULL) {
+       
+#line 2013 "ifupdown.nw"
+fprintf(stderr, "%s:%d: too few parameters for iface line\n", filename, line);
+return NULL;
+#line 1680 "ifupdown.nw"
+}
+
+if (rest[0] != '\0') {
+       
+#line 2018 "ifupdown.nw"
+fprintf(stderr, "%s:%d: too many parameters for iface line\n", filename, line);
+return NULL;
+#line 1684 "ifupdown.nw"
+}
+
+#line 1642 "ifupdown.nw"
+       
+#line 1690 "ifupdown.nw"
+currif->logical_iface = strdup(iface_name);
+if (!currif->logical_iface) {
+       
+#line 2008 "ifupdown.nw"
+perror(filename);
+return NULL;
+#line 1693 "ifupdown.nw"
+}
+#line 1643 "ifupdown.nw"
+       
+#line 1708 "ifupdown.nw"
+currif->address_family = get_address_family(addr_fams, address_family_name);
+if (!currif->address_family) {
+       
+#line 2023 "ifupdown.nw"
+fprintf(stderr, "%s:%d: unknown address type\n", filename, line);
+return NULL;
+#line 1711 "ifupdown.nw"
+}
+#line 1644 "ifupdown.nw"
+       
+#line 1743 "ifupdown.nw"
+currif->method = get_method(currif->address_family, method_name);
+if (!currif->method) {
+       
+#line 2028 "ifupdown.nw"
+fprintf(stderr, "%s:%d: unknown method\n", filename, line);
+return NULL;
+#line 1746 "ifupdown.nw"
+       return NULL; /* FIXME */
+}
+#line 1645 "ifupdown.nw"
+       
+#line 1766 "ifupdown.nw"
+currif->automatic = 1;
+currif->max_options = 0;
+currif->n_options = 0;
+currif->option = NULL;
+
+#line 1647 "ifupdown.nw"
+       
+#line 1782 "ifupdown.nw"
+{
+       interface_defn **where = &defn->ifaces; 
+       while(*where != NULL) {
+               if (duplicate_if(*where, currif)) {
+                       
+#line 2033 "ifupdown.nw"
+fprintf(stderr, "%s:%d: duplicate interface\n", filename, line);
+return NULL;
+#line 1787 "ifupdown.nw"
+               }
+               where = &(*where)->next;
+       }
+
+       *where = currif;
+       currif->next = NULL;
+}
+#line 1648 "ifupdown.nw"
+}
+#line 1502 "ifupdown.nw"
+       currently_processing = IFACE;
+} else if (strcmp(firstword, "auto") == 0) {
+       
+#line 1898 "ifupdown.nw"
+allowup_defn *auto_ups = get_allowup(&defn->allowups, "auto");
+if (!auto_ups) {
+       
+#line 2008 "ifupdown.nw"
+perror(filename);
+return NULL;
+#line 1901 "ifupdown.nw"
+}
+while((rest = next_word(rest, firstword, 80))) {
+       if (!add_allow_up(filename, line, auto_ups, firstword))
+               return NULL;
+}
+#line 1505 "ifupdown.nw"
+       currently_processing = NONE;
+} else if (strncmp(firstword, "allow-", 6) == 0 && strlen(firstword) > 6) {
+       
+#line 1908 "ifupdown.nw"
+allowup_defn *allow_ups = get_allowup(&defn->allowups, firstword + 6);
+if (!allow_ups) {
+       
+#line 2008 "ifupdown.nw"
+perror(filename);
+return NULL;
+#line 1911 "ifupdown.nw"
+}
+while((rest = next_word(rest, firstword, 80))) {
+       if (!add_allow_up(filename, line, allow_ups, firstword))
+               return NULL;
+}
+#line 1508 "ifupdown.nw"
+       currently_processing = NONE;
+} else {
+       
+#line 1515 "ifupdown.nw"
+switch(currently_processing) {
+       case IFACE:
+               
+#line 1821 "ifupdown.nw"
+if (strcmp(firstword, "post-up") == 0) {
+       strcpy(firstword, "up");
+}
+if (strcmp(firstword, "pre-down") == 0) {
+       strcpy(firstword, "down");
+} 
+#line 1830 "ifupdown.nw"
+{
+       int i;
+
+       if (strlen (rest) == 0) {
+               
+#line 2059 "ifupdown.nw"
+fprintf(stderr, "%s:%d: option with empty value\n", filename, line);
+return NULL;
+#line 1835 "ifupdown.nw"
+       }
+
+       if (strcmp(firstword, "pre-up") != 0 
+           && strcmp(firstword, "up") != 0
+           && strcmp(firstword, "down") != 0
+           && strcmp(firstword, "post-down") != 0)
+        {
+               for (i = 0; i < currif->n_options; i++) {
+                       if (strcmp(currif->option[i].name, firstword) == 0) {
+                               
+#line 2044 "ifupdown.nw"
+fprintf(stderr, "%s:%d: duplicate option\n", filename, line);
+return NULL;
+#line 1845 "ifupdown.nw"
+                       }
+               }
+       }
+}
+#line 1857 "ifupdown.nw"
+if (currif->n_options >= currif->max_options) {
+       
+#line 1879 "ifupdown.nw"
+{
+       variable *opt;
+       currif->max_options = currif->max_options + 10;
+       opt = realloc(currif->option, sizeof(*opt) * currif->max_options);
+       if (opt == NULL) {
+               
+#line 2008 "ifupdown.nw"
+perror(filename);
+return NULL;
+#line 1885 "ifupdown.nw"
+       }
+       currif->option = opt;
+}
+#line 1859 "ifupdown.nw"
+}
+
+currif->option[currif->n_options].name = strdup(firstword);
+currif->option[currif->n_options].value = strdup(rest);
+
+if (!currif->option[currif->n_options].name) {
+       
+#line 2008 "ifupdown.nw"
+perror(filename);
+return NULL;
+#line 1866 "ifupdown.nw"
+}
+
+if (!currif->option[currif->n_options].value) {
+       
+#line 2008 "ifupdown.nw"
+perror(filename);
+return NULL;
+#line 1870 "ifupdown.nw"
+}
+
+currif->n_options++;   
+#line 1518 "ifupdown.nw"
+               break;
+       case MAPPING:
+               
+#line 1598 "ifupdown.nw"
+if (strcmp(firstword, "script") == 0) {
+       
+#line 1608 "ifupdown.nw"
+if (currmap->script != NULL) {
+       
+#line 2049 "ifupdown.nw"
+fprintf(stderr, "%s:%d: duplicate script in mapping\n", filename, line);
+return NULL;
+#line 1610 "ifupdown.nw"
+} else {
+       currmap->script = strdup(rest);
+}
+#line 1600 "ifupdown.nw"
+} else if (strcmp(firstword, "map") == 0) {
+       
+#line 1616 "ifupdown.nw"
+if (currmap->max_mappings == currmap->n_mappings) {
+       char **opt;
+       currmap->max_mappings = currmap->max_mappings * 2 + 1;
+       opt = realloc(currmap->mapping, sizeof(*opt) * currmap->max_mappings);
+       if (opt == NULL) {
+               
+#line 2008 "ifupdown.nw"
+perror(filename);
+return NULL;
+#line 1622 "ifupdown.nw"
+       }
+       currmap->mapping = opt;
+}
+currmap->mapping[currmap->n_mappings] = strdup(rest);
+currmap->n_mappings++;
+#line 1602 "ifupdown.nw"
+} else {
+       
+#line 2054 "ifupdown.nw"
+fprintf(stderr, "%s:%d: misplaced option\n", filename, line);
+return NULL;
+#line 1604 "ifupdown.nw"
+}
+#line 1521 "ifupdown.nw"
+               break;
+       case NONE:
+       default:
+               
+#line 2054 "ifupdown.nw"
+fprintf(stderr, "%s:%d: misplaced option\n", filename, line);
+return NULL;
+#line 1525 "ifupdown.nw"
+}
+#line 1511 "ifupdown.nw"
+}
+#line 1183 "ifupdown.nw"
+       }
+       if (
+#line 1267 "ifupdown.nw"
+ferror(f) != 0
+#line 1184 "ifupdown.nw"
+                                           ) {
+               
+#line 2008 "ifupdown.nw"
+perror(filename);
+return NULL;
+#line 1186 "ifupdown.nw"
+       }
+
+       
+#line 1221 "ifupdown.nw"
+fclose(f);
+line = -1;
+
+#line 1190 "ifupdown.nw"
+       return defn;
+}
+#line 1280 "ifupdown.nw"
+static int get_line(char **result, size_t *result_len, FILE *f, int *line) {
+       
+#line 1305 "ifupdown.nw"
+size_t pos;
+
+#line 1283 "ifupdown.nw"
+       do {
+               
+#line 1312 "ifupdown.nw"
+pos = 0;
+#line 1285 "ifupdown.nw"
+               
+#line 1323 "ifupdown.nw"
+do {
+       
+#line 1344 "ifupdown.nw"
+if (*result_len - pos < 10) {
+       char *newstr = realloc(*result, *result_len * 2 + 80);
+       if (newstr == NULL) {
+               return 0;
+       }
+       *result = newstr;
+       *result_len = *result_len * 2 + 80;
+}
+#line 1325 "ifupdown.nw"
+       
+#line 1373 "ifupdown.nw"
+if (!fgets(*result + pos, *result_len - pos, f)) {
+       if (ferror(f) == 0 && pos == 0) return 0;
+       if (ferror(f) != 0) return 0;
+}
+pos += strlen(*result + pos);
+#line 1326 "ifupdown.nw"
+} while(
+#line 1364 "ifupdown.nw"
+pos == *result_len - 1 && (*result)[pos-1] != '\n'
+#line 1326 "ifupdown.nw"
+                                   );
+
+#line 1385 "ifupdown.nw"
+if (pos != 0 && (*result)[pos-1] == '\n') {
+       (*result)[--pos] = '\0';
+}
+
+#line 1330 "ifupdown.nw"
+(*line)++;
+
+assert( (*result)[pos] == '\0' );
+#line 1286 "ifupdown.nw"
+               
+#line 1401 "ifupdown.nw"
+{ 
+       int first = 0; 
+       while (isspace((*result)[first]) && (*result)[first]) {
+               first++;
+       }
+
+       memmove(*result, *result + first, pos - first + 1);
+       pos -= first;
+}
+#line 1287 "ifupdown.nw"
+       } while (
+#line 1425 "ifupdown.nw"
+(*result)[0] == '#'
+#line 1287 "ifupdown.nw"
+                               );
+
+       while (
+#line 1429 "ifupdown.nw"
+(*result)[pos-1] == '\\'
+#line 1289 "ifupdown.nw"
+                               ) {
+               
+#line 1433 "ifupdown.nw"
+(*result)[--pos] = '\0';
+#line 1291 "ifupdown.nw"
+               
+#line 1323 "ifupdown.nw"
+do {
+       
+#line 1344 "ifupdown.nw"
+if (*result_len - pos < 10) {
+       char *newstr = realloc(*result, *result_len * 2 + 80);
+       if (newstr == NULL) {
+               return 0;
+       }
+       *result = newstr;
+       *result_len = *result_len * 2 + 80;
+}
+#line 1325 "ifupdown.nw"
+       
+#line 1373 "ifupdown.nw"
+if (!fgets(*result + pos, *result_len - pos, f)) {
+       if (ferror(f) == 0 && pos == 0) return 0;
+       if (ferror(f) != 0) return 0;
+}
+pos += strlen(*result + pos);
+#line 1326 "ifupdown.nw"
+} while(
+#line 1364 "ifupdown.nw"
+pos == *result_len - 1 && (*result)[pos-1] != '\n'
+#line 1326 "ifupdown.nw"
+                                   );
+
+#line 1385 "ifupdown.nw"
+if (pos != 0 && (*result)[pos-1] == '\n') {
+       (*result)[--pos] = '\0';
+}
+
+#line 1330 "ifupdown.nw"
+(*line)++;
+
+assert( (*result)[pos] == '\0' );
+#line 1292 "ifupdown.nw"
+       }
+
+       
+#line 1413 "ifupdown.nw"
+while (isspace((*result)[pos-1])) { /* remove trailing whitespace */
+       pos--;
+}
+(*result)[pos] = '\0';
+
+#line 1296 "ifupdown.nw"
+       return 1;
+}
+#line 1471 "ifupdown.nw"
+static char *next_word(char *buf, char *word, int maxlen) {
+       if (!buf) return NULL;
+       if (!*buf) return NULL;
+
+       while(!isspace(*buf) && *buf) {
+               if (maxlen-- > 1) *word++ = *buf;
+               buf++;
+       }
+       if (maxlen > 0) *word = '\0';
+
+       while(isspace(*buf) && *buf) buf++;
+
+       return buf;
+}
+#line 1720 "ifupdown.nw"
+static address_family *get_address_family(address_family *af[], char *name) {
+       int i;
+       for (i = 0; af[i]; i++) {
+               if (strcmp(af[i]->name, name) == 0) {
+                       return af[i];
+               }
+       }
+       return NULL;
+}
+#line 1751 "ifupdown.nw"
+static method *get_method(address_family *af, char *name) {
+       int i;
+       for (i = 0; i < af->n_methods; i++) {
+               if (strcmp(af->method[i].name, name) == 0) {
+                       return &af->method[i];
+               }
+       }
+       return NULL;
+}
+#line 1804 "ifupdown.nw"
+static int duplicate_if(interface_defn *ifa, interface_defn *ifb) {
+       if (strcmp(ifa->logical_iface, ifb->logical_iface) != 0) return 0;
+       if (ifa->address_family != ifb->address_family) return 0;
+       return 1;
+}
+#line 1922 "ifupdown.nw"
+allowup_defn *get_allowup(allowup_defn **allowups, char *name) {
+       for (; *allowups; allowups = &(*allowups)->next) {
+               if (strcmp((*allowups)->when, name) == 0) break;
+       }
+       if (*allowups == NULL) {
+               *allowups = malloc(sizeof(allowup_defn));
+               if (*allowups == NULL) return NULL;
+               (*allowups)->when = strdup(name);
+               (*allowups)->next = NULL;
+               (*allowups)->max_interfaces = 0;
+               (*allowups)->n_interfaces = 0;
+               (*allowups)->interfaces = NULL;
+       }
+       return *allowups;
+}
+#line 1947 "ifupdown.nw"
+allowup_defn *find_allowup(interfaces_file *defn, char *name) {
+       allowup_defn *allowups = defn->allowups;
+       for (; allowups; allowups = allowups->next) {
+               if (strcmp(allowups->when, name) == 0) break;
+       }
+       return allowups;
+}
+#line 1962 "ifupdown.nw"
+allowup_defn *add_allow_up(char *filename, int line,
+       allowup_defn *allow_up, char *iface_name)
+{
+       
+#line 1972 "ifupdown.nw"
+{
+       int i;
+
+       for (i = 0; i < allow_up->n_interfaces; i++) {
+               if (strcmp(iface_name, allow_up->interfaces[i]) == 0) {
+                       
+#line 2038 "ifupdown.nw"
+fprintf(stderr, "%s:%d: interface %s declared allow-%s twice\n", 
+       filename, line, iface_name, allow_up->when);
+return NULL;
+#line 1978 "ifupdown.nw"
+               }
+       }
+}
+#line 1966 "ifupdown.nw"
+       
+#line 1984 "ifupdown.nw"
+if (allow_up->n_interfaces == allow_up->max_interfaces) {
+       char **tmp;
+       allow_up->max_interfaces *= 2;
+       allow_up->max_interfaces++;
+       tmp = realloc(allow_up->interfaces, 
+               sizeof(*tmp) * allow_up->max_interfaces);
+       if (tmp == NULL) {
+               
+#line 2008 "ifupdown.nw"
+perror(filename);
+return NULL;
+#line 1992 "ifupdown.nw"
+       }
+       allow_up->interfaces = tmp;
+}
+
+allow_up->interfaces[allow_up->n_interfaces] = strdup(iface_name);
+allow_up->n_interfaces++;
+#line 1967 "ifupdown.nw"
+       return allow_up;
+}
diff --git a/contrib/ensureifup b/contrib/ensureifup
new file mode 100644 (file)
index 0000000..b949648
--- /dev/null
@@ -0,0 +1,30 @@
+#!/bin/sh
+# This script is useful to check wether an interface is up and,
+# if not, it attempts to bring it back. This can be necessary
+# if your ISP provider causes occasional outages.
+# Some ISPs are known to termine connections when they reach
+# 24 hours to "prevent abuse".
+# Run this script through cron (every 5 minutes? your call)
+# and ensure that ifstate is located where it is defined below.
+#
+# NOTE: This script is just provided as an example. If you want this
+# feature you might be better off installing ifplugd which provides
+# similar functionality (but more featureful) out of the box.
+
+# TODO:
+# Improve it so it can find out (eg from /etc/network/run/ifstate)
+# whether an interface was brought down
+# unexpectedly, or if a clean "ifdown" was issued.
+
+iface="$1"
+ifstate=/usr/local/sbin/ifstate
+
+if [ `$ifstate "$iface"` = DOWN ]
+then
+    logger -s "Trying to bring $iface back up..."
+    ifdown "$iface"
+    ifup "$iface"
+    [ `$ifstate "$iface"` = UP ] && logger -s "$iface now up again"
+fi
+
+exit 0
diff --git a/contrib/ifstate b/contrib/ifstate
new file mode 100644 (file)
index 0000000..cd79e19
--- /dev/null
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+iface="$1"
+if [ -z "$iface" ] ; then
+       echo "Usage: $0 IFACE"
+       exit 1
+fi
+
+if ifconfig "$iface" | grep -Fw UP >/dev/null
+then
+       echo UP
+else
+       echo DOWN
+fi
diff --git a/contrib/ifstate-check b/contrib/ifstate-check
new file mode 100644 (file)
index 0000000..4f99d8a
--- /dev/null
@@ -0,0 +1,86 @@
+#!/usr/bin/perl
+#
+# Generate a report of the status of interfaces configured
+# by 'ifupdown'
+# (c) 2004 Javier Fernandez-Sanguino <jfs@debian.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; either version 2 of the License, or
+#    (at your option) any later version.
+#
+#    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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+
+$statefile="/etc/network/run/ifstate";
+$configfile="/etc/network/interfaces";
+
+open (IFACE,"<$configfile") || die ("Could not open $configfile: $!\n");
+while (<IFACE>) {
+       chomp;
+       if ( /^iface\s+(\w+)\s+/ ) {
+               $configured{$1}=$_; 
+       }
+}
+
+close IFACE;
+
+open (IPLINK,"ip link show|") || die ("Could not execute ip: $!\n");
+while (<IPLINK>) {
+       chomp;
+# FORMAT
+# #: AAAA: <XXXXX,UP> mtu 16436 qdisc noqueue
+       if ( /^\d+: (\w+):.*?\<.*?,UP.*?\>/ ) {
+               $iplink{$1}=$_;
+       }
+}
+close IPLINK;
+
+
+open (STATE,"<$statefile") || die ("Could not open $statefile: $!\n");
+$line = 0;
+while (<STATE>) {
+       chomp;
+       $line++;
+# Format is IFACE=IFACE
+       if ( /^(\w+)=(\w+)$/ ) {
+               $iface = $1;
+               $ifaces = $2;
+               if ( $iface ne $ifaces ) {
+                       print STDERR "Error in $statefile (line $line), interface names do not match ('$iface' and '$ifaces')\n";
+               } else {
+                       check_status($iface);
+               }
+       } else {
+               print STDERR "Error in $statefile (line $line), unknown content\n";
+       }
+
+}
+close STATE;
+
+exit 0;
+
+sub check_status {
+       my ($int) = @_;
+       print "$int: ";
+       my $status = "UP";
+# Check if it's really up, this is done basicly because ifupdown
+# might not have configured it properly even if it thinks he has
+# (sample: ifconfig croaks when wrong parameters are used and 
+# ifupdown does not detect that the system call went awry)
+       $status = "ERROR_NOT_REALLY_UP" if ! defined ($iplink{$int}) ;
+       if ( defined ( $configured{$int} ) ) {
+               $status .= ",CONFIGURED";
+       } else {
+               $status .= ",MANUALLY_CONFIGURED";
+       }
+       print "$status\n";
+       return 0;
+}
diff --git a/debian/TODO b/debian/TODO
new file mode 100644 (file)
index 0000000..8532938
--- /dev/null
@@ -0,0 +1,19 @@
+
+- The documentation in pdf generated by the .dia files does not show
+  up properly (it is bigger than the PDF itself)
+
+- There is currently no way to build an ifudown-doc package. Since dia
+  cannot be used without a $DISPLAY the only alternatives are to 
+  either build the dia stuff manually (for autobuilders) and build the
+  docs with the package or build all the docs manually and use a 
+  a 'clean-everything-but-docs' target to clean the package when building.
+
+- More documentation on how to configure ifupdown for different goals
+  is needed. A lot of content is already available in
+  the Debian Reference, but more detailed examples would be useful
+  (and should be included in a separate ifupdown-doc package)
+  See: http://www.debian.org/doc/manuals/reference/ch-gateway.en.html#s-net-high)
+
+- When compiling the package there are errors related to po files not being
+  correct. This is because of the current hack for woody compatibility in
+  debian/rules. Remove when sarge is released?
diff --git a/debian/changelog b/debian/changelog
new file mode 100644 (file)
index 0000000..2b51a75
--- /dev/null
@@ -0,0 +1,630 @@
+ifupdown (0.6.7osso+s4) unstable; urgency=low
+
+  * Bring interface usb0 automatically by default
+
+ -- Karol Lewandowski <k.lewandowsk@samsung.com>  Wed, 26 May 2010 22:03:36 +0200
+
+ifupdown (0.6.7osso+s3) unstable; urgency=low
+
+  * Set myself as maintainer.
+
+ -- Rafal Krypa <r.krypa@samsung.com>  Tue, 20 Apr 2010 18:29:43 +0200
+
+ifupdown (0.6.7osso+s2) unstable; urgency=low
+
+  * debian/control: added Uploaders field.
+
+ -- Rafal Krypa <r.krypa@samsung.com>  Thu, 04 Feb 2010 11:22:48 +0900
+
+ifupdown (0.6.7osso+s1) unstable; urgency=low
+
+  * Add etc/network/interfaces file for SLP 2.0
+  * Add LSB headers to init scripts
+  * debian/rules: switch order of dh_installinit for ifupdown and
+    ifupdown-clean to allow proper dependency boot calculation
+
+ -- Rafal Krypa <r.krypa@samsung.com>  Wed, 27 Jan 2010 13:27:31 +0900
+
+ifupdown (0.6.7osso) unstable; urgency=low
+
+  * build-dep on nowebm removed
+  * build-dep on po-debconf added 
+
+ -- Ed Bartosh <eduard.bartosh@nokia.com>  Sat,  8 Apr 2006 23:08:21 +0300
+
+ifupdown (0.6.7) unstable; urgency=low
+
+  * Don't use dirname/basename in ifupdown init script; they're in /usr/bin.
+    (Closes: Bug#304188)
+
+  * Check for free space on /dev/shm when working out where to link
+    /e/n/run. Thanks to Jose Manuel Delgado Mendinueta. (Closes:
+    Bug#303656)
+
+ -- Anthony Towns <ajt@debian.org>  Mon,  2 May 2005 23:57:25 +1000
+
+ifupdown (0.6.6) unstable; urgency=low
+
+  * The "what does wine come in" release
+
+  * Fix brown paper bag bug where %iface% maps to the logical interface
+    name rather than the hardware one. Thanks to Paul Hampson for being
+    the first to spot it once the BTS was working again. Also add a test
+    case. (Closes: Bug#303148)
+
+  * Fix brown paper bag bug where "test -e" doesn't actually identify a
+    dangling /etc/network/run symlink on upgrade. (Closes: Bug#303225)
+
+  * Fix brown paper bag bug where we only consider pointing
+    /etc/network/run at /dev/shm if /dev/shm *isn't* in /proc/mounts. (No
+    bug filed yet, though...)
+
+ -- Anthony Towns <ajt@debian.org>  Tue,  5 Apr 2005 14:19:21 +1000
+
+ifupdown (0.6.5) unstable; urgency=low
+
+  * The Gernot Heiser release -- aged like a fine South Australian wine.
+
+  * Switch to Debian-native versioning / source packaging for the time being.
+    (Closes: Bug#84697)
+  * Change Section: to base, to match overrides.
+
+  * Thanks to Michael Weber, Javier Fernandez-Sanguino Pena, Marc
+    Haber, and Thomas Hood for NMUs. (Closes: Bug#150773, Bug#151465,
+    Bug#152893, Bug#208726, Bug#209006, Bug#242314, Bug#263913,
+    Bug#266282, Bug#297762)
+
+  * debian/rules: Don't re-build unnecessarily. Thanks to Michael Banck
+    (Closes: Bug#296273)
+
+  * Add post-up, pre-down as aliases for "up" and "down". (Closes: Bug#62633)
+
+  * Deprecate (undocument) "--exclude" option.
+
+  * Add support for "allow-*" lines for systems such as hotplug or ifplugd.
+    Usage is "ifup --allow=hotplug <interfaces>"; only the allowed interfaces
+    whill actually be tried. (Closes: Bug#300937)
+
+  * Satiate the POSIX sh monkeys, makenwdep.sh now uses printf for \t's,
+    not echo -e. (Closes: Bug#294970)
+
+  * Switch to using "/etc/network/run/ifstate" instead of
+    "/etc/network/ifstate". Simplify all the complicated hackery dealing
+    with that. Use myreadlink function instead of /lib/init/readlink.
+    (Closes: Bug#302519)
+
+  * Make debian/rules test always succeed when cross-building. Thanks
+    to NIIBE Yutaka. (Closes: Bug#283649)
+
+  * Add VERBOSITY variable for scripts, invoke run-parts with --verbose.
+    Thanks to Michael Weber. (Closes: Bug#88946)
+  * Add LOGICAL variable for scripts. (Doesn't work for mapping scripts yet
+    though)
+  * Add PHASE variable for scripts, same as MODE but more detailed;
+    pre-up, post-down, etc. (Closes: Bug#286155)
+
+  * Document lack of support for end-of-line comments in interfaces(5).
+    (Closes: Bug#79683)
+
+  * Remove conflict with old, experimental-only version of dhcp-client.
+
+ -- Anthony Towns <ajt@debian.org>  Mon,  4 Apr 2005 23:41:06 +1000
+
+ifupdown (0.6.4-4.12) unstable; urgency=low
+
+  * Non-maintainer upload
+  * Begin description synopsis with lower case letter
+  * postinst:
+    + Create run dir at the target of /etc/network/run if it is absent
+      (Closes: #297898)
+
+ -- Thomas Hood <jdthood@yahoo.co.uk>  Thu,  3 Mar 2005 19:05:05 +0100
+
+ifupdown (0.6.4-4.11) unstable; urgency=low
+
+  * Non-maintainer upload
+  * postinst:
+    + Do not make /etc/network/run a symlink to /dev/shm/network/
+      if devfs is in use.  (Closes: #266479)
+  * /etc/init.d/ifupdown:
+    + Don't accept arguments to "start" method
+    + Fix initscript output
+  * ifup.8:
+    + Correct typo (Closes: #287172)
+  * interfaces.5:
+    + Correct description of what happens when user commands fail
+      (Closes: #286166)
+    + Remove reference to VERBOSE which isn't implemented in this
+      version  (Reported in #88946)
+  * Add it.po thanks to Luca Monducci  (Closes: #284123)
+
+ -- Thomas Hood <jdthood@yahoo.co.uk>  Sun, 12 Sep 2004 14:46:29 +0200
+
+ifupdown (0.6.4-4.10) unstable; urgency=low
+
+  * Non-maintainer upload. Fix critical bugs.
+  * fix ifstate cleaning in init script. (Closes: #264134).
+  * fix /etc/network/run creation in postinst (Closes: #265165).
+
+ -- Marc Haber <mh+debian-packages@zugschlus.de>  Tue, 17 Aug 2004 06:38:16 +0200
+
+ifupdown (0.6.4-4.9) unstable; urgency=low
+
+  * Non-maintainer upload: bug fixes and some improvements, unfortunately
+    they will not make it to sarge...
+   [Javier Fernandez-Sanguino]
+    - Added a generic --exclude option (modified ifupdown.nw and ifup.8)
+      This way other scripts (such as /e/i/networking in netbase)
+      can avoid bringing down 'lo' on shutdown doing: 'ifdown -e lo -a'
+      This will help close #254705, #256680 and #208700.
+    - Make it conflict with the dch-client version from experimental 
+      (Closes: #242537, #242527)
+    - Added usage examples provided by Thomas Hood (Closes: #247772)
+    - L10n:
+       + Updated catalan debconf templates provided by Aleix Badia i Bosch 
+        (Closes: #248717)
+        + Included Lithuanian translation of debconf templates provided
+        by Gintautas Miliauskas (Closes: #249233)
+    - /etc/init.d/ifupdown: Exit with error if called with unknown arguments
+    - ifupdown.nw: fix FTBFS with gcc-3.4 (Closes: #258965)
+    - ifup.8: ammended manpage describing how ifdown really works 
+      (Closes: #259609)
+    - Remove XSI:isms in several scripts (Closes: #255574)
+    - debian/po/POTFILES.in:  point to templates.master instead of templates
+   [Thomas Hood]
+    - debian/control:
+       + Build-Depend on version of debhelper with dh_installinit --name
+       + Put dhcp3-client before dhcp-client in disjunctive dependency
+         (Closes: #250713)
+     - Add /etc/default/ifupdown (currently not used, will be in the
+       future)
+     - /etc/init.d/ifupdown:
+        + Creates target of /etc/network/run if the latter is a dangling
+         symlink.  Thanks to AJT for good discussion.  (Closes: #242607)
+        + Delete ifstate on stop  (Closes: #245067)
+    - /etc/init.d/ifupdown-clean
+        + Delete ifstate on stop  (Closes: #245067)
+    - debian/rules:
+        + Now use dh_installdebconf to install debconf stuff
+        + Install new ifupdown-clean initscript.  It runs at S:S18.
+        + ifupdown initscript now runs at 0,6:S36 as well as S:S39.
+        Note: this will only apply to new installations (not to upgrades)
+     - examples/*
+        + Move the contributed scripts to contrib/
+        + Clean up and add comments
+     - examples/check-mac-address.sh:
+        + Fix argument check  (Closes: #254388)
+     - debian/postrm:
+        + Delete configuration files on purge  (Closes: #255228)
+     - ifup.8
+        + Clean up
+        + Add EXAMPLES section  (Closes #247772)
+     - interfaces.5
+        + Mention wireless(7)  (Closes: #255218)
+        + Reorder content and do some other minor changes.
+     - debian/postinst:
+        + Create /etc/network/run symlink to /dev/shm/network/ if 
+         it does not exist
+        + Warn if "auto lo" or "iface lo" stanza absent from /e/n/i
+        (Closes: #121755)
+       
+ -- Javier Fernandez-Sanguino Pen~a <jfs@computer.org>  Wed, 28 Jul 2004 17:04:19 +0200
+
+
+ifupdown (0.6.4-4.8) unstable; urgency=low
+
+  * Fix configuration of interfaces with multiple address families.
+    (Closes: Bug#242867) 
+  * Add testcase 3 to check for such errors.
+
+ -- Anthony Towns <aj@azure.humbug.org.au>  Sat, 10 Apr 2004 16:47:57 +1000
+
+ifupdown (0.6.4-4.7) unstable; urgency=low
+
+  * Non-maintainer upload. This is mostly a bug-fix release, no new
+    features have been added and the behaviour of ifupdown has only changed
+    slightly. Content has been reviewed by both the maintainer and several
+    other maintainers (who have NMUed this package previously)
+    - Ifupdown.dvi now depends on *eps files (Closes: #101204)
+    - Added missing Build-Dep to noweb since the Makefile calls makenwdep.sh
+      (and it calls 'noroots') on build.
+    - Remove the undocumented (and unused) -s option from the manpage and the
+      main.c code. (Closes: #231404)
+    - inet6.defn
+      + Make it possible to run an v4tunnel without an address (Closes: #96265)
+    - inet.defn
+      + Included different handling of dhclient3 versus dhclient.
+      + Avoids inconsistency in interface state if the command run
+       by ifup fails, also added -e option to dhclient in order to 
+       have it return an error if it cannot get an address. 
+       Notice that this is not yet done with dhclient3 (-1) since that would
+       mean not running dhclient3 as a daemon and renews not being done.
+       (Closes: #97782, #82339, #113338, #148666, #169194)
+      + An independent lease file is created per interface so that dhclient
+       can be used in more than one interface (Closes: #196366)
+      + If dhcp3-client is installed (the binary /sbin/dhclient3 is available)
+       then use the -r option instead of with a KILL signal, this enables
+       it to release the DHCP release an execute the hook script before
+       exiting. Also, the package now suggests 'dhcp-client | dhcp3-client'
+       (since dhcp3-client does not provide dhcp-client as pump does)
+       (Closes: #196865)
+      + Added a metric option for routes, notice, however, the dhclient's
+       -e (undocumented) option is not included from the provided patch.
+       (Closes: #235993)
+      + Use -r instead of -k when DHCP interfaces using pump are downed in 
+       order to avoid killing all interfaces (only release the one asked for)
+       (Closes: #198841)
+      + Properly implement the 'hw' option in interfaces by defining the 
+       hardware address before upping the interface. 
+       (Closes: #224468, #84602)
+      + Allow setting of the hw address in the dhcp method as suggested.
+       (Closes: #135502)
+    - examples:
+      + Added an example in the interfaces file on how to setup an interface
+       with multiple IP addresses. I've added a warning, though, since this
+       is expected not to work in some cases and might generate inconsistencies
+       between the real state and the one noted down in the interfaces state
+       file. It is worth documenting this option (with known caveats) rather
+       than have users figure it out for themselves.
+       (Closes: #172147)
+      + Added sample scripts ('ensureifup' and 'ifstate') to ensure that
+       interfaces are always up (might be useful for crappy ISP providers)
+       as provided by Yann Dirson (Closes: #86902)
+      + Provide a 'generate-interfaces.pl' script under the examples dir
+       in order to facilitate migration of network configuration in 
+       pre-woody systems. This script might also be useful to migrate other
+       Linux systems to Debian.
+       (Closes: #57830)
+      + Added a sample 'ifstate-complex' command. Since it is not documented
+        I'm adding it to the examples and not closing #153222 with it (yet)
+      + Fixed a syntax error in the 'check-mac-address.sh' script and added
+        both a little bit of comment code and proper usage.
+      + Provided an example on how to setup an interface without IP address
+        using the 'manual' method. This is suitable for some cases where we 
+        only want to have the interface to be up. This example can be used
+        to setup PPPOE interfaces or network IDS listening on a network. 
+        This might not be as good as providing a specific method but the
+        maintainer considers that this is the way it should be handled.
+        (Closes: #76142, #92993, #129003, #164823, #171981)
+      + Also, provided an example bridge configuration script that can
+        be setup in /e/n/if-{pre-up,down}.d/ in order to setup bridges.
+    - Interfaces(5).pre:
+      + Slight improvement in to better describe mapping and point to 
+       the examples available. (Closes: #232594)
+      + Minor changes in the manpage to avoid people being misled .
+        (Closes: #232347)
+      + Better description of mappings (Closes: #216716)
+      + Document IFACE=LIFACE syntax (Closes: #213068)
+      + Documented known bugs or limitations.
+      + Reference the location of the network examples.
+      + Reference also the "Debian Reference" manual since it is more
+        verbose in how /e/n/interfaces and ifupdown works.
+    - Ifup(8):
+      + Document that the -a option will take down all interfaces.
+       (Closes: #208607)
+      + Also describe in which order are interfaces started/stopped when
+        using -a which might avoid confusion, see  #208700 for example.
+      + Changed manpage name to ifup (instead of ifupdown).
+       (Closes: #81150)
+      + Document known bugs in the manpage: state maintained is sometimes
+       lost, the ifstate needs to be writable and there is a known deadlock
+       issue.
+      + Document known "limitations" and refer readers to alternatives to
+        monitor interface changes such as ifupd and hotplug.
+      + Minor formatting changes and rewrites for better comprehension.
+    - Translations:
+      + Added Spanish debconf translation provided by Carlos Valdivia.
+       (Closes: #207727)
+      + Added Japanese debconf translation provided by Kenshi Muto.
+       (Closes: #210436)
+      + Added Dutch debconf translation provided by Tim Dijkstra.
+       (Closes: #213723)
+      + Added Greek debconf translation provided by Konstantinos Margaritis.
+       (Closes: #229503, #229527)
+      + Added simplified Chinese debconf translation provided by Hiei Xu.
+       (Closes: #231910)
+      + Added Czech debconf translation provided by Miroslav Kure.
+       (Closes: #231995)
+      + Added Turkish debconf translation provided by Recai Oktas.
+       (Closes: #239142)
+      + Added Danish debconf translation provided by Morten Brix Pedersen.
+       (Closes: #241248)
+
+ -- Javier Fernandez-Sanguino Pen~a <jfs@computer.org>  Mon,  5 Apr 2004 21:12:05 +0200
+
+ifupdown (0.6.4-4.6) unstable; urgency=low
+
+  * Non-maintainer upload
+  * reinstate code creating non-existent /etc/network in preinst. Moving
+    that code to postinst is currently problematic since other packages
+    pre-depend on ifupdown and dpkg doesn't guarantee that pre-depended
+    packages are configured before unpacking the depending package.
+                                                             (Closes: #208811)
+  * don't call dpkg --compare-version on initial install in postinst
+
+ -- Marc Haber <mh+debian-packages@zugschlus.de>  Sat,  6 Sep 2003 10:49:48 +0000
+
+ifupdown (0.6.4-4.5) unstable; urgency=low
+
+  * Non-maintainer upload
+  * ifupdown.nw:
+    + Clarify description of --all option                    (Closes: #180000)
+    + Add manual interface method                            (Closes:  #88948)
+    + Document order of precedence of DHCP clients           (Closes: #156789)
+  * debian/prepostinstrm:
+    + Use "set -e" consistently
+  * debian/rules, debian/postinst, debian/preinst
+    + Add /etc/network/if*.d/ directories to the package     (Closes: #178226)
+    + Use dh_installinit with --no-start option
+  * debian/config: fix compare-versions so that debconf question
+    is asked when updating from < 0.6                        (Closes: #122422)
+  * debian/rules:
+    + documented {clobber,distclean} targets                 (Closes: #154517)
+    + removed obsolete call of dh_suidregister
+  * added Danish convert-interfaces template.  Thanks to morten@wtk.dk
+    for translation.                                         (Closes: #174764)
+  * Switch to gettext-based debconf templates and update French
+    translation. Thanks to Christian Perrier for this work.  (Closes: #200786)
+  * use Colin Watson's backporting helper for po-debconf'ed packages.
+  * interfaces(5):
+    + Format improvements
+    + Describe how mapping works                             (Closes: #86895)
+                                                             (Closes: #138694)
+                                                             (Closes: #175679)
+                                                             (Closes: #204468)
+    + Document order of processing of auto ifaces            (Closes: #112012)
+    + Say that "auto" takes physical interface names as arguments
+                                                             (Closes: #138403)
+    + Document function of /etc/network/if-*.d/ directories  (Closes: #141634)
+                                                             (Closes: #157698)
+    + There are more than three universal options            (Closes: #160918)
+                                                             (Closes: #186316)
+    + Mention extended options                               (Closes: #203636)
+  * ifup(8)
+    + Indicate in synopsis that -i option takes an argument       
+    + minor phrasing changes aiming at greater clarity  
+    + formatting corrections                   
+  * examples/*: fix typos                                    (Closes: #173101)
+  * debian/control:
+    + Suggest dhcp-client and ppp                            (Closes: #178630)
+    + Standards-Version: 3.6.1
+    + Priority: important to agree with override file
+    + Clarify wording of long description
+  * debian/copyright:
+    + Clean up and make lintian happy
+  * Thanks to Thomas Hood and Michael Weber for helping to prepare
+    these patches and the NMU.
+
+ -- Marc Haber <mh+debian-packages@zugschlus.de>  Wed, 27 Aug 2003 14:00:59 +0000
+
+ifupdown (0.6.4-4.4) unstable; urgency=low
+
+  * Non-maintainer upload
+  * adjustment to changed md5sum output format (as of dpkg 1.10)
+    (Closes: Bug#152853)
+
+ -- Michael Weber <michaelw@debian.org>  Sun, 14 Jul 2002 02:12:15 +0200
+
+ifupdown (0.6.4-4.3) unstable; urgency=low
+
+  * Non-maintainer upload
+  * flush stream buffers before forking and after writing the
+    statefile
+    (Closes: Bug#151932)
+         
+ -- Michael Weber <michaelw@debian.org>  Thu,  4 Jul 2002 21:02:10 +0200
+
+ifupdown (0.6.4-4.2) unstable; urgency=low
+
+  * Non-maintainer upload
+  * added locking support, parallel executions of if{up,down} will be
+    serialized (modified patch from bod@debian.org).
+    (Closes: Bug#108876, Bug#108857)
+
+ -- Michael Weber <michaelw@debian.org>  Mon, 24 Jun 2002 21:42:50 +0200
+
+ifupdown (0.6.4-4.1) unstable; urgency=low
+
+  * Non-maintainer upload
+  * added convert-interfaces template for:
+    + de (Closes: Bug#83542)
+    + fr (Closes: Bug#83804)
+    + pt_BR (Closes: Bug#98448, Bug#110198)
+    + pl (Closes: Bug#107701)
+    + ru (Closes: Bug#112652)
+    + sv (Closes: Bug#83496)
+    (thanks to all translators)
+  * fixed some typos in source documentation
+  * pass METHOD and ADDRFAM environment variables to if.d scripts
+    and {pre-,}{up,down} lines
+    (Closes: Bug#88947)
+  * upgrade-from-0.5.x.pl emits auto statements only once
+    (patch from weasel@debian.org)
+    (Closes: Bug#105342)
+  * added "mtu" option to inet and inet6 static stanzas
+    (Closes: Bug#57731)
+  * added options "local" and "ttl" to inet6 static stanza
+    (Closes: Bug#67743)
+  * added and documented option "media" to specify the medium type
+    (Closed: Bug#79999)
+  * added and documented option hwaddress
+    (Closes: Bug#82604)
+  * reject options with empty values
+    (Closes: #86410)
+  * added more documentation to the IPX stanza
+  * improved usenet2man conversion (handles punctuation 
+    before/after //,**
+  * added support for udhcpc (slightly modified patch from kraai@debian.org)
+    (Closes: Bug#113620)
+  * added support for multiple executions of dhclient (uses
+    /var/run/dhclient.%iface%.pid now)
+    (Closes: Bug#94656)
+  * man page update [pump works for kernels (> 2.2.x)]
+    (Closes: Bug#114429)
+  * configurable user/group for install (0/0 as default, since
+    NetBSD uses group "wheel" instead of "root")
+  * examples/{check,get}-mac-address.sh:
+    + mapping script now compares given MAC addresses case-insensitive.
+    + added LANG=C to make ifupdown output reliably parseable
+      (thanks to blade@debian.org)
+
+ -- Michael Weber <michaelw@debian.org>  Sun, 23 Jun 2002 11:56:25 +0200
+
+ifupdown (0.6.4-4) unstable; urgency=low
+
+  * Don't delete /etc/network/ifstate every boot, just empty the file. This
+    way people can symlink it to /var/run/ifstate if they so desire (ie, if
+    /var is local and /etc is read-only). (Closes: Bug#103868, Bug#85206)
+  * Explicitly set PATH in the environment, because pdksh is broken, broken
+    I say. (Closes: Bug#83557, Bug#99444)
+
+ -- Anthony Towns <aj@azure.humbug.org.au>  Tue, 19 Jun 2001 00:04:30 +1000
+
+ifupdown (0.6.4-3) unstable; urgency=low
+
+  * Add some test cases to hopefully catch miscompiles on silly
+    architectures like alpha. Weirdly, I can't duplicate this bug on
+    lully anymore, so I didn't add a -O0 workaround at this time. We'll
+    see what happens. (Closes: Bug#81143)
+
+  * Correct old /e/n/i check from -2 so it might even work. (Closes:
+    Bug#81611)
+
+ -- Anthony Towns <aj@azure.humbug.org.au>  Tue,  9 Jan 2001 10:48:18 +1000
+
+ifupdown (0.6.4-2) unstable; urgency=low
+
+  * Check for old /etc/network/interfaces conffile (all comments, same
+    md5, same size), and replace it with new conffile so as not to mislead
+    people into forgetting the "auto" lines. (Closes: Bug#79822) 
+
+  * Added wvdial support, theoretically. If it doesn't work, someone'll have
+    to file a new bug and tell me. (Closes: Bug#76985)
+
+ -- Anthony Towns <ajt@debian.org>  Thu, 28 Dec 2000 21:28:47 +1000
+
+ifupdown (0.6.4-1) unstable; urgency=low
+
+  * New upstream release. Removes a bashism from the makefile, and uses
+    ferror() correctly (hopefully) (Closes: Bug#75279, Bug#76086)
+
+  * Add example that checks a MAC address is what it should be. (Closes:
+    Bug#76198)
+
+ -- Anthony Towns <ajt@debian.org>  Sun, 19 Nov 2000 15:33:22 +1000
+
+ifupdown (0.6.3-1) unstable; urgency=low
+
+  * New upstream release. Debian patches incorporated upstream, and a
+    big fix wrt memory allocation.
+
+ -- Anthony Towns <ajt@debian.org>  Fri, 20 Oct 2000 18:38:10 -0700
+
+ifupdown (0.6.2pr-7) unstable; urgency=low
+
+  * Rename to ifupdown. Let's see what breaks.
+
+  * Add pointopoint option for static inet interfaces. (Closes: Bug#74563)
+
+  * Updating to 0.6.x fixes some problems:
+        --scheme no longer exists (Closes: Bug#54814)
+        line numbers are reported (Closes: Bug#62542)
+        you can use $IFACE in /e/n/interfaces (Closes: Bug#71779)
+
+ -- Anthony Towns <ajt@debian.org>  Mon, 16 Oct 2000 19:30:54 -0700
+
+ifupdown0.6 (0.6.2pr-6) unstable; urgency=low
+
+  * Cleanup /etc/network/ifstate when booting (it will be wrong
+    if the system crashed).
+
+  * This should be enough for ifupdown.deb to be updated, hopefully.
+
+ -- Anthony Towns <ajt@debian.org>  Fri, 13 Oct 2000 19:41:34 -0700
+
+ifupdown0.6 (0.6.2pr-5) unstable; urgency=low
+
+  * The previous few uploads should've fixed most of the bugs
+    described in 72872. (Closes: Bug#72872)
+
+  * Add .sh suffixes to the example mapping scripts.
+  * Fix a typo in postinst (interface *file* not files)
+  * Add a "press enter to continue" if the /e/n/i update fails. 
+
+  * Moved /var/run/ifupdown.state to /etc/network/ifstate. Gross.
+    (Closes: Bug#74312)
+
+ -- Anthony Towns <ajt@debian.org>  Sat,  7 Oct 2000 23:52:02 -0700
+
+ifupdown0.6 (0.6.2pr-4) unstable; urgency=low
+
+  * Automatically update /etc/network/interfaces, hopefully. 
+
+ -- Anthony Towns <ajt@debian.org>  Sat,  7 Oct 2000 21:53:21 -0700
+
+ifupdown0.6 (0.6.2pr-3) unstable; urgency=low
+
+  * Started work on automatically converting from 0.5.x config format to
+    0.6.x.
+  * Move the example from /usr/share/doc/ifupdown to ifupdown0.6.
+  * Add some example mapping scripts. 
+
+ -- Anthony Towns <ajt@debian.org>  Sat,  7 Oct 2000 18:15:10 -0700
+
+ifupdown0.6 (0.6.2pr-2) unstable; urgency=low
+
+  * Note that dhcpcd works with any kernel, not just 2.0 and 2.2.
+  * Remove the "noauto" keyword from the manpage. Ooopsy.
+  * Create /etc/network/if-*.d directories in preinst.
+  * Update the example-etc-network-interfaces to use the auto keyword.
+
+ -- Anthony Towns <ajt@debian.org>  Sun, 24 Sep 2000 17:05:21 -0700
+
+ifupdown0.6 (0.6.2pr-1) unstable; urgency=low
+
+  * New upstream release.
+  * Forward port some fixes from the last .deb that I hadn't put in the
+    upstream source. Whoops.
+
+  * This is a beta package that doesn't upgrade cleanly from ifupdown. It's
+    for testing purposes only.
+
+ -- Anthony Towns <ajt@debian.org>  Sun, 24 Sep 2000 16:05:25 -0700
+
+ifupdown (0.5.5pr-3) unstable; urgency=low
+
+  * debian/rules: Adjusted to *always* build from scratch if noweb is
+    installed, to ensure that the various .c and .defn files are updated
+    wherever possible. This should fix the problem where the updated
+    inet6.defn wasn't being included, even after -2, amongst others.
+
+ -- Anthony Towns <ajt@debian.org>  Mon, 28 Aug 2000 12:40:28 +1000
+
+ifupdown (0.5.5pr-2) unstable; urgency=low
+
+  * debian/rules: chmod +x any scripts that are created when the diff is
+    applied. (Closes: Bug#70030)
+
+  * ifupdown.nw: Forward port lost changes from netbase 3.18-4.
+    (Closes: Bug#69723)
+  * ifupdown.nw: Specify interface explicitly when adding default routes,
+    and explicitly remove the route when deconfiguring an interface.
+    (Closes: Bug#63071, Bug#67796)
+
+  * debian/control: Add dependency on net-tools.
+
+ -- Anthony Towns <ajt@debian.org>  Sun, 27 Aug 2000 17:47:01 +1000
+
+ifupdown (0.5.5pr-1) unstable; urgency=low
+
+  * Thought through and removed build-dependency on noweb. This involves
+    changing what I put in the .orig.tar.gz. (Closes: Bug#68869)
+
+ -- Anthony Towns <ajt@debian.org>  Sat, 19 Aug 2000 18:09:09 +1000
+
+ifupdown (0.5.5-1) unstable; urgency=low
+
+  * Split from netbase.
+
+ -- Anthony Towns <ajt@debian.org>  Mon, 17 Jul 2000 08:24:56 +1000
+
diff --git a/debian/conffiles b/debian/conffiles
new file mode 100644 (file)
index 0000000..20e3e16
--- /dev/null
@@ -0,0 +1,3 @@
+/etc/init.d/ifupdown
+/etc/init.d/ifupdown-clean
+/etc/default/ifupdown
diff --git a/debian/config b/debian/config
new file mode 100644 (file)
index 0000000..adf37c0
--- /dev/null
@@ -0,0 +1,15 @@
+#!/bin/sh
+set -e
+
+# Source debconf library
+[ -e /usr/share/debconf/confmodule ] || exit 0
+. /usr/share/debconf/confmodule
+
+if [ "$1" = "configure" ] && [ "$2" != "" ]; then
+       if dpkg --compare-versions "$2" lt "0.6"; then
+               db_input low ifupdown/convert-interfaces || true
+               db_go
+       fi
+fi
+
+db_stop
diff --git a/debian/control b/debian/control
new file mode 100644 (file)
index 0000000..3d08658
--- /dev/null
@@ -0,0 +1,17 @@
+Source: ifupdown
+Section: base
+Priority: important
+Maintainer: Rafal Krypa <r.krypa@samsung.com>
+X-Original-Maintainer: Anthony Towns <ajt@debian.org>
+Standards-Version: 3.6.1.0
+Build-Depends: debhelper (>= 4.1.68), po-debconf
+
+Package: ifupdown
+Architecture: any
+Depends: net-tools, ${shlibs:Depends}, ${debconf-depends}
+Suggests: iproute, dhcp3-client | dhcp-client, ppp
+Replaces: netbase (<< 4.00)
+Description: high level tools to configure network interfaces
+ This package provides the tools ifup and ifdown which may be used to
+ configure (or, respectively, deconfigure) network interfaces based on
+ interface definitions in the file /etc/network/interfaces.
diff --git a/debian/copyright b/debian/copyright
new file mode 100644 (file)
index 0000000..e3839a1
--- /dev/null
@@ -0,0 +1,21 @@
+This package was created and debianized by Anthony Towns
+<ajt@debian.org>. He is also the upstream author of ifupdown.
+
+Copyright (c) 1999, Anthony Towns.  All rights reserved.
+
+   This package 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 dated June, 1991.
+
+   This package 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 package; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+   02111-1307, USA.
+
+On Debian GNU/Linux systems, the complete text of the GNU General
+Public License can be found in /usr/share/common-licenses/GPL .
diff --git a/debian/dirs b/debian/dirs
new file mode 100644 (file)
index 0000000..323cb0c
--- /dev/null
@@ -0,0 +1,8 @@
+usr/bin
+usr/sbin
+usr/share/doc/ifupdown/examples
+usr/share/ifupdown
+usr/share/man/man5
+usr/share/man/man8
+etc/network
+etc/init.d
diff --git a/debian/ifupdown-clean.init b/debian/ifupdown-clean.init
new file mode 100644 (file)
index 0000000..fec6a35
--- /dev/null
@@ -0,0 +1,45 @@
+#!/bin/sh
+### BEGIN INIT INFO
+# Provides:          ifupdown-clean
+# Required-Start:    checkroot
+# Required-Stop:
+# Default-Start:     S
+# Default-Stop:
+# Short-Description: Clean old interface status info during boot.
+### END INIT INFO
+
+set -e
+
+MYNAME="${0##*/}"
+PATH=/sbin:/bin
+[ -r /etc/default/ifupdown ] && . /etc/default/ifupdown
+
+# Note: The state file location is hardcoded in ifup|ifdown
+# it is used as a variable in this script order to ease transitions
+# to other locations by the package (not by the sysadmin), if you want
+# to setup an alternate location please use a symlink
+IFSTATE=/etc/network/run/ifstate
+
+case "$1" in
+  start)
+    echo -n "Cleaning up ifupdown..."
+    if [ -f $IFSTATE -a ! -L $IFSTATE ]; then
+      rm -f "$IFSTATE"
+    elif [ -f $IFSTATE ]; then
+      # This is kinda bad :(
+      >$IFSTATE
+    fi
+    echo "done."
+    exit 0
+    ;;
+
+  stop|restart|force-reload)
+    exit 0
+    ;;
+
+  *)
+    echo "Usage: $0 {start|stop|restart|force-reload}" >&2
+    exit 3
+    ;;
+esac
+
diff --git a/debian/ifupdown.default b/debian/ifupdown.default
new file mode 100644 (file)
index 0000000..04715b1
--- /dev/null
@@ -0,0 +1,6 @@
+# Set to "yes" to turn on debugging messages in scripts
+# DEBUG=""
+
+# Time to wait for ifupdown to become ready at boot
+# (Currently not used)
+# IFUPDOWN_TIMEOUT=60
diff --git a/debian/ifupdown.init b/debian/ifupdown.init
new file mode 100644 (file)
index 0000000..0f70de6
--- /dev/null
@@ -0,0 +1,113 @@
+#!/bin/sh -e
+### BEGIN INIT INFO
+# Provides:          ifupdown
+# Required-Start:    ifupdown-clean
+# Required-Stop:     $local_fs
+# Default-Start:     S
+# Default-Stop:      0 6
+# Short-Description: Prepare the system for taking up interfaces.
+### END INIT INFO
+
+[ -x /sbin/ifup ] || exit 0
+[ -x /sbin/ifdown ] || exit 0
+
+MYNAME="${0##*/}"
+report() { echo "${MYNAME}: $*" ; }
+report_err() { report "Error: $*" >&2 ; }
+RUN_DIR=/etc/network/run
+[ -r /etc/default/ifupdown ] && . /etc/default/ifupdown
+
+# Note: The state file location is hardcoded in ifup|ifdown
+IFSTATE=/etc/network/run/ifstate
+
+myreadlink () {
+  dest="${1%/}"
+  extras=""
+
+  while [ "$dest" != "" ]; do
+    if [ -d "$dest" ]; then
+      cd "$dest"
+      dest=$(/bin/pwd)
+      break
+    fi
+
+    if [ -L "$dest" ]; then
+      d2=$(readlink "$dest")
+      if [ "${d2#/}" = "$d2" ]; then
+        dest="${dest%/*}/$d2"
+      else
+        dest="$d2"
+      fi
+    fi
+
+    while [ ! -e "$dest" ]; do
+      extras="${dest##*/}/$extras"
+      if [ "${extras%%/*}" = ".." ]; then return 1; fi
+      destx="${dest%/*}"
+      if [ "$destx" = "$dest" ]; then destx=""; fi
+      dest="$destx"
+    done
+  done
+  dest="$dest/$extras"
+  echo "${dest%/}"
+}
+
+case "$1" in
+  start|restart)
+    if [ "$2" ]; then
+      report_err "Arguments to '$1' command not accepted"
+      exit 3
+    fi
+    echo -n "Setting up networking..."
+
+    # if /etc/network/run is a symlink to a directory that doesn't exist,
+    # create it.
+
+    if [ -L "$RUN_DIR" ] && [ ! -d "$RUN_DIR" ] ; then
+      runmkdir="$(myreadlink "$RUN_DIR")"
+      if [ ! "$runmkdir" ] ; then
+        echo "failed."
+        report_err "Cannot create target of /etc/network/run"
+        exit 1
+      fi
+      if ! mkdir -p "$runmkdir"; then
+        echo "failed."
+        report_err "Failure creating directory $runmkdir"
+        exit 1
+      fi
+    fi
+
+    # Create the state file
+    # Doing this also signals that ifupdown is available for use
+    if [ ! -r "$IFSTATE" ]; then
+      if ! : > "$IFSTATE" ; then
+        echo "failed."
+        report_err "Failure initializing $IFSTATE"
+        exit 1
+      fi 
+    fi
+
+    echo "done."
+    exit 0
+    ;;
+
+  stop)
+    if [ "$2" ]; then
+      report_err "Arguments to '$1' command not accepted"
+      exit 3
+    fi
+    if [ -x /etc/init.d/ifupdown-clean ]; then
+      /etc/init.d/ifupdown-clean start
+    fi
+    ;;
+
+  force-reload)
+    ;;
+
+  *)
+    echo "Usage: $0 {start|stop|restart|force-reload}" >&2
+    exit 3
+    ;;
+esac
+
+exit 0
diff --git a/debian/interfaces b/debian/interfaces
new file mode 100644 (file)
index 0000000..05cbde6
--- /dev/null
@@ -0,0 +1,14 @@
+# This file describes the network interfaces available on your system
+# and how to activate them. For more information, see interfaces(5).
+
+# The loopback network interface
+auto lo
+iface lo inet loopback
+
+# The primary network interface
+auto usb0
+allow-hotplug usb0
+iface usb0 inet static
+       address 192.168.129.3
+       netmask 255.255.255.0
+       gateway 192.168.129.1
diff --git a/debian/po/POTFILES.in b/debian/po/POTFILES.in
new file mode 100644 (file)
index 0000000..302e553
--- /dev/null
@@ -0,0 +1 @@
+[type: gettext/rfc822deb] templates.master
diff --git a/debian/po/ca.po b/debian/po/ca.po
new file mode 100644 (file)
index 0000000..5238927
--- /dev/null
@@ -0,0 +1,36 @@
+# ifupdown (debconf) translation to Catalan.
+# Copyright (C) 2004 Free Software Foundation, Inc.
+# Aleix Badia i Bosch <abadia@ica.es>, 2004
+# Matt Bonner <mateubonet@yahoo.com>, 2004
+# Jordi Mallach <jordi@debian.org>, 2004
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ifupdown-0.6.4-4.6_templates\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2004-08-04 17:16+0200\n"
+"PO-Revision-Date: 2004-02-28 19:46GMT\n"
+"Last-Translator: Aleix Badia i Bosch <abadia@ica.es>\n"
+"Language-Team: Debian L10n Catalan <debian-l10n-catalan@lists.debian.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid "Update /etc/network/interfaces?"
+msgstr "Voleu actualitzar el fitxer /etc/network/interfaces?"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid ""
+"The format of /etc/network/interfaces has had a minor but incompatible "
+"change made between version 0.5.x and 0.6.x of ifupdown. It is however "
+"possible to automatically convert from the old format to the new in almost "
+"all cases."
+msgstr ""
+"El format del fitxer /etc/network/interfaces de l'ifupdown s'ha modificat "
+"entre les versions 0.5.x i 0.6.x. Tot i això, en la majoria dels casos es "
+"pot actualitzar automàticament del format vell al nou."
diff --git a/debian/po/cs.po b/debian/po/cs.po
new file mode 100644 (file)
index 0000000..dac701e
--- /dev/null
@@ -0,0 +1,43 @@
+#
+#    Translators, if you are not familiar with the PO format, gettext
+#    documentation is worth reading, especially sections dedicated to
+#    this format, e.g. by running:
+#         info -n '(gettext)PO Files'
+#         info -n '(gettext)Header Entry'
+#
+#    Some information specific to po-debconf are available at
+#            /usr/share/doc/po-debconf/README-trans
+#         or http://www.debian.org/intl/l10n/po-debconf/README-trans
+#
+#    Developers do not need to manually edit POT or PO files.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ifupdown\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2004-08-04 17:16+0200\n"
+"PO-Revision-Date: 2004-02-09 20:09+0100\n"
+"Last-Translator: Miroslav Kure <kurem@debian.cz>\n"
+"Language-Team: Czech <provoz@debian.cz>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO-8859-2\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid "Update /etc/network/interfaces?"
+msgstr "Aktualizovat /etc/network/interfaces?"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid ""
+"The format of /etc/network/interfaces has had a minor but incompatible "
+"change made between version 0.5.x and 0.6.x of ifupdown. It is however "
+"possible to automatically convert from the old format to the new in almost "
+"all cases."
+msgstr ""
+"Mezi verzemi 0.5.x a 0.6 programu ifupdown do¹lo k malé, ale nekompatibilní "
+"zmìnì formátu souboru /etc/network/interfaces. V témìø v¹ech pøípadech lze "
+"pøevést data ze starého formátu do nového zcela automaticky."
diff --git a/debian/po/da.po b/debian/po/da.po
new file mode 100644 (file)
index 0000000..396570e
--- /dev/null
@@ -0,0 +1,44 @@
+#
+#    Translators, if you are not familiar with the PO format, gettext
+#    documentation is worth reading, especially sections dedicated to
+#    this format, e.g. by running:
+#         info -n '(gettext)PO Files'
+#         info -n '(gettext)Header Entry'
+#
+#    Some information specific to po-debconf are available at
+#            /usr/share/doc/po-debconf/README-trans
+#         or http://www.debian.org/intl/l10n/po-debconf/README-trans
+#
+#    Developers do not need to manually edit POT or PO files.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ifupdown 0.6.4\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2004-08-04 17:16+0200\n"
+"PO-Revision-Date: 2004-03-31 14:37+0200\n"
+"Last-Translator: Morten Brix Pedersen <morten@wtf.dk>\n"
+"Language-Team: Danish <dansk@klid.dk>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid "Update /etc/network/interfaces?"
+msgstr "Opdatér /etc/network/interfaces?"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid ""
+"The format of /etc/network/interfaces has had a minor but incompatible "
+"change made between version 0.5.x and 0.6.x of ifupdown. It is however "
+"possible to automatically convert from the old format to the new in almost "
+"all cases."
+msgstr ""
+"Formatet i filen /etc/network/interfaces har fået lavet en mindre men "
+"inkompatibel ændring mellem version 0.5.x og 0.6.x af ifupdown. Det er dog "
+"muligt at automatisk konvertere fra det gamle format til det nye i næsten "
+"alle tilfælde."
diff --git a/debian/po/de.po b/debian/po/de.po
new file mode 100644 (file)
index 0000000..bacb4ac
--- /dev/null
@@ -0,0 +1,45 @@
+#
+#    Translators, if you are not familiar with the PO format, gettext
+#    documentation is worth reading, especially sections dedicated to
+#    this format, e.g. by running:
+#         info -n '(gettext)PO Files'
+#         info -n '(gettext)Header Entry'
+#
+#    Some information specific to po-debconf are available at
+#            /usr/share/doc/po-debconf/README-trans
+#         or http://www.debian.org/intl/l10n/po-debconf/README-trans
+#
+#    Developers do not need to manually edit POT or PO files.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2004-08-04 17:16+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO-8859-15\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid "Update /etc/network/interfaces?"
+msgstr "Soll /etc/network/interfaces erneuert werden?"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid ""
+"The format of /etc/network/interfaces has had a minor but incompatible "
+"change made between version 0.5.x and 0.6.x of ifupdown. It is however "
+"possible to automatically convert from the old format to the new in almost "
+"all cases."
+msgstr ""
+"Das Format von /etc/network/interfaces hat eine kleinere aber inkompatible "
+"Änderung zwischen Version 0.5.x und 0.6.x von ifupdown erfahren. Es ist "
+"jedoch in fast allen Fällen möglich, automatisch vom alten in das neue "
+"Format zu konvertieren."
diff --git a/debian/po/el.po b/debian/po/el.po
new file mode 100644 (file)
index 0000000..3f96181
--- /dev/null
@@ -0,0 +1,45 @@
+# translation of el.po to Greek
+# translation of templates.po to Greek
+#
+#    Translators, if you are not familiar with the PO format, gettext
+#    documentation is worth reading, especially sections dedicated to
+#    this format, e.g. by running:
+#         info -n '(gettext)PO Files'
+#         info -n '(gettext)Header Entry'
+#    Some information specific to po-debconf are available at
+#            /usr/share/doc/po-debconf/README-trans
+#         or http://www.debian.org/intl/l10n/po-debconf/README-trans#
+#    Developers do not need to manually edit POT or PO files.
+# Konstantinos Margaritis <markos@debian.org>, 2004.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: el\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2004-08-04 17:16+0200\n"
+"PO-Revision-Date: 2004-01-15 22:04EEST\n"
+"Last-Translator: Konstantinos Margaritis <markos@debian.org>\n"
+"Language-Team: Greek <debian-l10n-greek@lists.debian.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.0.2\n"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid "Update /etc/network/interfaces?"
+msgstr "Να γίνει διόρθωση του /etc/network/interfaces;"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid ""
+"The format of /etc/network/interfaces has had a minor but incompatible "
+"change made between version 0.5.x and 0.6.x of ifupdown. It is however "
+"possible to automatically convert from the old format to the new in almost "
+"all cases."
+msgstr ""
+"Η δομή του /etc/network/interfaces άλλαξε με ένα μικρό αλλά ασύμβατο τρόπο "
+"από την έκδοση του πακέτου ifupdown 0.5.x και 0.6.x.  Ωστόσο, είναι δυνατή η "
+"αυτόματη μετατροπή της παλιάς δομής στη νέα για σχεδόν όλες τις περιπτώσεις."
diff --git a/debian/po/es.po b/debian/po/es.po
new file mode 100644 (file)
index 0000000..f3d133c
--- /dev/null
@@ -0,0 +1,46 @@
+#
+#    Translators, if you are not familiar with the PO format, gettext
+#    documentation is worth reading, especially sections dedicated to
+#    this format, e.g. by running:
+#         info -n '(gettext)PO Files'
+#         info -n '(gettext)Header Entry'
+#
+#    Some information specific to po-debconf are available at
+#            /usr/share/doc/po-debconf/README-trans
+#         or http://www.debian.org/intl/l10n/po-debconf/README-trans
+#
+#    Developers do not need to manually edit POT or PO files.
+#
+# Carlos Valdivia Yagüe <valyag@dat.etsit.upm.es>, 2003
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ifupdown 0.6.4\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2004-08-04 17:16+0200\n"
+"PO-Revision-Date: 2003-08-29 01:00+0200\n"
+"Last-Translator: Carlos Valdivia Yagüe <valyag@dat.etsit.upm.es>\n"
+"Language-Team: Debian L10n Spanish <debian-l10n-spanish@lists.debian.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO-8859-15\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid "Update /etc/network/interfaces?"
+msgstr "¿Actualizar /etc/network/interfaces"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid ""
+"The format of /etc/network/interfaces has had a minor but incompatible "
+"change made between version 0.5.x and 0.6.x of ifupdown. It is however "
+"possible to automatically convert from the old format to the new in almost "
+"all cases."
+msgstr ""
+"El formato de /etc/network/interfaces ha sufrido un cambio pequeño pero "
+"incompatible entre las versiones 0.5.x y 0.6.x de ifupdown. No obstante, en "
+"casi todos los casos es posible realizar la conversión automáticamente entre "
+"el formato antiguo y el nuevo."
diff --git a/debian/po/fr.po b/debian/po/fr.po
new file mode 100644 (file)
index 0000000..2b5ec5f
--- /dev/null
@@ -0,0 +1,44 @@
+#
+#    Translators, if you are not familiar with the PO format, gettext
+#    documentation is worth reading, especially sections dedicated to
+#    this format, e.g. by running:
+#         info -n '(gettext)PO Files'
+#         info -n '(gettext)Header Entry'
+#
+#    Some information specific to po-debconf are available at
+#            /usr/share/doc/po-debconf/README-trans
+#         or http://www.debian.org/intl/l10n/po-debconf/README-trans
+#
+#    Developers do not need to manually edit POT or PO files.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ifupdown 0.6.4\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2004-08-04 17:16+0200\n"
+"PO-Revision-Date: 2003-07-10 19:52+0100\n"
+"Last-Translator: Thomas Morin <thomas.morin@webmotion.com>\n"
+"Language-Team: French <debian-l10n-french@lists.debian.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO-8859-15\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid "Update /etc/network/interfaces?"
+msgstr "Mettre à jour /etc/network/interfaces ?"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid ""
+"The format of /etc/network/interfaces has had a minor but incompatible "
+"change made between version 0.5.x and 0.6.x of ifupdown. It is however "
+"possible to automatically convert from the old format to the new in almost "
+"all cases."
+msgstr ""
+"Le format du fichier /etc/network/interfaces a subi un changement mineur "
+"mais incompatible entre les versions 0.5.x et 0.6.x d'ifupdown. Il est "
+"néanmoins possible de convertir automatiquement ce fichier de l'ancien "
+"format au nouveau, dans la plupart des cas."
diff --git a/debian/po/it.po b/debian/po/it.po
new file mode 100644 (file)
index 0000000..730dda8
--- /dev/null
@@ -0,0 +1,36 @@
+# ifupdown po-debconf translation to italian\r
+# Copyright (C) 2004 Software in the Public Interest\r
+# This file is distributed under the same license as the ifupdown package.\r
+# Luca Monducci, 2004.\r
+# \r
+msgid ""
+msgstr ""
+"Project-Id-Version: ifupdown 0.6.4-4.10\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2004-08-04 17:16+0200\n"
+"PO-Revision-Date: 2004-11-21 16:02+0100\n"
+"Last-Translator: Luca Monducci <luca.mo@tiscali.it>\n"
+"Language-Team: Italian <debian-l10n-italian@lists.debian.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid "Update /etc/network/interfaces?"
+msgstr "Aggiornare /etc/network/interfaces?"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid ""
+"The format of /etc/network/interfaces has had a minor but incompatible "
+"change made between version 0.5.x and 0.6.x of ifupdown. It is however "
+"possible to automatically convert from the old format to the new in almost "
+"all cases."
+msgstr ""
+"Il formato del file /etc/network/interfaces ha subito un piccolo cambiamento "
+"che lo rende incompatibile fra le versioni 0.5.x e 0.6.x di ifupdown. "
+"Comunque, nella maggior parte dei casi, è possibile convertire "
+"automaticamente il file dal vecchio formato al nuovo."
diff --git a/debian/po/ja.po b/debian/po/ja.po
new file mode 100644 (file)
index 0000000..984a761
--- /dev/null
@@ -0,0 +1,43 @@
+#
+#    Translators, if you are not familiar with the PO format, gettext
+#    documentation is worth reading, especially sections dedicated to
+#    this format, e.g. by running:
+#         info -n '(gettext)PO Files'
+#         info -n '(gettext)Header Entry'
+#
+#    Some information specific to po-debconf are available at
+#            /usr/share/doc/po-debconf/README-trans
+#         or http://www.debian.org/intl/l10n/po-debconf/README-trans
+#
+#    Developers do not need to manually edit POT or PO files.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2004-08-04 17:16+0200\n"
+"PO-Revision-Date: 2003-09-11 23:13+0900\n"
+"Last-Translator: Kenshi Muto <kmuto@debian.org>\n"
+"Language-Team: Japanese <debian-japanese@lists.debian.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=EUC-JP\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid "Update /etc/network/interfaces?"
+msgstr "/etc/network/interfaces ¤ò¹¹¿·¤·¤Þ¤¹¤«?"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid ""
+"The format of /etc/network/interfaces has had a minor but incompatible "
+"change made between version 0.5.x and 0.6.x of ifupdown. It is however "
+"possible to automatically convert from the old format to the new in almost "
+"all cases."
+msgstr ""
+"/etc/network/interfaces ¤Î·Á¼°¤Ï¡¢ifupdown ¤Î 0.5.x ¤È 0.6.x ¤Î¤¢¤¤¤À¤ÇºÙ¤«"
+"¤Ê¡¢¤·¤«¤·Èó¸ß´¹¤ÎÊѹ¹¤¬¹Ô¤ï¤ì¤Þ¤·¤¿¡£¤Û¤Ü¤¹¤Ù¤Æ¤Î¾ì¹ç¡¢¸Å¤¤·Á¼°¤«¤é¿·¤·¤¤·Á"
+"¼°¤Ø¼«Æ°Åª¤ËÊÑ´¹¤Ç¤­¤Þ¤¹¡£"
diff --git a/debian/po/lt.po b/debian/po/lt.po
new file mode 100644 (file)
index 0000000..43e31e9
--- /dev/null
@@ -0,0 +1,33 @@
+# translation of ifupdown debconf templates to Lithuanian
+# Copyright (C) 2004 Free Software Foundation, Inc.
+# Gintautas Miliauskas <gintas@akl.lt>, 2004.
+msgid ""
+msgstr ""
+"Project-Id-Version: pcmcia-cs\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2004-08-04 17:16+0200\n"
+"PO-Revision-Date: 2004-05-16 11:05+0300\n"
+"Last-Translator: Gintautas Miliauskas <gintas@akl.lt>\n"
+"Language-Team: Lithuanian <komp_lt@konferencijos.lt>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid "Update /etc/network/interfaces?"
+msgstr "Atnaujinti /etc/network/interfaces?"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid ""
+"The format of /etc/network/interfaces has had a minor but incompatible "
+"change made between version 0.5.x and 0.6.x of ifupdown. It is however "
+"possible to automatically convert from the old format to the new in almost "
+"all cases."
+msgstr ""
+"Failo /etc/network/interfaces formatas nežymiai, bet nesuderinamai skiriasi "
+"tarp ifupdown versijų 0.5.x ir 0.6.x, tačiau beveik visais atvejais galima "
+"automatiškai konvertuoti iš seno formato į naują."
diff --git a/debian/po/nl.po b/debian/po/nl.po
new file mode 100644 (file)
index 0000000..21eb670
--- /dev/null
@@ -0,0 +1,44 @@
+#
+#    Translators, if you are not familiar with the PO format, gettext
+#    documentation is worth reading, especially sections dedicated to
+#    this format, e.g. by running:
+#         info -n '(gettext)PO Files'
+#         info -n '(gettext)Header Entry'
+#
+#    Some information specific to po-debconf are available at
+#            /usr/share/doc/po-debconf/README-trans
+#         or http://www.debian.org/intl/l10n/po-debconf/README-trans
+#
+#    Developers do not need to manually edit POT or PO files.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ifupdown 0.6.4-4.6\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2004-08-04 17:16+0200\n"
+"PO-Revision-Date: 2003-09-20 00:44+0100\n"
+"Last-Translator: Tim Dijkstra <tim@famdijkstra.org>\n"
+"Language-Team: Dutch <debian-l10n-dutch@lists.debian.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=iso-8859-15\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid "Update /etc/network/interfaces?"
+msgstr "/etc/network/interfaces bijwerken?"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid ""
+"The format of /etc/network/interfaces has had a minor but incompatible "
+"change made between version 0.5.x and 0.6.x of ifupdown. It is however "
+"possible to automatically convert from the old format to the new in almost "
+"all cases."
+msgstr ""
+"De indeling van /etc/network/interfaces heeft tussen versie 0.5.x en 0.6.x "
+"van ifupdown een kleine, maar incompatibele verandering ondergaan. In bijna "
+"alle gevallen is het echter mogelijk om automatisch het oude format naar het "
+"nieuwe om te zetten."
diff --git a/debian/po/pl.po b/debian/po/pl.po
new file mode 100644 (file)
index 0000000..cbf6cdb
--- /dev/null
@@ -0,0 +1,46 @@
+#
+#    Translators, if you are not familiar with the PO format, gettext
+#    documentation is worth reading, especially sections dedicated to
+#    this format, e.g. by running:
+#         info -n '(gettext)PO Files'
+#         info -n '(gettext)Header Entry'
+#
+#    Some information specific to po-debconf are available at
+#            /usr/share/doc/po-debconf/README-trans
+#         or http://www.debian.org/intl/l10n/po-debconf/README-trans
+#
+#    Developers do not need to manually edit POT or PO files.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2004-08-04 17:16+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO-8859-2\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid "Update /etc/network/interfaces?"
+msgstr "Uaktualniæ /etc/network/interfaces?"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid ""
+"The format of /etc/network/interfaces has had a minor but incompatible "
+"change made between version 0.5.x and 0.6.x of ifupdown. It is however "
+"possible to automatically convert from the old format to the new in almost "
+"all cases."
+msgstr ""
+"W porównaniu z wersj± 0.5.x, wersja 0.6.x programu ifupdown wprowadza drobne "
+"zmiany, które jednak powoduj±, ¿e stara wersja pliku /etc/network/interfaces "
+"mo¿e nie pasowaæ do nowej konfiguracji. Istnieje jednak mo¿liwo¶æ "
+"automatycznej konwersji (w praktycznie wszystkich przypadkach) ze starego "
+"formatu do nowego."
diff --git a/debian/po/pt_BR.po b/debian/po/pt_BR.po
new file mode 100644 (file)
index 0000000..e557a7a
--- /dev/null
@@ -0,0 +1,45 @@
+#
+#    Translators, if you are not familiar with the PO format, gettext
+#    documentation is worth reading, especially sections dedicated to
+#    this format, e.g. by running:
+#         info -n '(gettext)PO Files'
+#         info -n '(gettext)Header Entry'
+#
+#    Some information specific to po-debconf are available at
+#            /usr/share/doc/po-debconf/README-trans
+#         or http://www.debian.org/intl/l10n/po-debconf/README-trans
+#
+#    Developers do not need to manually edit POT or PO files.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2004-08-04 17:16+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO-8859-1\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid "Update /etc/network/interfaces?"
+msgstr "Atualizar /etc/network/interfaces?"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid ""
+"The format of /etc/network/interfaces has had a minor but incompatible "
+"change made between version 0.5.x and 0.6.x of ifupdown. It is however "
+"possible to automatically convert from the old format to the new in almost "
+"all cases."
+msgstr ""
+"O formato do arquivo /etc/network/interfaces sofreu uma mudança menor mas "
+"incompatível entre as versões 0.5.x e 0.6.x do pacote ifupdown. Porém é "
+"possível converter a partir do formato antigo para o novo formato na maioria "
+"dos casos."
diff --git a/debian/po/ru.po b/debian/po/ru.po
new file mode 100644 (file)
index 0000000..7ccca68
--- /dev/null
@@ -0,0 +1,44 @@
+#
+#    Translators, if you are not familiar with the PO format, gettext
+#    documentation is worth reading, especially sections dedicated to
+#    this format, e.g. by running:
+#         info -n '(gettext)PO Files'
+#         info -n '(gettext)Header Entry'
+#
+#    Some information specific to po-debconf are available at
+#            /usr/share/doc/po-debconf/README-trans
+#         or http://www.debian.org/intl/l10n/po-debconf/README-trans
+#
+#    Developers do not need to manually edit POT or PO files.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2004-08-04 17:16+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=KOI8-R\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid "Update /etc/network/interfaces?"
+msgstr "ïÂÎÏ×ÉÔØ /etc/network/interfaces?"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid ""
+"The format of /etc/network/interfaces has had a minor but incompatible "
+"change made between version 0.5.x and 0.6.x of ifupdown. It is however "
+"possible to automatically convert from the old format to the new in almost "
+"all cases."
+msgstr ""
+"æÏÒÍÁÔ /etc/network/interfaces ÉÍÅÅÔ ÎÅÂÏÌØÛÉÅ, ÎÏ ÎÅÓÏ×ÍÅÓÔÉÍÙÅ ÉÚÍÅÎÅÎÉÑ "
+"ÍÅÖÄÕ ×ÅÒÓÉÑÍÉ 0.5.x É 0.6.x ifupdown. ïÄÎÁËÏ ×ÏÚÍÏÖÎÏ Á×ÔÏÍÁÔÉÞÅÓËÉ "
+"ÐÒÅÏÂÒÁÚÏ×ÁÔØ ÓÔÁÒÙÊ ÆÏÒÍÁÔ Ó ÎÏ×ÙÊ ÐÏÞÔÉ ×Ï ×ÓÅÈ ÓÌÕÞÁÑÈ."
diff --git a/debian/po/sv.po b/debian/po/sv.po
new file mode 100644 (file)
index 0000000..4c2ab42
--- /dev/null
@@ -0,0 +1,44 @@
+#
+#    Translators, if you are not familiar with the PO format, gettext
+#    documentation is worth reading, especially sections dedicated to
+#    this format, e.g. by running:
+#         info -n '(gettext)PO Files'
+#         info -n '(gettext)Header Entry'
+#
+#    Some information specific to po-debconf are available at
+#            /usr/share/doc/po-debconf/README-trans
+#         or http://www.debian.org/intl/l10n/po-debconf/README-trans
+#
+#    Developers do not need to manually edit POT or PO files.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2004-08-04 17:16+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO-8859-1\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid "Update /etc/network/interfaces?"
+msgstr "Uppdatera /etc/network/interfaces?"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid ""
+"The format of /etc/network/interfaces has had a minor but incompatible "
+"change made between version 0.5.x and 0.6.x of ifupdown. It is however "
+"possible to automatically convert from the old format to the new in almost "
+"all cases."
+msgstr ""
+"Formatet på /etc/network/interfaces genomgick en liten men inkompatibel "
+"ändring mellan version 0.5.x och 0.6.x av ifupdown. Det är dock möjligt att "
+"nästan alltid automatiskt konvertera från det gamla formatet till det nya."
diff --git a/debian/po/templates.pot b/debian/po/templates.pot
new file mode 100644 (file)
index 0000000..2edbd95
--- /dev/null
@@ -0,0 +1,41 @@
+#
+#    Translators, if you are not familiar with the PO format, gettext
+#    documentation is worth reading, especially sections dedicated to
+#    this format, e.g. by running:
+#         info -n '(gettext)PO Files'
+#         info -n '(gettext)Header Entry'
+#
+#    Some information specific to po-debconf are available at
+#            /usr/share/doc/po-debconf/README-trans
+#         or http://www.debian.org/intl/l10n/po-debconf/README-trans
+#
+#    Developers do not need to manually edit POT or PO files.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2004-08-04 17:16+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid "Update /etc/network/interfaces?"
+msgstr ""
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid ""
+"The format of /etc/network/interfaces has had a minor but incompatible "
+"change made between version 0.5.x and 0.6.x of ifupdown. It is however "
+"possible to automatically convert from the old format to the new in almost "
+"all cases."
+msgstr ""
diff --git a/debian/po/tr.po b/debian/po/tr.po
new file mode 100644 (file)
index 0000000..3c3a118
--- /dev/null
@@ -0,0 +1,37 @@
+# Turkish translation of ifupdown.
+# This file is distributed under the same license as the ifupdown package.
+# Mehmet Turker <mturker@innova.com.tr>, 2004.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ifupdown\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2004-08-04 17:16+0200\n"
+"PO-Revision-Date: 2004-03-21 03:22+0200\n"
+"Last-Translator: Mehmet Turker <mturker@innova.com.tr>\n"
+"Language-Team: Turkish <debian-l10n-turkish@lists.debian.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.3.1\n"
+"Plural-Forms:  nplurals=1; plural=0;\n"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid "Update /etc/network/interfaces?"
+msgstr "/etc/network/interfaces güncellensin mi?"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid ""
+"The format of /etc/network/interfaces has had a minor but incompatible "
+"change made between version 0.5.x and 0.6.x of ifupdown. It is however "
+"possible to automatically convert from the old format to the new in almost "
+"all cases."
+msgstr ""
+"/etc/network/interfaces dosya biçeminde 0.5.x'den 0.6.x sürümüne geçişte "
+"küçük fakat uyumsuzluk yaratan bir değişiklik oldu. Bununla birlikte eski "
+"biçemin otomatik olarak yenisine dönüştürülmesi neredeyse her durumda "
+"mümkündür."
diff --git a/debian/po/zh_CN.po b/debian/po/zh_CN.po
new file mode 100644 (file)
index 0000000..c9140f8
--- /dev/null
@@ -0,0 +1,42 @@
+#
+#    Translators, if you are not familiar with the PO format, gettext
+#    documentation is worth reading, especially sections dedicated to
+#    this format, e.g. by running:
+#         info -n '(gettext)PO Files'
+#         info -n '(gettext)Header Entry'
+#
+#    Some information specific to po-debconf are available at
+#            /usr/share/doc/po-debconf/README-trans
+#         or http://www.debian.org/intl/l10n/po-debconf/README-trans
+#
+#    Developers do not need to manually edit POT or PO files.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ifupdown 0.6.4\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2004-08-04 17:16+0200\n"
+"PO-Revision-Date: 2004-02-06 17:45+0800\n"
+"Last-Translator: Hiei Xu <nicky@mail.edu.cn>\n"
+"Language-Team: Chinese/Simplified <i18n-translation@lists.linux.net.cn>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid "Update /etc/network/interfaces?"
+msgstr "更新 /etc/network/interfaces 吗?"
+
+#. Type: boolean
+#. Description
+#: ../templates.master:4
+msgid ""
+"The format of /etc/network/interfaces has had a minor but incompatible "
+"change made between version 0.5.x and 0.6.x of ifupdown. It is however "
+"possible to automatically convert from the old format to the new in almost "
+"all cases."
+msgstr ""
+"ifupdown 0.5.x 与 0.6.x 所使用的 /etc/network/interfaces 的文件格式之间有一个"
+"较小但互不兼容的改变,然而在绝大多数情况下程序都能自动将旧格式转换到新格式。"
diff --git a/debian/postinst b/debian/postinst
new file mode 100644 (file)
index 0000000..953fed8
--- /dev/null
@@ -0,0 +1,156 @@
+#!/bin/sh
+set -e
+
+. /usr/share/debconf/confmodule
+
+MYNAME="${0##*/}"
+
+report() { echo "${MYNAME}: $*" ; }
+report_warn() { report "Warning: $*" >&2 ; }
+report_err() { report "Error: $*" >&2 ; }
+
+ATTEMPT_CONVERSION=false
+if [ "$1" = "configure" ] && [ "$2" != "" ] &&
+        dpkg --compare-versions "$2" le "0.6.2pr-3"
+then
+  # Get answers to questions
+  db_get ifupdown/convert-interfaces;    ATTEMPT_CONVERSION="$RET"
+fi
+
+# Update /etc/network/interfaces from "noauto" to "auto"
+if [ "$ATTEMPT_CONVERSION" = "true" ]; then
+  echo
+  echo -n "Automatically converting /etc/network/interfaces"
+  (
+    cd /etc/network;
+    if /usr/share/ifupdown/upgrade-from-0.5.x.pl \
+      < interfaces > interfaces.dpkg-new 2>/dev/null
+    then
+      echo " succeeded."
+      mv interfaces interfaces.dpkg-old
+      mv interfaces.dpkg-new interfaces
+      echo "Old interfaces file saved as interfaces.dpkg-old."
+    else
+      echo " failed."
+      echo
+      echo "If you wish to reattempt the conversion you may run"
+      echo "    cat /etc/network/interfaces |"
+      echo "         /usr/share/ifupdown/upgrade-from-0.5.x.pl"
+      echo
+    fi
+  )
+fi
+
+# Create /etc/network/run 
+if [ "$1" = configure -a ! -d /etc/network/run ]; then
+  if [ -e /etc/network/run -o -L /etc/network/run ]; then
+    echo "Renaming non-directory /etc/network/run to run.dpkg-old..."
+    mv /etc/network/run /etc/network/run.dpkg-old
+  fi
+
+  # The best choice is to use /dev/shm/network
+  #
+  # If we can't use that, we'll just make /etc/network/run a directory,
+  # unless we're upgrading, in which case we'll just keep ifstate where it
+  # is, by making /etc/network/run a symlink to /etc/network.
+
+  WHAT_TO_USE=devshm
+
+  if [ ! -d /dev/shm -o ! -w /dev/shm -o ! -r /proc/mounts ]; then
+    WHAT_TO_USE=owndir
+  elif ! grep -qs "^tmpfs[[:space:]]\+/dev/shm[[:space:]]\+tmpfs[[:space:]]\+\([^[:space:]]\+,\)\?rw" /proc/mounts
+  then
+    WHAT_TO_USE=owndir
+  elif grep -qs '[[:space:]]/dev[[:space:]]devfs[[:space:]]' /proc/mounts; then
+    WHAT_TO_USE=owndir
+  fi
+
+  # Check for available space if we are using devshm
+  if [ "$WHAT_TO_USE" = devshm ]; then
+    SPACE=`df -k /dev/shm | tail -1 | awk '{if ($4 ~ /%/) { print $3 } else { print $4 } }'`
+    if [ "$SPACE" -le 0 ]; then
+      WHAT_TO_USE=owndir
+    fi
+  fi
+
+  if [ "$WHAT_TO_USE" = owndir -a -e /etc/network/ifstate ]; then
+    WHAT_TO_USE=etcnetwork
+  fi
+
+  if [ "$WHAT_TO_USE" = devshm ]
+  then
+    [ -d /dev/shm/network ] || mkdir /dev/shm/network
+    ln -s /dev/shm/network /etc/network/run
+  elif [ "$WHAT_TO_USE" = "owndir" ]; then
+    mkdir /etc/network/run
+  else
+    ln -s . /etc/network/run
+  fi
+fi 
+
+# Move /etc/network/ifstate to /etc/network/run/ifstate
+if [ "$1" = configure -a "$2" != "" -a -e /etc/network/ifstate ] &&
+     dpkg --compare-versions "$2" lt "0.6.5"
+then
+  if [ ! -e /etc/network/run/ifstate ] || ! diff /etc/network/ifstate /etc/network/run/ifstate >/dev/null
+  then
+    echo "Moving /etc/network/ifstate to /etc/network/run/ifstate"
+    if [ ! -L /etc/network/ifstate ]; then
+      mv /etc/network/ifstate /etc/network/run/ifstate
+    else
+      cat /etc/network/ifstate >/etc/network/run/ifstate
+      mv /etc/network/ifstate /etc/network/ifstate.dpkg-old
+    fi
+  fi
+fi
+   
+if [ "$1" = "configure" -a "$2" != "" ] &&
+     dpkg --compare-versions "$2" le "0.6.4-4.1" &&
+     [ -f /etc/network/run/ifstate -a -x /sbin/dhclient ]
+then
+  # for every active ifupdown-controlled dhclient interface, copy
+  # /var/run/dhclient.pid, so that the new ifdown is able to kill
+  # dhclient.
+  #
+  # the old version had a bug with more than one DHCP iface anyway,
+  # so we don't know which one the PID file actually belongs to.
+
+  sed -e 's/^.*=//' /etc/network/run/ifstate |
+    while read iface; do
+      # handle \<newline>-continued lines
+      if sed -e '/^[[:space:]]*#/b;:g /\\$/{N;s/\\\n//;bg;}' /etc/network/interfaces | grep -qe "^[[:space:]]*iface[[:space:]]*\\b${iface}\\b[[:space:]]*.*\\bdhcp\\b.*" &&
+          [ -f "/var/run/dhclient.pid" ] &&
+          [ ! -f "/var/run/dhclient.${iface}.pid" ]
+      then
+        # copy original file.  If dhclient was started
+        # manually, one can still use dhclient.pid, if started
+        # by ifupdown, the new ifupdown can take it down with 
+        # dhclient.${iface}.pid.  Obsolete files are removed during
+        # next boot (bootmisc.sh).
+        cp /var/run/dhclient.pid "/var/run/dhclient.${iface}.pid"
+      fi
+    done
+fi
+
+# Generic stuff done on all configurations
+if [ "$1" = "configure" ] ; then
+  if [ -f /etc/network/interfaces ] ; then
+    # TODO: This should be handled with debconf and the script
+    # could introduce the line there directly
+    if ! grep -q "^[[:space:]]*iface[[:space:]]\+lo[[:space:]]\+inet[[:space:]]\+loopback\>" /etc/network/interfaces ; then
+      report_warn "No 'iface lo' definition found in /etc/network/interfaces"
+    fi
+    if ! grep -q "^[[:space:]]*auto[[:space:]].*\<lo\>" /etc/network/interfaces ; then
+      report_warn "No 'auto lo' statement found in /etc/network/interfaces"
+    fi
+  else  # ! -f /etc/network/interfaces
+    echo "Creating /etc/network/interfaces."
+    echo "# interfaces(5) file used by ifup(8) and ifdown(8)" > /etc/network/interfaces
+    echo "auto lo" >> /etc/network/interfaces
+    echo "iface lo inet loopback" >> /etc/network/interfaces
+  fi
+fi
+
+db_stop
+
+#DEBHELPER#
diff --git a/debian/postrm b/debian/postrm
new file mode 100644 (file)
index 0000000..883ffcd
--- /dev/null
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+case "$1" in
+  purge)
+    # Note: We don't remove /etc/network/interfaces
+    rm -f /etc/network/run/ifstate
+
+    if [ -L /etc/network/run ] ; then
+      rm -f /etc/network/run
+    elif [ -d /etc/network/run ] ; then
+      rmdir --ignore-fail-on-non-empty /etc/network/run
+    fi
+    ;;
+esac
+
+#DEBHELPER#
+
diff --git a/debian/preinst b/debian/preinst
new file mode 100644 (file)
index 0000000..eb5523f
--- /dev/null
@@ -0,0 +1,27 @@
+#!/bin/sh
+set -e
+
+if [ ! -d /etc/network ]; then
+  mkdir -p /etc/network
+fi
+
+if [ -f /etc/network/interfaces ] && ! grep -q '^[^#]' /etc/network/interfaces
+then
+  f=/etc/network/interfaces
+  if [ `md5sum < $f | cut -f1 -d ' '` = "4ed352919f69a77ad302ad1593204405" ]; then
+    if [ `wc -c < /etc/network/interfaces` -eq 2466 ]; then
+      echo -n "Removing old dummy /etc/network/interfaces: "
+      rm /etc/network/interfaces
+      echo "done."
+    fi
+  fi
+fi
+
+if [ ! -f /etc/network/interfaces ]; then
+  cat <<EOF >/etc/network/interfaces
+# Used by ifup(8) and ifdown(8). See the interfaces(5) manpage or
+# /usr/share/doc/ifupdown/examples for more information.
+EOF
+fi
+
+#DEBHELPER#
diff --git a/debian/rules b/debian/rules
new file mode 100755 (executable)
index 0000000..a3e6463
--- /dev/null
@@ -0,0 +1,176 @@
+#!/usr/bin/make -f
+
+######################################################################
+# BUILD NOTES
+#
+# ifupdown's written in litprog using noweb. noweb is written in icon.
+# icon isn't as portable as one might hope (it needs to have bits recoded
+# for each arch and OS it's ported to. ugh).
+#
+# So. The "upstream" source is made to not include any of the generated
+# files. That's neat and tidy. If you want to modify anything, you edit
+# the .nw file.
+#
+# Once you've done all the Debian changes, you run debian/rules binary,
+# and get all the .c files and such updated. Once you're done, you
+# run debian/rules clean, which leaves the generated .c files around
+# for porters. You then generate a .diff.gz, and all should be well.
+#
+# Useful targets of the toplevel makefile:
+# clobber:
+#   * gets rid of all the generated files except Makefile,
+#     make{c,nw}dep.sh, which are needed to bootstrap
+#
+# distclean:
+#   * removes ALL generated files.  Use with care.
+#
+# docs: 
+#   * builds the documentation. Note that this is not done per
+#     default (only executables are built). If this is added to
+#     the default build process (which will not be done in the near
+#     future since dia requires an X display even if using the -e option) 
+#     the 'tetex-base' and 'dia' packages would need to be added to the
+#     Build-Dep
+#
+######################################################################
+
+# Uncomment this to turn on verbose mode.
+#export DH_VERBOSE=1
+
+# This is the debhelper compatability version to use.
+export DH_COMPAT=1
+
+# For working out whether we're cross-building
+DEB_BUILD_GNU_TYPE     := $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)
+DEB_HOST_GNU_TYPE      := $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
+
+# user/group of to-be-installed files
+ROOT_USER  := 0
+ROOT_GROUP := 0
+
+ifeq (,$(wildcard /usr/bin/po2debconf))
+PO2DEBCONF := no
+MINDEBCONFVER := 0.5
+else
+PO2DEBCONF := yes
+MINDEBCONFVER := 1.2.0
+endif
+
+configure:
+       dh_testdir
+
+build: build-stamp
+build-stamp: # configure
+       dh_testdir
+
+       if [ -x /usr/bin/noweb ]; then \
+         $(MAKE) clobber; \
+       else \
+         chmod a+rx defn2c.pl defn2man.pl makecdep.sh makenwdep.sh; \
+       fi
+       $(MAKE)
+       touch build-stamp
+
+test: build
+       dh_testdir
+
+ifeq ($(DEB_BUILD_GNU_TYPE),$(DEB_HOST_GNU_TYPE))
+       chmod a+rx debian/testbuild
+       @echo running debian/testbuild
+       @if ! debian/testbuild; then \
+            echo '=================================================='; \
+            echo 'AUTOMATIC TESTS FAILED -- Something built wrong or'; \
+            echo 'there is a bug in the code!!! Either way something'; \
+            echo 'is completely screwed up!!! File a bug!'; \
+            echo ''; \
+            echo 'Aborting build.'; \
+            echo '=================================================='; \
+            exit 1; \
+       fi
+endif
+
+clean:
+       dh_testdir
+       dh_testroot
+
+       # Add here commands to clean up after the build process
+       rm -rf tests/
+       rm -f build-stamp install-stamp
+       -$(MAKE) clean
+
+       dh_clean
+ifeq ($(PO2DEBCONF),yes)
+       # Hack for woody compatibility. This makes sure that the
+       # debian/templates file shipped in the source package doesn't
+       # specify encodings, which woody's debconf can't handle. If building
+       # on a system with po-debconf installed (conveniently debhelper (>=
+       # 4.1.16) depends on it), the binary-arch target will generate a
+       # better version for sarge.
+       echo 1 > debian/po/output
+       po2debconf debian/templates.master > debian/templates
+       rm -f debian/po/output
+endif
+
+install-stamp: install
+install: build test
+       dh_testdir
+       dh_testroot
+       dh_clean -k
+       dh_installdirs etc/network/if-pre-up.d etc/network/if-up.d etc/network/if-down.d etc/network/if-post-down.d
+
+       # Add here commands to install the package into debian/tmp.
+       $(MAKE) install BASEDIR=`pwd`/debian/tmp
+
+       install -o $(ROOT_USER) -g $(ROOT_GROUP) -m 755 debian/upgrade-from-0.5.x.pl \
+               debian/tmp/usr/share/ifupdown/
+       install -o $(ROOT_USER) -g $(ROOT_GROUP) -m 644 debian/interfaces \
+               debian/tmp/etc/network/
+       touch install-stamp
+
+# Build architecture-independent files here.
+binary-indep: build-stamp install-stamp
+# We have nothing to do by default.
+
+# Build architecture-dependent files here.
+binary-arch: build install
+#      dh_testversion
+       dh_testdir
+       dh_testroot
+       dh_installdebconf       
+       dh_installdocs
+       dh_installexamples contrib/*
+       mv debian/tmp/usr/share/doc/ifupdown/examples debian/tmp/usr/share/doc/ifupdown/contrib
+       dh_installexamples examples/*
+       dh_installmenu
+#      dh_installemacsen
+#      dh_installpam
+       dh_installinit --name=ifupdown-clean --no-start -- start 18 S .
+       dh_installinit --name=ifupdown --no-start -- start 39 S .  start 36 0 6 .
+       dh_installcron
+#      dh_installmanpages
+#         ^-- can't do our symlink trick
+       install -o $(ROOT_USER) -g $(ROOT_GROUP) -m 644 interfaces.5 debian/tmp/usr/share/man/man5/interfaces.5
+       install -o $(ROOT_USER) -g $(ROOT_GROUP) -m 644 ifup.8 debian/tmp/usr/share/man/man8/ifup.8
+       ln -s ifup.8 debian/tmp/usr/share/man/man8/ifdown.8
+       dh_installinfo
+#      dh_undocumented
+       dh_installchangelogs ChangeLog
+       dh_link
+       dh_strip
+       dh_compress
+       dh_fixperms
+       # You may want to make some executables suid here.
+#      dh_suidregister
+#      dh_makeshlibs
+       dh_installdeb
+#      dh_perl
+       dh_shlibdeps
+ifeq ($(PO2DEBCONF),yes)
+       po2debconf -e utf8 debian/templates.master > debian/templates
+endif
+       dh_gencontrol -- -V'debconf-depends=debconf (>= $(MINDEBCONFVER)) | debconf-2.0'
+       dh_md5sums
+       dh_builddeb
+
+binary: binary-indep binary-arch
+.PHONY: build clean binary-indep binary-arch binary install configure test
diff --git a/debian/templates b/debian/templates
new file mode 100644 (file)
index 0000000..4ec1168
--- /dev/null
@@ -0,0 +1,42 @@
+Template: ifupdown/convert-interfaces
+Type: boolean
+Default: true
+Description: Update /etc/network/interfaces?
+ The format of /etc/network/interfaces has had a minor but incompatible
+ change made between version 0.5.x and 0.6.x of ifupdown. It is however
+ possible to automatically convert from the old format to the new in almost
+ all cases.
+Description-ca.UTF-8: Voleu actualitzar el fitxer /etc/network/interfaces?
+ El format del fitxer /etc/network/interfaces de l'ifupdown s'ha modificat entre les versions 0.5.x i 0.6.x. Tot i això, en la majoria dels casos es pot actualitzar automàticament del format vell al nou.
+Description-cs.UTF-8: Aktualizovat /etc/network/interfaces?
+ Mezi verzemi 0.5.x a 0.6 programu ifupdown došlo k malé, ale nekompatibilní změně formátu souboru /etc/network/interfaces. V téměř všech případech lze převést data ze starého formátu do nového zcela automaticky.
+Description-da.UTF-8: Opdatér /etc/network/interfaces?
+ Formatet i filen /etc/network/interfaces har fået lavet en mindre men inkompatibel ændring mellem version 0.5.x og 0.6.x af ifupdown. Det er dog muligt at automatisk konvertere fra det gamle format til det nye i næsten alle tilfælde.
+Description-de.UTF-8: Soll /etc/network/interfaces erneuert werden?
+ Das Format von /etc/network/interfaces hat eine kleinere aber inkompatible Änderung zwischen Version 0.5.x und 0.6.x von ifupdown erfahren. Es ist jedoch in fast allen Fällen möglich, automatisch vom alten in das neue Format zu konvertieren.
+Description-el.UTF-8: Να γίνει διόρθωση του /etc/network/interfaces;
+ Η δομή του /etc/network/interfaces άλλαξε με ένα μικρό αλλά ασύμβατο τρόπο από την έκδοση του πακέτου ifupdown 0.5.x και 0.6.x.  Ωστόσο, είναι δυνατή η αυτόματη μετατροπή της παλιάς δομής στη νέα για σχεδόν όλες τις περιπτώσεις.
+Description-es.UTF-8: ¿Actualizar /etc/network/interfaces
+ El formato de /etc/network/interfaces ha sufrido un cambio pequeño pero incompatible entre las versiones 0.5.x y 0.6.x de ifupdown. No obstante, en casi todos los casos es posible realizar la conversión automáticamente entre el formato antiguo y el nuevo.
+Description-fr.UTF-8: Mettre à jour /etc/network/interfaces ?
+ Le format du fichier /etc/network/interfaces a subi un changement mineur mais incompatible entre les versions 0.5.x et 0.6.x d'ifupdown. Il est néanmoins possible de convertir automatiquement ce fichier de l'ancien format au nouveau, dans la plupart des cas.
+Description-it.UTF-8: Aggiornare /etc/network/interfaces?
+ Il formato del file /etc/network/interfaces ha subito un piccolo cambiamento che lo rende incompatibile fra le versioni 0.5.x e 0.6.x di ifupdown. Comunque, nella maggior parte dei casi, è possibile convertire automaticamente il file dal vecchio formato al nuovo.
+Description-ja.UTF-8: /etc/network/interfaces を更新しますか?
+ /etc/network/interfaces の形式は、ifupdown の 0.5.x と 0.6.x のあいだで細かな、しかし非互換の変更が行われました。ほぼすべての場合、古い形式から新しい形式へ自動的に変換できます。
+Description-lt.UTF-8: Atnaujinti /etc/network/interfaces?
+ Failo /etc/network/interfaces formatas nežymiai, bet nesuderinamai skiriasi tarp ifupdown versijų 0.5.x ir 0.6.x, tačiau beveik visais atvejais galima automatiškai konvertuoti iš seno formato į naują.
+Description-nl.UTF-8: /etc/network/interfaces bijwerken?
+ De indeling van /etc/network/interfaces heeft tussen versie 0.5.x en 0.6.x van ifupdown een kleine, maar incompatibele verandering ondergaan. In bijna alle gevallen is het echter mogelijk om automatisch het oude format naar het nieuwe om te zetten.
+Description-pl.UTF-8: Uaktualnić /etc/network/interfaces?
+ W porównaniu z wersją 0.5.x, wersja 0.6.x programu ifupdown wprowadza drobne zmiany, które jednak powodują, że stara wersja pliku /etc/network/interfaces może nie pasować do nowej konfiguracji. Istnieje jednak możliwość automatycznej konwersji (w praktycznie wszystkich przypadkach) ze starego formatu do nowego.
+Description-pt_BR.UTF-8: Atualizar /etc/network/interfaces?
+ O formato do arquivo /etc/network/interfaces sofreu uma mudança menor mas incompatível entre as versões 0.5.x e 0.6.x do pacote ifupdown. Porém é possível converter a partir do formato antigo para o novo formato na maioria dos casos.
+Description-ru.UTF-8: Обновить /etc/network/interfaces?
+ Формат /etc/network/interfaces имеет небольшие, но несовместимые изменения между версиями 0.5.x и 0.6.x ifupdown. Однако возможно автоматически преобразовать старый формат с новый почти во всех случаях.
+Description-sv.UTF-8: Uppdatera /etc/network/interfaces?
+ Formatet på /etc/network/interfaces genomgick en liten men inkompatibel ändring mellan version 0.5.x och 0.6.x av ifupdown. Det är dock möjligt att nästan alltid automatiskt konvertera från det gamla formatet till det nya.
+Description-tr.UTF-8: /etc/network/interfaces güncellensin mi?
+ /etc/network/interfaces dosya biçeminde 0.5.x'den 0.6.x sürümüne geçişte küçük fakat uyumsuzluk yaratan bir değişiklik oldu. Bununla birlikte eski biçemin otomatik olarak yenisine dönüştürülmesi neredeyse her durumda mümkündür.
+Description-zh_CN.UTF-8: 更新 /etc/network/interfaces 吗?
+ ifupdown 0.5.x 与 0.6.x 所使用的 /etc/network/interfaces 的文件格式之间有一个较小但互不兼容的改变,然而在绝大多数情况下程序都能自动将旧格式转换到新格式。
diff --git a/debian/templates.master b/debian/templates.master
new file mode 100644 (file)
index 0000000..e3c5229
--- /dev/null
@@ -0,0 +1,8 @@
+Template: ifupdown/convert-interfaces
+Type: boolean
+Default: true
+_Description: Update /etc/network/interfaces?
+ The format of /etc/network/interfaces has had a minor but incompatible
+ change made between version 0.5.x and 0.6.x of ifupdown. It is however
+ possible to automatically convert from the old format to the new in almost
+ all cases.
diff --git a/debian/testbuild b/debian/testbuild
new file mode 100755 (executable)
index 0000000..bc7f4e5
--- /dev/null
@@ -0,0 +1,175 @@
+#!/bin/sh -e
+
+rm -rf tests/
+mkdir tests
+
+cat >tests/testcase.1 <<EOF
+# RUN: -a
+auto eth0
+iface eth0 inet static
+  address 1.2.3.4
+  netmask 255.255.255.0
+  up echo hi
+  post-up echo hello
+EOF
+cat >tests/up.1 <<EOF
+====stdout====
+====stderr====
+Configuring interface eth0=eth0 (inet)
+run-parts --verbose /etc/network/if-pre-up.d
+
+ifconfig eth0 1.2.3.4 netmask 255.255.255.0     up
+
+echo hi
+echo hello
+run-parts --verbose /etc/network/if-up.d
+EOF
+
+cat >tests/testcase.2 <<EOF
+# RUN: -a
+auto eth0 eth1 eth2
+auto eth3 eth4 eth5
+allow-hotplug eth6
+iface eth0 inet static
+  address 1.2.3.4
+  netmask 255.255.255.0
+iface eth1 inet static
+  address 1.3.4.5
+  netmask 255.255.255.0
+iface eth2 inet static
+  address 1.4.5.6
+  netmask 255.255.255.0
+iface eth3 inet static
+  address 1.5.6.7
+  netmask 255.255.255.0
+iface eth4 inet static
+  address 1.7.8.9
+  netmask 255.255.255.0
+iface eth5 inet static
+  address 1.8.9.10
+  netmask 255.255.255.0
+iface eth6 inet static
+  address 1.11.12.13
+  netmask 255.255.255.0
+iface eth7 inet static
+  address 1.14.15.16
+  netmask 255.255.255.0
+EOF
+cat >tests/up.2 <<EOF
+====stdout====
+====stderr====
+Configuring interface eth0=eth0 (inet)
+run-parts --verbose /etc/network/if-pre-up.d
+
+ifconfig eth0 1.2.3.4 netmask 255.255.255.0     up
+
+run-parts --verbose /etc/network/if-up.d
+Configuring interface eth1=eth1 (inet)
+run-parts --verbose /etc/network/if-pre-up.d
+
+ifconfig eth1 1.3.4.5 netmask 255.255.255.0     up
+
+run-parts --verbose /etc/network/if-up.d
+Configuring interface eth2=eth2 (inet)
+run-parts --verbose /etc/network/if-pre-up.d
+
+ifconfig eth2 1.4.5.6 netmask 255.255.255.0     up
+
+run-parts --verbose /etc/network/if-up.d
+Configuring interface eth3=eth3 (inet)
+run-parts --verbose /etc/network/if-pre-up.d
+
+ifconfig eth3 1.5.6.7 netmask 255.255.255.0     up
+
+run-parts --verbose /etc/network/if-up.d
+Configuring interface eth4=eth4 (inet)
+run-parts --verbose /etc/network/if-pre-up.d
+
+ifconfig eth4 1.7.8.9 netmask 255.255.255.0     up
+
+run-parts --verbose /etc/network/if-up.d
+Configuring interface eth5=eth5 (inet)
+run-parts --verbose /etc/network/if-pre-up.d
+
+ifconfig eth5 1.8.9.10 netmask 255.255.255.0    up
+
+run-parts --verbose /etc/network/if-up.d
+EOF
+cat >tests/testcase.3 <<EOF
+# RUN: -a
+auto eth0
+iface eth0 inet static
+  address 1.2.3.4
+  netmask 255.255.255.0
+iface eth0 inet6 static
+  address 3ffe:ffff:100:f101::1
+  netmask 64
+EOF
+cat >tests/up.3 <<EOF
+====stdout====
+====stderr====
+Configuring interface eth0=eth0 (inet)
+run-parts --verbose /etc/network/if-pre-up.d
+
+ifconfig eth0 1.2.3.4 netmask 255.255.255.0             up
+
+run-parts --verbose /etc/network/if-up.d
+Configuring interface eth0=eth0 (inet6)
+run-parts --verbose /etc/network/if-pre-up.d
+ifconfig eth0    up
+ifconfig eth0 add 3ffe:ffff:100:f101::1/64
+
+run-parts --verbose /etc/network/if-up.d
+EOF
+
+cat >tests/testcase.4 <<EOF
+# RUN: eth0=work
+mapping eth0
+  script tests/map.eth0.work
+iface work inet static
+  address 1.2.3.4
+  netmask 255.255.255.0
+  up echo hi
+  post-up echo hello
+EOF
+cat >tests/up.4 <<EOF
+====stdout====
+====stderr====
+Configuring interface eth0=work (inet)
+run-parts --verbose /etc/network/if-pre-up.d
+
+ifconfig eth0 1.2.3.4 netmask 255.255.255.0     up
+
+echo hi
+echo hello
+run-parts --verbose /etc/network/if-up.d
+EOF
+
+
+result=true
+for test in 1 2 3 4; do
+       args="$(cat tests/testcase.$test | sed -n 's/^# RUN: //p')"
+       ./ifup -nv --force -i tests/testcase.$test $args \
+               >tests/up-res-out.$test 2>tests/up-res-err.$test || 
+               true
+       (echo "====stdout===="; cat tests/up-res-out.$test
+        echo "====stderr===="; cat tests/up-res-err.$test) > tests/up-res.$test
+
+       echo "Testcase $test: $args"
+       
+       if diff -ub tests/up.$test tests/up-res.$test; then
+               echo "(okay)"
+       else
+               echo "(failed)"
+               result=false
+       fi
+       echo "=========="
+done
+
+if $result; then
+       echo "(okay overall)"
+       exit 0
+else
+       echo "(failed overall)"
+       exit 1
+fi
diff --git a/debian/upgrade-from-0.5.x.pl b/debian/upgrade-from-0.5.x.pl
new file mode 100644 (file)
index 0000000..2734d28
--- /dev/null
@@ -0,0 +1,65 @@
+#!/usr/bin/perl -w
+
+use strict;
+
+my %doneifaces = ();
+my @orig = ();   # original interfaces file
+my $line;
+
+while($line = <STDIN>) {
+       if ($line =~ m/^\s*#/) {
+               push @orig, $line;
+               next;
+       }
+
+       my $tmp;
+       while ($line =~ m/\\\n$/ and $tmp = <>) {
+               $line .= $tmp;
+       }
+       push @orig, $line;
+}
+
+my $out = "";
+my $block = "";
+my $auto = "";
+for my $x (@orig) {
+       my $y = $x;
+       $y =~ s/^\s*//s;
+       $y =~ s/\\\n//sg;
+       $y =~ s/\s*$//s;
+
+       if ($y =~ m/^scheme\b/) {
+               print STDERR "Schemes cannot be automatically converted\n";
+               exit(1);
+       }
+       if ($y =~ m/^auto\b/) {
+               print STDERR "File seems to already be converted\n";
+               exit(1);
+       }
+
+       if ($y =~ m/^iface\b/s) {
+               $out .= $auto . $block;
+               $block = $x;
+               if ($y =~ m/^iface\s+(\S+)/s && ! $doneifaces{$1}++ ) {
+                       $auto = "# automatically added when upgrading\n";
+                       $auto .= "auto $1\n";
+               } else {
+                       $auto = "";
+               }
+               next;
+       }
+
+       if ($y =~ m/^noauto/) {
+               $auto = "";
+               my $spaces = $x;
+               $spaces =~ s/\S.*$//s;
+               $block .= $spaces . "# noauto (removed on upgrade)\n";
+               next;
+       }
+
+       $block .= $x;
+}
+
+$out .= $auto . $block;
+
+print $out;
diff --git a/defn2c.pl b/defn2c.pl
new file mode 100755 (executable)
index 0000000..e32ddcc
--- /dev/null
+++ b/defn2c.pl
@@ -0,0 +1,144 @@
+#!/usr/bin/perl -w
+
+use strict;
+
+# declarations
+my $address_family = "";
+my %methods = ();
+my $line = "";
+my $match = "";
+
+# subroutines
+sub nextline {
+        $line = <>;
+        while($line and ($line =~ /^#/ or $line =~ /^\s*$/)) {
+                $line = <>;
+        }
+        if (!$line) { return 0; }
+        chomp $line;
+        while ($line =~ m/^(.*)\\$/) {
+                my $addon = <>;
+                chomp $addon;
+                $line = $1 . $addon;
+        }
+        return 1;
+}
+sub match {
+        my $line = $_[0];
+        my $cmd = "$_[1]" ? "$_[1]\\b\\s*" : "";;
+        my $indentexp = (@_ == 3) ? "$_[2]\\s+" : "";
+
+        if ($line =~ /^${indentexp}${cmd}(([^\s](.*[^\s])?)?)\s*$/) {
+                $match = $1;
+                return 1;
+        } else {
+                return 0;
+        } 
+}
+sub get_address_family {
+        $address_family = $_[0] if ($address_family eq "");
+        nextline;
+}
+sub get_architecture {
+        my $arch = $_[0];
+        die("architecture declaration appears too late") if (keys %methods);
+        print "#include \"arch${arch}.h\"\n\n\n";
+        nextline;
+}
+sub get_method {
+        my $method = $_[0];
+        my $indent = ($line =~ /(\s*)[^\s]/) ? $1 : "";
+
+        die "Duplicate method $method\n" if ($methods{$method}++);
+
+        nextline;
+        if (match($line, "description", $indent)) {
+                skip_section();
+        }
+        if (match($line, "options", $indent)) {
+                skip_section();
+        }
+        if (match($line, "up", $indent)) {
+                get_commands(${method}, "up");
+        } else {
+                print "static int ${method}_up(interface_defn ifd) { return 0; }\n"
+        }
+        if (match($line, "down", $indent)) {
+                get_commands(${method}, "down");
+        } else {
+                print "static int ${method}_down(interface_defn ifd) { return 0; }\n"
+        }
+}
+sub skip_section {
+        my $struct = $_[0];
+        my $indent = ($line =~ /(\s*)[^\s]/) ? $1 : "";
+
+        1 while (nextline && match($line, "", $indent));
+}
+sub get_commands {
+        my $method = $_[0];
+        my $mode = $_[1];
+        my $function = "${method}_${mode}";
+        my $indent = ($line =~ /(\s*)[^\s]/) ? $1 : "";
+
+        print "static int ${function}(interface_defn *ifd, execfn *exec) {\n";
+
+        while (nextline && match($line, "", $indent)) {
+                if ( $match =~ /^(.*[^\s])\s+if\s*\((.*)\)\s*$/ ) {
+                        print "if ( $2 ) {\n";
+                        print "  if (!execute(\"$1\", ifd, exec)) return 0;\n";
+                        print "}\n";
+                } elsif ( $match =~ /^(.*[^\s])\s+elsif\s*\((.*)\)\s*$/ ) {
+                        print "else if ( $2 ) {\n";
+                        print "  if (!execute(\"$1\", ifd, exec)) return 0;\n";
+                        print "}\n";
+                } elsif ( $match =~ /^(.*[^\s])\s*$/ ) {
+                        print "{\n";
+                        print "  if (!execute(\"$1\", ifd, exec)) return 0;\n";
+                        print "}\n";
+                }
+        }
+
+        print "return 1;\n";
+        print "}\n";
+}
+
+# main code
+print "#include \"header.h\"\n\n\n";
+nextline;
+while($line) {
+        if (match($line, "address_family")) {
+                get_address_family $match;
+                next;
+        }
+        if (match($line, "architecture")) {
+                get_architecture $match;
+                next;
+        }
+        if (match($line, "method")) {
+                get_method $match;
+                next;
+        }
+
+        # ...otherwise
+        die("Unknown command \"$line\"");
+}
+print "static method methods[] = {\n";
+my $method;
+foreach $method (keys %methods) {
+        print <<EOF;
+        {
+                "$method",
+                ${method}_up, ${method}_down,
+        },
+EOF
+}
+print "};\n\n";
+
+print <<EOF;
+address_family addr_${address_family} = {
+        "$address_family",
+        sizeof(methods)/sizeof(struct method),
+        methods
+};
+EOF
diff --git a/defn2man.pl b/defn2man.pl
new file mode 100755 (executable)
index 0000000..0d73fff
--- /dev/null
@@ -0,0 +1,148 @@
+#!/usr/bin/perl -w
+
+use strict;
+
+# declarations
+my $line;
+my $match;
+
+# subroutines
+sub nextline {
+        $line = <>;
+        while($line and ($line =~ /^#/ or $line =~ /^\s*$/)) {
+                $line = <>;
+        }
+        if (!$line) { return 0; }
+        chomp $line;
+        while ($line =~ m/^(.*)\\$/) {
+                my $addon = <>;
+                chomp $addon;
+                $line = $1 . $addon;
+        }
+        return 1;
+}
+sub match {
+        my $line = $_[0];
+        my $cmd = "$_[1]" ? "$_[1]\\b\\s*" : "";;
+        my $indentexp = (@_ == 3) ? "$_[2]\\s+" : "";
+
+        if ($line =~ /^${indentexp}${cmd}(([^\s](.*[^\s])?)?)\s*$/) {
+                $match = $1;
+                return 1;
+        } else {
+                return 0;
+        } 
+}
+sub skip_section {
+        my $struct = $_[0];
+        my $indent = ($line =~ /(\s*)[^\s]/) ? $1 : "";
+
+        1 while (nextline && match($line, "", $indent));
+}
+sub get_address_family {
+        print ".SH " . uc($match) . " ADDRESS FAMILY\n";
+        print "This section documents the methods available in the\n";
+        print "$match address family.\n";
+        nextline;
+}
+sub get_architecture {
+        # no op
+        nextline;
+}
+sub get_method {
+        my $method = shift;
+        my $indent = ($line =~ /(\s*)\S/) ? $1 : "";
+        my $description = "";
+        my @options = ();
+
+        nextline;
+        while ($line and match($line, "", $indent)) {
+                if (match($line, "description", $indent)) {
+                        $description = get_description();
+                } elsif (match($line, "options", $indent)) {
+                        @options = get_options();
+                } else {
+                        skip_section;
+                }
+        }
+
+        print ".SS The $method Method\n";
+        if ($description ne "") {
+                print usenet2man($description) . "\n";
+        } else {
+                print "(No description)\n";
+        }
+        print ".PP\n";
+        print ".B Options\n";
+        print ".RS\n";
+        if (@options) {
+                foreach my $o (@options) {
+                        if ($o =~ m/^\s*(\S*)\s*(.*)\s+--\s+(\S.*)$/) {
+                                my $opt = $1;
+                                my $optargs = $2;
+                                my $dsc = $3;
+                                print ".TP\n";
+                                print ".BI $opt";
+                                print " \" $optargs\"" unless($optargs =~ m/^\s*$/);
+                                print "\n";
+                                print usenet2man($dsc) . "\n";
+                        } else {
+                                print ".TP\n";
+                                print ".B $o\n";
+                        }
+                }
+        } else {
+                print ".TP\n";
+                print "(No options)\n";
+        }
+        print ".RE\n";
+}
+sub get_description {
+        my $desc = "";
+        my $indent = ($line =~ /(\s*)\S/) ? $1 : "";
+        while(nextline && match($line, "", $indent)) {
+                $desc .= "$match\n";
+        }
+        return $desc;
+}
+sub usenet2man {
+        my $in = shift;
+        my $out = "";
+
+        $in =~ s/\s+/ /g;
+        while ($in =~ m%^([^*/]*)([*/])([^*/]*)([*/])(.*)$%s) {
+                my ($pre, $l, $mid, $r, $post) = ($1, $2, $3, $4, $5);
+                if ($l eq $r && " $pre"  =~ m/[[:punct:][:space:]]$/ 
+                             && "$post " =~ m/^[[:punct:][:space:]]/) {
+                        $out .= $pre;
+                        $out .= ($l eq "*" ? '\fB' : '\fI') . $mid . '\fP';
+                        ($in = $post) =~ s/^\s+/ /;
+                } else {
+                        $out .= $pre . $l;
+                        $in = $mid . $r . $post;
+                }
+        } 
+        return $out . $in;
+}
+sub get_options {
+        my @opts = ();
+        my $indent = ($line =~ /(\s*)\S/) ? $1 : "";
+        while(nextline && match($line, "", $indent)) {
+                push @opts, $match;
+        }
+        return @opts;
+}
+
+# main code
+nextline;
+if ($line and match($line, "address_family")) {
+        get_address_family $match;
+} else {
+        die "address_family must be listed first\n";
+}
+if ($line and match($line, "architecture")) {
+        get_architecture $match;
+}
+while ($line and match($line, "method")) {
+        get_method $match;
+}
diff --git a/examples/bridge b/examples/bridge
new file mode 100644 (file)
index 0000000..97fe3f5
--- /dev/null
@@ -0,0 +1,69 @@
+#!/bin/sh 
+# The following script example, if dropped in /etc/network/if-pre-up.d/
+# and under /etc/network/if-down.d/, will manage to configure a bridge 
+# if defined in the /etc/network/interfaces file as either:
+#
+# Note: The bridge-utils package already provide a similar (more
+# powerful) script this is just provided here for convenience and to
+# show how the /etc/network/if-*.d/ methods can be defined.
+# 
+# [ a bridge with an associated IP address ]
+#  iface br0 inet static
+#       bridge-ifaces eth0 eth1
+#       address 192.168.1.1
+#       netmask 255.255.255.0
+# [ a bridge which acts as an anonymous bridge ]
+#  iface br0 inet manual
+#       bridge-ifaces eth0 eth1
+#       up ifconfig $IFACE up
+#
+# For more information read:
+#  http://bridge.sourceforge.net/howto.html
+
+brctl=`which brctl`
+
+# Notice that the bridge-utils package must be installed and 
+# we need to have the BRIDGE_IFACES in order to work
+[ "$IF_BRIDGE_IFACES" = "" ] && exit 0
+if [ -z "$brctl" ] ; then
+       # ? Somebody is trying to use us without having bridge-utils?
+       echo "Cannot find the 'brctl' program to setup the bridge"
+       echo "Hint: Have you installed the bridge-utils package?"
+       exit 1
+fi 
+
+# Check all interfaces before proceeding
+for i in $IF_BRIDGE_IFACES; do
+       ip link show $i >/dev/null 2>&1
+       if [ $? -ne 0 ] ; then
+               echo "Interface $i is not available, aborting"
+               exit 1
+       fi
+done
+
+if [ "$MODE" = "start" ] ; then
+       # We are being called by ifup:
+       # Bring up all the bridge interfaces
+       for i in $IF_BRIDGE_IFACES; do
+               ifconfig $i 0.0.0.0 up
+       done
+       # And now add the bridge itself and the interfaces which are part
+       # of the bridge
+       brctl addbr $IFACE
+       for i in $IF_BRIDGE_IFACES; do
+               brctl addif $IFACE $i
+       done
+elif [ "$MODE" = "stop" ];  then
+       # We are being called by ifdown:
+       # Remove the bridge itself and the bridge association
+       for i in $IF_BRIDGE_IFACES; do
+               brctl delif $IFACE $i
+       done
+       brctl delbr $IFACE
+       # Bring down all the bridge interfaces
+       for i in $IF_BRIDGE_IFACES; do
+               ifconfig $i down
+       done
+fi
+
+exit 0
diff --git a/examples/check-mac-address.sh b/examples/check-mac-address.sh
new file mode 100644 (file)
index 0000000..f5eaa92
--- /dev/null
@@ -0,0 +1,19 @@
+#!/bin/sh
+#
+# Checks if the given interface matches the given ethernet MAC.
+# If it does it exits with 0 (success) status;
+# if it doesn't then it exists with 1 (error) status.
+
+set -e
+
+export LANG=C
+
+if [ ! "$2" ] ; then
+       echo "Usage: $0 IFACE targetMAC"
+       exit 1
+fi
+iface="$1"
+targetmac=`echo "$2" | sed -e 'y/ABCDEF/abcdef/'`
+mac=$(/sbin/ifconfig "$iface" | sed -n -e '/^.*HWaddr \([:[:xdigit:]]*\).*/{s//\1/;y/ABCDEF/abcdef/;p;q;}')
+
+if [ "$targetmac" = "$mac" ]; then exit 0; else exit 1; fi
diff --git a/examples/generate-interfaces.pl b/examples/generate-interfaces.pl
new file mode 100644 (file)
index 0000000..b2d41d9
--- /dev/null
@@ -0,0 +1,133 @@
+#!/usr/bin/perl -w
+# Generate an /etc/network/interfaces script based on the
+# current interface and network status.
+# Useful to migrate the configuration of old Debian versions (i.e. pre-woody)
+# or non-Debian systems to the ifup/down scheme used in Debian.
+#
+# (c) 2000 Anthony Towns 
+# slight improvements (route parsing and direct command
+# execution) done by Javier Fernandez-Sanguino 
+# 
+# TODO:
+# [aj] It'd be good if it also grabbed the default gateway from route,
+# and worked out the network based on the netmask and the address
+# (the network is needed for ifup under 2.0.x kernels).
+#
+# [jfs] Some (optional) information is not parsed, like: route metrics
+# and hw addresses of interfaces
+
+
+use strict;
+
+my %iface = ();  # name -> iface info hash
+my $ciface;  # current iface name
+
+# First, read interfaces from ifconfig
+#
+open (IFC,"ifconfig -a | ") || die ("Could not execute ifconfig: $!\n");
+
+while(my $line = <IFC>) {
+    chomp $line;
+    if ($line =~ m/^(\S+)\s+(\S.*)$/) {
+        $ciface = $1;
+       $iface{$ciface} = { };
+        $line = $2;
+    } elsif ($line =~ m/^\s+(\S.*)$/) {
+        $line = $1;
+    } else {
+        $ciface = undef;
+        next;
+    }
+    next unless(defined $ciface);
+
+    if ($line =~ s/Link encap:(.*)$//) {
+        $iface{$ciface}->{"type"} = $1;
+    }
+    if ($line =~ s/^inet //) {
+        $iface{$ciface}->{"ipv4"} = "yes";
+        if ($line =~ s/addr:(\S*)//) {
+            $iface{$ciface}->{"ipv4_addr"} = $1;
+        }
+        if ($line =~ s/Bcast:(\S*)//) {
+            $iface{$ciface}->{"ipv4_bcast"} = $1;
+        }
+        if ($line =~ s/Mask:(\S*)//) {
+            $iface{$ciface}->{"ipv4_mask"} = $1;
+        }
+    }
+}
+
+close IFC;
+
+# Now, read route information from netstat
+#
+open (ROU,"route -n | ") || die ("Could not execute route: $!\n");
+while(my $line = <ROU>) {
+    chomp $line;
+    if ( $line =~ m/^([\d\.]+)\s+([\d\.]+)\s+([\d\.]+)\s+(\S+)\s+(\d+).*?\s+(\S+)$/) {
+       my $dest = $1; my $gw = $2; my $mask = $3; my $flags = $4;
+       my $metric = $5; my $if = $6;
+       if ( defined ( $iface{$if} ) ) {
+               if ( $dest eq "0.0.0.0" && $mask eq "0.0.0.0" ) {
+               # Default gateway
+                       $iface{$if}->{"gateway"} = $gw;
+               } elsif ( $gw ne "0.0.0.0" )  {
+               # Specific (static) route
+                       push @{$iface{$if}->{"up"}} , "route add -net $dest netmask $mask gw $gw dev $if";
+                       push @{$iface{$if}->{"down"}} , "route del -net $dest netmask $mask gw $gw dev $if";
+               }
+       }
+    }
+
+}
+
+close ROU;
+
+foreach my $if (keys %iface) {
+    if ($iface{$if}->{"type"} =~ m/loopback/i) {
+        if ($iface{$if}->{"ipv4"} eq "yes") {
+            print "iface $if inet loopback\n";
+        }
+    }
+
+    if ($iface{$if}->{"type"} =~ m/ethernet/i) {
+        if ($iface{$if}->{"ipv4"} eq "yes") {
+            print "iface $if inet static\n";
+            if (defined $iface{$if}->{"ipv4_addr"}) {
+                print "    address " . $iface{$if}->{"ipv4_addr"} . "\n";
+            }
+            if (defined $iface{$if}->{"ipv4_mask"}) {
+                print "    netmask " . $iface{$if}->{"ipv4_mask"} . "\n";
+            }
+            if (defined $iface{$if}->{"ipv4_addr"}) {
+                print "    broadcast " . $iface{$if}->{"ipv4_bcast"} . "\n";
+            }
+            if (defined $iface{$if}->{"gateway"}) {
+                print "    gateway " . $iface{$if}->{"gateway"} . "\n";
+            }
+            if (defined $iface{$if}->{"pre-up"}) {
+               while ( my $upcmd = pop @{$iface{$if}->{"pre-up"}} ) {
+                       print "    pre-up " . $upcmd . "\n";
+               }
+            }
+            if (defined $iface{$if}->{"up"}) {
+               while ( my $upcmd = pop @{$iface{$if}->{"up"}} ) {
+                       print "    up " . $upcmd . "\n";
+               }
+            }
+            if (defined $iface{$if}->{"down"}) {
+               while ( my $downcmd = pop @{$iface{$if}->{"down"}} ) {
+                       print "    down " . $downcmd . "\n";
+               }
+            }
+            if (defined $iface{$if}->{"post-down"}) {
+               while ( my $downcmd = pop @{$iface{$if}->{"pre-down"}} ) {
+                       print "    pre-down " . $downcmd . "\n";
+               }
+            }
+        }
+    }
+    print "\n";
+}
+
+exit 0;
diff --git a/examples/get-mac-address.sh b/examples/get-mac-address.sh
new file mode 100644 (file)
index 0000000..6f73d5a
--- /dev/null
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+set -e
+
+export LANG=C
+
+iface="$1"
+mac=$(/sbin/ifconfig "$iface" | sed -n -e '/^.*HWaddr \([:[:xdigit:]]*\).*/{s//\1/;y/ABCDEF/abcdef/;p;q;}')
+which=""
+
+while read testmac scheme; do
+       if [ "$which" ]; then continue; fi
+       if [ "$mac" = "$(echo "$testmac" | sed -e 'y/ABCDEF/abcdef/')" ]; then which="$scheme"; fi
+done
+
+if [ "$which" ]; then echo $which; exit 0; fi
+exit 1
diff --git a/examples/network-interfaces b/examples/network-interfaces
new file mode 100644 (file)
index 0000000..50a7eb3
--- /dev/null
@@ -0,0 +1,193 @@
+######################################################################
+# /etc/network/interfaces -- configuration file for ifup(8), ifdown(8)
+#
+# A "#" character in the very first column makes the rest of the line
+# be ignored. Blank lines are ignored. Lines may be indented freely.
+# A "\" character at the very end of the line indicates the next line
+# should be treated as a continuation of the current one.
+#
+# The "pre-up", "up", "down" and "post-down" options are valid for all 
+# interfaces, and may be specified multiple times. All other options
+# may only be specified once.
+#
+# See the interfaces(5) manpage for information on what options are 
+# available.
+######################################################################
+
+# We always want the loopback interface.
+#
+# auto lo
+# iface lo inet loopback
+
+# An example ethernet card setup: (broadcast and gateway are optional)
+#
+# auto eth0
+# iface eth0 inet static
+#     address 192.168.0.42
+#     network 192.168.0.0
+#     netmask 255.255.255.0
+#     broadcast 192.168.0.255
+#     gateway 192.168.0.1
+
+# A more complicated ethernet setup, with a less common netmask, and a downright
+# weird broadcast address: (the "up" lines are executed verbatim when the 
+# interface is brought up, the "down" lines when it's brought down)
+#
+# auto eth0
+# iface eth0 inet static
+#     address 192.168.1.42
+#     network 192.168.1.0
+#     netmask 255.255.255.128
+#     broadcast 192.168.1.0
+#     up route add -net 192.168.1.128 netmask 255.255.255.128 gw 192.168.1.2
+#     up route add default gw 192.168.1.200
+#     down route del default gw 192.168.1.200
+#     down route del -net 192.168.1.128 netmask 255.255.255.128 gw 192.168.1.2
+
+# A more complicated ethernet setup with a single ethernet card with
+# two interfaces.
+# Note: This happens to work since ifconfig handles it that way, not because
+# ifup/down handles the ':' any differently.
+# Warning: There is a known bug if you do this, since the state will not
+# be properly defined if you try to 'ifdown eth0' when both interfaces
+# are up. The ifconfig program will not remove eth0 but it will be
+# removed from the interfaces state so you will see it up until you execute:
+# 'ifdown eth0:1 ; ifup eth0; ifdown eth0'
+# BTW, this is "bug" #193679 (it's not really a bug, it's more of a 
+# limitation)
+#
+# auto eth0 eth0:1
+# iface eth0 inet static
+#     address 192.168.0.100
+#     network 192.168.0.0
+#     netmask 255.255.255.0
+#     broadcast 192.168.0.255
+#     gateway 192.168.0.1
+# iface eth0:1 inet static
+#     address 192.168.0.200
+#     network 192.168.0.0
+#     netmask 255.255.255.0
+
+# "pre-up" and "post-down" commands are also available. In addition, the
+# exit status of these commands are checked, and if any fail, configuration
+# (or deconfiguration) is aborted. So:
+#
+# auto eth0
+# iface eth0 inet dhcp
+#     pre-up [ -f /etc/network/local-network-ok ]
+#
+# will allow you to only have eth0 brought up when the file 
+# /etc/network/local-network-ok exists.
+
+# Two ethernet interfaces, one connected to a trusted LAN, the other to
+# the untrusted Internet. If their MAC addresses get swapped (because an
+# updated kernel uses a different order when probing for network cards,
+# say), then they don't get brought up at all.
+#
+# auto eth0 eth1
+# iface eth0 inet static
+#     address 192.168.42.1
+#     netmask 255.255.255.0
+#     pre-up /path/to/check-mac-address.sh eth0 11:22:33:44:55:66
+#     pre-up /usr/local/sbin/enable-masq
+# iface eth1 inet dhcp
+#     pre-up /path/to/check-mac-address.sh eth1 AA:BB:CC:DD:EE:FF
+#     pre-up /usr/local/sbin/firewall
+
+# Two ethernet interfaces, one connected to a trusted LAN, the other to
+# the untrusted Internet, identified by MAC address rather than interface
+# name:
+#
+# auto eth0 eth1
+# mapping eth0 eth1
+#     script /path/to/get-mac-address.sh
+#     map 11:22:33:44:55:66 lan
+#     map AA:BB:CC:DD:EE:FF internet
+# iface lan inet static
+#     address 192.168.42.1
+#     netmask 255.255.255.0
+#     pre-up /usr/local/sbin/enable-masq $IFACE
+# iface internet inet dhcp
+#     pre-up /usr/local/sbin/firewall $IFACE
+
+# A PCMCIA interface for a laptop that is used in different locations:
+# (note the lack of an "auto" line for any of these)
+#
+# mapping eth0
+#    script /path/to/pcmcia-compat.sh
+#    map home,*,*,*                  home
+#    map work,*,*,00:11:22:33:44:55  work-wireless
+#    map work,*,*,01:12:23:34:45:50  work-static
+#
+# iface home inet dhcp
+# iface work-wireless bootp
+# iface work-static static
+#     address 10.15.43.23
+#     netmask 255.255.255.0
+#     gateway 10.15.43.1
+#
+# Note, this won't work unless you specifically change the file
+# /etc/pcmcia/network to look more like:
+#
+#     if [ -r ./shared ] ; then . ./shared ; else . /etc/pcmcia/shared ; fi
+#     get_info $DEVICE
+#     case "$ACTION" in
+#         'start')
+#             /sbin/ifup $DEVICE
+#             ;;
+#         'stop')
+#             /sbin/ifdown $DEVICE
+#             ;;
+#     esac
+#     exit 0
+
+# An alternate way of doing the same thing: (in this case identifying
+# where the laptop is is done by configuring the interface as various
+# options, and seeing if a computer that is known to be on each particular
+# network will respond to pings. The various numbers here need to be chosen
+# with a great deal of care.)
+#
+# mapping eth0
+#    script /path/to/ping-places.sh
+#    map 192.168.42.254/24 192.168.42.1 home
+#    map 10.15.43.254/24 10.15.43.1 work-wireless
+#    map 10.15.43.23/24 10.15.43.1 work-static
+#
+# iface home inet dhcp
+# iface work-wireless bootp
+# iface work-static static
+#     address 10.15.43.23
+#     netmask 255.255.255.0
+#     gateway 10.15.43.1
+#
+# Note that the ping-places script requires the iproute package installed,
+# and the same changes to /etc/pcmcia/network are required for this as for
+# the previous example.
+
+
+# Set up an interface to read all the traffic on the network. This 
+# configuration can be useful to setup Network Intrusion Detection
+# sensors in 'stealth'-type configuration. This prevents the NIDS
+# system to be a direct target in a hostile network since they have
+# no IP address on the network. Notice, however, that there have been
+# known bugs over time in sensors part of NIDS (for example see 
+# DSA-297 related to Snort) and remote buffer overflows might even be
+# triggered by network packet processing.
+# 
+# auto eth0
+# iface eth0 inet manual
+#      up ifconfig $IFACE 0.0.0.0 up
+#       up ip link set $IFACE promisc on
+#       down ip link set $IFACE promisc off
+#       down ifconfig $IFACE down
+
+# Set up an interface which will not be allocated an IP address by
+# ifupdown but will be configured through external programs. This
+# can be useful to setup interfaces configured through other programs,
+# like, for example, PPPOE scripts.
+#
+# auto eth0
+# iface eth0 inet manual
+#       up ifconfig $IFACE 0.0.0.0 up
+#       up /usr/local/bin/myconfigscript
+#       down ifconfig $IFACE down
diff --git a/examples/pcmcia-compat.sh b/examples/pcmcia-compat.sh
new file mode 100644 (file)
index 0000000..4b31fdb
--- /dev/null
@@ -0,0 +1,29 @@
+#!/bin/sh
+
+if [ ! -e /etc/pcmcia/shared ]; then exit 1; fi
+
+pcmcia_shared () {
+       . /etc/pcmcia/shared
+}
+
+iface="$1"
+
+# /etc/pcmcia/shared sucks
+pcmcia_shared "start" $iface
+usage () {
+       exit 1
+}
+
+get_info $iface
+HWADDR=`/sbin/ifconfig $DEVICE | sed -n -e 's/.*addr \([^ ]*\) */\1/p'`
+
+which=""
+while read glob scheme; do
+       if [ "$which" ]; then continue; fi
+       case "$SCHEME,$SOCKET,$INSTANCE,$HWADDR" in
+               $glob) which=$scheme ;;
+       esac
+done
+
+if [ "$which" ]; then echo $which; exit 0; fi
+exit 1
diff --git a/examples/ping-places.sh b/examples/ping-places.sh
new file mode 100644 (file)
index 0000000..6f6f2e1
--- /dev/null
@@ -0,0 +1,30 @@
+#!/bin/sh
+
+if [ `id -u` -ne 0 ] || [ "$1" = "" ]; then exit 1; fi
+
+if [ -x /usr/bin/fping ]; then
+       PING="/usr/bin/fping"
+else
+       PING="/bin/ping -c 2"
+fi
+
+iface="$1"
+which=""
+
+while read addr pingme scheme; do
+       if [ "$which" ]; then continue; fi
+
+       #echo "  Trying $addr & $pingme ($scheme)" >&2
+
+       ip addr add $addr dev $iface  >/dev/null 2>&1
+       ip link set $iface up         >/dev/null 2>&1
+
+       if $PING $pingme >/dev/null 2>&1; then
+               which="$scheme" 
+       fi
+       ip link set $iface down       >/dev/null 2>&1
+       ip addr del $addr dev $iface  >/dev/null 2>&1
+done
+
+if [ "$which" ]; then echo $which; exit 0; fi
+exit 1
diff --git a/execute.c b/execute.c
new file mode 100644 (file)
index 0000000..8bb705f
--- /dev/null
+++ b/execute.c
@@ -0,0 +1,497 @@
+#line 2076 "ifupdown.nw"
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "header.h"
+#line 2698 "ifupdown.nw"
+#include <errno.h>
+#line 2884 "ifupdown.nw"
+#include <stdarg.h>
+#line 2907 "ifupdown.nw"
+#include <unistd.h>
+#include <sys/wait.h>
+#line 2160 "ifupdown.nw"
+static char **environ = NULL;
+#line 2137 "ifupdown.nw"
+static int check(char *str);
+#line 2167 "ifupdown.nw"
+static void set_environ(interface_defn *iface, char *mode, char *phase);
+#line 2245 "ifupdown.nw"
+static char *setlocalenv(char *format, char *name, char *value);
+#line 2358 "ifupdown.nw"
+static int doit(char *str);
+#line 2525 "ifupdown.nw"
+static char *parse(char *command, interface_defn *ifd);
+#line 2572 "ifupdown.nw"
+void addstr(char **buf, size_t *len, size_t *pos, char *str, size_t strlen);
+#line 2779 "ifupdown.nw"
+int strncmpz(char *l, char *r, size_t llen);
+#line 2796 "ifupdown.nw"
+char *get_var(char *id, size_t idlen, interface_defn *ifd);
+#line 2888 "ifupdown.nw"
+static int popen2(FILE **in, FILE **out, char *command, ...);
+#line 2141 "ifupdown.nw"
+static int check(char *str) {
+       return str != NULL;
+}
+#line 2173 "ifupdown.nw"
+static void set_environ(interface_defn *iface, char *mode, char *phase) {
+       
+#line 2202 "ifupdown.nw"
+char **environend;
+#line 2175 "ifupdown.nw"
+       int i;
+       const int n_env_entries = iface->n_options + 8;
+
+       
+#line 2215 "ifupdown.nw"
+if (environ != NULL) {
+       char **ppch;
+       for (ppch = environ; *ppch; ppch++) {
+               free(*ppch);
+               *ppch = NULL;
+       }
+       free(environ);
+       environ = NULL;
+}
+#line 2209 "ifupdown.nw"
+environ = malloc(sizeof(char*) * (n_env_entries + 1 /* for final NULL */));
+environend = environ; 
+*environend = NULL;
+
+#line 2180 "ifupdown.nw"
+       for (i = 0; i < iface->n_options; i++) {
+               
+#line 2229 "ifupdown.nw"
+if (strcmp(iface->option[i].name, "pre-up") == 0
+    || strcmp(iface->option[i].name, "up") == 0
+    || strcmp(iface->option[i].name, "down") == 0
+    || strcmp(iface->option[i].name, "post-down") == 0)
+{
+       continue;
+}
+
+#line 2183 "ifupdown.nw"
+               
+#line 2251 "ifupdown.nw"
+*(environend++) = setlocalenv("IF_%s=%s", iface->option[i].name,
+                              iface->option[i].value);
+*environend = NULL;
+#line 2184 "ifupdown.nw"
+       }
+
+       
+#line 2257 "ifupdown.nw"
+*(environend++) = setlocalenv("%s=%s", "IFACE", iface->real_iface);
+*environend = NULL;
+#line 2187 "ifupdown.nw"
+       
+#line 2262 "ifupdown.nw"
+*(environend++) = setlocalenv("%s=%s", "LOGICAL", iface->logical_iface);
+*environend = NULL;
+#line 2188 "ifupdown.nw"
+       
+#line 2287 "ifupdown.nw"
+*(environend++) = setlocalenv("%s=%s", "ADDRFAM", iface->address_family->name);
+*environend = NULL;
+#line 2189 "ifupdown.nw"
+       
+#line 2292 "ifupdown.nw"
+*(environend++) = setlocalenv("%s=%s", "METHOD", iface->method->name);
+*environend = NULL;
+
+#line 2191 "ifupdown.nw"
+       
+#line 2267 "ifupdown.nw"
+*(environend++) = setlocalenv("%s=%s", "MODE", mode);
+*environend = NULL;
+#line 2192 "ifupdown.nw"
+       
+#line 2272 "ifupdown.nw"
+*(environend++) = setlocalenv("%s=%s", "PHASE", phase); 
+*environend = NULL;
+#line 2193 "ifupdown.nw"
+       
+#line 2282 "ifupdown.nw"
+*(environend++) = setlocalenv("%s=%s", "VERBOSITY", verbose ? "1" : "0");
+*environend = NULL;
+#line 2194 "ifupdown.nw"
+       
+#line 2277 "ifupdown.nw"
+*(environend++) = setlocalenv("%s=%s", "PATH", "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin");
+*environend = NULL;
+#line 2195 "ifupdown.nw"
+}
+#line 2299 "ifupdown.nw"
+static char *setlocalenv(char *format, char *name, char *value) {
+       char *result;
+
+       
+#line 2317 "ifupdown.nw"
+result = malloc(strlen(format)   /* -4 for the two %s's */
+                + strlen(name) 
+                + strlen(value) 
+                + 1);
+if (!result) {
+       perror("malloc");
+       exit(1);
+}
+
+#line 2304 "ifupdown.nw"
+       sprintf(result, format, name, value);
+
+       
+#line 2333 "ifupdown.nw"
+{
+       char *here, *there;
+
+       for(here = there = result; *there != '=' && *there; there++) {
+               if (*there == '-') *there = '_';
+               if (isalpha(*there)) *there = toupper(*there);
+
+               if (isalnum(*there) || *there == '_') {
+                       *here = *there;
+                       here++;
+               }
+       }
+       memmove(here, there, strlen(there) + 1);
+}
+
+#line 2308 "ifupdown.nw"
+       return result;
+}
+#line 2362 "ifupdown.nw"
+static int doit(char *str) {
+       assert(str);
+
+       if (verbose || no_act) {
+               fprintf(stderr, "%s\n", str);
+       }
+       if (!no_act) {
+               pid_t child;
+               int status;
+
+               fflush(NULL);
+               switch(child = fork()) {
+                   case -1: /* failure */
+                       return 0;
+                   case 0: /* child */
+                       execle("/bin/sh", "/bin/sh", "-c", str, NULL, environ);
+                       exit(127);
+                   default: /* parent */
+                       break;
+               }
+               waitpid(child, &status, 0);
+               if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
+                       return 0;
+       }
+       return 1;
+}
+#line 2408 "ifupdown.nw"
+int execute_all(interface_defn *ifd, execfn *exec, char *opt) {
+       int i;
+       char buf[100];
+       for (i = 0; i < ifd->n_options; i++) {
+               if (strcmp(ifd->option[i].name, opt) == 0) {
+                       if (!(*exec)(ifd->option[i].value)) {
+                               return 0;
+                       }
+               }
+       }
+
+       snprintf(buf, sizeof(buf), "run-parts %s /etc/network/if-%s.d",
+               verbose ? "--verbose" : "", opt);
+
+       (*exec)(buf); 
+
+       return 1;
+}
+#line 2438 "ifupdown.nw"
+int iface_up(interface_defn *iface) {
+       if (!iface->method->up(iface,check)) return -1;
+
+       set_environ(iface, "start", "pre-up");
+       if (!execute_all(iface,doit,"pre-up")) return 0;
+
+       if (!iface->method->up(iface,doit)) return 0;
+
+       set_environ(iface, "start", "post-up");
+       if (!execute_all(iface,doit,"up")) return 0;
+
+       return 1;
+}
+#line 2454 "ifupdown.nw"
+int iface_down(interface_defn *iface) {
+       if (!iface->method->down(iface,check)) return -1;
+
+       set_environ(iface, "stop", "pre-down");
+       if (!execute_all(iface,doit,"down")) return 0;
+
+       if (!iface->method->down(iface,doit)) return 0;
+
+       set_environ(iface, "stop", "post-down");
+       if (!execute_all(iface,doit,"post-down")) return 0;
+
+       return 1;
+}
+#line 2483 "ifupdown.nw"
+int execute(char *command, interface_defn *ifd, execfn *exec) { 
+       char *out;
+       int ret;
+
+       out = parse(command, ifd);
+       if (!out) { return 0; }
+
+       ret = (*exec)(out);
+
+       free(out);
+       return ret;
+}
+#line 2529 "ifupdown.nw"
+static char *parse(char *command, interface_defn *ifd) {
+       
+#line 2554 "ifupdown.nw"
+char *result = NULL;
+size_t pos = 0, len = 0;
+#line 2648 "ifupdown.nw"
+size_t old_pos[MAX_OPT_DEPTH] = {0};
+int okay[MAX_OPT_DEPTH] = {1};
+int opt_depth = 1;
+
+#line 2532 "ifupdown.nw"
+       while(*command) {
+               switch(*command) {
+                       
+#line 2602 "ifupdown.nw"
+default:
+       addstr(&result, &len, &pos, command, 1);
+       command++;
+       break;
+#line 2615 "ifupdown.nw"
+case '\\':
+       if (command[1]) {
+               addstr(&result, &len, &pos, command+1, 1);
+               command += 2;
+       } else {
+               addstr(&result, &len, &pos, command, 1);
+               command++;
+       }
+       break;
+#line 2663 "ifupdown.nw"
+case '[':
+       if (command[1] == '[' && opt_depth < MAX_OPT_DEPTH) {
+               old_pos[opt_depth] = pos;
+               okay[opt_depth] = 1;
+               opt_depth++;
+               command += 2;
+       } else {
+               addstr(&result, &len, &pos, "[", 1);
+               command++;
+       }
+       break;
+#line 2677 "ifupdown.nw"
+case ']':
+       if (command[1] == ']' && opt_depth > 1) {
+               opt_depth--;
+               if (!okay[opt_depth]) {
+                       pos = old_pos[opt_depth];
+                       result[pos] = '\0';
+               }
+               command += 2;
+       } else {
+               addstr(&result, &len, &pos, "]", 1);
+               command++;
+       }
+       break;
+#line 2732 "ifupdown.nw"
+case '%':
+{
+       
+#line 2757 "ifupdown.nw"
+char *nextpercent;
+#line 2735 "ifupdown.nw"
+       char *varvalue;
+
+       
+#line 2761 "ifupdown.nw"
+command++;
+nextpercent = strchr(command, '%');
+if (!nextpercent) {
+       errno = EUNBALPER;
+       free(result);
+       return NULL;
+}
+
+#line 2739 "ifupdown.nw"
+       
+#line 2820 "ifupdown.nw"
+varvalue = get_var(command, nextpercent - command, ifd);
+
+#line 2741 "ifupdown.nw"
+       if (varvalue) {
+               addstr(&result, &len, &pos, varvalue, strlen(varvalue));
+       } else {
+               okay[opt_depth - 1] = 0;
+       }
+
+       
+#line 2771 "ifupdown.nw"
+command = nextpercent + 1;
+
+#line 2749 "ifupdown.nw"
+       break;
+}
+#line 2535 "ifupdown.nw"
+               }
+       }
+
+       
+#line 2707 "ifupdown.nw"
+if (opt_depth > 1) {
+       errno = EUNBALBRACK;
+       free(result);
+       return NULL;
+}
+
+if (!okay[0]) {
+       errno = EUNDEFVAR;
+       free(result);
+       return NULL;
+}
+
+#line 2540 "ifupdown.nw"
+       
+#line 2561 "ifupdown.nw"
+return result;
+#line 2541 "ifupdown.nw"
+}
+#line 2576 "ifupdown.nw"
+void addstr(char **buf, size_t *len, size_t *pos, char *str, size_t strlen) {
+       assert(*len >= *pos);
+       assert(*len == 0 || (*buf)[*pos] == '\0');
+
+       if (*pos + strlen >= *len) {
+               char *newbuf;
+               newbuf = realloc(*buf, *len * 2 + strlen + 1);
+               if (!newbuf) {
+                       perror("realloc");
+                       exit(1); /* a little ugly */
+               }
+               *buf = newbuf;
+               *len = *len * 2 + strlen + 1;
+       }
+
+       while (strlen-- >= 1) {
+               (*buf)[(*pos)++] = *str;
+               str++;
+       }
+       (*buf)[*pos] = '\0';
+}
+#line 2783 "ifupdown.nw"
+int strncmpz(char *l, char *r, size_t llen) {
+       int i = strncmp(l, r, llen);
+       if (i == 0)
+               return -r[llen];
+       else
+               return i;
+}
+#line 2800 "ifupdown.nw"
+char *get_var(char *id, size_t idlen, interface_defn *ifd) {
+       int i;
+
+       if (strncmpz(id, "iface", idlen) == 0) {
+               return ifd->real_iface;
+       } else {
+               for (i = 0; i < ifd->n_options; i++) {
+                       if (strncmpz(id, ifd->option[i].name, idlen) == 0) {
+                               return ifd->option[i].value;
+                       }
+               }
+       }
+
+       return NULL;
+}
+#line 2839 "ifupdown.nw"
+int run_mapping(char *physical, char *logical, int len, mapping_defn *map) {
+       FILE *in, *out;
+       int i, status;
+       pid_t pid;
+
+       
+#line 2898 "ifupdown.nw"
+pid = popen2(&in, &out, map->script, physical, NULL);
+if (pid == 0) {
+       return 0;
+}
+#line 2845 "ifupdown.nw"
+       
+#line 2857 "ifupdown.nw"
+for (i = 0; i < map->n_mappings; i++) {
+       fprintf(in, "%s\n", map->mapping[i]);
+}
+fclose(in);
+#line 2846 "ifupdown.nw"
+       
+#line 2864 "ifupdown.nw"
+waitpid(pid, &status, 0);
+#line 2847 "ifupdown.nw"
+       
+#line 2868 "ifupdown.nw"
+if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
+       if (fgets(logical, len, out)) {
+               char *pch = logical + strlen(logical) - 1;
+               while (pch >= logical && isspace(*pch)) 
+                       *(pch--) = '\0';
+       }
+}
+fclose(out);   
+
+#line 2849 "ifupdown.nw"
+       return 1;
+}
+#line 2912 "ifupdown.nw"
+static int popen2(FILE **in, FILE **out, char *command, ...) {
+       va_list ap;
+       char *argv[11] = {command};
+       int argc;
+       int infd[2], outfd[2];
+       pid_t pid;
+
+       argc = 1;
+       va_start(ap, command);
+       while((argc < 10) && (argv[argc] = va_arg(ap, char*))) {
+               argc++;
+       }
+       argv[argc] = NULL; /* make sure */
+       va_end(ap);
+
+       if (pipe(infd) != 0) return 0;
+       if (pipe(outfd) != 0) {
+               close(infd[0]); close(infd[1]);
+               return 0;
+       }
+
+       fflush(NULL);
+       switch(pid = fork()) {
+               case -1: /* failure */
+                       close(infd[0]); close(infd[1]);
+                       close(outfd[0]); close(outfd[1]);
+                       return 0;
+               case 0: /* child */
+                       dup2(infd[0], 0);
+                       dup2(outfd[1], 1);
+                       close(infd[0]); close(infd[1]);
+                       close(outfd[0]); close(outfd[1]);
+                       execvp(command, argv);
+                       exit(127);
+               default: /* parent */
+                       *in = fdopen(infd[1], "w");
+                       *out = fdopen(outfd[0], "r");
+                       close(infd[0]); close(outfd[1]);
+                       return pid;
+       }
+       /* unreached */
+}
diff --git a/execution.dia b/execution.dia
new file mode 100644 (file)
index 0000000..70cd9c3
Binary files /dev/null and b/execution.dia differ
diff --git a/header.h b/header.h
new file mode 100644 (file)
index 0000000..ee5f3a6
--- /dev/null
+++ b/header.h
@@ -0,0 +1,111 @@
+#line 91 "ifupdown.nw"
+#ifndef HEADER_H
+#define HEADER_H
+
+#line 392 "ifupdown.nw"
+typedef struct address_family address_family;
+#line 425 "ifupdown.nw"
+typedef struct method method;
+#line 1069 "ifupdown.nw"
+typedef struct interfaces_file interfaces_file;
+#line 1085 "ifupdown.nw"
+typedef struct allowup_defn allowup_defn;
+#line 1104 "ifupdown.nw"
+typedef struct interface_defn interface_defn;
+#line 1129 "ifupdown.nw"
+typedef struct variable variable;
+#line 1145 "ifupdown.nw"
+typedef struct mapping_defn mapping_defn;
+#line 441 "ifupdown.nw"
+typedef int (execfn)(char *command);
+typedef int (command_set)(interface_defn *ifd, execfn *e);
+#line 396 "ifupdown.nw"
+struct address_family {
+       char *name;
+       int n_methods;
+       method *method;
+};
+#line 429 "ifupdown.nw"
+struct method {
+       char *name;
+       command_set *up, *down;
+};
+#line 1073 "ifupdown.nw"
+struct interfaces_file {
+       allowup_defn *allowups;
+       interface_defn *ifaces;
+       mapping_defn *mappings;
+};
+#line 1089 "ifupdown.nw"
+struct allowup_defn {
+       allowup_defn *next;
+
+       char *when;
+       int max_interfaces;
+       int n_interfaces;
+       char **interfaces;
+};
+#line 1108 "ifupdown.nw"
+struct interface_defn {
+       interface_defn *next;
+
+       char *logical_iface;
+       char *real_iface;
+
+       address_family *address_family;
+       method *method;
+
+       int automatic;
+
+       int max_options;
+       int n_options;
+       variable *option;
+};
+#line 1133 "ifupdown.nw"
+struct variable {
+       char *name;
+       char *value;
+};
+#line 1149 "ifupdown.nw"
+struct mapping_defn {
+       mapping_defn *next;
+
+       int max_matches;
+       int n_matches;
+       char **match;
+
+       char *script;
+
+       int max_mappings;
+       int n_mappings;
+       char **mapping;
+};
+#line 2644 "ifupdown.nw"
+#define MAX_OPT_DEPTH 10
+#line 2702 "ifupdown.nw"
+#define EUNBALBRACK 10001
+#define EUNDEFVAR   10002
+#line 2727 "ifupdown.nw"
+#define MAX_VARNAME    32
+#define EUNBALPER   10000
+#line 408 "ifupdown.nw"
+extern address_family *addr_fams[];
+#line 1170 "ifupdown.nw"
+interfaces_file *read_interfaces(char *filename);
+#line 1943 "ifupdown.nw"
+allowup_defn *find_allowup(interfaces_file *defn, char *name);
+#line 2396 "ifupdown.nw"
+int execute_all(interface_defn *ifd, execfn *exec, char *opt);
+#line 2433 "ifupdown.nw"
+int iface_up(interface_defn *iface);
+int iface_down(interface_defn *iface);
+#line 2476 "ifupdown.nw"
+int execute(char *command, interface_defn *ifd, execfn *exec);
+#line 2835 "ifupdown.nw"
+int run_mapping(char *physical, char *logical, int len, mapping_defn *map);
+#line 3161 "ifupdown.nw"
+extern int no_act;
+extern int verbose;
+
+#line 100 "ifupdown.nw"
+#endif /* HEADER_H */
diff --git a/ifup.8 b/ifup.8
new file mode 100644 (file)
index 0000000..4b29edd
--- /dev/null
+++ b/ifup.8
@@ -0,0 +1,165 @@
+.TH ifup 8 "22 May 2004" IFUPDOWN ""
+.SH NAME
+ifup \- bring a network interface up
+.PP
+ifdown \- take a network interface down
+.SH SYNOPSIS
+.B ifup 
+[\fB\-nv\fR]
+[\fB\-\-no\-act\fR]
+[\fB\-\-verbose\fR]
+[\fB\-i\fR \fIFILE\fR|\fB\-\-interfaces=\fR\fIFILE\fR]
+[\fB\-\-allow\fR \fICLASS\fR]
+\fB\-a\fR|\fIIFACE\fR...
+.br
+.B ifup 
+\fB\-h\fR|\fB\-\-help\fR
+.br
+.B ifup 
+\fB\-V\fR|\fB\-\-version\fR
+.PP
+.B ifdown
+[\fB\-nv\fR]
+[\fB\-\-no\-act\fR]
+[\fB\-\-verbose\fR]
+[\fB\-i\fR \fIFILE\fR|\fB\-\-interfaces=\fR\fIFILE\fR]
+[\fB\-\-allow\fR \fICLASS\fR]
+\fB\-a\fR|\fIIFACE\fR...
+.SH DESCRIPTION
+The
+.BR ifup " and " ifdown
+commands may be used to configure (or, respectively, deconfigure) network
+interfaces based on interface definitions in the file
+.IR /etc/network/interfaces .
+.SH OPTIONS
+A summary of options is included below.
+.TP
+.BR \-a ", " \-\-all
+If given to \fBifup\fP, affect all interfaces marked \fBauto\fP.
+Interfaces are brought up in the order in which they are defined
+in /etc/network/interfaces.
+If given to \fBifdown\fP, affect all defined interfaces.
+Interfaces are brought down in the order in which they are
+currently listed in the state file. Only interfaces defined
+in /etc/network/interfaces will be brought down.
+.TP
+.B \-\-force
+Force configuration or deconfiguration of the interface.
+.TP
+.BR \-h ", " \-\-help
+Show summary of options.
+.TP
+\fB\-\-allow=\fR\fICLASS\fR
+Only allow interfaces listed in an
+.I allow\-CLASS
+line in /etc/network/interfaces to be acted upon.
+.TP
+\fB\-i\fR \fIFILE\fR, \fB\-\-interfaces=\fR\fIFILE\fR
+Read interface definitions from 
+.I FILE
+instead of from /etc/network/interfaces.
+.TP
+.BR \-n ", " \-\-no\-act
+Don't configure any interfaces or run any "up" or "down" commands.
+.TP
+.B \-\-no\-mappings
+Don't run any mappings.  See
+.BR interfaces (5)
+for more information about the mapping feature.
+.TP
+.BR \-V ", " \-\-version
+Show copyright and version information.
+.TP
+.BR \-v ", " \-\-verbose
+Show commands as they are executed.
+.SH EXAMPLES
+.TP
+.B ifup -a
+Bring up all the interfaces defined with
+.I auto
+in 
+.I /etc/network/interfaces
+.TP
+.B ifup eth0
+Bring up interface
+.B eth0
+.TP
+.B ifup eth0=home
+Bring up interface
+.B eth0
+as logical interface
+.B home
+.TP
+.B ifdown -a
+Bring down all interfaces that are currently up.
+.SH NOTES
+.BR ifup " and " ifdown
+are actually the same program called by different names.
+.P
+The program does not configure network interfaces directly;
+it runs low level utilities such as
+.BR ifconfig " and " route
+to do its dirty work.
+.SH FILES
+.TP
+.I /etc/network/interfaces
+definitions of network interfaces
+See
+.BR interfaces (5)
+for more information.
+.TP
+.I /etc/network/run/ifstate
+current state of network interfaces
+.SH KNOWN BUGS/LIMITATIONS
+The program keeps records of whether network interfaces are up or down.
+Under exceptional circumstances these records can become
+inconsistent with the real states of the interfaces.
+For example, an interface that was brought up using
+.B ifup
+and later deconfigured using
+.B ifconfig
+will still be recorded as up.
+To fix this you can use the
+.B \-\-force
+option to force
+.B ifup
+or
+.B ifdown
+to run configuration or deconfiguration commands despite what
+it considers the current state of the interface to be.
+.P
+The file
+.I /etc/network/run/ifstate
+must be writable for
+.B ifup
+or
+.B ifdown
+to work properly.
+If that location is not writable
+(for example, because the root filesystem is mounted read-only
+for system recovery)
+then
+.I /etc/network/run/ifstate
+should be made a symbolic link to a writable location.
+If that is not possible then you can use the
+.B \-\-force
+option to run configuration or deconfiguration commands
+without updating the file.
+.P
+Note that the program does not run automatically:
+.B ifup
+alone does not bring up interfaces
+that appear as a result of hardware being installed and 
+.B ifdown
+alone does not bring down interfaces
+that disappear as a result of hardware being removed.
+To automate the configuration of network interfaces you need to
+install other packages such as
+.BR hotplug (8)
+or
+.BR ifplugd (8).
+.SH AUTHOR
+The ifupdown suite was written by Anthony Towns <aj@azure.humbug.org.au>.
+.SH SEE ALSO
+.BR interfaces (5),
+.BR ifconfig (8).
diff --git a/ifupdown.nw b/ifupdown.nw
new file mode 100644 (file)
index 0000000..e0f774e
--- /dev/null
@@ -0,0 +1,4121 @@
+%
+\documentclass{article}
+\usepackage{graphicx}
+\usepackage{noweb}
+\pagestyle{noweb}
+\noweboptions{smallcode,hideunuseddefs}
+\begin{document}
+@
+
+\def\nwendcode{\endtrivlist\endgroup}
+\let\nwdocspar=\relax
+
+\title{ Interface Tools\thanks{
+Copyright \copyright\ 1999--2005 Anthony Towns. 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; either version 2 of the License, or (at your option) any
+later version.  
+}}
+
+\author{ Anthony Towns \\ { \tt aj@azure.humbug.org.au } }
+
+\pagenumbering{roman}
+
+\maketitle
+\tableofcontents
+
+\vfill
+\pagebreak
+\pagenumbering{arabic}
+
+\section{Introduction}
+
+This source defines the commands [[ifup]] and [[ifdown]], used to
+manipulate interfaces in an easily controllable manner.
+
+\subsection{Assumed Knowledge}
+
+The reader is assumed to have knowledge of the C \cite{K&R} and Perl
+\cite{camel} programming languages in a Unix environment \cite{StevensUnix}.
+A cursory understanding of network administration on the appropriate
+platform is also assumed, along with access to the relevant manual
+pages as necessary.
+
+This source has been written as a literate program using the [[noweb]]
+\cite{wwwnoweb} tool suite, and typeset using \LaTeX\ \cite{latex}.
+
+\subsection{Program Structure}
+
+We shall decompose this program into four main areas of functionality:
+compile-time configuration, run-time configuration, execution, and the
+overall driver.
+
+Compile-time configuration will deal with differing available address
+families (IP vs IPX vs IPv6, and so on), and the differing methods of
+enabling and disabling interfaces configured for each family. This will
+be implemented using the [[addrfam]] module, and various [[.defn]] files,
+for the address family definitions.
+
+Run-time configuration will deal with determining the local setup
+based on the file [[/etc/network/interfaces]], and producing a data
+structure encapsulating these details. This will be implemented in the
+[[config]] module.
+
+Execution will deal with issues relating to working out exactly which
+commands to run based on a somewhat abstract description from the
+compile-time configuration and the details determined at
+run-time. This will be dealt with in the [[execute]] module.
+
+The remaining work --- argument parsing, error reporting, and,
+essentially, putting all the pieces together --- is done by the
+[[main]] module.
+
+The following diagram gives a brief idea of the information and control
+flow amongst the modules.
+
+\begin{center}
+\includegraphics[height=45mm]{modules}
+\end{center}
+
+Much of the information sharing will be done by defining and filling
+in some data structures and allowing the other modules to just access
+that information directly. Rather than hiding the information itself,
+most of our modules simply attempt to hide how that information was
+originally written. Because of this, we shall find that these modules are
+too closely linked to be completely separated in a convenient manner,
+so they will all make use of a single header file for each other's
+structure definitions, exported interfaces and so on.
+
+<<header.h>>=
+#ifndef HEADER_H
+#define HEADER_H
+
+<<type definitions>>
+<<function type definitions>>
+<<structure definitions>>
+<<constant definitions>>
+<<exported symbols>>
+
+#endif /* HEADER_H */
+@ 
+
+\section{The Build System}
+
+We shall begin with the template for the Makefile we shall use.
+
+<<Makefile>>=
+<<make options>>
+
+CFILES := addrfam.c execute.c config.c main.c archlinux.c
+HFILES := header.h archlinux.h
+PERLFILES := defn2c.pl defn2man.pl
+DEFNFILES := inet.defn ipx.defn inet6.defn
+
+OBJ := main.o addrfam.o execute.o config.o \
+       $(patsubst %.defn,%.o,$(DEFNFILES)) archlinux.o
+
+MAN := $(patsubst %.defn,%.man,$(DEFNFILES))
+
+default : executables
+all : executables docs
+
+executables : ifup ifdown ifup.8 ifdown.8 interfaces.5
+docs : ifupdown.ps.gz ifup.8.ps.gz interfaces.5.ps.gz ifupdown.pdf
+
+.PHONY : executables 
+<<phony targets>>
+<<executable targets>>
+<<manpage targets>>
+<<extra dependencies>>
+<<implicit rules>>
+
+<<generated dependency inclusion>>
+@ 
+
+We shall build exactly two executables, [[ifup]] and [[ifdown]], which
+will in truth simply be two names for a single binary, albeit with
+different functionality.
+
+<<executable targets>>=
+ifup: $(OBJ)
+       $(CC) $(CFLAGS) $^ $(LDFLAGS) $(OUTPUT_OPTION)
+
+ifdown: ifup
+       ln -sf ifup ifdown
+@ 
+
+Both of these executables have a manpage. Since they're actually the
+same executable, what could be more appropriate than them having the
+same manpage too?
+
+<<manpage targets>>=
+interfaces.5: interfaces.5.pre $(MAN)
+       sed $(foreach man,$(MAN),-e '/^##ADDRESSFAM##$$/r $(man)') \
+            -e '/^##ADDRESSFAM##$$/d' < $< > $@        
+
+ifdown.8: ifup.8
+       ln -sf $< $@
+
+%.5.ps: %.5
+       groff -mandoc -Tps $< > $@
+%.8.ps: %.8
+       groff -mandoc -Tps $< > $@
+@ 
+
+Further, for convenience, we'll make use of two phony targets, [[clean]],
+[[clobber]] and [[distclean]], which will delete working files, everything
+that can be rebuilt with a [[make]] command, and everything that can be
+rebuilt at all, respectively.
+
+<<phony targets>>=
+.PHONY : clean clobber
+
+install :
+       install -m 0755 -d     ${BASEDIR}/sbin
+       install -m 0755 ifup   ${BASEDIR}/sbin
+       ln ${BASEDIR}/sbin/ifup ${BASEDIR}/sbin/ifdown  
+
+clean :
+       rm -f *.aux *.toc *.log *.bbl *.blg *.ps *.eps *.pdf
+       rm -f *.o *.d $(patsubst %.defn,%.c,$(DEFNFILES)) *~
+       rm -f $(patsubst %.defn,%.man,$(DEFNFILES))
+       rm -f ifup ifdown interfaces.5 ifdown.8
+       rm -f ifupdown.dvi *.ps{,.gz}
+
+clobber : clean
+       rm -f ifupdown.tex $(PERLFILES) $(CFILES) $(HFILES) $(DEFNFILES)
+
+distclean : clobber
+       rm -f makecdep.sh makenwdep.sh Makefile
+@ 
+
+We have some fairly standard rules to build the printed version of the
+source code using \LaTeX\ that are, unfortunately, not included in
+[[make(1)]]'s builtin rules, so we'll note them here.
+
+<<implicit rules>>=
+%.tex : %.nw
+       noweave -delay -index -latex $< >$@
+
+%.bbl : %.tex biblio.bib
+       latex $<
+       bibtex $(basename $<)
+
+%.dvi : %.tex %.bbl
+       latex $<
+       latex $<
+
+%.pdf : %.tex %.bbl
+       pdflatex $<
+       pdflatex $<
+
+%.ps : %.dvi
+       dvips -o $@ $<
+
+%.gz : %
+       gzip --best --stdout $< >$@
+@ 
+
+Additionally, some of [[make]]'s builtin rules are fairly
+conservative, so we'll encourage it to use a more entertaining method
+of compiling source code.
+
+<<make options>>=
+CFLAGS := -Wall -W -g -O2 -D'IFUPDOWN_VERSION="0.6.5"'
+CC := gcc
+@ 
+
+\subsection{Graphics}
+
+We include a few graphics (made using dia) in this document. We have to
+express these fairly explicitly, unfortunately.
+
+<<implicit rules>>=
+%.eps : %.dia
+       dia --nosplash -e $@ $<
+
+%.pdf : %.eps
+       gs -q -sDEVICE=pdfwrite -dNOPAUSE -sOutputFile=$@ - < $<
+@
+
+<<extra dependencies>>=
+ifupdown.dvi: modules.eps execution.eps
+ifupdown.ps: modules.eps execution.eps
+ifupdown.pdf: modules.pdf execution.pdf
+@
+
+\subsection{Automatic Dependencies}
+
+To build the system, we'll make use of some techniques discussed in
+\cite{recursivemake} for determining dependencies. Namely, a number
+of files will have an associated [[.d]] file containing dynamically
+determined dependency information. The first such file we will construct
+is the dependency information for [[noweb]] source files, which can be
+identified by the [[.nw]] extension.
+
+<<implicit rules>>=
+%.d: %.nw makenwdep.sh
+       ./makenwdep.sh $< > $@
+@
+
+To construct the dependency information, we may use the [[noroots(1)]]
+command to determine the \emph{root chunks} in the [[noweb]] source
+(stripping the unwanted [[<<]] and [[>>]] markers as we go, and
+denoting that in such a way that [[noweb]] doesn't mistakenly think
+the [[sed]] command is a chunk reference itself), and then noting down
+appropriate commands to construct the target.
+
+<<makenwdep.sh>>=
+<<parse makenwdep arguments>>
+
+noroots $FILE | sed 's/^<''<\(.*\)>>$/\1/' |
+       while read chunk; do
+               <<output dependency info for [[$chunk]]>>
+       done
+@ 
+
+Our dependency information is straightforward. To construct a file from
+[[noweb]] source, we simply need to run [[notangle(1)]] over it. We add
+a couple of extra tweaks in order to only update files that were actually
+changed (the [[cpif(1)]] call), and to handle tabs properly.
+
+We also need some extra things to take care of particular types of files.
+In particular its important to have our scripts marked executable, so we
+can use them as part of the build process itself, and it's also important
+to have the dependency information for our C files (which are dealt with
+next) included at some point.
+
+<<output dependency info for [[$chunk]]>>=
+printf "%s : %s\n" "$chunk" "$FILE"
+case $chunk in
+       *.pl|*.sh)
+               printf "\tnotangle -R\$@ \$< >\$@\n"
+               printf "\tchmod 755 %s\n" "$chunk"
+               ;;
+       *.c)
+               printf "\tnotangle -L -R\$@ \$< | cpif \$@\n"
+               printf "include ${chunk%.c}.d\n"
+               ;;
+       *.h)
+               printf "\tnotangle -L -R\$@ \$< | cpif \$@\n"
+               ;;
+       *)
+               printf "\tnotangle -t8 -R\$@ $< >\$@\n"
+               ;;
+esac
+@ 
+
+Finally, our fairly primitive argument parsing is simply:
+
+<<parse makenwdep arguments>>=
+FILE=$1
+
+if [ "$FILE" = "" -o ! -f "$FILE" ]; then
+       echo "Please specify a .nw file"
+       exit 1
+fi
+@ 
+
+We have a related system for object files generated from C source
+code. Since each object file depends not only on its source, but also
+the headers included in that source, we generate a [[.d]] file indicating
+exactly which headers need to be checked.
+
+<<implicit rules>>=
+%.d: %.c makecdep.sh
+       ./makecdep.sh $< > $@
+@ 
+
+We can do this using [[gcc(1)]]'s convenient [[-MM -MG]] options,
+which do exactly this, with the added proviso that the [[.d]] file
+itself can possibly depend on any of the header files being modified
+(and, in particular, [[#include]] lines being added or deleted).
+
+<<makecdep.sh>>=
+#!/bin/sh
+<<parse makecdep arguments>>
+
+gcc -MM -MG $FILE |
+  sed -e 's@^\(.*\)\.o:@\1.o \1.d:@'
+@ 
+
+\emph{Deja vu}, anyone?
+
+<<parse makecdep arguments>>= 
+FILE=$1
+if [ "$FILE" = "" -o ! -f "$FILE" ]; then
+       echo "Please specify a .c file"
+       exit 1
+fi
+@
+
+To include the generated dependencies in [[Makefile]], we have to
+be a bit careful.  The problem here is that they should not be rebuild
+when merely the cleaning of the source tree is asked for.  Any targets
+ending in [[clean]], plus the [[clobber]] target prevent the inclusion
+of the generated dependencies.
+
+Unfortunately, [[make]] doesn't allow logical combinations within
+[[ifeq]] and friends, so we have to simulate this.
+
+<<generated dependency inclusion>>=
+include-deps := YES
+ifneq "" "$(filter %clean,$(MAKECMDGOALS))"
+include-deps := NO
+endif
+ifeq "clobber" "$(MAKECMDGOALS)"
+include-deps := NO
+endif
+@
+
+Finally, include the dependency information:
+
+<<generated dependency inclusion>>=
+ifeq "$(strip $(include-deps))" "YES"
+include ifupdown.d
+endif
+@
+
+\section{Compile Time Configuration}
+
+At compile time we need to determine all the possible address families
+that may be used, and all the methods of setting up interfaces for
+those address families, along with the various possible options
+affecting each method.
+
+Our key definition at this point is that of the [[address_family]]
+structure, which encapsulates all the compile time information about
+each address family.
+
+<<type definitions>>=
+typedef struct address_family address_family;
+@ 
+
+<<structure definitions>>=
+struct address_family {
+       char *name;
+       int n_methods;
+       method *method;
+};
+@ 
+
+Each defined address family will be included in the [[addr_fams]]
+array, which becomes the \emph{raison d'\^etre} of the [[addrfam]]
+module.
+
+<<exported symbols>>=
+extern address_family *addr_fams[];
+@ 
+
+Each address family incorporates a number of methods, which
+encapsulate various ways of configuring an interface for a particular
+address family. There are two definining components of a method: two
+sets of commands to bring an interface up and down, and a number of
+options for the commands.
+
+\emph{NB: I expect this will be extended sooner or later to make the
+options more flexible. Probably introducing some form of typing (for
+example to convert netmasks from CIDR specs to dotted-quads, ie
+/24~$\rightarrow$~255.255.255.0), and some form of matching to allow
+multiple options to be deduced from a single configuration
+statement. --- aj}
+
+<<type definitions>>=
+typedef struct method method;
+@ 
+
+<<structure definitions>>=
+struct method {
+       char *name;
+       command_set *up, *down;
+};
+@ 
+
+Each command set is implemented as a single function, accepting two
+parameters: the definitions of the interface the commands should deal
+with, and the function that should be used to execute them. See the
+[[execute]] module for more details.
+
+<<function type definitions>>=
+typedef int (execfn)(char *command);
+typedef int (command_set)(interface_defn *ifd, execfn *e);
+@ 
+
+As our compile-time configuration is done at, well, compile-time, there
+is little need for functions in the actual module, and we can make do with
+a single exported array.
+
+<<addrfam.c>>=
+#include <stdlib.h>
+#include "header.h"
+
+<<address family declarations>>
+
+address_family *addr_fams[] = {
+       <<address family references>>
+       NULL
+};
+@ 
+
+\subsection{Generating C Code}
+
+Unfortunately, while the [[.defn]] representation is reasonably
+convenient for human use, it's less convenient for a compiler. As
+such, at build time, we will build a single structure of type
+[[address_family]] in a separate module, and reference that from
+[[addrfam.c]].
+
+Naturally, we'll use a [[perl]] script to convert [[.defn]] files to C
+code.
+
+<<implicit rules>>=
+%.c : %.defn defn2c.pl
+       ./defn2c.pl $< > $@
+@ 
+
+The functionality of our program is pretty basic: read from the file
+specified as the argument, output to [[stdout]]; and correspondingly
+the structure of the program is similarly simple. We make use of a
+couple of global variables, a few helpful subroutines, and then build
+our C program.
+
+<<defn2c.pl>>=
+#!/usr/bin/perl -w
+
+use strict;
+
+# declarations
+<<defn2c variables>>
+
+# subroutines
+<<defn2c subroutines>>
+
+# main code
+<<output headers for address family>>
+<<parse [[.defn]] file and output intermediate structures>>
+<<output address family data structure>>
+@ 
+
+Clearly we need to reference some of the data structures we defined
+above, so we can begin with the rather trivial:
+
+<<output headers for address family>>=
+print "#include \"header.h\"\n\n\n";
+@ 
+
+The overall purpose of the C code we're trying to construct is to
+define a structure of type [[address_family]], and have it externally
+visible. So we'd like to declare a statically-initialized structure of
+this type, and be done with it.
+
+To do this, however, we need to have some way of uniquely identifying
+the structure to avoid naming conflicts. We'll do this by assuming we
+have a previously initialized variable, [[$address_family]], and that
+names of the form [[addr_foo]] won't be used elsewhere.
+
+<<defn2c variables>>=
+my $address_family = "";
+@
+
+We also need to reference an array of pointers to this address
+family's [[method]]s, which will have to be initialized separately.
+We'll assume that previous code will create such a structure, and call
+it (imaginatively) [[methods]].
+
+<<output address family data structure>>=
+<<output [[methods]] data structure>>
+
+print <<EOF;
+address_family addr_${address_family} = {
+       "$address_family",
+       sizeof(methods)/sizeof(struct method),
+       methods
+};
+EOF
+@ 
+
+Our [[methods]] array will be a little more complicated to
+construct. The first difficulty is that it will actually require some
+state from having read the [[.defn]] file. To handle this, we'll
+introduce a hash [[%methods]] that has the value [[1]] for each method
+from the [[.defn]] file. We use a hash instead of a list because it
+makes some error checking more convenient later, and since order
+doesn't particularly matter.
+
+<<defn2c variables>>=
+my %methods = ();
+@
+
+We'll use standard names, such as [[foo_up]], [[foo_down]], and
+[[foo_options]] for the various elements of each method which cannot
+be defined inline. The two functions and the array will be declared
+static to avoid name conflicts.
+
+<<output [[methods]] data structure>>=
+print "static method methods[] = {\n";
+my $method;
+foreach $method (keys %methods) {
+       print <<EOF;
+       {
+               "$method",
+               ${method}_up, ${method}_down,
+       },
+EOF
+}
+print "};\n\n";
+@ 
+
+In a reasonably obvious manner we can then proceed to process the
+[[.defn]] file to initialize the aforementioned variables, and to
+output the method-specific functions and array. We'll begin by
+defining a variable to keep track of the current line.
+
+<<defn2c variables>>=
+my $line = "";
+@ 
+
+Our semantics for this variable will be basically that it contains a
+valid, meaningful input line. It won't be blank, or contain comments,
+and if there aren't any more lines to be read, it will evaluate to
+[[false]]. In order to keep these semantics, we'll use the subroutine
+[[nextline]] to update it. (Since we'll later find we'll want to reuse
+this subroutine, we'll keep it in a chunk of its own)
+
+<<defn2c subroutines>>=
+<<[[nextline]] subroutine>>
+@ 
+
+<<[[nextline]] subroutine>>=
+sub nextline {
+       $line = <>;
+       while($line and ($line =~ /^#/ or $line =~ /^\s*$/)) {
+               $line = <>;
+       }
+       if (!$line) { return 0; }
+       chomp $line;
+       while ($line =~ m/^(.*)\\$/) {
+               my $addon = <>;
+               chomp $addon;
+               $line = $1 . $addon;
+       }
+       return 1;
+}
+@ 
+
+Our high-level logic then looks basically like:
+
+<<parse [[.defn]] file and output intermediate structures>>=
+nextline;
+while($line) {
+       <<parse a top-level section and output intermediate structures>>
+
+       # ...otherwise
+       die("Unknown command \"$line\"");
+}
+@
+
+To make all this stuff easier, we'll use a `matching' function to help
+with parsing lines: basically, given a line, a command, and possibly
+an indentation prefix (eg [["    "]]). (As with [[nextline]], this will
+also be useful to reuse, hence it has its own pair of chunks, too)
+
+<<defn2c variables>>=
+my $match = "";
+@ 
+
+<<defn2c subroutines>>=
+<<[[match]] subroutine>>
+@ 
+
+<<[[match]] subroutine>>=
+sub match {
+       my $line = $_[0];
+       my $cmd = "$_[1]" ? "$_[1]\\b\\s*" : "";;
+       my $indentexp = (@_ == 3) ? "$_[2]\\s+" : "";
+
+       if ($line =~ /^${indentexp}${cmd}(([^\s](.*[^\s])?)?)\s*$/) {
+               $match = $1;
+               return 1;
+       } else {
+               return 0;
+       } 
+}
+@ 
+
+Okay. So, the first line we expect to see is the name of the address
+family we're defining.
+
+<<parse a top-level section and output intermediate structures>>=
+if (match($line, "address_family")) {
+       get_address_family $match;
+       next;
+}
+@ 
+
+This is, as you'd imagine, pretty simple to deal with. We just need to
+store the address family's name, and move on to the next line.
+
+<<defn2c subroutines>>=
+sub get_address_family {
+       $address_family = $_[0] if ($address_family eq "");
+       nextline;
+}
+@ 
+
+Which brings us to determining the architecture.
+
+<<parse a top-level section and output intermediate structures>>=
+if (match($line, "architecture")) {
+       get_architecture $match;
+       next;
+}
+@ 
+
+You'd never guess what, but it's just as easy as the address family thing
+was.
+
+<<defn2c subroutines>>=
+sub get_architecture {
+       my $arch = $_[0];
+       die("architecture declaration appears too late") if (keys %methods);
+       print "#include \"arch${arch}.h\"\n\n\n";
+       nextline;
+}
+@ 
+
+Which leaves us with the hard bit, actually creating the functions and
+array for each method.
+
+<<parse a top-level section and output intermediate structures>>=
+if (match($line, "method")) {
+       get_method $match;
+       next;
+}
+@
+
+The basic premise is to check for each of our options in a given
+order: if they don't match, then we can presume they don't exist ---
+any errors will be reported when the main function finds something
+weird going on. All we really have to take care of so far is ensuring
+an appropriate level of indentation, and that we're not defining the
+same method twice.
+
+<<defn2c subroutines>>=
+sub get_method {
+       my $method = $_[0];
+       my $indent = ($line =~ /(\s*)[^\s]/) ? $1 : "";
+
+       die "Duplicate method $method\n" if ($methods{$method}++);
+
+       nextline;
+       <<output code for description>>
+       <<output code for options list>>
+       <<output code for up commands>>
+       <<output code for down commands>>
+}
+@ 
+
+The description and options sections are just documentation chunks,
+and hence aren't at all relevant for the C code.
+
+<<output code for description>>=
+if (match($line, "description", $indent)) {
+       skip_section();
+}
+@ 
+
+<<output code for options list>>=
+if (match($line, "options", $indent)) {
+       skip_section();
+}
+@ 
+
+Skipping a section is fairly easy: we just need to check alignments. This is
+yet another subroutine that'll come in handy elsewhere.
+
+<<defn2c subroutines>>=
+<<[[skip_section]] subroutine>>
+@ 
+
+<<[[skip_section]] subroutine>>=
+sub skip_section {
+       my $struct = $_[0];
+       my $indent = ($line =~ /(\s*)[^\s]/) ? $1 : "";
+
+       1 while (nextline && match($line, "", $indent));
+}
+@ 
+
+Checking the various relevant components of each method is fairly
+simple: we need to see if it exists, and if it does, parse and output
+it, while if it doesn't, we need to output a place holder.
+
+<<output code for up commands>>=
+if (match($line, "up", $indent)) {
+       get_commands(${method}, "up");
+} else {
+       print "static int ${method}_up(interface_defn ifd) { return 0; }\n"
+}
+@ 
+
+<<output code for down commands>>=
+if (match($line, "down", $indent)) {
+       get_commands(${method}, "down");
+} else {
+       print "static int ${method}_down(interface_defn ifd) { return 0; }\n"
+}
+@
+
+<<defn2c subroutines>>=
+sub get_commands {
+       my $method = $_[0];
+       my $mode = $_[1];
+       my $function = "${method}_${mode}";
+       my $indent = ($line =~ /(\s*)[^\s]/) ? $1 : "";
+
+       print "static int ${function}(interface_defn *ifd, execfn *exec) {\n";
+
+       while (nextline && match($line, "", $indent)) {
+               if ( $match =~ /^(.*[^\s])\s+if\s*\((.*)\)\s*$/ ) {
+                       print "if ( $2 ) {\n";
+                       print "  if (!execute(\"$1\", ifd, exec)) return 0;\n";
+                       print "}\n";
+               } elsif ( $match =~ /^(.*[^\s])\s+elsif\s*\((.*)\)\s*$/ ) {
+                       print "else if ( $2 ) {\n";
+                       print "  if (!execute(\"$1\", ifd, exec)) return 0;\n";
+                       print "}\n";
+               } elsif ( $match =~ /^(.*[^\s])\s*$/ ) {
+                       print "{\n";
+                       print "  if (!execute(\"$1\", ifd, exec)) return 0;\n";
+                       print "}\n";
+               }
+       }
+
+       print "return 1;\n";
+       print "}\n";
+}
+@ 
+
+\subsection{Building Manual Pages}
+
+So having C code is all very well, but if you want to ignore all user
+problems with a casual ``RTFM!'' there has to be some semblance of an
+M for them to R. So we need a script to generate some useful
+descriptions of the various methods.
+
+We'll achieve this by making another Perl script, [[defn2man.pl]],
+which will generate fragments of [[troff]] that can be catted together
+with a general overview of [[ifupdown]] to produce real manpages.
+
+<<implicit rules>>=
+%.man: %.defn defn2man.pl
+       ./defn2man.pl $< > $@
+@ 
+
+So we'll use a similar structure to [[defn2c.pl]].
+
+<<defn2man.pl>>=
+#!/usr/bin/perl -w
+
+use strict;
+
+# declarations
+<<defn2man variables>>
+
+# subroutines
+<<defn2man subroutines>>
+
+# main code
+<<parse [[.defn]] file and output manpage fragment>>
+@ 
+
+As predicted, we'll also incorporate [[nextline]], [[match]] and
+[[skip_section]]:
+
+<<defn2man variables>>=
+my $line;
+my $match;
+@ 
+
+<<defn2man subroutines>>=
+<<[[nextline]] subroutine>>
+<<[[match]] subroutine>>
+<<[[skip_section]] subroutine>>
+@ 
+
+Now we'll have a slightly different structure to the program itself
+this time, since we need to do things pretty much in order for
+outputting the manpage. This imposes stricter ordering requirements on
+the [[.defn]] files than [[defn2c]] did.
+
+<<parse [[.defn]] file and output manpage fragment>>=
+nextline;
+if ($line and match($line, "address_family")) {
+       get_address_family $match;
+} else {
+       die "address_family must be listed first\n";
+}
+if ($line and match($line, "architecture")) {
+       get_architecture $match;
+}
+while ($line and match($line, "method")) {
+       get_method $match;
+}
+@ 
+
+Okay, so it wasn't \emph{that} different from what we had before. Sue
+me.
+
+The [[get_address_family]] and [[get_architecture]] subroutines are
+fairly straight forward:
+
+<<defn2man subroutines>>=
+sub get_address_family {
+       print ".SH " . uc($match) . " ADDRESS FAMILY\n";
+       print "This section documents the methods available in the\n";
+       print "$match address family.\n";
+       nextline;
+}
+@ 
+
+<<defn2man subroutines>>=
+sub get_architecture {
+       # no op
+       nextline;
+}
+@ 
+
+Which only leaves extracting the description and options for each
+method. And, of course, this imposes less restrictions of the
+[[.defn]] file than [[defn2c.pl]] did. It's a crazy old world.
+
+<<defn2man subroutines>>=
+sub get_method {
+       my $method = shift;
+       my $indent = ($line =~ /(\s*)\S/) ? $1 : "";
+       my $description = "";
+       my @options = ();
+
+       nextline;
+       while ($line and match($line, "", $indent)) {
+               if (match($line, "description", $indent)) {
+                       $description = get_description();
+               } elsif (match($line, "options", $indent)) {
+                       @options = get_options();
+               } else {
+                       skip_section;
+               }
+       }
+
+       <<output [[$method]] introduction man fragment>>
+       <<output [[$description]] man fragment>>
+       <<output [[@options]] man fragment>>
+}
+@
+
+<<output [[$method]] introduction man fragment>>=
+print ".SS The $method Method\n";
+@ 
+
+Okay. Now our [[$description]] is just the description with any [['\n']]
+characters it may've had, but without the leading spaces.
+
+<<defn2man subroutines>>=
+sub get_description {
+       my $desc = "";
+       my $indent = ($line =~ /(\s*)\S/) ? $1 : "";
+       while(nextline && match($line, "", $indent)) {
+               $desc .= "$match\n";
+       }
+       return $desc;
+}
+@ 
+
+We're actually going to be a little tricky here, and allow some formatting
+in our descriptions. Basically, we'll allow bold and italic encoding
+to be denoted by [[*bold*]] and [[/italics/]] in the wonderful Usenet
+tradition. As such, we'll use a cute little function to convert the
+Usenet style to \emph{roff}. We'll also take care not to do this conversion
+within words (for things like [[/etc/hosts]], eg). Voila:
+
+<<defn2man subroutines>>=
+sub usenet2man {
+       my $in = shift;
+       my $out = "";
+
+       $in =~ s/\s+/ /g;
+       while ($in =~ m%^([^*/]*)([*/])([^*/]*)([*/])(.*)$%s) {
+               my ($pre, $l, $mid, $r, $post) = ($1, $2, $3, $4, $5);
+               if ($l eq $r && " $pre"  =~ m/[[:punct:][:space:]]$/ 
+                            && "$post " =~ m/^[[:punct:][:space:]]/) {
+                       $out .= $pre;
+                       $out .= ($l eq "*" ? '\fB' : '\fI') . $mid . '\fP';
+                       ($in = $post) =~ s/^\s+/ /;
+               } else {
+                       $out .= $pre . $l;
+                       $in = $mid . $r . $post;
+               }
+       } 
+       return $out . $in;
+}
+@
+
+The only further thing to note about this is that we're being careless
+and ignoring the possibility of \emph{roff} escape sequences in the input. But
+since this is for internal use only, well, too bad. So here we go:
+
+<<output [[$description]] man fragment>>=
+if ($description ne "") {
+       print usenet2man($description) . "\n";
+} else {
+       print "(No description)\n";
+}
+@ 
+
+Damn that was fun.
+
+Reading the options is almost exactly the same as the description,
+except we want a list instead of just a string.
+
+<<defn2man subroutines>>=
+sub get_options {
+       my @opts = ();
+       my $indent = ($line =~ /(\s*)\S/) ? $1 : "";
+       while(nextline && match($line, "", $indent)) {
+               push @opts, $match;
+       }
+       return @opts;
+}
+@ 
+
+Output is slightly more complicated, but not too much so.
+
+<<output [[@options]] man fragment>>=
+print ".PP\n";
+print ".B Options\n";
+print ".RS\n";
+if (@options) {
+       foreach my $o (@options) {
+               if ($o =~ m/^\s*(\S*)\s*(.*)\s+--\s+(\S.*)$/) {
+                       my $opt = $1;
+                       my $optargs = $2;
+                       my $dsc = $3;
+                       print ".TP\n";
+                       print ".BI $opt";
+                       print " \" $optargs\"" unless($optargs =~ m/^\s*$/);
+                       print "\n";
+                       print usenet2man($dsc) . "\n";
+               } else {
+                       print ".TP\n";
+                       print ".B $o\n";
+               }
+       }
+} else {
+       print ".TP\n";
+       print "(No options)\n";
+}
+print ".RE\n";
+@ 
+
+\section{Run-time Configuration}
+
+Our module is of the usual form, and we'll make use of a few fairly standard
+headers. Please move along, there's nothing to see here.
+
+<<config.c>>=
+<<config headers>>
+<<config function declarations>>
+<<config functions>>
+@ 
+
+<<config headers>>=
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+@ 
+
+We'll also make use of some of our other modules. This is, after all,
+why we had a single header in the first place.
+
+<<config headers>>=
+#include "header.h"
+@ 
+
+The key function we're interested in defining here is
+[[read_interfaces()]], which will (wait for it) read an interfaces
+file. The intention is to make it really easy to deal with the
+vagaries of [[/etc/network/interfaces]] anywhere else.
+
+So the first question we need to deal with is ``What's a convenient
+form for other functions which deal with interfaces?'' Well, our
+answer to that is basically:
+
+\begin{enumerate}
+       \item an array of interface names that should be brought up at
+       bootup.
+
+       \item a singly linked list to represent the various mappings.
+
+       \item another singly linked list to represent the interface
+       definitions themselves.
+\end{enumerate}
+
+ These are almost in exact correspondence with the original file.
+
+<<type definitions>>=
+typedef struct interfaces_file interfaces_file;
+@ 
+
+<<structure definitions>>=
+struct interfaces_file {
+       allowup_defn *allowups;
+       interface_defn *ifaces;
+       mapping_defn *mappings;
+};
+@
+
+So, at run-time, we first need a way of dealing with the [[auto]] and
+[[allow-*]] lines. We'll treat [[allow-auto]] and [[auto]] as equivalent,
+making that pretty straightforward:
+
+<<type definitions>>=
+typedef struct allowup_defn allowup_defn;
+@
+
+<<structure definitions>>=
+struct allowup_defn {
+       allowup_defn *next;
+
+       char *when;
+       int max_interfaces;
+       int n_interfaces;
+       char **interfaces;
+};
+@ 
+
+We also require a way of representing each interface listed in the
+configuration file. This naturally needs to reference an address family
+and method, and all the options a user may specify about an interface.
+
+<<type definitions>>=
+typedef struct interface_defn interface_defn;
+@ 
+
+<<structure definitions>>=
+struct interface_defn {
+       interface_defn *next;
+
+       char *logical_iface;
+       char *real_iface;
+
+       address_family *address_family;
+       method *method;
+
+       int automatic;
+
+       int max_options;
+       int n_options;
+       variable *option;
+};
+@
+
+The last component in the above, the options, is represented by a
+series of name/value pairs, as follows:
+
+<<type definitions>>=
+typedef struct variable variable;
+@ 
+
+<<structure definitions>>=
+struct variable {
+       char *name;
+       char *value;
+};
+@ 
+
+In addition, we want to represent each mapping in the configuration
+file. This is somewhat simpler, since each mapping is entirely self
+contained, and doesn't need to reference previously determined address
+families or methods or anything.
+
+<<type definitions>>=
+typedef struct mapping_defn mapping_defn;
+@ 
+
+<<structure definitions>>=
+struct mapping_defn {
+       mapping_defn *next;
+
+       int max_matches;
+       int n_matches;
+       char **match;
+
+       char *script;
+
+       int max_mappings;
+       int n_mappings;
+       char **mapping;
+};
+@ 
+
+We can thus begin to instantiate our actual function. What we want is
+something that, given the name of a file, will produce the appropriate
+linked list of interfaces defined in it, or possibly give some sort of
+helpful error message. Pretty simple, hey?
+
+<<exported symbols>>=
+interfaces_file *read_interfaces(char *filename);
+@ 
+
+<<config functions>>=
+interfaces_file *read_interfaces(char *filename) {
+       <<variables local to read interfaces>>
+       interfaces_file *defn;
+
+       <<allocate defn or [[return NULL]]>>
+       <<open file or [[return NULL]]>>
+
+       while (<<we've gotten a line from the file>>) {
+               <<process the line>>
+       }
+       if (<<an error occurred getting the line>>) {
+               <<report internal error and die>>
+       }
+
+       <<close file>>
+
+       return defn;
+}
+@ 
+
+<<allocate defn or [[return NULL]]>>=
+defn = malloc(sizeof(interfaces_file));
+if (defn == NULL) {
+       return NULL;
+}
+defn->allowups = NULL;
+defn->mappings = NULL;
+defn->ifaces = NULL;
+@ 
+
+\subsection{File Handling}
+
+So, the first and most obvious thing to deal with is the file
+handling. Nothing particularly imaginative here.
+
+<<variables local to read interfaces>>=
+FILE *f;
+int line;
+@ 
+
+<<open file or [[return NULL]]>>=
+f = fopen(filename, "r");
+if ( f == NULL ) return NULL;
+line = 0;
+@
+
+<<close file>>=
+fclose(f);
+line = -1;
+@
+
+\subsection{Line Parsing}
+
+Our next problem is to work out how to read a single line from our
+input file. While this is nominally easy, we also want to deal nicely
+with things like continued lines, comments, and very long lines.
+
+So we're going to have to write and make use of a complicated little
+function, which we'll imaginatively call [[get_line()]]. It will need
+a pointer to the file it's reading from, as well as a buffer to store
+the line it finds. Since this buffer's size can't be known in advance
+we'll need to make it [[realloc()]]-able, which means we need to pass
+around references to both the buffer's location (which may change),
+and it's size (which probably will). Our function declaration is thus:
+
+<<config function declarations>>=
+static int get_line(char **result, size_t *result_len, FILE *f, int *line);
+@ 
+
+To use it, we'll need a couple of variables to stores the buffer's
+location, and it's current length.
+
+<<variables local to read interfaces>>=
+char *buf = NULL;
+size_t buf_len = 0;
+@ 
+
+Given these, and presuming we can actually implement the function, our
+key chunk can thus be implemented simply as:
+
+<<we've gotten a line from the file>>=
+get_line(&buf,&buf_len,f,&line)
+@ 
+
+We'll also add the requirement that errors are indicated by the
+[[errno]] variable being non-zero, which is usual and reasonable for
+all the circumstances where [[get_line()]] might have problems.
+
+<<config headers>>=
+#include <errno.h>
+@ 
+
+<<an error occurred getting the line>>=
+ferror(f) != 0
+@ 
+
+Actually defining the function is, as you'd probably imagine, a little
+more complicated. We begin by reading a line from the file. If it was
+a comment (that is, it has a [[#]] character at the first non-blank
+position) then we try again. Otherwise, if the line is continued
+(indicated by a [[\]] character at the very end of the line) we append
+the next line to the buffer. We go to a little bit of effort to trim
+whitespace, and finally return a boolean result indicating whether we
+got a line or not.
+
+<<config functions>>=
+static int get_line(char **result, size_t *result_len, FILE *f, int *line) {
+       <<variables local to get line>>
+
+       do {
+               <<clear buffer>>
+               <<append next line to buffer, or [[return 0]]>>
+               <<trim leading whitespace>>
+       } while (<<line is a comment>>);
+
+       while (<<buffer is continued>>) {
+               <<remove continuation mark>>
+               <<append next line to buffer, or [[return 0]]>>
+       }
+
+       <<trim trailing whitespace>>
+
+       return 1;
+}
+@ 
+
+In order to do string concatenation efficiently, we'll keep track of
+where the end of the line so far is --- this is thus where the
+terminating [[NUL]] will be by the end of the function.
+
+<<variables local to get line>>=
+size_t pos;
+@ 
+
+We can thus clear the buffer by simply resetting where we append new
+text to the beginning of the buffer. What could be simpler?
+
+<<clear buffer>>=
+pos = 0;
+@ 
+
+We'll be making use of the [[fgets()]] function to read the line
+(rather than, say, [[fgetc()]]) so to get an entire line we may have
+to make multiple attempts (if the line is bigger than our
+buffer). Realising this, and the fact that we may not have any
+allocated space for our buffer initially, we need a loop something
+like:
+
+<<append next line to buffer, or [[return 0]]>>=
+do {
+       <<reallocate buffer as necessary, or [[return 0]]>>
+       <<get some more of the line, or [[return 0]]>>
+} while(<<the line isn't complete>>);
+
+<<remove trailing newline>>
+
+(*line)++;
+
+assert( (*result)[pos] == '\0' );
+@ 
+
+When reallocating the buffer, we need to make sure it increases in
+chunks large enough that we don't have to do this too often, but not
+so huge that we run out of memory just to read an 81 character line.
+We'll use two fairly simple heuristics for this: if we've got room to
+add no more than 10 characters, we may as well reallocate the buffer,
+and when reallocating, we want to more or less double the buffer, but
+we want to at least add 80 characters. So we do both.
+
+<<reallocate buffer as necessary, or [[return 0]]>>=
+if (*result_len - pos < 10) {
+       char *newstr = realloc(*result, *result_len * 2 + 80);
+       if (newstr == NULL) {
+               return 0;
+       }
+       *result = newstr;
+       *result_len = *result_len * 2 + 80;
+}
+@ 
+
+The only time we need to keep reading is when the buffer wasn't big
+enough for the entire line. This is indicated by a full buffer, with
+no newline at the end. There is, actually, one case where this can
+happen legitimately --- where the last line of the file is
+\emph{exactly} the length of the buffer. We need to detect this
+because [[fgets()]] will return [[NULL]] and indicate that it's hit
+the end of the file, but we won't want to indicate that until the
+\emph{next} time we try to get a line. Complicated, isn't it?
+
+<<the line isn't complete>>=
+pos == *result_len - 1 && (*result)[pos-1] != '\n'
+@ 
+
+So having thought through all that, actually working with [[fgets()]]
+is fairly simple, especially since we deal with the actual errors
+elsewhere. All we need to do is make the call, update [[pos]] and
+check that the problems [[fgets()]] may have actually bother us.
+
+<<get some more of the line, or [[return 0]]>>=
+if (!fgets(*result + pos, *result_len - pos, f)) {
+       if (ferror(f) == 0 && pos == 0) return 0;
+       if (ferror(f) != 0) return 0;
+}
+pos += strlen(*result + pos);
+@ 
+
+[[fgets()]] leaves a [[\n]] in our buffer in some cases. We're never
+actually interested in it, however, so it's a good move to get rid of
+it.
+
+<<remove trailing newline>>=
+if (pos != 0 && (*result)[pos-1] == '\n') {
+       (*result)[--pos] = '\0';
+}
+@ 
+
+
+Pretty simple, hey? Now the next thing we want to do is get rid of
+some of the whitespace lying about. This is all pretty basic, and just
+involves finding where the whitespace begins and ends, and, well,
+getting rid of it.
+
+<<config headers>>=
+#include <ctype.h>
+@ 
+
+<<trim leading whitespace>>=
+{ 
+       int first = 0; 
+       while (isspace((*result)[first]) && (*result)[first]) {
+               first++;
+       }
+
+       memmove(*result, *result + first, pos - first + 1);
+       pos -= first;
+}
+@ 
+
+<<trim trailing whitespace>>=
+while (isspace((*result)[pos-1])) { /* remove trailing whitespace */
+       pos--;
+}
+(*result)[pos] = '\0';
+@ 
+
+As we mentioned earlier, a line is a comment iff it's first character
+is a [[#]] symbol. Similarly, it's continued iff it's very last
+character is a [[\]]. And, rather obviously, if we want to remove a
+single trailing [[\]], we can do so by changing it to a [[NUL]].
+
+<<line is a comment>>=
+(*result)[0] == '#'
+@ 
+
+<<buffer is continued>>=
+(*result)[pos-1] == '\\'
+@ 
+
+<<remove continuation mark>>=
+(*result)[--pos] = '\0';
+@ 
+
+\subsection{Line Processing}
+
+So. We've gone to a lot of trouble to get a line that we can parse
+with a snap of our fingers, so we probably better jump to it, to mix
+some \emph{clich\'e's}.
+
+We have two alternative bits of state to maintain between lines: either
+what interface we're currently defining, or what mapping we're currently
+defining.
+
+<<variables local to read interfaces>>=
+interface_defn *currif = NULL;
+mapping_defn *currmap = NULL;
+enum { NONE, IFACE, MAPPING } currently_processing = NONE;
+@ 
+
+Since our configuration files are pretty basic, we can work out what
+any particular line means based on the first word in it. To cope with
+this, we'll thus make use of a couple of variables, one to store the
+first word, and the other to store the rest of the line.
+
+<<variables local to read interfaces>>=
+char firstword[80];
+char *rest;
+@ 
+
+To initialize these variables we'll make use of a function I'm overly
+fond of called [[next_word()]]. It copies the first word in a string
+to a given buffer, and returns a pointer to the rest of the buffer.
+
+<<config function declarations>>=
+static char *next_word(char *buf, char *word, int maxlen);
+@
+
+<<config functions>>=
+static char *next_word(char *buf, char *word, int maxlen) {
+       if (!buf) return NULL;
+       if (!*buf) return NULL;
+
+       while(!isspace(*buf) && *buf) {
+               if (maxlen-- > 1) *word++ = *buf;
+               buf++;
+       }
+       if (maxlen > 0) *word = '\0';
+
+       while(isspace(*buf) && *buf) buf++;
+
+       return buf;
+}
+@ 
+
+So after all this, there are basically three different sorts of line
+we can get: the start of a new interface, the start of a new mapping,
+or an option for whatever interface we're currently working with.
+Note that we check for blank lines, but \emph{not} for options with
+empty values.  This has to be done on a case-by-case basis.
+
+<<process the line>>=
+rest = next_word(buf, firstword, 80);
+if (rest == NULL) continue; /* blank line */
+
+if (strcmp(firstword, "mapping") == 0) {
+       <<process [[mapping]] line>>
+       currently_processing = MAPPING;
+} else if (strcmp(firstword, "iface") == 0) {
+       <<process [[iface]] line>>
+       currently_processing = IFACE;
+} else if (strcmp(firstword, "auto") == 0) {
+       <<process [[auto]] line>>
+       currently_processing = NONE;
+} else if (strncmp(firstword, "allow-", 6) == 0 && strlen(firstword) > 6) {
+       <<process [[allow-]] line>>
+       currently_processing = NONE;
+} else {
+       <<process option line>>
+}
+@ 
+
+<<process option line>>=
+switch(currently_processing) {
+       case IFACE:
+               <<process iface option line>>
+               break;
+       case MAPPING:
+               <<process mapping option line>>
+               break;
+       case NONE:
+       default:
+               <<report bad option and die>>
+}
+@ 
+
+\subsubsection{Mapping Line}
+
+Declaring a new mapping is reasonably copewithable --- we need to process
+a few things, but they're reasonably easy to handle.
+
+The main weirdness is that we're processing the [[mapping]] line itself
+and the rest of the stanza in separate blocks of code. So this first
+chunk just needs to do the basics of initialising the data structure,
+but can't really fill in all that much of it.
+
+<<process [[mapping]] line>>=
+<<allocate new mapping>>
+<<parse mapping interfaces>>
+<<set other mapping options to defaults>>
+<<add to list of mappings>>
+@ 
+
+<<allocate new mapping>>=
+currmap = malloc(sizeof(mapping_defn));
+if (currmap == NULL) {
+       <<report internal error and die>>
+}
+@ 
+
+<<parse mapping interfaces>>=
+currmap->max_matches = 0;
+currmap->n_matches = 0;
+currmap->match = NULL;
+
+while((rest = next_word(rest, firstword, 80))) {
+       if (currmap->max_matches == currmap->n_matches) {
+               char **tmp;
+               currmap->max_matches = currmap->max_matches * 2 + 1;
+               tmp = realloc(currmap->match, 
+                       sizeof(*tmp) * currmap->max_matches);
+               if (tmp == NULL) {
+                       currmap->max_matches = (currmap->max_matches - 1) / 2;
+                       <<report internal error and die>>
+               }
+               currmap->match = tmp;
+       }
+
+       currmap->match[currmap->n_matches++] = strdup(firstword);
+}
+@ 
+
+<<set other mapping options to defaults>>=
+currmap->script = NULL;
+
+currmap->max_mappings = 0;
+currmap->n_mappings = 0;
+currmap->mapping = NULL;
+@ 
+
+<<add to list of mappings>>=
+{
+       mapping_defn **where = &defn->mappings;
+       while(*where != NULL) {
+               where = &(*where)->next;
+       }
+       *where = currmap;
+       currmap->next = NULL;
+}
+@ 
+
+So that's that. But as mentioned, we also need to cope with the options
+within the stanza, as well as the lead in. As before, it's not really
+complicated, and we do it thusly:
+
+<<process mapping option line>>=
+if (strcmp(firstword, "script") == 0) {
+       <<handle [[script]] line>>
+} else if (strcmp(firstword, "map") == 0) {
+       <<handle [[map]] line>>
+} else {
+       <<report bad option and die>>
+}
+@ 
+
+<<handle [[script]] line>>=
+if (currmap->script != NULL) {
+       <<report duplicate script in mapping and die>>
+} else {
+       currmap->script = strdup(rest);
+}
+@ 
+
+<<handle [[map]] line>>=
+if (currmap->max_mappings == currmap->n_mappings) {
+       char **opt;
+       currmap->max_mappings = currmap->max_mappings * 2 + 1;
+       opt = realloc(currmap->mapping, sizeof(*opt) * currmap->max_mappings);
+       if (opt == NULL) {
+               <<report internal error and die>>
+       }
+       currmap->mapping = opt;
+}
+currmap->mapping[currmap->n_mappings] = strdup(rest);
+currmap->n_mappings++;
+@ 
+
+\subsubsection{Interface line}
+
+Declaring a new interface follows the same pattern, but is somewhat more
+interesting and some more complicated data structures are involved.
+
+<<process [[iface]] line>>=
+{
+       <<variables local to process [[iface]] line>>
+
+       <<allocate new interface>>
+
+       <<parse interface settings>>
+
+       <<set iface name>>
+       <<set address family>>
+       <<set method>>
+       <<set other interface options to defaults>>
+
+       <<add to list of interfaces>>
+}
+@ 
+
+We'll deal with each of these phases one by one and pretty much in
+order, so prepare yourself for the intense excitement of memory
+allocation!
+
+<<allocate new interface>>=
+currif = malloc(sizeof(interface_defn));
+if (!currif) {
+       <<report internal error and die>>
+}
+@ 
+
+When we introduce a new interface, we simultaneously name the
+interface, the address family, and the method. We cope with this by,
+well, getting somewhere to store each of them, and then, well, storing
+them.
+
+<<variables local to process [[iface]] line>>=
+char iface_name[80];
+char address_family_name[80];
+char method_name[80];
+@ 
+
+<<parse interface settings>>=
+rest = next_word(rest, iface_name, 80);
+rest = next_word(rest, address_family_name, 80);
+rest = next_word(rest, method_name, 80);
+
+if (rest == NULL) {
+       <<report too few parameters for iface line and die>>
+}
+
+if (rest[0] != '\0') {
+       <<report too many parameters for iface line and die>>
+}
+@ 
+
+We then want to store the interface name.
+
+<<set iface name>>=
+currif->logical_iface = strdup(iface_name);
+if (!currif->logical_iface) {
+       <<report internal error and die>>
+}
+@ 
+
+Setting the address family is a little more involved, because it's not
+very useful to know what the name of the address family is, you really
+want to know all the details recorded in the appropriate
+[[address_family]] structure. So we'll make use of a little helper
+function, called [[get_address_family()]] to convert the useless
+string, to the hopefully less useless structure.
+
+<<config function declarations>>=
+static address_family *get_address_family(address_family *af[], char *name);
+@ 
+
+<<set address family>>=
+currif->address_family = get_address_family(addr_fams, address_family_name);
+if (!currif->address_family) {
+       <<report unknown address family and die>>
+}
+@ 
+
+Of course, we probably need to actually implement the function too. We
+won't do anything particularly fancy here, just a simple linear
+search. \emph{Should this really be here, or an exported symbol from
+[[addrfam.c]]? --- aj}
+
+<<config functions>>=
+static address_family *get_address_family(address_family *af[], char *name) {
+       int i;
+       for (i = 0; af[i]; i++) {
+               if (strcmp(af[i]->name, name) == 0) {
+                       return af[i];
+               }
+       }
+       return NULL;
+}
+@
+
+We do something incredibly similar when dealing with the method the
+user wishes to use, and we do it for incredibly similar reasons. Again
+we declare a cute little helper function, this time imaginatively
+called [[get_method()]], and then go and use it and implement in
+almost exactly the same way as before. I told you this was going to be
+a thrill. \emph{The same note applies here, too --- aj}
+
+<<config function declarations>>=
+static method *get_method(address_family *af, char *name);
+@ 
+
+<<set method>>=
+currif->method = get_method(currif->address_family, method_name);
+if (!currif->method) {
+       <<report unknown method and die>>
+       return NULL; /* FIXME */
+}
+@
+
+<<config functions>>=
+static method *get_method(address_family *af, char *name) {
+       int i;
+       for (i = 0; i < af->n_methods; i++) {
+               if (strcmp(af->method[i].name, name) == 0) {
+                       return &af->method[i];
+               }
+       }
+       return NULL;
+}
+@
+
+You'll continue to be enthralled as we set the remaining options to
+some default values.
+
+<<set other interface options to defaults>>=
+currif->automatic = 1;
+currif->max_options = 0;
+currif->n_options = 0;
+currif->option = NULL;
+@ 
+
+Since we want to keep the interfaces in order, we have to go all the
+way to the end of the list of interfaces to add the new interface, and
+we can hence set the [[next]] pointer to NULL in all cases. Gee. Whiz.
+
+Actually, I'm selling this a little short. We also want to make sure
+we don't try instantiating the same interface twice or anything. So we
+take care of that too. There now. Didn't that just get the adrenalin
+pumping?
+
+<<add to list of interfaces>>=
+{
+       interface_defn **where = &defn->ifaces; 
+       while(*where != NULL) {
+               if (duplicate_if(*where, currif)) {
+                       <<report duplicate interface and die>>
+               }
+               where = &(*where)->next;
+       }
+
+       *where = currif;
+       currif->next = NULL;
+}
+@ 
+
+Duplicate interfaces are interfaces that have the same name and the
+same address family. Nothing more complicated than that.
+
+<<config function declarations>>=
+static int duplicate_if(interface_defn *ifa, interface_defn *ifb);
+@ 
+
+<<config functions>>=
+static int duplicate_if(interface_defn *ifa, interface_defn *ifb) {
+       if (strcmp(ifa->logical_iface, ifb->logical_iface) != 0) return 0;
+       if (ifa->address_family != ifb->address_family) return 0;
+       return 1;
+}
+@ 
+
+Dealing with the per-interface options is the next thing to deal
+with. 
+
+<<process iface option line>>=
+<<convert [[post-up]] and [[pre-down]] aliases to [[up]] and [[down]]>>
+<<check for duplicate options>>
+<<add option>>
+@
+
+<<convert [[post-up]] and [[pre-down]] aliases to [[up]] and [[down]]>>=
+if (strcmp(firstword, "post-up") == 0) {
+       strcpy(firstword, "up");
+}
+if (strcmp(firstword, "pre-down") == 0) {
+       strcpy(firstword, "down");
+} 
+@
+
+<<check for duplicate options>>=
+{
+       int i;
+
+       if (strlen (rest) == 0) {
+               <<report empty option and die>>
+       }
+
+       if (strcmp(firstword, "pre-up") != 0 
+           && strcmp(firstword, "up") != 0
+           && strcmp(firstword, "down") != 0
+           && strcmp(firstword, "post-down") != 0)
+        {
+               for (i = 0; i < currif->n_options; i++) {
+                       if (strcmp(currif->option[i].name, firstword) == 0) {
+                               <<report duplicate option and die>>
+                       }
+               }
+       }
+}
+@ 
+
+Adding an option is fairly straightforward: we simply construct
+a new variable and add it at the end of our array of variables,
+increasing the size of the array first if necessary.  Options with 
+empty values are rejected.
+
+<<add option>>=
+if (currif->n_options >= currif->max_options) {
+       <<increase max number of options>>
+}
+
+currif->option[currif->n_options].name = strdup(firstword);
+currif->option[currif->n_options].value = strdup(rest);
+
+if (!currif->option[currif->n_options].name) {
+       <<report internal error and die>>
+}
+
+if (!currif->option[currif->n_options].value) {
+       <<report internal error and die>>
+}
+
+currif->n_options++;   
+@
+
+We'll increase the space for variables by a constant amount each time,
+rather than doubling or anything smart like that.
+
+<<increase max number of options>>=
+{
+       variable *opt;
+       currif->max_options = currif->max_options + 10;
+       opt = realloc(currif->option, sizeof(*opt) * currif->max_options);
+       if (opt == NULL) {
+               <<report internal error and die>>
+       }
+       currif->option = opt;
+}
+@ 
+
+\subsubsection{Auto and Allow Lines}
+
+Processing the [[auto]] and [[allow-]] lines is pretty straightforward
+after the above, we just need to add each parameter to the list and
+check for duplicates. Since we're doing essentially the same thing twice,
+we'll break the common part out into a function.
+
+<<process [[auto]] line>>=
+allowup_defn *auto_ups = get_allowup(&defn->allowups, "auto");
+if (!auto_ups) {
+       <<report internal error and die>>
+}
+while((rest = next_word(rest, firstword, 80))) {
+       if (!add_allow_up(filename, line, auto_ups, firstword))
+               return NULL;
+}
+@ 
+<<process [[allow-]] line>>=
+allowup_defn *allow_ups = get_allowup(&defn->allowups, firstword + 6);
+if (!allow_ups) {
+       <<report internal error and die>>
+}
+while((rest = next_word(rest, firstword, 80))) {
+       if (!add_allow_up(filename, line, allow_ups, firstword))
+               return NULL;
+}
+@ 
+
+<<config function declarations>>=
+allowup_defn *get_allowup(allowup_defn **allowups, char *name);
+
+<<config functions>>=
+allowup_defn *get_allowup(allowup_defn **allowups, char *name) {
+       for (; *allowups; allowups = &(*allowups)->next) {
+               if (strcmp((*allowups)->when, name) == 0) break;
+       }
+       if (*allowups == NULL) {
+               *allowups = malloc(sizeof(allowup_defn));
+               if (*allowups == NULL) return NULL;
+               (*allowups)->when = strdup(name);
+               (*allowups)->next = NULL;
+               (*allowups)->max_interfaces = 0;
+               (*allowups)->n_interfaces = 0;
+               (*allowups)->interfaces = NULL;
+       }
+       return *allowups;
+}
+@
+
+We'll want to export a little helper function to make finding the appropriate
+allowup easier too:
+
+<<exported symbols>>=
+allowup_defn *find_allowup(interfaces_file *defn, char *name);
+@
+
+<<config functions>>=
+allowup_defn *find_allowup(interfaces_file *defn, char *name) {
+       allowup_defn *allowups = defn->allowups;
+       for (; allowups; allowups = allowups->next) {
+               if (strcmp(allowups->when, name) == 0) break;
+       }
+       return allowups;
+}
+@
+
+<<config function declarations>>=
+allowup_defn *add_allow_up(char *filename, int line,
+        allowup_defn *allow_up, char *iface_name);
+@
+
+<<config functions>>=
+allowup_defn *add_allow_up(char *filename, int line,
+       allowup_defn *allow_up, char *iface_name)
+{
+       <<check [[iface_name]] isn't already an [[allow_up]] interface or die>>
+       <<add [[iface_name]] as an [[allow_up]] interface or die>>
+       return allow_up;
+}
+@
+
+<<check [[iface_name]] isn't already an [[allow_up]] interface or die>>=
+{
+       int i;
+
+       for (i = 0; i < allow_up->n_interfaces; i++) {
+               if (strcmp(iface_name, allow_up->interfaces[i]) == 0) {
+                       <<report [[iface_name]] as [[allow_up]] duplicate, die>>
+               }
+       }
+}
+@
+
+<<add [[iface_name]] as an [[allow_up]] interface or die>>=
+if (allow_up->n_interfaces == allow_up->max_interfaces) {
+       char **tmp;
+       allow_up->max_interfaces *= 2;
+       allow_up->max_interfaces++;
+       tmp = realloc(allow_up->interfaces, 
+               sizeof(*tmp) * allow_up->max_interfaces);
+       if (tmp == NULL) {
+               <<report internal error and die>>
+       }
+       allow_up->interfaces = tmp;
+}
+
+allow_up->interfaces[allow_up->n_interfaces] = strdup(iface_name);
+allow_up->n_interfaces++;
+@
+
+\subsection{Error Handling}
+
+We don't do anything too fancy about handling errors that occur, we
+just print out a hopefully helpful error message, and return from the
+function. \emph{We probably should also go to some effort to close files,
+and free memory, but well, you know. Maybe version $n+1$. --- aj}
+
+<<report internal error and die>>=
+perror(filename);
+return NULL;
+@ 
+
+<<report too few parameters for iface line and die>>=
+fprintf(stderr, "%s:%d: too few parameters for iface line\n", filename, line);
+return NULL;
+@
+
+<<report too many parameters for iface line and die>>=
+fprintf(stderr, "%s:%d: too many parameters for iface line\n", filename, line);
+return NULL;
+@
+
+<<report unknown address family and die>>=
+fprintf(stderr, "%s:%d: unknown address type\n", filename, line);
+return NULL;
+@
+
+<<report unknown method and die>>=
+fprintf(stderr, "%s:%d: unknown method\n", filename, line);
+return NULL;
+@
+
+<<report duplicate interface and die>>=
+fprintf(stderr, "%s:%d: duplicate interface\n", filename, line);
+return NULL;
+@
+
+<<report [[iface_name]] as [[allow_up]] duplicate, die>>=
+fprintf(stderr, "%s:%d: interface %s declared allow-%s twice\n", 
+       filename, line, iface_name, allow_up->when);
+return NULL;
+@
+
+<<report duplicate option and die>>=
+fprintf(stderr, "%s:%d: duplicate option\n", filename, line);
+return NULL;
+@
+
+<<report duplicate script in mapping and die>>=
+fprintf(stderr, "%s:%d: duplicate script in mapping\n", filename, line);
+return NULL;
+@ 
+
+<<report bad option and die>>=
+fprintf(stderr, "%s:%d: misplaced option\n", filename, line);
+return NULL;
+@
+
+<<report empty option and die>>=
+fprintf(stderr, "%s:%d: option with empty value\n", filename, line);
+return NULL;
+@ 
+
+\section{Execution}
+
+The [[execute]] module will be laid out in the standard manner, and
+will make use of the usual header files.
+
+<<execute.c>>=
+<<execute headers>>
+<<execute global variables>>
+<<execute function declarations>>
+<<execute functions>>
+@ 
+
+<<execute headers>>=
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "header.h"
+@
+
+The key functions we export from here are all the functions that as a
+fairly direct result run some executable.
+
+\begin{itemize}
+       \item [[iface_up()]] and [[iface_down()]] which will actually
+       configure or deconfigure an interface.
+
+       \item [[execute()]] which will take an interface definition and
+       a command and fill in the details from the first into the
+       second, and the execute the result. This is basically just a
+       callback for the address family module.
+
+       \item [[run_mapping()]] which will run a mapping script and
+       determine if a new logical interface should be selected.
+\end{itemize}
+
+We'll discuss each of these in order.
+
+\subsection{Interface Configuration and Deconfiguration}
+
+Most of the complexity is involved in implementing the [[iface_up()]] and
+[[iface_down()]] functions. These are complicated enough that an explanatory
+diagram is probably useful:
+
+\begin{center}
+\includegraphics[height=60mm]{execution}
+\end{center}
+
+At a conceptual level, [[iface_up()]] and [[iface_down()]] have a
+reasonably straightforward job: they have to run one set of scripts,
+the configure or deconfigure the interface, then run another set of
+scripts.
+
+This is complicated slightly in that they also have to handle the
+possibility that some of an interface's required arguments may be missing
+(in which case none of the commands should be attempted), and that some
+of the commands may fail (in which case none of the following commands
+should be attempted). We've already encoded most of the early-abort
+logic for the latter case into the address family definitions; so the way
+we'll handle the the former case is simply to call the address family's
+method [[up()]] or [[down()]] twice: once to ensure all the variables are
+appropriately filled out, and once to actually configure the interface.
+
+\subsubsection{Command checking}
+
+As such, we'll make use of two execution functions, each of which take
+one parameter, a shell command. We'll uninventively call these [[doit()]]
+and [[check()]]. They'll return 0 on failure, non-zero on success.
+
+[[check()]] is thus fairly trivial:
+
+<<execute function declarations>>=
+static int check(char *str);
+@
+
+<<execute functions>>=
+static int check(char *str) {
+       return str != NULL;
+}
+@ 
+
+\subsubsection{Environment handling}
+
+[[doit()]] is much more complicated, mainly by the fact that we
+don't simply want to just run the programs, but because we also want
+to setup a sanitized environment. In particular, we want to make the
+environment variables [[IFACE]], and [[MODE]] available (eg, [[eth0]] and
+[[start]] respectively), and we want to export all the given options as
+[[IF_OPTION]], with some sanitisation.
+
+We'll do this just once per interface rather than once per command,
+and so we'll use a global variable to store our new environment, and a
+special function which will initialise it for us.
+
+<<execute global variables>>=
+static char **environ = NULL;
+@ 
+
+[[environ]] will be in the format used by the [[execle()]] function call,
+that is, a [[NULL]]-terminated array of strings of the form [[foo=bar]].
+
+<<execute function declarations>>=
+static void set_environ(interface_defn *iface, char *mode, char *phase);
+@
+
+Our function then will be:
+
+<<execute functions>>=
+static void set_environ(interface_defn *iface, char *mode, char *phase) {
+       <<variables local to set environ>>
+       int i;
+       const int n_env_entries = iface->n_options + 8;
+
+       <<initialise environ [[n_env_entries]]>>
+
+       for (i = 0; i < iface->n_options; i++) {
+               <<[[continue]] if option is a command>>
+
+               <<add [[IF_]]option to environment>>
+       }
+
+       <<add [[IFACE]] to environment>>
+       <<add [[LOGICAL]] to environment>>
+       <<add [[ADDRFAM]] to environment>>
+       <<add [[METHOD]] to environment>>
+
+       <<add [[MODE]] to environment>>
+       <<add [[PHASE]] to environment>>
+       <<add [[VERBOSITY]] to environment>>
+       <<add [[PATH]] to environment>>
+}
+@
+
+Since we keep adding at the end, we'll make use of a pointer to keep track
+of where the end actually is, namely:
+
+<<variables local to set environ>>=
+char **environend;
+@
+
+Initialising thus becomes:
+
+<<initialise environ [[n_env_entries]]>>=
+<<clear environ if necessary>>
+environ = malloc(sizeof(char*) * (n_env_entries + 1 /* for final NULL */));
+environend = environ; 
+*environend = NULL;
+@
+
+<<clear environ if necessary>>=
+if (environ != NULL) {
+       char **ppch;
+       for (ppch = environ; *ppch; ppch++) {
+               free(*ppch);
+               *ppch = NULL;
+       }
+       free(environ);
+       environ = NULL;
+}
+@
+
+Our continue chunk is also fairly straight forward:
+
+<<[[continue]] if option is a command>>=
+if (strcmp(iface->option[i].name, "pre-up") == 0
+    || strcmp(iface->option[i].name, "up") == 0
+    || strcmp(iface->option[i].name, "down") == 0
+    || strcmp(iface->option[i].name, "post-down") == 0)
+{
+       continue;
+}
+@
+
+We'll make use of a small helper function for actually setting the
+environment. This function will handle [[malloc]]ing enough memory, and
+ensuring the environment variable name is reasonably sensible. It'll
+take three parameters: a [[printf]]-style format string presumed to
+contain two [[%s]]s, and the two parameters to that format string.
+
+<<execute function declarations>>=
+static char *setlocalenv(char *format, char *name, char *value);
+@
+
+We can then go ahead and fill in the environment.
+
+<<add [[IF_]]option to environment>>=
+*(environend++) = setlocalenv("IF_%s=%s", iface->option[i].name,
+                              iface->option[i].value);
+*environend = NULL;
+@
+
+<<add [[IFACE]] to environment>>=
+*(environend++) = setlocalenv("%s=%s", "IFACE", iface->real_iface);
+*environend = NULL;
+@
+
+<<add [[LOGICAL]] to environment>>=
+*(environend++) = setlocalenv("%s=%s", "LOGICAL", iface->logical_iface);
+*environend = NULL;
+@
+
+<<add [[MODE]] to environment>>=
+*(environend++) = setlocalenv("%s=%s", "MODE", mode);
+*environend = NULL;
+@
+
+<<add [[PHASE]] to environment>>=
+*(environend++) = setlocalenv("%s=%s", "PHASE", phase); 
+*environend = NULL;
+@
+
+<<add [[PATH]] to environment>>=
+*(environend++) = setlocalenv("%s=%s", "PATH", "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin");
+*environend = NULL;
+@
+
+<<add [[VERBOSITY]] to environment>>=
+*(environend++) = setlocalenv("%s=%s", "VERBOSITY", verbose ? "1" : "0");
+*environend = NULL;
+@
+
+<<add [[ADDRFAM]] to environment>>=
+*(environend++) = setlocalenv("%s=%s", "ADDRFAM", iface->address_family->name);
+*environend = NULL;
+@
+
+<<add [[METHOD]] to environment>>=
+*(environend++) = setlocalenv("%s=%s", "METHOD", iface->method->name);
+*environend = NULL;
+@
+
+Our helper function then will then be something like:
+
+<<execute functions>>=
+static char *setlocalenv(char *format, char *name, char *value) {
+       char *result;
+
+       <<allocate memory for [[result]]>>
+
+       sprintf(result, format, name, value);
+
+       <<tidy [[result]]>>
+
+       return result;
+}
+@
+
+Allocating the memory is fairly straightforward (although working out
+exactly how much memory involves a little guesswork, and assuming the
+caller passes in a reasonable [[format]]).
+
+<<allocate memory for [[result]]>>=
+result = malloc(strlen(format)   /* -4 for the two %s's */
+                + strlen(name) 
+                + strlen(value) 
+                + 1);
+if (!result) {
+       perror("malloc");
+       exit(1);
+}
+@
+
+And finally, tidying the result is a fairly simple matter of eliding all
+the characters we don't like, or translating them to ones we do like. We
+do like upper case letters, digits and underscores; and we're willing
+to translate hyphens and lower case letters. So here we go.
+
+<<tidy [[result]]>>=
+{
+       char *here, *there;
+
+       for(here = there = result; *there != '=' && *there; there++) {
+               if (*there == '-') *there = '_';
+               if (isalpha(*there)) *there = toupper(*there);
+
+               if (isalnum(*there) || *there == '_') {
+                       *here = *there;
+                       here++;
+               }
+       }
+       memmove(here, there, strlen(there) + 1);
+}
+@
+
+\subsubsection{Command Execution}
+
+Our [[doit()]] function is then essentially a rewrite of the standard
+[[system()]] function call. The only additions are that we setup our
+child's environment as discussed previously, and we make use of two
+external globals, [[no_act]] and [[verbose]] and modify our behaviour
+based on those.
+
+<<execute function declarations>>=
+static int doit(char *str);
+@
+
+<<execute functions>>=
+static int doit(char *str) {
+       assert(str);
+
+       if (verbose || no_act) {
+               fprintf(stderr, "%s\n", str);
+       }
+       if (!no_act) {
+               pid_t child;
+               int status;
+
+               fflush(NULL);
+               switch(child = fork()) {
+                   case -1: /* failure */
+                       return 0;
+                   case 0: /* child */
+                       execle("/bin/sh", "/bin/sh", "-c", str, NULL, environ);
+                       exit(127);
+                   default: /* parent */
+                       break;
+               }
+               waitpid(child, &status, 0);
+               if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
+                       return 0;
+       }
+       return 1;
+}
+@
+
+\subsubsection{Executing a list of commands}
+
+In addition to the above, we also need a function to cope with running
+all the [[pre-up]] commands and so forth.
+
+<<exported symbols>>=
+int execute_all(interface_defn *ifd, execfn *exec, char *opt);
+@ 
+
+All we need to do for this is to iterate through the options in the
+interface definition, and execute whichever ones are the right type,
+and call the [[run-parts]] command on the appropriate directory of
+scripts. That doesn't make for thrilling code.
+
+This function will generally have [[doit]] passed in as the [[exec]]
+parameter.
+
+<<execute functions>>=
+int execute_all(interface_defn *ifd, execfn *exec, char *opt) {
+       int i;
+       char buf[100];
+       for (i = 0; i < ifd->n_options; i++) {
+               if (strcmp(ifd->option[i].name, opt) == 0) {
+                       if (!(*exec)(ifd->option[i].value)) {
+                               return 0;
+                       }
+               }
+       }
+
+       snprintf(buf, sizeof(buf), "run-parts %s /etc/network/if-%s.d",
+               verbose ? "--verbose" : "", opt);
+
+       (*exec)(buf); 
+
+       return 1;
+}
+@ 
+
+\subsubsection{[[iface_up()]] and [[iface_down()]]}
+
+Our functions, then are:
+
+<<exported symbols>>=
+int iface_up(interface_defn *iface);
+int iface_down(interface_defn *iface);
+@ 
+
+<<execute functions>>=
+int iface_up(interface_defn *iface) {
+       if (!iface->method->up(iface,check)) return -1;
+
+       set_environ(iface, "start", "pre-up");
+       if (!execute_all(iface,doit,"pre-up")) return 0;
+
+       if (!iface->method->up(iface,doit)) return 0;
+
+       set_environ(iface, "start", "post-up");
+       if (!execute_all(iface,doit,"up")) return 0;
+
+       return 1;
+}
+@ 
+
+<<execute functions>>=
+int iface_down(interface_defn *iface) {
+       if (!iface->method->down(iface,check)) return -1;
+
+       set_environ(iface, "stop", "pre-down");
+       if (!execute_all(iface,doit,"down")) return 0;
+
+       if (!iface->method->down(iface,doit)) return 0;
+
+       set_environ(iface, "stop", "post-down");
+       if (!execute_all(iface,doit,"post-down")) return 0;
+
+       return 1;
+}
+@ 
+
+\subsection{Command Parsing}
+
+All the above just leave one thing out: how the address family method's
+configuration function gets back to calling [[doit()]]. This function
+answers that question:
+
+<<exported symbols>>=
+int execute(char *command, interface_defn *ifd, execfn *exec);
+@ 
+
+At the somewhat abstract level, this is fairly trivial. The devil is
+in the details of the parsing, which makes up the rest of the module.
+
+<<execute functions>>=
+int execute(char *command, interface_defn *ifd, execfn *exec) { 
+       char *out;
+       int ret;
+
+       out = parse(command, ifd);
+       if (!out) { return 0; }
+
+       ret = (*exec)(out);
+
+       free(out);
+       return ret;
+}
+@ 
+
+We'll need a basic parser function, which we'll call [[parse()]], to
+make the appropriate substitutions into a command. It's probably worth
+a note as to exactly what substitutions may be made:
+
+\begin{itemize}
+
+       \item Special characters can be escaped with a backslash. eg
+       [[ls MoreThan80\%]].
+
+       \item Variables can be substituted by including their name
+       delimeted by percents. eg [[ls %directory%]].
+
+       \item Optional components may be enclosed in double square
+       brackets. Optional components will be included exactly when
+       every variable referenced within exists. eg
+       [[ls [[--color=%color%]]][[] %directory%]]. Optional components
+       may be nested.
+
+\end{itemize}
+
+Most of the parsing is fairly straightforward -- basically, we keep an
+output buffer, and add things to it as we stroll through the input
+buffer: either the actual character we want, or whatever the value of
+the variable we're looking at is, or whatever. The only particularly
+complicated bit is how we deal with the optional sections, which will
+be explained when we get to them.
+
+<<execute function declarations>>=
+static char *parse(char *command, interface_defn *ifd);
+@ 
+
+<<execute functions>>=
+static char *parse(char *command, interface_defn *ifd) {
+       <<variables local to parse>>
+
+       while(*command) {
+               switch(*command) {
+                       <<handle a token>>
+               }
+       }
+
+       <<deal with error conditions>>
+
+       <<return result>>
+}
+@
+
+\subsubsection{Maintain output buffer}
+
+So the first thing we need to do is actually write some code to deal
+with the output buffer, which will need to be dynamically resized and
+so on to take care of possibly long strings and what-not. It is the
+caller's responsibility to [[free()]] this buffer. We'll maintain two
+extra variables for convenience: who much memory we've allocated
+[[len]], and where the next character should be stuck [[pos]].
+
+<<variables local to parse>>=
+char *result = NULL;
+size_t pos = 0, len = 0;
+@ 
+
+This makes it pretty easy to return the result to the caller, too.
+
+<<return result>>=
+return result;
+@
+
+The main thing to be done to this buffer is to add characters or
+strings to it. To deal with this, we'll make use of an [[addstr()]]
+function that resizes the buffer as necessary, and appends a string to
+it. So we can deal with single characters, and substrings in general,
+we'll specify the string to be added as a pointer-length combination,
+rather than as a [[NUL]] terminated string.
+
+<<execute function declarations>>=
+void addstr(char **buf, size_t *len, size_t *pos, char *str, size_t strlen);
+@ 
+
+<<execute functions>>=
+void addstr(char **buf, size_t *len, size_t *pos, char *str, size_t strlen) {
+       assert(*len >= *pos);
+       assert(*len == 0 || (*buf)[*pos] == '\0');
+
+       if (*pos + strlen >= *len) {
+               char *newbuf;
+               newbuf = realloc(*buf, *len * 2 + strlen + 1);
+               if (!newbuf) {
+                       perror("realloc");
+                       exit(1); /* a little ugly */
+               }
+               *buf = newbuf;
+               *len = *len * 2 + strlen + 1;
+       }
+
+       while (strlen-- >= 1) {
+               (*buf)[(*pos)++] = *str;
+               str++;
+       }
+       (*buf)[*pos] = '\0';
+}
+@ 
+
+Given this, we can define our default behaviour for a character:
+
+<<handle a token>>=
+default:
+       addstr(&result, &len, &pos, command, 1);
+       command++;
+       break;
+@ 
+
+\subsubsection{Escaped characters}
+
+We can also deal pretty simply with escaped tokens. The only special
+circumstance is if the [[\]] is at the very end of string. We don't
+want buffer overflows afterall.
+
+<<handle a token>>=
+case '\\':
+       if (command[1]) {
+               addstr(&result, &len, &pos, command+1, 1);
+               command += 2;
+       } else {
+               addstr(&result, &len, &pos, command, 1);
+               command++;
+       }
+       break;
+@ 
+
+\subsubsection{Optional components}
+
+Basically we keep track of each optional section we're in, whether
+we've been unable to fill in any variables, and where we started
+it. When we reach the end of an optional section, we check to see if
+we were unable to fill in any variables, and, if so, we discard any
+text we'd added within that block. This also allows us to neatly check
+for any errors trying to fill in variables that aren't in optional
+sections.
+
+Basically what we'll do here is keep one stack to represent where the
+various thingos started, and another to represent whether any
+variables didn't exist. We'll use the bottom-most entry in the stack
+to represent the entire command, and thus keep track of whether or not
+we have to return an error because an undefined variable was used in a
+non-optional part of the command.
+
+<<constant definitions>>=
+#define MAX_OPT_DEPTH 10
+@ 
+
+<<variables local to parse>>=
+size_t old_pos[MAX_OPT_DEPTH] = {0};
+int okay[MAX_OPT_DEPTH] = {1};
+int opt_depth = 1;
+@ 
+
+Given this, when we encounter a double open bracket, we need to just
+add the appropriate values to our stacks, and, similarly, when we
+encounter a double close bracket, we simply need to pop the stack, and
+see whether we need to move back or not, as well as taking care of an
+possible errors, naturally. \emph{We probably could actually give
+error messages here instead of just treating the brackets literally
+when they might cause problems. But there doesn't seem much point,
+really. --- aj}
+
+<<handle a token>>=
+case '[':
+       if (command[1] == '[' && opt_depth < MAX_OPT_DEPTH) {
+               old_pos[opt_depth] = pos;
+               okay[opt_depth] = 1;
+               opt_depth++;
+               command += 2;
+       } else {
+               addstr(&result, &len, &pos, "[", 1);
+               command++;
+       }
+       break;
+@ 
+
+<<handle a token>>=
+case ']':
+       if (command[1] == ']' && opt_depth > 1) {
+               opt_depth--;
+               if (!okay[opt_depth]) {
+                       pos = old_pos[opt_depth];
+                       result[pos] = '\0';
+               }
+               command += 2;
+       } else {
+               addstr(&result, &len, &pos, "]", 1);
+               command++;
+       }
+       break;
+@
+
+Finally, at the end of the function, the stacks can be left in an
+unacceptable state --- either one of the optional blocks was never
+closed, or an undefined variable was used elsewhere. We'll note these
+circumstances by returning [[NULL]] and setting [[errno]].
+
+<<execute headers>>=
+#include <errno.h>
+@
+
+<<constant definitions>>=
+#define EUNBALBRACK 10001
+#define EUNDEFVAR   10002
+@ 
+
+<<deal with error conditions>>=
+if (opt_depth > 1) {
+       errno = EUNBALBRACK;
+       free(result);
+       return NULL;
+}
+
+if (!okay[0]) {
+       errno = EUNDEFVAR;
+       free(result);
+       return NULL;
+}
+@ 
+
+\subsubsection{Variables}
+
+Dealing with variables is comparatively fairly simple. We just need to
+find the next percent, and see if whatever's in-between is a variable,
+and, if so, get it's value.
+
+<<constant definitions>>=
+#define MAX_VARNAME    32
+#define EUNBALPER   10000
+@ 
+
+<<handle a token>>=
+case '%':
+{
+       <<variables local to handle percent token>>
+       char *varvalue;
+
+       <<determine variable name>>
+
+       <<get [[varvalue]]>>
+
+       if (varvalue) {
+               addstr(&result, &len, &pos, varvalue, strlen(varvalue));
+       } else {
+               okay[opt_depth - 1] = 0;
+       }
+
+       <<move to token after closing percent>>
+
+       break;
+}
+@ 
+
+We don't do anything particularly clever dealing with the next percent
+--- just a pointer to the appropriate character.
+
+<<variables local to handle percent token>>=
+char *nextpercent;
+@ 
+
+<<determine variable name>>=
+command++;
+nextpercent = strchr(command, '%');
+if (!nextpercent) {
+       errno = EUNBALPER;
+       free(result);
+       return NULL;
+}
+@ 
+
+<<move to token after closing percent>>=
+command = nextpercent + 1;
+@
+
+The slightly tricky thing we do here is use a [[strncmpz]] function,
+which allows us to check that a string represented by a [[char*]] and
+a length is the same as a [[NUL]] terminated string.
+
+<<execute function declarations>>=
+int strncmpz(char *l, char *r, size_t llen);
+@ 
+
+<<execute functions>>=
+int strncmpz(char *l, char *r, size_t llen) {
+       int i = strncmp(l, r, llen);
+       if (i == 0)
+               return -r[llen];
+       else
+               return i;
+}
+@ 
+
+Given the above, the implementation of the [[get_var()]] function to
+lookup the value of a variable, is reasonably straight forward.
+
+<<execute function declarations>>=
+char *get_var(char *id, size_t idlen, interface_defn *ifd);
+@ 
+
+<<execute functions>>=
+char *get_var(char *id, size_t idlen, interface_defn *ifd) {
+       int i;
+
+       if (strncmpz(id, "iface", idlen) == 0) {
+               return ifd->real_iface;
+       } else {
+               for (i = 0; i < ifd->n_options; i++) {
+                       if (strncmpz(id, ifd->option[i].name, idlen) == 0) {
+                               return ifd->option[i].value;
+                       }
+               }
+       }
+
+       return NULL;
+}
+@ 
+
+Which means we can finish of the chunk, thus:
+
+<<get [[varvalue]]>>=
+varvalue = get_var(command, nextpercent - command, ifd);
+@ 
+
+\subsection{Mapping Scripts}
+
+Doing a mapping is moderately complicated, since we need to pass a
+fair bit of stuff to the script. The way we'll do this is via a
+mixture of command line arguments, and [[stdin]]: basically, we'll
+pass all the mapping variables from the interfaces file via [[stdin]],
+and anything else necessary will be a command line argument. The
+script will be expected to exit successfully with the appropriate
+logical interface as the first line of [[stdout]] if it made a match,
+or exit unsuccessfully (error code [[1]], eg) otherwise.
+
+<<exported symbols>>=
+int run_mapping(char *physical, char *logical, int len, mapping_defn *map);
+@ 
+
+<<execute functions>>=
+int run_mapping(char *physical, char *logical, int len, mapping_defn *map) {
+       FILE *in, *out;
+       int i, status;
+       pid_t pid;
+
+       <<execute the mapping script>>
+       <<send input to mapping script>>
+       <<wait for mapping script to finish>>
+       <<check output from mapping script>>
+
+       return 1;
+}
+@ 
+
+The latter options here are fairly straightforward, given some Unix
+knowledge.
+
+<<send input to mapping script>>=
+for (i = 0; i < map->n_mappings; i++) {
+       fprintf(in, "%s\n", map->mapping[i]);
+}
+fclose(in);
+@ 
+
+<<wait for mapping script to finish>>=
+waitpid(pid, &status, 0);
+@ 
+
+<<check output from mapping script>>=
+if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
+       if (fgets(logical, len, out)) {
+               char *pch = logical + strlen(logical) - 1;
+               while (pch >= logical && isspace(*pch)) 
+                       *(pch--) = '\0';
+       }
+}
+fclose(out);   
+@ 
+
+Slightly more complicated is setting up the child process and grabbing
+its [[stdin]] and [[stdout]]. Unfortunately we can't just use
+[[popen()]] for this, since it'll only allow us to go one way. So,
+instead we'll write our own [[popen()]]. It'll look like:
+
+<<execute headers>>=
+#include <stdarg.h>
+@ 
+
+<<execute function declarations>>=
+static int popen2(FILE **in, FILE **out, char *command, ...);
+@ 
+
+The varargs component will be the arguments, as per [[execl()]], and
+the return value will be the [[PID]] if the call was successful, or 0
+otherwise.
+
+As such, we will be able to execute the script thusly:
+
+<<execute the mapping script>>=
+pid = popen2(&in, &out, map->script, physical, NULL);
+if (pid == 0) {
+       return 0;
+}
+@ 
+
+Writing [[popen2()]] is an exercise in Unix arcana.
+
+<<execute headers>>=
+#include <unistd.h>
+#include <sys/wait.h>
+@ 
+
+<<execute functions>>=
+static int popen2(FILE **in, FILE **out, char *command, ...) {
+       va_list ap;
+       char *argv[11] = {command};
+       int argc;
+       int infd[2], outfd[2];
+       pid_t pid;
+
+       argc = 1;
+       va_start(ap, command);
+       while((argc < 10) && (argv[argc] = va_arg(ap, char*))) {
+               argc++;
+       }
+       argv[argc] = NULL; /* make sure */
+       va_end(ap);
+
+       if (pipe(infd) != 0) return 0;
+       if (pipe(outfd) != 0) {
+               close(infd[0]); close(infd[1]);
+               return 0;
+       }
+
+       fflush(NULL);
+       switch(pid = fork()) {
+               case -1: /* failure */
+                       close(infd[0]); close(infd[1]);
+                       close(outfd[0]); close(outfd[1]);
+                       return 0;
+               case 0: /* child */
+                       dup2(infd[0], 0);
+                       dup2(outfd[1], 1);
+                       close(infd[0]); close(infd[1]);
+                       close(outfd[0]); close(outfd[1]);
+                       execvp(command, argv);
+                       exit(127);
+               default: /* parent */
+                       *in = fdopen(infd[1], "w");
+                       *out = fdopen(outfd[0], "r");
+                       close(infd[0]); close(outfd[1]);
+                       return pid;
+       }
+       /* unreached */
+}
+@
+
+\section{The Driver}
+
+The final C module we'll have is the one with the [[main()]]
+function. It's put together in a fairly straightforward way.
+
+<<main.c>>=
+<<main headers>>
+<<main global variables>>
+<<main function declarations>>
+<<main functions>>
+<<main>>
+@ 
+
+Equally, there's nothing particularly special about our headers.
+
+<<main headers>>=
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "header.h"
+@
+
+Now, after all the above modules, our main program doesn't have too
+much to do: it just has to interpret arguments and coordinate the
+intervening modules. Since we're being ``smart'', as well as parsing
+arguments, we'll decide whether the interface is going up or down
+depending on whether we were called as [[ifup]] or [[ifdown]].
+
+<<main>>=
+int main(int argc, char **argv) {
+       <<variables local to main>>
+
+       <<ensure environment is sane>>
+
+       <<parse command name or die>>
+       <<parse arguments>>
+
+       <<read interfaces files or die>>
+
+       <<run commands for appropriate interfaces>>
+
+       return 0;
+}
+@
+
+\subsection{Check the Environment}
+
+In the earlier code we assume that we have stdin, stdout and stderr all
+available. We need to assure that, just in case:
+
+<<main headers>>=
+#include <unistd.h>
+#include <fcntl.h>
+@
+
+<<ensure environment is sane>>=
+{
+       int i;
+       for (i = 0; i <= 2; i++) {
+               if (fcntl(i, F_GETFD) == -1) {
+                       if (errno == EBADF && open("/dev/null", 0) == -1) {
+                               fprintf(stderr,
+                                       "%s: fd %d not available; aborting\n",
+                                       argv[0], i);
+                               exit(2);
+                       } else if (errno == EBADF) {
+                               errno = 0; /* no more problems */
+                       } else {
+                               /* some other problem -- eeek */
+                               perror(argv[0]);
+                               exit(2);
+                       }
+               }
+       }
+}
+@
+
+\subsection{Configuring or Deconfiguring?}
+
+So the very first real thing we need to do is parse the command name. To
+do this, we'll obviously need to work out somewhere to store the result. A
+reasonable thing to do here is just to keep a function pointer about,
+which will point to one of the previously defined [[iface_up]] or
+[[iface_down]] functions, depending on which should be used on the
+specified interfaces.
+
+<<variables local to main>>=
+int (*cmds)(interface_defn *) = NULL;
+@
+
+So given this, we can just:
+
+<<parse command name or die>>=
+{
+       char *command;
+
+       <<set [[command]] to the base of the command name>>
+       <<set [[cmds]] based on [[command]] or die>>
+}
+@
+
+And fill out each component in the reasonably obvious manner of:
+
+<<set [[command]] to the base of the command name>>=
+if ((command = strrchr(argv[0],'/'))) {
+       command++; /* first char after / */
+} else {
+       command = argv[0]; /* no /'s in argv[0] */
+}
+@
+
+<<set [[cmds]] based on [[command]] or die>>=
+if (strcmp(command, "ifup")==0) {
+       cmds = iface_up;
+} else if (strcmp(command, "ifdown")==0) {
+       cmds = iface_down;
+} else {
+       fprintf(stderr,"This command should be called as ifup or ifdown\n");
+       exit(1);
+}
+@ 
+
+In addition, since our later behaviour varies depending on whether we're
+bringing interfaces up or taking them down we'll define two chunks to assist
+with this, namely:
+
+<<we're bringing interfaces up>>=
+(cmds == iface_up)
+@
+
+<<we're taking interfaces down>>=
+(cmds == iface_down)
+@
+
+The [[--allow]] option lets us limit the interfaces ifupdown will act on.
+It's implemented by having an [[allow_class]] that tells us which class
+of interfaces we're working with, and skipping interfaces that aren't
+in that class, like so:
+
+<<we're limiting to [[--allow]]ed interfaces>>=
+(allow_class != NULL)
+
+<<find [[iface]] in [[allow_class]] or [[continue]]>>=
+{
+       int i;
+       allowup_defn *allowup = find_allowup(defn, allow_class);
+       if (allowup == NULL)
+               continue;
+
+       for (i = 0; i < allowup->n_interfaces; i++) {
+               if (strcmp(allowup->interfaces[i], iface) == 0)
+                       break;
+       }
+       if (i >= allowup->n_interfaces)
+               continue;
+}
+@
+
+Finally, the behaviour might vary depending on whether we are 
+excluding this interface or not. Notice that
+the exclude option can use a full interface name or substrings that
+match interfaces. A user could easily have unexpected behaviour
+if he uses a small string to do the match:
+
+<<we're [[--exclude]]ing this interface>>=
+(excludeint != NULL && strstr(iface,excludeint) != NULL)
+@
+
+\subsection{Argument Handling}
+
+Okay, so next on our agenda is argument handling.
+
+We'll do argument handling via the GNU [[getopt]] function, which
+means we have to include the appropriate header, and define a cute
+little structure to represent out long options:
+
+<<main headers>>=
+#include <getopt.h>
+@
+
+<<variables local to main>>=
+struct option long_opts[] = {
+       {"help",        no_argument,       NULL, 'h'},
+       {"version",     no_argument,       NULL, 'V'},
+       {"verbose",     no_argument,       NULL, 'v'},
+       {"all",         no_argument,       NULL, 'a'},
+       {"allow",       required_argument, NULL,  3 },
+       {"interfaces",  required_argument, NULL, 'i'},
+       {"exclude",     required_argument, NULL, 'e'},
+       {"no-act",      no_argument,       NULL, 'n'},
+       {"no-mappings", no_argument,       NULL,  1 },
+       {"force",       no_argument,       NULL,  2 },
+       {0,0,0,0}
+};
+@ 
+
+The usual way of dealing with options then is to have a variable to store
+the various things. The only special note here is that we need to export
+[[no_act]] and [[verbose]] to the [[execute]] module.
+
+<<exported symbols>>=
+extern int no_act;
+extern int verbose;
+@
+
+<<main global variables>>=
+int no_act = 0;
+int verbose = 0;
+@
+
+<<variables local to main>>=
+int do_all = 0;
+int run_mappings = 1;
+int force = 0;
+char *allow_class = NULL;
+char *interfaces = "/etc/network/interfaces";
+char *statefile = "/etc/network/run/ifstate";
+char *excludeint = NULL ;
+@ 
+
+We'll also have two helper functions to display usage information,
+like so:
+
+<<main function declarations>>=
+static void usage(char *execname);
+static void help(char *execname);
+static void version(char *execname);
+@ 
+
+<<main functions>>=
+static void usage(char *execname) {
+       fprintf(stderr, "%s: Use --help for help\n", execname);
+       exit(1);
+}
+@ 
+
+<<main functions>>=
+static void version(char *execname) {
+       printf("%s version " IFUPDOWN_VERSION "\n", execname);
+       printf("Copyright (c) 1999-2005 Anthony Towns\n\n");
+       printf(
+
+"This program is free software; you can redistribute it and/or modify\n"
+"it under the terms of the GNU General Public License as published by\n"
+"the Free Software Foundation; either version 2 of the License, or (at\n"
+"your option) any later version.\n"
+
+       );
+       exit(0);
+}
+@ 
+
+<<main functions>>=
+static void help(char *execname) {
+       printf("Usage: %s <options> <ifaces...>\n\n", execname);
+       printf("Options:\n");
+       printf("\t-h, --help\t\tthis help\n");
+       printf("\t-V, --version\t\tcopyright and version information\n");
+       printf("\t-a, --all\t\tde/configure all interfaces marked \"auto\"\n");
+       printf("\t--allow CLASS\t\tignore non-\"allow-CLASS\" interfaces\n");
+       printf("\t-i, --interfaces FILE\tuse FILE for interface definitions\n");
+       printf("\t-n, --no-act\t\tprint out what would happen, but don't do it\n");
+       printf("\t\t\t\t(note that this option doesn't disable mappings)\n");
+       printf("\t-v, --verbose\t\tprint out what would happen before doing it\n");
+       printf("\t--no-mappings\t\tdon't run any mappings\n");
+       printf("\t--force\t\t\tforce de/configuration\n");
+       exit(0);
+}
+@ 
+
+Now, the meat of argument parsing is done with [[getopt()]] and a
+[[switch]], like so:
+
+<<parse arguments>>=
+for(;;) {
+       int c;
+       c = getopt_long(argc, argv, "e:s:i:hVvna", long_opts, NULL);
+       if (c == EOF) break;
+
+       switch(c) {
+               <<[[getopt]] possibilities>>
+       }
+}
+
+<<check unreasonable arguments>>
+@ 
+
+Now, our [[getopt]] possibilities are basically each option, or something
+really bad. Actual interface names are automagically collected at the end
+by [[getopt()]].So first, the legitimate cases get handled:
+
+<<[[getopt]] possibilities>>=
+case 'i':
+       interfaces = strdup(optarg);
+       break;
+@ 
+<<[[getopt]] possibilities>>=
+case 'v':
+       verbose = 1;
+       break;
+@ 
+<<[[getopt]] possibilities>>=
+case 'a':
+       do_all = 1;
+       break;
+@ 
+<<[[getopt]] possibilities>>=
+case 3:
+       allow_class = strdup(optarg);
+       break;
+@ 
+<<[[getopt]] possibilities>>=
+case 'n':
+       no_act = 1;
+       break;
+@ 
+<<[[getopt]] possibilities>>=
+case 1:
+       run_mappings = 0;
+       break;
+@ 
+<<[[getopt]] possibilities>>=
+case 2:
+       force = 1;
+       break;
+@
+<<[[getopt]] possibilities>>=
+case 'e':
+       excludeint = strdup(optarg);
+       break;
+@ 
+
+And we also have a help option and a version option:
+
+<<[[getopt]] possibilities>>=
+case 'h':
+       help(argv[0]);
+       break;
+@ 
+<<[[getopt]] possibilities>>=
+case 'V':
+       version(argv[0]);
+       break;
+@ 
+
+And we also have the possibility that the user is just making up
+options:
+
+<<[[getopt]] possibilities>>=
+default:
+       usage(argv[0]);
+       break;
+@
+
+After all that there are still some things that can be a bit weird. We
+can be told either to act on all interfaces (except the noauto ones),
+or we can be told to act on specific interface. We won't accept been
+told to do both, and we won't accept not being told to do one or the
+other. We can test these two cases as follows:
+
+<<check unreasonable arguments>>=
+if (argc - optind > 0 && do_all) {
+       usage(argv[0]);
+}
+@ 
+
+<<check unreasonable arguments>>=
+if (argc - optind == 0 && !do_all) {
+       usage(argv[0]);
+}
+@ 
+
+\subsection{Reading the Interfaces File}
+
+Since this has all been covered in a previous section, this is pretty
+trivial.
+
+<<variables local to main>>=
+interfaces_file *defn;
+@ 
+
+<<read interfaces files or die>>=
+defn = read_interfaces(interfaces);
+if ( !defn ) {
+       fprintf(stderr, "%s: couldn't read interfaces file \"%s\"\n",
+               argv[0], interfaces);
+       exit(1);
+}
+@
+
+\subsection{Execution}
+
+A broad overview of what we'll actually be doing is as follows:
+
+<<run commands for appropriate interfaces>>=
+<<lock 'n load ifupdown state>>
+<<determine target interfaces>>
+{
+       int i;
+       for (<<each target interface, [[i]]>>) {
+               char iface[80], liface[80];
+
+               <<initialize [[iface]] to [[i]]th target interface>>
+               if (!force) {
+                       <<check ifupdown state (possibly [[continue]])>>
+               }
+
+               if (<<we're limiting to [[--allow]]ed interfaces>>) {
+                       <<find [[iface]] in [[allow_class]] or [[continue]]>>
+               }
+
+               if (<<we're [[--exclude]]ing this interface>>)  
+                       continue;
+
+               if (<<we're bringing interfaces up>> && run_mappings) {
+                       <<run mappings>>
+               }
+
+               <<bring interface up/down and update ifupdown state>>
+               <<commit ifupdown state>>
+       }
+}
+<<close ifupdown state>>
+@
+
+We'll leave determining the appropriate target interfaces and dealing
+with the state until a little later. That leaves us with covering running
+the mappings and bringing the interface up or taking it down.
+
+Mappings are dealt with like so:
+
+<<run mappings>>=
+{
+       mapping_defn *currmap;
+       for (currmap = defn->mappings; currmap; currmap = currmap->next) {
+               int i;
+               for (i = 0; i < currmap->n_matches; i++) {
+                       <<[[continue]] unless mapping matches>>
+                       <<run mapping>>
+                       break;
+               }
+       }
+}
+@
+
+We check if mappings match by using shell globs, so we'll need a new header
+to take care of that.
+
+<<main headers>>=
+#include <fnmatch.h>
+@ 
+
+<<[[continue]] unless mapping matches>>=
+if (fnmatch(currmap->match[i], liface, 0) != 0)
+       continue;
+@
+
+Actually running a mapping is fairly straightforward, thanks to our
+previous handywork.
+
+<<run mapping>>=
+if (verbose) {
+       fprintf(stderr, "Running mapping script %s on %s\n",
+               currmap->script, liface);
+}
+run_mapping(iface, liface, sizeof(liface), currmap);
+@
+
+Bringing an interface up or taking it down can be done thusly:
+
+<<bring interface up/down and update ifupdown state>>=
+{
+       interface_defn *currif;
+       int okay = 0;
+       int failed = 0; 
+       for (currif = defn->ifaces; currif; currif = currif->next) {
+               if (strcmp(liface, currif->logical_iface) == 0) {
+                       okay = 1;
+
+                       <<run commands for [[currif]]; set [[failed]] on error>>
+
+                       if (failed) break;
+                       /* Otherwise keep going: this interface may have
+                        * match with other address families */
+               }
+       }
+
+       if (!okay && !force) {
+               fprintf(stderr, "Ignoring unknown interface %s=%s.\n", 
+                       iface, liface);
+       } else {
+               <<update ifupdown state>>
+       }
+}
+@
+
+<<run commands for [[currif]]; set [[failed]] on error>>=
+{
+       currif->real_iface = iface;
+
+       if (verbose) {
+               fprintf(stderr, "Configuring interface %s=%s (%s)\n", 
+                       iface, liface, currif->address_family->name);
+       }
+
+       switch(cmds(currif)) {
+           case -1:
+               printf("Don't seem to be have all the variables for %s/%s.\n", 
+                       liface, currif->address_family->name);
+               failed = 1;
+               break;
+           case 0:
+               failed = 1;
+               break;
+               /* not entirely successful */
+           case 1:
+               failed = 0;
+               break;
+               /* successful */
+           default:
+               printf("Internal error while configuring interface %s/%s (assuming it failed)\n", 
+                       liface, currif->address_family->name);
+               failed = 1;
+               /* what happened here? */
+       }
+       currif->real_iface = NULL;
+}
+@ 
+
+\subsection{Target Interfaces}
+
+So, if we're going to actually do something, we should probably figure
+out exactly what we're going to do it to. So, we need to know the set
+of interfaces we're going to hax0r. This is just an array of interfaces,
+either [[physical_iface]] or [[physical_iface=logical_iface]].
+
+<<variables local to main>>=
+int n_target_ifaces;
+char **target_iface;
+@ 
+
+<<each target interface, [[i]]>>=
+i = 0; i < n_target_ifaces; i++
+@
+
+We initialise this based on our command line arguments.
+
+<<determine target interfaces>>=
+if (do_all) {
+       if (<<we're bringing interfaces up>>) {
+               allowup_defn *autos = find_allowup(defn, "auto");
+               target_iface = autos ? autos->interfaces : NULL;
+               n_target_ifaces = autos ? autos->n_interfaces : 0;
+       } else if (<<we're taking interfaces down>>) {
+               target_iface = state;
+               n_target_ifaces = n_state;
+       } else {
+               assert(0);
+       }       
+} else {
+       target_iface = argv + optind;
+       n_target_ifaces = argc - optind;
+}
+@ 
+
+<<initialize [[iface]] to [[i]]th target interface>>=
+strncpy(iface, target_iface[i], sizeof(iface));
+iface[sizeof(iface)-1] = '\0';
+
+{
+       char *pch;
+       if ((pch = strchr(iface, '='))) {
+               *pch = '\0';
+               strncpy(liface, pch+1, sizeof(liface));
+               liface[sizeof(liface)-1] = '\0';
+       } else {
+               strncpy(liface, iface, sizeof(liface));
+               liface[sizeof(liface)-1] = '\0';
+       }
+}
+@ 
+
+\subsection{State}
+
+Since it's generally not feasible to rerun a mapping script after an
+interface is configured (since a mapping script may well bring the
+interface down while it's investigating matters), we need to maintain a
+statefile between invocations to keep track of which physical interfaces
+were mapped to which logical ones. We ought to use 
+[[/var/run/ifupdown.state]] or something similar for this, but [[/var]]
+isn't guaranteed to be available until the network's up, so we'll use
+[[/etc/network/run/ifstate]] instead.
+
+<<variables local to main>>=
+char **state = NULL; /* list of iface=liface */
+int n_state = 0;
+int max_state = 0;
+@ 
+
+We'll also use two helper functions: one to lookup an interface, and one to
+add an interface.
+
+<<main function declarations>>=
+static int lookfor_iface(char **ifaces, int n_ifaces, char *iface);
+@ 
+
+<<main functions>>=
+static int lookfor_iface(char **ifaces, int n_ifaces, char *iface) {
+       int i;
+       for (i = 0; i < n_ifaces; i++) {
+               if (strncmp(iface, ifaces[i], strlen(iface)) == 0) {
+                       if (ifaces[i][strlen(iface)] == '=') {
+                               return i;
+                       }
+               }
+       }
+       return -1;
+}
+@ 
+
+<<main function declarations>>=
+static void add_to_state(char ***ifaces, int *n_ifaces, int *max_ifaces, 
+                         char *new_iface);
+@ 
+
+<<main functions>>=
+static void add_to_state(char ***ifaces, int *n_ifaces, int *max_ifaces, 
+                         char *new_iface)
+{
+       assert(*max_ifaces >= *n_ifaces);
+       if (*max_ifaces == *n_ifaces) {
+               *max_ifaces = (*max_ifaces * 2) + 1;
+               *ifaces = realloc(*ifaces, sizeof(**ifaces) * *max_ifaces);
+               if (*ifaces == NULL) {
+                       perror("realloc");
+                       exit(1);
+               }
+       }
+
+       (*ifaces)[(*n_ifaces)++] = new_iface;
+}
+@ 
+
+The state file is opened and locked, blocking parallel updates:
+
+<<main function declarations>>=
+static int lock_fd (int fd);
+@ 
+
+<<main functions>>=
+static int lock_fd (int fd) {
+       struct flock lock;
+
+       lock.l_type = F_WRLCK;
+       lock.l_whence = SEEK_SET;
+       lock.l_start = 0;
+       lock.l_len = 0;
+
+       if  (fcntl(fd, F_SETLKW, &lock) < 0) {
+               return -1;
+       }
+
+       return 0;
+}
+@ 
+
+
+<<variables local to main>>=
+static FILE *state_fp = NULL;
+@
+
+<<lock 'n load ifupdown state>>=
+{
+       state_fp = fopen(statefile, no_act ? "r" : "a+");
+       if (state_fp == NULL && !no_act) {
+               fprintf(stderr, 
+                       "%s: failed to open statefile %s: %s\n",
+                       argv[0], statefile, strerror(errno));
+               exit (1);
+       }
+
+       if (state_fp != NULL) {
+               char buf[80];
+               char *p;
+
+               if (!no_act) {
+                       int flags;
+
+                       if ((flags = fcntl(fileno(state_fp), F_GETFD)) < 0
+                           || fcntl(fileno(state_fp), F_SETFD, flags | FD_CLOEXEC) < 0) {
+                               fprintf(stderr, 
+                                       "%s: failed to set FD_CLOEXEC on statefile %s: %s\n",
+                                       argv[0], statefile, strerror(errno));
+                               exit(1);
+                       }
+
+                       if (lock_fd (fileno(state_fp)) < 0) {
+                               fprintf(stderr, 
+                                       "%s: failed to lock statefile %s: %s\n",
+                                       argv[0], statefile, strerror(errno));
+                               exit(1);
+                       }
+
+               }
+
+               rewind (state_fp);
+               while((p = fgets(buf, sizeof buf, state_fp)) != NULL) {
+                       char *pch;
+
+                       pch = buf + strlen(buf) - 1;
+                       while(pch > buf && isspace(*pch)) pch--;
+                       *(pch+1) = '\0';
+
+                       pch = buf;
+                       while(isspace(*pch)) pch++;
+
+                       add_to_state(&state, &n_state, &max_state, strdup(pch));
+               }
+       }
+}
+@
+
+<<close ifupdown state>>=
+if (state_fp != NULL) {
+       fclose(state_fp);
+       state_fp = NULL;
+}
+@
+
+
+<<commit ifupdown state>>=
+if (state_fp != NULL && !no_act) {
+       int i;
+
+       if (ftruncate(fileno(state_fp), 0) < 0)
+       {
+               fprintf(stderr, 
+                       "%s: failed to truncate statefile %s: %s\n",
+                       argv[0], statefile, strerror(errno));
+               exit(1);
+       }
+
+       rewind(state_fp);
+       for (i = 0; i < n_state; i++) {
+               fprintf(state_fp, "%s\n", state[i]);
+       }
+       fflush(state_fp);
+}
+@
+
+This leaves our two useful chunks. The first checks to ensure what we're
+proposing to do is reasonable (ie, we're not downing an interface that's
+not up, or uping one that's not down).
+
+<<check ifupdown state (possibly [[continue]])>>=
+{
+       int already_up = lookfor_iface(state, n_state, iface);;
+
+       if (<<we're bringing interfaces up>>) {
+               if (already_up != -1) {
+                       fprintf(stderr, 
+                               "%s: interface %s already configured\n",
+                               argv[0], iface);
+                       continue;
+               }
+       } else if (<<we're taking interfaces down>>) {
+               if (already_up == -1) {
+                       fprintf(stderr, "%s: interface %s not configured\n",
+                               argv[0], iface);
+                       continue;
+               }
+               strncpy(liface, strchr(state[already_up], '=') + 1, 80);
+               liface[79] = 0;
+       } else {
+               assert(0);
+       }
+}
+@ 
+
+And finally, we also need to be able to update the state as we bring
+interfaces up and down.
+
+<<update ifupdown state>>=
+{
+       int already_up = lookfor_iface(state, n_state, iface);
+
+       if (<<we're bringing interfaces up>>) {
+               char *newiface = 
+                       malloc(strlen(iface) + 1 + strlen(liface) + 1);
+               sprintf(newiface, "%s=%s", iface, liface);
+
+               if (already_up == -1) {
+                       if (failed == 1) {
+                               printf("Failed to bring up %s.\n", liface);
+                       } else {
+                               add_to_state(&state, &n_state, &max_state, newiface);
+                       }
+               } else {
+                       free(state[already_up]);
+                       state[already_up] = newiface;
+               }
+       } else if (<<we're taking interfaces down>>) {
+               if (already_up != -1) {
+                       state[already_up] = state[--n_state];
+               }
+       } else {
+               assert(0);
+       }
+}
+@ 
+
+\appendix
+
+\section{Linux Address Families}
+
+<<archlinux.h>>=
+unsigned int mylinuxver();
+unsigned int mylinux(int,int,int);
+int execable(char *);
+@
+
+<<archlinux.c>>=
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/utsname.h>
+#include <sys/stat.h>
+
+#include "archlinux.h"
+
+unsigned int mylinuxver() {
+       static int maj = -1, rev, min;
+
+       if (maj == -1) {
+               struct utsname u;
+               char *pch;
+               uname(&u);
+               maj = atoi(u.release);
+               pch = strchr(u.release, '.');
+               rev = atoi(pch+1);
+               pch = strchr(pch+1, '.');
+               min = atoi(pch+1);
+       }
+
+       return mylinux(maj,rev,min);
+}
+
+unsigned int mylinux(int maj, int rev, int min) { 
+       return min | rev << 10 | maj << 13;
+}
+
+int execable(char *program) {
+       struct stat buf;
+
+       if (0 == stat(program, &buf)) {
+               if (S_ISREG(buf.st_mode) && (S_IXUSR & buf.st_mode)) return 1;
+       }
+       return 0;
+}
+@ 
+
+\subsection{IPv4 Address Family}
+
+<<address family declarations>>=
+extern address_family addr_inet;
+@ 
+
+<<address family references>>=
+&addr_inet, 
+@ 
+
+<<inet.defn>>=
+address_family inet
+architecture linux
+
+<<inet methods>>
+@ 
+
+<<inet methods>>=
+method loopback
+  description
+    This method may be used to define the IPv4 loopback interface.
+
+  up
+    ifconfig %iface% 127.0.0.1 up
+    route add -net 127.0.0.0       if ( mylinuxver() < mylinux(2,1,100) )
+
+  down
+    ifconfig %iface% down
+@ 
+
+<<inet methods>>=
+method static
+  description
+    This method may be used to define ethernet interfaces with statically
+    allocated IPv4 addresses.
+      
+  options
+    address address             -- Address (dotted quad) *required*
+    netmask netmask             -- Netmask (dotted quad) *required*
+    broadcast broadcast_address -- Broadcast address (dotted quad)
+    network network_address     -- Network address (dotted quad) *required \
+                                     for 2.0.x kernels*
+    metric metric               -- Routing metric for default gateway (integer)
+    gateway address             -- Default gateway (dotted quad)
+    pointopoint address                -- Address of other end point (dotted quad). \
+                                  Note the spelling of "point-to".
+    media type                  -- Medium type, driver dependent
+    hwaddress class address     -- Hardware Address. /class/ is one of \
+                                     *ether*, *ax25*, *ARCnet* or *netrom*. \
+                                     /address/ is dependent on the above \
+                                     choice.
+    mtu size                    -- MTU size
+
+  up
+    [[ ifconfig %iface% hw %hwaddress%]]
+    ifconfig %iface% %address% netmask %netmask% [[broadcast %broadcast%]] \
+       [[pointopoint %pointopoint%]] [[media %media%]] [[mtu %mtu%]] \
+       up
+    route add -net %network%  \
+        if ( mylinuxver() < mylinux(2,1,100) )
+    [[ route add default gw %gateway% [[metric %metric%]] %iface% ]]
+
+  down
+    [[ route del default gw %gateway% [[metric %metric%]] %iface% ]]
+    ifconfig %iface% down
+@
+
+<<inet methods>>=
+method manual
+  description
+    This method may be used to define interfaces for which no configuration
+    is done by default.  Such interfaces can be configured manually by
+    means of *up* and *down* commands or /etc/network/if-*.d scripts.
+
+  up
+
+  down
+@ 
+
+<<inet methods>>=
+method dhcp
+  description
+    This method may be used to obtain an address via DHCP with any of
+    the tools: dhclient, pump, udhcpc, dhcpcd.
+    (They have been listed in their order of precedence.)
+    If you have a complicated DHCP setup you should
+    note that some of these clients use their own configuration files
+    and do not obtain their configuration information via *ifup*.
+
+  options
+    hostname hostname       -- Hostname to be requested (pump, dhcpcd, udhcpc)
+    leasehours leastime     -- Preferred lease time in hours (pump)
+    leasetime leasetime     -- Preferred lease time in seconds (dhcpcd)
+    vendor vendor           -- Vendor class identifier (dhcpcd)
+    client client_id        -- Client identifier (dhcpcd, udhcpc)
+    hwaddress class address -- Hardware Address. /class/ is one of \
+                                *ether*, *ax25*, *ARCnet* or *netrom*. \
+                                /address/ is dependent on this choice.
+
+  up
+    [[ifconfig %iface% hw %hwaddress%]]
+    dhclient3 -pf /var/run/dhclient.%iface%.pid -lf /var/run/dhclient.%iface%.leases %iface% \
+        if (execable("/sbin/dhclient3"))
+    dhclient -e -pf /var/run/dhclient.%iface%.pid -lf /var/run/dhclient.%iface%.leases %iface% \
+        elsif (execable("/sbin/dhclient"))
+    pump -i %iface% [[-h %hostname%]] [[-l %leasehours%]] \
+        elsif (execable("/sbin/pump") && mylinuxver() >= mylinux(2,1,100))
+    udhcpc -n -p /var/run/udhcpc.%iface%.pid -i %iface% [[-H %hostname%]] \
+           [[-c %clientid%]] \
+        elsif (execable("/sbin/udhcpc") && mylinuxver() >= mylinux(2,2,0))
+    dhcpcd [[-h %hostname%]] [[-i %vendor%]] [[-I %clientid%]] \
+           [[-l %leasetime%]] %iface% \
+        elsif (execable("/sbin/dhcpcd"))
+
+  down
+    dhclient3 -r -pf /var/run/dhclient.%iface%.pid -lf /var/run/dhclient.%iface%.leases %iface% \
+        if (execable("/sbin/dhclient3"))
+    cat /var/run/dhclient.%iface%.pid | xargs -i kill -TERM {} \
+        elsif (execable("/sbin/dhclient"))
+    pump -i %iface% -r \
+        elsif (execable("/sbin/pump") && mylinuxver() >= mylinux(2,1,100))
+    cat /var/run/udhcpc.%iface%.pid | xargs -i kill -TERM {} \
+        elsif (execable("/sbin/udhcpc"))
+    dhcpcd -k %iface% \
+        elsif (execable("/sbin/dhcpcd"))
+
+    ifconfig %iface% down
+@ 
+
+<<inet methods>>=
+method bootp
+  description
+    This method may be used to obtain an address via bootp.
+
+  options
+    bootfile file  -- Tell the server to use /file/ as the bootfile.
+    server address -- Use the IP address /address/ to communicate with \
+                      the server.
+    hwaddr addr    -- Use /addr/ as the hardware address instead of \
+                      whatever it really is.
+
+  up
+    bootpc [[--bootfile %bootfile%]] --dev %iface% [[--server %server%]] \
+           [[--hwaddr %hwaddr%]] --returniffail --serverbcast
+
+  down
+    ifconfig down %iface%
+@ 
+
+<<inet methods>>=
+method ppp
+  description
+    This method uses pon/poff to configure a PPP interface. See those
+    commands for details.
+  options
+    provider name  -- Use /name/ as the provider (from /etc/ppp/peers).
+  up
+    pon [[%provider%]]
+  down
+    poff [[%provider%]]
+@ 
+
+<<inet methods>>=
+method wvdial
+  description
+    This method uses wvdial to configure a PPP interface. See that command
+    for more details.
+  options
+    provider name  -- Use /name/ as the provider (from /etc/ppp/peers).
+  up
+    /sbin/start-stop-daemon --start -x /usr/bin/wvdial \
+                      -p /var/run/wvdial.%iface% -b -m -- [[ %provider% ]]
+  down
+    /sbin/start-stop-daemon --stop -x /usr/bin/wvdial \
+                      -p /var/run/wvdial.%iface% -s 2
+@
+
+
+
+
+\subsection{IPv6 Address Family}
+
+<<address family declarations>>=
+extern address_family addr_inet6;
+@ 
+
+<<address family references>>=
+&addr_inet6,
+@ 
+
+<<inet6.defn>>=
+address_family inet6
+architecture linux
+
+method loopback
+  description
+    This method may be used to define the IPv6 loopback interface.
+  up
+    ifconfig %iface% add ::1
+  down
+    ifconfig %iface% del ::1
+
+method static
+  description
+    This method may be used to define interfaces with statically assigned
+    IPv6 addresses.
+
+  options
+    address address        -- Address (colon delimited) *required*
+    netmask mask           -- Netmask (number of bits, eg 64) *required*
+    gateway address        -- Default gateway (colon delimited)
+    media type             -- Medium type, driver dependent
+    hwaddress class address -- Hardware Address. /class/ is one of \
+                                 *ether*, *ax25*, *ARCnet* or *netrom*. \
+                                 /address/ is dependent on this choice.
+    mtu size               -- MTU size
+  up
+    ifconfig %iface% [[media %media%]] [[hw %hwaddress%]] [[mtu %mtu%]] up
+    ifconfig %iface% add %address%/%netmask%
+    [[ route -A inet6 add ::/0 gw %gateway% ]] 
+
+  down
+    ifconfig %iface% down
+
+method v4tunnel
+  description
+    This method may be used to setup an IPv6-over-IPv4 tunnel. It requires
+    the *ip* command from the *iproute* package.
+
+  options
+    address address       -- Address (colon delimited)
+    netmask mask          -- Netmask (number of bits, eg 64) 
+    endpoint address      -- Address of other tunnel endpoint (IPv4 \
+                             dotted quad) *required*
+    local address         -- Address of the local endpoint (IPv4 \
+                             dotted quad)
+    gateway address       -- Default gateway (colon delimited)
+    ttl time              -- TTL setting
+
+  up
+    ip tunnel add %iface% mode sit remote %endpoint% [[local %local%]] \
+       [[ttl %ttl%]]
+    ip link set %iface% up
+    [[ ip addr add %address%/%netmask% dev %iface% ]]
+    [[ ip route add %gateway% dev %iface% ]]
+    [[ ip route add ::/0 via %gateway% dev %iface% ]]
+
+  down
+    ip tunnel del %iface%
+@ 
+
+\subsection{IPX Address Family}
+
+<<address family declarations>>=
+extern address_family addr_ipx;
+@ 
+
+<<address family references>>=
+&addr_ipx,
+@ 
+
+<<ipx.defn>>=
+address_family ipx
+architecture linux
+
+method static
+  description
+    This method may be used to setup an IPX interface.  It requires the
+    /ipx_interface/ command.
+
+  options
+    frame type             -- /type/ of ethernet frames to use (e.g. *802.2*)
+    netnum id              -- Network number
+
+  up
+    ipx_interface add %iface% %frame% %netnum%
+
+  down
+    ipx_interface del %iface% %frame%
+
+method dynamic
+  description
+    This method may be used to setup an IPX interface dynamically.
+
+  options
+    frame type             -- /type/ of ethernet frames to use (e.g. *802.2*)
+
+  up
+    ipx_interface add %iface% %frame%
+
+  down
+    ipx_interface del %iface% %frame%
+@ 
+
+\begin{flushleft}
+\bibliography{biblio}
+\bibliographystyle{unsrt}
+\end{flushleft}
+
+\end{document}
diff --git a/inet.defn b/inet.defn
new file mode 100644 (file)
index 0000000..e3f22bd
--- /dev/null
+++ b/inet.defn
@@ -0,0 +1,142 @@
+address_family inet
+architecture linux
+
+method loopback
+  description
+    This method may be used to define the IPv4 loopback interface.
+
+  up
+    ifconfig %iface% 127.0.0.1 up
+    route add -net 127.0.0.0       if ( mylinuxver() < mylinux(2,1,100) )
+
+  down
+    ifconfig %iface% down
+method static
+  description
+    This method may be used to define ethernet interfaces with statically
+    allocated IPv4 addresses.
+      
+  options
+    address address             -- Address (dotted quad) *required*
+    netmask netmask             -- Netmask (dotted quad) *required*
+    broadcast broadcast_address -- Broadcast address (dotted quad)
+    network network_address     -- Network address (dotted quad) *required \
+                                     for 2.0.x kernels*
+    metric metric               -- Routing metric for default gateway (integer)
+    gateway address             -- Default gateway (dotted quad)
+    pointopoint address                -- Address of other end point (dotted quad). \
+                                  Note the spelling of "point-to".
+    media type                  -- Medium type, driver dependent
+    hwaddress class address     -- Hardware Address. /class/ is one of \
+                                     *ether*, *ax25*, *ARCnet* or *netrom*. \
+                                     /address/ is dependent on the above \
+                                     choice.
+    mtu size                    -- MTU size
+
+  up
+    [[ ifconfig %iface% hw %hwaddress%]]
+    ifconfig %iface% %address% netmask %netmask% [[broadcast %broadcast%]] \
+       [[pointopoint %pointopoint%]] [[media %media%]] [[mtu %mtu%]] \
+       up
+    route add -net %network%  \
+        if ( mylinuxver() < mylinux(2,1,100) )
+    [[ route add default gw %gateway% [[metric %metric%]] %iface% ]]
+
+  down
+    [[ route del default gw %gateway% [[metric %metric%]] %iface% ]]
+    ifconfig %iface% down
+method manual
+  description
+    This method may be used to define interfaces for which no configuration
+    is done by default.  Such interfaces can be configured manually by
+    means of *up* and *down* commands or /etc/network/if-*.d scripts.
+
+  up
+
+  down
+method dhcp
+  description
+    This method may be used to obtain an address via DHCP with any of
+    the tools: dhclient, pump, udhcpc, dhcpcd.
+    (They have been listed in their order of precedence.)
+    If you have a complicated DHCP setup you should
+    note that some of these clients use their own configuration files
+    and do not obtain their configuration information via *ifup*.
+
+  options
+    hostname hostname       -- Hostname to be requested (pump, dhcpcd, udhcpc)
+    leasehours leastime     -- Preferred lease time in hours (pump)
+    leasetime leasetime     -- Preferred lease time in seconds (dhcpcd)
+    vendor vendor           -- Vendor class identifier (dhcpcd)
+    client client_id        -- Client identifier (dhcpcd, udhcpc)
+    hwaddress class address -- Hardware Address. /class/ is one of \
+                                *ether*, *ax25*, *ARCnet* or *netrom*. \
+                                /address/ is dependent on this choice.
+
+  up
+    [[ifconfig %iface% hw %hwaddress%]]
+    dhclient3 -pf /var/run/dhclient.%iface%.pid -lf /var/run/dhclient.%iface%.leases %iface% \
+        if (execable("/sbin/dhclient3"))
+    dhclient -e -pf /var/run/dhclient.%iface%.pid -lf /var/run/dhclient.%iface%.leases %iface% \
+        elsif (execable("/sbin/dhclient"))
+    pump -i %iface% [[-h %hostname%]] [[-l %leasehours%]] \
+        elsif (execable("/sbin/pump") && mylinuxver() >= mylinux(2,1,100))
+    udhcpc -n -p /var/run/udhcpc.%iface%.pid -i %iface% [[-H %hostname%]] \
+           [[-c %clientid%]] \
+        elsif (execable("/sbin/udhcpc") && mylinuxver() >= mylinux(2,2,0))
+    dhcpcd [[-h %hostname%]] [[-i %vendor%]] [[-I %clientid%]] \
+           [[-l %leasetime%]] %iface% \
+        elsif (execable("/sbin/dhcpcd"))
+
+  down
+    dhclient3 -r -pf /var/run/dhclient.%iface%.pid -lf /var/run/dhclient.%iface%.leases %iface% \
+        if (execable("/sbin/dhclient3"))
+    cat /var/run/dhclient.%iface%.pid | xargs -i kill -TERM {} \
+        elsif (execable("/sbin/dhclient"))
+    pump -i %iface% -r \
+        elsif (execable("/sbin/pump") && mylinuxver() >= mylinux(2,1,100))
+    cat /var/run/udhcpc.%iface%.pid | xargs -i kill -TERM {} \
+        elsif (execable("/sbin/udhcpc"))
+    dhcpcd -k %iface% \
+        elsif (execable("/sbin/dhcpcd"))
+
+    ifconfig %iface% down
+method bootp
+  description
+    This method may be used to obtain an address via bootp.
+
+  options
+    bootfile file  -- Tell the server to use /file/ as the bootfile.
+    server address -- Use the IP address /address/ to communicate with \
+                      the server.
+    hwaddr addr    -- Use /addr/ as the hardware address instead of \
+                      whatever it really is.
+
+  up
+    bootpc [[--bootfile %bootfile%]] --dev %iface% [[--server %server%]] \
+           [[--hwaddr %hwaddr%]] --returniffail --serverbcast
+
+  down
+    ifconfig down %iface%
+method ppp
+  description
+    This method uses pon/poff to configure a PPP interface. See those
+    commands for details.
+  options
+    provider name  -- Use /name/ as the provider (from /etc/ppp/peers).
+  up
+    pon [[%provider%]]
+  down
+    poff [[%provider%]]
+method wvdial
+  description
+    This method uses wvdial to configure a PPP interface. See that command
+    for more details.
+  options
+    provider name  -- Use /name/ as the provider (from /etc/ppp/peers).
+  up
+    /sbin/start-stop-daemon --start -x /usr/bin/wvdial \
+                      -p /var/run/wvdial.%iface% -b -m -- [[ %provider% ]]
+  down
+    /sbin/start-stop-daemon --stop -x /usr/bin/wvdial \
+                      -p /var/run/wvdial.%iface% -s 2
diff --git a/inet6.defn b/inet6.defn
new file mode 100644 (file)
index 0000000..21da846
--- /dev/null
@@ -0,0 +1,58 @@
+address_family inet6
+architecture linux
+
+method loopback
+  description
+    This method may be used to define the IPv6 loopback interface.
+  up
+    ifconfig %iface% add ::1
+  down
+    ifconfig %iface% del ::1
+
+method static
+  description
+    This method may be used to define interfaces with statically assigned
+    IPv6 addresses.
+
+  options
+    address address        -- Address (colon delimited) *required*
+    netmask mask           -- Netmask (number of bits, eg 64) *required*
+    gateway address        -- Default gateway (colon delimited)
+    media type             -- Medium type, driver dependent
+    hwaddress class address -- Hardware Address. /class/ is one of \
+                                 *ether*, *ax25*, *ARCnet* or *netrom*. \
+                                 /address/ is dependent on this choice.
+    mtu size               -- MTU size
+  up
+    ifconfig %iface% [[media %media%]] [[hw %hwaddress%]] [[mtu %mtu%]] up
+    ifconfig %iface% add %address%/%netmask%
+    [[ route -A inet6 add ::/0 gw %gateway% ]] 
+
+  down
+    ifconfig %iface% down
+
+method v4tunnel
+  description
+    This method may be used to setup an IPv6-over-IPv4 tunnel. It requires
+    the *ip* command from the *iproute* package.
+
+  options
+    address address       -- Address (colon delimited)
+    netmask mask          -- Netmask (number of bits, eg 64) 
+    endpoint address      -- Address of other tunnel endpoint (IPv4 \
+                             dotted quad) *required*
+    local address         -- Address of the local endpoint (IPv4 \
+                             dotted quad)
+    gateway address       -- Default gateway (colon delimited)
+    ttl time              -- TTL setting
+
+  up
+    ip tunnel add %iface% mode sit remote %endpoint% [[local %local%]] \
+       [[ttl %ttl%]]
+    ip link set %iface% up
+    [[ ip addr add %address%/%netmask% dev %iface% ]]
+    [[ ip route add %gateway% dev %iface% ]]
+    [[ ip route add ::/0 via %gateway% dev %iface% ]]
+
+  down
+    ip tunnel del %iface%
diff --git a/interfaces.5.pre b/interfaces.5.pre
new file mode 100644 (file)
index 0000000..c550e51
--- /dev/null
@@ -0,0 +1,271 @@
+.\" -*- nroff -*-
+.\" macros
+.de EX \" Begin Example
+.  IP
+.  ft CW
+.  nf
+.  ne \\$1
+..
+.de EE \" End Example
+.  ft P
+.  fi
+.  PP
+..
+.TH INTERFACES 5 "5 April 2004" "ifupdown" "File formats"
+.SH NAME
+/etc/network/interfaces \- network interface configuration for ifup and ifdown 
+.SH DESCRIPTION
+/etc/network/interfaces contains network interface configuration
+information for the
+.BR ifup (8)
+and
+.BR ifdown (8)
+commands.
+This is where you configure how your system is connected to the network.
+.P
+Lines starting with `#' are ignored. Note that end-of-line comments are
+NOT supported, comments must be on a line of their own.
+.P
+A line may be extended across multiple lines by making the last character
+a backslash.
+.P
+The file consists of zero or more "iface", "mapping", "auto" and "allow-"
+stanzas. Here is an example.
+.EX
+auto lo eth0
+allow-hotplug eth1
+
+iface lo inet loopback
+
+mapping eth0 
+       script /usr/local/sbin/map\-scheme
+       map HOME eth0\-home
+       map WORK eth0\-work
+
+iface eth0\-home inet static
+       address 192.168.1.1
+       netmask 255.255.255.0
+       up flush\-mail
+
+iface eth0\-work inet dhcp
+
+iface eth1 inet dhcp
+.EE
+Lines beginning with the word "auto" are used to identify the physical
+interfaces to be brought up when
+.B ifup
+is run with the
+.B \-a
+option.  (This option is used by the system boot scripts.)
+Physical interface names should follow the word "auto" on the same line.
+There can be multiple "auto" stanzas.
+.B ifup
+brings the named interfaces up in the order listed.
+.P
+Lines beginning with "allow-" are used to identify interfaces that should
+be brought up automatically by various subsytems. This may be done using
+a command such as "ifup --allow=hotplug eth0 eth1", which will only bring
+up eth0 or eth1 if it is listed in an "allow-hotplug" line. Note that
+"allow-auto" and "auto" are synonyms.
+.P
+Stanzas beginning with the word "mapping" are used to determine how a
+logical interface name is chosen for a physical interface that is to be
+brought up.  The first line of a mapping stanza consists of the word
+"mapping" followed by a pattern in shell glob syntax.  Each mapping stanza
+must contain a
+.BR script
+definition.  The named script is run with the physical interface name as
+its argument and with the contents of all following "map" lines 
+(\fBwithout\fR the leading "map") in the
+stanza provided to it on its standard input. The script must print a
+string on its standard output before exiting. See 
+.IR /usr/share/doc/ifupdown/examples
+for examples of what the script must print.
+.P
+Mapping a name consists of searching the remaining mapping
+patterns and running the script corresponding to the first match;
+the script outputs the name to which the original is mapped.
+.P
+.B ifup
+is normally given a physical interface name as its first non\-option argument.
+.B ifup
+also uses this name as the initial logical name for the interface unless
+it is accompanied by a  suffix of the form \fI=LOGICAL\fR, in which case
+ifup chooses \fILOGICAL\fR as the initial logical name for the interface.
+It then maps this name, possibly more than once according to successive
+mapping specifications,  until no further mappings are possible.  If the
+resulting name is the name of some defined logical interface then
+.B ifup 
+attempts to bring up the physical interface
+as that logical interface.  Otherwise
+.B ifup
+exits with an error.
+.P
+Stanzas defining logical interfaces start with a line consisting of the
+word "iface" followed by the name of the logical interface.
+In simple configurations without mapping stanzas this name should simply
+be the name of the physical interface to which it is to be applied.
+(The default mapping script is, in effect, the
+.B echo
+command.)
+The interface name is followed by the name of the address family that the
+interface uses.  This will be "inet" for TCP/IP networking, but there is
+also some support for IPX networking ("ipx"), and IPv6 networking ("inet6").
+Following that is the name of the method used to configure the interface.
+.P
+Additional options can be given on subsequent lines in the stanza.
+Which options are available depends on the family and method,
+as described below.
+Additional options can be made available by other Debian packages.
+For example, the wireless\-tools package makes available a number of
+options prefixed with "wireless\-" which can be used to configure the
+interface using
+.BR iwconfig (8) .
+(See
+.BR wireless (7)
+for details.)
+.P
+Options are usually indented for clarity (as in the example above)
+but are not required to be.
+.SH IFACE OPTIONS
+The following "command" options are available for every family and method.
+Each of these options can be given multiple times in a single stanza,
+in which case the commands are executed in the order in which they appear
+in the stanza.
+(You can ensure a command never fails by suffixing "|| true".)
+.TP
+.BI pre\-up " command"
+Run
+.I command
+before bringing the interface up.
+If this command fails then
+.B ifup
+aborts,
+refraining from marking the interface as configured,
+prints an error message,
+and exits with status 0.
+This behavior may change in the future.
+.TP
+.BI up " command" 
+.TP
+.BI post\-up " command"
+Run
+.I command
+after bringing the interface up.
+If this command fails then
+.B ifup
+aborts,
+refraining from marking the interface as configured
+(even though it has really been configured),
+prints an error message,
+and exits with status 0.
+This behavior may change in the future.
+.TP
+.BI down " command"
+.TP
+.BI pre\-down " command"
+Run
+.I command
+before taking the interface down.
+If this command fails then
+.B ifdown
+aborts,
+marks the interface as deconfigured
+(even though it has not really been deconfigured),
+and exits with status 0.
+This behavior may change in the future.
+.TP
+.BI post\-down " command"
+Run
+.I command
+after taking the interface down.
+If this command fails then
+.B ifdown
+aborts,
+marks the interface as deconfigured,
+and exits with status 0.
+This behavior may change in the future.
+.P
+There exists for each of the above mentioned options a directory
+.IR /etc/network/if\-\fB<option>\fI.d/ 
+the scripts in which are run (with no arguments) using
+.BR run\-parts (8)
+after the option itself has been processed.
+.P
+All of these commands have access to the following environment variables.
+.TP
+.B IFACE
+physical name of the interface being processed
+.TP
+.B LOGICAL
+logical name of the interface being processed
+.TP
+.B ADDRFAM
+address family of the interface
+.TP
+.B METHOD
+method of the interface (e.g.,
+.IR static )
+.TP
+.B MODE
+.IR start " if run from ifup, " stop " if run from ifdown"
+.TP
+.B PHASE 
+as per MODE, but with finer granularity, distinguishing the
+\fIpre-up\fR, \fIpost-up\fR, \fIpre-down\fR and \fIpost-down\fR phases.
+.TP
+.B VERBOSITY
+indicates whether \fB--verbose\fR was used; set to 1 if so, 0 if not.
+.TP
+.B PATH
+the command search path:
+.I /usr/local/sbin:\%/usr/local/bin:\%/usr/sbin:\%/usr/bin:\%/sbin:\%/bin
+.P
+Additionally, all options given in an interface definition stanza are
+exported to the environment in upper case with "IF_" prepended and with
+hyphens converted to underscores and non\-alphanumeric characters discarded.
+##ADDRESSFAM##
+.SH KNOWN BUGS/LIMITATIONS
+The
+.B ifup
+and
+.B ifdown
+programs work with so-called "physical" interface names.
+These names are assigned to hardware by the kernel.
+Unfortunately it can happen that the kernel assigns different
+physical interface names to the same hardware at different
+times; for example, what was called "eth0" last time you booted
+is now called "eth1" and vice versa.
+This creates a problem if you want to configure the interfaces
+appropriately.
+A way to deal with this problem is to use mapping scripts that
+choose logical interface names according to the properties of
+the interface hardware.
+See the
+.B get-mac-address.sh
+script in the examples directory for an example of such a mapping
+script.  See also Debian bug #101728.
+.P
+It is not currently possible to divide up
+.B /etc/network/interfaces 
+into multiple files.  A feature that would make this possible is
+some sort of inclusion directive.  No such feature exists in the
+current ifupdown program.  For more information see Debian
+bug #159884.
+.SH AUTHOR
+The ifupdown suite was written by Anthony Towns <aj@azure.humbug.org.au>.
+This manpage was contributed by Joey Hess <joey@kitenet.net>.
+.SH "SEE ALSO"
+.BR ifup (8),
+.BR iwconfig (8),
+.BR run\-parts (8).
+.P
+For advice on configuring this package read the
+.B Network Configuration
+chapter of the \fIDebian Reference\fR manual,
+available at
+\fIhttp://www.debian.org/doc/manuals/reference/ch-gateway.en.html\fR
+or in the \fBdebian-reference-en\fR package.
+.P
+Examples of how to set up interfaces can be found in
+.BR /usr/share/doc/ifupdown/examples/network-interfaces .
diff --git a/ipx.defn b/ipx.defn
new file mode 100644 (file)
index 0000000..b956abd
--- /dev/null
+++ b/ipx.defn
@@ -0,0 +1,30 @@
+address_family ipx
+architecture linux
+
+method static
+  description
+    This method may be used to setup an IPX interface.  It requires the
+    /ipx_interface/ command.
+
+  options
+    frame type             -- /type/ of ethernet frames to use (e.g. *802.2*)
+    netnum id              -- Network number
+
+  up
+    ipx_interface add %iface% %frame% %netnum%
+
+  down
+    ipx_interface del %iface% %frame%
+
+method dynamic
+  description
+    This method may be used to setup an IPX interface dynamically.
+
+  options
+    frame type             -- /type/ of ethernet frames to use (e.g. *802.2*)
+
+  up
+    ipx_interface add %iface% %frame%
+
+  down
+    ipx_interface del %iface% %frame%
diff --git a/main.c b/main.c
new file mode 100644 (file)
index 0000000..c3f7a73
--- /dev/null
+++ b/main.c
@@ -0,0 +1,599 @@
+#line 2972 "ifupdown.nw"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "header.h"
+#line 3011 "ifupdown.nw"
+#include <unistd.h>
+#include <fcntl.h>
+#line 3137 "ifupdown.nw"
+#include <getopt.h>
+#line 3409 "ifupdown.nw"
+#include <fnmatch.h>
+#line 3166 "ifupdown.nw"
+int no_act = 0;
+int verbose = 0;
+#line 3184 "ifupdown.nw"
+static void usage(char *execname);
+static void help(char *execname);
+static void version(char *execname);
+#line 3563 "ifupdown.nw"
+static int lookfor_iface(char **ifaces, int n_ifaces, char *iface);
+#line 3581 "ifupdown.nw"
+static void add_to_state(char ***ifaces, int *n_ifaces, int *max_ifaces, 
+                         char *new_iface);
+#line 3606 "ifupdown.nw"
+static int lock_fd (int fd);
+#line 3190 "ifupdown.nw"
+static void usage(char *execname) {
+       fprintf(stderr, "%s: Use --help for help\n", execname);
+       exit(1);
+}
+#line 3197 "ifupdown.nw"
+static void version(char *execname) {
+       printf("%s version " IFUPDOWN_VERSION "\n", execname);
+       printf("Copyright (c) 1999-2005 Anthony Towns\n\n");
+       printf(
+
+"This program is free software; you can redistribute it and/or modify\n"
+"it under the terms of the GNU General Public License as published by\n"
+"the Free Software Foundation; either version 2 of the License, or (at\n"
+"your option) any later version.\n"
+
+       );
+       exit(0);
+}
+#line 3213 "ifupdown.nw"
+static void help(char *execname) {
+       printf("Usage: %s <options> <ifaces...>\n\n", execname);
+       printf("Options:\n");
+       printf("\t-h, --help\t\tthis help\n");
+       printf("\t-V, --version\t\tcopyright and version information\n");
+       printf("\t-a, --all\t\tde/configure all interfaces marked \"auto\"\n");
+       printf("\t--allow CLASS\t\tignore non-\"allow-CLASS\" interfaces\n");
+       printf("\t-i, --interfaces FILE\tuse FILE for interface definitions\n");
+       printf("\t-n, --no-act\t\tprint out what would happen, but don't do it\n");
+       printf("\t\t\t\t(note that this option doesn't disable mappings)\n");
+       printf("\t-v, --verbose\t\tprint out what would happen before doing it\n");
+       printf("\t--no-mappings\t\tdon't run any mappings\n");
+       printf("\t--force\t\t\tforce de/configuration\n");
+       exit(0);
+}
+#line 3567 "ifupdown.nw"
+static int lookfor_iface(char **ifaces, int n_ifaces, char *iface) {
+       int i;
+       for (i = 0; i < n_ifaces; i++) {
+               if (strncmp(iface, ifaces[i], strlen(iface)) == 0) {
+                       if (ifaces[i][strlen(iface)] == '=') {
+                               return i;
+                       }
+               }
+       }
+       return -1;
+}
+#line 3586 "ifupdown.nw"
+static void add_to_state(char ***ifaces, int *n_ifaces, int *max_ifaces, 
+                         char *new_iface)
+{
+       assert(*max_ifaces >= *n_ifaces);
+       if (*max_ifaces == *n_ifaces) {
+               *max_ifaces = (*max_ifaces * 2) + 1;
+               *ifaces = realloc(*ifaces, sizeof(**ifaces) * *max_ifaces);
+               if (*ifaces == NULL) {
+                       perror("realloc");
+                       exit(1);
+               }
+       }
+
+       (*ifaces)[(*n_ifaces)++] = new_iface;
+}
+#line 3610 "ifupdown.nw"
+static int lock_fd (int fd) {
+       struct flock lock;
+
+       lock.l_type = F_WRLCK;
+       lock.l_whence = SEEK_SET;
+       lock.l_start = 0;
+       lock.l_len = 0;
+
+       if  (fcntl(fd, F_SETLKW, &lock) < 0) {
+               return -1;
+       }
+
+       return 0;
+}
+#line 2989 "ifupdown.nw"
+int main(int argc, char **argv) {
+       
+#line 3047 "ifupdown.nw"
+int (*cmds)(interface_defn *) = NULL;
+#line 3141 "ifupdown.nw"
+struct option long_opts[] = {
+       {"help",        no_argument,       NULL, 'h'},
+       {"version",     no_argument,       NULL, 'V'},
+       {"verbose",     no_argument,       NULL, 'v'},
+       {"all",         no_argument,       NULL, 'a'},
+       {"allow",       required_argument, NULL,  3 },
+       {"interfaces",  required_argument, NULL, 'i'},
+       {"exclude",     required_argument, NULL, 'e'},
+       {"no-act",      no_argument,       NULL, 'n'},
+       {"no-mappings", no_argument,       NULL,  1 },
+       {"force",       no_argument,       NULL,  2 },
+       {0,0,0,0}
+};
+#line 3171 "ifupdown.nw"
+int do_all = 0;
+int run_mappings = 1;
+int force = 0;
+char *allow_class = NULL;
+char *interfaces = "/etc/network/interfaces";
+char *statefile = "/etc/network/run/ifstate";
+char *excludeint = NULL ;
+#line 3338 "ifupdown.nw"
+interfaces_file *defn;
+#line 3497 "ifupdown.nw"
+int n_target_ifaces;
+char **target_iface;
+#line 3554 "ifupdown.nw"
+char **state = NULL; /* list of iface=liface */
+int n_state = 0;
+int max_state = 0;
+#line 3628 "ifupdown.nw"
+static FILE *state_fp = NULL;
+
+#line 2992 "ifupdown.nw"
+       
+#line 3016 "ifupdown.nw"
+{
+       int i;
+       for (i = 0; i <= 2; i++) {
+               if (fcntl(i, F_GETFD) == -1) {
+                       if (errno == EBADF && open("/dev/null", 0) == -1) {
+                               fprintf(stderr,
+                                       "%s: fd %d not available; aborting\n",
+                                       argv[0], i);
+                               exit(2);
+                       } else if (errno == EBADF) {
+                               errno = 0; /* no more problems */
+                       } else {
+                               /* some other problem -- eeek */
+                               perror(argv[0]);
+                               exit(2);
+                       }
+               }
+       }
+}
+
+#line 2994 "ifupdown.nw"
+       
+#line 3053 "ifupdown.nw"
+{
+       char *command;
+
+       
+#line 3064 "ifupdown.nw"
+if ((command = strrchr(argv[0],'/'))) {
+       command++; /* first char after / */
+} else {
+       command = argv[0]; /* no /'s in argv[0] */
+}
+#line 3057 "ifupdown.nw"
+       
+#line 3072 "ifupdown.nw"
+if (strcmp(command, "ifup")==0) {
+       cmds = iface_up;
+} else if (strcmp(command, "ifdown")==0) {
+       cmds = iface_down;
+} else {
+       fprintf(stderr,"This command should be called as ifup or ifdown\n");
+       exit(1);
+}
+#line 3058 "ifupdown.nw"
+}
+#line 2995 "ifupdown.nw"
+       
+#line 3234 "ifupdown.nw"
+for(;;) {
+       int c;
+       c = getopt_long(argc, argv, "e:s:i:hVvna", long_opts, NULL);
+       if (c == EOF) break;
+
+       switch(c) {
+               
+#line 3252 "ifupdown.nw"
+case 'i':
+       interfaces = strdup(optarg);
+       break;
+#line 3257 "ifupdown.nw"
+case 'v':
+       verbose = 1;
+       break;
+#line 3262 "ifupdown.nw"
+case 'a':
+       do_all = 1;
+       break;
+#line 3267 "ifupdown.nw"
+case 3:
+       allow_class = strdup(optarg);
+       break;
+#line 3272 "ifupdown.nw"
+case 'n':
+       no_act = 1;
+       break;
+#line 3277 "ifupdown.nw"
+case 1:
+       run_mappings = 0;
+       break;
+#line 3282 "ifupdown.nw"
+case 2:
+       force = 1;
+       break;
+#line 3287 "ifupdown.nw"
+case 'e':
+       excludeint = strdup(optarg);
+       break;
+#line 3295 "ifupdown.nw"
+case 'h':
+       help(argv[0]);
+       break;
+#line 3300 "ifupdown.nw"
+case 'V':
+       version(argv[0]);
+       break;
+#line 3309 "ifupdown.nw"
+default:
+       usage(argv[0]);
+       break;
+#line 3241 "ifupdown.nw"
+       }
+}
+
+#line 3321 "ifupdown.nw"
+if (argc - optind > 0 && do_all) {
+       usage(argv[0]);
+}
+#line 3327 "ifupdown.nw"
+if (argc - optind == 0 && !do_all) {
+       usage(argv[0]);
+}
+
+#line 2997 "ifupdown.nw"
+       
+#line 3342 "ifupdown.nw"
+defn = read_interfaces(interfaces);
+if ( !defn ) {
+       fprintf(stderr, "%s: couldn't read interfaces file \"%s\"\n",
+               argv[0], interfaces);
+       exit(1);
+}
+
+#line 2999 "ifupdown.nw"
+       
+#line 3632 "ifupdown.nw"
+{
+       state_fp = fopen(statefile, no_act ? "r" : "a+");
+       if (state_fp == NULL && !no_act) {
+               fprintf(stderr, 
+                       "%s: failed to open statefile %s: %s\n",
+                       argv[0], statefile, strerror(errno));
+               exit (1);
+       }
+
+       if (state_fp != NULL) {
+               char buf[80];
+               char *p;
+
+               if (!no_act) {
+                       int flags;
+
+                       if ((flags = fcntl(fileno(state_fp), F_GETFD)) < 0
+                           || fcntl(fileno(state_fp), F_SETFD, flags | FD_CLOEXEC) < 0) {
+                               fprintf(stderr, 
+                                       "%s: failed to set FD_CLOEXEC on statefile %s: %s\n",
+                                       argv[0], statefile, strerror(errno));
+                               exit(1);
+                       }
+
+                       if (lock_fd (fileno(state_fp)) < 0) {
+                               fprintf(stderr, 
+                                       "%s: failed to lock statefile %s: %s\n",
+                                       argv[0], statefile, strerror(errno));
+                               exit(1);
+                       }
+
+               }
+
+               rewind (state_fp);
+               while((p = fgets(buf, sizeof buf, state_fp)) != NULL) {
+                       char *pch;
+
+                       pch = buf + strlen(buf) - 1;
+                       while(pch > buf && isspace(*pch)) pch--;
+                       *(pch+1) = '\0';
+
+                       pch = buf;
+                       while(isspace(*pch)) pch++;
+
+                       add_to_state(&state, &n_state, &max_state, strdup(pch));
+               }
+       }
+}
+#line 3508 "ifupdown.nw"
+if (do_all) {
+       if (
+#line 3087 "ifupdown.nw"
+(cmds == iface_up)
+#line 3509 "ifupdown.nw"
+                                     ) {
+               allowup_defn *autos = find_allowup(defn, "auto");
+               target_iface = autos ? autos->interfaces : NULL;
+               n_target_ifaces = autos ? autos->n_interfaces : 0;
+       } else if (
+#line 3091 "ifupdown.nw"
+(cmds == iface_down)
+#line 3513 "ifupdown.nw"
+                                            ) {
+               target_iface = state;
+               n_target_ifaces = n_state;
+       } else {
+               assert(0);
+       }       
+} else {
+       target_iface = argv + optind;
+       n_target_ifaces = argc - optind;
+}
+#line 3357 "ifupdown.nw"
+{
+       int i;
+       for (
+#line 3502 "ifupdown.nw"
+i = 0; i < n_target_ifaces; i++
+#line 3359 "ifupdown.nw"
+                                      ) {
+               char iface[80], liface[80];
+
+               
+#line 3526 "ifupdown.nw"
+strncpy(iface, target_iface[i], sizeof(iface));
+iface[sizeof(iface)-1] = '\0';
+
+{
+       char *pch;
+       if ((pch = strchr(iface, '='))) {
+               *pch = '\0';
+               strncpy(liface, pch+1, sizeof(liface));
+               liface[sizeof(liface)-1] = '\0';
+       } else {
+               strncpy(liface, iface, sizeof(liface));
+               liface[sizeof(liface)-1] = '\0';
+       }
+}
+#line 3363 "ifupdown.nw"
+               if (!force) {
+                       
+#line 3715 "ifupdown.nw"
+{
+       int already_up = lookfor_iface(state, n_state, iface);;
+
+       if (
+#line 3087 "ifupdown.nw"
+(cmds == iface_up)
+#line 3718 "ifupdown.nw"
+                                     ) {
+               if (already_up != -1) {
+                       fprintf(stderr, 
+                               "%s: interface %s already configured\n",
+                               argv[0], iface);
+                       continue;
+               }
+       } else if (
+#line 3091 "ifupdown.nw"
+(cmds == iface_down)
+#line 3725 "ifupdown.nw"
+                                            ) {
+               if (already_up == -1) {
+                       fprintf(stderr, "%s: interface %s not configured\n",
+                               argv[0], iface);
+                       continue;
+               }
+               strncpy(liface, strchr(state[already_up], '=') + 1, 80);
+               liface[79] = 0;
+       } else {
+               assert(0);
+       }
+}
+#line 3365 "ifupdown.nw"
+               }
+
+               if (
+#line 3100 "ifupdown.nw"
+(allow_class != NULL)
+
+#line 3367 "ifupdown.nw"
+                                                    ) {
+                       
+#line 3103 "ifupdown.nw"
+{
+       int i;
+       allowup_defn *allowup = find_allowup(defn, allow_class);
+       if (allowup == NULL)
+               continue;
+
+       for (i = 0; i < allowup->n_interfaces; i++) {
+               if (strcmp(allowup->interfaces[i], iface) == 0)
+                       break;
+       }
+       if (i >= allowup->n_interfaces)
+               continue;
+}
+#line 3369 "ifupdown.nw"
+               }
+
+               if (
+#line 3125 "ifupdown.nw"
+(excludeint != NULL && strstr(iface,excludeint) != NULL)
+#line 3371 "ifupdown.nw"
+                                               )  
+                       continue;
+
+               if (
+#line 3087 "ifupdown.nw"
+(cmds == iface_up)
+#line 3374 "ifupdown.nw"
+                                       && run_mappings) {
+                       
+#line 3392 "ifupdown.nw"
+{
+       mapping_defn *currmap;
+       for (currmap = defn->mappings; currmap; currmap = currmap->next) {
+               int i;
+               for (i = 0; i < currmap->n_matches; i++) {
+                       
+#line 3413 "ifupdown.nw"
+if (fnmatch(currmap->match[i], liface, 0) != 0)
+       continue;
+#line 3398 "ifupdown.nw"
+                       
+#line 3421 "ifupdown.nw"
+if (verbose) {
+       fprintf(stderr, "Running mapping script %s on %s\n",
+               currmap->script, liface);
+}
+run_mapping(iface, liface, sizeof(liface), currmap);
+#line 3399 "ifupdown.nw"
+                       break;
+               }
+       }
+}
+#line 3376 "ifupdown.nw"
+               }
+
+               
+#line 3431 "ifupdown.nw"
+{
+       interface_defn *currif;
+       int okay = 0;
+       int failed = 0; 
+       for (currif = defn->ifaces; currif; currif = currif->next) {
+               if (strcmp(liface, currif->logical_iface) == 0) {
+                       okay = 1;
+
+                       
+#line 3457 "ifupdown.nw"
+{
+       currif->real_iface = iface;
+
+       if (verbose) {
+               fprintf(stderr, "Configuring interface %s=%s (%s)\n", 
+                       iface, liface, currif->address_family->name);
+       }
+
+       switch(cmds(currif)) {
+           case -1:
+               printf("Don't seem to be have all the variables for %s/%s.\n", 
+                       liface, currif->address_family->name);
+               failed = 1;
+               break;
+           case 0:
+               failed = 1;
+               break;
+               /* not entirely successful */
+           case 1:
+               failed = 0;
+               break;
+               /* successful */
+           default:
+               printf("Internal error while configuring interface %s/%s (assuming it failed)\n", 
+                       liface, currif->address_family->name);
+               failed = 1;
+               /* what happened here? */
+       }
+       currif->real_iface = NULL;
+}
+
+#line 3441 "ifupdown.nw"
+                       if (failed) break;
+                       /* Otherwise keep going: this interface may have
+                        * match with other address families */
+               }
+       }
+
+       if (!okay && !force) {
+               fprintf(stderr, "Ignoring unknown interface %s=%s.\n", 
+                       iface, liface);
+       } else {
+               
+#line 3743 "ifupdown.nw"
+{
+       int already_up = lookfor_iface(state, n_state, iface);
+
+       if (
+#line 3087 "ifupdown.nw"
+(cmds == iface_up)
+#line 3746 "ifupdown.nw"
+                                     ) {
+               char *newiface = 
+                       malloc(strlen(iface) + 1 + strlen(liface) + 1);
+               sprintf(newiface, "%s=%s", iface, liface);
+
+               if (already_up == -1) {
+                       if (failed == 1) {
+                               printf("Failed to bring up %s.\n", liface);
+                       } else {
+                               add_to_state(&state, &n_state, &max_state, newiface);
+                       }
+               } else {
+                       free(state[already_up]);
+                       state[already_up] = newiface;
+               }
+       } else if (
+#line 3091 "ifupdown.nw"
+(cmds == iface_down)
+#line 3761 "ifupdown.nw"
+                                            ) {
+               if (already_up != -1) {
+                       state[already_up] = state[--n_state];
+               }
+       } else {
+               assert(0);
+       }
+}
+#line 3452 "ifupdown.nw"
+       }
+}
+#line 3379 "ifupdown.nw"
+               
+#line 3691 "ifupdown.nw"
+if (state_fp != NULL && !no_act) {
+       int i;
+
+       if (ftruncate(fileno(state_fp), 0) < 0)
+       {
+               fprintf(stderr, 
+                       "%s: failed to truncate statefile %s: %s\n",
+                       argv[0], statefile, strerror(errno));
+               exit(1);
+       }
+
+       rewind(state_fp);
+       for (i = 0; i < n_state; i++) {
+               fprintf(state_fp, "%s\n", state[i]);
+       }
+       fflush(state_fp);
+}
+#line 3380 "ifupdown.nw"
+       }
+}
+#line 3683 "ifupdown.nw"
+if (state_fp != NULL) {
+       fclose(state_fp);
+       state_fp = NULL;
+}
+
+#line 3001 "ifupdown.nw"
+       return 0;
+}
diff --git a/makecdep.sh b/makecdep.sh
new file mode 100755 (executable)
index 0000000..e39dadf
--- /dev/null
@@ -0,0 +1,9 @@
+#!/bin/sh
+FILE=$1
+if [ "$FILE" = "" -o ! -f "$FILE" ]; then
+        echo "Please specify a .c file"
+        exit 1
+fi
+
+gcc -MM -MG $FILE |
+  sed -e 's@^\(.*\)\.o:@\1.o \1.d:@'
diff --git a/makenwdep.sh b/makenwdep.sh
new file mode 100755 (executable)
index 0000000..4360528
--- /dev/null
@@ -0,0 +1,27 @@
+FILE=$1
+
+if [ "$FILE" = "" -o ! -f "$FILE" ]; then
+        echo "Please specify a .nw file"
+        exit 1
+fi
+
+noroots $FILE | sed 's/^<''<\(.*\)>>$/\1/' |
+        while read chunk; do
+                printf "%s : %s\n" "$chunk" "$FILE"
+                case $chunk in
+                        *.pl|*.sh)
+                                printf "\tnotangle -R\$@ \$< >\$@\n"
+                                printf "\tchmod 755 %s\n" "$chunk"
+                                ;;
+                        *.c)
+                                printf "\tnotangle -L -R\$@ \$< | cpif \$@\n"
+                                printf "include ${chunk%.c}.d\n"
+                                ;;
+                        *.h)
+                                printf "\tnotangle -L -R\$@ \$< | cpif \$@\n"
+                                ;;
+                        *)
+                                printf "\tnotangle -t8 -R\$@ $< >\$@\n"
+                                ;;
+                esac
+        done
diff --git a/modules.dia b/modules.dia
new file mode 100644 (file)
index 0000000..ebe8afd
Binary files /dev/null and b/modules.dia differ