~ubuntu-branches/ubuntu/jaunty/ifupdown/jaunty-201309120846

« back to all changes in this revision

Viewing changes to ifupdown.nw

  • Committer: Bazaar Package Importer
  • Author(s): Scott James Remnant
  • Date: 2006-01-26 15:56:54 UTC
  • Revision ID: james.westby@ubuntu.com-20060126155654-65t7t24rgpsm669d
Tags: 0.6.7ubuntu6
* Rewrite the way that ifup and ifdown read and write the state file.
  Instead of storing it in memory and holding a lock on it (preventing
  concurrent processes from actually being concurrent) use atomic read and
  write functions that only hold the lock for very short periods.

* Write to the state file when we start bringing up or tearing down the
  interface, so we don't ever try to do the same operation at the same
  time.
* Update the state file once the operation is complete to ensure we
  record the actual status of it.

* Restore the dhcp wait, so "ifup eth0" will hang around until DHCP is
  either successful or times out.  Adjust the udev rule again so that
  udevplug doesn't hang around.

Show diffs side-by-side

added added

removed removed

Lines of Context:
3165
3165
<<main global variables>>=
3166
3166
int no_act = 0;
3167
3167
int verbose = 0;
 
3168
char *statefile = "/var/run/network/ifstate";
 
3169
char *tmpstatefile = "/var/run/network/.ifstate.tmp";
3168
3170
@
3169
3171
 
3170
3172
<<variables local to main>>=
3173
3175
int force = 0;
3174
3176
char *allow_class = NULL;
3175
3177
char *interfaces = "/etc/network/interfaces";
3176
 
char *statefile = "/var/run/network/ifstate";
3177
3178
char *excludeint = NULL ;
3178
3179
3179
3180
 
3352
3353
A broad overview of what we'll actually be doing is as follows:
3353
3354
 
3354
3355
<<run commands for appropriate interfaces>>=
3355
 
<<lock 'n load ifupdown state>>
3356
3356
<<determine target interfaces>>
3357
3357
{
3358
3358
        int i;
3359
3359
        for (<<each target interface, [[i]]>>) {
3360
3360
                char iface[80], liface[80];
 
3361
                const char *current_state;
3361
3362
 
3362
3363
                <<initialize [[iface]] to [[i]]th target interface>>
 
3364
                current_state = read_state(argv[0], iface);
3363
3365
                if (!force) {
3364
3366
                        <<check ifupdown state (possibly [[continue]])>>
3365
3367
                }
3376
3378
                }
3377
3379
 
3378
3380
                <<bring interface up/down and update ifupdown state>>
3379
 
                <<commit ifupdown state>>
3380
3381
        }
3381
3382
}
3382
 
<<close ifupdown state>>
3383
3383
@
3384
3384
 
3385
3385
We'll leave determining the appropriate target interfaces and dealing
3432
3432
        interface_defn *currif;
3433
3433
        int okay = 0;
3434
3434
        int failed = 0; 
 
3435
        
 
3436
        <<update ifupdown state>>
 
3437
 
3435
3438
        for (currif = defn->ifaces; currif; currif = currif->next) {
3436
3439
                if (strcmp(liface, currif->logical_iface) == 0) {
3437
3440
                        okay = 1;
3447
3450
        if (!okay && !force) {
3448
3451
                fprintf(stderr, "Ignoring unknown interface %s=%s.\n", 
3449
3452
                        iface, liface);
 
3453
                update_state (argv[0], iface, NULL);
3450
3454
        } else {
3451
3455
                <<update ifupdown state>>
3452
3456
        }
3511
3515
                target_iface = autos ? autos->interfaces : NULL;
3512
3516
                n_target_ifaces = autos ? autos->n_interfaces : 0;
3513
3517
        } else if (<<we're taking interfaces down>>) {
3514
 
                target_iface = state;
3515
 
                n_target_ifaces = n_state;
 
3518
                read_all_state(argv[0], &target_iface, &n_target_ifaces);
3516
3519
        } else {
3517
3520
                assert(0);
3518
3521
        }       
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.
3550
 
 
3551
 
<<variables local to main>>=
3552
 
char **state = NULL; /* list of iface=liface */
3553
 
int n_state = 0;
3554
 
int max_state = 0;
3555
 
3556
 
 
3557
 
We'll also use two helper functions: one to lookup an interface, and one to
3558
 
add an interface.
3559
 
 
3560
 
<<main function declarations>>=
3561
 
static int lookfor_iface(char **ifaces, int n_ifaces, char *iface);
3562
 
3563
 
 
3564
 
<<main functions>>=
3565
 
static int lookfor_iface(char **ifaces, int n_ifaces, char *iface) {
3566
 
        int i;
3567
 
        for (i = 0; i < n_ifaces; i++) {
3568
 
                if (strncmp(iface, ifaces[i], strlen(iface)) == 0) {
3569
 
                        if (ifaces[i][strlen(iface)] == '=') {
3570
 
                                return i;
3571
 
                        }
3572
 
                }
3573
 
        }
3574
 
        return -1;
3575
 
}
3576
 
3577
 
 
3578
 
<<main function declarations>>=
3579
 
static void add_to_state(char ***ifaces, int *n_ifaces, int *max_ifaces, 
3580
 
                         char *new_iface);
3581
 
3582
 
 
3583
 
<<main functions>>=
3584
 
static void add_to_state(char ***ifaces, int *n_ifaces, int *max_ifaces, 
3585
 
                         char *new_iface)
3586
 
{
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) {
3592
 
                        perror("realloc");
3593
 
                        exit(1);
3594
 
                }
3595
 
        }
