~ubuntu-branches/ubuntu/hoary/ifupdown/hoary

« back to all changes in this revision

Viewing changes to ifupdown.nw

  • Committer: Bazaar Package Importer
  • Author(s): Anthony Towns
  • Date: 2001-06-19 00:04:30 UTC
  • Revision ID: james.westby@ubuntu.com-20010619000430-ivxncx51i5i5dpk0
Tags: upstream-0.6.4
ImportĀ upstreamĀ versionĀ 0.6.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
%
 
2
\documentclass{article}
 
3
\usepackage{graphicx}
 
4
\usepackage{noweb}
 
5
\pagestyle{noweb}
 
6
\noweboptions{smallcode,hideunuseddefs}
 
7
\begin{document}
 
8
@
 
9
 
 
10
\def\nwendcode{\endtrivlist\endgroup}
 
11
\let\nwdocspar=\relax
 
12
 
 
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
 
18
later version.  
 
19
}}
 
20
 
 
21
\author{ Anthony Towns \\ { \tt aj@azure.humbug.org.au } }
 
22
 
 
23
\pagenumbering{roman}
 
24
 
 
25
\maketitle
 
26
\tableofcontents
 
27
 
 
28
\vfill
 
29
\pagebreak
 
30
\pagenumbering{arabic}
 
31
 
 
32
\section{Introduction}
 
33
 
 
34
This source defines the commands [[ifup]] and [[ifdown]], used to
 
35
manipulate interfaces in an easily controllable manner.
 
36
 
 
37
\subsection{Assumed Knowledge}
 
38
 
 
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
 
43
pages as necessary.
 
44
 
 
45
This source has been written as a literate program using the [[noweb]]
 
46
\cite{wwwnoweb} tool suite, and typeset using \LaTeX\ \cite{latex}.
 
47
 
 
48
\subsection{Program Structure}
 
49
 
 
50
We shall decompose this program into four main areas of functionality:
 
51
compile-time configuration, run-time configuration, execution, and the
 
52
overall driver.
 
53
 
 
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.
 
59
 
 
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
 
63
[[config]] module.
 
64
 
 
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.
 
69
 
 
70
The remaining work --- argument parsing, error reporting, and,
 
71
essentially, putting all the pieces together --- is done by the
 
72
[[main]] module.
 
73
 
 
74
The following diagram gives a brief idea of the information and control
 
75
flow amongst the modules.
 
76
 
 
77
\begin{center}
 
78
\includegraphics[height=45mm]{modules}
 
79
\end{center}
 
80
 
 
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.
 
89
 
 
90
<<header.h>>=
 
91
#ifndef HEADER_H
 
92
#define HEADER_H
 
93
 
 
94
<<type definitions>>
 
95
<<function type definitions>>
 
96
<<structure definitions>>
 
97
<<constant definitions>>
 
98
<<exported symbols>>
 
99
 
 
100
#endif /* HEADER_H */
 
101
 
102
 
 
103
\section{The Build System}
 
104
 
 
105
We shall begin with the template for the Makefile we shall use.
 
106
 
 
107
<<Makefile>>=
 
108
<<make options>>
 
109
 
 
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
 
114
 
 
115
OBJ := main.o addrfam.o execute.o config.o \
 
116
        $(patsubst %.defn,%.o,$(DEFNFILES)) archlinux.o
 
117
 
 
118
MAN := $(patsubst %.defn,%.man,$(DEFNFILES))
 
119
 
 
120
default : executables
 
121
all : executables docs
 
122
 
 
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
 
125
 
 
126
.PHONY : executables 
 
127
<<phony targets>>
 
128
<<executable targets>>
 
129
<<manpage targets>>
 
130
<<extra dependencies>>
 
131
<<implicit rules>>
 
132
 
 
133
include ifupdown.d
 
134
 
135
 
 
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.
 
139
 
 
140
<<executable targets>>=
 
141
ifup: $(OBJ)
 
142
        $(CC) $(CFLAGS) -o ifup $^
 
143
 
 
144
ifdown: ifup
 
145
        ln -sf ifup ifdown
 
146
 
147
 
 
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
 
150
same manpage too?
 
151
 
 
152
<<manpage targets>>=
 
153
interfaces.5: interfaces.5.pre $(MAN)
 
154
        LINE=$$(grep -n '^##ADDRESSFAM##$$' $< | sed 's/:.*//g'); \
 
155
        WC=`wc -l < $<`;                                          \
 
156
        (                                                         \
 
157
          head -$$(($$LINE - 1)) $<;                              \
 
158
          cat $(MAN);                                             \
 
159
          tail -$$(($$WC - $$LINE)) $<;                           \
 
160
        ) > $@
 
161
 
 
162
ifdown.8: ifup.8
 
163
        ln -sf $< $@
 
164
 
 
165
%.5.ps: %.5
 
166
        groff -mandoc -Tps $< > $@
 
167
%.8.ps: %.8
 
168
        groff -mandoc -Tps $< > $@
 
169
 
170
 
 
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.
 
175
 
 
176
<<phony targets>>=
 
177
.PHONY : clean clobber
 
178
 
 
179
install :
 
180
        install -m 0755 -d     ${BASEDIR}/sbin
 
181
        install -m 0755 ifup   ${BASEDIR}/sbin
 
182
        ln ${BASEDIR}/sbin/ifup ${BASEDIR}/sbin/ifdown  
 
183
 
 
184
clean :
 
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
 
190
 
 
191
clobber : clean
 
192
        rm -f ifupdown.tex $(PERL) $(CFILES) $(HFILES) $(DEFNFILES)
 
193
 
 
194
distclean : clobber
 
195
        rm -f makecdep.sh makenwdep.sh Makefile
 
196
 
197
 
 
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.
 
201
 
 
202
<<implicit rules>>=
 
203
%.tex : %.nw
 
204
        noweave -delay -index -latex $< >$@
 
205
 
 
206
%.bbl : %.tex biblio.bib
 
207
        latex $<
 
208
        bibtex $(basename $<)
 
209
 
 
210
%.dvi : %.tex %.bbl
 
211
        latex $<
 
212
        latex $<
 
213
 
 
214
%.pdf : %.tex %.bbl
 
215
        pdflatex $<
 
216
        pdflatex $<
 
217
 
 
218
%.ps : %.dvi
 
219
        dvips -o $@ $<
 
220
 
 
221
%.gz : %
 
222
        gzip --best --stdout $< >$@
 
223
 
224
 
 
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.
 
228
 
 
229
<<make options>>=
 
230
CFLAGS := -Wall -W -g -O2 -D'IFUPDOWN_VERSION="0.6.4"'
 
231
CC := gcc
 
232
 
233
 
 
234
\subsection{Graphics}
 
235
 
 
236
We include a few graphics (made using dia) in this document. We have to
 
237
express these fairly explicitly, unfortunately.
 
238
 
 
239
<<implicit rules>>=
 
240
%.eps : %.dia
 
241
        dia -e $@ $<
 
242
 
 
243
%.pdf : %.eps
 
244
        gs -q -sDEVICE=pdfwrite -dNOPAUSE -sOutputFile=$@ - < $<
 
245
@
 
246
 
 
247
<<extra dependencies>>=
 
248
ifupdown.ps: modules.eps execution.eps
 
249
ifupdown.pdf: modules.pdf execution.pdf
 
250
@
 
251
 
 
252
\subsection{Automatic Dependencies}
 
253
 
 
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.
 
260
 
 
261
<<implicit rules>>=
 
262
%.d: %.nw makenwdep.sh
 
263
        ./makenwdep.sh $< > $@
 
264
@
 
265
 
 
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.
 
272
 
 
273
<<makenwdep.sh>>=
 
274
<<parse makenwdep arguments>>
 
275
 
 
276
noroots $FILE | sed 's/^<''<\(.*\)>>$/\1/' |
 
277
        while read chunk; do
 
278
                <<output dependency info for [[$chunk]]>>
 
279
        done
 
280
 
281
 
 
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.
 
286
 
 
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.
 
292
 
 
293
<<output dependency info for [[$chunk]]>>=
 
294
case $chunk in
 
295
        *.pl|*.sh)
 
296
                echo -e "$chunk : $FILE"
 
297
                echo -e "\tnotangle -R\$@ $< >\$@"
 
298
                echo -e "\tchmod 755 $chunk"
 
299
                ;;
 
300
        *.c)
 
301
                echo -e "$chunk : $FILE"
 
302
                echo -e "\tnotangle -L -R\$@ $< | cpif \$@"
 
303
                echo -e "include ${chunk%.c}.d"
 
304
                ;;
 
305
        *.h)
 
306
                echo -e "$chunk : $FILE"
 
307
                echo -e "\tnotangle -L -R\$@ $< | cpif \$@"
 
308
                ;;
 
309
        *)
 
310
                echo -e "$chunk : $FILE"
 
311
                echo -e "\tnotangle -t8 -R\$@ $< >\$@"
 
312
                ;;
 
313
esac
 
314
 
315
 
 
316
Finally, our fairly primitive argument parsing is simply:
 
317
 
 
318
<<parse makenwdep arguments>>=
 
319
FILE=$1
 
320
 
 
321
if [ "$FILE" = "" -o ! -f "$FILE" ]; then
 
322
        echo "Please specify a .nw file"
 
323
        exit 1
 
324
fi
 
325
 
326
 
 
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.
 
331
 
 
332
<<implicit rules>>=
 
333
%.d: %.c makecdep.sh
 
334
        ./makecdep.sh $< > $@
 
335
 
336
 
 
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).
 
341
 
 
342
<<makecdep.sh>>=
 
343
#!/bin/sh
 
344
<<parse makecdep arguments>>
 
345
 
 
346
gcc -MM -MG $FILE |
 
347
  sed -e 's@^\(.*\)\.o:@\1.o \1.d:@'
 
348
 
349
 
 
350
\emph{Deja vu}, anyone?
 
351
 
 
352
<<parse makecdep arguments>>= 
 
353
FILE=$1
 
354
if [ "$FILE" = "" -o ! -f "$FILE" ]; then
 
355
        echo "Please specify a .c file"
 
356
        exit 1
 
357
fi
 
358
@
 
359
 
 
360
\section{Compile Time Configuration}
 
361
 
 
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.
 
366
 
 
367
Our key definition at this point is that of the [[address_family]]
 
368
structure, which encapsulates all the compile time information about
 
369
each address family.
 
370
 
 
371
<<type definitions>>=
 
372
typedef struct address_family address_family;
 
373
 
374
 
 
375
<<structure definitions>>=
 
376
struct address_family {
 
377
        char *name;
 
378
        int n_methods;
 
379
        method *method;
 
380
};
 
381
 
382
 
 
383
Each defined address family will be included in the [[addr_fams]]
 
384
array, which becomes the \emph{raison d'\^etre} of the [[addrfam]]
 
385
module.
 
386
 
 
387
<<exported symbols>>=
 
388
extern address_family *addr_fams[];
 
389
 
390
 
 
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.
 
396
 
 
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
 
402
statement. --- aj}
 
403
 
 
404
<<type definitions>>=
 
405
typedef struct method method;
 
406
 
407
 
 
408
<<structure definitions>>=
 
409
struct method {
 
410
        char *name;
 
411
        command_set *up, *down;
 
412
};
 
413
 
414
 
 
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.
 
419
 
 
420
<<function type definitions>>=
 
421
typedef int (execfn)(char *command);
 
422
typedef int (command_set)(interface_defn *ifd, execfn *e);
 
423
 
424
 
 
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.
 
428
 
 
429
<<addrfam.c>>=
 
430
#include <stdlib.h>
 
431
#include "header.h"
 
432
 
 
433
<<address family declarations>>
 
434
 
 
435
address_family *addr_fams[] = {
 
436
        <<address family references>>
 
437
        NULL
 
438
};
 
439
 
440
 
 
441
\subsection{Generating C Code}
 
442
 
 
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
 
447
[[addrfam.c]].
 
448
 
 
449
Naturally, we'll use a [[perl]] script to convert [[.defn]] files to C
 
450
code.
 
451
 
 
452
<<implicit rules>>=
 
453
%.c : %.defn defn2c.pl
 
454
        ./defn2c.pl $< > $@
 
455
 
456
 
 
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
 
461
our C program.
 
462
 
 
463
<<defn2c.pl>>=
 
464
#!/usr/bin/perl -w
 
465
 
 
466
use strict;
 
467
 
 
468
# declarations
 
469
<<defn2c variables>>
 
470
 
 
471
# subroutines
 
472
<<defn2c subroutines>>
 
473
 
 
474
# main code
 
475
<<output headers for address family>>
 
476
<<parse [[.defn]] file and output intermediate structures>>
 
477
<<output address family data structure>>
 
478
 
479
 
 
480
Clearly we need to reference some of the data structures we defined
 
481
above, so we can begin with the rather trivial:
 
482
 
 
483
<<output headers for address family>>=
 
