2
\documentclass{article}
6
\noweboptions{smallcode,hideunuseddefs}
10
\def\nwendcode{\endtrivlist\endgroup}
13
\title{ Interface Tools\thanks{
14
Copyright \copyright\ 1999,2000 Anthony Towns. This program is free
15
software; you can redistribute it and/or modify it under the terms of
16
the GNU General Public License as published by the Free Software
17
Foundation; either version 2 of the License, or (at your option) any
21
\author{ Anthony Towns \\ { \tt aj@azure.humbug.org.au } }
30
\pagenumbering{arabic}
32
\section{Introduction}
34
This source defines the commands [[ifup]] and [[ifdown]], used to
35
manipulate interfaces in an easily controllable manner.
37
\subsection{Assumed Knowledge}
39
The reader is assumed to have knowledge of the C \cite{K&R} and Perl
40
\cite{camel} programming languages in a Unix environment \cite{StevensUnix}.
41
A cursory understanding of network administration on the appropriate
42
platform is also assumed, along with access to the relevant manual
45
This source has been written as a literate program using the [[noweb]]
46
\cite{wwwnoweb} tool suite, and typeset using \LaTeX\ \cite{latex}.
48
\subsection{Program Structure}
50
We shall decompose this program into four main areas of functionality:
51
compile-time configuration, run-time configuration, execution, and the
54
Compile-time configuration will deal with differing available address
55
families (IP vs IPX vs IPv6, and so on), and the differing methods of
56
enabling and disabling interfaces configured for each family. This will
57
be implemented using the [[addrfam]] module, and various [[.defn]] files,
58
for the address family definitions.
60
Run-time configuration will deal with determining the local setup
61
based on the file [[/etc/network/interfaces]], and producing a data
62
structure encapsulating these details. This will be implemented in the
65
Execution will deal with issues relating to working out exactly which
66
commands to run based on a somewhat abstract description from the
67
compile-time configuration and the details determined at
68
run-time. This will be dealt with in the [[execute]] module.
70
The remaining work --- argument parsing, error reporting, and,
71
essentially, putting all the pieces together --- is done by the
74
The following diagram gives a brief idea of the information and control
75
flow amongst the modules.
78
\includegraphics[height=45mm]{modules}
81
Much of the information sharing will be done by defining and filling
82
in some data structures and allowing the other modules to just access
83
that information directly. Rather than hiding the information itself,
84
most of our modules simply attempt to hide how that information was
85
originally written. Because of this, we shall find that these modules are
86
too closely linked to be completely separated in a convenient manner,
87
so they will all make use of a single header file for each other's
88
structure definitions, exported interfaces and so on.
95
<<function type definitions>>
96
<<structure definitions>>
97
<<constant definitions>>
100
#endif /* HEADER_H */
103
\section{The Build System}
105
We shall begin with the template for the Makefile we shall use.
110
CFILES := addrfam.c execute.c config.c main.c archlinux.c
111
HFILES := header.h archlinux.h
112
PERL := defn2c.pl defn2man.pl
113
DEFNFILES := inet.defn ipx.defn inet6.defn
115
OBJ := main.o addrfam.o execute.o config.o \
116
$(patsubst %.defn,%.o,$(DEFNFILES)) archlinux.o
118
MAN := $(patsubst %.defn,%.man,$(DEFNFILES))
120
default : executables
121
all : executables docs
123
executables : ifup ifdown ifup.8 ifdown.8 interfaces.5
124
docs : ifupdown.ps.gz ifup.8.ps.gz interfaces.5.ps.gz ifupdown.pdf
128
<<executable targets>>
130
<<extra dependencies>>
136
We shall build exactly two executables, [[ifup]] and [[ifdown]], which
137
will in truth simply be two names for a single binary, albeit with
138
different functionality.
140
<<executable targets>>=
142
$(CC) $(CFLAGS) -o ifup $^
148
Both of these executables have a manpage. Since they're actually the
149
same executable, what could be more appropriate than them having the
153
interfaces.5: interfaces.5.pre $(MAN)
154
LINE=$$(grep -n '^##ADDRESSFAM##$$' $< | sed 's/:.*//g'); \
157
head -$$(($$LINE - 1)) $<; \
159
tail -$$(($$WC - $$LINE)) $<; \
166
groff -mandoc -Tps $< > $@
168
groff -mandoc -Tps $< > $@
171
Further, for convenience, we'll make use of two phony targets, [[clean]],
172
[[clobber]] and [[distclean]], which will delete working files, everything
173
that can be rebuilt with a [[make]] command, and everything that can be
174
rebuilt at all, respectively.
177
.PHONY : clean clobber
180
install -m 0755 -d ${BASEDIR}/sbin
181
install -m 0755 ifup ${BASEDIR}/sbin
182
ln ${BASEDIR}/sbin/ifup ${BASEDIR}/sbin/ifdown
185
rm -f *.aux *.toc *.log *.bbl *.blg *.ps *.eps
186
rm -f *.o *.d $(patsubst %.defn,%.c,$(DEFNFILES)) *~
187
rm -f $(patsubst %.defn,%.man,$(DEFNFILES))
188
rm -f ifup ifdown interfaces.5 ifdown.8
189
rm -f ifupdown.dvi *.ps{,.gz} ifupdown.pdf
192
rm -f ifupdown.tex $(PERL) $(CFILES) $(HFILES) $(DEFNFILES)
195
rm -f makecdep.sh makenwdep.sh Makefile
198
We have some fairly standard rules to build the printed version of the
199
source code using \LaTeX\ that are, unfortunately, not included in
200
[[make(1)]]'s builtin rules, so we'll note them here.
204
noweave -delay -index -latex $< >$@
206
%.bbl : %.tex biblio.bib
208
bibtex $(basename $<)
222
gzip --best --stdout $< >$@
225
Additionally, some of [[make]]'s builtin rules are fairly
226
conservative, so we'll encourage it to use a more entertaining method
227
of compiling source code.
230
CFLAGS := -Wall -W -g -O2 -D'IFUPDOWN_VERSION="0.6.4"'
234
\subsection{Graphics}
236
We include a few graphics (made using dia) in this document. We have to
237
express these fairly explicitly, unfortunately.
244
gs -q -sDEVICE=pdfwrite -dNOPAUSE -sOutputFile=$@ - < $<
247
<<extra dependencies>>=
248
ifupdown.ps: modules.eps execution.eps
249
ifupdown.pdf: modules.pdf execution.pdf
252
\subsection{Automatic Dependencies}
254
To build the system, we'll make use of some techniques discussed in
255
\cite{recursivemake} for determining dependencies. Namely, a number
256
of files will have an associated [[.d]] file containing dynamically
257
determined dependency information. The first such file we will construct
258
is the dependency information for [[noweb]] source files, which can be
259
identified by the [[.nw]] extension.
262
%.d: %.nw makenwdep.sh
263
./makenwdep.sh $< > $@
266
To construct the dependency information, we may use the [[noroots(1)]]
267
command to determine the \emph{root chunks} in the [[noweb]] source
268
(stripping the unwanted [[<<]] and [[>>]] markers as we go, and
269
denoting that in such a way that [[noweb]] doesn't mistakenly think
270
the [[sed]] command is a chunk reference itself), and then noting down
271
appropriate commands to construct the target.
274
<<parse makenwdep arguments>>
276
noroots $FILE | sed 's/^<''<\(.*\)>>$/\1/' |
278
<<output dependency info for [[$chunk]]>>
282
Our dependency information is straightforward. To construct a file from
283
[[noweb]] source, we simply need to run [[notangle(1)]] over it. We add
284
a couple of extra tweeks in order to only update files that were actually
285
changed (the [[cpif(1)]] call), and to handle tabs properly.
287
We also need some extra things to take care of particular types of files.
288
In particular its important to have our scripts marked executable, so we
289
can use them as part of the build process itself, and it's also important
290
to have the dependency information for our C files (which are dealt with
291
next) included at some point.
293
<<output dependency info for [[$chunk]]>>=
296
echo -e "$chunk : $FILE"
297
echo -e "\tnotangle -R\$@ $< >\$@"
298
echo -e "\tchmod 755 $chunk"
301
echo -e "$chunk : $FILE"
302
echo -e "\tnotangle -L -R\$@ $< | cpif \$@"
303
echo -e "include ${chunk%.c}.d"
306
echo -e "$chunk : $FILE"
307
echo -e "\tnotangle -L -R\$@ $< | cpif \$@"
310
echo -e "$chunk : $FILE"
311
echo -e "\tnotangle -t8 -R\$@ $< >\$@"
316
Finally, our fairly primitive argument parsing is simply:
318
<<parse makenwdep arguments>>=
321
if [ "$FILE" = "" -o ! -f "$FILE" ]; then
322
echo "Please specify a .nw file"
327
We have a related system for object files generated from C source
328
code. Since each object file depends not only on its source, but also
329
the headers included in that source, we generate a [[.d]] file indicating
330
exactly which headers need to be checked.
334
./makecdep.sh $< > $@
337
We can do this using [[gcc(1)]]'s convenient [[-MM -MG]] options,
338
which do exactly this, with the added proviso that the [[.d]] file
339
itself can possibly depend on any of the header files being modified
340
(and, in particular, [[#include]] lines being added or deleted).
344
<<parse makecdep arguments>>
347
sed -e 's@^\(.*\)\.o:@\1.o \1.d:@'
350
\emph{Deja vu}, anyone?
352
<<parse makecdep arguments>>=
354
if [ "$FILE" = "" -o ! -f "$FILE" ]; then
355
echo "Please specify a .c file"
360
\section{Compile Time Configuration}
362
At compile time we need to determine all the possible address families
363
that may be used, and all the methods of setting up interfaces for
364
those address families, along with the various possible options
365
affecting each method.
367
Our key definition at this point is that of the [[address_family]]
368
structure, which encapsulates all the compile time information about
371
<<type definitions>>=
372
typedef struct address_family address_family;
375
<<structure definitions>>=
376
struct address_family {
383
Each defined address family will be included in the [[addr_fams]]
384
array, which becomes the \emph{raison d'\^etre} of the [[addrfam]]
387
<<exported symbols>>=
388
extern address_family *addr_fams[];
391
Each address family incorporates a number of methods, which
392
encapsulate various ways of configuring an interface for a particular
393
address family. There are two definining components of a method: two
394
sets of commands to bring an interface up and down, and a number of
395
options for the commands.
397
\emph{NB: I expect this will be extended sooner or later to make the
398
options more flexible. Probably introducing some form of typing (for
399
example to convert netmasks from CIDR specs to dotted-quads, ie
400
/24~$\rightarrow$~255.255.255.0), and some form of matching to allow
401
multiple options to be deduced from a single configuration
404
<<type definitions>>=
405
typedef struct method method;
408
<<structure definitions>>=
411
command_set *up, *down;
415
Each command set is implemented as a single function, accepting two
416
parameters: the definitions of the interface the commands should deal
417
with, and the function that should be used to execute them. See the
418
[[execute]] module for more details.
420
<<function type definitions>>=
421
typedef int (execfn)(char *command);
422
typedef int (command_set)(interface_defn *ifd, execfn *e);
425
As our compile-time configuration is done at, well, compile-time, there
426
is little need for functions in the actual module, and we can make do with
427
a single exported array.
433
<<address family declarations>>
435
address_family *addr_fams[] = {
436
<<address family references>>
441
\subsection{Generating C Code}
443
Unfortunately, while the [[.defn]] representation is reasonably
444
convenient for human use, it's less convenient for a compiler. As
445
such, at build time, we will build a single structure of type
446
[[address_family]] in a separate module, and reference that from
449
Naturally, we'll use a [[perl]] script to convert [[.defn]] files to C
453
%.c : %.defn defn2c.pl
457
The functionality of our program is pretty basic: read from the file
458
specified as the argument, output to [[stdout]]; and correspondingly
459
the structure of the program is similarly simple. We make use of a
460
couple of global variables, a few helpful subroutines, and then build
472
<<defn2c subroutines>>
475
<<output headers for address family>>
476
<<parse [[.defn]] file and output intermediate structures>>
477
<<output address family data structure>>
480
Clearly we need to reference some of the data structures we defined
481
above, so we can begin with the rather trivial:
483
<<output headers for address family>>=
484
print "#include \"header.h\"\n\n\n";
487
The overall purpose of the C code we're trying to construct is to
488
define a structure of type [[address_family]], and have it externally
489
visible. So we'd like to declare a statically-initialized structure of
490
this type, and be done with it.
492
To do this, however, we need to have some way of uniquely identifying
493
the structure to avoid naming conflicts. We'll do this by assuming we
494
have a previously initialized variable, [[$address_family]], and that
495
names of the form [[addr_foo]] won't be used elsewhere.
497
<<defn2c variables>>=
498
my $address_family = "";
501
We also need to reference an array of pointers to this address
502
family's [[method]]s, which will have to be initialized separately.
503
We'll assume that previous code will create such a structure, and call
504
it (imaginativly) [[methods]].
506
<<output address family data structure>>=
507
<<output [[methods]] data structure>>
510
address_family addr_${address_family} = {
512
sizeof(methods)/sizeof(struct method),
518
Our [[methods]] array will be a little more complicated to
519
construct. The first difficulty is that it will actually require some
520
state from having read the [[.defn]] file. To handle this, we'll
521
introduce a hash [[%methods]] that has the value [[1]] for each method
522
from the [[.defn]] file. We use a hash instead of a list because it
523
makes some error checking more convenient later, and since order
524
doesn't particularly matter.
526
<<defn2c variables>>=
530
We'll use standard names, such as [[foo_up]], [[foo_down]], and
531
[[foo_options]] for the various elements of each method which cannot
532
be defined inline. The two functions and the array will be declared
533
static to avoid name conflicts.
535
<<output [[methods]] data structure>>=
536
print "static method methods[] = {\n";
538
foreach $method (keys %methods) {
542
${method}_up, ${method}_down,
549
In a reasonably obvious manner we can then proceed to process the
550
[[.defn]] file to initialize the aforementioned variables, and to
551
output the method-specific functions and array. We'll begin by
552
defining a variable to keep track of the current line.
554
<<defn2c variables>>=
558
Our semantics for this variable will be basically that it contains a
559
valid, meaningful input line. It won't be blank, or contain comments,
560
and if there aren't any more lines to be read, it will evaluate to
561
[[false]]. In order to keep these semantics, we'll use the subroutine
562
[[nextline]] to update it. (Since we'll later find we'll want to reuse
563
this subroutine, we'll keep it in a chunk of its own)
565
<<defn2c subroutines>>=
566
<<[[nextline]] subroutine>>
569
<<[[nextline]] subroutine>>=
572
while($line and ($line =~ /^#/ or $line =~ /^\s*$/)) {
575
if (!$line) { return 0; }
577
while ($line =~ m/^(.*)\\$/) {
586
Our high-level logic then looks basically like:
588
<<parse [[.defn]] file and output intermediate structures>>=
591
<<parse a top-level section and output intermediate structures>>
594
die("Unknown command \"$line\"");
598
To make all this stuff easier, we'll use a `matching' function to help
599
with parsing lines: basically, given a line, a command, and possibly
600
an indentation prefix (eg [[" "]]). (As with [[nextline]], this will
601
also be useful to reuse, hence it has its own pair of chunks, too)
603
<<defn2c variables>>=
607
<<defn2c subroutines>>=
608
<<[[match]] subroutine>>
611
<<[[match]] subroutine>>=
614
my $cmd = "$_[1]" ? "$_[1]\\b\\s*" : "";;
615
my $indentexp = (@_ == 3) ? "$_[2]\\s+" : "";
617
if ($line =~ /^${indentexp}${cmd}(([^\s](.*[^\s])?)?)\s*$/) {
626
Okay. So, the first line we expect to see is the name of the address
627
family we're defining.
629
<<parse a top-level section and output intermediate structures>>=
630
if (match($line, "address_family")) {
631
get_address_family $match;
636
This is, as you'd imagine, pretty simple to deal with. We just need to
637
store the address family's name, and move on to the next line.
639
<<defn2c subroutines>>=
640
sub get_address_family {
641
$address_family = $_[0] if ($address_family eq "");
646
Which brings us to determining the architecture.
648
<<parse a top-level section and output intermediate structures>>=
649
if (match($line, "architecture")) {
650
get_architecture $match;
655
You'd never guess what, but it's just as easy as the address family thing
658
<<defn2c subroutines>>=
659
sub get_architecture {
661
die("architecture declaration appears too late") if (keys %methods);
662
print "#include \"arch${arch}.h\"\n\n\n";
667
Which leaves us with the hard bit, actually creating the functions and
668
array for each method.
670
<<parse a top-level section and output intermediate structures>>=
671
if (match($line, "method")) {
677
The basic premise is to check for each of our options in a given
678
order: if they don't match, then we can presume they don't exist ---
679
any errors will be reported when the main function finds something
680
weird going on. All we really have to take care of so far is ensuring
681
an appropriate level of indentation, and that we're not defining the
684
<<defn2c subroutines>>=
687
my $indent = ($line =~ /(\s*)[^\s]/) ? $1 : "";
689
die "Duplicate method $method\n" if ($methods{$method}++);
692
<<output code for description>>
693
<<output code for options list>>
694
<<output code for up commands>>
695
<<output code for down commands>>
699
The description and options sections are just documentation chunks,
700
and hence aren't at all relevant for the C code.
702
<<output code for description>>=
703
if (match($line, "description", $indent)) {
708
<<output code for options list>>=
709
if (match($line, "options", $indent)) {
714
Skipping a section is fairly easy: we just need to check alignments. This is
715
yet another subroutine that'll come in handy elsewhere.
717
<<defn2c subroutines>>=
718
<<[[skip_section]] subroutine>>
721
<<[[skip_section]] subroutine>>=
724
my $indent = ($line =~ /(\s*)[^\s]/) ? $1 : "";
726
1 while (nextline && match($line, "", $indent));
730
Checking the various relevant components of each method is fairly
731
simple: we need to see if it exists, and if it does, parse and output
732
it, while if it doesn't, we need to output a place holder.
734
<<output code for up commands>>=
735
if (match($line, "up", $indent)) {
736
get_commands(${method}, "up");
738
print "static int ${method}_up(interface_defn ifd) { return 0; }\n"
742
<<output code for down commands>>=
743
if (match($line, "down", $indent)) {
744
get_commands(${method}, "down");
746
print "static int ${method}_down(interface_defn ifd) { return 0; }\n"
750
<<defn2c subroutines>>=
754
my $function = "${method}_${mode}";
755
my $indent = ($line =~ /(\s*)[^\s]/) ? $1 : "";
757
print "static int ${function}(interface_defn *ifd, execfn *exec) {\n";
759
while (nextline && match($line, "", $indent)) {
760
if ( $match =~ /^(.*[^\s])\s+if\s*\((.*)\)\s*$/ ) {
761
print "if ( $2 ) {\n";
762
print " if (!execute(\"$1\", ifd, exec)) return 0;\n";
764
} elsif ( $match =~ /^(.*[^\s])\s+elsif\s*\((.*)\)\s*$/ ) {
765
print "else if ( $2 ) {\n";
766
print " if (!execute(\"$1\", ifd, exec)) return 0;\n";
768
} elsif ( $match =~ /^(.*[^\s])\s*$/ ) {
770
print " if (!execute(\"$1\", ifd, exec)) return 0;\n";
780
\subsection{Building Manual Pages}
782
So having C code is all very well, but if you want to ignore all user
783
problems with a casual ``RTFM!'' there has to be some semblance of an
784
M for them to R. So we need a script to generate some useful
785
descriptions of the various methods.
787
We'll achieve this by making another Perl script, [[defn2man.pl]],
788
which will generate fragments of [[troff]] that can be catted together
789
with a general overview of [[ifupdown]] to produce real manpages.
792
%.man: %.defn defn2man.pl
793
./defn2man.pl $< > $@
796
So we'll use a similar structure to [[defn2c.pl]].
804
<<defn2man variables>>
807
<<defn2man subroutines>>
810
<<parse [[.defn]] file and output manpage fragment>>
813
As predicted, we'll also incorporate [[nextline]], [[match]] and
816
<<defn2man variables>>=
821
<<defn2man subroutines>>=
822
<<[[nextline]] subroutine>>
823
<<[[match]] subroutine>>
824
<<[[skip_section]] subroutine>>
827
Now we'll have a slightly different structure to the program itself
828
this time, since we need to do things pretty much in order for
829
outputting the manpage. This imposes stricter ordering requirements on
830
the [[.defn]] files than [[defn2c]] did.
832
<<parse [[.defn]] file and output manpage fragment>>=
834
if ($line and match($line, "address_family")) {
835
get_address_family $match;
837
die "address_family must be listed first\n";
839
if ($line and match($line, "architecture")) {
840
get_architecture $match;
842
while ($line and match($line, "method")) {
847
Okay, so it wasn't \emph{that} different from what we had before. Sue
850
The [[get_address_family]] and [[get_architecture]] subroutines are
851
fairly straight forward:
853
<<defn2man subroutines>>=
854
sub get_address_family {
855
print ".SH " . uc($match) . " ADDRESS FAMILY\n";
856
print "This section documents the methods available in the\n";
857
print "$match address family.\n";
862
<<defn2man subroutines>>=
863
sub get_architecture {
869
Which only leaves extracting the description and options for each
870
method. And, of course, this imposes less restrictions of the
871
[[.defn]] file than [[defn2c.pl]] did. It's a crazy old world.
873
<<defn2man subroutines>>=
876
my $indent = ($line =~ /(\s*)\S/) ? $1 : "";
877
my $description = "";
881
while ($line and match($line, "", $indent)) {
882
if (match($line, "description", $indent)) {
883
$description = get_description();
884
} elsif (match($line, "options", $indent)) {
885
@options = get_options();
891
<<output [[$method]] introduction man fragment>>
892
<<output [[$description]] man fragment>>
893
<<output [[@options]] man fragment>>
897
<<output [[$method]] introduction man fragment>>=
898
print ".SS The $method Method\n";
901
Okay. Now our [[$description]] is just the description with any [['\n']]
902
characters it may've had, but without the leading spaces.
904
<<defn2man subroutines>>=
905
sub get_description {
907
my $indent = ($line =~ /(\s*)\S/) ? $1 : "";
908
while(nextline && match($line, "", $indent)) {
915
We're actually going to be a little tricky here, and allow some formatting
916
in our descriptions. Basically, we'll allow bold and italic encoding
917
to be denoted by [[*bold*]] and [[/italics/]] in the wonderful Usenet
918
tradition. As such, we'll use a cute little function to convert the
919
Usenet style to roff. We'll also take care not to do this conversion
920
within words (for things like [[/etc/hosts]], eg). Voila:
922
<<defn2man subroutines>>=
928
while ($in =~ m/^([^\*\/]*)([\*\/])([^\*\/]*)([\*\/])(.*)$/s) {
929
my ($pre, $l, $mid, $r, $post) = ($1, $2, $3, $4, $5);
930
if ($l eq $r && " $pre" =~ m/ $/ && "$post " =~ m/^ /) {
932
$out .= ($l eq "*" ? ".B" : ".I") . " \"$mid\"\n";
933
($in = $post) =~ s/^ *//;
936
$in = $mid . $r . $post;
943
The only further thing to note about this is that we're being careless
944
and ignoring the possibility of ROFF escape sequences in the input. But
945
since this is for internal use only, well, too bad. So here we go:
947
<<output [[$description]] man fragment>>=
948
if ($description ne "") {
949
print usenet2man($description) . "\n";
951
print "(No description)\n";
957
Reading the options is almost exactly the same as the description,
958
except we want a list instead of just a string.
960
<<defn2man subroutines>>=
963
my $indent = ($line =~ /(\s*)\S/) ? $1 : "";
964
while(nextline && match($line, "", $indent)) {
971
Output is slightly more complicated, but not too much so.
973
<<output [[@options]] man fragment>>=
975
print ".B Options\n";
978
foreach my $o (@options) {
979
if ($o =~ m/^\s*(\S*)\s*(.*)\s+--\s+(\S.*)$/) {
985
print " \" $optargs\"" unless($optargs =~ m/^\s*$/);
987
print usenet2man($dsc) . "\n";
995
print "(No options)\n";
1000
\section{Run-time Configuration}
1002
Our module is of the usual form, and we'll make use of a few fairly standard
1003
headers. Please move along, there's nothing to see here.
1007
<<config function declarations>>
1008
<<config functions>>
1018
We'll also make use of some of our other modules. This is, after all,
1019
why we had a single header in the first place.
1025
The key function we're interested in defining here is
1026
[[read_interfaces()]], which will (wait for it) read an interfaces
1027
file. The intention is to make it really easy to deal with the
1028
vagaries of [[/etc/network/interfaces]] anywhere else.
1030
So the first question we need to deal with is ``What's a convenient
1031
form for other functions which deal with interfaces?'' Well, our
1032
answer to that is basically:
1035
\item an array of interface names that should be brought up at
1038
\item a singly linked list to represent the various mappings.
1040
\item another singly linked list to represent the interface
1041
definitions themselves.
1044
These are almost in exact correspondence with the original file.
1046
<<type definitions>>=
1047
typedef struct interfaces_file interfaces_file;
1050
<<structure definitions>>=
1051
struct interfaces_file {
1052
int max_autointerfaces;
1053
int n_autointerfaces;
1054
char **autointerfaces;
1056
interface_defn *ifaces;
1057
mapping_defn *mappings;
1061
So, at run-time, we require a way of representing each interface
1062
listed in the configuration file. This naturally needs to reference an
1063
address family and method, and all the options a user may specify
1066
<<type definitions>>=
1067
typedef struct interface_defn interface_defn;
1070
<<structure definitions>>=
1071
struct interface_defn {
1072
interface_defn *next;
1075
address_family *address_family;
1086
The last component in the above, the options, is represented by a
1087
series of name/value pairs, as follows:
1089
<<type definitions>>=
1090
typedef struct variable variable;
1093
<<structure definitions>>=
1100
In addition, we want to represent each mapping in the configuration
1101
file. This is somewhat simpler, since each mapping is entirely self
1102
contained, and doesn't need to reference previously determined address
1103
families or methods or anything.
1105
<<type definitions>>=
1106
typedef struct mapping_defn mapping_defn;
1109
<<structure definitions>>=
1110
struct mapping_defn {
1125
We can thus begin to instantiate our actual function. What we want is
1126
something that, given the name of a file, will produce the appropriate
1127
linked list of interfaces defined in it, or possibly give some sort of
1128
helpful error message. Pretty simple, hey?
1130
<<exported symbols>>=
1131
interfaces_file *read_interfaces(char *filename);
1134
<<config functions>>=
1135
interfaces_file *read_interfaces(char *filename) {
1136
<<variables local to read interfaces>>
1137
interfaces_file *defn;
1139
<<allocate defn or [[return NULL]]>>
1140
<<open file or [[return NULL]]>>
1142
while (<<we've gotten a line from the file>>) {
1143
<<process the line>>
1145
if (<<an error occurred getting the line>>) {
1146
<<report internal error and die>>
1155
<<allocate defn or [[return NULL]]>>=
1156
defn = malloc(sizeof(interfaces_file));
1160
defn->max_autointerfaces = defn->n_autointerfaces = 0;
1161
defn->autointerfaces = NULL;
1162
defn->mappings = NULL;
1163
defn->ifaces = NULL;
1166
\subsection{File Handling}
1168
So, the first and most obvious thing to deal with is the file
1169
handling. Nothing particularly imaginative here.
1171
<<variables local to read interfaces>>=
1176
<<open file or [[return NULL]]>>=
1177
f = fopen(filename, "r");
1178
if ( f == NULL ) return NULL;
1187
\subsection{Line Parsing}
1189
Our next problem is to work out how to read a single line from our
1190
input file. While this is nominally easy, we also want to deal nicely
1191
with things like continued lines, comments, and very long lines.
1193
So we're going to have to write and make use of a complicated little
1194
function, which we'll imaginatively call [[get_line()]]. It will need
1195
a pointer to the file it's reading from, as well as a buffer to store
1196
the line it finds. Since this buffer's size can't be known in advance
1197
we'll need to make it [[realloc()]]-able, which means we need to pass
1198
around references to both the buffer's location (which may change),
1199
and it's size (which probably will). Our function declaration is thus:
1201
<<config function declarations>>=
1202
static int get_line(char **result, size_t *result_len, FILE *f, int *line);
1205
To use it, we'll need a couple of variables to stores the buffer's
1206
location, and it's current length.
1208
<<variables local to read interfaces>>=
1213
Given these, and presuming we can actually implement the function, our
1214
key chunk can thus be implemented simply as:
1216
<<we've gotten a line from the file>>=
1217
get_line(&buf,&buf_len,f,&line)
1220
We'll also add the requirement that errors are indicated by the
1221
[[errno]] variable being non-zero, which is usual and reasonable for
1222
all the circumstances where [[get_line()]] might have problems.
1228
<<an error occurred getting the line>>=
1232
Actually defining the function is, as you'd probably imagine, a little
1233
more complicated. We begin by reading a line from the file. If it was
1234
a comment (that is, it has a [[#]] character at the first non-blank
1235
position) then we try again. Otherwise, if the line is continued
1236
(indicated by a [[\]] character at the very end of the line) we append
1237
the next line to the buffer. We go to a little bit of effort to trim
1238
whitespace, and finally return a boolean result indicating whether we
1241
<<config functions>>=
1242
static int get_line(char **result, size_t *result_len, FILE *f, int *line) {
1243
<<variables local to get line>>
1247
<<append next line to buffer, or [[return 0]]>>
1248
<<trim leading whitespace>>
1249
} while (<<line is a comment>>);
1251
while (<<buffer is continued>>) {
1252
<<remove continuation mark>>
1253
<<append next line to buffer, or [[return 0]]>>
1256
<<trim trailing whitespace>>
1262
In order to do string concatenation efficiently, we'll keep track of
1263
where the end of the line so far is --- this is thus where the
1264
terminating [[NUL]] will be by the end of the function.
1266
<<variables local to get line>>=
1270
We can thus clear the buffer by simply resetting where we append new
1271
text to the beginning of the buffer. What could be simpler?
1277
We'll be making use of the [[fgets()]] function to read the line
1278
(rather than, say, [[fgetc()]]) so to get an entire line we may have
1279
to make multiple attempts (if the line is bigger than our
1280
buffer). Realising this, and the fact that we may not have any
1281
allocated space for our buffer initially, we need a loop something
1284
<<append next line to buffer, or [[return 0]]>>=
1286
<<reallocate buffer as necessary, or [[return 0]]>>
1287
<<get some more of the line, or [[return 0]]>>
1288
} while(<<the line isn't complete>>);
1290
<<remove trailing newline>>
1294
assert( (*result)[pos] == '\0' );
1297
When reallocating the buffer, we need to make sure it increases in
1298
chunks large enough that we don't have to do this too often, but not
1299
so huge that we run out of memory just to read an 81 character line.
1300
We'll use two fairly simple heuristics for this: if we've got room to
1301
add no more than 10 characters, we may as well reallocate the buffer,
1302
and when reallocating, we want to more or less double the buffer, but
1303
we want to at least add 80 characters. So we do both.
1305
<<reallocate buffer as necessary, or [[return 0]]>>=
1306
if (*result_len - pos < 10) {
1307
char *newstr = realloc(*result, *result_len * 2 + 80);
1308
if (newstr == NULL) {
1312
*result_len = *result_len * 2 + 80;
1316
The only time we need to keep reading is when the buffer wasn't big
1317
enough for the entire line. This is indicated by a full buffer, with
1318
no newline at the end. There is, actually, one case where this can
1319
happen legitimately --- where the last line of the file is
1320
\emph{exactly} the length of the buffer. We need to detect this
1321
because [[fgets()]] will return [[NULL]] and indicate that it's hit
1322
the end of the file, but we won't want to indicate that until the
1323
\emph{next} time we try to get a line. Complicated, isn't it?
1325
<<the line isn't complete>>=
1326
pos == *result_len - 1 && (*result)[pos-1] != '\n'
1329
So having thought through all that, actually working with [[fgets()]]
1330
is fairly simple, especially since we deal with the actual errors
1331
elsewhere. All we need to do is make the call, update [[pos]] and
1332
check that the problems [[fgets()]] may have actually bother us.
1334
<<get some more of the line, or [[return 0]]>>=
1335
if (!fgets(*result + pos, *result_len - pos, f)) {
1336
if (ferror(f) == 0 && pos == 0) return 0;
1337
if (ferror(f) != 0) return 0;
1339
pos += strlen(*result + pos);
1342
[[fgets()]] leaves a [[\n]] in our buffer in some cases. We're never
1343
actually interested in it, however, so it's a good move to get rid of
1346
<<remove trailing newline>>=
1347
if (pos != 0 && (*result)[pos-1] == '\n') {
1348
(*result)[--pos] = '\0';
1353
Pretty simple, hey? Now the next thing we want to do is get rid of
1354
some of the whitespace lying about. This is all pretty basic, and just
1355
involves finding where the whitespace begins and ends, and, well,
1362
<<trim leading whitespace>>=
1365
while (isspace((*result)[first]) && (*result)[first]) {
1369
memmove(*result, *result + first, pos - first + 1);
1374
<<trim trailing whitespace>>=
1375
while (isspace((*result)[pos-1])) { /* remove trailing whitespace */
1378
(*result)[pos] = '\0';
1381
As we mentioned earlier, a line is a comment iff it's first character
1382
is a [[#]] symbol. Similarly, it's continued iff it's very last
1383
character is a [[\]]. And, rather obviously, if we want to remove a
1384
single trailing [[\]], we can do so by changing it to a [[NUL]].
1386
<<line is a comment>>=
1390
<<buffer is continued>>=
1391
(*result)[pos-1] == '\\'
1394
<<remove continuation mark>>=
1395
(*result)[--pos] = '\0';
1398
\subsection{Line Processing}
1400
So. We've gone to a lot of trouble to get a line that we can parse
1401
with a snap of our fingers, so we probably better jump to it, to mix
1402
some \emph{clich\'e's}.
1404
We have two alternative bits of state to maintain between lines: either
1405
what interface we're currently defining, or what mapping we're currently
1408
<<variables local to read interfaces>>=
1409
interface_defn *currif = NULL;
1410
mapping_defn *currmap = NULL;
1411
enum { NONE, IFACE, MAPPING } currently_processing = NONE;
1414
Since our configuration files are pretty basic, we can work out what
1415
any particular line means based on the first word in it. To cope with
1416
this, we'll thus make use of a couple of variables, one to store the
1417
first word, and the other to store the rest of the line.
1419
<<variables local to read interfaces>>=
1424
To initialize these variables we'll make use of a function I'm overly
1425
fond of called [[next_word()]]. It copies the first word in a string
1426
to a given buffer, and returns a pointer to the rest of the buffer.
1428
<<config function declarations>>=
1429
static char *next_word(char *buf, char *word, int maxlen);
1432
<<config functions>>=
1433
static char *next_word(char *buf, char *word, int maxlen) {
1434
if (!buf) return NULL;
1435
if (!*buf) return NULL;
1437
while(!isspace(*buf) && *buf) {
1438
if (maxlen-- > 1) *word++ = *buf;
1441
if (maxlen > 0) *word = '\0';
1443
while(isspace(*buf) && *buf) buf++;
1449
So after all this, there are basically three different sorts of line
1450
we can get: the start of a new interface, the start of a new mapping,
1451
or an option for whatever interface we're currently working with.
1453
<<process the line>>=
1454
rest = next_word(buf, firstword, 80);
1455
if (rest == NULL) continue; /* blank line */
1457
if (strcmp(firstword, "mapping") == 0) {
1458
<<process [[mapping]] line>>
1459
currently_processing = MAPPING;
1460
} else if (strcmp(firstword, "iface") == 0) {
1461
<<process [[iface]] line>>
1462
currently_processing = IFACE;
1463
} else if (strcmp(firstword, "auto") == 0) {
1464
<<process [[auto]] line>>
1465
currently_processing = NONE;
1467
<<process option line>>
1471
<<process option line>>=
1472
switch(currently_processing) {
1474
<<process iface option line>>
1477
<<process mapping option line>>
1481
<<report bad option and die>>
1485
\subsubsection{Mapping Line}
1487
Declaring a new mapping is reasonably copewithable --- we need to process
1488
a few things, but they're reasonably easy to handle.
1490
The main weirdness is that we're processing the [[mapping]] line itself
1491
and the rest of the stanza in separate blocks of code. So this first
1492
chunk just needs to do the basics of initialising the data structure,
1493
but can't really fill in all that much of it.
1495
<<process [[mapping]] line>>=
1496
<<allocate new mapping>>
1497
<<parse mapping interfaces>>
1498
<<set other mapping options to defaults>>
1499
<<add to list of mappings>>
1502
<<allocate new mapping>>=
1503
currmap = malloc(sizeof(mapping_defn));
1504
if (currmap == NULL) {
1505
<<report internal error and die>>
1509
<<parse mapping interfaces>>=
1510
currmap->max_matches = 0;
1511
currmap->n_matches = 0;
1512
currmap->match = NULL;
1514
while((rest = next_word(rest, firstword, 80))) {
1515
if (currmap->max_matches == currmap->n_matches) {
1517
currmap->max_matches = currmap->max_matches * 2 + 1;
1518
tmp = realloc(currmap->match,
1519
sizeof(*tmp) * currmap->max_matches);
1521
currmap->max_matches = (currmap->max_matches - 1) / 2;
1522
<<report internal error and die>>
1524
currmap->match = tmp;
1527
currmap->match[currmap->n_matches++] = strdup(firstword);
1531
<<set other mapping options to defaults>>=
1532
currmap->script = NULL;
1534
currmap->max_mappings = 0;
1535
currmap->n_mappings = 0;
1536
currmap->mapping = NULL;
1539
<<add to list of mappings>>=
1541
mapping_defn **where = &defn->mappings;
1542
while(*where != NULL) {
1543
where = &(*where)->next;
1546
currmap->next = NULL;
1550
So that's that. But as mentioned, we also need to cope with the options
1551
within the stanza, as well as the lead in. As before, it's not really
1552
complicated, and we do it thusly:
1554
<<process mapping option line>>=
1555
if (strcmp(firstword, "script") == 0) {
1556
<<handle [[script]] line>>
1557
} else if (strcmp(firstword, "map") == 0) {
1558
<<handle [[map]] line>>
1560
<<report bad option and die>>
1564
<<handle [[script]] line>>=
1565
if (currmap->script != NULL) {
1566
<<report duplicate script in mapping and die>>
1568
currmap->script = strdup(rest);
1572
<<handle [[map]] line>>=
1573
if (currmap->max_mappings == currmap->n_mappings) {
1575
currmap->max_mappings = currmap->max_mappings * 2 + 1;
1576
opt = realloc(currmap->mapping, sizeof(*opt) * currmap->max_mappings);
1578
<<report internal error and die>>
1580
currmap->mapping = opt;
1582
currmap->mapping[currmap->n_mappings] = strdup(rest);
1583
currmap->n_mappings++;
1586
\subsubsection{Interface line}
1588
Declaring a new interface follows the same pattern, but is somewhat more
1589
interesting and some more complicated data structures are involved.
1591
<<process [[iface]] line>>=
1593
<<variables local to process [[iface]] line>>
1595
<<allocate new interface>>
1597
<<parse interface settings>>
1600
<<set address family>>
1602
<<set other interface options to defaults>>
1604
<<add to list of interfaces>>
1608
We'll deal with each of these phases one by one and pretty much in
1609
order, so prepare yourself for the intense excitement of memory
1612
<<allocate new interface>>=
1613
currif = malloc(sizeof(interface_defn));
1615
<<report internal error and die>>
1619
When we introduce a new interface, we simultaneously name the
1620
interface, the address family, and the method. We cope with this by,
1621
well, getting somewhere to store each of them, and then, well, storing
1624
<<variables local to process [[iface]] line>>=
1625
char iface_name[80];
1626
char address_family_name[80];
1627
char method_name[80];
1630
<<parse interface settings>>=
1631
rest = next_word(rest, iface_name, 80);
1632
rest = next_word(rest, address_family_name, 80);
1633
rest = next_word(rest, method_name, 80);
1636
<<report too few parameters for iface line and die>>
1639
if (rest[0] != '\0') {
1640
<<report too many parameters for iface line and die>>
1644
We then want to store the interface name.
1647
currif->iface = strdup(iface_name);
1648
if (!currif->iface) {
1649
<<report internal error and die>>
1653
Setting the address family is a little more involved, because it's not
1654
very useful to know what the name of the address family is, you really
1655
want to know all the details recorded in the appropriate
1656
[[address_family]] structure. So we'll make use of a little helper
1657
function, called [[get_address_family()]] to convert the useless
1658
string, to the hopefully less useless structure.
1660
<<config function declarations>>=
1661
static address_family *get_address_family(address_family *af[], char *name);
1664
<<set address family>>=
1665
currif->address_family = get_address_family(addr_fams, address_family_name);
1666
if (!currif->address_family) {
1667
<<report unknown address family and die>>
1671
Of course, we probably need to actually implement the function too. We
1672
won't do anything particularly fancy here, just a simple linear
1673
search. \emph{Should this really be here, or an exported symbol from
1674
[[addrfam.c]]? --- aj}
1676
<<config functions>>=
1677
static address_family *get_address_family(address_family *af[], char *name) {
1679
for (i = 0; af[i]; i++) {
1680
if (strcmp(af[i]->name, name) == 0) {
1688
We do something incredibly similar when dealing with the method the
1689
user wishes to use, and we do it for incredibly similar reasons. Again
1690
we declare a cute little helper function, this time imaginatively
1691
called [[get_method()]], and then go and use it and implement in
1692
almost exactly the same way as before. I told you this was going to be
1693
a thrill. \emph{The same note applies here, too --- aj}
1695
<<config function declarations>>=
1696
static method *get_method(address_family *af, char *name);
1700
currif->method = get_method(currif->address_family, method_name);
1701
if (!currif->method) {
1702
<<report unknown method and die>>
1703
return NULL; /* FIXME */
1707
<<config functions>>=
1708
static method *get_method(address_family *af, char *name) {
1710
for (i = 0; i < af->n_methods; i++) {
1711
if (strcmp(af->method[i].name, name) == 0) {
1712
return &af->method[i];
1719
You'll continue to be enthralled as we set the remaining options to
1720
some default values.
1722
<<set other interface options to defaults>>=
1723
currif->automatic = 1;
1724
currif->max_options = 0;
1725
currif->n_options = 0;
1726
currif->option = NULL;
1729
Since we want to keep the interfaces in order, we have to go all the
1730
way to the end of the list of interfaces to add the new interface, and
1731
we can hence set the [[next]] pointer to NULL in all cases. Gee. Whiz.
1733
Actually, I'm selling this a little short. We also want to make sure
1734
we don't try instantiating the same interface twice or anything. So we
1735
take care of that too. There now. Didn't that just get the adrenalin
1738
<<add to list of interfaces>>=
1740
interface_defn **where = &defn->ifaces;
1741
while(*where != NULL) {
1742
if (duplicate_if(*where, currif)) {
1743
<<report duplicate interface and die>>
1745
where = &(*where)->next;
1749
currif->next = NULL;
1753
Duplicate interfaces are interfaces that have the same name and the
1754
same address family. Nothing more complicated than that.
1756
<<config function declarations>>=
1757
static int duplicate_if(interface_defn *ifa, interface_defn *ifb);
1760
<<config functions>>=
1761
static int duplicate_if(interface_defn *ifa, interface_defn *ifb) {
1762
if (strcmp(ifa->iface, ifb->iface) != 0) return 0;
1763
if (ifa->address_family != ifb->address_family) return 0;
1768
Dealing with the per-interface options is the next thing to deal
1771
<<process iface option line>>=
1772
<<check for duplicate options>>
1776
<<check for duplicate options>>=
1779
if (strcmp(firstword, "up") != 0
1780
&& strcmp(firstword, "down") != 0
1781
&& strcmp(firstword, "pre-up") != 0
1782
&& strcmp(firstword, "post-down") != 0)
1784
for (i = 0; i < currif->n_options; i++) {
1785
if (strcmp(currif->option[i].name, firstword) == 0) {
1786
<<report duplicate option and die>>
1793
Adding an option is fairly straightforward: we simply construct
1794
a new variable and add it at the end of our array of variables,
1795
increasing the size of the array first if necessary.
1798
if (currif->n_options >= currif->max_options) {
1799
<<increase max number of options>>
1802
currif->option[currif->n_options].name = strdup(firstword);
1803
currif->option[currif->n_options].value = strdup(rest);
1805
if (!currif->option[currif->n_options].name) {
1806
<<report internal error and die>>
1809
if (!currif->option[currif->n_options].value) {
1810
<<report internal error and die>>
1813
currif->n_options++;
1816
We'll increase the space for variables by a constant amount each time,
1817
rather than doubling or anything smart like that.
1819
<<increase max number of options>>=
1822
currif->max_options = currif->max_options + 10;
1823
opt = realloc(currif->option, sizeof(*opt) * currif->max_options);
1825
<<report internal error and die>>
1827
currif->option = opt;
1831
\subsubsection{Auto Line}
1833
Processing an [[auto]] line is pretty straightforward after the above,
1834
we just need to add each parameter to the list and check for duplicates.
1836
<<process [[auto]] line>>=
1837
while((rest = next_word(rest, firstword, 80))) {
1838
<<check [[firstword]] isn't already an auto interface or die>>
1839
<<add [[firstword]] as an auto interface or die>>
1843
<<check [[firstword]] isn't already an auto interface or die>>=
1847
for (i = 0; i < defn->n_autointerfaces; i++) {
1848
if (strcmp(firstword, defn->autointerfaces[i]) == 0) {
1849
<<report duplicate auto interface and die>>
1855
<<add [[firstword]] as an auto interface or die>>=
1856
if (defn->n_autointerfaces == defn->max_autointerfaces) {
1858
defn->max_autointerfaces *= 2;
1859
defn->max_autointerfaces++;
1860
tmp = realloc(defn->autointerfaces,
1861
sizeof(*tmp) * defn->max_autointerfaces);
1863
<<report internal error and die>>
1865
defn->autointerfaces = tmp;
1868
defn->autointerfaces[defn->n_autointerfaces] = strdup(firstword);
1869
defn->n_autointerfaces++;
1872
\subsection{Error Handling}
1874
We don't do anything too fancy about handling errors that occur, we
1875
just print out a hopefully helpful error message, and return from the
1876
function. \emph{We probably should also go to some effort to close files,
1877
and free memory, but well, you know. Maybe version $n+1$. --- aj}
1879
<<report internal error and die>>=
1884
<<report too few parameters for iface line and die>>=
1885
fprintf(stderr, "%s:%d: too few parameters for iface line\n", filename, line);
1889
<<report too many parameters for iface line and die>>=
1890
fprintf(stderr, "%s:%d: too many parameters for iface line\n", filename, line);
1894
<<report unknown address family and die>>=
1895
fprintf(stderr, "%s:%d: unknown address type\n", filename, line);
1899
<<report unknown method and die>>=
1900
fprintf(stderr, "%s:%d: unknown method\n", filename, line);
1904
<<report duplicate interface and die>>=
1905
fprintf(stderr, "%s:%d: duplicate interface\n", filename, line);
1909
<<report duplicate auto interface and die>>=
1910
fprintf(stderr, "%s:%d: interface declared auto twice\n", filename, line);
1914
<<report duplicate option and die>>=
1915
fprintf(stderr, "%s:%d: duplicate option\n", filename, line);
1919
<<report duplicate script in mapping and die>>=
1920
fprintf(stderr, "%s:%d: duplicate script in mapping\n", filename, line);
1924
<<report bad option and die>>=
1925
fprintf(stderr, "%s:%d: misplaced option\n", filename, line);
1931
The [[execute]] module will be laid out in the standard manner, and
1932
will make use of the usual header files.
1936
<<execute global variables>>
1937
<<execute function declarations>>
1938
<<execute functions>>
1941
<<execute headers>>=
1951
The key functions we export from here are all the functions that as a
1952
fairly direct result run some executable.
1955
\item [[iface_up()]] and [[iface_down()]] which will actually
1956
configure or deconfigure an interface.
1958
\item [[execute()]] which will take an interface definition and
1959
a command and fill in the details from the first into the
1960
second, and the execute the result. This is basically just a
1961
callback for the address family module.
1963
\item [[run_mapping()]] which will run a mapping script and
1964
determine if a new logical interface should be selected.
1967
We'll discuss each of these in order.
1969
\subsection{Interface Configuration and Deconfiguration}
1971
Most of the complexity is involved in implementing the [[iface_up()]] and
1972
[[iface_down()]] functions. These are complicated enough that an explanatory
1973
diagram is probably useful:
1976
\includegraphics[height=60mm]{execution}
1979
At a conceptual level, [[iface_up()]] and [[iface_down()]] have a
1980
reasonably straightforward job: they have to run one set of scripts,
1981
the configure or deconfigure the interface, then run another set of
1984
This is complicated slightly in that they also have to handle the
1985
possibility that some of an interface's required arguments may be missing
1986
(in which case none of the commands should be attempted), and that some
1987
of the commands may fail (in which case none of the following commands
1988
should be attempted). We've already encoded most of the early-abort
1989
logic for the latter case into the address family definitions; so the way
1990
we'll handle the the former case is simply to call the address family's
1991
method [[up()]] or [[down()]] twice: once to ensure all the variables are
1992
appropriately filled out, and once to actually configure the interface.
1994
\subsubsection{Command checking}
1996
As such, we'll make use of two execution functions, each of which take
1997
one parameter, a shell command. We'll uninventively call thses [[doit()]]
1998
and [[check()]]. They'll return 0 on failure, non-zero on success.
2000
[[check()]] is thus fairly trivial:
2002
<<execute function declarations>>=
2003
static int check(char *str);
2006
<<execute functions>>=
2007
static int check(char *str) {
2012
\subsubsection{Environment handling}
2014
[[doit()]] is much more complicated, mainly by the fact that we
2015
don't simply want to just run the programs, but because we also want
2016
to setup a sanitized environment. In particular, we want to make the
2017
environment variables [[IFACE]], and [[MODE]] available (eg, [[eth0]] and
2018
[[start]] respectively), and we want to export all the given options as
2019
[[IF_OPTION]], with some sanitisation.
2021
We'll do this just once per interface rather than once per command,
2022
and so we'll use a global variable to store our new environment, and a
2023
special function which will initialise it for us.
2025
<<execute global variables>>=
2026
static char **environ = NULL;
2029
[[environ]] will be in the format used by the [[execle()]] function call,
2030
that is, a [[NULL]]-terminated array of strings of the form [[foo=bar]].
2032
<<execute function declarations>>=
2033
static void set_environ(interface_defn *iface, char *mode);
2036
Our function then will be:
2038
<<execute functions>>=
2039
static void set_environ(interface_defn *iface, char *mode) {
2040
<<variables local to set environ>>
2043
<<initialise environ>>
2045
for (i = 0; i < iface->n_options; i++) {
2046
<<[[continue]] if option is a command>>
2048
<<add [[IF_]]option to environment>>
2050
<<add [[IFACE]] to environment>>
2051
<<add [[MODE]] to environment>>
2055
Since we keep adding at the end, we'll make use of a pointer to keep track
2056
of where the end actually is, namely:
2058
<<variables local to set environ>>=
2062
Initialising thus becomes:
2064
<<initialise environ>>=
2065
<<clear environ if necessary>>
2067
environ = malloc(sizeof(char*) * (iface->n_options + 3));
2068
environend = environ;
2072
<<clear environ if necessary>>=
2075
if (environ != NULL) {
2076
for (ppch = environ; *ppch; ppch++) {
2086
Our continue chunk is also fairly straight forward:
2088
<<[[continue]] if option is a command>>=
2089
if (strcmp(iface->option[i].name, "up") == 0
2090
|| strcmp(iface->option[i].name, "down") == 0
2091
|| strcmp(iface->option[i].name, "pre-up") == 0
2092
|| strcmp(iface->option[i].name, "post-down") == 0)
2098
We'll make use of a small helper function for actually setting the
2099
environment. This function will handle [[malloc]]ing enough memory, and
2100
ensuring the environment variable name is reasonably sensible. It'll
2101
take three parameters: a [[printf]]-style format string presumed to
2102
contain two [[%s]]s, and the two parameters to that format string.
2104
<<execute function declarations>>=
2105
static char *setlocalenv(char *format, char *name, char *value);
2108
We can then go ahead and fill in the environment.
2110
<<add [[IF_]]option to environment>>=
2111
*(environend++) = setlocalenv("IF_%s=%s", iface->option[i].name,
2112
iface->option[i].value);
2116
<<add [[IFACE]] to environment>>=
2117
*(environend++) = setlocalenv("%s=%s", "IFACE", iface->iface);
2121
<<add [[MODE]] to environment>>=
2122
*(environend++) = setlocalenv("%s=%s", "MODE", mode);
2126
Our helper function then will then be something like:
2128
<<execute functions>>=
2129
static char *setlocalenv(char *format, char *name, char *value) {
2132
<<allocate memory for [[result]]>>
2134
sprintf(result, format, name, value);
2142
Allocating the memory is fairly straightforward (although working out
2143
exactly how much memory involves a little guesswork, and assuming the
2144
caller passes in a reasonable [[format]]).
2146
<<allocate memory for [[result]]>>=
2147
result = malloc(strlen(format) /* -4 for the two %s's */
2157
And finally, tidying the result is a fairly simple matter of eliding all
2158
the characters we don't like, or translating them to ones we do like. We
2159
do like upper case letters, digits and underscores; and we're willing
2160
to translate hyphens and lower case letters. So here we go.
2162
<<tidy [[result]]>>=
2166
for(here = there = result; *there != '=' && *there; there++) {
2167
if (*there == '-') *there = '_';
2168
if (isalpha(*there)) *there = toupper(*there);
2170
if (isalnum(*there) || *there == '_') {
2175
memmove(here, there, strlen(there) + 1);
2179
\subsubsection{Command Execution}
2181
Our [[doit()]] function is then essentially a rewrite of the standard
2182
[[system()]] function call. The only additions are that we setup our
2183
child's environment as discussed previously, and we make use of two
2184
external globals, [[no_act]] and [[verbose]] and modify our behaviour
2187
<<execute function declarations>>=
2188
static int doit(char *str);
2191
<<execute functions>>=
2192
static int doit(char *str) {
2195
if (verbose || no_act) {
2196
fprintf(stderr, "%s\n", str);
2202
switch(child = fork()) {
2203
case -1: /* failure */
2206
execle("/bin/sh", "/bin/sh", "-c", str, NULL, environ);
2208
default: /* parent */
2210
waitpid(child, &status, 0);
2211
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
2218
\subsubsection{Executing a list of commands}
2220
In addition to the above, we also need a function to cope with running
2221
all the [[pre-up]] commands and so forth.
2223
<<exported symbols>>=
2224
int execute_all(interface_defn *ifd, execfn *exec, char *opt);
2227
All we need to do for this is to iterate through the options in the
2228
interface definition, and execute whichever ones are the right type,
2229
and call the [[run-parts]] command on the appropriate directory of
2230
scripts. That doesn't make for thrilling code.
2232
This function will generally have [[doit]] passed in as the [[exec]]
2235
<<execute functions>>=
2236
int execute_all(interface_defn *ifd, execfn *exec, char *opt) {
2239
for (i = 0; i < ifd->n_options; i++) {
2240
if (strcmp(ifd->option[i].name, opt) == 0) {
2241
if (!(*exec)(ifd->option[i].value)) {
2247
sprintf(buf, "run-parts /etc/network/if-%s.d", opt);
2254
\subsubsection{[[iface_up()]] and [[iface_down()]]}
2256
Our functions, then are:
2258
<<exported symbols>>=
2259
int iface_up(interface_defn *iface);
2260
int iface_down(interface_defn *iface);
2263
<<execute functions>>=
2264
int iface_up(interface_defn *iface) {
2265
if (!iface->method->up(iface,check)) return -1;
2267
set_environ(iface, "start");
2268
if (!execute_all(iface,doit,"pre-up")) return 0;
2269
if (!iface->method->up(iface,doit)) return 0;
2270
if (!execute_all(iface,doit,"up")) return 0;
2276
<<execute functions>>=
2277
int iface_down(interface_defn *iface) {
2278
if (!iface->method->down(iface,check)) return -1;
2280
set_environ(iface, "stop");
2281
if (!execute_all(iface,doit,"down")) return 0;
2282
if (!iface->method->down(iface,doit)) return 0;
2283
if (!execute_all(iface,doit,"post-down")) return 0;
2289
\subsection{Command Parsing}
2291
All the above just leave one thing out: how the address family method's
2292
configuration function gets back to calling [[doit()]]. This function
2293
answers that question:
2295
<<exported symbols>>=
2296
int execute(char *command, interface_defn *ifd, execfn *exec);
2299
At the somewhat abstract level, this is fairly trivial. The devil is
2300
in the details of the parsing, which makes up the rest of the module.
2302
<<execute functions>>=
2303
int execute(char *command, interface_defn *ifd, execfn *exec) {
2307
out = parse(command, ifd);
2308
if (!out) { return 0; }
2317
We'll need a basic parser function, which we'll call [[parse()]], to
2318
make the appropriate substitutions into a command. It's probably worth
2319
a note as to exactly what substitutions may be made:
2323
\item Special characters can be escaped with a backslash. eg
2324
[[ls MoreThan80\%]].
2326
\item Variables can be substituted by including their name
2327
delimeted by percents. eg [[ls %directory%]].
2329
\item Optional components may be enclosed in double square
2330
brackets. Optional components will be included exactly when
2331
every variable referenced within exists. eg
2332
[[ls [[--color=%color%]]][[] %directory%]]. Optional components
2337
Most of the parsing is fairly straightforward -- basically, we keep an
2338
output buffer, and add things to it as we stroll through the input
2339
buffer: either the actual character we want, or whatever the value of
2340
the variable we're looking at is, or whatever. The only particularly
2341
complicated bit is how we deal with the optional sections, which will
2342
be explained when we get to them.
2344
<<execute function declarations>>=
2345
static char *parse(char *command, interface_defn *ifd);
2348
<<execute functions>>=
2349
static char *parse(char *command, interface_defn *ifd) {
2350
<<variables local to parse>>
2358
<<deal with error conditions>>
2364
\subsubsection{Maintain output buffer}
2366
So the first thing we need to do is actually write some code to deal
2367
with the output buffer, which will need to be dynamically resized and
2368
so on to take care of possibly long strings and what-not. It is the
2369
caller's responsibility to [[free()]] this buffer. We'll maintain two
2370
extra variables for convenience: who much memory we've allocated
2371
[[len]], and where the next character should be stuck [[pos]].
2373
<<variables local to parse>>=
2374
char *result = NULL;
2375
size_t pos = 0, len = 0;
2378
This makes it pretty easy to return the result to the caller, too.
2384
The main thing to be done to this buffer is to add characters or
2385
strings to it. To deal with this, we'll make use of an [[addstr()]]
2386
function that resizes the buffer as necessary, and appends a string to
2387
it. So we can deal with single characters, and substrings in general,
2388
we'll specify the string to be added as a pointer-length combination,
2389
rather than as a [[NUL]] terminated string.
2391
<<execute function declarations>>=
2392
void addstr(char **buf, size_t *len, size_t *pos, char *str, size_t strlen);
2395
<<execute functions>>=
2396
void addstr(char **buf, size_t *len, size_t *pos, char *str, size_t strlen) {
2397
assert(*len >= *pos);
2398
assert(*len == 0 || (*buf)[*pos] == '\0');
2400
if (*pos + strlen >= *len) {
2402
newbuf = realloc(*buf, *len * 2 + strlen + 1);
2405
exit(1); /* a little ugly */
2408
*len = *len * 2 + strlen + 1;
2411
while (strlen-- >= 1) {
2412
(*buf)[(*pos)++] = *str;
2415
(*buf)[*pos] = '\0';
2419
Given this, we can define our default behaviour for a character:
2423
addstr(&result, &len, &pos, command, 1);
2428
\subsubsection{Escaped characters}
2430
We can also deal pretty simply with escaped tokens. The only special
2431
circumstance is if the [[\]] is at the very end of string. We don't
2432
want buffer overflows afterall.
2437
addstr(&result, &len, &pos, command+1, 1);
2440
addstr(&result, &len, &pos, command, 1);
2446
\subsubsection{Optional components}
2448
Basically we keep track of each optional section we're in, whether
2449
we've been unable to fill in any variables, and where we started
2450
it. When we reach the end of an optional section, we check to see if
2451
we were unable to fill in any variables, and, if so, we discard any
2452
text we'd added within that block. This also allows us to neatly check
2453
for any errors trying to fill in variables that aren't in optional
2456
Basically what we'll do here is keep one stack to represent where the
2457
various thingos started, and another to represent whether any
2458
variables didn't exist. We'll use the bottom-most entry in the stack
2459
to represent the entire command, and thus keep track of whether or not
2460
we have to return an error because an undefined variable was used in a
2461
non-optional part of the command.
2463
<<constant definitions>>=
2464
#define MAX_OPT_DEPTH 10
2467
<<variables local to parse>>=
2468
size_t old_pos[MAX_OPT_DEPTH] = {0};
2469
int okay[MAX_OPT_DEPTH] = {1};
2473
Given this, when we encounter a double open bracket, we need to just
2474
add the appropriate values to our stacks, and, similarly, when we
2475
encounter a double close bracket, we simply need to pop the stack, and
2476
see whether we need to move back or not, as well as taking care of an
2477
possible errors, naturally. \emph{We probably could actually give
2478
error messages here instead of just treating the brackets literally
2479
when they might cause problems. But there doesn't seem much point,
2484
if (command[1] == '[' && opt_depth < MAX_OPT_DEPTH) {
2485
old_pos[opt_depth] = pos;
2486
okay[opt_depth] = 1;
2490
addstr(&result, &len, &pos, "[", 1);
2498
if (command[1] == ']' && opt_depth > 1) {
2500
if (!okay[opt_depth]) {
2501
pos = old_pos[opt_depth];
2506
addstr(&result, &len, &pos, "]", 1);
2512
Finally, at the end of the function, the stacks can be left in an
2513
unacceptable state --- either one of the optional blocks was never
2514
closed, or an undefined variable was used elsewhere. We'll note these
2515
circumstances by returning [[NULL]] and setting [[errno]].
2517
<<execute headers>>=
2521
<<constant definitions>>=
2522
#define EUNBALBRACK 10001
2523
#define EUNDEFVAR 10002
2526
<<deal with error conditions>>=
2527
if (opt_depth > 1) {
2528
errno = EUNBALBRACK;
2540
\subsubsection{Variables}
2542
Dealing with variables is comparatively fairly simple. We just need to
2543
find the next percent, and see if whatever's inbetween is a variable,
2544
and, if so, get it's value.
2546
<<constant definitions>>=
2547
#define MAX_VARNAME 32
2548
#define EUNBALPER 10000
2554
<<variables local to handle percent token>>
2557
<<determine variable name>>
2559
<<get [[varvalue]]>>
2562
addstr(&result, &len, &pos, varvalue, strlen(varvalue));
2564
okay[opt_depth - 1] = 0;
2567
<<move to token after closing percent>>
2573
We don't do anything particularly clever dealing with the next percent
2574
--- just a pointer to the appropriate character.
2576
<<variables local to handle percent token>>=
2580
<<determine variable name>>=
2582
nextpercent = strchr(command, '%');
2590
<<move to token after closing percent>>=
2591
command = nextpercent + 1;
2594
The slightly tricky thing we do here is use a [[strncmpz]] function,
2595
which allows us to check that a string represented by a [[char*]] and
2596
a length is the same as a [[NUL]] terminated string.
2598
<<execute function declarations>>=
2599
int strncmpz(char *l, char *r, size_t llen);
2602
<<execute functions>>=
2603
int strncmpz(char *l, char *r, size_t llen) {
2604
int i = strncmp(l, r, llen);
2612
Given the above, the implementation of the [[get_var()]] function to
2613
lookup the value of a variable, is reasonably straight forward.
2615
<<execute function declarations>>=
2616
char *get_var(char *id, size_t idlen, interface_defn *ifd);
2619
<<execute functions>>=
2620
char *get_var(char *id, size_t idlen, interface_defn *ifd) {
2623
if (strncmpz(id, "iface", idlen) == 0) {
2626
for (i = 0; i < ifd->n_options; i++) {
2627
if (strncmpz(id, ifd->option[i].name, idlen) == 0) {
2628
return ifd->option[i].value;
2637
Which means we can finish of the chunk, thus:
2639
<<get [[varvalue]]>>=
2640
varvalue = get_var(command, nextpercent - command, ifd);
2643
\subsection{Mapping Scripts}
2645
Doing a mapping is moderately complicated, since we need to pass a
2646
fair bit of stuff to the script. The way we'll do this is via a
2647
mixture of command line arguments, and [[stdin]]: basically, we'll
2648
pass all the mapping variables from the interfaces file via [[stdin]],
2649
and anything else necessary will be a command line argument. The
2650
script will be expected to exit successfully with the appropriate
2651
logical interface as the first line of [[stdout]] if it made a match,
2652
or exit unsuccessfully (error code [[1]], eg) otherwise.
2654
<<exported symbols>>=
2655
int run_mapping(char *physical, char *logical, int len, mapping_defn *map);
2658
<<execute functions>>=
2659
int run_mapping(char *physical, char *logical, int len, mapping_defn *map) {
2664
<<execute the mapping script>>
2665
<<send input to mapping script>>
2666
<<wait for mapping script to finish>>
2667
<<check output from mapping script>>
2673
The latter options here are fairly straightforward, given some Unix
2676
<<send input to mapping script>>=
2677
for (i = 0; i < map->n_mappings; i++) {
2678
fprintf(in, "%s\n", map->mapping[i]);
2683
<<wait for mapping script to finish>>=
2684
waitpid(pid, &status, 0);
2687
<<check output from mapping script>>=
2688
if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
2689
if (fgets(logical, len, out)) {
2690
char *pch = logical + strlen(logical) - 1;
2691
while (pch >= logical && isspace(*pch))
2698
Slightly more complicated is setting up the child process and grabbing
2699
its [[stdin]] and [[stdout]]. Unfortunately we can't just use
2700
[[popen()]] for this, since it'll only allow us to go one way. So,
2701
instead we'll write our own [[popen()]]. It'll look like:
2703
<<execute headers>>=
2707
<<execute function declarations>>=
2708
static int popen2(FILE **in, FILE **out, char *command, ...);
2711
The varargs component will be the arguments, as per [[execl()]], and
2712
the return value will be the [[PID]] if the call was successful, or 0
2715
As such, we will be able to execute the scrtip thusly:
2717
<<execute the mapping script>>=
2718
pid = popen2(&in, &out, map->script, physical, NULL);
2724
Writing [[popen2()]] is an exercise in Unix arcana.
2726
<<execute headers>>=
2728
#include <sys/wait.h>
2731
<<execute functions>>=
2732
static int popen2(FILE **in, FILE **out, char *command, ...) {
2734
char *argv[11] = {command};
2736
int infd[2], outfd[2];
2740
va_start(ap, command);
2741
while((argc < 10) && (argv[argc] = va_arg(ap, char*))) {
2744
argv[argc] = NULL; /* make sure */
2747
if (pipe(infd) != 0) return 0;
2748
if (pipe(outfd) != 0) {
2749
close(infd[0]); close(infd[1]);
2753
switch(pid = fork()) {
2754
case -1: /* failure */
2755
close(infd[0]); close(infd[1]);
2756
close(outfd[0]); close(outfd[1]);
2761
close(infd[0]); close(infd[1]);
2762
close(outfd[0]); close(outfd[1]);
2763
execvp(command, argv);
2765
default: /* parent */
2766
*in = fdopen(infd[1], "w");
2767
*out = fdopen(outfd[0], "r");
2768
close(infd[0]); close(outfd[1]);
2775
\section{The Driver}
2777
The final C module we'll have is the one with the [[main()]]
2778
function. It's put together in a fairly straightforward way.
2782
<<main global variables>>
2783
<<main function declarations>>
2788
Equally, there's nothing particularly special about our headers.
2801
Now, after all the above modules, our main program doesn't have too
2802
much to do: it just has to interpret arguments and coordinate the
2803
intervening modules. Since we're being ``smart'', as well as parsing
2804
arguments, we'll decide whether the interface is going up or down
2805
depending on whether we were called as [[ifup]] or [[ifdown]].
2808
int main(int argc, char **argv) {
2809
<<variables local to main>>
2811
<<ensure environment is sane>>
2813
<<parse command name or die>>
2816
<<read interfaces files or die>>
2818
<<run commands for appropriate interfaces>>
2824
\subsection{Check the Environment}
2826
In the earlier code we assume that we have stdin, stdout and stderr all
2827
available. We need to assure that, just in case:
2834
<<ensure environment is sane>>=
2837
for (i = 0; i <= 2; i++) {
2838
if (fcntl(i, F_GETFD) == -1) {
2839
if (errno == EBADF && open("/dev/null", 0) == -1) {
2841
"%s: fd %d not available; aborting\n",
2844
} else if (errno == EBADF) {
2845
errno = 0; /* no more problems */
2847
/* some other problem -- eeek */
2856
\subsection{Configuring or Deconfiguring?}
2858
So the very first real thing we need to do is parse the command name. To
2859
do this, we'll obviously need to work out somewhere to store the result. A
2860
reasonable thing to do here is just to keep a function pointer about,
2861
which will point to one of the previously defined [[iface_up]] or
2862
[[iface_down]] functions, depending on which should be used on the
2863
specified interfaces.
2865
<<variables local to main>>=
2866
int (*cmds)(interface_defn *) = NULL;
2869
So given this, we can just:
2871
<<parse command name or die>>=
2875
<<set [[command]] to the base of the command name>>
2876
<<set [[cmds]] based on [[command]] or die>>
2880
And fill out each component in the reasonably obvious manner of:
2882
<<set [[command]] to the base of the command name>>=
2883
if ((command = strrchr(argv[0],'/'))) {
2884
command++; /* first char after / */
2886
command = argv[0]; /* no /'s in argv[0] */
2890
<<set [[cmds]] based on [[command]] or die>>=
2891
if (strcmp(command, "ifup")==0) {
2893
} else if (strcmp(command, "ifdown")==0) {
2896
fprintf(stderr,"This command should be called as ifup or ifdown\n");
2901
In addition, since our later behaviour varies depending on whether we're
2902
bringing interfaces up or taking them down we'll define two chunks to assist
2905
<<we're bringing interfaces up>>=
2909
<<we're taking interfaces down>>=
2910
(cmds == iface_down)
2913
\subsection{Argument Handling}
2915
Okay, so next on our agenda is argument handling.
2917
We'll do argument handling via the GNU [[getopt]] function, which
2918
means we have to include the appropriate header, and define a cute
2919
little structure to represent out long options:
2925
<<variables local to main>>=
2926
struct option long_opts[] = {
2927
{"help", no_argument, NULL, 'h'},
2928
{"version", no_argument, NULL, 'V'},
2929
{"verbose", no_argument, NULL, 'v'},
2930
{"all", no_argument, NULL, 'a'},
2931
{"interfaces", required_argument, NULL, 'i'},
2932
{"no-act", no_argument, NULL, 'n'},
2933
{"no-mappings", no_argument, NULL, 1 },
2934
{"force", no_argument, NULL, 2 },
2939
The usual way of dealing with options then is to have a variable to store
2940
the various things. The only special note here is that we need to export
2941
[[no_act]] and [[verbose]] to the [[execute]] module.
2943
<<exported symbols>>=
2948
<<main global variables>>=
2953
<<variables local to main>>=
2955
int run_mappings = 1;
2957
char *interfaces = "/etc/network/interfaces";
2960
We'll also have two helper functions to display usage information,
2963
<<main function declarations>>=
2964
static void usage(char *execname);
2965
static void help(char *execname);
2966
static void version(char *execname);
2970
static void usage(char *execname) {
2971
fprintf(stderr, "%s: Use --help for help\n", execname);
2977
static void version(char *execname) {
2978
printf("%s version " IFUPDOWN_VERSION "\n", execname);
2979
printf("Copyright (c) 1999,2000 Anthony Towns\n\n");
2982
"This program is free software; you can redistribute it and/or modify\n"
2983
"it under the terms of the GNU General Public License as published by\n"
2984
"the Free Software Foundation; either version 2 of the License, or (at\n"
2985
"your option) any later version.\n"
2993
static void help(char *execname) {
2994
printf("Usage: %s <options> <ifaces...>\n\n", execname);
2995
printf("Options:\n");
2996
printf("\t-h, --help\t\tthis help\n");
2997
printf("\t-V, --version\t\tcopyright and version information\n");
2998
printf("\t-a, --all\t\tde/configure all interfaces automatically\n");
2999
printf("\t-i, --interfaces FILE\tuse FILE for interface definitions\n");
3000
printf("\t-n, --no-act\t\tprint out what would happen, but don't do it\n");
3001
printf("\t\t\t\t(note that this option doesn't disable mappings)\n");
3002
printf("\t-v, --verbose\t\tprint out what would happen before doing it\n");
3003
printf("\t--no-mappings\t\tdon't run any mappings\n");
3004
printf("\t--force\t\t\tforce de/configuration\n");
3009
Now, the meat of argument parsing is done with [[getopt()]] and a
3010
[[switch]], like so:
3012
<<parse arguments>>=
3015
c = getopt_long(argc, argv, "s:i:hVvna", long_opts, NULL);
3016
if (c == EOF) break;
3019
<<[[getopt]] possibilities>>
3023
<<check unreasonable arguments>>
3026
Now, our [[getopt]] possibilities are basically each option, or something
3027
really bad. Actual interface names are automagically collected at the end
3028
by [[getopt()]].So first, the legitimate cases get handled:
3030
<<[[getopt]] possibilities>>=
3032
interfaces = strdup(optarg);
3035
<<[[getopt]] possibilities>>=
3040
<<[[getopt]] possibilities>>=
3045
<<[[getopt]] possibilities>>=
3050
<<[[getopt]] possibilities>>=
3055
<<[[getopt]] possibilities>>=
3061
And we also have a help option and a version option:
3063
<<[[getopt]] possibilities>>=
3068
<<[[getopt]] possibilities>>=
3074
And we also have the possibility that the user is just making up
3077
<<[[getopt]] possibilities>>=
3083
After all that there are still some things that can be a bit weird. We
3084
can be told either to act on all interfaces (except the noauto ones),
3085
or we can be told to act on specific interface. We won't accept been
3086
told to do both, and we won't accept not being told to do one or the
3087
other. We can test these two cases as follows:
3089
<<check unreasonable arguments>>=
3090
if (argc - optind > 0 && do_all) {
3095
<<check unreasonable arguments>>=
3096
if (argc - optind == 0 && !do_all) {
3101
\subsection{Reading the Interfaces File}
3103
Since this has all been covered in a previous section, this is pretty
3106
<<variables local to main>>=
3107
interfaces_file *defn;
3110
<<read interfaces files or die>>=
3111
defn = read_interfaces(interfaces);
3113
fprintf(stderr, "%s: couldn't read interfaces file \"%s\"\n",
3114
argv[0], interfaces);
3119
\subsection{Execution}
3121
A broad overview of what we'll actually be doing is as follows:
3123
<<run commands for appropriate interfaces>>=
3124
<<load ifupdown state>>
3125
<<determine target interfaces>>
3128
for (<<each target interface, [[i]]>>) {
3129
char iface[80], liface[80];
3131
<<initialize [[iface]] to [[i]]th target interface>>
3133
<<check ifupdown state (possibly [[continue]])>>
3136
if (<<we're bringing interfaces up>> && run_mappings) {
3140
<<bring interface up/down and update ifupdown state>>
3141
<<commit ifupdown state>>
3146
We'll leave determining the appropriate target interfaces and dealing
3147
with the state until a little later. That leaves us with covering running
3148
the mappings and bringing the interface up or taking it down.
3150
Mappings are dealt with like so:
3154
mapping_defn *currmap;
3155
for (currmap = defn->mappings; currmap; currmap = currmap->next) {
3157
for (i = 0; i < currmap->n_matches; i++) {
3158
<<[[continue]] unless mapping matches>>
3166
We check if mappings match by using shell globs, so we'll need a new header
3167
to take care of that.
3170
#include <fnmatch.h>
3173
<<[[continue]] unless mapping matches>>=
3174
if (fnmatch(currmap->match[i], liface, 0) != 0)
3178
Actually running a mapping is fairly straightforward, thanks to our
3183
fprintf(stderr, "Running mapping script %s on %s\n",
3184
currmap->script, liface);
3186
run_mapping(iface, liface, sizeof(liface), currmap);
3189
Bringing an interface up or taking it down can be done thusly:
3191
<<bring interface up/down and update ifupdown state>>=
3193
interface_defn *currif;
3195
for (currif = defn->ifaces; currif; currif = currif->next) {
3196
if (strcmp(liface, currif->iface) == 0) {
3198
<<run commands for [[currif]]>>
3202
if (!okay && !force) {
3203
fprintf(stderr, "Ignoring unknown interface %s=%s.\n",
3206
<<update ifupdown state>>
3211
<<run commands for [[currif]]>>=
3213
char *oldiface = currif->iface;
3214
currif->iface = iface;
3217
fprintf(stderr, "Configuring interface %s=%s (%s)\n",
3218
iface, liface, currif->address_family->name);
3221
switch(cmds(currif)) {
3223
printf("Don't seem to be have all the variables for %s/%s.\n",
3224
liface, currif->address_family->name);
3227
/* this wasn't entirely successful, should it be added to
3233
currif->iface = oldiface;
3237
\subsection{Target Interfaces}
3239
So, if we're going to actually do something, we should probably figure
3240
out exactly what we're going to do it to. So, we need to know the set
3241
of interfaces we're going to hax0r. This is just an array of interfaces,
3242
either [[physical_iface]] or [[physical_iface=logical_iface]].
3244
<<variables local to main>>=
3245
int n_target_ifaces;
3246
char **target_iface;
3249
<<each target interface, [[i]]>>=
3250
i = 0; i < n_target_ifaces; i++
3253
We initialise this based on our command line arguments.
3255
<<determine target interfaces>>=
3257
if (<<we're bringing interfaces up>>) {
3258
target_iface = defn->autointerfaces;
3259
n_target_ifaces = defn->n_autointerfaces;
3260
} else if (<<we're taking interfaces down>>) {
3261
target_iface = state;
3262
n_target_ifaces = n_state;
3267
target_iface = argv + optind;
3268
n_target_ifaces = argc - optind;
3272
<<initialize [[iface]] to [[i]]th target interface>>=
3273
strncpy(iface, target_iface[i], sizeof(iface));
3274
iface[sizeof(iface)-1] = '\0';
3278
if ((pch = strchr(iface, '='))) {
3280
strncpy(liface, pch+1, sizeof(liface));
3281
liface[sizeof(liface)-1] = '\0';
3283
strncpy(liface, iface, sizeof(liface));
3284
liface[sizeof(liface)-1] = '\0';
3291
Since it's generally not feasible to rerun a mapping script after an
3292
interface is configured (since a mapping script may well bring the
3293
interface down while it's investigating matters), we need to maintain a
3294
statefile between invocations to keep track of which phusical interfaces
3295
were mapped to which logical ones. We ought to use
3296
[[/var/run/ifupdown.state]] or something similar for this, but [[/var]]
3297
isn't guaranteed to be available until the network's up, so we'll use
3298
[[/etc/network/ifstate]] instead.
3300
<<variables local to main>>=
3301
char **state = NULL; /* list of iface=liface */
3306
We'll also use two helper functions: one to lookup an interface, and one to
3309
<<main function declarations>>=
3310
static int lookfor_iface(char **ifaces, int n_ifaces, char *iface);
3314
static int lookfor_iface(char **ifaces, int n_ifaces, char *iface) {
3316
for (i = 0; i < n_ifaces; i++) {
3317
if (strncmp(iface, ifaces[i], strlen(iface)) == 0) {
3318
if (ifaces[i][strlen(iface)] == '=') {
3327
<<main function declarations>>=
3328
static void add_to_state(char ***ifaces, int *n_ifaces, int *max_ifaces,
3333
static void add_to_state(char ***ifaces, int *n_ifaces, int *max_ifaces,
3336
assert(*max_ifaces >= *n_ifaces);
3337
if (*max_ifaces == *n_ifaces) {
3338
*max_ifaces = (*max_ifaces * 2) + 1;
3339
*ifaces = realloc(*ifaces, sizeof(**ifaces) * *max_ifaces);
3340
if (*ifaces == NULL) {
3346
(*ifaces)[(*n_ifaces)++] = new_iface;
3350
Given these, we can then load our state file like so:
3352
<<load ifupdown state>>=
3354
FILE *f = fopen("/etc/network/ifstate", "r");
3357
while(fgets(buf, 80, f)) {
3360
pch = buf + strlen(buf) - 1;
3361
while(pch > buf && isspace(*pch)) pch--;
3365
while(isspace(*pch)) pch++;
3367
add_to_state(&state, &n_state, &max_state, strdup(pch));
3374
<<commit ifupdown state>>=
3376
FILE *f = fopen("/etc/network/ifstate", "w");
3380
perror("/etc/network/ifstate");
3384
for (i = 0; i < n_state; i++) {
3385
fprintf(f, "%s\n", state[i]);
3392
This leaves our two useful chunks. The first checks to ensure what we're
3393
proposing to do is reasonable (ie, we're not downing an interface that's
3394
not up, or uping one that's not down).
3396
<<check ifupdown state (possibly [[continue]])>>=
3398
int already_up = lookfor_iface(state, n_state, iface);;
3400
if (<<we're bringing interfaces up>>) {
3401
if (already_up != -1) {
3403
"%s: interface %s already configured\n",
3407
} else if (<<we're taking interfaces down>>) {
3408
if (already_up == -1) {
3409
fprintf(stderr, "%s: interface %s not configured\n",
3413
strncpy(liface, strchr(state[already_up], '=') + 1, 80);
3421
And finally, we also need to be able to update the state as we bring
3422
interfaces up and down.
3424
<<update ifupdown state>>=
3426
int already_up = lookfor_iface(state, n_state, iface);
3428
if (<<we're bringing interfaces up>>) {
3430
malloc(strlen(iface) + 1 + strlen(liface) + 1);
3431
sprintf(newiface, "%s=%s", iface, liface);
3433
if (already_up == -1) {
3434
add_to_state(&state, &n_state, &max_state, newiface);
3436
free(state[already_up]);
3437
state[already_up] = newiface;
3439
} else if (<<we're taking interfaces down>>) {
3440
if (already_up != -1) {
3441
state[already_up] = state[--n_state];
3451
\section{Linux Address Families}
3454
unsigned int mylinuxver();
3455
unsigned int mylinux(int,int,int);
3456
int execable(char *);
3464
#include <sys/utsname.h>
3465
#include <sys/stat.h>
3467
#include "archlinux.h"
3469
unsigned int mylinuxver() {
3470
static int maj = -1, rev, min;
3476
maj = atoi(u.release);
3477
pch = strchr(u.release, '.');
3479
pch = strchr(pch+1, '.');
3483
return mylinux(maj,rev,min);
3486
unsigned int mylinux(int maj, int rev, int min) {
3487
return min | rev << 10 | maj << 13;
3490
int execable(char *program) {
3493
if (0 == stat(program, &buf)) {
3494
if (S_ISREG(buf.st_mode) && (S_IXUSR & buf.st_mode)) return 1;
3500
\subsection{IPv4 Address Family}
3502
<<address family declarations>>=
3503
extern address_family addr_inet;
3506
<<address family references>>=
3520
This method may be used to define the IPv4 loopback interface.
3523
ifconfig %iface% 127.0.0.1 up
3524
route add -net 127.0.0.0 if ( mylinuxver() < mylinux(2,1,100) )
3527
ifconfig %iface% down
3533
This method may be used to define ethernet interfaces with statically
3534
allocated IPv4 addresses.
3537
address address -- Address (dotted quad) *required*
3538
netmask netmask -- Netmask (dotted quad) *required*
3539
broadcast broadcast_address -- Broadcast address (dotted quad)
3540
network network_address -- Network address (dotted quad) *required \
3542
gateway address -- Default gateway (dotted quad)
3543
pointopoint address -- Address of other end point (dotted quad). \
3544
Note the spelling of "point-to".
3547
ifconfig %iface% %address% netmask %netmask% [[broadcast %broadcast%]] \
3548
[[pointopoint %pointopoint%]] up
3549
route add -net %network% \
3550
if ( mylinuxver() < mylinux(2,1,100) )
3551
[[ route add default gw %gateway% %iface% ]]
3554
[[ route del default gw %gateway% %iface% ]]
3555
ifconfig %iface% down
3561
This method may be used to obtain an address via DHCP with any of
3562
the tools: dhclient, pump (2.2.x kernels only), or dhcpcd.
3563
If you have a complicated DHCP setup you should
3564
note that some of these clients use their own configuration files,
3565
rather than obtaining their configuration via *ifup*.
3568
hostname hostname -- Hostname to be requested (pump, dhcpcd)
3569
leasehours leastime -- Preferred lease time in hours (pump)
3570
leasetime leasetime -- Preferred lease time in seconds (dhcpcd)
3571
vendor vendor -- Vendor class identifier (dhcpcd)
3572
client client_id -- Client identifier (dhcpcd)
3576
if (execable("/sbin/dhclient"))
3577
pump -i %iface% [[-h %hostname%]] [[-l %leasehours%]] \
3578
elsif (execable("/sbin/pump") && mylinuxver() >= mylinux(2,1,100))
3579
dhcpcd [[-h %hostname%]] [[-i %vendor%]] [[-I %clientid%]] \
3580
[[-l %leasetime%]] %iface% \
3581
elsif (execable("/sbin/dhcpcd"))
3584
cat /var/run/dhclient.pid | xargs -i kill -TERM {} \
3585
if (execable("/sbin/dhclient"))
3586
pump -i %iface% -k \
3587
elsif (execable("/sbin/pump") && mylinuxver() >= mylinux(2,1,100))
3589
elsif (execable("/sbin/dhcpcd"))
3591
ifconfig %iface% down
3597
This method may be used to obtain an address via bootp.
3600
bootfile file -- Tell the server to use /file/ as the bootfile.
3601
server address -- Use the IP address /address/ to communicate with \
3603
hwaddr addr -- Use /addr/ as the hardware address instead of \
3604
whatever it really is.
3607
bootpc [[--bootfile %bootfile%]] --dev %iface% [[--server %server%]] \
3608
[[--hwaddr %hwaddr%]] --returniffail --serverbcast
3611
ifconfig down %iface%
3617
This method uses pon/poff to configure a PPP interface. See those
3618
commands for details.
3620
provider name -- Use /name/ as the provider (from /etc/ppp/peers).
3627
\subsection{IPv6 Address Family}
3629
<<address family declarations>>=
3630
extern address_family addr_inet6;
3633
<<address family references>>=
3638
address_family inet6
3643
This method may be used to define the IPv6 loopback interface.
3645
ifconfig %iface% add ::1
3647
ifconfig %iface% del ::1
3651
This method may be used to define interfaces with statically assigned
3655
address address -- Address (colon delimited) *required*
3656
netmask mask -- Netmask (number of bits, eg 64) *required*
3657
gateway address -- Default gateway (colon delimited)
3661
ifconfig %iface% add %address%/%netmask%
3662
[[ route -A inet6 add ::/0 gw %gateway% ]]
3665
ifconfig %iface% down
3669
This method may be used to setup an IPv6-over-IPv4 tunnel. It requires
3670
the *ip* command from the *iproute* package.
3673
address address -- Address (colon delimited) *required*
3674
netmask mask -- Netmask (number of bits, eg 64) *required*
3675
endpoint address -- Address of other tunnel endpoint (IPv4 \
3676
dotted quad) *required*
3677
gateway address -- Default gateway (colon delimited)
3680
ip tunnel add %iface% mode sit remote %endpoint%
3681
ip link set %iface% up
3682
ip addr add %address%/%netmask% dev %iface%
3683
[[ ip route add ::/0 via %gateway% ]]
3686
ip tunnel del %iface%
3689
\subsection{IPX Address Family}
3691
<<address family declarations>>=
3692
extern address_family addr_ipx;
3695
<<address family references>>=
3705
This method may be used to setup an IPX interface.
3712
ipx_interface add %iface% %frame% %netnum%
3715
ipx_interface del %iface% %frame%
3719
This method may be used to setup an IPX interface dynamically.
3725
ipx_interface add %iface% %frame%
3728
ipx_interface del %iface% %frame%
3732
\bibliography{biblio}
3733
\bibliographystyle{unsrt}