1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
#! /usr/bin/perl
use POSIX;
use strict;
use warnings;
my $default = '/etc/default/openvswitch-switch';
my (%config) = load_config($default);
if (@ARGV) {
foreach my $arg (@ARGV) {
my ($key, $value) = $arg =~ /^([^=]+)=(.*)/
or die "bad argument '$arg'\n";
if ($value ne '') {
$config{$key} = $value;
} else {
delete $config{$key};
}
}
save_config($default, %config);
}
print "$_=$config{$_}\n" foreach sort(keys(%config));
sub load_config {
my ($file) = @_;
# Get the list of the variables that the shell sets automatically.
my (%auto_vars) = read_vars("set -a && env");
# Get the variables from $default.
my (%config) = read_vars("set -a && . '$default' && env");
# Subtract.
delete @config{keys %auto_vars};
return %config;
}
sub read_vars {
my ($cmd) = @_;
local @ENV;
if (!open(VARS, '-|', $cmd)) {
print STDERR "$cmd: failed to execute: $!\n";
return ();
}
my (%config);
while (<VARS>) {
my ($var, $value) = /^([^=]+)=(.*)$/ or next;
$config{$var} = $value;
}
close(VARS);
return %config;
}
sub shell_escape {
local $_ = $_[0];
if ($_ eq '') {
return '""';
} elsif (m&^[-a-zA-Z0-9:./%^_+,]*$&) {
return $_;
} else {
s/'/'\\''/;
return "'$_'";
}
}
sub shell_assign {
my ($var, $value) = @_;
return $var . '=' . shell_escape($value);
}
sub save_config {
my ($file, %config) = @_;
my (@lines);
if (open(FILE, '<', $file)) {
@lines = <FILE>;
chomp @lines;
close(FILE);
}
# Replace all existing variable assignments.
for (my ($i) = 0; $i <= $#lines; $i++) {
local $_ = $lines[$i];
my ($var, $value) = /^\s*([^=#]+)=(.*)$/ or next;
if (exists($config{$var})) {
$lines[$i] = shell_assign($var, $config{$var});
delete $config{$var};
} else {
$lines[$i] = "#$lines[$i]";
}
}
# Find a place to put any remaining variable assignments.
VAR:
for my $var (keys(%config)) {
my $assign = shell_assign($var, $config{$var});
# Replace the last commented-out variable assignment to $var, if any.
for (my ($i) = $#lines; $i >= 0; $i--) {
local $_ = $lines[$i];
if (/^\s*#\s*$var=/) {
$lines[$i] = $assign;
next VAR;
}
}
# Find a place to add the var: after the final commented line
# just after a line that contains "$var:".
for (my ($i) = 0; $i <= $#lines; $i++) {
if ($lines[$i] =~ /^\s*#\s*$var:/) {
for (my ($j) = $i + 1; $j <= $#lines; $j++) {
if ($lines[$j] !~ /^\s*#/) {
splice(@lines, $j, 0, $assign);
next VAR;
}
}
}
}
# Just append it.
push(@lines, $assign);
}
open(NEWFILE, '>', "$file.tmp") or die "$file.tmp: create: $!\n";
print NEWFILE join('', map("$_\n", @lines));
close(NEWFILE);
rename("$file.tmp", $file) or die "$file.tmp: rename to $file: $!\n";
}
|