484
print "#include \"header.h\"\n\n\n";
 
485
 
486
 
 
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.
 
491
 
 
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.
 
496
 
 
497
<<defn2c variables>>=
 
498
my $address_family = "";
 
499
@
 
500
 
 
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]].
 
505
 
 
506
<<output address family data structure>>=
 
507
<<output [[methods]] data structure>>
 
508
 
 
509
print <<EOF;
 
510
address_family addr_${address_family} = {
 
511
        "$address_family",
 
512
        sizeof(methods)/sizeof(struct method),
 
513
        methods
 
514
};
 
515
EOF
 
516
 
517
 
 
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.
 
525
 
 
526
<<defn2c variables>>=
 
527
my %methods = ();
 
528
@
 
529
 
 
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.
 
534
 
 
535
<<output [[methods]] data structure>>=
 
536
print "static method methods[] = {\n";
 
537
my $method;
 
538
foreach $method (keys %methods) {
 
539
        print <<EOF;
 
540
        {
 
541
                "$method",
 
542
                ${method}_up, ${method}_down,
 
543
        },
 
544
EOF
 
545
}
 
546
print "};\n\n";
 
547
 
548
 
 
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.
 
553
 
 
554
<<defn2c variables>>=
 
555
my $line = "";
 
556
 
557
 
 
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)
 
564
 
 
565
<<defn2c subroutines>>=
 
566
<<[[nextline]] subroutine>>
 
567
 
568
 
 
569
<<[[nextline]] subroutine>>=
 
570
sub nextline {
 
571
        $line = <>;
 
572
        while($line and ($line =~ /^#/ or $line =~ /^\s*$/)) {
 
573
                $line = <>;
 
574
        }
 
575
        if (!$line) { return 0; }
 
576
        chomp $line;
 
577
        while ($line =~ m/^(.*)\\$/) {
 
578
                my $addon = <>;
 
579
                chomp $addon;
 
580
                $line = $1 . $addon;
 
581
        }
 
582
        return 1;
 
583
}
 
584
 
585
 
 
586
Our high-level logic then looks basically like:
 
587
 
 
588
<<parse [[.defn]] file and output intermediate structures>>=
 
589
nextline;
 
590
while($line) {
 
591
        <<parse a top-level section and output intermediate structures>>
 
592
 
 
593
        # ...otherwise
 
594
        die("Unknown command \"$line\"");
 
595
}
 
596
@
 
597
 
 
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)
 
602
 
 
603
<<defn2c variables>>=
 
604
my $match = "";
 
605
 
606
 
 
607
<<defn2c subroutines>>=
 
608
<<[[match]] subroutine>>
 
609
 
610
 
 
611
<<[[match]] subroutine>>=
 
612
sub match {
 
613
        my $line = $_[0];
 
614
        my $cmd = "$_[1]" ? "$_[1]\\b\\s*" : "";;
 
615
        my $indentexp = (@_ == 3) ? "$_[2]\\s+" : "";
 
616
 
 
617
        if ($line =~ /^${indentexp}${cmd}(([^\s](.*[^\s])?)?)\s*$/) {
 
618
                $match = $1;
 
619
                return 1;
 
620
        } else {
 
621
                return 0;
 
622
        } 
 
623
}
 
624
 
625
 
 
626
Okay. So, the first line we expect to see is the name of the address
 
627
family we're defining.
 
628
 
 
629
<<parse a top-level section and output intermediate structures>>=
 
630
if (match($line, "address_family")) {
 
631
        get_address_family $match;
 
632
        next;
 
633
}
 
634
 
635
 
 
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.
 
638
 
 
639
<<defn2c subroutines>>=
 
640
sub get_address_family {
 
641
        $address_family = $_[0] if ($address_family eq "");
 
642
        nextline;
 
643
}
 
644
 
645
 
 
646
Which brings us to determining the architecture.
 
647
 
 
648
<<parse a top-level section and output intermediate structures>>=
 
649
if (match($line, "architecture")) {
 
650
        get_architecture $match;
 
651
        next;
 
652
}
 
653
 
654
 
 
655
You'd never guess what, but it's just as easy as the address family thing
 
656
was.
 
657
 
 
658
<<defn2c subroutines>>=
 
659
sub get_architecture {
 
660
        my $arch = $_[0];
 
661
        die("architecture declaration appears too late") if (keys %methods);
 
662
        print "#include \"arch${arch}.h\"\n\n\n";
 
663
        nextline;
 
664
}
 
665
 
666
 
 
667
Which leaves us with the hard bit, actually creating the functions and
 
668
array for each method.
 
669
 
 
670
<<parse a top-level section and output intermediate structures>>=
 
671
if (match($line, "method")) {
 
672
        get_method $match;
 
673
        next;
 
674
}
 
675
@
 
676
 
 
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
 
682
same method twice.
 
683
 
 
684
<<defn2c subroutines>>=
 
685
sub get_method {
 
686
        my $method = $_[0];
 
687
        my $indent = ($line =~ /(\s*)[^\s]/) ? $1 : "";
 
688
 
 
689
        die "Duplicate method $method\n" if ($methods{$method}++);
 
690
 
 
691
        nextline;
 
692
        <<output code for description>>
 
693
        <<output code for options list>>
 
694
        <<output code for up commands>>
 
695
        <<output code for down commands>>
 
696
}
 
697
 
698
 
 
699
The description and options sections are just documentation chunks,
 
700
and hence aren't at all relevant for the C code.
 
701
 
 
702
<<output code for description>>=
 
703
if (match($line, "description", $indent)) {
 
704
        skip_section();
 
705
}
 
706
 
707
 
 
708
<<output code for options list>>=
 
709
if (match($line, "options", $indent)) {
 
710
        skip_section();
 
711
}
 
712
 
713
 
 
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.
 
716
 
 
717
<<defn2c subroutines>>=
 
718
<<[[skip_section]] subroutine>>
 
719
 
720
 
 
721
<<[[skip_section]] subroutine>>=
 
722
sub skip_section {
 
723
        my $struct = $_[0];
 
724
        my $indent = ($line =~ /(\s*)[^\s]/) ? $1 : "";
 
725
 
 
726
        1 while (nextline && match($line, "", $indent));
 
727
}
 
728
 
729
 
 
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.
 
733
 
 
734
<<output code for up commands>>=
 
735
if (match($line, "up", $indent)) {
 
736
        get_commands(${method}, "up");
 
737
} else {
 
738
        print "static int ${method}_up(interface_defn ifd) { return 0; }\n"
 
739
}
 
740
 
741
 
 
742
<<output code for down commands>>=
 
743
if (match($line, "down", $indent)) {
 
744
        get_commands(${method}, "down");
 
745
} else {
 
746
        print "static int ${method}_down(interface_defn ifd) { return 0; }\n"
 
747
}
 
748
@
 
749
 
 
750
<<defn2c subroutines>>=
 
751
sub get_commands {
 
752
        my $method = $_[0];
 
753
        my $mode = $_[1];
 
754
        my $function = "${method}_${mode}";
 
755
        my $indent = ($line =~ /(\s*)[^\s]/) ? $1 : "";
 
756
 
 
757
        print "static int ${function}(interface_defn *ifd, execfn *exec) {\n";
 
758
 
 
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";
 
763
                        print "}\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";
 
767
                        print "}\n";
 
768
                } elsif ( $match =~ /^(.*[^\s])\s*$/ ) {
 
769
                        print "{\n";
 
770
                        print "  if (!execute(\"$1\", ifd, exec)) return 0;\n";
 
771
                        print "}\n";
 
772
                }
 
773
        }
 
774
 
 
775
        print "return 1;\n";
 
776
        print "}\n";
 
777
}
 
778
 
779
 
 
780
\subsection{Building Manual Pages}
 
781
 
 
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.
 
786
 
 
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.
 
790
 
 
791
<<implicit rules>>=
 
792
%.man: %.defn defn2man.pl
 
793
        ./defn2man.pl $< > $@
 
794
 
795
 
 
796
So we'll use a similar structure to [[defn2c.pl]].
 
797
 
 
798
<<defn2man.pl>>=
 
799
#!/usr/bin/perl -w
 
800
 
 
801
use strict;
 
802
 
 
803
# declarations
 
804
<<defn2man variables>>
 
805
 
 
806
# subroutines
 
807
<<defn2man subroutines>>
 
808
 
 
809
# main code
 
810
<<parse [[.defn]] file and output manpage fragment>>
 
811
 
812
 
 
813
As predicted, we'll also incorporate [[nextline]], [[match]] and
 
814
[[skip_section]]:
 
815
 
 
816
<<defn2man variables>>=
 
817
my $line;
 
818
my $match;
 
819
 
820
 
 
821
<<defn2man subroutines>>=
 
822
<<[[nextline]] subroutine>>
 
823
<<[[match]] subroutine>>
 
824
<<[[skip_section]] subroutine>>
 
825
 
826
 
 
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.
 
831
 
 
832
<<parse [[.defn]] file and output manpage fragment>>=
 
833
nextline;
 
834
if ($line and match($line, "address_family")) {
 
835
        get_address_family $match;
 
836
} else {
 
837
        die "address_family must be listed first\n";
 
838
}
 
839
if ($line and match($line, "architecture")) {
 
840
        get_architecture $match;
 
841
}
 
842
while ($line and match($line, "method")) {
 
843
        get_method $match;
 
844
}
 
845
 
846
 
 
847
Okay, so it wasn't \emph{that} different from what we had before. Sue
 
848
me.
 
849
 
 
850
The [[get_address_family]] and [[get_architecture]] subroutines are
 
851
fairly straight forward:
 
852
 
 
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";
 
858
        nextline;
 
859
}
 
860
 
861
 
 
862
<<defn2man subroutines>>=
 
863
sub get_architecture {
 
864
        # no op
 
865
        nextline;
 
866
}
 
867
 
868
 
 
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.
 
872
 
 
873
<<defn2man subroutines>>=
 
874
sub get_method {
 
875
        my $method = shift;
 
876
        my $indent = ($line =~ /(\s*)\S/) ? $1 : "";
 
877
        my $description = "";
 
878
        my @options = ();
 
879
 
 
880
        nextline;
 
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();
 
886
                } else {
 
887
                        skip_section;
 
888
                }
 
889
        }
 
890
 
 
891
        <<output [[$method]] introduction man fragment>>
 
892
        <<output [[$description]] man fragment>>
 
893
        <<output [[@options]] man fragment>>
 
894
}
 
895
@
 
896
 
 
897
<<output [[$method]] introduction man fragment>>=
 
898
print ".SS The $method Method\n";
 
899
 
900
 
 
901
Okay. Now our [[$description]] is just the description with any [['\n']]
 
902
characters it may've had, but without the leading spaces.
 
903
 
 
904
<<defn2man subroutines>>=
 
905
sub get_description {
 
906
        my $desc = "";
 
907
        my $indent = ($line =~ /(\s*)\S/) ? $1 : "";
 
908
        while(nextline && match($line, "", $indent)) {
 
909
                $desc .= "$match\n";
 
910
        }
 
911
        return $desc;
 
912
}
 
913
 
914
 
 
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:
 
921
 
 
922
<<defn2man subroutines>>=
 
923
sub usenet2man {
 
924
        my $in = shift;
 
925
        my $out = "";
 
926
 
 
927
        $in =~ s/\s+/ /g;
 
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/^ /) {
 
931
                        $out .= "$pre\n";
 
932
                        $out .= ($l eq "*" ? ".B" : ".I") . " \"$mid\"\n";
 
933
                        ($in = $post) =~ s/^ *//;
 
934
                } else {
 
935
                        $out .= $pre . $l;
 
936
                        $in = $mid . $r . $post;
 
937
                }
 
938
        } 
 
939
        return $out . $in;
 
940
}
 
941
@
 
942
 
 
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:
 
946
 
 
947
<<output [[$description]] man fragment>>=
 
948
if ($description ne "") {
 
949
        print usenet2man($description) . "\n";
 
950
} else {
 
951
        print "(No description)\n";
 
952
}
 
953
 
954
 
 
955
Damn that was fun.
 
956
 
 
957
Reading the options is almost exactly the same as the description,
 
958
except we want a list instead of just a string.
 
959
 
 
960
<<defn2man subroutines>>=
 
961
sub get_options {
 
962
        my @opts = ();
 
963
        my $indent = ($line =~ /(\s*)\S/) ? $1 : "";
 
964
        while(nextline && match($line, "", $indent)) {
 
965
                push @opts, $match;
 
966
        }
 
967
        return @opts;
 
968
}
 
969
 
970
 
 
971
Output is slightly more complicated, but not too much so.
 
972
 
 
973
<<output [[@options]] man fragment>>=
 
974
print ".PP\n";
 
975
print ".B Options\n";
 
976
print ".RS\n";
 
