++ udev-124/debian/fix-persistent-net.pl #!/usr/bin/perl use strict; use warnings; my $RULES = "/etc/udev/rules.d/70-persistent-net.rules"; #-----------------------------------------------------------------------------# # Sanity check #-----------------------------------------------------------------------------# die "$RULES does not exist to fix\n" unless -f $RULES; #-----------------------------------------------------------------------------# # Parse existing /etc/udev/rules.d/70-persistent-net.rules #-----------------------------------------------------------------------------# open RULES, $RULES or die "Unable to open $RULES: $!"; my @rules; while () { # Rules may cross multiple lines when lines ends in \ while (/\\$/ && (my $extra = )) { $_ .= $extra; } # Skip lines that are empty, have only whitespace and/or comments if (/^\s*(\#.*)?$/) { push @rules, [ $_ ]; next; } # Parse rule elements my $rule = []; while (/(?:([\s,]*)((\S*?)\s*(==|\+=|!=|:=|=)\s*\"([^\"]*)\")|(.+))/gs) { if (defined $1) { push @{$rule}, $1 if length $1; push @{$rule}, { 'text' => $2, 'key' => $3, 'op' => $4, 'val' => $5 }; } else { push @{$rule}, $6; } } push @rules, $rule; } close RULES or warn "Error while closing $RULES: $!"; #-----------------------------------------------------------------------------# # Fix rule entries #-----------------------------------------------------------------------------# RULE: foreach my $rule (@rules) { my $has_rule = 0; my $has_match = 0; my $has_type = 0; my $name_idx = -1; my $name; my $address; MATCH: foreach my $idx (0..$#{$rule}) { my $match = $rule->[$idx]; next unless ref $match; $has_rule = 1; if ($match->{key} =~ /^ATTRS?{type}$/) { # Rule matches on interface type $has_type = 1; } elsif ($match->{key} =~ /^ATTRS?{address}$/) { # Rule matches on MAC address $has_match = 1; $address = $match->{val}; } elsif ($match->{key} =~ /^ATTRS?{[^}]*}|ENV{[^}]*}|KERNELS$/) { # Rule matches on a possibly unique attribute $has_match = 1; } elsif ($match->{key} =~ /^NAME$/ && $match->{op} =~ /^:?=$/) { # Name setting $name_idx = $idx; $name = $match->{val}; } } next unless $has_rule; # Comment out lines that don't match a device by any potentially unique # property, since they'll match everything unless ($has_match) { unshift @{$rule}, "#removed by upgrade, will match any device\n# "; $name_idx++; } # Add a match on type for any rule missing that to avoid matching # "master" devices unless ($has_type) { my $type; # Make sure that the device currently has the "1" (Ethernet) type if (-f "/sys/class/net/$name/type" && `cat /sys/class/net/$name/type` =~ /^1\s*$/) { # It does $type = "1"; } elsif (defined $address) { # It doesn't, it's possible that we've already renamed it to # something else and a device exists with the right MAC address # and a different name opendir NET, "/sys/class/net" or die "Unable to open /sys/class/net: $!"; my $found = 0; while (my $dev = readdir(NET)) { next if $dev =~ /^\./; next unless (-f "/sys/class/net/$dev/address" && `cat /sys/class/net/$dev/address` =~ /^$address\s*$/i); $found = 1; next unless (-f "/sys/class/net/$dev/type" && `cat /sys/class/net/$dev/type` =~ /^1\s*$/); # Found a device with a matching address and the right type $type = "1"; } closedir NET or die "Error while closing /sys/class/net: $!"; # No device with the matching MAC address found (unplugged?) # stick type in anyway $type = "1" unless $found; } # Append a rule to match the type. If we couldn't find an Ethernet # device with the set name, or a different name but the right address, # then we don't attempt to change the file and instead leave a comment # to highlight a line that might be a problem. if (defined $type) { my $match = { 'text' => "ATTR{type}==\"$type\"", 'key' => 'ATTR{type}', 'op' => '==', 'val' => "$type" }; splice(@{$rule}, $name_idx, 0, $match, ", "); $name_idx += 2; } elsif ($has_match) { unshift @{$rule}, "#following line may cause a device to become stuck as ${name}_rename\n#add ADDR{type}==\"...\" if that happens\n"; $name_idx++; } } } #-----------------------------------------------------------------------------# # Write new /etc/udev/rules.d/70-persistent-net.rules #-----------------------------------------------------------------------------# open RULES, ">$RULES.new" or die "Unable to open $RULES.new: $!"; foreach my $rule (@rules) { my $line = ""; foreach my $match (@{$rule}) { if (ref $match) { $line .= $match->{text}; } else { $line .= $match; } } print RULES $line; } close RULES or warn "Error while closing $RULES: $!"; rename "$RULES.new", $RULES or die "Unable to replace $RULES: $!";