3545
3548
interface is configured (since a mapping script may well bring the
3546
3549
interface down while it's investigating matters), we need to maintain a
3547
3550
statefile between invocations to keep track of which physical interfaces
3548
were mapped to which logical ones. We use [[/var/run/network/ifstate]] for
3549
this, because on Ubuntu that's guaranteed to be a tmpfs.
3551
<<variables local to main>>=
3552
char **state = NULL; /* list of iface=liface */
3557
We'll also use two helper functions: one to lookup an interface, and one to
3560
<<main function declarations>>=
3561
static int lookfor_iface(char **ifaces, int n_ifaces, char *iface);
3565
static int lookfor_iface(char **ifaces, int n_ifaces, char *iface) {
3567
for (i = 0; i < n_ifaces; i++) {
3568
if (strncmp(iface, ifaces[i], strlen(iface)) == 0) {
3569
if (ifaces[i][strlen(iface)] == '=') {
3578
<<main function declarations>>=
3579
static void add_to_state(char ***ifaces, int *n_ifaces, int *max_ifaces,
3584
static void add_to_state(char ***ifaces, int *n_ifaces, int *max_ifaces,
3587
assert(*max_ifaces >= *n_ifaces);
3588
if (*max_ifaces == *n_ifaces) {
3589
*max_ifaces = (*max_ifaces * 2) + 1;
3590
*ifaces = realloc(*ifaces, sizeof(**ifaces) * *max_ifaces);
3591
if (*ifaces == NULL) {
3597
(*ifaces)[(*n_ifaces)++] = new_iface;
3551
were mapped to which logical ones. This file also serves to record which
3552
interfaces have been configured so far, and which haven't. On Ubuntu we
3553
use [[/var/run/network/ifstate]] as that filesystem is guaranteed to be
3554
a tmpfs, meaning we don't have to worry about cleaning up after a reboot.
3556
Because different interfaces may be brought up and down at the same time,
3557
it's important that all updates to the state file are atomic and that we
3558
aren't confused by any changes made by another running process. For this
3559
reason we use functions to examine or modify the state file at the point
3560
necessary rather than holding it all in memory.
3562
<<main function declarations>>=
3563
static const char *read_state(const char *argv0, const char *iface);
3564
static void read_all_state(const char *argv0, char ***ifaces, int *n_ifaces);
3565
static void update_state(const char *argv0, const char *iface, const char *liface);
3568
The first of these functions reads the state file to look for an interface
3569
and returns the current state of it as a pointer to a static buffer which
3570
should be copied if it's needed for any duration. If the interface has no
3571
current state (ie. is down) then NULL is returned.
3575
read_state (const char *argv0, const char *iface)
3579
<<open ifupdown state>>
3581
while((p = fgets(buf, sizeof buf, state_fp)) != NULL) {
3582
<<parse ifupdown state line>>
3584
if (strncmp(iface, pch, strlen(iface)) == 0) {
3585
if (pch[strlen(iface)] == '=') {
3586
ret = pch + strlen(iface) + 1;
3592
<<close ifupdown state>>
3598
The second of these functions is a variant on the above used to grab a list
3599
of all currently up interfaces so we can tear them all down.
3603
read_all_state (const char *argv0, char ***ifaces, int *n_ifaces)
3605
<<open ifupdown state>>
3610
while((p = fgets(buf, sizeof buf, state_fp)) != NULL) {
3611
<<parse ifupdown state line>>
3614
*ifaces = realloc (*ifaces, sizeof (**ifaces) * *n_ifaces);
3615
(*ifaces)[(*n_ifaces)-1] = strdup (pch);
3618
<<close ifupdown state>>
3622
The last of these functions is used to modify a state file, specifically
3623
for the interface given as the first argument. If the second argument is
3624
NULL then any existing state for that interface is removed from the file,
3625
otherwise any existing state is changed to the new state or a new state
3629
static void update_state(const char *argv0, const char *iface, const char *state)
3633
<<open ifupdown state>>
3638
tmp_fp = fopen(tmpstatefile, "w");
3639
if (tmp_fp == NULL) {
3641
"%s: failed to open temporary statefile %s: %s\n",
3642
argv0, tmpstatefile, strerror(errno));
3646
while((p = fgets(buf, sizeof buf, state_fp)) != NULL) {
3647
<<parse ifupdown state line>>
3649
if (strncmp(iface, pch, strlen(iface)) == 0) {
3650
if (pch[strlen(iface)] == '=') {
3651
if (state != NULL) {
3652
fprintf (tmp_fp, "%s=%s\n",
3661
fprintf (tmp_fp, "%s\n", pch);
3665
fprintf (tmp_fp, "%s=%s\n", iface, state);
3668
if (rename (tmpstatefile, statefile)) {
3670
"%s: failed to overwrite statefile %s: %s\n",
3671
argv0, statefile, strerror(errno));
3675
<<close ifupdown state>>
3625
<<variables local to main>>=
3626
static FILE *state_fp = NULL;
3629
<<lock 'n load ifupdown state>>=
3631
state_fp = fopen(statefile, no_act ? "r" : "a+");
3632
if (state_fp == NULL && !no_act) {
3702
<<open ifupdown state>>=
3707
state_fp = fopen(statefile, no_act ? "r" : "a+");
3708
if (state_fp == NULL) {
3633
3710
fprintf(stderr,
3634
3711
"%s: failed to open statefile %s: %s\n",
3635
argv[0], statefile, strerror(errno));
3712
argv0, statefile, strerror(errno));
3639
if (state_fp != NULL) {
3646
if ((flags = fcntl(fileno(state_fp), F_GETFD)) < 0
3647
|| fcntl(fileno(state_fp), F_SETFD, flags | FD_CLOEXEC) < 0) {
3649
"%s: failed to set FD_CLOEXEC on statefile %s: %s\n",
3650
argv[0], statefile, strerror(errno));
3654
if (lock_fd (fileno(state_fp)) < 0) {
3656
"%s: failed to lock statefile %s: %s\n",
3657
argv[0], statefile, strerror(errno));
3664
while((p = fgets(buf, sizeof buf, state_fp)) != NULL) {
3667
pch = buf + strlen(buf) - 1;
3668
while(pch > buf && isspace(*pch)) pch--;
3672
while(isspace(*pch)) pch++;
3674
add_to_state(&state, &n_state, &max_state, strdup(pch));
3722
if ((flags = fcntl(fileno(state_fp), F_GETFD)) < 0
3723
|| fcntl(fileno(state_fp), F_SETFD, flags | FD_CLOEXEC) < 0) {
3725
"%s: failed to set FD_CLOEXEC on statefile %s: %s\n",
3726
argv0, statefile, strerror(errno));
3730
if (lock_fd (fileno(state_fp)) < 0) {
3732
"%s: failed to lock statefile %s: %s\n",
3733
argv0, statefile, strerror(errno));
3739
<<parse ifupdown state line>>=
3742
pch = buf + strlen(buf) - 1;
3743
while(pch > buf && isspace(*pch)) pch--;
3747
while(isspace(*pch)) pch++;
3680
3750
<<close ifupdown state>>=
3681
3752
if (state_fp != NULL) {
3682
3753
fclose(state_fp);
3683
3754
state_fp = NULL;
3688
<<commit ifupdown state>>=
3689
if (state_fp != NULL && !no_act) {
3692
if (ftruncate(fileno(state_fp), 0) < 0)
3695
"%s: failed to truncate statefile %s: %s\n",
3696
argv[0], statefile, strerror(errno));
3701
for (i = 0; i < n_state; i++) {
3702
fprintf(state_fp, "%s\n", state[i]);
3708
3758
This leaves our two useful chunks. The first checks to ensure what we're
3709
3759
proposing to do is reasonable (ie, we're not downing an interface that's
3710
3760
not up, or uping one that's not down).
3712
3762
<<check ifupdown state (possibly [[continue]])>>=
3714
int already_up = lookfor_iface(state, n_state, iface);;
3716
3764
if (<<we're bringing interfaces up>>) {
3717
if (already_up != -1) {
3765
if (current_state != NULL) {
3719
3767
fprintf(stderr,
3720
3768
"%s: interface %s already configured\n",
3721
3769
argv[0], iface);
3744
3792
<<update ifupdown state>>=
3746
int already_up = lookfor_iface(state, n_state, iface);
3748
3794
if (<<we're bringing interfaces up>>) {
3750
malloc(strlen(iface) + 1 + strlen(liface) + 1);
3751
sprintf(newiface, "%s=%s", iface, liface);
3753
if (already_up == -1) {
3795
if (current_state == NULL) {
3754
3796
if (failed == 1) {
3755
3797
printf("Failed to bring up %s.\n", liface);
3798
update_state (argv[0], iface, NULL);
3757
add_to_state(&state, &n_state, &max_state, newiface);
3800
update_state (argv[0], iface, liface);
3760
free(state[already_up]);
3761
state[already_up] = newiface;
3803
update_state (argv[0], iface, liface);
3763
3805
} else if (<<we're taking interfaces down>>) {
3764
if (already_up != -1) {
3765
state[already_up] = state[--n_state];
3806
update_state (argv[0], iface, NULL);