977
if (@options) {
 
978
        foreach my $o (@options) {
 
979
                if ($o =~ m/^\s*(\S*)\s*(.*)\s+--\s+(\S.*)$/) {
 
980
                        my $opt = $1;
 
981
                        my $optargs = $2;
 
982
                        my $dsc = $3;
 
983
                        print ".TP\n";
 
984
                        print ".BI $opt";
 
985
                        print " \" $optargs\"" unless($optargs =~ m/^\s*$/);
 
986
                        print "\n";
 
987
                        print usenet2man($dsc) . "\n";
 
988
                } else {
 
989
                        print ".TP\n";
 
990
                        print ".B $o\n";
 
991
                }
 
992
        }
 
993
} else {
 
994
        print ".TP\n";
 
995
        print "(No options)\n";
 
996
}
 
997
print ".RE\n";
 
998
 
999
 
 
1000
\section{Run-time Configuration}
 
1001
 
 
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.
 
1004
 
 
1005
<<config.c>>=
 
1006
<<config headers>>
 
1007
<<config function declarations>>
 
1008
<<config functions>>
 
1009
 
1010
 
 
1011
<<config headers>>=
 
1012
#include <stdlib.h>
 
1013
#include <stdio.h>
 
1014
#include <string.h>
 
1015
#include <assert.h>
 
1016
 
1017
 
 
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.
 
1020
 
 
1021
<<config headers>>=
 
1022
#include "header.h"
 
1023
 
1024
 
 
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.
 
1029
 
 
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:
 
1033
 
 
1034
\begin{enumerate}
 
1035
        \item an array of interface names that should be brought up at
 
1036
        bootup.
 
1037
 
 
1038
        \item a singly linked list to represent the various mappings.
 
1039
 
 
1040
        \item another singly linked list to represent the interface
 
1041
        definitions themselves.
 
1042
\end{enumerate}
 
1043
 
 
1044
 These are almost in exact correspondence with the original file.
 
1045
 
 
1046
<<type definitions>>=
 
1047
typedef struct interfaces_file interfaces_file;
 
1048
 
1049
 
 
1050
<<structure definitions>>=
 
1051
struct interfaces_file {
 
1052
        int max_autointerfaces;
 
1053
        int n_autointerfaces;
 
1054
        char **autointerfaces;
 
1055
 
 
1056
        interface_defn *ifaces;
 
1057
        mapping_defn *mappings;
 
1058
};
 
1059
 
1060
 
 
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
 
1064
about an interface.
 
1065
 
 
1066
<<type definitions>>=
 
1067
typedef struct interface_defn interface_defn;
 
1068
 
1069
 
 
1070
<<structure definitions>>=
 
1071
struct interface_defn {
 
1072
        interface_defn *next;
 
1073
 
 
1074
        char *iface;
 
1075
        address_family *address_family;
 
1076
        method *method;
 
1077
 
 
1078
        int automatic;
 
1079
 
 
1080
        int max_options;
 
1081
        int n_options;
 
1082
        variable *option;
 
1083
};
 
1084
@
 
1085
 
 
1086
The last component in the above, the options, is represented by a
 
1087
series of name/value pairs, as follows:
 
1088
 
 
1089
<<type definitions>>=
 
1090
typedef struct variable variable;
 
1091
 
1092
 
 
1093
<<structure definitions>>=
 
1094
struct variable {
 
1095
        char *name;
 
1096
        char *value;
 
1097
};
 
1098
 
1099
 
 
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.
 
1104
 
 
1105
<<type definitions>>=
 
1106
typedef struct mapping_defn mapping_defn;
 
1107
 
1108
 
 
1109
<<structure definitions>>=
 
1110
struct mapping_defn {
 
1111
        mapping_defn *next;
 
1112
 
 
1113
        int max_matches;
 
1114
        int n_matches;
 
1115
        char **match;
 
1116
 
 
1117
        char *script;
 
1118
 
 
1119
        int max_mappings;
 
1120
        int n_mappings;
 
1121
        char **mapping;
 
1122
};
 
1123
 
1124
 
 
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?
 
1129
 
 
1130
<<exported symbols>>=
 
1131
interfaces_file *read_interfaces(char *filename);
 
1132
 
1133
 
 
1134
<<config functions>>=
 
1135
interfaces_file *read_interfaces(char *filename) {
 
1136
        <<variables local to read interfaces>>
 
1137
        interfaces_file *defn;
 
1138
 
 
1139
        <<allocate defn or [[return NULL]]>>
 
1140
        <<open file or [[return NULL]]>>
 
1141
 
 
1142
        while (<<we've gotten a line from the file>>) {
 
1143
                <<process the line>>
 
1144
        }
 
1145
        if (<<an error occurred getting the line>>) {
 
1146
                <<report internal error and die>>
 
1147
        }
 
1148
 
 
1149
        <<close file>>
 
1150
 
 
1151
        return defn;
 
1152
}
 
1153
 
1154
 
 
1155
<<allocate defn or [[return NULL]]>>=
 
1156
defn = malloc(sizeof(interfaces_file));
 
1157
if (defn == NULL) {
 
1158
        return NULL;
 
1159
}
 
1160
defn->max_autointerfaces = defn->n_autointerfaces = 0;
 
1161
defn->autointerfaces = NULL;
 
1162
defn->mappings = NULL;
 
1163
defn->ifaces = NULL;
 
1164
 
1165
 
 
1166
\subsection{File Handling}
 
1167
 
 
1168
So, the first and most obvious thing to deal with is the file
 
1169
handling. Nothing particularly imaginative here.
 
1170
 
 
1171
<<variables local to read interfaces>>=
 
1172
FILE *f;
 
1173
int line;
 
1174
 
1175
 
 
1176
<<open file or [[return NULL]]>>=
 
1177
f = fopen(filename, "r");
 
1178
if ( f == NULL ) return NULL;
 
1179
line = 0;
 
1180
@
 
1181
 
 
1182
<<close file>>=
 
1183
fclose(f);
 
1184
line = -1;
 
1185
@
 
1186
 
 
1187
\subsection{Line Parsing}
 
1188
 
 
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.
 
1192
 
 
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:
 
1200
 
 
1201
<<config function declarations>>=
 
1202
static int get_line(char **result, size_t *result_len, FILE *f, int *line);
 
1203
 
1204
 
 
1205
To use it, we'll need a couple of variables to stores the buffer's
 
1206
location, and it's current length.
 
1207
 
 
1208
<<variables local to read interfaces>>=
 
1209
char *buf = NULL;
 
1210
size_t buf_len = 0;
 
1211
 
1212
 
 
1213
Given these, and presuming we can actually implement the function, our
 
1214
key chunk can thus be implemented simply as:
 
1215
 
 
1216
<<we've gotten a line from the file>>=
 
1217
get_line(&buf,&buf_len,f,&line)
 
1218
 
1219
 
 
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.
 
1223
 
 
1224
<<config headers>>=
 
1225
#include <errno.h>
 
1226
 
1227
 
 
1228
<<an error occurred getting the line>>=
 
1229
ferror(f) != 0
 
1230
 
1231
 
 
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
 
1239
got a line or not.
 
1240
 
 
1241
<<config functions>>=
 
1242
static int get_line(char **result, size_t *result_len, FILE *f, int *line) {
 
1243
        <<variables local to get line>>
 
1244
 
 
1245
        do {
 
1246
                <<clear buffer>>
 
1247
                <<append next line to buffer, or [[return 0]]>>
 
1248
                <<trim leading whitespace>>
 
1249
        } while (<<line is a comment>>);
 
1250
 
 
1251
        while (<<buffer is continued>>) {
 
1252
                <<remove continuation mark>>
 
1253
                <<append next line to buffer, or [[return 0]]>>
 
1254
        }
 
1255
 
 
1256
        <<trim trailing whitespace>>
 
1257
 
 
1258
        return 1;
 
1259
}
 
1260
 
1261
 
 
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.
 
1265
 
 
1266
<<variables local to get line>>=
 
1267
size_t pos;
 
1268
 
1269
 
 
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?
 
1272
 
 
1273
<<clear buffer>>=
 
1274
pos = 0;
 
1275
 
1276
 
 
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
 
1282
like:
 
1283
 
 
1284
<<append next line to buffer, or [[return 0]]>>=
 
1285
do {
 
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>>);
 
1289
 
 
1290
<<remove trailing newline>>
 
1291
 
 
1292
(*line)++;
 
1293
 
 
1294
assert( (*result)[pos] == '\0' );
 
1295
 
1296
 
 
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.
 
1304
 
 
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) {
 
1309
                return 0;
 
1310
        }
 
1311
        *result = newstr;
 
1312
        *result_len = *result_len * 2 + 80;
 
1313
}
 
1314
 
1315
 
 
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?
 
1324
 
 
1325
<<the line isn't complete>>=
 
1326
pos == *result_len - 1 && (*result)[pos-1] != '\n'
 
1327
 
1328
 
 
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.
 
1333
 
 
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;
 
1338
}
 
1339
pos += strlen(*result + pos);
 
1340
 
1341
 
 
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
 
1344
it.
 
1345
 
 
1346
<<remove trailing newline>>=
 
1347
if (pos != 0 && (*result)[pos-1] == '\n') {
 
1348
        (*result)[--pos] = '\0';
 
1349
}
 
1350
 
1351
 
 
1352
 
 
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,
 
1356
getting rid of it.
 
1357
 
 
1358
<<config headers>>=
 
1359
#include <ctype.h>
 
1360
 
1361
 
 
1362
<<trim leading whitespace>>=
 
1363
 
1364
        int first = 0; 
 
1365
        while (isspace((*result)[first]) && (*result)[first]) {
 
1366
                first++;
 
1367
        }
 
1368
 
 
1369
        memmove(*result, *result + first, pos - first + 1);
 
1370
        pos -= first;
 
1371
}
 
1372
 
1373
 
 
1374
<<trim trailing whitespace>>=
 
1375
while (isspace((*result)[pos-1])) { /* remove trailing whitespace */
 
1376
        pos--;
 
1377
}
 
1378
(*result)[pos] = '\0';
 
1379
 
1380
 
 
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]].
 
1385
 
 
1386
<<line is a comment>>=
 
1387
(*result)[0] == '#'
 
1388
 
1389
 
 
1390
<<buffer is continued>>=
 
1391
(*result)[pos-1] == '\\'
 
1392
 
1393
 
 
1394
<<remove continuation mark>>=
 
1395
(*result)[--pos] = '\0';
 
1396
 
1397
 
 
1398
\subsection{Line Processing}
 
1399
 
 
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}.
 
1403
 
 
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
 
1406
defining.
 
1407
 
 
1408
<<variables local to read interfaces>>=
 
1409
interface_defn *currif = NULL;
 
1410
mapping_defn *currmap = NULL;
 
1411
enum { NONE, IFACE, MAPPING } currently_processing = NONE;
 
1412
 
1413
 
 
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.
 
1418
 
 
1419
<<variables local to read interfaces>>=
 
1420
char firstword[80];
 
1421
char *rest;
 
1422
 
1423
 
 
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.
 
1427
 
 
1428
<<config function declarations>>=
 
1429
static char *next_word(char *buf, char *word, int maxlen);
 
1430
@
 
1431
 
 
1432
<<config functions>>=
 
1433
static char *next_word(char *buf, char *word, int maxlen) {
 
1434
        if (!buf) return NULL;
 
1435
        if (!*buf) return NULL;
 
1436
 
 
1437
        while(!isspace(*buf) && *buf) {
 
1438
                if (maxlen-- > 1) *word++ = *buf;
 
1439
                buf++;
 
1440
        }
 
1441
        if (maxlen > 0) *word = '\0';
 
1442
 
 
1443
        while(isspace(*buf) && *buf) buf++;
 
1444
 
 
1445
        return buf;
 
1446
}
 
1447
 
1448
 
 
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.
 
1452
 
 
1453
<<process the line>>=
 
1454
rest = next_word(buf, firstword, 80);
 
1455
if (rest == NULL) continue; /* blank line */
 
1456
 
 
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;
 
1466
} else {
 
1467
        <<process option line>>
 
1468
}
 
1469
 
1470
 
 
1471
<<process option line>>=
 
1472
switch(currently_processing) {
 
1473
        case IFACE:
 
1474
                <<process iface option line>>
 
1475
                break;
 
1476
        case MAPPING:
 
1477
                <<process mapping option line>>
 
1478
                break;
 
1479
        case NONE:
 
1480
        default:
 
1481
                <<report bad option and die>>
 
1482
}
 
1483
 
1484
 
 
1485
\subsubsection{Mapping Line}
 
1486
 
 
1487
Declaring a new mapping is reasonably copewithable --- we need to process
 
1488
a few things, but they're reasonably easy to handle.
 
1489
 
 
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.
 
1494
 
 
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>>
 
1500
 
1501
 
 
1502
<<allocate new mapping>>=
 
1503
currmap = malloc(sizeof(mapping_defn));
 