3596
 
 
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.
 
3555
 
 
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.
 
3561
 
 
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);
 
3566
 
3567
 
 
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.
 
3572
 
 
3573
<<main functions>>=
 
3574
static const char *
 
3575
read_state (const char *argv0, const char *iface)
 
3576
{
 
3577
        char *ret = NULL;
 
3578
 
 
3579
        <<open ifupdown state>>
 
3580
 
 
3581
        while((p = fgets(buf, sizeof buf, state_fp)) != NULL) {
 
3582
                <<parse ifupdown state line>>
 
3583
 
 
3584
                if (strncmp(iface, pch, strlen(iface)) == 0) {
 
3585
                        if (pch[strlen(iface)] == '=') {
 
3586
                                ret = pch + strlen(iface) + 1;
 
3587
                                break;
 
3588
                        }
 
3589
                }
 
3590
        }
 
3591
 
 
3592
        <<close ifupdown state>>
 
3593
 
 
3594
        return ret;
 
3595
}
 
3596
@
 
3597
 
 
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.
 
3600
 
 
3601
<<main functions>>=
 
3602
static void
 
3603
read_all_state (const char *argv0, char ***ifaces, int *n_ifaces)
 
3604
{
 
3605
        <<open ifupdown state>>
 
3606
 
 
3607
        *n_ifaces = 0;
 
3608
        *ifaces = NULL;
 
3609
 
 
3610
        while((p = fgets(buf, sizeof buf, state_fp)) != NULL) {
 
3611
                <<parse ifupdown state line>>
 
3612
 
 
3613
                (*n_ifaces)++;
 
3614
                *ifaces = realloc (*ifaces, sizeof (**ifaces) * *n_ifaces);
 
3615
                (*ifaces)[(*n_ifaces)-1] = strdup (pch);
 
3616
        }
 
3617
 
 
3618
        <<close ifupdown state>>
 
3619
}
 
3620
@
 
3621
 
 
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
 
3626
line is appended.
 
3627
 
 
3628
<<main functions>>=
 
3629
static void update_state(const char *argv0, const char *iface, const char *state)
 
3630
{
 
3631
        FILE *tmp_fp;
 
3632
 
 
3633
        <<open ifupdown state>>
 
3634
 
 
3635
        if (no_act)
 
3636
                goto noact;
 
3637
 
 
3638
        tmp_fp = fopen(tmpstatefile, "w");
 
3639
        if (tmp_fp == NULL) {
 
3640
                fprintf(stderr, 
 
3641
                        "%s: failed to open temporary statefile %s: %s\n",
 
3642
                        argv0, tmpstatefile, strerror(errno));
 
3643
                exit (1);
 
3644
        }
 
3645
 
 
3646
        while((p = fgets(buf, sizeof buf, state_fp)) != NULL) {
 
3647
                <<parse ifupdown state line>>
 
3648
 
 
3649
                if (strncmp(iface, pch, strlen(iface)) == 0) {
 
3650
                        if (pch[strlen(iface)] == '=') {
 
3651
                                if (state != NULL) {
 
3652
                                        fprintf (tmp_fp, "%s=%s\n",
 
3653
                                                 iface, state);
 
3654
                                        state = NULL;
 
3655
                                }
 
3656
 
 
3657
                                continue;
 
3658
                        }
 
3659
                }
 
3660
 
 
3661
                fprintf (tmp_fp, "%s\n", pch);
 
3662
        }
 
3663
 
 
3664
        if (state != NULL)
 
3665
                fprintf (tmp_fp, "%s=%s\n", iface, state);
 
3666
 
 
3667
        fclose (tmp_fp);
 
3668
        if (rename (tmpstatefile, statefile)) {
 
3669
                fprintf(stderr, 
 
3670
                        "%s: failed to overwrite statefile %s: %s\n",
 
3671
                        argv0, statefile, strerror(errno));
 
3672
                exit (1);
 
3673
        }
 
3674
 
 
3675
        <<close ifupdown state>>
3598
3676
}
3599
3677
3600
3678
 
