#! /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 () { 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 = ; 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"; }