1504
if (currmap == NULL) {
 
1505
        <<report internal error and die>>
 
1506
}
 
1507
 
1508
 
 
1509
<<parse mapping interfaces>>=
 
1510
currmap->max_matches = 0;
 
1511
currmap->n_matches = 0;
 
1512
currmap->match = NULL;
 
1513
 
 
1514
while((rest = next_word(rest, firstword, 80))) {
 
1515
        if (currmap->max_matches == currmap->n_matches) {
 
1516
                char **tmp;
 
1517
                currmap->max_matches = currmap->max_matches * 2 + 1;
 
1518
                tmp = realloc(currmap->match, 
 
1519
                        sizeof(*tmp) * currmap->max_matches);
 
1520
                if (tmp == NULL) {
 
1521
                        currmap->max_matches = (currmap->max_matches - 1) / 2;
 
1522
                        <<report internal error and die>>
 
1523
                }
 
1524
                currmap->match = tmp;
 
1525
        }
 
1526
 
 
1527
        currmap->match[currmap->n_matches++] = strdup(firstword);
 
1528
}
 
1529
 
1530
 
 
1531
<<set other mapping options to defaults>>=
 
1532
currmap->script = NULL;
 
1533
 
 
1534
currmap->max_mappings = 0;
 
1535
currmap->n_mappings = 0;
 
1536
currmap->mapping = NULL;
 
1537
 
1538
 
 
1539
<<add to list of mappings>>=
 
1540
{
 
1541
        mapping_defn **where = &defn->mappings;
 
1542
        while(*where != NULL) {
 
1543
                where = &(*where)->next;
 
1544
        }
 
1545
        *where = currmap;
 
1546
        currmap->next = NULL;
 
1547
}
 
1548
 
1549
 
 
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:
 
1553
 
 
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>>
 
1559
} else {
 
1560
        <<report bad option and die>>
 
1561
}
 
1562
 
1563
 
 
1564
<<handle [[script]] line>>=
 
1565
if (currmap->script != NULL) {
 
1566
        <<report duplicate script in mapping and die>>
 
1567
} else {
 
1568
        currmap->script = strdup(rest);
 
1569
}
 
1570
 
1571
 
 
1572
<<handle [[map]] line>>=
 
1573
if (currmap->max_mappings == currmap->n_mappings) {
 
1574
        char **opt;
 
1575
        currmap->max_mappings = currmap->max_mappings * 2 + 1;
 
1576
        opt = realloc(currmap->mapping, sizeof(*opt) * currmap->max_mappings);
 
1577
        if (opt == NULL) {
 
1578
                <<report internal error and die>>
 
1579
        }
 
1580
        currmap->mapping = opt;
 
1581
}
 
1582
currmap->mapping[currmap->n_mappings] = strdup(rest);
 
1583
currmap->n_mappings++;
 
1584
 
1585
 
 
1586
\subsubsection{Interface line}
 
1587
 
 
1588
Declaring a new interface follows the same pattern, but is somewhat more
 
1589
interesting and some more complicated data structures are involved.
 
1590
 
 
1591
<<process [[iface]] line>>=
 
1592
{
 
1593
        <<variables local to process [[iface]] line>>
 
1594
 
 
1595
        <<allocate new interface>>
 
1596
 
 
1597
        <<parse interface settings>>
 
1598
 
 
1599
        <<set iface name>>
 
1600
        <<set address family>>
 
1601
        <<set method>>
 
1602
        <<set other interface options to defaults>>
 
1603
 
 
1604
        <<add to list of interfaces>>
 
1605
}
 
1606
 
1607
 
 
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
 
1610
allocation!
 
1611
 
 
1612
<<allocate new interface>>=
 
1613
currif = malloc(sizeof(interface_defn));
 
1614
if (!currif) {
 
1615
        <<report internal error and die>>
 
1616
}
 
1617
 
1618
 
 
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
 
1622
them.
 
1623
 
 
1624
<<variables local to process [[iface]] line>>=
 
1625
char iface_name[80];
 
1626
char address_family_name[80];
 
1627
char method_name[80];
 
1628
 
1629
 
 
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);
 
1634
 
 
1635
if (rest == NULL) {
 
1636
        <<report too few parameters for iface line and die>>
 
1637
}
 
1638
 
 
1639
if (rest[0] != '\0') {
 
1640
        <<report too many parameters for iface line and die>>
 
1641
}
 
1642
 
1643
 
 
1644
We then want to store the interface name.
 
1645
 
 
1646
<<set iface name>>=
 
1647
currif->iface = strdup(iface_name);
 
1648
if (!currif->iface) {
 
1649
        <<report internal error and die>>
 
1650
}
 
1651
 
1652
 
 
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.
 
1659
 
 
1660
<<config function declarations>>=
 
1661
static address_family *get_address_family(address_family *af[], char *name);
 
1662
 
1663
 
 
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>>
 
1668
}
 
1669
 
1670
 
 
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}
 
1675
 
 
1676
<<config functions>>=
 
1677
static address_family *get_address_family(address_family *af[], char *name) {
 
1678
        int i;
 
1679
        for (i = 0; af[i]; i++) {
 
1680
                if (strcmp(af[i]->name, name) == 0) {
 
1681
                        return af[i];
 
1682
                }
 
1683
        }
 
1684
        return NULL;
 
1685
}
 
1686
@
 
1687
 
 
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}
 
1694
 
 
1695
<<config function declarations>>=
 
1696
static method *get_method(address_family *af, char *name);
 
1697
 
1698
 
 
1699
<<set method>>=
 
1700
currif->method = get_method(currif->address_family, method_name);
 
1701
if (!currif->method) {
 
1702
        <<report unknown method and die>>
 
1703
        return NULL; /* FIXME */
 
1704
}
 
1705
@
 
1706
 
 
1707
<<config functions>>=
 
1708
static method *get_method(address_family *af, char *name) {
 
1709
        int i;
 
1710
        for (i = 0; i < af->n_methods; i++) {
 
1711
                if (strcmp(af->method[i].name, name) == 0) {
 
1712
                        return &af->method[i];
 
1713
                }
 
1714
        }
 
1715
        return NULL;
 
1716
}
 
1717
@
 
1718
 
 
1719
You'll continue to be enthralled as we set the remaining options to
 
1720
some default values.
 
1721
 
 
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;
 
1727
 
1728
 
 
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.
 
1732
 
 
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
 
1736
pumping?
 
1737
 
 
1738
<<add to list of interfaces>>=
 
1739
{
 
1740
        interface_defn **where = &defn->ifaces; 
 
1741
        while(*where != NULL) {
 
1742
                if (duplicate_if(*where, currif)) {
 
1743
                        <<report duplicate interface and die>>
 
1744
                }
 
1745
                where = &(*where)->next;
 
1746
        }
 
1747
 
 
1748
        *where = currif;
 
1749
        currif->next = NULL;
 
1750
}
 
1751
 
1752
 
 
1753
Duplicate interfaces are interfaces that have the same name and the
 
1754
same address family. Nothing more complicated than that.
 
1755
 
 
1756
<<config function declarations>>=
 
1757
static int duplicate_if(interface_defn *ifa, interface_defn *ifb);
 
1758
 
1759
 
 
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;
 
1764
        return 1;
 
1765
}
 
1766
 
1767
 
 
1768
Dealing with the per-interface options is the next thing to deal
 
1769
with. 
 
1770
 
 
1771
<<process iface option line>>=
 
1772
<<check for duplicate options>>
 
1773
<<add option>>
 
1774
 
1775
 
 
1776
<<check for duplicate options>>=
 
1777
{
 
1778
        int i;
 
1779
        if (strcmp(firstword, "up") != 0
 
1780
            && strcmp(firstword, "down") != 0
 
1781
            && strcmp(firstword, "pre-up") != 0
 
1782
            && strcmp(firstword, "post-down") != 0)
 
1783
        {
 
1784
                for (i = 0; i < currif->n_options; i++) {
 
1785
                        if (strcmp(currif->option[i].name, firstword) == 0) {
 
1786
                                <<report duplicate option and die>>
 
1787
                        }
 
1788
                }
 
1789
        }
 
1790
}
 
1791
 
1792
 
 
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.
 
1796
 
 
1797
<<add option>>=
 
1798
if (currif->n_options >= currif->max_options) {
 
1799
        <<increase max number of options>>
 
1800
}
 
1801
 
 
1802
currif->option[currif->n_options].name = strdup(firstword);
 
1803
currif->option[currif->n_options].value = strdup(rest);
 
1804
 
 
1805
if (!currif->option[currif->n_options].name) {
 
1806
        <<report internal error and die>>
 
1807
}
 
1808
 
 
1809
if (!currif->option[currif->n_options].value) {
 
1810
        <<report internal error and die>>
 
1811
}
 
1812
 
 
1813
currif->n_options++;    
 
1814
@
 
1815
 
 
1816
We'll increase the space for variables by a constant amount each time,
 
1817
rather than doubling or anything smart like that.
 
1818
 
 
1819
<<increase max number of options>>=
 
1820
{
 
1821
        variable *opt;
 
1822
        currif->max_options = currif->max_options + 10;
 
1823
        opt = realloc(currif->option, sizeof(*opt) * currif->max_options);
 
1824
        if (opt == NULL) {
 
1825
                <<report internal error and die>>
 
1826
        }
 
1827
        currif->option = opt;
 
1828
}
 
1829
 
1830
 
 
1831
\subsubsection{Auto Line}
 
1832
 
 
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.
 
1835
 
 
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>>
 
1840
}
 
1841
 
1842
 
 
1843
<<check [[firstword]] isn't already an auto interface or die>>=
 
1844
{
 
1845
        int i;
 
1846
 
 
1847
        for (i = 0; i < defn->n_autointerfaces; i++) {
 
1848
                if (strcmp(firstword, defn->autointerfaces[i]) == 0) {
 
1849
                        <<report duplicate auto interface and die>>
 
1850
                }
 
1851
        }
 
1852
}
 
1853
@
 
1854
 
 
1855
<<add [[firstword]] as an auto interface or die>>=
 
1856
if (defn->n_autointerfaces == defn->max_autointerfaces) {
 
1857
        char **tmp;
 
1858
        defn->max_autointerfaces *= 2;
 
1859
        defn->max_autointerfaces++;
 
1860
        tmp = realloc(defn->autointerfaces, 
 
1861
                sizeof(*tmp) * defn->max_autointerfaces);
 
1862
        if (tmp == NULL) {
 
1863
                <<report internal error and die>>
 
1864
        }
 
1865
        defn->autointerfaces = tmp;
 
1866
}
 
1867
 
 
1868
defn->autointerfaces[defn->n_autointerfaces] = strdup(firstword);
 
1869
defn->n_autointerfaces++;
 
1870
@
 
1871
 
 
1872
\subsection{Error Handling}
 
1873
 
 
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}
 
1878
 
 
1879
<<report internal error and die>>=
 
1880
perror(filename);
 
1881
return NULL;
 
1882
 
1883
 
 
1884
<<report too few parameters for iface line and die>>=
 
1885
fprintf(stderr, "%s:%d: too few parameters for iface line\n", filename, line);
 
1886
return NULL;
 
1887
@
 
1888
 
 
1889
<<report too many parameters for iface line and die>>=
 
1890
fprintf(stderr, "%s:%d: too many parameters for iface line\n", filename, line);
 
1891
return NULL;
 
1892
@
 
1893
 
 
1894
<<report unknown address family and die>>=
 
1895
fprintf(stderr, "%s:%d: unknown address type\n", filename, line);
 
1896
return NULL;
 
1897
@
 
1898
 
 
1899
<<report unknown method and die>>=
 
1900
fprintf(stderr, "%s:%d: unknown method\n", filename, line);
 
1901
return NULL;
 
1902
@
 
1903
 
 
1904
<<report duplicate interface and die>>=
 
1905
fprintf(stderr, "%s:%d: duplicate interface\n", filename, line);
 
1906
return NULL;
 
1907
@
 
1908
 
 
1909
<<report duplicate auto interface and die>>=
 
1910
fprintf(stderr, "%s:%d: interface declared auto twice\n", filename, line);
 
1911
return NULL;
 
1912
@
 
1913
 
 
1914
<<report duplicate option and die>>=
 
1915
fprintf(stderr, "%s:%d: duplicate option\n", filename, line);
 
1916
return NULL;
 
1917
@
 
1918
 
 
1919
<<report duplicate script in mapping and die>>=
 
1920
fprintf(stderr, "%s:%d: duplicate script in mapping\n", filename, line);
 
1921
return NULL;
 
1922
 
1923
 
 
1924
<<report bad option and die>>=
 
1925
fprintf(stderr, "%s:%d: misplaced option\n", filename, line);
 
1926
return NULL;
 
1927
@
 
1928
 
 
1929
\section{Execution}
 
1930
 
 
1931
The [[execute]] module will be laid out in the standard manner, and
 
1932
will make use of the usual header files.
 