3621
3699
}
3622
3700
3623
3701
 
3624
 
 
3625
 
<<variables local to main>>=
3626
 
static FILE *state_fp = NULL;
3627
 
@
3628
 
 
3629
 
<<lock 'n load ifupdown state>>=
3630
 
{
3631
 
        state_fp = fopen(statefile, no_act ? "r" : "a+");
3632
 
        if (state_fp == NULL && !no_act) {
 
3702
<<open ifupdown state>>=
 
3703
FILE *state_fp;
 
3704
char buf[80];
 
3705
char *p;
 
3706
 
 
3707
state_fp = fopen(statefile, no_act ? "r" : "a+");
 
3708
if (state_fp == NULL) {
 
3709
        if (!no_act) {
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));
3636
3713
                exit (1);
3637
 
        }
3638
 
 
3639
 
        if (state_fp != NULL) {
3640
 
                char buf[80];
3641
 
                char *p;
3642
 
 
3643
 
                if (!no_act) {
3644
 
                        int flags;
3645
 
 
3646
 
                        if ((flags = fcntl(fileno(state_fp), F_GETFD)) < 0
3647
 
                            || fcntl(fileno(state_fp), F_SETFD, flags | FD_CLOEXEC) < 0) {
3648
 
                                fprintf(stderr, 
3649
 
                                        "%s: failed to set FD_CLOEXEC on statefile %s: %s\n",
3650
 
                                        argv[0], statefile, strerror(errno));
3651
 
                                exit(1);
3652
 
                        }
3653
 
 
3654
 
                        if (lock_fd (fileno(state_fp)) < 0) {
3655
 
                                fprintf(stderr, 
3656
 
                                        "%s: failed to lock statefile %s: %s\n",
3657
 
                                        argv[0], statefile, strerror(errno));
3658
 
                                exit(1);
3659
 
                        }
3660
 
 
3661
 
                }
3662
 
 
3663
 
                rewind (state_fp);
3664
 
                while((p = fgets(buf, sizeof buf, state_fp)) != NULL) {
3665
 
                        char *pch;
3666
 
 
3667
 
                        pch = buf + strlen(buf) - 1;
3668
 
                        while(pch > buf && isspace(*pch)) pch--;
3669
 
                        *(pch+1) = '\0';
3670
 
 
3671
 
                        pch = buf;
3672
 
                        while(isspace(*pch)) pch++;
3673
 
 
3674
 
                        add_to_state(&state, &n_state, &max_state, strdup(pch));
3675
 
                }
 
3714
        } else {
 
3715
                goto noact;
 
3716
        }
 
3717
}
 
3718
 
 
3719
if (!no_act) {
 
3720
        int flags;
 
3721
 
 
3722
        if ((flags = fcntl(fileno(state_fp), F_GETFD)) < 0
 
3723
            || fcntl(fileno(state_fp), F_SETFD, flags | FD_CLOEXEC) < 0) {
 
3724
                fprintf(stderr, 
 
3725
                        "%s: failed to set FD_CLOEXEC on statefile %s: %s\n",
 
3726
                        argv0, statefile, strerror(errno));
 
3727
                exit(1);
 
3728
        }
 
3729
 
 
3730
        if (lock_fd (fileno(state_fp)) < 0) {
 
3731
                fprintf(stderr, 
 
3732
                        "%s: failed to lock statefile %s: %s\n",
 
3733
                        argv0, statefile, strerror(errno));
 
3734
                exit(1);
3676
3735
        }
3677
3736
}
3678
3737
@
3679
3738
 
 
3739
<<parse ifupdown state line>>=
 
3740
char *pch;
 
3741
 
 
3742
pch = buf + strlen(buf) - 1;
 
3743
while(pch > buf && isspace(*pch)) pch--;
 
