bin/zoneconf: Abstract out command substitution machinery.
[zoneconf] / bin / zoneconf
index e988a83..7ee6d6a 100755 (executable)
@@ -60,13 +60,14 @@ proc merge-lists {lists} {
     set cand {}
     foreach list $lists { pushnew cand [lindex $list 0] }
 
-    ## Remove candidate items which have not the first in some other list.
+    ## Remove candidate items which are not first in some other list.
     set ncand {}
     foreach cand $cand {
       foreach list $lists {
-       if {[lsearch -exact $list $cand] < 0} { lappend ncand $cand }
+       if {[lsearch -exact $list $cand] <= 0} { lappend ncand $cand }
       }
     }
+    set cand $ncand
 
     ## If there's nothing left, report an error.
     if {![llength $cand]} {
@@ -311,7 +312,7 @@ proc preserving-config {confvar body} {
   ## Evaluate BODY, but on exit restore the CONFVAR array so that the BODY
   ## has no lasting effect on it.
 
-  upvar #1 $confvar CONFIG
+  upvar #0 $confvar CONFIG
   set old [array get CONFIG]
   unwind-protect {
     uplevel 1 $body
@@ -979,6 +980,24 @@ define-configuration-space zone ZONECFG {
   }
 
   define view-map {map} {
+
+    ## OK, this needs careful documentation.
+    ##
+    ## The local nameserver presents a number of views according to its
+    ## configuration.  It is our purpose here to generate a configuration
+    ## snippet for such a view.
+    ##
+    ## A user might have several different views of a zone which are meant to
+    ## be presented to different clients.  These map on to the server views
+    ## in a one-to-many fashion.  The `view-map' option defines this mapping.
+    ## The argument is a list of alternating SERVER-VIEW USER-VIEW pairs; the
+    ## SERVER-VIEW may be a glob pattern; the USER-VIEW may be the special
+    ## token `=' to mean `same as the SERVER-VIEW'.
+    ##
+    ## We only keep one copy of the zone file for each user view: if the user
+    ## view is used by many server views, then the zone stanza for each of
+    ## those views refers to the same zone file.
+
     if {[llength $map] % 2} {
       error "view map must have an even number of items"
     }
@@ -1018,6 +1037,17 @@ define-configuration-space toplevel ZONECFG {
 ###--------------------------------------------------------------------------
 ### Processing the results.
 
+proc build-command {command args} {
+  ## Return the COMMAND list, after applying the string map ARGS to each item
+  ## in turn.
+
+  set cmd {}
+  foreach item $command {
+    lappend cmd [string map $args $item]
+  }
+  return $cmd
+}
+
 proc zone-file-name {view config} {
   ## Return the relative file name for the zone described by CONFIG, relative
   ## to the given VIEW.  An absolute filename may be derived later, depending
@@ -1040,7 +1070,7 @@ proc output-file-name {view} {
 
 proc compute-zone-properties {view config} {
   ## Derive interesting information from the zone configuration plist CONFIG,
-  ## relative to the stated VIEW.  Return a new plist.
+  ## relative to the stated server VIEW.  Return a new plist.
 
   array set zone $config
 
@@ -1278,14 +1308,11 @@ provided by the named USER"
     }
     close $chan
 
-    set cmd {}
-    foreach item $zone(checkzone-command) {
-      lappend cmd [string map [list \
-                                  "%z" $name \
-                                  "%v" $view \
-                                  "%f" $tmp] \
-                      $item]
-    }
+    ## Check the zone for sanity.
+    set cmd [build-command $zone(checkzone-command) \
+                "%z" $name \
+                "%v" $view \
+                "%f" $tmp]
     set rc [catch {
       set out [eval exec $cmd]
     } msg]
@@ -1303,14 +1330,9 @@ provided by the named USER"
     file rename -force -- $tmp $zone(file-name)
     set cleanup {}
     foreach view $matchview {
-      set cmd {}
-      foreach item $zone(reload-command) {
-       lappend cmd [string map [list \
-                                    "%v" $view \
-                                    "%z" $zone(name)] \
-                        $item]
-      }
-      eval exec $cmd
+      eval exec $cmd [build-command $zone(reload-command) \
+                         "%v" $view \
+                         "%z" $zone(name)]
     }
   } {
     eval $cleanup