1933
 
 
1934
<<execute.c>>=
 
1935
<<execute headers>>
 
1936
<<execute global variables>>
 
1937
<<execute function declarations>>
 
1938
<<execute functions>>
 
1939
 
1940
 
 
1941
<<execute headers>>=
 
1942
#include <stdio.h>
 
1943
#include <ctype.h>
 
1944
#include <stdlib.h>
 
1945
#include <string.h>
 
1946
#include <assert.h>
 
1947
 
 
1948
#include "header.h"
 
1949
@
 
1950
 
 
1951
The key functions we export from here are all the functions that as a
 
1952
fairly direct result run some executable.
 
1953
 
 
1954
\begin{itemize}
 
1955
        \item [[iface_up()]] and [[iface_down()]] which will actually
 
1956
        configure or deconfigure an interface.
 
1957
 
 
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.
 
1962
 
 
1963
        \item [[run_mapping()]] which will run a mapping script and
 
1964
        determine if a new logical interface should be selected.
 
1965
\end{itemize}
 
1966
 
 
1967
We'll discuss each of these in order.
 
1968
 
 
1969
\subsection{Interface Configuration and Deconfiguration}
 
1970
 
 
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:
 
1974
 
 
1975
\begin{center}
 
1976
\includegraphics[height=60mm]{execution}
 
1977
\end{center}
 
1978
 
 
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
 
1982
scripts.
 
1983
 
 
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.
 
1993
 
 
1994
\subsubsection{Command checking}
 
1995
 
 
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.
 
1999
 
 
2000
[[check()]] is thus fairly trivial:
 
2001
 
 
2002
<<execute function declarations>>=
 
2003
static int check(char *str);
 
2004
@
 
2005
 
 
2006
<<execute functions>>=
 
2007
static int check(char *str) {
 
2008
        return str != NULL;
 
2009
}
 
2010
 
2011
 
 
2012
\subsubsection{Environment handling}
 
2013
 
 
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.
 
2020
 
 
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.
 
2024
 
 
2025
<<execute global variables>>=
 
2026
static char **environ = NULL;
 
2027
 
2028
 
 
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]].
 
2031
 
 
2032
<<execute function declarations>>=
 
2033
static void set_environ(interface_defn *iface, char *mode);
 
2034
@
 
2035
 
 
2036
Our function then will be:
 
2037
 
 
2038
<<execute functions>>=
 
2039
static void set_environ(interface_defn *iface, char *mode) {
 
2040
        <<variables local to set environ>>
 
2041
        int i;
 
2042
 
 
2043
        <<initialise environ>>
 
2044
 
 
2045
        for (i = 0; i < iface->n_options; i++) {
 
2046
                <<[[continue]] if option is a command>>
 
2047
 
 
2048
                <<add [[IF_]]option to environment>>
 
2049
        }
 
2050
        <<add [[IFACE]] to environment>>
 
2051
        <<add [[MODE]] to environment>>
 
2052
}
 
2053
@
 
2054
 
 
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:
 
2057
 
 
2058
<<variables local to set environ>>=
 
2059
char **environend;
 
2060
@
 
2061
 
 
2062
Initialising thus becomes:
 
2063
 
 
2064
<<initialise environ>>=
 
2065
<<clear environ if necessary>>
 
2066
 
 
2067
environ = malloc(sizeof(char*) * (iface->n_options + 3));
 
2068
environend = environ; 
 
2069
*environend = NULL;
 
2070
@
 
2071
 
 
2072
<<clear environ if necessary>>=
 
2073
{
 
2074
        char **ppch;
 
2075
        if (environ != NULL) {
 
2076
                for (ppch = environ; *ppch; ppch++) {
 
2077
                        free(*ppch);
 
2078
                        *ppch = NULL;
 
2079
                }
 
2080
                free(environ);
 
2081
                environ = NULL;
 
2082
        }
 
2083
}
 
2084
@
 
2085
 
 
2086
Our continue chunk is also fairly straight forward:
 
2087
 
 
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)
 
2093
{
 
2094
        continue;
 
2095
}
 
2096
@
 
2097
 
 
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.
 
2103
 
 
2104
<<execute function declarations>>=
 
2105
static char *setlocalenv(char *format, char *name, char *value);
 
2106
@
 
2107
 
 
2108
We can then go ahead and fill in the environment.
 
2109
 
 
2110
<<add [[IF_]]option to environment>>=
 
2111
*(environend++) = setlocalenv("IF_%s=%s", iface->option[i].name,
 
2112
                              iface->option[i].value);
 
2113
*environend = NULL;
 
2114
@
 
2115
 
 
2116
<<add [[IFACE]] to environment>>=
 
2117
*(environend++) = setlocalenv("%s=%s", "IFACE", iface->iface);
 
2118
*environend = NULL;
 
2119
@
 
2120
 
 
2121
<<add [[MODE]] to environment>>=
 
2122
*(environend++) = setlocalenv("%s=%s", "MODE", mode);
 
2123
*environend = NULL;
 
2124
@
 
2125
 
 
2126
Our helper function then will then be something like:
 
2127
 
 
2128
<<execute functions>>=
 
2129
static char *setlocalenv(char *format, char *name, char *value) {
 
2130
        char *result;
 
2131
 
 
2132
        <<allocate memory for [[result]]>>
 
2133
 
 
2134
        sprintf(result, format, name, value);
 
2135
 
 
2136
        <<tidy [[result]]>>
 
2137
 
 
2138
        return result;
 
2139
}
 
2140
@
 
2141
 
 
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]]).
 
2145
 
 
2146
<<allocate memory for [[result]]>>=
 
2147
result = malloc(strlen(format)   /* -4 for the two %s's */
 
2148
                + strlen(name) 
 
2149
                + strlen(value) 
 
2150
                + 1);
 
2151
if (!result) {
 
2152
        perror("malloc");
 
2153
        exit(1);
 
2154
}
 
2155
@
 
2156
 
 
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.
 
2161
 
 
2162
<<tidy [[result]]>>=
 
2163
{
 
2164
        char *here, *there;
 
2165
 
 
2166
        for(here = there = result; *there != '=' && *there; there++) {
 
2167
                if (*there == '-') *there = '_';
 
2168
                if (isalpha(*there)) *there = toupper(*there);
 
2169
 
 
2170
                if (isalnum(*there) || *there == '_') {
 
2171
                        *here = *there;
 
2172
                        here++;
 
2173
                }
 
2174
        }
 
2175
        memmove(here, there, strlen(there) + 1);
 
2176
}
 
2177
@
 
2178
 
 
2179
\subsubsection{Command Execution}
 
2180
 
 
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
 
2185
based on those.
 
2186
 
 
2187
<<execute function declarations>>=
 
2188
static int doit(char *str);
 
2189
@
 
2190
 
 
2191
<<execute functions>>=
 
2192
static int doit(char *str) {
 
2193
        assert(str);
 
2194
 
 
2195
        if (verbose || no_act) {
 
2196
                fprintf(stderr, "%s\n", str);
 
2197
        }
 
2198
        if (!no_act) {
 
2199
                pid_t child;
 
2200
                int status;
 
2201
 
 
2202
                switch(child = fork()) {
 
2203
                    case -1: /* failure */
 
2204
                        return 0;
 
2205
                    case 0: /* child */
 
2206
                        execle("/bin/sh", "/bin/sh", "-c", str, NULL, environ);
 
2207
                        exit(127);
 
2208
                    default: /* parent */
 
2209
                }
 
2210
                waitpid(child, &status, 0);
 
2211
                if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
 
2212
                        return 0;
 
2213
        }
 
2214
        return 1;
 
2215
}
 
2216
@
 
2217
 
 
2218
\subsubsection{Executing a list of commands}
 
2219
 
 
2220
In addition to the above, we also need a function to cope with running
 
2221
all the [[pre-up]] commands and so forth.
 
2222
 
 
2223
<<exported symbols>>=
 
2224
int execute_all(interface_defn *ifd, execfn *exec, char *opt);
 
2225
 
2226
 
 
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.
 
2231
 
 
2232
This function will generally have [[doit]] passed in as the [[exec]]
 
2233
parameter.
 
2234
 
 
2235
<<execute functions>>=
 
2236
int execute_all(interface_defn *ifd, execfn *exec, char *opt) {
 
2237
        int i;
 
2238
        char buf[100];
 
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)) {
 
2242
                                return 0;
 
2243
                        }
 
2244
                }
 
2245
        }
 
2246
 
 
2247
        sprintf(buf, "run-parts /etc/network/if-%s.d", opt);
 
2248
        (*exec)(buf); 
 
2249
 
 
2250
        return 1;
 
2251
}
 
2252
 
2253
 
 
2254
\subsubsection{[[iface_up()]] and [[iface_down()]]}
 
2255
 
 
2256
Our functions, then are:
 
2257
 
 
2258
<<exported symbols>>=
 
2259
int iface_up(interface_defn *iface);
 
2260
int iface_down(interface_defn *iface);
 
2261
 
2262
 
 
2263
<<execute functions>>=
 
2264
int iface_up(interface_defn *iface) {
 
2265
        if (!iface->method->up(iface,check)) return -1;
 
2266
 
 
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;
 
2271
 
 
2272
        return 1;
 
2273
}
 
2274
 
2275
 
 
2276
<<execute functions>>=
 
2277
int iface_down(interface_defn *iface) {
 
2278
        if (!iface->method->down(iface,check)) return -1;
 
2279
 
 
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;
 
2284
 
 
2285
        return 1;
 
2286
}
 
2287
 
2288
 
 
2289
\subsection{Command Parsing}
 
2290
 
 
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:
 
2294
 
 
2295
<<exported symbols>>=
 
2296
int execute(char *command, interface_defn *ifd, execfn *exec);
 
2297
 
2298
 
 
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.
 
2301
 
 
2302
<<execute functions>>=
 
2303
int execute(char *command, interface_defn *ifd, execfn *exec) { 
 
2304
        char *out;
 
2305
        int ret;
 
2306
 
 
2307
        out = parse(command, ifd);
 
2308
        if (!out) { return 0; }
 
2309
 
 
2310
        ret = (*exec)(out);
 
2311
 
 
2312
        free(out);
 
2313
        return ret;
 
2314
}
 
2315
 
2316
 
 
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:
 
2320
 
 
2321
\begin{itemize}
 
2322
 
 
2323
        \item Special characters can be escaped with a backslash. eg
 
2324
        [[ls MoreThan80\%]].
 
2325
 
 
2326
        \item Variables can be substituted by including their name
 
2327
        delimeted by percents. eg [[ls %directory%]].
 
2328
 
 
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
 
2333
        may be nested.
 
2334
 
 
2335
\end{itemize}
 
2336
 
 
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.
 
2343
 
 
2344
<<execute function declarations>>=
 
2345
static char *parse(char *command, interface_defn *ifd);
 
2346
 
2347
 
 
2348
<<execute functions>>=
 
2349
static char *parse(char *command, interface_defn *ifd) {
 
2350
        <<variables local to parse>>
 
2351
 
 
2352
        while(*command) {
 
2353
                switch(*command) {
 
2354
                        <<handle a token>>
 
2355
                }
 
2356
        }
 
2357
 
 
2358
        <<deal with error conditions>>
 
2359
 
 
2360
        <<return result>>
 
2361
}
 
2362
@
 
2363
 
 
2364
\subsubsection{Maintain output buffer}
 
2365
 
 
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]].
 
2372
 
 
2373
<<variables local to parse>>=
 
2374
char *result = NULL;
 
2375
size_t pos = 0, len = 0;
 
2376
 
2377
 
 
2378
This makes it pretty easy to return the result to the caller, too.
 
2379
 
 
2380
<<return result>>=
 
2381
return result;
 
2382
@
 
2383
 
 
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.
 
2390
 
 
2391
<<execute function declarations>>=
 
2392
void addstr(char **buf, size_t *len, size_t *pos, char *str, size_t strlen);
 
2393
 
2394
 
 
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');
 
2399
 
 
2400
        if (*pos + strlen >= *len) {
 
2401
                char *newbuf;
 
2402
                newbuf = realloc(*buf, *len * 2 + strlen + 1);
 
2403
                if (!newbuf) {
 
2404
                        perror("realloc");
 
2405
                        exit(1); /* a little ugly */
 
2406
                }
 
2407
                *buf = newbuf;
 
2408
                *len = *len * 2 + strlen + 1;
 
2409
        }
 
2410
 
 
2411
        while (strlen-- >= 1) {
 
2412
                (*buf)[(*pos)++] = *str;
 
2413
                str++;
 
2414
        }
 
2415
        (*buf)[*pos] = '\0';
 
2416
}
 
2417
 
2418
 
 
2419
Given this, we can define our default behaviour for a character:
 
2420
 
 
2421
<<handle a token>>=
 
2422
default:
 
2423
        addstr(&result, &len, &pos, command, 1);
 
2424
        command++;
 