3744
*(pch+1) = '\0';
 
3745
 
 
3746
pch = buf;
 
3747
while(isspace(*pch)) pch++;
 
3748
 
3749
 
3680
3750
<<close ifupdown state>>=
 
3751
noact:
3681
3752
if (state_fp != NULL) {
3682
3753
        fclose(state_fp);
3683
3754
        state_fp = NULL;
3684
3755
}
3685
3756
@
3686
3757
 
3687
 
 
3688
 
<<commit ifupdown state>>=
3689
 
if (state_fp != NULL && !no_act) {
3690
 
        int i;
3691
 
 
3692
 
        if (ftruncate(fileno(state_fp), 0) < 0)
3693
 
        {
3694
 
                fprintf(stderr, 
3695
 
                        "%s: failed to truncate statefile %s: %s\n",
3696
 
                        argv[0], statefile, strerror(errno));
3697
 
                exit(1);
3698
 
        }
3699
 
 
3700
 
        rewind(state_fp);
3701
 
        for (i = 0; i < n_state; i++) {
3702
 
                fprintf(state_fp, "%s\n", state[i]);
3703
 
        }
3704
 
        fflush(state_fp);
3705
 
}
3706
 
@
3707
 
 
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).
3711
3761
 
3712
3762
<<check ifupdown state (possibly [[continue]])>>=
3713
3763
{
3714
 
        int already_up = lookfor_iface(state, n_state, iface);;
3715
 
 
3716
3764
        if (<<we're bringing interfaces up>>) {
3717
 
                if (already_up != -1) {
3718
 
                        if (do_all == 0) {
 
3765
                if (current_state != NULL) {
 
3766
                        if (!do_all) {
3719
3767
                                fprintf(stderr, 
3720
3768
                                        "%s: interface %s already configured\n",
3721
3769
                                        argv[0], iface);
3723
3771
                        continue;
3724
3772
                }
3725
3773
        } else if (<<we're taking interfaces down>>) {
3726
 
                if (already_up == -1) {
3727
 
                        if (do_all == 0) {
 
3774
                if (current_state == NULL) {
 
3775
                        if (!do_all) {
3728
3776
                                fprintf(stderr, "%s: interface %s not configured\n",
3729
3777
                                        argv[0], iface);
3730
3778
                        }
3731
3779
                        continue;
3732
3780
                }
3733
 
                strncpy(liface, strchr(state[already_up], '=') + 1, 80);
 
3781
                strncpy(liface, current_state, 80);
3734
3782
                liface[79] = 0;
3735
3783
        } else {
3736
3784
                assert(0);
3743
3791
 
3744
3792
<<update ifupdown state>>=
3745
3793
{
3746
 
        int already_up = lookfor_iface(state, n_state, iface);
3747
 
 
3748
3794
        if (<<we're bringing interfaces up>>) {
3749
 
                char *newiface = 
3750
 
                        malloc(strlen(iface) + 1 + strlen(liface) + 1);
3751
 
                sprintf(newiface, "%s=%s", iface, liface);
3752
 
 
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);
3756
3799
                        } else {
3757
 
                                add_to_state(&state, &n_state, &max_state, newiface);
 
3800
                                update_state (argv[0], iface, liface);
3758
3801
                        }
3759
3802
                } else {
3760
 
                        free(state[already_up]);
3761
 
                        state[already_up] = newiface;
 
3803
                        update_state (argv[0], iface, liface);
3762
3804
                }
3763
3805
        } else if (<<we're taking interfaces down>>) {
3764
 
                if (already_up != -1) {
3765
 
                        state[already_up] = state[--n_state];
3766
 
                }
 
3806
                update_state (argv[0], iface, NULL);
3767
3807
        } else {
3768
3808
                assert(0);
3769
3809
        }
3922
3962
 
3923
3963
  up
3924
3964
    [[ifconfig %iface% hw %hwaddress%]]
3925
 
    dhclient3 -nw -pf /var/run/dhclient.%iface%.pid -lf /var/lib/dhcp3/dhclient.%iface%.leases %iface% \
 
3965
    dhclient3 -pf /var/run/dhclient.%iface%.pid -lf /var/lib/dhcp3/dhclient.%iface%.leases %iface% \
3926
3966
        if (execable("/sbin/dhclient3"))
3927
3967
    dhclient -e -pf /var/run/dhclient.%iface%.pid -lf /var/run/dhclient.%iface%.leases %iface% \
3928
3968
        elsif (execable("/sbin/dhclient"))