From 04115f9aa5cf9bc2ee6d7a2c4f386c8a15da4df7 Mon Sep 17 00:00:00 2001 From: Jamie Cameron Date: Tue, 21 Oct 2008 06:37:11 +0000 Subject: [PATCH] Fixed option ordering bug --- dhcpd/CHANGELOG | 2 ++ dhcpd/dhcpd-lib.pl | 27 ++++++++++++++++++++++++--- dhcpd/save_options.cgi | 9 ++++++++- 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/dhcpd/CHANGELOG b/dhcpd/CHANGELOG index e83f69e98..9b158d6a0 100644 --- a/dhcpd/CHANGELOG +++ b/dhcpd/CHANGELOG @@ -23,3 +23,5 @@ Fixed a bug that causes hosts to be deleted when searching for them! Clashes between hosts with the same IP address, MAC address or hostname are no longer allowed by default - but this can be changed on the DHCP Server access control page in the Webmin User's module. ---- Changes since 1.420 ---- Support the new configuration file format for custom options, as used in DHCPd version 3. +---- Changes since 1.430 ---- +Fixed bug that can cause option definitions and values to be incorrectly ordered. diff --git a/dhcpd/dhcpd-lib.pl b/dhcpd/dhcpd-lib.pl index 0749d9d3a..bb661bb25 100755 --- a/dhcpd/dhcpd-lib.pl +++ b/dhcpd/dhcpd-lib.pl @@ -325,7 +325,7 @@ else { } } -# save_directive(&parent, [name|&oldvalues], &values, indent, start) +# save_directive(&parent, [name|&oldvalues], &values, indent, start, [after]) # Given a structure containing a directive name, type, values and members # add, update or remove that directive in config structure and data files. # Updating of files assumes that there is no overlap between directives - @@ -337,10 +337,28 @@ $pm = $_[0]->{'members'}; @oldv = ref($_[1]) ? @{$_[1]} : &find($_[1], $pm); @newv = @{$_[2]}; for($i=0; $i<@oldv || $i<@newv; $i++) { - if ($i >= @oldv && $_[4]) { + if ($i >= @oldv && $_[5]) { + # a new directive is being added.. put it after some other + $lref = $_[0]->{'file'} ? &read_file_lines($_[0]->{'file'}) + : [ ]; + @nl = &directive_lines($newv[$i], $_[3]); + $nline = $_[5]->{'line'}+1; + $nidx = &indexof($_[5], @$pm) + 1; + splice(@$lref, $nline, 0, @nl); + &renumber(&get_config(), $nline, + $_[0]->{'file'}, scalar(@nl)); + &renumber_index($_[0]->{'members'}, $nidx, 1); + $newv[$i]->{'index'} = $nidx; + $newv[$i]->{'file'} = $_[0]->{'file'}; + $newv[$i]->{'line'} = $nline; + $newv[$i]->{'eline'} = $nline + scalar(@nl); + splice(@$pm, $nidx, 0, $newv[$i]); + } + elsif ($i >= @oldv && $_[4]) { # a new directive is being added.. put it at the start of # the parent - $lref = $_[0]->{'file'} ? &read_file_lines($_[0]->{'file'}) : [ ]; + $lref = $_[0]->{'file'} ? &read_file_lines($_[0]->{'file'}) + : [ ]; @nl = &directive_lines($newv[$i], $_[3]); $nline = $_[0]->{'fline'}+1; splice(@$lref, $nline, 0, @nl); @@ -377,6 +395,9 @@ for($i=0; $i<@oldv || $i<@newv; $i++) { } else { # updating some directive + if (!defined($newv[$i]->{'comment'})) { + $newv[$i]->{'comment'} = $oldv[$i]->{'comment'}; + } $lref = $oldv[$i]->{'file'} ? &read_file_lines($oldv[$i]->{'file'}) : [ ]; @nl = &directive_lines($newv[$i], $_[3]); $ol = $oldv[$i]->{'eline'} - $oldv[$i]->{'line'} + 1; diff --git a/dhcpd/save_options.cgi b/dhcpd/save_options.cgi index 8910f43d7..d6c3718b1 100755 --- a/dhcpd/save_options.cgi +++ b/dhcpd/save_options.cgi @@ -106,6 +106,12 @@ if ($config{'dhcpd_version'} >= 3) { } &save_directive($client, \@defs, \@newdefs, $indent, 1); + # Find the last definition + $maxdef = undef; + foreach $d (@newdefs) { + $maxdef = $d if (!$maxdef || $d->{'line'} > $maxdef->{'line'}); + } + # Save custom options @custom = grep { $_->{'name'} eq 'option' && $optdef{$_->{'values'}->[0]} && @@ -120,7 +126,8 @@ if ($config{'dhcpd_version'} >= 3) { push(@newcustom, { 'name' => 'option', 'values' => [ $in{"cname_$i"}, $cv ] } ); } - &save_directive($client, \@custom, \@newcustom, $indent, 1); + &save_directive($client, \@custom, \@newcustom, $indent, + $maxdef ? 0 : 1, $maxdef); } else { # Save custom options