2425
        break;
 
2426
 
2427
 
 
2428
\subsubsection{Escaped characters}
 
2429
 
 
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.
 
2433
 
 
2434
<<handle a token>>=
 
2435
case '\\':
 
2436
        if (command[1]) {
 
2437
                addstr(&result, &len, &pos, command+1, 1);
 
2438
                command += 2;
 
2439
        } else {
 
2440
                addstr(&result, &len, &pos, command, 1);
 
2441
                command++;
 
2442
        }
 
2443
        break;
 
2444
 
2445
 
 
2446
\subsubsection{Optional components}
 
2447
 
 
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
 
2454
sections.
 
2455
 
 
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.
 
2462
 
 
2463
<<constant definitions>>=
 
2464
#define MAX_OPT_DEPTH 10
 
2465
 
2466
 
 
2467
<<variables local to parse>>=
 
2468
size_t old_pos[MAX_OPT_DEPTH] = {0};
 
2469
int okay[MAX_OPT_DEPTH] = {1};
 
2470
int opt_depth = 1;
 
2471
 
2472
 
 
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,
 
2480
really. --- aj}
 
2481
 
 
2482
<<handle a token>>=
 
2483
case '[':
 
2484
        if (command[1] == '[' && opt_depth < MAX_OPT_DEPTH) {
 
2485
                old_pos[opt_depth] = pos;
 
2486
                okay[opt_depth] = 1;
 
2487
                opt_depth++;
 
2488
                command += 2;
 
2489
        } else {
 
2490
                addstr(&result, &len, &pos, "[", 1);
 
2491
                command++;
 
2492
        }
 
2493
        break;
 
2494
 
2495
 
 
2496
<<handle a token>>=
 
2497
case ']':
 
2498
        if (command[1] == ']' && opt_depth > 1) {
 
2499
                opt_depth--;
 
2500
                if (!okay[opt_depth]) {
 
2501
                        pos = old_pos[opt_depth];
 
2502
                        result[pos] = '\0';
 
2503
                }
 
2504
                command += 2;
 
2505
        } else {
 
2506
                addstr(&result, &len, &pos, "]", 1);
 
2507
                command++;
 
2508
        }
 
2509
        break;
 
2510
@
 
2511
 
 
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]].
 
2516
 
 
2517
<<execute headers>>=
 
2518
#include <errno.h>
 
2519
@
 
2520
 
 
2521
<<constant definitions>>=
 
2522
#define EUNBALBRACK 10001
 
2523
#define EUNDEFVAR   10002
 
2524
 
2525
 
 
2526
<<deal with error conditions>>=
 
2527
if (opt_depth > 1) {
 
2528
        errno = EUNBALBRACK;
 
2529
        free(result);
 
2530
        return NULL;
 
2531
}
 
2532
 
 
2533
if (!okay[0]) {
 
2534
        errno = EUNDEFVAR;
 
2535
        free(result);
 
2536
        return NULL;
 
2537
}
 
2538
 
2539
 
 
2540
\subsubsection{Variables}
 
2541
 
 
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.
 
2545
 
 
2546
<<constant definitions>>=
 
2547
#define MAX_VARNAME    32
 
2548
#define EUNBALPER   10000
 
2549
 
2550
 
 
2551
<<handle a token>>=
 
2552
case '%':
 
2553
{
 
2554
        <<variables local to handle percent token>>
 
2555
        char *varvalue;
 
2556
 
 
2557
        <<determine variable name>>
 
2558
 
 
2559
        <<get [[varvalue]]>>
 
2560
 
 
2561
        if (varvalue) {
 
2562
                addstr(&result, &len, &pos, varvalue, strlen(varvalue));
 
2563
        } else {
 
2564
                okay[opt_depth - 1] = 0;
 
2565
        }
 
2566
 
 
2567
        <<move to token after closing percent>>
 
2568
 
 
2569
        break;
 
2570
}
 
2571
 
2572
 
 
2573
We don't do anything particularly clever dealing with the next percent
 
2574
--- just a pointer to the appropriate character.
 
2575
 
 
2576
<<variables local to handle percent token>>=
 
2577
char *nextpercent;
 
2578
 
2579
 
 
2580
<<determine variable name>>=
 
2581
command++;
 
2582
nextpercent = strchr(command, '%');
 
2583
if (!nextpercent) {
 
2584
        errno = EUNBALPER;
 
2585
        free(result);
 
2586
        return NULL;
 
2587
}
 
2588
 
2589
 
 
2590
<<move to token after closing percent>>=
 
2591
command = nextpercent + 1;
 
2592
@
 
2593
 
 
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.
 
2597
 
 
2598
<<execute function declarations>>=
 
2599
int strncmpz(char *l, char *r, size_t llen);
 
2600
 
2601
 
 
2602
<<execute functions>>=
 
2603
int strncmpz(char *l, char *r, size_t llen) {
 
2604
        int i = strncmp(l, r, llen);
 
2605
        if (i == 0)
 
2606
                return -r[llen];
 
2607
        else
 
2608
                return i;
 
2609
}
 
2610
 
2611
 
 
2612
Given the above, the implementation of the [[get_var()]] function to
 
2613
lookup the value of a variable, is reasonably straight forward.
 
2614
 
 
2615
<<execute function declarations>>=
 
2616
char *get_var(char *id, size_t idlen, interface_defn *ifd);
 
2617
 
2618
 
 
2619
<<execute functions>>=
 
2620
char *get_var(char *id, size_t idlen, interface_defn *ifd) {
 
2621
        int i;
 
2622
 
 
2623
        if (strncmpz(id, "iface", idlen) == 0) {
 
2624
                return ifd->iface;
 
2625
        } else {
 
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;
 
2629
                        }
 
2630
                }
 
2631
        }
 
2632
 
 
2633
        return NULL;
 
2634
}
 
2635
 
2636
 
 
2637
Which means we can finish of the chunk, thus:
 
2638
 
 
2639
<<get [[varvalue]]>>=
 
2640
varvalue = get_var(command, nextpercent - command, ifd);
 
2641
 
2642
 
 
2643
\subsection{Mapping Scripts}
 
2644
 
 
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.
 
2653
 
 
2654
<<exported symbols>>=
 
2655
int run_mapping(char *physical, char *logical, int len, mapping_defn *map);
 
2656
 
2657
 
 
2658
<<execute functions>>=
 
2659
int run_mapping(char *physical, char *logical, int len, mapping_defn *map) {
 
2660
        FILE *in, *out;
 
2661
        int i, status;
 
2662
        pid_t pid;
 
2663
 
 
2664
        <<execute the mapping script>>
 
2665
        <<send input to mapping script>>
 
2666
        <<wait for mapping script to finish>>
 
2667
        <<check output from mapping script>>
 
2668
 
 
2669
        return 1;
 
2670
}
 
2671
 
2672
 
 
2673
The latter options here are fairly straightforward, given some Unix
 
2674
knowledge.
 
2675
 
 
2676
<<send input to mapping script>>=
 
2677
for (i = 0; i < map->n_mappings; i++) {
 
2678
        fprintf(in, "%s\n", map->mapping[i]);
 
2679
}
 
2680
fclose(in);
 
2681
 
2682
 
 
2683
<<wait for mapping script to finish>>=
 
2684
waitpid(pid, &status, 0);
 
2685
 
2686
 
 
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)) 
 
2692
                        *(pch--) = '\0';
 
2693
        }
 
2694
}
 
2695
fclose(out);    
 
2696
 
2697
 
 
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:
 
2702
 
 
2703
<<execute headers>>=
 
2704
#include <stdarg.h>
 
2705
 
2706
 
 
2707
<<execute function declarations>>=
 
2708
static int popen2(FILE **in, FILE **out, char *command, ...);
 
2709
 
2710
 
 
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
 
2713
otherwise.
 
2714
 
 
2715
As such, we will be able to execute the scrtip thusly:
 
2716
 
 
2717
<<execute the mapping script>>=
 
2718
pid = popen2(&in, &out, map->script, physical, NULL);
 
2719
if (pid == 0) {
 
2720
        return 0;
 
2721
}
 
2722
 
2723
 
 
2724
Writing [[popen2()]] is an exercise in Unix arcana.
 
2725
 
 
2726
<<execute headers>>=
 
2727
#include <unistd.h>
 
2728
#include <sys/wait.h>
 
2729
 
2730
 
 
2731
<<execute functions>>=
 
2732
static int popen2(FILE **in, FILE **out, char *command, ...) {
 
2733
        va_list ap;
 
2734
        char *argv[11] = {command};
 
2735
        int argc;
 
2736
        int infd[2], outfd[2];
 
2737
        pid_t pid;
 
2738
 
 
2739
        argc = 1;
 
2740
        va_start(ap, command);
 
2741
        while((argc < 10) && (argv[argc] = va_arg(ap, char*))) {
 
2742
                argc++;
 
2743
        }
 
2744
        argv[argc] = NULL; /* make sure */
 
2745
        va_end(ap);
 
2746
 
 
2747
        if (pipe(infd) != 0) return 0;
 
2748
        if (pipe(outfd) != 0) {
 
2749
                close(infd[0]); close(infd[1]);
 
2750
                return 0;
 
2751
        }
 
2752
 
 
2753
        switch(pid = fork()) {
 
2754
                case -1: /* failure */
 
2755
                        close(infd[0]); close(infd[1]);
 
2756
                        close(outfd[0]); close(outfd[1]);
 
2757
                        return 0;
 
2758
                case 0: /* child */
 
2759
                        dup2(infd[0], 0);
 
2760
                        dup2(outfd[1], 1);
 
2761
                        close(infd[0]); close(infd[1]);
 
2762
                        close(outfd[0]); close(outfd[1]);
 
2763
                        execvp(command, argv);
 
2764
                        exit(127);
 
2765
                default: /* parent */
 
2766
                        *in = fdopen(infd[1], "w");
 
2767
                        *out = fdopen(outfd[0], "r");
 
2768
                        close(infd[0]); close(outfd[1]);
 
2769
                        return pid;
 
2770
        }
 
2771
        /* unreached */
 
2772
}
 
2773
@
 
2774
 
 
2775
\section{The Driver}
 
2776
 
 
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.
 
2779
 
 
2780
<<main.c>>=
 
2781
<<main headers>>
 
2782
<<main global variables>>
 
2783
<<main function declarations>>
 
2784
<<main functions>>
 
2785
<<main>>
 
2786
 
2787
 
 
2788
Equally, there's nothing particularly special about our headers.
 
2789
 
 
2790
<<main headers>>=
 
2791
#include <stdio.h>
 
2792
#include <stdlib.h>
 
2793
#include <string.h>
 
2794
#include <ctype.h>
 
2795
#include <errno.h>
 
2796
#include <assert.h>
 
2797
 
 
2798
#include "header.h"
 
2799
@
 
2800
 
 
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]].
 
2806
 
 
2807
<<main>>=
 
2808
int main(int argc, char **argv) {
 
2809
        <<variables local to main>>
 
2810
 
 
2811
        <<ensure environment is sane>>
 
2812
 
 
2813
        <<parse command name or die>>
 
2814
        <<parse arguments>>
 
2815
 
 
2816
        <<read interfaces files or die>>
 
2817
 
 
2818
        <<run commands for appropriate interfaces>>
 
2819
 
 
2820
        return 0;
 
2821
}
 
2822
@
 
2823
 
 
2824
\subsection{Check the Environment}
 
2825
 
 
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:
 
2828
 
 
2829
<<main headers>>=
 
2830
#include <unistd.h>
 
2831
#include <fcntl.h>
 
2832
@
 
2833
 
 
2834
<<ensure environment is sane>>=
 
2835
{
 
2836
        int i;
 
2837
        for (i = 0; i <= 2; i++) {
 
2838
                if (fcntl(i, F_GETFD) == -1) {
 
2839
                        if (errno == EBADF && open("/dev/null", 0) == -1) {
 
2840
                                fprintf(stderr,
 
2841
                                        "%s: fd %d not available; aborting\n",
 
2842
                                        argv[0], i);
 
2843
                                exit(2);
 
2844
                        } else if (errno == EBADF) {
 
2845
                                errno = 0; /* no more problems */
 
2846
                        } else {
 
2847
                                /* some other problem -- eeek */
 
2848
                                perror(argv[0]);
 
2849
                                exit(2);
 
2850
                        }
 
2851
                }
 
2852
        }
 
2853
}
 
2854
@
 
2855
 
 
2856
\subsection{Configuring or Deconfiguring?}
 
2857
 
 
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.
 
2864
 
 
2865
<<variables local to main>>=
 
2866
int (*cmds)(interface_defn *) = NULL;
 
2867
@
 
2868
 
 
2869
So given this, we can just:
 
2870
 
 
2871
<<parse command name or die>>=
 
2872
{
 
2873
        char *command;
 
2874
 
 
2875
        <<set [[command]] to the base of the command name>>
 
2876
        <<set [[cmds]] based on [[command]] or die>>
 
2877
}
 
2878
@
 
2879
 
 
2880
And fill out each component in the reasonably obvious manner of:
 
2881
 
 
2882
<<set [[command]] to the base of the command name>>=
 
2883
if ((command = strrchr(argv[0],'/'))) {
 
2884
        command++; /* first char after / */
 
2885
} else {
 
2886
        command = argv[0]; /* no /'s in argv[0] */
 
2887
}
 
2888
@
 
2889
 
 
2890
<<set [[cmds]] based on [[command]] or die>>=
 
2891
if (strcmp(command, "ifup")==0) {
 
2892
        cmds = iface_up;
 
2893
} else if (strcmp(command, "ifdown")==0) {
 
2894
        cmds = iface_down;
 
2895
} else {
 
2896
        fprintf(stderr,"This command should be called as ifup or ifdown\n");
 
2897
        exit(1);
 
2898
}
 
2899
 
2900
 
 
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
 
2903
with this, namely:
 
2904
 
 
2905
<<we're bringing interfaces up>>=
 
2906
(cmds == iface_up)
 
2907
@
 
2908
 
 
2909
<<we're taking interfaces down>>=
 
2910
(cmds == iface_down)
 
2911
@
 
2912
 
 
2913
\subsection{Argument Handling}
 
2914
 
 
2915
Okay, so next on our agenda is argument handling.
 
2916
 
 
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:
 
2920
 
 
2921
<<main headers>>=
 
2922
#include <getopt.h>
 
2923
@
 
2924
 
 
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 },
 
2935
        {0,0,0,0}
 
2936
};
 
2937
 
2938
 
 
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.
 
2942
 
 
2943
<<exported symbols>>=
 
2944
extern int no_act;
 
2945
extern int verbose;
 
2946
@
 
2947
 
 
2948
<<main global variables>>=
 
2949
int no_act = 0;
 
2950
int verbose = 0;
 
2951
@
 
2952
 
 
2953
<<variables local to main>>=
 
2954
int do_all = 0;
 
2955
int run_mappings = 1;
 
2956
int force = 0;
 
2957
char *interfaces = "/etc/network/interfaces";
 
2958
 
2959
 
 
2960
We'll also have two helper functions to display usage information,
 
2961
like so:
 
2962
 
 
2963
<<main function declarations>>=
 
2964
static void usage(char *execname);
 
2965
static void help(char *execname);
 
2966
static void version(char *execname);
 
2967
 
2968
 
 
2969
<<main functions>>=
 
2970
static void usage(char *execname) {
 
2971
        fprintf(stderr, "%s: Use --help for help\n", execname);
 
2972
        exit(1);
 
2973
}
 
2974
 
2975
 
 
2976
<<main functions>>=
 
2977
static void version(char *execname) {
 
2978
        printf("%s version " IFUPDOWN_VERSION "\n", execname);
 
2979
        printf("Copyright (c) 1999,2000 Anthony Towns\n\n");
 
2980
        printf(
 
2981
 
 
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"
 
2986
 
 
2987
        );
 
2988
        exit(0);
 
2989
}
 
2990
 
2991
 
 
2992
<<main functions>>=
 
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");
 
3005
        exit(0);
 
3006
}
 
3007
 
3008
 
 
3009
Now, the meat of argument parsing is done with [[getopt()]] and a
 
3010
[[switch]], like so:
 
3011
 
 
3012
<<parse arguments>>=
 
3013
for(;;) {
 
3014
        int c;
 
3015
        c = getopt_long(argc, argv, "s:i:hVvna", long_opts, NULL);
 
3016
        if (c == EOF) break;
 
3017
 
 
3018
        switch(c) {
 
3019
                <<[[getopt]] possibilities>>
 
3020
        }
 
3021
}
 
3022
 
 
3023
<<check unreasonable arguments>>
 
3024
 
3025
 
 
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:
 
3029
 
 
3030
<<[[getopt]] possibilities>>=
 
3031
case 'i':
 
3032
        interfaces = strdup(optarg);
 
3033
        break;
 
3034
 
3035
<<[[getopt]] possibilities>>=
 
3036
case 'v':
 
3037
        verbose = 1;
 
3038
        break;
 
3039
 
3040
<<[[getopt]] possibilities>>=
 
3041
case 'a':
 
3042
        do_all = 1;
 
3043
        break;
 
3044
 
3045
<<[[getopt]] possibilities>>=
 
3046
case 'n':
 
3047
        no_act = 1;
 
3048
        break;
 
3049
 
3050
<<[[getopt]] possibilities>>=
 
3051
case 1:
 
3052
        run_mappings = 0;
 
3053
        break;
 
3054
 
3055
<<[[getopt]] possibilities>>=
 
3056
case 2:
 
3057
        force = 1;
 
3058
        break;
 
3059
@
 
3060
 
 
3061
And we also have a help option and a version option:
 
3062
 
 
3063
<<[[getopt]] possibilities>>=
 
3064
case 'h':
 
3065
        help(argv[0]);
 
3066
        break;
 
3067
 
3068
<<[[getopt]] possibilities>>=
 
3069
case 'V':
 
3070
        version(argv[0]);
 
3071
        break;
 
3072
 
3073
 
 
3074
And we also have the possibility that the user is just making up
 
3075
options:
 
3076
 
 
3077
<<[[getopt]] possibilities>>=
 
3078
default:
 
3079
        usage(argv[0]);
 
3080
        break;
 
3081
@
 
3082
 
 
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:
 
3088
 
 
3089
<<check unreasonable arguments>>=
 
3090
if (argc - optind > 0 && do_all) {
 
3091
        usage(argv[0]);
 
3092
}
 
3093
 
3094
 
 
3095
<<check unreasonable arguments>>=
 
3096
if (argc - optind == 0 && !do_all) {
 
3097
        usage(argv[0]);
 
3098
}
 
3099
 
3100
 
 
3101
\subsection{Reading the Interfaces File}
 
3102
 
 
3103
Since this has all been covered in a previous section, this is pretty
 
3104
trivial.
 
3105
 
 
3106
<<variables local to main>>=
 
3107
interfaces_file *defn;
 
3108
 
3109
 
 
3110
<<read interfaces files or die>>=
 
3111
defn = read_interfaces(interfaces);
 
3112
if ( !defn ) {
 
3113
        fprintf(stderr, "%s: couldn't read interfaces file \"%s\"\n",
 
3114
                argv[0], interfaces);
 
3115
        exit(1);
 
3116
}
 
3117
@
 
3118
 
 
3119
\subsection{Execution}
 
3120
 
 
3121
A broad overview of what we'll actually be doing is as follows:
 
3122
 
 
3123
<<run commands for appropriate interfaces>>=
 
3124
<<load ifupdown state>>
 
3125
<<determine target interfaces>>
 
3126
{
 
3127
        int i;
 
3128
        for (<<each target interface, [[i]]>>) {
 
3129
                char iface[80], liface[80];
 
3130
 
 
3131
                <<initialize [[iface]] to [[i]]th target interface>>
 
3132
                if (!force) {
 
3133
                        <<check ifupdown state (possibly [[continue]])>>
 
3134
                }
 
3135
 
 
3136
                if (<<we're bringing interfaces up>> && run_mappings) {
 
3137
                        <<run mappings>>
 
3138
                }
 
3139
 
 
3140
                <<bring interface up/down and update ifupdown state>>
 
3141
                <<commit ifupdown state>>
 
3142
        }
 
3143
}
 
3144
@
 
3145
 
 
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.
 
3149
 
 
3150
Mappings are dealt with like so:
 
3151
 
 
3152
<<run mappings>>=
 
3153
{
 
3154
        mapping_defn *currmap;
 
3155
        for (currmap = defn->mappings; currmap; currmap = currmap->next) {
 
3156
                int i;
 
3157
                for (i = 0; i < currmap->n_matches; i++) {
 
3158
                        <<[[continue]] unless mapping matches>>
 
3159
                        <<run mapping>>
 
3160
                        break;
 
3161
                }
 
3162
        }
 
3163
}
 
3164
@
 
3165
 
 
3166
We check if mappings match by using shell globs, so we'll need a new header
 
3167
to take care of that.
 
3168
 
 
3169
<<main headers>>=
 
3170
#include <fnmatch.h>
 
3171
 
3172
 
 
3173
<<[[continue]] unless mapping matches>>=
 
3174
if (fnmatch(currmap->match[i], liface, 0) != 0)
 
3175
        continue;
 
3176
@
 
3177
 
 
3178
Actually running a mapping is fairly straightforward, thanks to our
 
3179
previous handywork.
 
3180
 
 
3181
<<run mapping>>=
 
3182
if (verbose) {
 
3183
        fprintf(stderr, "Running mapping script %s on %s\n",
 
3184
                currmap->script, liface);
 
3185
}
 
3186
run_mapping(iface, liface, sizeof(liface), currmap);
 
3187
@
 
3188
 
 
3189
Bringing an interface up or taking it down can be done thusly:
 
3190
 
 
3191
<<bring interface up/down and update ifupdown state>>=
 
3192
{
 
3193
        interface_defn *currif;
 
3194
        int okay = 0;
 
3195
        for (currif = defn->ifaces; currif; currif = currif->next) {
 
3196
                if (strcmp(liface, currif->iface) == 0) {
 
3197
                        okay = 1;
 
3198
                        <<run commands for [[currif]]>>
 
3199
                }
 
3200
        }
 
3201
 
 
3202
        if (!okay && !force) {
 
3203
                fprintf(stderr, "Ignoring unknown interface %s=%s.\n", 
 
3204
                        iface, liface);
 
3205
        } else {
 
3206
                <<update ifupdown state>>
 
3207
        }
 
3208
}
 
3209
@
 
3210
 
 
3211
<<run commands for [[currif]]>>=
 
3212
{
 
3213
        char *oldiface = currif->iface;
 
3214
        currif->iface = iface;
 
3215
 
 
3216
        if (verbose) {
 
3217
                fprintf(stderr, "Configuring interface %s=%s (%s)\n", 
 
3218
                        iface, liface, currif->address_family->name);
 
3219
        }
 
3220
 
 
3221
        switch(cmds(currif)) {
 
3222
            case -1:
 
3223
                printf("Don't seem to be have all the variables for %s/%s.\n", 
 
3224
                        liface, currif->address_family->name);
 
3225
                break;
 
3226
            case 0:
 
3227
                /* this wasn't entirely successful, should it be added to
 
3228
                 *      the state file?
 
3229
                 */
 
3230
            case 1:
 
3231
                /* successful */
 
3232
        }
 
3233
        currif->iface = oldiface;
 
3234
}
 
3235
 
3236
 
 
3237
\subsection{Target Interfaces}
 
3238
 
 
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]].
 
3243
 
 
3244
<<variables local to main>>=
 
3245
int n_target_ifaces;
 
3246
char **target_iface;
 
3247
 
3248
 
 
3249
<<each target interface, [[i]]>>=
 
3250
i = 0; i < n_target_ifaces; i++
 
3251
@
 
3252
 
 
3253
We initialise this based on our command line arguments.
 
3254
 
 
3255
<<determine target interfaces>>=
 
3256
if (do_all) {
 
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;
 
3263
        } else {
 
3264
                assert(0);
 
3265
        }       
 
3266
} else {
 
3267
        target_iface = argv + optind;
 
3268
        n_target_ifaces = argc - optind;
 
3269
}
 
3270
 
3271
 
 
3272
<<initialize [[iface]] to [[i]]th target interface>>=
 
3273
strncpy(iface, target_iface[i], sizeof(iface));
 
3274
iface[sizeof(iface)-1] = '\0';
 
3275
 
 
3276
{
 
3277
        char *pch;
 
3278
        if ((pch = strchr(iface, '='))) {
 
3279
                *pch = '\0';
 
3280
                strncpy(liface, pch+1, sizeof(liface));
 
3281
                liface[sizeof(liface)-1] = '\0';
 
3282
        } else {
 
3283
                strncpy(liface, iface, sizeof(liface));
 
3284
                liface[sizeof(liface)-1] = '\0';
 
3285
        }
 
3286
}
 
3287
 
3288
 
 
3289
\subsection{State}
 
3290
 
 
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.
 
3299
 
 
3300
<<variables local to main>>=
 
3301
char **state = NULL; /* list of iface=liface */
 
3302
int n_state = 0;
 
3303
int max_state = 0;
 
3304
 
3305
 
 
3306
We'll also use two helper functions: one to lookup an interface, and one to
 
3307
add an interface.
 
3308
 
 
3309
<<main function declarations>>=
 
3310
static int lookfor_iface(char **ifaces, int n_ifaces, char *iface);
 
3311
 
3312
 
 
3313
<<main functions>>=
 
3314
static int lookfor_iface(char **ifaces, int n_ifaces, char *iface) {
 
3315
        int i;
 
3316
        for (i = 0; i < n_ifaces; i++) {
 
3317
                if (strncmp(iface, ifaces[i], strlen(iface)) == 0) {
 
3318
                        if (ifaces[i][strlen(iface)] == '=') {
 
3319
                                return i;
 
3320
                        }
 
3321
                }
 
3322
        }
 
3323
        return -1;
 
3324
}
 
3325
 
3326
 
 
3327
<<main function declarations>>=
 
3328
static void add_to_state(char ***ifaces, int *n_ifaces, int *max_ifaces, 
 
3329
                         char *new_iface);
 
3330
 
3331
 
 
3332
<<main functions>>=
 
3333
static void add_to_state(char ***ifaces, int *n_ifaces, int *max_ifaces, 
 
3334
                         char *new_iface)
 
3335
{
 
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) {
 
3341
                        perror("realloc");
 
3342
                        exit(1);
 
3343
                }
 
3344
        }
 
3345
 
 
3346
        (*ifaces)[(*n_ifaces)++] = new_iface;
 
3347
}
 
3348
 
3349
 
 
3350
Given these, we can then load our state file like so:
 
3351
 
 
3352
<<load ifupdown state>>=
 
3353
{
 
3354
        FILE *f = fopen("/etc/network/ifstate", "r");
 
3355
        if (f != NULL) {
 
3356
                char buf[80];
 
3357
                while(fgets(buf, 80, f)) {
 
3358
                        char *pch;
 
3359
 
 
3360
                        pch = buf + strlen(buf) - 1;
 
3361
                        while(pch > buf && isspace(*pch)) pch--;
 
3362
                        *(pch+1) = '\0';
 
3363
 
 
3364
                        pch = buf;
 
3365
                        while(isspace(*pch)) pch++;
 
3366
 
 
3367
                        add_to_state(&state, &n_state, &max_state, strdup(pch));
 
3368
                }
 
3369
                fclose(f);
 
3370
        }
 
3371
}
 
3372
 
3373
 
 
3374
<<commit ifupdown state>>=
 
3375
if (!no_act) {
 
3376
        FILE *f = fopen("/etc/network/ifstate", "w");
 
3377
        int i;
 
3378
 
 
3379
        if (f == NULL) {
 
3380
                perror("/etc/network/ifstate");
 
3381
                exit(1);
 
3382
        }
 
3383
 
 
3384
        for (i = 0; i < n_state; i++) {
 
3385
                fprintf(f, "%s\n", state[i]);
 
3386
        }
 
3387
 
 
3388
        fclose(f);
 
3389
}
 
3390
 
3391
 
 
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).
 
3395
 
 
3396
<<check ifupdown state (possibly [[continue]])>>=
 
3397
{
 
3398
        int already_up = lookfor_iface(state, n_state, iface);;
 
3399
 
 
3400
        if (<<we're bringing interfaces up>>) {
 
3401
                if (already_up != -1) {
 
3402
                        fprintf(stderr, 
 
3403
                                "%s: interface %s already configured\n",
 
3404
                                argv[0], iface);
 
3405
                        continue;
 
3406
                }
 
3407
        } else if (<<we're taking interfaces down>>) {
 
3408
                if (already_up == -1) {
 
3409
                        fprintf(stderr, "%s: interface %s not configured\n",
 
3410
                                argv[0], iface);
 
3411
                        continue;
 
3412
                }
 
3413
                strncpy(liface, strchr(state[already_up], '=') + 1, 80);
 
3414
                liface[79] = 0;
 
3415
        } else {
 
3416
                assert(0);
 
3417
        }
 
3418
}
 
3419
 
3420
 
 
3421
And finally, we also need to be able to update the state as we bring
 
3422
interfaces up and down.
 
3423
 
 
3424
<<update ifupdown state>>=
 
3425
{
 
3426
        int already_up = lookfor_iface(state, n_state, iface);
 
3427
 
 
3428
        if (<<we're bringing interfaces up>>) {
 
3429
                char *newiface = 
 
3430
                        malloc(strlen(iface) + 1 + strlen(liface) + 1);
 
3431
                sprintf(newiface, "%s=%s", iface, liface);
 
3432
 
 
3433
                if (already_up == -1) {
 
3434
                        add_to_state(&state, &n_state, &max_state, newiface);
 
3435
                } else {
 
3436
                        free(state[already_up]);
 
3437
                        state[already_up] = newiface;
 
3438
                }
 
3439
        } else if (<<we're taking interfaces down>>) {
 
3440
                if (already_up != -1) {
 
3441
                        state[already_up] = state[--n_state];
 
3442
                }
 
3443
        } else {
 
3444
                assert(0);
 
3445
        }
 
3446
}
 
3447
 
3448
 
 
3449
\appendix
 
3450
 
 
3451
\section{Linux Address Families}
 
3452
 
 
3453
<<archlinux.h>>=
 
3454
unsigned int mylinuxver();
 
3455
unsigned int mylinux(int,int,int);
 
3456
int execable(char *);
 
3457
@
 
3458
 
 
3459
<<archlinux.c>>=
 
3460
#include <stdio.h>
 
3461
#include <stdlib.h>
 
3462
#include <string.h>
 
3463
#include <unistd.h>
 
3464
#include <sys/utsname.h>
 
3465
#include <sys/stat.h>
 
3466
 
 
3467
#include "archlinux.h"
 
3468
 
 
3469
unsigned int mylinuxver() {
 
3470
        static int maj = -1, rev, min;
 
3471
 
 
3472
        if (maj == -1) {
 
3473
                struct utsname u;
 
3474
                char *pch;
 
3475
                uname(&u);
 
3476
                maj = atoi(u.release);
 
3477
                pch = strchr(u.release, '.');
 
3478
                rev = atoi(pch+1);
 
3479
                pch = strchr(pch+1, '.');
 
3480
                min = atoi(pch+1);
 
3481
        }
 
3482
 
 
3483
        return mylinux(maj,rev,min);
 
3484
}
 
3485
 
 
3486
unsigned int mylinux(int maj, int rev, int min) { 
 
3487
        return min | rev << 10 | maj << 13;
 
3488
}
 
3489
 
 
3490
int execable(char *program) {
 
3491
        struct stat buf;
 
3492
 
 
3493
        if (0 == stat(program, &buf)) {
 
3494
                if (S_ISREG(buf.st_mode) && (S_IXUSR & buf.st_mode)) return 1;
 
3495
        }
 
3496
        return 0;
 
3497
}
 
3498
 
3499
 
 
3500
\subsection{IPv4 Address Family}
 
3501
 
 
3502
<<address family declarations>>=
 
3503
extern address_family addr_inet;
 
3504
 
3505
 
 
3506
<<address family references>>=
 
3507
&addr_inet, 
 
3508
 
3509
 
 
3510
<<inet.defn>>=
 
3511
address_family inet
 
3512
architecture linux
 
3513
 
 
3514
<<inet methods>>
 
3515
 
3516
 
 
3517
<<inet methods>>=
 
3518
method loopback
 
3519
  description
 
3520
    This method may be used to define the IPv4 loopback interface.
 
3521
 
 
3522
  up
 
3523
    ifconfig %iface% 127.0.0.1 up
 
3524
    route add -net 127.0.0.0       if ( mylinuxver() < mylinux(2,1,100) )
 
3525
 
 
3526
  down
 
3527
    ifconfig %iface% down
 
3528
 
3529
 
 
3530
<<inet methods>>=
 
3531
method static
 
3532
  description
 
3533
    This method may be used to define ethernet interfaces with statically
 
3534
    allocated IPv4 addresses.
 
3535
      
 
3536
  options
 
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 \
 
3541
                                     for 2.0.x kernels*
 
3542
    gateway address             -- Default gateway (dotted quad)
 
3543
    pointopoint address         -- Address of other end point (dotted quad). \
 
3544
                                   Note the spelling of "point-to".
 
3545
 
 
3546
  up
 
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% ]]
 
3552
 
 
3553
  down
 
3554
    [[ route del default gw %gateway% %iface% ]]
 
3555
    ifconfig %iface% down
 
3556
 
3557
 
 
3558
<<inet methods>>=
 
3559
method dhcp
 
3560
  description
 
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*.
 
3566
 
 
3567
  options
 
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)
 
3573
 
 
3574
  up
 
3575
    dhclient %iface%  \
 
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"))
 
3582
 
 
3583
  down
 
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))
 
3588
    dhcpcd -k %iface% \
 
3589
        elsif (execable("/sbin/dhcpcd"))
 
3590
 
 
3591
    ifconfig %iface% down
 
3592
 
3593
 
 
3594
<<inet methods>>=
 
3595
method bootp
 
3596
  description
 
3597
    This method may be used to obtain an address via bootp.
 
3598
 
 
3599
  options
 
3600
    bootfile file  -- Tell the server to use /file/ as the bootfile.
 
3601
    server address -- Use the IP address /address/ to communicate with \
 
3602
                      the server.
 
3603
    hwaddr addr    -- Use /addr/ as the hardware address instead of \
 
3604
                      whatever it really is.
 
3605
 
 
3606
  up
 
3607
    bootpc [[--bootfile %bootfile%]] --dev %iface% [[--server %server%]] \
 
3608
           [[--hwaddr %hwaddr%]] --returniffail --serverbcast
 
3609
 
 
3610
  down
 
3611
    ifconfig down %iface%
 
3612
 
3613
 
 
3614
<<inet methods>>=
 
3615
method ppp
 
3616
  description
 
3617
    This method uses pon/poff to configure a PPP interface. See those
 
3618
    commands for details.
 
3619
  options
 
3620
    provider name  -- Use /name/ as the provider (from /etc/ppp/peers).
 
3621
  up
 
3622
    pon [[%provider%]]
 
3623
  down
 
3624
    poff [[%provider%]]
 
3625
 
3626
 
 
3627
\subsection{IPv6 Address Family}
 
3628
 
 
3629
<<address family declarations>>=
 
3630
extern address_family addr_inet6;
 
3631
 
3632
 
 
3633
<<address family references>>=
 
3634
&addr_inet6,
 
3635
 
3636
 
 
3637
<<inet6.defn>>=
 
3638
address_family inet6
 
3639
architecture linux
 
3640
 
 
3641
method loopback
 
3642
  description
 
3643
    This method may be used to define the IPv6 loopback interface.
 
3644
  up
 
3645
    ifconfig %iface% add ::1
 
3646
  down
 
3647
    ifconfig %iface% del ::1
 
3648
 
 
3649
method static
 
3650
  description
 
3651
    This method may be used to define interfaces with statically assigned
 
3652
    IPv6 addresses.
 
3653
 
 
3654
  options
 
3655
    address address        -- Address (colon delimited) *required*
 
3656
    netmask mask           -- Netmask (number of bits, eg 64) *required*
 
3657
    gateway address        -- Default gateway (colon delimited)
 
3658
 
 
3659
  up
 
3660
    ifconfig %iface% up
 
3661
    ifconfig %iface% add %address%/%netmask%
 
3662
    [[ route -A inet6 add ::/0 gw %gateway% ]] 
 
3663
 
 
3664
  down
 
3665
    ifconfig %iface% down
 
3666
 
 
3667
method v4tunnel
 
3668
  description
 
3669
    This method may be used to setup an IPv6-over-IPv4 tunnel. It requires
 
3670
    the *ip* command from the *iproute* package.
 
3671
 
 
3672
  options
 
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)
 
3678
 
 
3679
  up
 
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% ]]
 
3684
 
 
3685
  down
 
3686
    ip tunnel del %iface%
 
3687
 
3688
 
 
3689
\subsection{IPX Address Family}
 
3690
 
 
3691
<<address family declarations>>=
 
3692
extern address_family addr_ipx;
 
3693
 
3694
 
 
3695
<<address family references>>=
 
3696
&addr_ipx,
 
3697
 
3698
 
 
3699
<<ipx.defn>>=
 
3700
address_family ipx
 
3701
architecture linux
 
3702
 
 
3703
method static
 
3704
  description
 
3705
    This method may be used to setup an IPX interface.
 
3706
 
 
3707
  options
 
3708
    frame
 
3709
    netnum
 
3710
 
 
3711
  up
 
3712
    ipx_interface add %iface% %frame% %netnum%
 
3713
 
 
3714
  down
 
3715
    ipx_interface del %iface% %frame%
 
3716
 
 
3717
method dynamic
 
3718
  description
 
3719
    This method may be used to setup an IPX interface dynamically.
 
3720
 
 
3721
  options
 
3722
    frame
 
3723
 
 
3724
  up
 
3725
    ipx_interface add %iface% %frame%
 
3726
 
 
3727
  down
 
3728
    ipx_interface del %iface% %frame%
 
3729
 
3730
 
 
3731
\begin{flushleft}
 
3732
\bibliography{biblio}
 
3733
\bibliographystyle{unsrt}
 
3734
\end{flushleft}
 
3735
 
 
3736
\end{document}